From b64bbcbd7e13854340d14eaf93511218b09642e3 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Fri, 26 Jun 2020 11:11:27 +0200 Subject: [PATCH] Vendor dependencies --- vendor/github.com/google/uuid/.travis.yml | 9 + vendor/github.com/google/uuid/CONTRIBUTING.md | 10 + vendor/github.com/google/uuid/CONTRIBUTORS | 9 + vendor/github.com/google/uuid/LICENSE | 27 + vendor/github.com/google/uuid/README.md | 19 + vendor/github.com/google/uuid/dce.go | 80 + vendor/github.com/google/uuid/doc.go | 12 + vendor/github.com/google/uuid/go.mod | 1 + vendor/github.com/google/uuid/hash.go | 53 + vendor/github.com/google/uuid/marshal.go | 37 + vendor/github.com/google/uuid/node.go | 89 + vendor/github.com/google/uuid/node_js.go | 12 + vendor/github.com/google/uuid/node_net.go | 33 + vendor/github.com/google/uuid/sql.go | 59 + vendor/github.com/google/uuid/time.go | 123 ++ vendor/github.com/google/uuid/util.go | 43 + vendor/github.com/google/uuid/uuid.go | 245 +++ vendor/github.com/google/uuid/version1.go | 44 + vendor/github.com/google/uuid/version4.go | 38 + .../go-windows-terminal-sequences/LICENSE | 9 + .../go-windows-terminal-sequences/README.md | 41 + .../go-windows-terminal-sequences/go.mod | 1 + .../sequences.go | 36 + .../sequences_dummy.go | 11 + vendor/github.com/mattn/goveralls/.gitignore | 2 + vendor/github.com/mattn/goveralls/.travis.yml | 14 + vendor/github.com/mattn/goveralls/README.md | 266 +++ vendor/github.com/mattn/goveralls/gitinfo.go | 124 ++ vendor/github.com/mattn/goveralls/go.mod | 5 + vendor/github.com/mattn/goveralls/go.sum | 17 + vendor/github.com/mattn/goveralls/gocover.go | 131 ++ .../github.com/mattn/goveralls/goveralls.go | 508 +++++ .../github.com/mattn/goveralls/renovate.json | 5 + vendor/github.com/mohae/deepcopy/.gitignore | 26 + vendor/github.com/mohae/deepcopy/.travis.yml | 11 + vendor/github.com/mohae/deepcopy/LICENSE | 21 + vendor/github.com/mohae/deepcopy/README.md | 8 + vendor/github.com/mohae/deepcopy/deepcopy.go | 125 ++ vendor/github.com/ory/fosite/.gitignore | 7 + vendor/github.com/ory/fosite/.golangci.yml | 17 + vendor/github.com/ory/fosite/.travis.yml | 16 + vendor/github.com/ory/fosite/CONTRIBUTING.md | 141 ++ vendor/github.com/ory/fosite/HISTORY.md | 653 ++++++ vendor/github.com/ory/fosite/LICENSE | 201 ++ vendor/github.com/ory/fosite/MAINTAINERS | 2 + vendor/github.com/ory/fosite/Makefile | 5 + vendor/github.com/ory/fosite/README.md | 434 ++++ vendor/github.com/ory/fosite/SECURITY.md | 38 + vendor/github.com/ory/fosite/access_error.go | 50 + .../github.com/ory/fosite/access_request.go | 43 + .../ory/fosite/access_request_handler.go | 102 + .../github.com/ory/fosite/access_response.go | 77 + .../ory/fosite/access_response_writer.go | 48 + vendor/github.com/ory/fosite/access_write.go | 42 + vendor/github.com/ory/fosite/arguments.go | 98 + .../ory/fosite/audience_strategy.go | 60 + .../github.com/ory/fosite/authorize_error.go | 77 + .../github.com/ory/fosite/authorize_helper.go | 181 ++ .../ory/fosite/authorize_request.go | 88 + .../ory/fosite/authorize_request_handler.go | 276 +++ .../ory/fosite/authorize_response.go | 77 + .../ory/fosite/authorize_response_writer.go | 51 + .../github.com/ory/fosite/authorize_write.go | 72 + vendor/github.com/ory/fosite/client.go | 179 ++ .../ory/fosite/client_authentication.go | 294 +++ .../client_authentication_jwks_strategy.go | 81 + .../github.com/ory/fosite/client_manager.go | 42 + .../github.com/ory/fosite/compose/compose.go | 122 ++ .../ory/fosite/compose/compose_oauth2.go | 138 ++ .../ory/fosite/compose/compose_openid.go | 99 + .../ory/fosite/compose/compose_pkce.go | 38 + .../ory/fosite/compose/compose_strategy.go | 79 + .../github.com/ory/fosite/compose/config.go | 184 ++ vendor/github.com/ory/fosite/context.go | 28 + vendor/github.com/ory/fosite/errors.go | 319 +++ vendor/github.com/ory/fosite/fosite.go | 105 + vendor/github.com/ory/fosite/fosite.png | Bin 0 -> 43726 bytes .../github.com/ory/fosite/generate-mocks.sh | 31 + vendor/github.com/ory/fosite/go.mod | 26 + vendor/github.com/ory/fosite/go.sum | 735 +++++++ vendor/github.com/ory/fosite/handler.go | 69 + .../oauth2/flow_authorize_code_auth.go | 129 ++ .../oauth2/flow_authorize_code_token.go | 208 ++ .../handler/oauth2/flow_authorize_implicit.go | 106 + .../handler/oauth2/flow_client_credentials.go | 81 + .../oauth2/flow_client_credentials_storage.go | 26 + .../ory/fosite/handler/oauth2/flow_refresh.go | 194 ++ .../handler/oauth2/flow_resource_owner.go | 115 ++ .../oauth2/flow_resource_owner_storage.go | 32 + .../ory/fosite/handler/oauth2/helper.go | 58 + .../ory/fosite/handler/oauth2/introspector.go | 114 ++ .../fosite/handler/oauth2/introspector_jwt.go | 60 + .../ory/fosite/handler/oauth2/revocation.go | 77 + .../handler/oauth2/revocation_storage.go | 49 + .../ory/fosite/handler/oauth2/storage.go | 68 + .../ory/fosite/handler/oauth2/strategy.go | 56 + .../fosite/handler/oauth2/strategy_hmacsha.go | 96 + .../ory/fosite/handler/oauth2/strategy_jwt.go | 176 ++ .../handler/oauth2/strategy_jwt_session.go | 105 + .../ory/fosite/handler/openid/errors.go | 28 + .../handler/openid/flow_explicit_auth.go | 72 + .../handler/openid/flow_explicit_token.go | 76 + .../ory/fosite/handler/openid/flow_hybrid.go | 159 ++ .../fosite/handler/openid/flow_implicit.go | 111 + .../handler/openid/flow_refresh_token.go | 101 + .../ory/fosite/handler/openid/helper.go | 76 + .../ory/fosite/handler/openid/storage.go | 45 + .../ory/fosite/handler/openid/strategy.go | 32 + .../ory/fosite/handler/openid/strategy_jwt.go | 236 +++ .../ory/fosite/handler/openid/validator.go | 168 ++ .../ory/fosite/handler/pkce/handler.go | 229 +++ .../ory/fosite/handler/pkce/storage.go | 34 + vendor/github.com/ory/fosite/hash.go | 34 + vendor/github.com/ory/fosite/hash_bcrypt.go | 54 + vendor/github.com/ory/fosite/helper.go | 46 + vendor/github.com/ory/fosite/introspect.go | 78 + .../fosite/introspection_request_handler.go | 189 ++ .../fosite/introspection_response_writer.go | 234 +++ vendor/github.com/ory/fosite/oauth2.go | 318 +++ vendor/github.com/ory/fosite/request.go | 195 ++ .../github.com/ory/fosite/revoke_handler.go | 129 ++ .../github.com/ory/fosite/scope_strategy.go | 103 + vendor/github.com/ory/fosite/session.go | 99 + vendor/github.com/ory/fosite/storage.go | 27 + .../github.com/ory/fosite/storage/memory.go | 267 +++ .../ory/fosite/storage/transactional.go | 55 + .../github.com/ory/fosite/token/hmac/bytes.go | 38 + .../ory/fosite/token/hmac/hmacsha.go | 174 ++ .../github.com/ory/fosite/token/jwt/claims.go | 95 + .../ory/fosite/token/jwt/claims_id_token.go | 113 ++ .../ory/fosite/token/jwt/claims_jwt.go | 194 ++ .../github.com/ory/fosite/token/jwt/header.go | 66 + vendor/github.com/ory/fosite/token/jwt/jwt.go | 218 ++ vendor/github.com/ory/fosite/tools.go | 9 + vendor/github.com/ory/go-acc/.gitignore | 7 + vendor/github.com/ory/go-acc/.travis.yml | 18 + vendor/github.com/ory/go-acc/CONTRIBUTING.md | 119 ++ vendor/github.com/ory/go-acc/LICENSE | 202 ++ vendor/github.com/ory/go-acc/README.md | 33 + vendor/github.com/ory/go-acc/cmd/root.go | 234 +++ vendor/github.com/ory/go-acc/coverage.txt | 1 + vendor/github.com/ory/go-acc/go.mod | 10 + vendor/github.com/ory/go-acc/go.sum | 680 +++++++ vendor/github.com/ory/go-acc/main.go | 7 + vendor/github.com/ory/go-convenience/LICENSE | 21 + .../ory/go-convenience/stringslice/filter.go | 34 + .../ory/go-convenience/stringslice/has.go | 23 + .../ory/go-convenience/stringslice/merge.go | 10 + .../ory/go-convenience/stringslice/unique.go | 15 + .../ory/go-convenience/stringsx/coalesce.go | 11 + .../ory/go-convenience/stringsx/split.go | 13 + vendor/github.com/ory/x/LICENSE | 201 ++ vendor/github.com/ory/x/cmdx/args.go | 35 + vendor/github.com/ory/x/cmdx/env.go | 28 + vendor/github.com/ory/x/cmdx/helper.go | 81 + vendor/github.com/ory/x/cmdx/version.go | 56 + vendor/github.com/ory/x/flagx/flagx.go | 54 + vendor/github.com/pborman/uuid/.travis.yml | 10 + .../github.com/pborman/uuid/CONTRIBUTING.md | 10 + vendor/github.com/pborman/uuid/CONTRIBUTORS | 1 + vendor/github.com/pborman/uuid/LICENSE | 27 + vendor/github.com/pborman/uuid/README.md | 15 + vendor/github.com/pborman/uuid/dce.go | 84 + vendor/github.com/pborman/uuid/doc.go | 13 + vendor/github.com/pborman/uuid/go.mod | 3 + vendor/github.com/pborman/uuid/go.sum | 2 + vendor/github.com/pborman/uuid/hash.go | 53 + vendor/github.com/pborman/uuid/marshal.go | 85 + vendor/github.com/pborman/uuid/node.go | 50 + vendor/github.com/pborman/uuid/sql.go | 68 + vendor/github.com/pborman/uuid/time.go | 57 + vendor/github.com/pborman/uuid/util.go | 32 + vendor/github.com/pborman/uuid/uuid.go | 162 ++ vendor/github.com/pborman/uuid/version1.go | 23 + vendor/github.com/pborman/uuid/version4.go | 26 + vendor/github.com/satori/go.uuid/.travis.yml | 23 + vendor/github.com/satori/go.uuid/LICENSE | 20 + vendor/github.com/satori/go.uuid/README.md | 65 + vendor/github.com/satori/go.uuid/codec.go | 206 ++ vendor/github.com/satori/go.uuid/generator.go | 239 +++ vendor/github.com/satori/go.uuid/sql.go | 78 + vendor/github.com/satori/go.uuid/uuid.go | 161 ++ vendor/github.com/sirupsen/logrus/.gitignore | 2 + vendor/github.com/sirupsen/logrus/.travis.yml | 25 + .../github.com/sirupsen/logrus/CHANGELOG.md | 200 ++ vendor/github.com/sirupsen/logrus/LICENSE | 21 + vendor/github.com/sirupsen/logrus/README.md | 495 +++++ vendor/github.com/sirupsen/logrus/alt_exit.go | 76 + .../github.com/sirupsen/logrus/appveyor.yml | 14 + vendor/github.com/sirupsen/logrus/doc.go | 26 + vendor/github.com/sirupsen/logrus/entry.go | 407 ++++ vendor/github.com/sirupsen/logrus/exported.go | 225 +++ .../github.com/sirupsen/logrus/formatter.go | 78 + vendor/github.com/sirupsen/logrus/go.mod | 10 + vendor/github.com/sirupsen/logrus/go.sum | 16 + vendor/github.com/sirupsen/logrus/hooks.go | 34 + .../sirupsen/logrus/json_formatter.go | 121 ++ vendor/github.com/sirupsen/logrus/logger.go | 351 ++++ vendor/github.com/sirupsen/logrus/logrus.go | 186 ++ .../logrus/terminal_check_appengine.go | 11 + .../sirupsen/logrus/terminal_check_bsd.go | 13 + .../logrus/terminal_check_no_terminal.go | 11 + .../logrus/terminal_check_notappengine.go | 17 + .../sirupsen/logrus/terminal_check_solaris.go | 11 + .../sirupsen/logrus/terminal_check_unix.go | 13 + .../sirupsen/logrus/terminal_check_windows.go | 34 + .../sirupsen/logrus/text_formatter.go | 295 +++ vendor/github.com/sirupsen/logrus/writer.go | 64 + vendor/golang.org/x/crypto/ed25519/ed25519.go | 222 ++ .../x/crypto/ed25519/ed25519_go113.go | 73 + .../ed25519/internal/edwards25519/const.go | 1422 +++++++++++++ .../internal/edwards25519/edwards25519.go | 1793 +++++++++++++++++ vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 + vendor/golang.org/x/tools/cover/profile.go | 256 +++ .../square/go-jose.v2/.gitcookies.sh.enc | 1 + vendor/gopkg.in/square/go-jose.v2/.gitignore | 8 + vendor/gopkg.in/square/go-jose.v2/.travis.yml | 43 + .../gopkg.in/square/go-jose.v2/BUG-BOUNTY.md | 10 + .../square/go-jose.v2/CONTRIBUTING.md | 14 + vendor/gopkg.in/square/go-jose.v2/LICENSE | 202 ++ vendor/gopkg.in/square/go-jose.v2/README.md | 118 ++ .../gopkg.in/square/go-jose.v2/asymmetric.go | 592 ++++++ .../square/go-jose.v2/cipher/cbc_hmac.go | 196 ++ .../square/go-jose.v2/cipher/concat_kdf.go | 75 + .../square/go-jose.v2/cipher/ecdh_es.go | 86 + .../square/go-jose.v2/cipher/key_wrap.go | 109 + vendor/gopkg.in/square/go-jose.v2/crypter.go | 541 +++++ vendor/gopkg.in/square/go-jose.v2/doc.go | 27 + vendor/gopkg.in/square/go-jose.v2/encoding.go | 185 ++ .../gopkg.in/square/go-jose.v2/json/LICENSE | 27 + .../gopkg.in/square/go-jose.v2/json/README.md | 13 + .../gopkg.in/square/go-jose.v2/json/decode.go | 1183 +++++++++++ .../gopkg.in/square/go-jose.v2/json/encode.go | 1197 +++++++++++ .../gopkg.in/square/go-jose.v2/json/indent.go | 141 ++ .../square/go-jose.v2/json/scanner.go | 623 ++++++ .../gopkg.in/square/go-jose.v2/json/stream.go | 480 +++++ .../gopkg.in/square/go-jose.v2/json/tags.go | 44 + vendor/gopkg.in/square/go-jose.v2/jwe.go | 294 +++ vendor/gopkg.in/square/go-jose.v2/jwk.go | 721 +++++++ vendor/gopkg.in/square/go-jose.v2/jws.go | 366 ++++ vendor/gopkg.in/square/go-jose.v2/opaque.go | 144 ++ vendor/gopkg.in/square/go-jose.v2/shared.go | 520 +++++ vendor/gopkg.in/square/go-jose.v2/signing.go | 441 ++++ .../gopkg.in/square/go-jose.v2/symmetric.go | 482 +++++ vendor/modules.txt | 7 + 245 files changed, 32476 insertions(+) create mode 100644 vendor/github.com/google/uuid/.travis.yml create mode 100644 vendor/github.com/google/uuid/CONTRIBUTING.md create mode 100644 vendor/github.com/google/uuid/CONTRIBUTORS create mode 100644 vendor/github.com/google/uuid/LICENSE create mode 100644 vendor/github.com/google/uuid/README.md create mode 100644 vendor/github.com/google/uuid/dce.go create mode 100644 vendor/github.com/google/uuid/doc.go create mode 100644 vendor/github.com/google/uuid/go.mod create mode 100644 vendor/github.com/google/uuid/hash.go create mode 100644 vendor/github.com/google/uuid/marshal.go create mode 100644 vendor/github.com/google/uuid/node.go create mode 100644 vendor/github.com/google/uuid/node_js.go create mode 100644 vendor/github.com/google/uuid/node_net.go create mode 100644 vendor/github.com/google/uuid/sql.go create mode 100644 vendor/github.com/google/uuid/time.go create mode 100644 vendor/github.com/google/uuid/util.go create mode 100644 vendor/github.com/google/uuid/uuid.go create mode 100644 vendor/github.com/google/uuid/version1.go create mode 100644 vendor/github.com/google/uuid/version4.go create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/README.md create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go create mode 100644 vendor/github.com/mattn/goveralls/.gitignore create mode 100644 vendor/github.com/mattn/goveralls/.travis.yml create mode 100644 vendor/github.com/mattn/goveralls/README.md create mode 100644 vendor/github.com/mattn/goveralls/gitinfo.go create mode 100644 vendor/github.com/mattn/goveralls/go.mod create mode 100644 vendor/github.com/mattn/goveralls/go.sum create mode 100644 vendor/github.com/mattn/goveralls/gocover.go create mode 100644 vendor/github.com/mattn/goveralls/goveralls.go create mode 100644 vendor/github.com/mattn/goveralls/renovate.json create mode 100644 vendor/github.com/mohae/deepcopy/.gitignore create mode 100644 vendor/github.com/mohae/deepcopy/.travis.yml create mode 100644 vendor/github.com/mohae/deepcopy/LICENSE create mode 100644 vendor/github.com/mohae/deepcopy/README.md create mode 100644 vendor/github.com/mohae/deepcopy/deepcopy.go create mode 100644 vendor/github.com/ory/fosite/.gitignore create mode 100644 vendor/github.com/ory/fosite/.golangci.yml create mode 100644 vendor/github.com/ory/fosite/.travis.yml create mode 100644 vendor/github.com/ory/fosite/CONTRIBUTING.md create mode 100644 vendor/github.com/ory/fosite/HISTORY.md create mode 100644 vendor/github.com/ory/fosite/LICENSE create mode 100644 vendor/github.com/ory/fosite/MAINTAINERS create mode 100644 vendor/github.com/ory/fosite/Makefile create mode 100644 vendor/github.com/ory/fosite/README.md create mode 100644 vendor/github.com/ory/fosite/SECURITY.md create mode 100644 vendor/github.com/ory/fosite/access_error.go create mode 100644 vendor/github.com/ory/fosite/access_request.go create mode 100644 vendor/github.com/ory/fosite/access_request_handler.go create mode 100644 vendor/github.com/ory/fosite/access_response.go create mode 100644 vendor/github.com/ory/fosite/access_response_writer.go create mode 100644 vendor/github.com/ory/fosite/access_write.go create mode 100644 vendor/github.com/ory/fosite/arguments.go create mode 100644 vendor/github.com/ory/fosite/audience_strategy.go create mode 100644 vendor/github.com/ory/fosite/authorize_error.go create mode 100644 vendor/github.com/ory/fosite/authorize_helper.go create mode 100644 vendor/github.com/ory/fosite/authorize_request.go create mode 100644 vendor/github.com/ory/fosite/authorize_request_handler.go create mode 100644 vendor/github.com/ory/fosite/authorize_response.go create mode 100644 vendor/github.com/ory/fosite/authorize_response_writer.go create mode 100644 vendor/github.com/ory/fosite/authorize_write.go create mode 100644 vendor/github.com/ory/fosite/client.go create mode 100644 vendor/github.com/ory/fosite/client_authentication.go create mode 100644 vendor/github.com/ory/fosite/client_authentication_jwks_strategy.go create mode 100644 vendor/github.com/ory/fosite/client_manager.go create mode 100644 vendor/github.com/ory/fosite/compose/compose.go create mode 100644 vendor/github.com/ory/fosite/compose/compose_oauth2.go create mode 100644 vendor/github.com/ory/fosite/compose/compose_openid.go create mode 100644 vendor/github.com/ory/fosite/compose/compose_pkce.go create mode 100644 vendor/github.com/ory/fosite/compose/compose_strategy.go create mode 100644 vendor/github.com/ory/fosite/compose/config.go create mode 100644 vendor/github.com/ory/fosite/context.go create mode 100644 vendor/github.com/ory/fosite/errors.go create mode 100644 vendor/github.com/ory/fosite/fosite.go create mode 100644 vendor/github.com/ory/fosite/fosite.png create mode 100644 vendor/github.com/ory/fosite/generate-mocks.sh create mode 100644 vendor/github.com/ory/fosite/go.mod create mode 100644 vendor/github.com/ory/fosite/go.sum create mode 100644 vendor/github.com/ory/fosite/handler.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_auth.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_token.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_implicit.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials_storage.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_refresh.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner_storage.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/helper.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/introspector.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/introspector_jwt.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/revocation.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/revocation_storage.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/storage.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/strategy.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/strategy_hmacsha.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt.go create mode 100644 vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt_session.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/errors.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/flow_explicit_auth.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/flow_explicit_token.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/flow_hybrid.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/flow_implicit.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/flow_refresh_token.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/helper.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/storage.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/strategy.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/strategy_jwt.go create mode 100644 vendor/github.com/ory/fosite/handler/openid/validator.go create mode 100644 vendor/github.com/ory/fosite/handler/pkce/handler.go create mode 100644 vendor/github.com/ory/fosite/handler/pkce/storage.go create mode 100644 vendor/github.com/ory/fosite/hash.go create mode 100644 vendor/github.com/ory/fosite/hash_bcrypt.go create mode 100644 vendor/github.com/ory/fosite/helper.go create mode 100644 vendor/github.com/ory/fosite/introspect.go create mode 100644 vendor/github.com/ory/fosite/introspection_request_handler.go create mode 100644 vendor/github.com/ory/fosite/introspection_response_writer.go create mode 100644 vendor/github.com/ory/fosite/oauth2.go create mode 100644 vendor/github.com/ory/fosite/request.go create mode 100644 vendor/github.com/ory/fosite/revoke_handler.go create mode 100644 vendor/github.com/ory/fosite/scope_strategy.go create mode 100644 vendor/github.com/ory/fosite/session.go create mode 100644 vendor/github.com/ory/fosite/storage.go create mode 100644 vendor/github.com/ory/fosite/storage/memory.go create mode 100644 vendor/github.com/ory/fosite/storage/transactional.go create mode 100644 vendor/github.com/ory/fosite/token/hmac/bytes.go create mode 100644 vendor/github.com/ory/fosite/token/hmac/hmacsha.go create mode 100644 vendor/github.com/ory/fosite/token/jwt/claims.go create mode 100644 vendor/github.com/ory/fosite/token/jwt/claims_id_token.go create mode 100644 vendor/github.com/ory/fosite/token/jwt/claims_jwt.go create mode 100644 vendor/github.com/ory/fosite/token/jwt/header.go create mode 100644 vendor/github.com/ory/fosite/token/jwt/jwt.go create mode 100644 vendor/github.com/ory/fosite/tools.go create mode 100644 vendor/github.com/ory/go-acc/.gitignore create mode 100644 vendor/github.com/ory/go-acc/.travis.yml create mode 100644 vendor/github.com/ory/go-acc/CONTRIBUTING.md create mode 100644 vendor/github.com/ory/go-acc/LICENSE create mode 100644 vendor/github.com/ory/go-acc/README.md create mode 100644 vendor/github.com/ory/go-acc/cmd/root.go create mode 100644 vendor/github.com/ory/go-acc/coverage.txt create mode 100644 vendor/github.com/ory/go-acc/go.mod create mode 100644 vendor/github.com/ory/go-acc/go.sum create mode 100644 vendor/github.com/ory/go-acc/main.go create mode 100644 vendor/github.com/ory/go-convenience/LICENSE create mode 100644 vendor/github.com/ory/go-convenience/stringslice/filter.go create mode 100644 vendor/github.com/ory/go-convenience/stringslice/has.go create mode 100644 vendor/github.com/ory/go-convenience/stringslice/merge.go create mode 100644 vendor/github.com/ory/go-convenience/stringslice/unique.go create mode 100644 vendor/github.com/ory/go-convenience/stringsx/coalesce.go create mode 100644 vendor/github.com/ory/go-convenience/stringsx/split.go create mode 100644 vendor/github.com/ory/x/LICENSE create mode 100644 vendor/github.com/ory/x/cmdx/args.go create mode 100644 vendor/github.com/ory/x/cmdx/env.go create mode 100644 vendor/github.com/ory/x/cmdx/helper.go create mode 100644 vendor/github.com/ory/x/cmdx/version.go create mode 100644 vendor/github.com/ory/x/flagx/flagx.go create mode 100644 vendor/github.com/pborman/uuid/.travis.yml create mode 100644 vendor/github.com/pborman/uuid/CONTRIBUTING.md create mode 100644 vendor/github.com/pborman/uuid/CONTRIBUTORS create mode 100644 vendor/github.com/pborman/uuid/LICENSE create mode 100644 vendor/github.com/pborman/uuid/README.md create mode 100644 vendor/github.com/pborman/uuid/dce.go create mode 100644 vendor/github.com/pborman/uuid/doc.go create mode 100644 vendor/github.com/pborman/uuid/go.mod create mode 100644 vendor/github.com/pborman/uuid/go.sum create mode 100644 vendor/github.com/pborman/uuid/hash.go create mode 100644 vendor/github.com/pborman/uuid/marshal.go create mode 100644 vendor/github.com/pborman/uuid/node.go create mode 100644 vendor/github.com/pborman/uuid/sql.go create mode 100644 vendor/github.com/pborman/uuid/time.go create mode 100644 vendor/github.com/pborman/uuid/util.go create mode 100644 vendor/github.com/pborman/uuid/uuid.go create mode 100644 vendor/github.com/pborman/uuid/version1.go create mode 100644 vendor/github.com/pborman/uuid/version4.go create mode 100644 vendor/github.com/satori/go.uuid/.travis.yml create mode 100644 vendor/github.com/satori/go.uuid/LICENSE create mode 100644 vendor/github.com/satori/go.uuid/README.md create mode 100644 vendor/github.com/satori/go.uuid/codec.go create mode 100644 vendor/github.com/satori/go.uuid/generator.go create mode 100644 vendor/github.com/satori/go.uuid/sql.go create mode 100644 vendor/github.com/satori/go.uuid/uuid.go create mode 100644 vendor/github.com/sirupsen/logrus/.gitignore create mode 100644 vendor/github.com/sirupsen/logrus/.travis.yml create mode 100644 vendor/github.com/sirupsen/logrus/CHANGELOG.md create mode 100644 vendor/github.com/sirupsen/logrus/LICENSE create mode 100644 vendor/github.com/sirupsen/logrus/README.md create mode 100644 vendor/github.com/sirupsen/logrus/alt_exit.go create mode 100644 vendor/github.com/sirupsen/logrus/appveyor.yml create mode 100644 vendor/github.com/sirupsen/logrus/doc.go create mode 100644 vendor/github.com/sirupsen/logrus/entry.go create mode 100644 vendor/github.com/sirupsen/logrus/exported.go create mode 100644 vendor/github.com/sirupsen/logrus/formatter.go create mode 100644 vendor/github.com/sirupsen/logrus/go.mod create mode 100644 vendor/github.com/sirupsen/logrus/go.sum create mode 100644 vendor/github.com/sirupsen/logrus/hooks.go create mode 100644 vendor/github.com/sirupsen/logrus/json_formatter.go create mode 100644 vendor/github.com/sirupsen/logrus/logger.go create mode 100644 vendor/github.com/sirupsen/logrus/logrus.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_appengine.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_bsd.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_solaris.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_unix.go create mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_windows.go create mode 100644 vendor/github.com/sirupsen/logrus/text_formatter.go create mode 100644 vendor/github.com/sirupsen/logrus/writer.go create mode 100644 vendor/golang.org/x/crypto/ed25519/ed25519.go create mode 100644 vendor/golang.org/x/crypto/ed25519/ed25519_go113.go create mode 100644 vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go create mode 100644 vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go create mode 100644 vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 vendor/golang.org/x/tools/cover/profile.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/.gitcookies.sh.enc create mode 100644 vendor/gopkg.in/square/go-jose.v2/.gitignore create mode 100644 vendor/gopkg.in/square/go-jose.v2/.travis.yml create mode 100644 vendor/gopkg.in/square/go-jose.v2/BUG-BOUNTY.md create mode 100644 vendor/gopkg.in/square/go-jose.v2/CONTRIBUTING.md create mode 100644 vendor/gopkg.in/square/go-jose.v2/LICENSE create mode 100644 vendor/gopkg.in/square/go-jose.v2/README.md create mode 100644 vendor/gopkg.in/square/go-jose.v2/asymmetric.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/cipher/concat_kdf.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/cipher/key_wrap.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/crypter.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/doc.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/encoding.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/LICENSE create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/README.md create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/decode.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/encode.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/indent.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/scanner.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/stream.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/json/tags.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwe.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jwk.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/jws.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/opaque.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/shared.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/signing.go create mode 100644 vendor/gopkg.in/square/go-jose.v2/symmetric.go diff --git a/vendor/github.com/google/uuid/.travis.yml b/vendor/github.com/google/uuid/.travis.yml new file mode 100644 index 0000000000..d8156a60ba --- /dev/null +++ b/vendor/github.com/google/uuid/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.4.3 + - 1.5.3 + - tip + +script: + - go test -v ./... diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md new file mode 100644 index 0000000000..04fdf09f13 --- /dev/null +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -0,0 +1,10 @@ +# How to contribute + +We definitely welcome patches and contribution to this project! + +### Legal requirements + +In order to protect both you and ourselves, you will need to sign the +[Contributor License Agreement](https://cla.developers.google.com/clas). + +You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS new file mode 100644 index 0000000000..b4bb97f6bc --- /dev/null +++ b/vendor/github.com/google/uuid/CONTRIBUTORS @@ -0,0 +1,9 @@ +Paul Borman +bmatsuo +shawnps +theory +jboverfelt +dsymonds +cd1 +wallclockbuilder +dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE new file mode 100644 index 0000000000..5dc68268d9 --- /dev/null +++ b/vendor/github.com/google/uuid/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009,2014 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md new file mode 100644 index 0000000000..9d92c11f16 --- /dev/null +++ b/vendor/github.com/google/uuid/README.md @@ -0,0 +1,19 @@ +# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master) +The uuid package generates and inspects UUIDs based on +[RFC 4122](http://tools.ietf.org/html/rfc4122) +and DCE 1.1: Authentication and Security Services. + +This package is based on the github.com/pborman/uuid package (previously named +code.google.com/p/go-uuid). It differs from these earlier packages in that +a UUID is a 16 byte array rather than a byte slice. One loss due to this +change is the ability to represent an invalid UUID (vs a NIL UUID). + +###### Install +`go get github.com/google/uuid` + +###### Documentation +[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid) + +Full `go doc` style documentation for the package can be viewed online without +installing this package by using the GoDoc site here: +http://godoc.org/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go new file mode 100644 index 0000000000..fa820b9d30 --- /dev/null +++ b/vendor/github.com/google/uuid/dce.go @@ -0,0 +1,80 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "fmt" + "os" +) + +// A Domain represents a Version 2 domain +type Domain byte + +// Domain constants for DCE Security (Version 2) UUIDs. +const ( + Person = Domain(0) + Group = Domain(1) + Org = Domain(2) +) + +// NewDCESecurity returns a DCE Security (Version 2) UUID. +// +// The domain should be one of Person, Group or Org. +// On a POSIX system the id should be the users UID for the Person +// domain and the users GID for the Group. The meaning of id for +// the domain Org or on non-POSIX systems is site defined. +// +// For a given domain/id pair the same token may be returned for up to +// 7 minutes and 10 seconds. +func NewDCESecurity(domain Domain, id uint32) (UUID, error) { + uuid, err := NewUUID() + if err == nil { + uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 + uuid[9] = byte(domain) + binary.BigEndian.PutUint32(uuid[0:], id) + } + return uuid, err +} + +// NewDCEPerson returns a DCE Security (Version 2) UUID in the person +// domain with the id returned by os.Getuid. +// +// NewDCESecurity(Person, uint32(os.Getuid())) +func NewDCEPerson() (UUID, error) { + return NewDCESecurity(Person, uint32(os.Getuid())) +} + +// NewDCEGroup returns a DCE Security (Version 2) UUID in the group +// domain with the id returned by os.Getgid. +// +// NewDCESecurity(Group, uint32(os.Getgid())) +func NewDCEGroup() (UUID, error) { + return NewDCESecurity(Group, uint32(os.Getgid())) +} + +// Domain returns the domain for a Version 2 UUID. Domains are only defined +// for Version 2 UUIDs. +func (uuid UUID) Domain() Domain { + return Domain(uuid[9]) +} + +// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 +// UUIDs. +func (uuid UUID) ID() uint32 { + return binary.BigEndian.Uint32(uuid[0:4]) +} + +func (d Domain) String() string { + switch d { + case Person: + return "Person" + case Group: + return "Group" + case Org: + return "Org" + } + return fmt.Sprintf("Domain%d", int(d)) +} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go new file mode 100644 index 0000000000..5b8a4b9af8 --- /dev/null +++ b/vendor/github.com/google/uuid/doc.go @@ -0,0 +1,12 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package uuid generates and inspects UUIDs. +// +// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security +// Services. +// +// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to +// maps or compared directly. +package uuid diff --git a/vendor/github.com/google/uuid/go.mod b/vendor/github.com/google/uuid/go.mod new file mode 100644 index 0000000000..fc84cd79d4 --- /dev/null +++ b/vendor/github.com/google/uuid/go.mod @@ -0,0 +1 @@ +module github.com/google/uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go new file mode 100644 index 0000000000..b174616315 --- /dev/null +++ b/vendor/github.com/google/uuid/hash.go @@ -0,0 +1,53 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "crypto/md5" + "crypto/sha1" + "hash" +) + +// Well known namespace IDs and UUIDs +var ( + NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) + Nil UUID // empty UUID, all zeros +) + +// NewHash returns a new UUID derived from the hash of space concatenated with +// data generated by h. The hash should be at least 16 byte in length. The +// first 16 bytes of the hash are used to form the UUID. The version of the +// UUID will be the lower 4 bits of version. NewHash is used to implement +// NewMD5 and NewSHA1. +func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { + h.Reset() + h.Write(space[:]) + h.Write(data) + s := h.Sum(nil) + var uuid UUID + copy(uuid[:], s) + uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) + uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant + return uuid +} + +// NewMD5 returns a new MD5 (Version 3) UUID based on the +// supplied name space and data. It is the same as calling: +// +// NewHash(md5.New(), space, data, 3) +func NewMD5(space UUID, data []byte) UUID { + return NewHash(md5.New(), space, data, 3) +} + +// NewSHA1 returns a new SHA1 (Version 5) UUID based on the +// supplied name space and data. It is the same as calling: +// +// NewHash(sha1.New(), space, data, 5) +func NewSHA1(space UUID, data []byte) UUID { + return NewHash(sha1.New(), space, data, 5) +} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go new file mode 100644 index 0000000000..7f9e0c6c0e --- /dev/null +++ b/vendor/github.com/google/uuid/marshal.go @@ -0,0 +1,37 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "fmt" + +// MarshalText implements encoding.TextMarshaler. +func (uuid UUID) MarshalText() ([]byte, error) { + var js [36]byte + encodeHex(js[:], uuid) + return js[:], nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (uuid *UUID) UnmarshalText(data []byte) error { + id, err := ParseBytes(data) + if err == nil { + *uuid = id + } + return err +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (uuid UUID) MarshalBinary() ([]byte, error) { + return uuid[:], nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (uuid *UUID) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + copy(uuid[:], data) + return nil +} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go new file mode 100644 index 0000000000..3e4e90dc44 --- /dev/null +++ b/vendor/github.com/google/uuid/node.go @@ -0,0 +1,89 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "sync" +) + +var ( + nodeMu sync.Mutex + ifname string // name of interface being used + nodeID [6]byte // hardware for version 1 UUIDs + zeroID [6]byte // nodeID with only 0's +) + +// NodeInterface returns the name of the interface from which the NodeID was +// derived. The interface "user" is returned if the NodeID was set by +// SetNodeID. +func NodeInterface() string { + defer nodeMu.Unlock() + nodeMu.Lock() + return ifname +} + +// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. +// If name is "" then the first usable interface found will be used or a random +// Node ID will be generated. If a named interface cannot be found then false +// is returned. +// +// SetNodeInterface never fails when name is "". +func SetNodeInterface(name string) bool { + defer nodeMu.Unlock() + nodeMu.Lock() + return setNodeInterface(name) +} + +func setNodeInterface(name string) bool { + iname, addr := getHardwareInterface(name) // null implementation for js + if iname != "" && addr != nil { + ifname = iname + copy(nodeID[:], addr) + return true + } + + // We found no interfaces with a valid hardware address. If name + // does not specify a specific interface generate a random Node ID + // (section 4.1.6) + if name == "" { + randomBits(nodeID[:]) + return true + } + return false +} + +// NodeID returns a slice of a copy of the current Node ID, setting the Node ID +// if not already set. +func NodeID() []byte { + defer nodeMu.Unlock() + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + nid := nodeID + return nid[:] +} + +// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes +// of id are used. If id is less than 6 bytes then false is returned and the +// Node ID is not set. +func SetNodeID(id []byte) bool { + if len(id) < 6 { + return false + } + defer nodeMu.Unlock() + nodeMu.Lock() + copy(nodeID[:], id) + ifname = "user" + return true +} + +// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is +// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) NodeID() []byte { + var node [6]byte + copy(node[:], uuid[10:]) + return node[:] +} diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go new file mode 100644 index 0000000000..24b78edc90 --- /dev/null +++ b/vendor/github.com/google/uuid/node_js.go @@ -0,0 +1,12 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js + +package uuid + +// getHardwareInterface returns nil values for the JS version of the code. +// This remvoves the "net" dependency, because it is not used in the browser. +// Using the "net" library inflates the size of the transpiled JS code by 673k bytes. +func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go new file mode 100644 index 0000000000..0cbbcddbd6 --- /dev/null +++ b/vendor/github.com/google/uuid/node_net.go @@ -0,0 +1,33 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !js + +package uuid + +import "net" + +var interfaces []net.Interface // cached list of interfaces + +// getHardwareInterface returns the name and hardware address of interface name. +// If name is "" then the name and hardware address of one of the system's +// interfaces is returned. If no interfaces are found (name does not exist or +// there are no interfaces) then "", nil is returned. +// +// Only addresses of at least 6 bytes are returned. +func getHardwareInterface(name string) (string, []byte) { + if interfaces == nil { + var err error + interfaces, err = net.Interfaces() + if err != nil { + return "", nil + } + } + for _, ifs := range interfaces { + if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { + return ifs.Name, ifs.HardwareAddr + } + } + return "", nil +} diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go new file mode 100644 index 0000000000..f326b54db3 --- /dev/null +++ b/vendor/github.com/google/uuid/sql.go @@ -0,0 +1,59 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "database/sql/driver" + "fmt" +) + +// Scan implements sql.Scanner so UUIDs can be read from databases transparently +// Currently, database types that map to string and []byte are supported. Please +// consult database-specific driver documentation for matching types. +func (uuid *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case nil: + return nil + + case string: + // if an empty UUID comes from a table, we return a null UUID + if src == "" { + return nil + } + + // see Parse for required string format + u, err := Parse(src) + if err != nil { + return fmt.Errorf("Scan: %v", err) + } + + *uuid = u + + case []byte: + // if an empty UUID comes from a table, we return a null UUID + if len(src) == 0 { + return nil + } + + // assumes a simple slice of bytes if 16 bytes + // otherwise attempts to parse + if len(src) != 16 { + return uuid.Scan(string(src)) + } + copy((*uuid)[:], src) + + default: + return fmt.Errorf("Scan: unable to scan type %T into UUID", src) + } + + return nil +} + +// Value implements sql.Valuer so that UUIDs can be written to databases +// transparently. Currently, UUIDs map to strings. Please consult +// database-specific driver documentation for matching types. +func (uuid UUID) Value() (driver.Value, error) { + return uuid.String(), nil +} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go new file mode 100644 index 0000000000..e6ef06cdc8 --- /dev/null +++ b/vendor/github.com/google/uuid/time.go @@ -0,0 +1,123 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "sync" + "time" +) + +// A Time represents a time as the number of 100's of nanoseconds since 15 Oct +// 1582. +type Time int64 + +const ( + lillian = 2299160 // Julian day of 15 Oct 1582 + unix = 2440587 // Julian day of 1 Jan 1970 + epoch = unix - lillian // Days between epochs + g1582 = epoch * 86400 // seconds between epochs + g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs +) + +var ( + timeMu sync.Mutex + lasttime uint64 // last time we returned + clockSeq uint16 // clock sequence for this run + + timeNow = time.Now // for testing +) + +// UnixTime converts t the number of seconds and nanoseconds using the Unix +// epoch of 1 Jan 1970. +func (t Time) UnixTime() (sec, nsec int64) { + sec = int64(t - g1582ns100) + nsec = (sec % 10000000) * 100 + sec /= 10000000 + return sec, nsec +} + +// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and +// clock sequence as well as adjusting the clock sequence as needed. An error +// is returned if the current time cannot be determined. +func GetTime() (Time, uint16, error) { + defer timeMu.Unlock() + timeMu.Lock() + return getTime() +} + +func getTime() (Time, uint16, error) { + t := timeNow() + + // If we don't have a clock sequence already, set one. + if clockSeq == 0 { + setClockSequence(-1) + } + now := uint64(t.UnixNano()/100) + g1582ns100 + + // If time has gone backwards with this clock sequence then we + // increment the clock sequence + if now <= lasttime { + clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 + } + lasttime = now + return Time(now), clockSeq, nil +} + +// ClockSequence returns the current clock sequence, generating one if not +// already set. The clock sequence is only used for Version 1 UUIDs. +// +// The uuid package does not use global static storage for the clock sequence or +// the last time a UUID was generated. Unless SetClockSequence is used, a new +// random clock sequence is generated the first time a clock sequence is +// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) +func ClockSequence() int { + defer timeMu.Unlock() + timeMu.Lock() + return clockSequence() +} + +func clockSequence() int { + if clockSeq == 0 { + setClockSequence(-1) + } + return int(clockSeq & 0x3fff) +} + +// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to +// -1 causes a new sequence to be generated. +func SetClockSequence(seq int) { + defer timeMu.Unlock() + timeMu.Lock() + setClockSequence(seq) +} + +func setClockSequence(seq int) { + if seq == -1 { + var b [2]byte + randomBits(b[:]) // clock sequence + seq = int(b[0])<<8 | int(b[1]) + } + oldSeq := clockSeq + clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant + if oldSeq != clockSeq { + lasttime = 0 + } +} + +// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in +// uuid. The time is only defined for version 1 and 2 UUIDs. +func (uuid UUID) Time() Time { + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + return Time(time) +} + +// ClockSequence returns the clock sequence encoded in uuid. +// The clock sequence is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) ClockSequence() int { + return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff +} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go new file mode 100644 index 0000000000..5ea6c73780 --- /dev/null +++ b/vendor/github.com/google/uuid/util.go @@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// randomBits completely fills slice b with random data. +func randomBits(b []byte) { + if _, err := io.ReadFull(rander, b); err != nil { + panic(err.Error()) // rand should never fail + } +} + +// xvalues returns the value of a byte as a hexadecimal digit or 255. +var xvalues = [256]byte{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +} + +// xtob converts hex characters x1 and x2 into a byte. +func xtob(x1, x2 byte) (byte, bool) { + b1 := xvalues[x1] + b2 := xvalues[x2] + return (b1 << 4) | b2, b1 != 255 && b2 != 255 +} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go new file mode 100644 index 0000000000..524404cc52 --- /dev/null +++ b/vendor/github.com/google/uuid/uuid.go @@ -0,0 +1,245 @@ +// Copyright 2018 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "errors" + "fmt" + "io" + "strings" +) + +// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC +// 4122. +type UUID [16]byte + +// A Version represents a UUID's version. +type Version byte + +// A Variant represents a UUID's variant. +type Variant byte + +// Constants returned by Variant. +const ( + Invalid = Variant(iota) // Invalid UUID + RFC4122 // The variant specified in RFC4122 + Reserved // Reserved, NCS backward compatibility. + Microsoft // Reserved, Microsoft Corporation backward compatibility. + Future // Reserved for future definition. +) + +var rander = rand.Reader // random function + +// Parse decodes s into a UUID or returns an error. Both the standard UUID +// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the +// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex +// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +func Parse(s string) (UUID, error) { + var uuid UUID + switch len(s) { + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36: + + // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36 + 9: + if strings.ToLower(s[:9]) != "urn:uuid:" { + return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + case 36 + 2: + s = s[1:] + + // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + case 32: + var ok bool + for i := range uuid { + uuid[i], ok = xtob(s[i*2], s[i*2+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + } + return uuid, nil + default: + return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) + } + // s is now at least 36 bytes long + // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return uuid, errors.New("invalid UUID format") + } + for i, x := range [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34} { + v, ok := xtob(s[x], s[x+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + uuid[i] = v + } + return uuid, nil +} + +// ParseBytes is like Parse, except it parses a byte slice instead of a string. +func ParseBytes(b []byte) (UUID, error) { + var uuid UUID + switch len(b) { + case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { + return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) + } + b = b[9:] + case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + b = b[1:] + case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + var ok bool + for i := 0; i < 32; i += 2 { + uuid[i/2], ok = xtob(b[i], b[i+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + } + return uuid, nil + default: + return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) + } + // s is now at least 36 bytes long + // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { + return uuid, errors.New("invalid UUID format") + } + for i, x := range [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34} { + v, ok := xtob(b[x], b[x+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + uuid[i] = v + } + return uuid, nil +} + +// MustParse is like Parse but panics if the string cannot be parsed. +// It simplifies safe initialization of global variables holding compiled UUIDs. +func MustParse(s string) UUID { + uuid, err := Parse(s) + if err != nil { + panic(`uuid: Parse(` + s + `): ` + err.Error()) + } + return uuid +} + +// FromBytes creates a new UUID from a byte slice. Returns an error if the slice +// does not have a length of 16. The bytes are copied from the slice. +func FromBytes(b []byte) (uuid UUID, err error) { + err = uuid.UnmarshalBinary(b) + return uuid, err +} + +// Must returns uuid if err is nil and panics otherwise. +func Must(uuid UUID, err error) UUID { + if err != nil { + panic(err) + } + return uuid +} + +// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// , or "" if uuid is invalid. +func (uuid UUID) String() string { + var buf [36]byte + encodeHex(buf[:], uuid) + return string(buf[:]) +} + +// URN returns the RFC 2141 URN form of uuid, +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. +func (uuid UUID) URN() string { + var buf [36 + 9]byte + copy(buf[:], "urn:uuid:") + encodeHex(buf[9:], uuid) + return string(buf[:]) +} + +func encodeHex(dst []byte, uuid UUID) { + hex.Encode(dst, uuid[:4]) + dst[8] = '-' + hex.Encode(dst[9:13], uuid[4:6]) + dst[13] = '-' + hex.Encode(dst[14:18], uuid[6:8]) + dst[18] = '-' + hex.Encode(dst[19:23], uuid[8:10]) + dst[23] = '-' + hex.Encode(dst[24:], uuid[10:]) +} + +// Variant returns the variant encoded in uuid. +func (uuid UUID) Variant() Variant { + switch { + case (uuid[8] & 0xc0) == 0x80: + return RFC4122 + case (uuid[8] & 0xe0) == 0xc0: + return Microsoft + case (uuid[8] & 0xe0) == 0xe0: + return Future + default: + return Reserved + } +} + +// Version returns the version of uuid. +func (uuid UUID) Version() Version { + return Version(uuid[6] >> 4) +} + +func (v Version) String() string { + if v > 15 { + return fmt.Sprintf("BAD_VERSION_%d", v) + } + return fmt.Sprintf("VERSION_%d", v) +} + +func (v Variant) String() string { + switch v { + case RFC4122: + return "RFC4122" + case Reserved: + return "Reserved" + case Microsoft: + return "Microsoft" + case Future: + return "Future" + case Invalid: + return "Invalid" + } + return fmt.Sprintf("BadVariant%d", int(v)) +} + +// SetRand sets the random number generator to r, which implements io.Reader. +// If r.Read returns an error when the package requests random data then +// a panic will be issued. +// +// Calling SetRand with nil sets the random number generator to the default +// generator. +func SetRand(r io.Reader) { + if r == nil { + rander = rand.Reader + return + } + rander = r +} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go new file mode 100644 index 0000000000..199a1ac654 --- /dev/null +++ b/vendor/github.com/google/uuid/version1.go @@ -0,0 +1,44 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" +) + +// NewUUID returns a Version 1 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewUUID returns nil. If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewUUID returns nil and an error. +// +// In most cases, New should be used. +func NewUUID() (UUID, error) { + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + nodeMu.Unlock() + + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + timeLow := uint32(now & 0xffffffff) + timeMid := uint16((now >> 32) & 0xffff) + timeHi := uint16((now >> 48) & 0x0fff) + timeHi |= 0x1000 // Version 1 + + binary.BigEndian.PutUint32(uuid[0:], timeLow) + binary.BigEndian.PutUint16(uuid[4:], timeMid) + binary.BigEndian.PutUint16(uuid[6:], timeHi) + binary.BigEndian.PutUint16(uuid[8:], seq) + copy(uuid[10:], nodeID[:]) + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go new file mode 100644 index 0000000000..84af91c9f5 --- /dev/null +++ b/vendor/github.com/google/uuid/version4.go @@ -0,0 +1,38 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "io" + +// New creates a new random UUID or panics. New is equivalent to +// the expression +// +// uuid.Must(uuid.NewRandom()) +func New() UUID { + return Must(NewRandom()) +} + +// NewRandom returns a Random (Version 4) UUID. +// +// The strength of the UUIDs is based on the strength of the crypto/rand +// package. +// +// A note about uniqueness derived from the UUID Wikipedia entry: +// +// Randomly generated UUIDs have 122 random bits. One's annual risk of being +// hit by a meteorite is estimated to be one chance in 17 billion, that +// means the probability is about 0.00000000006 (6 × 10−11), +// equivalent to the odds of creating a few tens of trillions of UUIDs in a +// year and having one duplicate. +func NewRandom() (UUID, error) { + var uuid UUID + _, err := io.ReadFull(rander, uuid[:]) + if err != nil { + return Nil, err + } + uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 + uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 + return uuid, nil +} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE new file mode 100644 index 0000000000..14127cd831 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE @@ -0,0 +1,9 @@ +(The MIT License) + +Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md new file mode 100644 index 0000000000..195333e51d --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md @@ -0,0 +1,41 @@ +# Windows Terminal Sequences + +This library allow for enabling Windows terminal color support for Go. + +See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details. + +## Usage + +```go +import ( + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func main() { + sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true) +} + +``` + +## Authors + +The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de). + +We thank all the authors who provided code to this library: + +* Felix Kollmann +* Nicolas Perraut + +## License + +(The MIT License) + +Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod new file mode 100644 index 0000000000..716c613125 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod @@ -0,0 +1 @@ +module github.com/konsorten/go-windows-terminal-sequences diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go new file mode 100644 index 0000000000..ef18d8f978 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go @@ -0,0 +1,36 @@ +// +build windows + +package sequences + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll") + setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode") +) + +func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { + const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4 + + var mode uint32 + err := syscall.GetConsoleMode(syscall.Stdout, &mode) + if err != nil { + return err + } + + if enable { + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } else { + mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } + + ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode)) + if ret == 0 { + return err + } + + return nil +} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go new file mode 100644 index 0000000000..df61a6f2f6 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go @@ -0,0 +1,11 @@ +// +build linux darwin + +package sequences + +import ( + "fmt" +) + +func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error { + return fmt.Errorf("windows only package") +} diff --git a/vendor/github.com/mattn/goveralls/.gitignore b/vendor/github.com/mattn/goveralls/.gitignore new file mode 100644 index 0000000000..705db8c8d0 --- /dev/null +++ b/vendor/github.com/mattn/goveralls/.gitignore @@ -0,0 +1,2 @@ +*~ +/goveralls diff --git a/vendor/github.com/mattn/goveralls/.travis.yml b/vendor/github.com/mattn/goveralls/.travis.yml new file mode 100644 index 0000000000..ccd11105c4 --- /dev/null +++ b/vendor/github.com/mattn/goveralls/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: + - '1.7' + - '1.8' + - '1.9' + - '1.10' + - '1.11' + - '1.12' + - '1.13' +before_install: + - go get ./... + - go install . +script: + - goveralls diff --git a/vendor/github.com/mattn/goveralls/README.md b/vendor/github.com/mattn/goveralls/README.md new file mode 100644 index 0000000000..ddf947dfc0 --- /dev/null +++ b/vendor/github.com/mattn/goveralls/README.md @@ -0,0 +1,266 @@ +goveralls +========= + +[Go](http://golang.org) integration for [Coveralls.io](http://coveralls.io) +continuous code coverage tracking system. + +# Installation + +`goveralls` requires a working Go installation (Go-1.2 or higher). + +```bash +$ go get github.com/mattn/goveralls +``` + + +# Usage + +First you will need an API token. It is found at the bottom of your +repository's page when you are logged in to Coveralls.io. Each repo has its +own token. + +```bash +$ cd $GOPATH/src/github.com/yourusername/yourpackage +$ goveralls -repotoken your_repos_coveralls_token +``` + +You can set the environment variable `$COVERALLS_TOKEN` to your token so you do +not have to specify it at each invocation. + + +You can also run this reporter for multiple passes with the flag `-parallel` or +by setting the environment variable `COVERALLS_PARALLEL=true` (see [coveralls +docs](https://docs.coveralls.io/parallel-build-webhook) for more details. + + +# Continuous Integration + +There is no need to run `go test` separately, as `goveralls` runs the entire +test suite. + +## Github Actions + +[shogo82148/actions-goveralls](https://github.com/marketplace/actions/actions-goveralls) is available on GitHub Marketplace. +It provides the shorthand of the GitHub Actions YAML configure. + +```yaml +name: Quality +on: [push, pull_request] +jobs: + test: + name: Test with Coverage + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: '1.13' + - name: Check out code + uses: actions/checkout@v2 + - name: Install dependencies + run: | + go mod download + - name: Run Unit tests + run: | + go test -race -covermode atomic -coverprofile=profile.cov ./... + - name: Send coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + GO111MODULE=off go get github.com/mattn/goveralls + $(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github + # or use shogo82148/actions-goveralls + # - name: Send coverage + # uses: shogo82148/actions-goveralls@v1 + # with: + # path-to-profile: profile.cov +``` + +### Test with Legacy GOPATH mode + +If you want to use Go 1.10 or earlier, you have to set `GOPATH` environment value and the working directory. +See for more detail. + +Here is an example for testing `example.com/owner/repo` package. + +```yaml +name: Quality +on: [push, pull_request] +jobs: + test: + name: Test with Coverage + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: '1.10' + + # add this step + - name: Set up GOPATH + run: | + echo "::set-env name=GOPATH::${{ github.workspace }}" + echo "::add-path::${{ github.workspace }}/bin" + + - name: Check out code + uses: actions/checkout@v2 + with: + path: src/example.com/owner/repo # add this + - name: Run Unit tests + run: | + go test -race -covermode atomic -coverprofile=profile.cov ./... + working-directory: src/example.com/owner/repo # add this + - name: Send coverage + env: + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + GO111MODULE=off go get github.com/mattn/goveralls + $(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github + working-directory: src/example.com/owner/repo # add this +``` + +## Travis CI + +### GitHub Integration + +Enable Travis-CI on your github repository settings. + +For a **public** github repository put bellow's `.travis.yml`. + +```yml +language: go +go: + - tip +before_install: + - go get github.com/mattn/goveralls +script: + - $GOPATH/bin/goveralls -service=travis-ci +``` + +For a **public** github repository, it is not necessary to define your repository key (`COVERALLS_TOKEN`). + +For a **private** github repository put bellow's `.travis.yml`. If you use **travis pro**, you need to specify `-service=travis-pro` instead of `-service=travis-ci`. + +```yml +language: go +go: + - tip +before_install: + - go get github.com/mattn/goveralls +script: + - $GOPATH/bin/goveralls -service=travis-pro +``` + +Store your Coveralls API token in `Environment variables`. + +``` +COVERALLS_TOKEN = your_token_goes_here +``` + +or you can store token using [travis encryption keys](https://docs.travis-ci.com/user/encryption-keys/). Note that this is the token provided in the page for that specific repository on Coveralls. This is *not* one that was created from the "Personal API Tokens" area under your Coveralls account settings. + +``` +$ gem install travis +$ travis encrypt COVERALLS_TOKEN=your_token_goes_here --add env.global +``` + +travis will add `env` block as following example: + +```yml +env: + global: + secure: xxxxxxxxxxxxx +``` + +### For others: + +``` +$ go get github.com/mattn/goveralls +$ go test -covermode=count -coverprofile=profile.cov +$ goveralls -coverprofile=profile.cov -service=travis-ci +``` + +## Drone.io + +Store your Coveralls API token in `Environment Variables`: + +``` +COVERALLS_TOKEN=your_token_goes_here +``` + +Replace the `go test` line in your `Commands` with these lines: + +``` +$ go get github.com/mattn/goveralls +$ goveralls -service drone.io +``` + +`goveralls` automatically use the environment variable `COVERALLS_TOKEN` as the +default value for `-repotoken`. + +You can use the `-v` flag to see verbose output from the test suite: + +``` +$ goveralls -v -service drone.io +``` + +## CircleCI + +Store your Coveralls API token as an [Environment Variable](https://circleci.com/docs/environment-variables). + +In your `circle.yml` add the following commands under the `test` section. + +```yml +test: + pre: + - go get github.com/mattn/goveralls + override: + - go test -v -cover -race -coverprofile=/home/ubuntu/coverage.out + post: + - /home/ubuntu/.go_workspace/bin/goveralls -coverprofile=/home/ubuntu/coverage.out -service=circle-ci -repotoken=$COVERALLS_TOKEN +``` + +For more information, See https://coveralls.zendesk.com/hc/en-us/articles/201342809-Go + +## Semaphore + +Store your Coveralls API token in `Environment Variables`: + +``` +COVERALLS_TOKEN=your_token_goes_here +``` + +More instructions on how to do this can be found in the [Semaphore documentation](https://semaphoreci.com/docs/exporting-environment-variables.html). + +Replace the `go test` line in your `Commands` with these lines: + +``` +$ go get github.com/mattn/goveralls +$ goveralls -service semaphore +``` + +`goveralls` automatically use the environment variable `COVERALLS_TOKEN` as the +default value for `-repotoken`. + +You can use the `-v` flag to see verbose output from the test suite: + +``` +$ goveralls -v -service semaphore +``` + +## Coveralls Enterprise + +If you are using Coveralls Enterprise and have a self-signed certificate, you need to skip certificate verification: + +```shell +$ goveralls -insecure +``` + +# Authors + +* Yasuhiro Matsumoto (a.k.a. mattn) +* haya14busa + +# License + +under the MIT License: http://mattn.mit-license.org/2016 diff --git a/vendor/github.com/mattn/goveralls/gitinfo.go b/vendor/github.com/mattn/goveralls/gitinfo.go new file mode 100644 index 0000000000..0992603e4c --- /dev/null +++ b/vendor/github.com/mattn/goveralls/gitinfo.go @@ -0,0 +1,124 @@ +package main + +import ( + "bytes" + "log" + "os" + "os/exec" + "strings" +) + +// A Head object encapsulates information about the HEAD revision of a git repo. +type Head struct { + ID string `json:"id"` + AuthorName string `json:"author_name,omitempty"` + AuthorEmail string `json:"author_email,omitempty"` + CommitterName string `json:"committer_name,omitempty"` + CommitterEmail string `json:"committer_email,omitempty"` + Message string `json:"message"` +} + +// A Git object encapsulates information about a git repo. +type Git struct { + Head Head `json:"head"` + Branch string `json:"branch"` +} + +// collectGitInfo runs several git commands to compose a Git object. +func collectGitInfo(ref string) *Git { + gitCmds := map[string][]string{ + "id": {"rev-parse", ref}, + "branch": {"branch", "--format", "%(refname:short)", "--contains", ref}, + "aname": {"show", "-s", "--format=%aN", ref}, + "aemail": {"show", "-s", "--format=%aE", ref}, + "cname": {"show", "-s", "--format=%cN", ref}, + "cemail": {"show", "-s", "--format=%cE", ref}, + "message": {"show", "-s", "--format=%s", ref}, + } + results := map[string]string{} + gitPath, err := exec.LookPath("git") + if err != nil { + log.Printf("fail to look path of git: %v", err) + log.Print("git information is omitted") + return nil + } + + if ref != "HEAD" { + // make sure that the commit is in the local + // e.g. shallow cloned repository + _, _ = runCommand(gitPath, "fetch", "--depth=1", "origin", ref) + // ignore errors because we don't have enough information about the origin. + } + + for key, args := range gitCmds { + if key == "branch" { + if envBranch := loadBranchFromEnv(); envBranch != "" { + results[key] = envBranch + continue + } + } + + ret, err := runCommand(gitPath, args...) + if err != nil { + log.Printf(`fail to run "%s %s": %v`, gitPath, strings.Join(args, " "), err) + log.Print("git information is omitted") + return nil + } + results[key] = ret + } + h := Head{ + ID: firstLine(results["id"]), + AuthorName: firstLine(results["aname"]), + AuthorEmail: firstLine(results["aemail"]), + CommitterName: firstLine(results["cname"]), + CommitterEmail: firstLine(results["cemail"]), + Message: results["message"], + } + g := &Git{ + Head: h, + Branch: firstLine(results["branch"]), + } + return g +} + +func runCommand(gitPath string, args ...string) (string, error) { + cmd := exec.Command(gitPath, args...) + ret, err := cmd.CombinedOutput() + if err != nil { + return "", err + } + ret = bytes.TrimRight(ret, "\n") + return string(ret), nil +} + +func firstLine(s string) string { + if idx := strings.Index(s, "\n"); idx >= 0 { + return s[:idx] + } + return s +} + +var varNames = [...]string{ + "GIT_BRANCH", + + // https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-environment-variables + "GITHUB_HEAD_REF", "GITHUB_REF", + + "CIRCLE_BRANCH", "TRAVIS_BRANCH", + "CI_BRANCH", "APPVEYOR_REPO_BRANCH", + "WERCKER_GIT_BRANCH", "DRONE_BRANCH", + "BUILDKITE_BRANCH", "BRANCH_NAME", +} + +func loadBranchFromEnv() string { + for _, varName := range varNames { + if branch := os.Getenv(varName); branch != "" { + if varName == "GITHUB_REF" { + return strings.TrimPrefix(branch, "refs/heads/") + } + return branch + } + } + + return "" +} diff --git a/vendor/github.com/mattn/goveralls/go.mod b/vendor/github.com/mattn/goveralls/go.mod new file mode 100644 index 0000000000..fcafa48886 --- /dev/null +++ b/vendor/github.com/mattn/goveralls/go.mod @@ -0,0 +1,5 @@ +module github.com/mattn/goveralls + +go 1.11 + +require golang.org/x/tools v0.0.0-20200113040837-eac381796e91 diff --git a/vendor/github.com/mattn/goveralls/go.sum b/vendor/github.com/mattn/goveralls/go.sum new file mode 100644 index 0000000000..47ea115221 --- /dev/null +++ b/vendor/github.com/mattn/goveralls/go.sum @@ -0,0 +1,17 @@ +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98 h1:tZwpOHmF1OEL9wJGSgBALnhFg/8VKjQTtctCX51GLNI= +golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2 h1:V9r/14uGBqLgNlHRYWdVqjMdWkcOHnE2KG8DwVqQSEc= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91 h1:OOkytthzFBKHY5EfEgLUabprb0LtJVkQtNxAQ02+UE4= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +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= diff --git a/vendor/github.com/mattn/goveralls/gocover.go b/vendor/github.com/mattn/goveralls/gocover.go new file mode 100644 index 0000000000..532efd998b --- /dev/null +++ b/vendor/github.com/mattn/goveralls/gocover.go @@ -0,0 +1,131 @@ +package main + +// Much of the core of this is copied from go's cover tool itself. + +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The rest is written by Dustin Sallings + +import ( + "bytes" + "fmt" + "go/build" + "io/ioutil" + "log" + "path/filepath" + "strings" + + "golang.org/x/tools/cover" +) + +func findFile(file string) (string, error) { + dir, file := filepath.Split(file) + pkg, err := build.Import(dir, ".", build.FindOnly) + if err != nil { + return "", fmt.Errorf("can't find %q: %v", file, err) + } + return filepath.Join(pkg.Dir, file), nil +} + +// mergeProfs merges profiles for same target packages. +// It assumes each profiles have same sorted FileName and Blocks. +func mergeProfs(pfss [][]*cover.Profile) []*cover.Profile { + // skip empty profiles ([no test files]) + for i := 0; i < len(pfss); i++ { + if len(pfss[i]) > 0 { + pfss = pfss[i:] + break + } + } + if len(pfss) == 0 { + return nil + } else if len(pfss) == 1 { + return pfss[0] + } + head, rest := pfss[0], pfss[1:] + ret := make([]*cover.Profile, 0, len(head)) + for i, profile := range head { + for _, ps := range rest { + // find profiles + if len(ps) == 0 { + continue + } else if len(ps) < i+1 { + continue + } else if ps[i].FileName != profile.FileName { + continue + } + profile.Blocks = mergeProfBlocks(profile.Blocks, ps[i].Blocks) + } + ret = append(ret, profile) + } + return ret +} + +func mergeProfBlocks(as, bs []cover.ProfileBlock) []cover.ProfileBlock { + if len(as) != len(bs) { + log.Fatal("Two block length should be same") + } + // cover.ProfileBlock generated by cover.ParseProfiles() is sorted by + // StartLine and StartCol, so we can use index. + ret := make([]cover.ProfileBlock, 0, len(as)) + for i, a := range as { + b := bs[i] + if a.StartLine != b.StartLine || a.StartCol != b.StartCol { + log.Fatal("Blocks are not sorted") + } + a.Count += b.Count + ret = append(ret, a) + } + return ret +} + +// toSF converts profiles to sourcefiles for coveralls. +func toSF(profs []*cover.Profile) ([]*SourceFile, error) { + var rv []*SourceFile + for _, prof := range profs { + path, err := findFile(prof.FileName) + if err != nil { + log.Fatalf("Can't find %v", err) + } + fb, err := ioutil.ReadFile(path) + if err != nil { + log.Fatalf("Error reading %v: %v", path, err) + } + sf := &SourceFile{ + Name: getCoverallsSourceFileName(path), + Source: string(fb), + Coverage: make([]interface{}, 1+bytes.Count(fb, []byte{'\n'})), + } + + for _, block := range prof.Blocks { + for i := block.StartLine; i <= block.EndLine; i++ { + count, _ := sf.Coverage[i-1].(int) + sf.Coverage[i-1] = count + block.Count + } + } + + rv = append(rv, sf) + } + + return rv, nil +} + +func parseCover(fn string) ([]*SourceFile, error) { + var pfss [][]*cover.Profile + for _, p := range strings.Split(fn, ",") { + profs, err := cover.ParseProfiles(p) + if err != nil { + return nil, fmt.Errorf("Error parsing coverage: %v", err) + } + pfss = append(pfss, profs) + } + + sourceFiles, err := toSF(mergeProfs(pfss)) + if err != nil { + return nil, err + } + + return sourceFiles, nil +} diff --git a/vendor/github.com/mattn/goveralls/goveralls.go b/vendor/github.com/mattn/goveralls/goveralls.go new file mode 100644 index 0000000000..7a2f31f906 --- /dev/null +++ b/vendor/github.com/mattn/goveralls/goveralls.go @@ -0,0 +1,508 @@ +// Copyright (c) 2013 Yasuhiro Matsumoto, Jason McVetta. +// This is Free Software, released under the MIT license. +// See http://mattn.mit-license.org/2013 for details. + +// goveralls is a Go client for Coveralls.io. +package main + +import ( + "bytes" + _ "crypto/sha512" + "crypto/tls" + "encoding/json" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" + + "golang.org/x/tools/cover" +) + +/* + https://coveralls.io/docs/api_reference +*/ + +// Flags are extra flags to the tests +type Flags []string + +// String implements flag.Value interface. +func (a *Flags) String() string { + return strings.Join(*a, ",") +} + +// Set implements flag.Value interface. +func (a *Flags) Set(value string) error { + *a = append(*a, value) + return nil +} + +var ( + extraFlags Flags + pkg = flag.String("package", "", "Go package") + verbose = flag.Bool("v", false, "Pass '-v' argument to 'go test' and output to stdout") + race = flag.Bool("race", false, "Pass '-race' argument to 'go test'") + debug = flag.Bool("debug", false, "Enable debug output") + coverprof = flag.String("coverprofile", "", "If supplied, use a go cover profile (comma separated)") + covermode = flag.String("covermode", "count", "sent as covermode argument to go test") + repotoken = flag.String("repotoken", os.Getenv("COVERALLS_TOKEN"), "Repository Token on coveralls") + reponame = flag.String("reponame", "", "Repository name") + parallel = flag.Bool("parallel", os.Getenv("COVERALLS_PARALLEL") != "", "Submit as parallel") + endpoint = flag.String("endpoint", "https://coveralls.io", "Hostname to submit Coveralls data to") + service = flag.String("service", "", "The CI service or other environment in which the test suite was run. ") + shallow = flag.Bool("shallow", false, "Shallow coveralls internal server errors") + ignore = flag.String("ignore", "", "Comma separated files to ignore") + insecure = flag.Bool("insecure", false, "Set insecure to skip verification of certificates") + show = flag.Bool("show", false, "Show which package is being tested") + customJobID = flag.String("jobid", "", "Custom set job token") + jobNumber = flag.String("jobnumber", "", "Custom set job number") + + parallelFinish = flag.Bool("parallel-finish", false, "finish parallel test") +) + +// usage supplants package flag's Usage variable +var usage = func() { + cmd := os.Args[0] + // fmt.Fprintf(os.Stderr, "Usage of %s:\n", cmd) + s := "Usage: %s [options]\n" + fmt.Fprintf(os.Stderr, s, cmd) + flag.PrintDefaults() +} + +// A SourceFile represents a source code file and its coverage data for a +// single job. +type SourceFile struct { + Name string `json:"name"` // File path of this source file + Source string `json:"source"` // Full source code of this file + Coverage []interface{} `json:"coverage"` // Requires both nulls and integers +} + +// A Job represents the coverage data from a single run of a test suite. +type Job struct { + RepoToken *string `json:"repo_token,omitempty"` + ServiceJobID string `json:"service_job_id"` + ServiceJobNumber string `json:"service_job_number,omitempty"` + ServicePullRequest string `json:"service_pull_request,omitempty"` + ServiceName string `json:"service_name"` + SourceFiles []*SourceFile `json:"source_files"` + Parallel *bool `json:"parallel,omitempty"` + Git *Git `json:"git,omitempty"` + RunAt time.Time `json:"run_at"` +} + +// A Response is returned by the Coveralls.io API. +type Response struct { + Message string `json:"message"` + URL string `json:"url"` + Error bool `json:"error"` +} + +// A WebHookResponse is returned by the Coveralls.io WebHook. +type WebHookResponse struct { + Done bool `json:"done"` +} + +// getPkgs returns packages for measuring coverage. Returned packages doesn't +// contain vendor packages. +func getPkgs(pkg string) ([]string, error) { + if pkg == "" { + pkg = "./..." + } + out, err := exec.Command("go", "list", pkg).CombinedOutput() + if err != nil { + return nil, err + } + allPkgs := strings.Split(strings.Trim(string(out), "\n"), "\n") + pkgs := make([]string, 0, len(allPkgs)) + for _, p := range allPkgs { + if strings.Contains(p, "/vendor/") { + continue + } + // go modules output + if strings.Contains(p, "go: ") { + continue + } + pkgs = append(pkgs, p) + } + return pkgs, nil +} + +func getCoverage() ([]*SourceFile, error) { + if *coverprof != "" { + return parseCover(*coverprof) + } + + // pkgs is packages to run tests and get coverage. + pkgs, err := getPkgs(*pkg) + if err != nil { + return nil, err + } + coverpkg := fmt.Sprintf("-coverpkg=%s", strings.Join(pkgs, ",")) + var pfss [][]*cover.Profile + for _, line := range pkgs { + f, err := ioutil.TempFile("", "goveralls") + if err != nil { + return nil, err + } + f.Close() + cmd := exec.Command("go") + outBuf := new(bytes.Buffer) + cmd.Stdout = outBuf + cmd.Stderr = outBuf + coverm := *covermode + if *race { + coverm = "atomic" + } + args := []string{"go", "test", "-covermode", coverm, "-coverprofile", f.Name(), coverpkg} + if *verbose { + args = append(args, "-v") + cmd.Stdout = os.Stdout + } + if *race { + args = append(args, "-race") + } + args = append(args, extraFlags...) + args = append(args, line) + cmd.Args = args + + if *show { + fmt.Println("goveralls:", line) + } + err = cmd.Run() + if err != nil { + return nil, fmt.Errorf("%v: %v", err, outBuf.String()) + } + + pfs, err := cover.ParseProfiles(f.Name()) + if err != nil { + return nil, err + } + err = os.Remove(f.Name()) + if err != nil { + return nil, err + } + pfss = append(pfss, pfs) + } + + sourceFiles, err := toSF(mergeProfs(pfss)) + if err != nil { + return nil, err + } + + return sourceFiles, nil +} + +var vscDirs = []string{".git", ".hg", ".bzr", ".svn"} + +func findRepositoryRoot(dir string) (string, bool) { + for _, vcsdir := range vscDirs { + if d, err := os.Stat(filepath.Join(dir, vcsdir)); err == nil && d.IsDir() { + return dir, true + } + } + nextdir := filepath.Dir(dir) + if nextdir == dir { + return "", false + } + return findRepositoryRoot(nextdir) +} + +func getCoverallsSourceFileName(name string) string { + if dir, ok := findRepositoryRoot(name); ok { + name = strings.TrimPrefix(name, dir+string(os.PathSeparator)) + } + return filepath.ToSlash(name) +} + +// processParallelFinish notifies coveralls that all jobs are completed +// ref. https://docs.coveralls.io/parallel-build-webhook +func processParallelFinish(jobID, token string) error { + var name string + if reponame != nil && *reponame != "" { + name = *reponame + } else if s := os.Getenv("GITHUB_REPOSITORY"); s != "" { + name = s + } + + params := make(url.Values) + params.Set("repo_token", token) + params.Set("repo_name", name) + params.Set("payload[build_num]", jobID) + params.Set("payload[status]", "done") + res, err := http.PostForm(*endpoint+"/webhook", params) + if err != nil { + return err + } + defer res.Body.Close() + bodyBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("Unable to read response body from coveralls: %s", err) + } + + if res.StatusCode >= http.StatusInternalServerError && *shallow { + fmt.Println("coveralls server failed internally") + return nil + } + + if res.StatusCode != 200 { + return fmt.Errorf("Bad response status from coveralls: %d\n%s", res.StatusCode, bodyBytes) + } + + var response WebHookResponse + if err = json.Unmarshal(bodyBytes, &response); err != nil { + return fmt.Errorf("Unable to unmarshal response JSON from coveralls: %s\n%s", err, bodyBytes) + } + + if !response.Done { + return fmt.Errorf("jobs are not completed:\n%s", bodyBytes) + } + + return nil +} + +func process() error { + log.SetFlags(log.Ltime | log.Lshortfile) + // + // Parse Flags + // + flag.Usage = usage + flag.Var(&extraFlags, "flags", "extra flags to the tests") + flag.Parse() + if len(flag.Args()) > 0 { + flag.Usage() + os.Exit(1) + } + + // + // Setup PATH environment variable + // + paths := filepath.SplitList(os.Getenv("PATH")) + if goroot := os.Getenv("GOROOT"); goroot != "" { + paths = append(paths, filepath.Join(goroot, "bin")) + } + if gopath := os.Getenv("GOPATH"); gopath != "" { + for _, path := range filepath.SplitList(gopath) { + paths = append(paths, filepath.Join(path, "bin")) + } + } + os.Setenv("PATH", strings.Join(paths, string(filepath.ListSeparator))) + + // + // Handle certificate verification configuration + // + if *insecure { + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + } + + // + // Initialize Job + // + + // flags are never nil, so no nil check needed + githubEvent := getGithubEvent() + var jobID string + if *customJobID != "" { + jobID = *customJobID + } else if ServiceJobID := os.Getenv("COVERALLS_SERVICE_JOB_ID"); ServiceJobID != "" { + jobID = ServiceJobID + } else if travisjobID := os.Getenv("TRAVIS_JOB_ID"); travisjobID != "" { + jobID = travisjobID + } else if circleCIJobID := os.Getenv("CIRCLE_BUILD_NUM"); circleCIJobID != "" { + jobID = circleCIJobID + } else if appveyorJobID := os.Getenv("APPVEYOR_JOB_ID"); appveyorJobID != "" { + jobID = appveyorJobID + } else if semaphorejobID := os.Getenv("SEMAPHORE_BUILD_NUMBER"); semaphorejobID != "" { + jobID = semaphorejobID + } else if jenkinsjobID := os.Getenv("BUILD_NUMBER"); jenkinsjobID != "" { + jobID = jenkinsjobID + } else if buildID := os.Getenv("BUILDKITE_BUILD_ID"); buildID != "" { + jobID = buildID + } else if droneBuildNumber := os.Getenv("DRONE_BUILD_NUMBER"); droneBuildNumber != "" { + jobID = droneBuildNumber + } else if buildkiteBuildNumber := os.Getenv("BUILDKITE_BUILD_NUMBER"); buildkiteBuildNumber != "" { + jobID = buildkiteBuildNumber + } else if codeshipjobID := os.Getenv("CI_BUILD_ID"); codeshipjobID != "" { + jobID = codeshipjobID + } else if githubSHA := os.Getenv("GITHUB_SHA"); githubSHA != "" { + githubShortSha := githubSHA[0:9] + if os.Getenv("GITHUB_EVENT_NAME") == "pull_request" { + number := githubEvent["number"].(float64) + jobID = fmt.Sprintf(`%s-PR-%d`, githubShortSha, int(number)) + } else { + jobID = githubShortSha + } + } + + if *parallelFinish { + return processParallelFinish(jobID, *repotoken) + } + + if *repotoken == "" { + repotoken = nil // remove the entry from json + } + + head := "HEAD" + var pullRequest string + if prNumber := os.Getenv("CIRCLE_PR_NUMBER"); prNumber != "" { + // for Circle CI (pull request from forked repo) + pullRequest = prNumber + } else if prNumber := os.Getenv("TRAVIS_PULL_REQUEST"); prNumber != "" && prNumber != "false" { + pullRequest = prNumber + } else if prURL := os.Getenv("CI_PULL_REQUEST"); prURL != "" { + // for Circle CI + pullRequest = regexp.MustCompile(`[0-9]+$`).FindString(prURL) + } else if prNumber := os.Getenv("APPVEYOR_PULL_REQUEST_NUMBER"); prNumber != "" { + pullRequest = prNumber + } else if prNumber := os.Getenv("PULL_REQUEST_NUMBER"); prNumber != "" { + pullRequest = prNumber + } else if prNumber := os.Getenv("BUILDKITE_PULL_REQUEST"); prNumber != "" { + pullRequest = prNumber + } else if prNumber := os.Getenv("DRONE_PULL_REQUEST"); prNumber != "" { + pullRequest = prNumber + } else if prNumber := os.Getenv("BUILDKITE_PULL_REQUEST"); prNumber != "" { + pullRequest = prNumber + } else if prNumber := os.Getenv("CI_PR_NUMBER"); prNumber != "" { + pullRequest = prNumber + } else if os.Getenv("GITHUB_EVENT_NAME") == "pull_request" { + number := githubEvent["number"].(float64) + pullRequest = strconv.Itoa(int(number)) + + ghPR := githubEvent["pull_request"].(map[string]interface{}) + ghHead := ghPR["head"].(map[string]interface{}) + head = ghHead["sha"].(string) + } + + if *service == "" && os.Getenv("TRAVIS_JOB_ID") != "" { + *service = "travis-ci" + } + + sourceFiles, err := getCoverage() + if err != nil { + return err + } + + j := Job{ + RunAt: time.Now(), + RepoToken: repotoken, + ServicePullRequest: pullRequest, + Parallel: parallel, + Git: collectGitInfo(head), + SourceFiles: sourceFiles, + ServiceName: *service, + } + + // Only include a job ID if it's known, otherwise, Coveralls looks + // for the job and can't find it. + if jobID != "" { + j.ServiceJobID = jobID + } + j.ServiceJobNumber = *jobNumber + + // Ignore files + if len(*ignore) > 0 { + patterns := strings.Split(*ignore, ",") + for i, pattern := range patterns { + patterns[i] = strings.TrimSpace(pattern) + } + var files []*SourceFile + Files: + for _, file := range j.SourceFiles { + for _, pattern := range patterns { + match, err := filepath.Match(pattern, file.Name) + if err != nil { + return err + } + if match { + fmt.Printf("ignoring %s\n", file.Name) + continue Files + } + } + files = append(files, file) + } + j.SourceFiles = files + } + + if *debug { + b, err := json.MarshalIndent(j, "", " ") + if err != nil { + return err + } + log.Printf("Posting data: %s", b) + } + + b, err := json.Marshal(j) + if err != nil { + return err + } + + params := make(url.Values) + params.Set("json", string(b)) + res, err := http.PostForm(*endpoint+"/api/v1/jobs", params) + if err != nil { + return err + } + defer res.Body.Close() + bodyBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("Unable to read response body from coveralls: %s", err) + } + + if res.StatusCode >= http.StatusInternalServerError && *shallow { + fmt.Println("coveralls server failed internally") + return nil + } + + if res.StatusCode != 200 { + return fmt.Errorf("Bad response status from coveralls: %d\n%s", res.StatusCode, bodyBytes) + } + var response Response + if err = json.Unmarshal(bodyBytes, &response); err != nil { + return fmt.Errorf("Unable to unmarshal response JSON from coveralls: %s\n%s", err, bodyBytes) + } + if response.Error { + return errors.New(response.Message) + } + fmt.Println(response.Message) + fmt.Println(response.URL) + return nil +} + +func getGithubEvent() map[string]interface{} { + jsonFilePath := os.Getenv("GITHUB_EVENT_PATH") + if jsonFilePath == "" { + return nil + } + + jsonFile, err := os.Open(jsonFilePath) + if err != nil { + log.Fatal(err) + } + defer jsonFile.Close() + + jsonByte, _ := ioutil.ReadAll(jsonFile) + + // unmarshal the json into a release event + var event map[string]interface{} + err = json.Unmarshal(jsonByte, &event) + if err != nil { + log.Fatal(err) + } + + return event +} + +func main() { + if err := process(); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } +} diff --git a/vendor/github.com/mattn/goveralls/renovate.json b/vendor/github.com/mattn/goveralls/renovate.json new file mode 100644 index 0000000000..f45d8f110c --- /dev/null +++ b/vendor/github.com/mattn/goveralls/renovate.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "config:base" + ] +} diff --git a/vendor/github.com/mohae/deepcopy/.gitignore b/vendor/github.com/mohae/deepcopy/.gitignore new file mode 100644 index 0000000000..5846dd1531 --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/.gitignore @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*~ +*.out +*.log diff --git a/vendor/github.com/mohae/deepcopy/.travis.yml b/vendor/github.com/mohae/deepcopy/.travis.yml new file mode 100644 index 0000000000..fd47a8cf78 --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - tip + +matrix: + allow_failures: + - go: tip + +script: + - go test ./... diff --git a/vendor/github.com/mohae/deepcopy/LICENSE b/vendor/github.com/mohae/deepcopy/LICENSE new file mode 100644 index 0000000000..419673f005 --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Joel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/mohae/deepcopy/README.md b/vendor/github.com/mohae/deepcopy/README.md new file mode 100644 index 0000000000..f81841885b --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/README.md @@ -0,0 +1,8 @@ +deepCopy +======== +[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy) + +DeepCopy makes deep copies of things: unexported field values are not copied. + +## Usage + cpy := deepcopy.Copy(orig) diff --git a/vendor/github.com/mohae/deepcopy/deepcopy.go b/vendor/github.com/mohae/deepcopy/deepcopy.go new file mode 100644 index 0000000000..ba763ad091 --- /dev/null +++ b/vendor/github.com/mohae/deepcopy/deepcopy.go @@ -0,0 +1,125 @@ +// deepcopy makes deep copies of things. A standard copy will copy the +// pointers: deep copy copies the values pointed to. Unexported field +// values are not copied. +// +// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved. +// License: MIT, for more details check the included LICENSE file. +package deepcopy + +import ( + "reflect" + "time" +) + +// Interface for delegating copy process to type +type Interface interface { + DeepCopy() interface{} +} + +// Iface is an alias to Copy; this exists for backwards compatibility reasons. +func Iface(iface interface{}) interface{} { + return Copy(iface) +} + +// Copy creates a deep copy of whatever is passed to it and returns the copy +// in an interface{}. The returned value will need to be asserted to the +// correct type. +func Copy(src interface{}) interface{} { + if src == nil { + return nil + } + + // Make the interface a reflect.Value + original := reflect.ValueOf(src) + + // Make a copy of the same type as the original. + cpy := reflect.New(original.Type()).Elem() + + // Recursively copy the original. + copyRecursive(original, cpy) + + // Return the copy as an interface. + return cpy.Interface() +} + +// copyRecursive does the actual copying of the interface. It currently has +// limited support for what it can handle. Add as needed. +func copyRecursive(original, cpy reflect.Value) { + // check for implement deepcopy.Interface + if original.CanInterface() { + if copier, ok := original.Interface().(Interface); ok { + cpy.Set(reflect.ValueOf(copier.DeepCopy())) + return + } + } + + // handle according to original's Kind + switch original.Kind() { + case reflect.Ptr: + // Get the actual value being pointed to. + originalValue := original.Elem() + + // if it isn't valid, return. + if !originalValue.IsValid() { + return + } + cpy.Set(reflect.New(originalValue.Type())) + copyRecursive(originalValue, cpy.Elem()) + + case reflect.Interface: + // If this is a nil, don't do anything + if original.IsNil() { + return + } + // Get the value for the interface, not the pointer. + originalValue := original.Elem() + + // Get the value by calling Elem(). + copyValue := reflect.New(originalValue.Type()).Elem() + copyRecursive(originalValue, copyValue) + cpy.Set(copyValue) + + case reflect.Struct: + t, ok := original.Interface().(time.Time) + if ok { + cpy.Set(reflect.ValueOf(t)) + return + } + // Go through each field of the struct and copy it. + for i := 0; i < original.NumField(); i++ { + // The Type's StructField for a given field is checked to see if StructField.PkgPath + // is set to determine if the field is exported or not because CanSet() returns false + // for settable fields. I'm not sure why. -mohae + if original.Type().Field(i).PkgPath != "" { + continue + } + copyRecursive(original.Field(i), cpy.Field(i)) + } + + case reflect.Slice: + if original.IsNil() { + return + } + // Make a new slice and copy each element. + cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap())) + for i := 0; i < original.Len(); i++ { + copyRecursive(original.Index(i), cpy.Index(i)) + } + + case reflect.Map: + if original.IsNil() { + return + } + cpy.Set(reflect.MakeMap(original.Type())) + for _, key := range original.MapKeys() { + originalValue := original.MapIndex(key) + copyValue := reflect.New(originalValue.Type()).Elem() + copyRecursive(originalValue, copyValue) + copyKey := Copy(key.Interface()) + cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue) + } + + default: + cpy.Set(original) + } +} diff --git a/vendor/github.com/ory/fosite/.gitignore b/vendor/github.com/ory/fosite/.gitignore new file mode 100644 index 0000000000..80e850b87c --- /dev/null +++ b/vendor/github.com/ory/fosite/.gitignore @@ -0,0 +1,7 @@ +.idea +*.iml +.cover +*.log +*.exe +cover.out +vendor/ \ No newline at end of file diff --git a/vendor/github.com/ory/fosite/.golangci.yml b/vendor/github.com/ory/fosite/.golangci.yml new file mode 100644 index 0000000000..1a6ec235e2 --- /dev/null +++ b/vendor/github.com/ory/fosite/.golangci.yml @@ -0,0 +1,17 @@ +linters: + enable: + - gosec + disable: + - ineffassign + - deadcode + - unused + - structcheck + - errcheck + - gosimple + - bodyclose + - staticcheck + +run: + skip-files: + - ".+_test.go" + - ".+_test_.+.go" diff --git a/vendor/github.com/ory/fosite/.travis.yml b/vendor/github.com/ory/fosite/.travis.yml new file mode 100644 index 0000000000..6dd327af26 --- /dev/null +++ b/vendor/github.com/ory/fosite/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go_import_path: github.com/ory/fosite + +go: + - "1.14" + +install: + - go install github.com/mattn/goveralls + - go install github.com/ory/go-acc + - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.24.0 + +script: + - golangci-lint run + - go-acc -o coverage.txt ./... -- -failfast -timeout=20m + - goveralls -coverprofile="coverage.txt" diff --git a/vendor/github.com/ory/fosite/CONTRIBUTING.md b/vendor/github.com/ory/fosite/CONTRIBUTING.md new file mode 100644 index 0000000000..c89f639f69 --- /dev/null +++ b/vendor/github.com/ory/fosite/CONTRIBUTING.md @@ -0,0 +1,141 @@ + + + +# Contributing to ORY Fosite + + + + + +- [Introduction](#introduction) +- [Contributing Code](#contributing-code) +- [Disclosing vulnerabilities](#disclosing-vulnerabilities) +- [Code Style](#code-style) +- [Documentation](#documentation) +- [Pull request procedure](#pull-request-procedure) +- [Communication](#communication) +- [Conduct](#conduct) + + + +## Introduction + +Please note: We take ORY Fosite's security and our users' trust very +seriously. If you believe you have found a security issue in ORY Fosite, +please responsibly disclose by contacting us at hi@ory.sh. + +First: if you're unsure or afraid of anything, just ask or submit the issue or +pull request anyways. You won't be yelled at for giving it your best effort. The +worst that can happen is that you'll be politely asked to change something. We +appreciate any sort of contributions, and don't want a wall of rules to get in +the way of that. + +That said, if you want to ensure that a pull request is likely to be merged, +talk to us! You can find out our thoughts and ensure that your contribution +won't clash or be obviated by ORY Fosite's normal direction. A great way to +do this is via the [ORY Community](https://community.ory.sh/) or join the +[ORY Chat](https://www.ory.sh/chat). + +## Contributing Code + +Unless you are fixing a known bug, we **strongly** recommend discussing it with +the core team via a GitHub issue or [in our chat](https://www.ory.sh/chat) +before getting started to ensure your work is consistent with ORY Fosite's +roadmap and architecture. + +All contributions are made via pull request. Note that **all patches from all +contributors get reviewed**. After a pull request is made other contributors +will offer feedback, and if the patch passes review a maintainer will accept it +with a comment. When pull requests fail testing, authors are expected to update +their pull requests to address the failures until the tests pass and the pull +request merges successfully. + +At least one review from a maintainer is required for all patches (even patches +from maintainers). + +Reviewers should leave a "LGTM" comment once they are satisfied with the patch. +If the patch was submitted by a maintainer with write access, the pull request +should be merged by the submitter after review. + +## Disclosing vulnerabilities + +Please disclose vulnerabilities exclusively to +[security@ory.sh](mailto:security@ory.sh). Do not use GitHub issues. + +## Code Style + +Please follow these guidelines when formatting source code: + +- Go code should match the output of `gofmt -s` and pass `golangci-lint run`. +- NodeJS and JavaScript code should be prettified using `npm run format` where + appropriate. + +## Documentation + +Please provide documentation when changing, removing, or adding features. +Documentation resides in the project's [docs](docs) folder. Generate API and +configuration reference documentation using `cd docs; npm run gen`. + +For further instructions please head over to [docs/README.md](docs/README.md). + +## Pull request procedure + +To make a pull request, you will need a GitHub account; if you are unclear on +this process, see GitHub's documentation on +[forking](https://help.github.com/articles/fork-a-repo) and +[pull requests](https://help.github.com/articles/using-pull-requests). Pull +requests should be targeted at the `master` branch. Before creating a pull +request, go through this checklist: + +1. Create a feature branch off of `master` so that changes do not get mixed up. +1. [Rebase](http://git-scm.com/book/en/Git-Branching-Rebasing) your local + changes against the `master` branch. +1. Run the full project test suite with the `go test ./...` (or equivalent) + command and confirm that it passes. +1. Run `gofmt -s` (if the project is written in Go). +1. Ensure that each commit has a subsystem prefix (ex: `controller:`). + +Pull requests will be treated as "review requests," and maintainers will give +feedback on the style and substance of the patch. + +Normally, all pull requests must include tests that test your change. +Occasionally, a change will be very difficult to test for. In those cases, +please include a note in your commit message explaining why. + +## Communication + +We use [Slack](https://www.ory.sh/chat). You are welcome to drop in and ask +questions, discuss bugs, etc. + +## Conduct + +Whether you are a regular contributor or a newcomer, we care about making this +community a safe place for you and we've got your back. + +- We are committed to providing a friendly, safe and welcoming environment for + all, regardless of gender, sexual orientation, disability, ethnicity, + religion, or similar personal characteristic. +- Please avoid using nicknames that might detract from a friendly, safe and + welcoming environment for all. +- Be kind and courteous. There is no need to be mean or rude. +- We will exclude you from interaction if you insult, demean or harass anyone. + In particular, we do not tolerate behavior that excludes people in socially + marginalized groups. +- Private harassment is also unacceptable. No matter who you are, if you feel + you have been or are being harassed or made uncomfortable by a community + member, please contact one of the channel ops or a member of the ORY + Fosite core team immediately. +- Likewise any spamming, trolling, flaming, baiting or other attention-stealing + behaviour is not welcome. + +We welcome discussion about creating a welcoming, safe, and productive +environment for the community. If you have any questions, feedback, or concerns +[please let us know](https://www.ory.sh/chat). diff --git a/vendor/github.com/ory/fosite/HISTORY.md b/vendor/github.com/ory/fosite/HISTORY.md new file mode 100644 index 0000000000..9c43a82218 --- /dev/null +++ b/vendor/github.com/ory/fosite/HISTORY.md @@ -0,0 +1,653 @@ +This is a list of breaking changes. As long as `1.0.0` is not released, breaking changes will be addressed as minor version +bumps (`0.1.0` -> `0.2.0`). + + + + + +- [0.28.0](#0280) +- [0.27.0](#0270) + - [Conceptual Changes](#conceptual-changes) + - [API Changes](#api-changes) +- [0.26.0](#0260) +- [0.24.0](#0240) + - [Breaking change(s)](#breaking-changes) + - [`fosite/handler/oauth2.JWTStrategy`](#fositehandleroauth2jwtstrategy) + - [`OpenIDConnectRequestValidator.ValidatePrompt`](#openidconnectrequestvalidatorvalidateprompt) +- [0.23.0](#0230) + - [Breaking change(s)](#breaking-changes-1) + - [`Hasher`](#hasher) +- [0.22.0](#0220) + - [Breaking change(s)](#breaking-changes-2) + - [`JWTStrategy`](#jwtstrategy) +- [0.21.0](#0210) + - [Changes to parsing of OAuth 2.0 Client `response_types`](#changes-to-parsing-of-oauth-20-client-response_types) + - [`openid.DefaultStrategy` field name changed](#openiddefaultstrategy-field-name-changed) + - [`oauth2.RS256JWTStrategy` was renamed and field name changed](#oauth2rs256jwtstrategy-was-renamed-and-field-name-changed) + - [Adds `private_key_jwt` client authentication method](#adds-private_key_jwt-client-authentication-method) + - [Response Type `id_token` no longer required for authorize_code flow](#response-type-id_token-no-longer-required-for-authorize_code-flow) +- [0.20.0](#0200) +- [Breaking Changes](#breaking-changes) + - [JWT Claims](#jwt-claims) + - [`AuthorizeCodeStorage`](#authorizecodestorage) +- [0.19.0](#0190) +- [0.18.0](#0180) +- [0.17.0](#0170) +- [0.16.0](#0160) +- [0.15.0](#0150) +- [0.14.0](#0140) +- [0.13.0](#0130) + - [Breaking changes](#breaking-changes) +- [0.12.0](#0120) + - [Breaking changes](#breaking-changes-1) + - [Improved cryptographic methods](#improved-cryptographic-methods) +- [0.11.0](#0110) + - [Non-breaking changes](#non-breaking-changes) + - [Storage adapter](#storage-adapter) + - [Reducing use of gomock](#reducing-use-of-gomock) + - [Breaking Changes](#breaking-changes-1) + - [`fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed](#fositehandleroauth2authorizecodegrantstorage-was-removed) + - [`fosite/handler/oauth2.RefreshTokenGrantStorage` was removed](#fositehandleroauth2refreshtokengrantstorage-was-removed) + - [`fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed](#fositehandleroauth2authorizecodegrantstorage-was-removed-1) + - [WildcardScopeStrategy](#wildcardscopestrategy) + - [Refresh tokens and authorize codes are no longer JWTs](#refresh-tokens-and-authorize-codes-are-no-longer-jwts) + - [Delete access tokens when persisting refresh session](#delete-access-tokens-when-persisting-refresh-session) +- [0.10.0](#0100) +- [0.9.0](#090) +- [0.8.0](#080) + - [Breaking changes](#breaking-changes-2) + - [`ClientManager`](#clientmanager) + - [`OAuth2Provider`](#oauth2provider) +- [0.7.0](#070) +- [0.6.0](#060) +- [0.5.0](#050) +- [0.4.0](#040) +- [0.3.0](#030) +- [0.2.0](#020) +- [0.1.0](#010) + + + +## 0.28.0 + +This version (re-)introduces refresh token lifespans. Per default, this feature is enabled and set to 30 days. +If a refresh token has not been used within 30 days, it will expire. + +To disable refresh token lifespans (previous behaviour), set `compose.Config.RefreshTokenLifespan = -1`. + +## 0.27.0 + +This PR adds the ability to specify a target audience for OAuth 2.0 Access Tokens. + +### Conceptual Changes + +From now on, `scope` and `audience` will be checked against the client's whitelisted scope and audience on every +refresh token exchange. This prevents clients, which no longer are allowed to request a certain audience or scope, +to keep using those values with existing refresh tokens. + +### API Changes + +```go +type fosite.Client interface { ++ // GetAudience returns the allowed audience(s) for this client. ++ GetAudience() Arguments +} +``` + +```go +type fosite.Request struct { +- Scopes Argument ++ RequestedScope Argument + +- GrantedScopes Argument ++ GrantedScope Argument +} +``` + +```go +type fosite.Requester interface { ++ // GetRequestedAudience returns the requested audiences for this request. ++ GetRequestedAudience() (audience Arguments) + ++ // SetRequestedAudience sets the requested audienc. ++ SetRequestedAudience(audience Arguments) + ++ // GetGrantedAudience returns all granted scopes. ++ GetGrantedAudience() (grantedAudience Arguments) + ++ // GrantAudience marks a request's audience as granted. ++ GrantAudience(audience string) +} +``` + +```go +type fosite/token/jwt.JWTClaimsContainer interface { +- // With returns a copy of itself with expiresAt and scope set to the given values. +- With(expiry time.Time, scope, audience []string) JWTClaimsContainer + ++ // With returns a copy of itself with expiresAt, scope, audience set to the given values. ++ With(expiry time.Time, scope, audience []string) JWTClaimsContainer +} +``` + +## 0.26.0 + +This release makes it easier to define custom JWT Containers for access tokens when using the JWT strategy. To do that, +the following signatures have changed: + +```go +// github.com/ory/fosite/handler/oauth2 +type JWTSessionContainer interface { + // GetJWTClaims returns the claims. +- GetJWTClaims() *jwt.JWTClaims ++ GetJWTClaims() jwt.JWTClaimsContainer + + // GetJWTHeader returns the header. + GetJWTHeader() *jwt.Headers + + fosite.Session +} +``` + +```go ++ type JWTClaimsContainer interface { ++ // With returns a copy of itself with expiresAt and scope set to the given values. ++ With(expiry time.Time, scope []string) JWTClaimsContainer ++ ++ // WithDefaults returns a copy of itself with issuedAt and issuer set to the given default values. If those ++ // values are already set in the claims, they will not be updated. ++ WithDefaults(iat time.Time, issuer string) JWTClaimsContainer ++ ++ // ToMapClaims returns the claims as a github.com/dgrijalva/jwt-go.MapClaims type. ++ ToMapClaims() jwt.MapClaims ++ } +``` + +All default session implementations have been updated to reflect this change. If you define custom session, this patch +will affect you. + +## 0.24.0 + +This release addresses areas where the go context was missing or not propagated down the call path properly. + +### Breaking change(s) + +#### `fosite/handler/oauth2.JWTStrategy` + +The [`fosite/handler/oauth2.JWTStrategy`](https://github.com/ory/fosite/blob/master/handler/oauth2/strategy.go) interface changed as a context +parameter was added to its method signature: + +```go +type JWTStrategy interface { +- Validate(tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) ++ Validate(ctx context.Context, tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) +} +``` + +#### `OpenIDConnectRequestValidator.ValidatePrompt` + +The [`OpenIDConnectRequestValidator.ValidatePrompt`](https://github.com/ory/fosite/blob/master/handler/openid/validator.go) +method signature was updated to take a go context as its first parameter: + +```go +- func (v *OpenIDConnectRequestValidator) ValidatePrompt(req fosite.AuthorizeRequester) error { ++ func (v *OpenIDConnectRequestValidator) ValidatePrompt(ctx context.Context, req fosite.AuthorizeRequester) error { +``` + +## 0.23.0 + +This releases addresses inconsistencies in some of the public interfaces by passing in the go context to their signatures. + +### Breaking change(s) + +#### `Hasher` + +The [`Hasher`](https://github.com/ory/fosite/blob/master/hash.go) interface +changed as a context parameter was added to its method signatures: + +```go +type Hasher interface { +- Compare(hash, data []byte) error ++ Compare(ctx context.Context, hash, data []byte) error +- Hash(data []byte) ([]byte, error) ++ Hash(ctx context.Context, data []byte) ([]byte, error) +} +``` + +## 0.22.0 + +This releases addresses inconsistencies in some of the public interfaces by passing in the go context to their signatures. + +### Breaking change(s) + +#### `JWTStrategy` + +The [`JWTStrategy`](https://github.com/ory/fosite/blob/master/token/jwt/jwt.go) interface +changed as a context parameter was added to its method signatures: + +```go +type JWTStrategy interface { +- Generate(claims jwt.Claims, header Mapper) (string, string, error) ++ Generate(ctx context.Context, claims jwt.Claims, header Mapper) (string, string, error) +- Validate(token string) (string, error) ++ Validate(ctx context.Context, token string) (string, error) +- GetSignature(token string) (string, error) ++ GetSignature(ctx context.Context, token string) (string, error) +- Hash(in []byte) ([]byte, error) ++ Hash(ctx context.Context, in []byte) ([]byte, error) +- Decode(token string) (*jwt.Token, error) ++ Decode(ctx context.Context, token string) (*jwt.Token, error) + GetSigningMethodLength() int +} +``` + +## 0.21.0 + +This release improves compatibility with the OpenID Connect Dynamic Client Registration 1.0 specification. + +### Changes to parsing of OAuth 2.0 Client `response_types` + +Previously, when response types such as `code token id_token` were requested (OpenID Connect Hybrid Flow) it was enough +for the client to have `response_types=["code", "token", "id_token"]`. This is however incompatible with the +OpenID Connect Dynamic Client Registration 1.0 spec which dictates that the `response_types` have to match exactly. + +Assuming you are requesting `&response_types=code+token+id_token`, your client should have `response_types=["code token id_token"]`, +if other response types are required (e.g. `&response_types=code`, `&response_types=token`) they too must be included: +`response_types=["code", "token", "code token id_token"]`. + +### `openid.DefaultStrategy` field name changed + +Field `RS256JWTStrategy` was renamed to `JWTStrategy` and now relies on an interface instead of a concrete struct. + +### `oauth2.RS256JWTStrategy` was renamed and field name changed + +The strategy `oauth2.RS256JWTStrategy` was renamed to `oauth2.DefaultJWTStrategy` and now accepts an interface that +implements `jwt.JWTStrategy` instead of directly relying on `jwt.RS256JWTStrategy`. For this reason, +the field `RS256JWTStrategy` was renamed to `JWTStrategy` + +### Adds `private_key_jwt` client authentication method + +This patch adds the ability to perform the [`private_key_jwt` client authentication method](http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication) +defined in the OpenID Connect specification. Please note that method `client_secret_jwt` is not supported because of the BCrypt hashing strategy. + +For this strategy to work, you must set the `TokenURL` field of the `compose.Config` object to the authorization server's +Token URL. + +If you would like to support this authentication method, your `Client` implementation must also implement `fosite.DefaultOpenIDConnectClient` +and then, for example, `GetTokenEndpointAuthMethod()` should return `private_key_jwt`. + +### Response Type `id_token` no longer required for authorize_code flow + +The `authorize_code` [does not require](https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata) +the `id_token` response type to be available when performing the OpenID Connect flow: + +> grant_types +> OPTIONAL. JSON array containing a list of the OAuth 2.0 Grant Types that the Client is declaring that it will restrict itself to using. The Grant Type values used by OpenID Connect are: +> +> authorization_code: The Authorization Code Grant Type described in OAuth 2.0 Section 4.1. +> implicit: The Implicit Grant Type described in OAuth 2.0 Section 4.2. +> refresh_token: The Refresh Token Grant Type described in OAuth 2.0 Section 6. +> +> The following table lists the correspondence between response_type values that the Client will use and grant_type values that MUST be included in the registered grant_types list: +> +> code: authorization_code +> id_token: implicit +> token id_token: implicit +> code id_token: authorization_code, implicit +> code token: authorization_code, implicit +> code token id_token: authorization_code, implicit +> +> If omitted, the default is that the Client will use only the authorization_code Grant Type. + +Before this patch, the `id_token` response type was required whenever an ID Token was requested. This patch changes that. + +## 0.20.0 + +This release implements an OAuth 2.0 Best Practice with regards to revoking already issued access and refresh tokens +if an authorization code is used more than one time. + +## Breaking Changes + +### JWT Claims + +- `github.com/ory/fosite/token/jwt.JWTClaims.Audience` is no longer a `string`, but a string slice `[]string`. +- `github.com/ory/fosite/handler/openid.IDTokenClaims` is no longer a `string`, but a string slice `[]string`. + +### `AuthorizeCodeStorage` + +This improves security as, in the event of an authorization code being leaked, all associated tokens are revoked. To +implement this feature, a breaking change had to be introduced. The `github.com/ory/fosite/handler/oauth2.AuthorizeCodeStorage` +interface changed as follows: + +- `DeleteAuthorizeCodeSession(ctx context.Context, code string) (err error)` has been removed from the interface and +is no longer used by this library. +- `InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error)` has been introduced. +- The error `github.com/ory/fosite/handler/oauth2.ErrInvalidatedAuthorizeCode` has been added. + +The following documentation sheds light on how you should update your storage adapter: + +``` +// ErrInvalidatedAuthorizeCode is an error indicating that an authorization code has been +// used previously. +var ErrInvalidatedAuthorizeCode = errors.New("Authorization code has ben invalidated") + +// AuthorizeCodeStorage handles storage requests related to authorization codes. +type AuthorizeCodeStorage interface { + // GetAuthorizeCodeSession stores the authorization request for a given authorization code. + CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error) + + // GetAuthorizeCodeSession hydrates the session based on the given code and returns the authorization request. + // If the authorization code has been invalidated with `InvalidateAuthorizeCodeSession`, this + // method should return the ErrInvalidatedAuthorizeCode error. + // + // Make sure to also return the fosite.Requester value when returning the ErrInvalidatedAuthorizeCode error! + GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (request fosite.Requester, err error) + + // InvalidateAuthorizeCodeSession is called when an authorize code is being used. The state of the authorization + // code should be set to invalid and consecutive requests to GetAuthorizeCodeSession should return the + // ErrInvalidatedAuthorizeCode error. + InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error) +} +``` + +## 0.19.0 + +This release improves the OpenID Connect vaildation strategy which now properly handles `prompt`, `max_age`, and `id_token_hint` +at the `/oauth2/auth` endpoint instead of the `/oauth2/token` endpoint. + +To achieve this, the `OpenIDConnectRequestValidator` has been modified and now requires a `jwt.JWTStrategy` (implemented by, +for example `jwt.RS256JWTStrategy`). + +The compose package has been updated accordingly. You should not expect any major breaking changes from this release. + +## 0.18.0 + +This release allows the introspection handler to return the token type (e.g. `access_token`, `refresh_token`) of the +introspected token. To achieve that, some breaking API changes have been introduced: + +* `OAuth2.IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scope ...string) (AccessRequester, error)` is now `OAuth2.IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scope ...string) (TokenType, AccessRequester, error)`. +* `TokenIntrospector.IntrospectToken(ctx context.Context, token string, tokenType TokenType, accessRequest AccessRequester, scopes []string) (error)` is now `TokenIntrospector.IntrospectToken(ctx context.Context, token string, tokenType TokenType, accessRequest AccessRequester, scopes []string) (TokenType, error)`. + +This patch also resolves a misconfigured json key in the `IntrospectionResponse` struct. `AccessRequester AccessRequester json:",extra"` is now properly declared as `AccessRequester AccessRequester json:"extra"`. + +## 0.17.0 + +This release resolves a security issue (reported by [platform.sh](https://www.platform.sh)) related to potential storage implementations. +This library used to pass all of the request body from both authorize and token endpoints to the storage adapters. As some of these values +are needed in consecutive requests, some storage adapters chose to drop the full body to the database. + +This implied that confidential parameters, such as the `client_secret` which can be passed in the request body since +version 0.15.0, were stored as key/value pairs in plaintext in the database. While most client secrets are generated +programmatically (as opposed to set by the user), it's a considerable security issue nonetheless. + +The issue has been resolved by sanitizing the request body and only including those values truly required by their +respective handlers. This lead to two breaking changes in the API: + +1. The `fosite.Requester` interface has a new method `Sanitize(allowedParameters []string) Requester` which returns +a sanitized clone of the method receiver. If you do not use your own `fosite.Requester` implementation, this won't affect you. +2. If you use the PKCE handler, you will have to add three new methods to your storage implementation. The methods +to be added work exactly like, for example `CreateAuthorizeCodeSession`. A reference implementation can be found in +[./storage/memory.go](./storage/memory.go). The method signatures are as follows: +```go +type PKCERequestStorage interface { + GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) + CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error + DeletePKCERequestSession(ctx context.Context, signature string) error +} +``` + +We encourage you to upgrade to this release and check your storage implementations and potentially remove old data. + +We would like to thank [platform.sh](https://www.platform.sh) for sponsoring the development of a patch that resolves this +issue. + +## 0.16.0 + +This patch introduces `SendDebugMessagesToClients` to the Fosite struct which enables/disables sending debug information to +clients. Debug information may contain sensitive information as it forwards error messages from, for example, storage +implementations. For this reason, `RevealDebugPayloads` defaults to false. Keep in mind that the information may be +very helpful when specific OAuth 2.0 requests fail and we generally recommend displaying debug information. + +Additionally, error keys for JSON changed which caused a new minor version, speicifically +[`statusCode` was changed to `status_code`](https://github.com/ory/fosite/pull/242/files#diff-dd25e0e0a594c3f3592c1c717039b85eR221). + + +## 0.15.0 + +This release focuses on improving compatibility with OpenID Connect Certification and better error context. + +* Error handling is improved by explicitly adding debug information (e.g. "Token invalid because it was not found +in the database") to the error object. Previously, the original error was prepended which caused weird formatting issues. +* Allows client credentials in POST body at the `/oauth2/token` endpoint. Please note that this method is not recommended +to be used, unless the client making the request is unable to use HTTP Basic Authorization. +* Allows public clients (without secret) to access the `/oauth2/token` endpoint which was previously only possible by adding an arbitrary +secret. + +This release has no breaking changes to the external API but due to the nature of the changes, it is released +as a new major version. + +## 0.14.0 + +Improves error contexts. A breaking code changes to the public API was reverted with 0.14.1. + +## 0.13.0 + +### Breaking changes + +`glide` was replaced with `dep`. + +## 0.12.0 + +### Breaking changes + +#### Improved cryptographic methods + +* The minimum required secret length used to generate signatures of access tokens has increased from 16 to 32 byte. +* The algorithm used to generate access tokens using the HMAC-SHA strategy has changed from HMAC-SHA256 to HMAC-SHA512. + +## 0.11.0 + +### Non-breaking changes + +#### Storage adapter + +To simplify the storage adapter logic, and also reduce the likelihoods of bugs within the storage adapter, the +interface was greatly simplified. Specifically, these two methods have been removed: + +* `PersistRefreshTokenGrantSession(ctx context.Context, requestRefreshSignature, accessSignature, refreshSignature string, request fosite.Requester) error` +* `PersistAuthorizeCodeGrantSession(ctx context.Context, authorizeCode, accessSignature, refreshSignature string, request fosite.Requester) error` + +For this change, you don't need to do anything. You can however simply delete those two methods from your store. + +#### Reducing use of gomock + +In the long term, fosite should remove all gomocks and instead test against the internal implementations. This +will increase iterations per line during tests and reduce annoying mock updates. + +### Breaking Changes + +#### `fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed + +`AuthorizeCodeGrantStorage` was used specifically in the composer. Refactor references to `AuthorizeCodeGrantStorage` with `CoreStorage`. + +#### `fosite/handler/oauth2.RefreshTokenGrantStorage` was removed + +`RefreshTokenGrantStorage` was used specifically in the composer. Refactor references to `RefreshTokenGrantStorage` with `CoreStorage`. + +#### `fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed + +`AuthorizeCodeGrantStorage` was used specifically in the composer. Refactor references to `AuthorizeCodeGrantStorage` with `CoreStorage`. + +#### WildcardScopeStrategy + +A new [scope strategy](https://github.com/ory/fosite/pull/187) was introduced called `WildcardScopeStrategy`. This strategy is now the default when using +the composer. To set the HierarchicScopeStrategy strategy, do: + +``` +import "github.com/ory/fosite/compose" + +var config = &compose.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, +} +``` + +#### Refresh tokens and authorize codes are no longer JWTs + +Using JWTs for refresh tokens and authorize codes did not make sense: + +1. Refresh tokens are long-living credentials, JWTs require an expiry date. +2. Refresh tokens are never validated client-side, only server-side. Thus access to the store is available. +3. Authorize codes are never validated client-side, only server-side. + +Also, one compose method changed due to this: + +```go +package compose + +// .. + +- func NewOAuth2JWTStrategy(key *rsa.PrivateKey) *oauth2.RS256JWTStrategy ++ func NewOAuth2JWTStrategy(key *rsa.PrivateKey, strategy *oauth2.HMACSHAStrategy) *oauth2.RS256JWTStrategy +``` + +#### Delete access tokens when persisting refresh session + +Please delete access tokens in your store when you persist a refresh session. This increases security. Here +is an example of how to do that using only existing methods: + +```go +func (s *MemoryStore) PersistRefreshTokenGrantSession(ctx context.Context, originalRefreshSignature, accessSignature, refreshSignature string, request fosite.Requester) error { + if ts, err := s.GetRefreshTokenSession(ctx, originalRefreshSignature, nil); err != nil { + return err + } else if err := s.RevokeAccessToken(ctx, ts.GetID()); err != nil { + return err + } else if err := s.RevokeRefreshToken(ctx, ts.GetID()); err != nil { + return err + } else if err := s.CreateAccessTokenSession(ctx, accessSignature, request); err != nil { + return err + } else if err := s.CreateRefreshTokenSession(ctx, refreshSignature, request); err != nil { + return err + } + + return nil +} +``` + +## 0.10.0 + +It is no longer possible to introspect authorize codes, and passing scopes to the introspector now also checks +refresh token scopes. + +## 0.9.0 + +This patch adds the ability to pass a custom hasher to `compose.Compose`, which is a breaking change. You can pass nil for the fosite default hasher: + +``` +package compose + +-func Compose(config *Config, storage interface{}, strategy interface{}, factories ...Factory) fosite.OAuth2Provider { ++func Compose(config *Config, storage interface{}, strategy interface{}, hasher fosite.Hasher, factories ...Factory) fosite.OAuth2Provider { +``` + +## 0.8.0 + +This patch addresses some inconsistencies in the public interfaces. Also +remaining references to the old repository location at `ory-am/fosite` +where updated to `ory/fosite`. + +### Breaking changes + +#### `ClientManager` + +The [`ClientManager`](https://github.com/ory/fosite/blob/master/client_manager.go) interface +changed, as a context parameter was added: + +```go +type ClientManager interface { + // GetClient loads the client by its ID or returns an error + // if the client does not exist or another error occurred. +- GetClient(id string) (Client, error) ++ GetClient(ctx context.Context, id string) (Client, error) +} +``` + +#### `OAuth2Provider` + +The [OAuth2Provider](https://github.com/ory/fosite/blob/master/oauth2.go) interface changed, +as the need for passing down `*http.Request` was removed. This is justifiable +because `NewAuthorizeRequest` and `NewAccessRequest` already contain `*http.Request`. + +The public api of those two methods changed: + +```go +- NewAuthorizeResponse(ctx context.Context, req *http.Request, requester AuthorizeRequester, session Session) (AuthorizeResponder, error) ++ NewAuthorizeResponse(ctx context.Context, requester AuthorizeRequester, session Session) (AuthorizeResponder, error) + + +- NewAccessResponse(ctx context.Context, req *http.Request, requester AccessRequester) (AccessResponder, error) ++ NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error) +``` + +## 0.7.0 + +Breaking changes: + +* Replaced `"golang.org/x/net/context"` with `"context"`. +* Move the repo from `github.com/ory-am/fosite` to `github.com/ory/fosite` + +## 0.6.0 + +A bug related to refresh tokens was found. To mitigate it, a `Clone()` method has been introduced to the `fosite.Session` interface. +If you use a custom session object, this will be a breaking change. Fosite's default sessions have been upgraded and no additional +work should be required. If you use your own session struct, we encourage using package `gob/encoding` to deep-copy it in `Clone()`. + +## 0.5.0 + +Breaking changes: + +* `compose.OpenIDConnectExplicit` is now `compose.OpenIDConnectExplicitFactory` +* `compose.OpenIDConnectImplicit` is now `compose.OpenIDConnectImplicitFactory` +* `compose.OpenIDConnectHybrid` is now `compose.OpenIDConnectHybridFactory` +* The token introspection handler is no longer added automatically by `compose.OAuth2*`. Add `compose.OAuth2TokenIntrospectionFactory` +to your composer if you need token introspection. +* Session refactor: + * The HMACSessionContainer was removed and replaced by `fosite.Session` / `fosite.DefaultSession`. All sessions + must now implement this signature. The new session interface allows for better expiration time handling. + * The OpenID `DefaultSession` signature changed as well, it is now implementing the `fosite.Session` interface + +## 0.4.0 + +Breaking changes: + +* `./fosite-example` is now a separate repository: https://github.com/ory-am/fosite-example +* `github.com/ory-am/fosite/fosite-example/pkg.Store` is now `github.com/ory-am/fosite/storage.MemoryStore` +* `fosite.Client` has now a new method called `IsPublic()` which can be used to identify public clients who do not own a client secret +* All grant types except the client_credentials grant now allow public clients. public clients are usually mobile apps and single page apps. +* `TokenValidator` is now `TokenIntrospector`, `TokenValidationHandlers` is now `TokenIntrospectionHandlers`. +* `TokenValidator.ValidateToken` is now `TokenIntrospector.IntrospectToken` +* `fosite.OAuth2Provider.NewIntrospectionRequest()` has been added +* `fosite.OAuth2Provider.WriteIntrospectionError()` has been added +* `fosite.OAuth2Provider.WriteIntrospectionResponse()` has been added + +## 0.3.0 + +* Updated jwt-go from 2.7.0 to 3.0.0 + +## 0.2.0 + +Breaking changes: + +* Token validation refactored: `ValidateRequestAuthorization` is now `Validate` and does not require a http request +but instead a token and a token hint. A token can be anything, including authorization codes, refresh tokens, +id tokens, ... +* Remove mandatory scope: The mandatory scope (`fosite`) has been removed as it has proven impractical. +* Allowed OAuth2 Client scopes are now being set with `scope` instead of `granted_scopes` when using the DefaultClient. +* There is now a scope matching strategy that can be replaced. +* OAuth2 Client scopes are now checked on every grant type. +* Handler subpackages such as `core/client` or `oidc/explicit` have been merged and moved one level up +* `handler/oidc` is now `handler/openid` +* `handler/core` is now `handler/oauth2` + +## 0.1.0 + +Initial release diff --git a/vendor/github.com/ory/fosite/LICENSE b/vendor/github.com/ory/fosite/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/ory/fosite/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ory/fosite/MAINTAINERS b/vendor/github.com/ory/fosite/MAINTAINERS new file mode 100644 index 0000000000..75713ca9ae --- /dev/null +++ b/vendor/github.com/ory/fosite/MAINTAINERS @@ -0,0 +1,2 @@ +Aeneas Rekkas (github: arekkas) +Thomas Aidan Curran (github: tacurran) \ No newline at end of file diff --git a/vendor/github.com/ory/fosite/Makefile b/vendor/github.com/ory/fosite/Makefile new file mode 100644 index 0000000000..72a35400b7 --- /dev/null +++ b/vendor/github.com/ory/fosite/Makefile @@ -0,0 +1,5 @@ +format: + goreturns -w -local github.com/ory $$(listx .) + +test: + go test ./... diff --git a/vendor/github.com/ory/fosite/README.md b/vendor/github.com/ory/fosite/README.md new file mode 100644 index 0000000000..5144c93bc2 --- /dev/null +++ b/vendor/github.com/ory/fosite/README.md @@ -0,0 +1,434 @@ +

ORY Fosite - Security-first OAuth2 framework

+ +[![Build Status](https://travis-ci.org/ory/fosite.svg?branch=master)](https://travis-ci.org/ory/fosite?branch=master) +[![Coverage Status](https://coveralls.io/repos/ory/fosite/badge.svg?branch=master&service=github&foo)](https://coveralls.io/github/ory/fosite?branch=master) +[![Go Report Card](https://goreportcard.com/badge/ory/fosite)](https://goreportcard.com/report/ory/fosite) + +[![Join the chat at https://www.ory.sh/chat](https://img.shields.io/badge/join-chat-00cc99.svg)](https://www.ory.sh/chat) + +**The security first OAuth2 & OpenID Connect framework for [Go](https://golang.org).** +Built simple, powerful and extensible. This library implements peer-reviewed [IETF RFC6749](https://tools.ietf.org/html/rfc6749), +counterfeits weaknesses covered in peer-reviewed [IETF RFC6819](https://tools.ietf.org/html/rfc6819) and countermeasures various database +attack scenarios, keeping your application safe when that hacker penetrates or leaks your database. OpenID Connect is +implemented according to [OpenID Connect Core 1.0 incorporating errata set 1](https://openid.net/specs/openid-connect-core-1_0.html) and +includes all flows: code, implicit, hybrid. + +This library considered and implemented: +* [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) +* [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html) +* [OAuth 2.0 Threat Model and Security Considerations](https://tools.ietf.org/html/rfc6819) +* [Proof Key for Code Exchange by OAuth Public Clients](https://tools.ietf.org/html/rfc7636) +* [OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252) +* [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) + +OAuth2 and OpenID Connect are difficult protocols. If you want quick wins, we strongly encourage you to look at [Hydra](https://github.com/ory-am/hydra). +Hydra is a secure, high performance, cloud native OAuth2 and OpenID Connect service that integrates with every authentication method +imaginable and is built on top of Fosite. + + + +**Table of Contents** + +- [Motivation](#motivation) +- [API Stability](#api-stability) +- [Example](#example) +- [A word on quality](#a-word-on-quality) +- [A word on security](#a-word-on-security) +- [A word on extensibility](#a-word-on-extensibility) +- [Installation](#installation) +- [Documentation](#documentation) + - [Scopes](#scopes) + - [`fosite.WildcardScopeStrategy`](#fositewildcardscopestrategy) + - [`fosite.HierarchicScopeStrategy`](#fositehierarchicscopestrategy) + - [Quickstart](#quickstart) + - [Code Examples](#code-examples) + - [Example Storage Implementation](#example-storage-implementation) + - [Extensible handlers](#extensible-handlers) + - [JWT Introspection](#jwt-introspection) +- [Contribute](#contribute) + - [Refresh mock objects](#refresh-mock-objects) +- [Hall of Fame](#hall-of-fame) + + + +## Motivation + +Fosite was written because our OAuth2 and OpenID Connect service [**Hydra**](https://github.com/ory-am/hydra) +required a secure and extensible OAuth2 library. We had to realize that nothing matching our requirements +was out there, so we decided to build it ourselves. + +## API Stability + +The core public API is almost stable as most changes will only touch the inner workings. + +We strongly encourage vendoring fosite using [dep](https://github.com/golang/dep) or comparable tools. + +## Example + +The example does not have nice visuals but it should give you an idea of what you can do with Fosite and a few lines +of code. + +![Authorize Code Grant](docs/authorize-code-grant.gif) + +You can run this minimalistic example by doing + +``` +go get github.com/ory/fosite-example +cd $GOPATH/src/github.com/ory/fosite-example +dep ensure +go install github.com/ory/fosite-example +fosite-example +``` + +There should be a server listening on [localhost:3846](https://localhost:3846/). You can check out the example's +source code [here](https://github.com/ory/fosite-example/). + +## A word on quality + +We tried to set up as many tests as possible and test for as many cases covered in the RFCs as possible. But we are only +human. Please, feel free to add tests for the various cases defined in the OAuth2 RFCs 6749 and 6819 or any other cases that improve the tests. + +**Everyone** writing an RFC conform test that breaks with the current implementation, will receive a place in the +[Hall of Fame](#hall-of-fame)! + +## A word on security + +Please be aware that Fosite only secures parts your server side security. You still need to secure your apps and clients, keep +your tokens safe, prevent CSRF attacks, ensure database security, use valid and strong TLS certificates and much more. If you need any help or advice feel free to contact our security staff through [our website](https://ory.am/)! + +We have given the various specifications, especially [OAuth 2.0 Threat Model and Security Considerations](https://tools.ietf.org/html/rfc6819#section-5.1.5.3), +a very close look and included everything we thought was in the scope of this framework. Here is a complete list +of things we implemented in Fosite: + +* [No Cleartext Storage of Credentials](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.3) +* [Encryption of Credentials](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.4) +* [Use Short Expiration Time](https://tools.ietf.org/html/rfc6819#section-5.1.5.3) +* [Limit Number of Usages or One-Time Usage](https://tools.ietf.org/html/rfc6819#section-5.1.5.4) +* [Bind Token to Client id](https://tools.ietf.org/html/rfc6819#section-5.1.5.8) +* [Automatic Revocation of Derived Tokens If Abuse Is Detected](https://tools.ietf.org/html/rfc6819#section-5.2.1.1) +* [Binding of Refresh Token to "client_id"](https://tools.ietf.org/html/rfc6819#section-5.2.2.2) +* [Refresh Token Rotation](https://tools.ietf.org/html/rfc6819#section-5.2.2.3) +* [Revocation of Refresh Tokens](https://tools.ietf.org/html/rfc6819#section-5.2.2.4) +* [Validate Pre-Registered "redirect_uri"](https://tools.ietf.org/html/rfc6819#section-5.2.3.5) +* [Binding of Authorization "code" to "client_id"](https://tools.ietf.org/html/rfc6819#section-5.2.4.4) +* [Binding of Authorization "code" to "redirect_uri"](https://tools.ietf.org/html/rfc6819#section-5.2.4.6) +* [Opaque access tokens](https://tools.ietf.org/html/rfc6749#section-1.4) +* [Opaque refresh tokens](https://tools.ietf.org/html/rfc6749#section-1.5) +* [Ensure Confidentiality of Requests](https://tools.ietf.org/html/rfc6819#section-5.1.1) +* [Use of Asymmetric Cryptography](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.5) + Fosite ensures that redirect URIs use https **except localhost** but you need to implement + TLS for the token and auth endpoints yourself. + +Additionally, we added these safeguards: +* **Enforcing random states:** Without a random-looking state or OpenID Connect nonce the request will fail. +* **Advanced Token Validation:** Tokens are layouted as `.` where `` is created using HMAC-SHA256 + using a global secret. + This is what a token can look like: + `/tgBeUhWlAT8tM8Bhmnx+Amf8rOYOUhrDi3pGzmjP7c=.BiV/Yhma+5moTP46anxMT6cWW8gz5R5vpC9RbpwSDdM=` + +Sections below [Section 5](https://tools.ietf.org/html/rfc6819#section-5) +that are not covered in the list above should be reviewed by you. If you think that a specific section should be something +that is covered in Fosite, feel free to create an [issue](https://github.com/ory/fosite/issues). Please be +aware that OpenID Connect requires specific knowledge of the identity provider, which is why Fosite only implements core +requirements and most things must be implemented by you (for example prompt, max_age, ui_locales, id_token_hint, user authentication, session management, ...). + +**It is strongly encouraged to use the handlers shipped with Fosite as they follow the specs and are well tested.** + +## A word on extensibility + +Fosite is extensible ... because OAuth2 is an extensible and flexible **framework**. +Fosite let's you register custom token and authorize endpoint handlers with the security that the requests +have been validated against the OAuth2 specs beforehand. +You can easily extend Fosite's capabilities. For example, if you want to provide OpenID Connect on top of your +OAuth2 stack, that's no problem. Or custom assertions, what ever you like and as long as it is secure. ;) + +## Installation + +[Go 1.11+](https://golang.org) must be installed on your system and it is required that you have set up your +GOPATH environment variable. + +``` +go get -u github.com/ory/fosite/... +``` + +We recommend to use [dep](https://github.com/golang/dep) to +mitigate compatibility breaks that come with new api versions. + +## Documentation + +There is an API documentation available at [godoc.org/ory/fosite](https://godoc.org/github.com/ory/fosite). + +### Scopes + +Fosite has three strategies for matching scopes. You can replace the default scope strategy if you need a custom +one by implementing `fosite.ScopeStrategy`. + +Using the composer, setting a strategy is easy: + +```go +import "github.com/ory/fosite/compose" + +var config = &compose.Config{ + ScopeStrategy: fosite.HierarchicScopeStrategy, +} +``` + +**Note:** To issue refresh tokens with any of the grants, you need to include the `offline` scope in the OAuth2 request. This can be modified by the `RefreshTokenScopes` compose configuration. When set to an empty array, _all_ grants will issue refresh tokens. + +#### `fosite.WildcardScopeStrategy` + +This is the default strategy, and the safest one. It is best explained by looking at some examples: + +* `users.*` matches `users.read` +* `users.*` matches `users.read.foo` +* `users.read` matches `users.read` +* `users` does not match `users.read` +* `users.read.*` does not match `users.read` +* `users.*.*` does not match `users.read` +* `users.*.*` matches `users.read.own` +* `users.*.*` matches `users.read.own.other` +* `users.read.*` matches `users.read.own` +* `users.read.*` matches `users.read.own.other` +* `users.write.*` does not match `users.read.own` +* `users.*.bar` matches `users.baz.bar` +* `users.*.bar` does not `users.baz.baz.bar` + +To request `users.*`, a client must have exactly `users.*` as granted scope. + +#### `fosite.ExactScopeStrategy` + +This strategy is searching only for exact matches. It returns true iff the scope is granted. + +#### `fosite.HierarchicScopeStrategy` + +This strategy is deprecated, use it with care. Again, it is best explained by looking at some examples: + +* `users` matches `users` +* `users` matches `users.read` +* `users` matches `users.read.own` +* `users.read` matches `users.read` +* `users.read` matches `users.read.own` +* `users.read` does not match `users.write` +* `users.read` does not match `users.write.own` + +### Quickstart + +Instantiating fosite by hand can be painful. Therefore we created a few convenience helpers available through the [compose package](/compose). +It is strongly encouraged to use these well tested composers. + +In this very basic example, we will instantiate fosite with all OpenID Connect and OAuth2 handlers enabled. Please refer +to the [example app](https://github.com/ory/fosite-example/) for more details. + +This little code snippet sets up a full-blown OAuth2 and OpenID Connect example. + +```go +import "github.com/ory/fosite" +import "github.com/ory/fosite/compose" +import "github.com/ory/fosite/storage" + +// This is the example storage that contains: +// * an OAuth2 Client with id "my-client" and secret "foobar" capable of all oauth2 and open id connect grant and response types. +// * a User for the resource owner password credentials grant type with username "peter" and password "secret". +// +// You will most likely replace this with your own logic once you set up a real world application. +var storage = storage.NewExampleStore() + +// This secret is being used to sign access and refresh tokens as well as +// authorization codes. It must be exactly 32 bytes long. +var secret = []byte("my super secret signing password") + +privateKey, err := rsa.GenerateKey(rand.Reader, 2048) +if err != nil { + panic("unable to create private key") +} + +// check the api docs of compose.Config for further configuration options +var config = &compose.Config { + AccessTokenLifespan: time.Minute * 30, + // ... +} + +var oauth2Provider = compose.ComposeAllEnabled(config, storage, secret, privateKey) + +// The authorize endpoint is usually at "https://mydomain.com/oauth2/auth". +func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) { + // This context will be passed to all methods. It doesn't fulfill a real purpose in the standard library but could be used + // to abort database lookups or similar things. + ctx := req.Context() + + // Let's create an AuthorizeRequest object! + // It will analyze the request and extract important information like scopes, response type and others. + ar, err := oauth2Provider.NewAuthorizeRequest(ctx, req) + if err != nil { + oauth2Provider.WriteAuthorizeError(rw, ar, err) + return + } + + // Normally, this would be the place where you would check if the user is logged in and gives his consent. + // We're simplifying things and just checking if the request includes a valid username and password + if req.Form.Get("username") != "peter" { + rw.Header().Set("Content-Type", "text/html; charset=utf-8") + rw.Write([]byte(`

Login page

`)) + rw.Write([]byte(` +

Howdy! This is the log in page. For this example, it is enough to supply the username.

+
+ try peter
+ +
+ `)) + return + } + + // Now that the user is authorized, we set up a session. When validating / looking up tokens, we additionally get + // the session. You can store anything you want in it. + + // The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests. + // The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the + // session struct can be anything you want it to be. + mySessionData := &fosite.DefaultSession{ + Username: req.Form.Get("username"), + } + + // It's also wise to check the requested scopes, e.g.: + // if authorizeRequest.GetScopes().Has("admin") { + // http.Error(rw, "you're not allowed to do that", http.StatusForbidden) + // return + // } + + // Now we need to get a response. This is the place where the AuthorizeEndpointHandlers kick in and start processing the request. + // NewAuthorizeResponse is capable of running multiple response type handlers which in turn enables this library + // to support open id connect. + response, err := oauth2Provider.NewAuthorizeResponse(ctx, ar, mySessionData) + if err != nil { + oauth2Provider.WriteAuthorizeError(rw, ar, err) + return + } + + // Awesome, now we redirect back to the client redirect uri and pass along an authorize code + oauth2Provider.WriteAuthorizeResponse(rw, ar, response) +} + +// The token endpoint is usually at "https://mydomain.com/oauth2/token" +func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) { + ctx := req.Context() + mySessionData := new(fosite.DefaultSession) + + // This will create an access request object and iterate through the registered TokenEndpointHandlers to validate the request. + accessRequest, err := oauth2Provider.NewAccessRequest(ctx, req, mySessionData) + if err != nil { + oauth2Provider.WriteAccessError(rw, accessRequest, err) + return + } + + if mySessionData.Username == "super-admin-guy" { + // do something... + } + + // Next we create a response for the access request. Again, we iterate through the TokenEndpointHandlers + // and aggregate the result in response. + response, err := oauth2Provider.NewAccessResponse(ctx, accessRequest) + if err != nil { + oauth2Provider.WriteAccessError(rw, accessRequest, err) + return + } + + // All done, send the response. + oauth2Provider.WriteAccessResponse(rw, accessRequest, response) + + // The client has a valid access token now +} + +func someResourceProviderHandlerFunc(rw http.ResponseWriter, req *http.Request) { + ctx := req.Context() + requiredScope := "blogposts.create" + + _, ar, err := oauth2Provider.IntrospectToken(ctx, fosite.AccessTokenFromRequest(req), fosite.AccessToken, new(fosite.DefaultSession), requiredScope) + if err != nil { + // ... + } + + // If no error occurred the token + scope is valid and you have access to: + // ar.GetClient().GetID(), ar.GetGrantedScopes(), ar.GetScopes(), ar.GetSession().UserID, ar.GetRequestedAt(), ... +} +``` + +### Code Examples + +Fosite provides integration tests as well as a http server example: + +* Fosite ships with an example app that runs in your browser: [Example app](https://github.com/ory/fosite-example/). +* If you want to check out how to enable specific handlers, check out the [integration tests](integration/). + +If you have working examples yourself, please share them with us! + +### Example Storage Implementation + +Fosite does not ship a storage implementation. This is intended, because requirements vary with every environment. +You can find a reference implementation at [storage/memory.go](storage/memory.go). +This storage fulfills requirements from all OAuth2 and OpenID Connect handlers. + +### Extensible handlers + +OAuth2 is a framework. Fosite mimics this behaviour by enabling you to replace existing or create new OAuth2 handlers. +Of course, fosite ships handlers for all OAuth2 and OpenID Connect flows. + +* **[Fosite OAuth2 Core Handlers](handler/oauth2)** implement the [Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4), + [Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.3), + [Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2), + [Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1), + [Refresh Token Grant](https://tools.ietf.org/html/rfc6749#section-6) +* **[Fosite OpenID Connect Handlers](handler/openid)** implement the + [Authentication using the Authorization Code Flow](http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth), + [Authentication using the Implicit Flow](http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth), + [Authentication using the Hybrid Flow](http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth) + +This section is missing documentation and we welcome any contributions in that direction. + +### JWT Introspection + +Please note that when using the OAuth2StatelessJWTIntrospectionFactory access token revocation is not possible. + +## Contribute + +You need git and golang installed on your system. + +``` +go get -d github.com/ory/fosite +cd $GOPATH/src/github.com/ory/fosite +git status +git remote add myfork +go test ./.. +``` + +Simple, right? Now you are ready to go! Make sure to run `go test ./...` often, detecting problems with your code +rather sooner than later. Please read [CONTRIBUTE.md] before creating pull requests and issues. + +### Refresh mock objects + +Run `./generate-mocks.sh` in fosite's root directory or run the contents of [generate-mocks.sh] in a shell. + +## Hall of Fame + +This place is reserved for the fearless bug hunters, reviewers and contributors (alphabetical order). + +* [agtorre](https://github.com/agtorre): + [contributions](https://github.com/ory/fosite/issues?q=author%3Aagtorre), + [participations](https://github.com/ory/fosite/issues?q=commenter%3Aagtorre). +* [danielchatfield](https://github.com/danielchatfield): + [contributions](https://github.com/ory/fosite/issues?q=author%3Adanielchatfield), + [participations](https://github.com/ory/fosite/issues?q=commenter%3Adanielchatfield). +* [leetal](https://github.com/leetal): + [contributions](https://github.com/ory/fosite/issues?q=author%3Aleetal), + [participations](https://github.com/ory/fosite/issues?q=commenter%3Aleetal). +* [jrossiter](https://github.com/jrossiter): + [contributions](https://github.com/ory/fosite/issues?q=author%3Ajrossiter), + [participations](https://github.com/ory/fosite/issues?q=commenter%3Ajrossiter). +* [jrossiter](https://github.com/jrossiter): + [contributions](https://github.com/ory/fosite/issues?q=author%3Ajrossiter), + [participations](https://github.com/ory/fosite/issues?q=commenter%3Ajrossiter). +* [danilobuerger](https://github.com/danilobuerger): + [contributions](https://github.com/ory/fosite/issues?q=author%3Adanilobuerger), + [participations](https://github.com/ory/fosite/issues?q=commenter%3Adanilobuerger). + +Find out more about the [author](https://aeneas.io/) of Fosite and Hydra, and the +[Ory Company](https://ory.am/). diff --git a/vendor/github.com/ory/fosite/SECURITY.md b/vendor/github.com/ory/fosite/SECURITY.md new file mode 100644 index 0000000000..8bae0531cd --- /dev/null +++ b/vendor/github.com/ory/fosite/SECURITY.md @@ -0,0 +1,38 @@ + + + + + + +- [Security Policy](#security-policy) + - [Supported Versions](#supported-versions) + - [Reporting a Vulnerability](#reporting-a-vulnerability) + + + +# Security Policy + +## Supported Versions + +We release patches for security vulnerabilities. Which versions are eligible +receiving such patches depend on the CVSS v3.0 Rating: + +| CVSS v3.0 | Supported Versions | +| --------- | ----------------------------------------- | +| 9.0-10.0 | Releases within the previous three months | +| 4.0-8.9 | Most recent release | + +## Reporting a Vulnerability + +Please report (suspected) security vulnerabilities to +**[security@ory.sh](mailto:security@ory.sh)**. You will receive a response from +us within 48 hours. If the issue is confirmed, we will release a patch as soon +as possible depending on complexity but historically within a few days. diff --git a/vendor/github.com/ory/fosite/access_error.go b/vendor/github.com/ory/fosite/access_error.go new file mode 100644 index 0000000000..9c6902a35b --- /dev/null +++ b/vendor/github.com/ory/fosite/access_error.go @@ -0,0 +1,50 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "encoding/json" + "fmt" + "net/http" +) + +func (f *Fosite) WriteAccessError(rw http.ResponseWriter, _ AccessRequester, err error) { + f.writeJsonError(rw, err) +} + +func (f *Fosite) writeJsonError(rw http.ResponseWriter, err error) { + rw.Header().Set("Content-Type", "application/json;charset=UTF-8") + + rfcerr := ErrorToRFC6749Error(err) + if !f.SendDebugMessagesToClients { + rfcerr.Debug = "" + } + + js, err := json.Marshal(rfcerr) + if err != nil { + http.Error(rw, fmt.Sprintf(`{"error": "%s"}`, err.Error()), http.StatusInternalServerError) + return + } + + rw.WriteHeader(rfcerr.Code) + rw.Write(js) +} diff --git a/vendor/github.com/ory/fosite/access_request.go b/vendor/github.com/ory/fosite/access_request.go new file mode 100644 index 0000000000..6efb9df10d --- /dev/null +++ b/vendor/github.com/ory/fosite/access_request.go @@ -0,0 +1,43 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +type AccessRequest struct { + GrantTypes Arguments `json:"grantTypes" gorethink:"grantTypes"` + HandledGrantType Arguments `json:"handledGrantType" gorethink:"handledGrantType"` + + Request +} + +func NewAccessRequest(session Session) *AccessRequest { + r := &AccessRequest{ + GrantTypes: Arguments{}, + HandledGrantType: Arguments{}, + Request: *NewRequest(), + } + r.Session = session + return r +} + +func (a *AccessRequest) GetGrantTypes() Arguments { + return a.GrantTypes +} diff --git a/vendor/github.com/ory/fosite/access_request_handler.go b/vendor/github.com/ory/fosite/access_request_handler.go new file mode 100644 index 0000000000..c13363f579 --- /dev/null +++ b/vendor/github.com/ory/fosite/access_request_handler.go @@ -0,0 +1,102 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "net/http" + "strings" + + "github.com/pkg/errors" +) + +// Implements +// * https://tools.ietf.org/html/rfc6749#section-2.3.1 +// Clients in possession of a client password MAY use the HTTP Basic +// authentication scheme as defined in [RFC2617] to authenticate with +// the authorization server. The client identifier is encoded using the +// "application/x-www-form-urlencoded" encoding algorithm per +// Appendix B, and the encoded value is used as the username; the client +// password is encoded using the same algorithm and used as the +// password. The authorization server MUST support the HTTP Basic +// authentication scheme for authenticating clients that were issued a +// client password. +// Including the client credentials in the request-body using the two +// parameters is NOT RECOMMENDED and SHOULD be limited to clients unable +// to directly utilize the HTTP Basic authentication scheme (or other +// password-based HTTP authentication schemes). The parameters can only +// be transmitted in the request-body and MUST NOT be included in the +// request URI. +// * https://tools.ietf.org/html/rfc6749#section-3.2.1 +// - Confidential clients or other clients issued client credentials MUST +// authenticate with the authorization server as described in +// Section 2.3 when making requests to the token endpoint. +// - If the client type is confidential or the client was issued client +// credentials (or assigned other authentication requirements), the +// client MUST authenticate with the authorization server as described +// in Section 3.2.1. +func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session Session) (AccessRequester, error) { + var err error + accessRequest := NewAccessRequest(session) + + if r.Method != "POST" { + return accessRequest, errors.WithStack(ErrInvalidRequest.WithHintf("HTTP method is \"%s\", expected \"POST\".", r.Method)) + } else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart { + return accessRequest, errors.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithDebug(err.Error())) + } else if len(r.PostForm) == 0 { + return accessRequest, errors.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty.")) + } + + accessRequest.Form = r.PostForm + if session == nil { + return accessRequest, errors.New("Session must not be nil") + } + + accessRequest.SetRequestedScopes(RemoveEmpty(strings.Split(r.PostForm.Get("scope"), " "))) + accessRequest.SetRequestedAudience(RemoveEmpty(strings.Split(r.PostForm.Get("audience"), " "))) + accessRequest.GrantTypes = RemoveEmpty(strings.Split(r.PostForm.Get("grant_type"), " ")) + if len(accessRequest.GrantTypes) < 1 { + return accessRequest, errors.WithStack(ErrInvalidRequest.WithHint(`Request parameter "grant_type"" is missing`)) + } + + client, err := f.AuthenticateClient(ctx, r, r.PostForm) + if err != nil { + return accessRequest, err + } + accessRequest.Client = client + + var found bool = false + for _, loader := range f.TokenEndpointHandlers { + if err := loader.HandleTokenEndpointRequest(ctx, accessRequest); err == nil { + found = true + } else if errors.Cause(err).Error() == ErrUnknownRequest.Error() { + // do nothing + } else if err != nil { + return accessRequest, err + } + } + + if !found { + return nil, errors.WithStack(ErrInvalidRequest) + } + return accessRequest, nil +} diff --git a/vendor/github.com/ory/fosite/access_response.go b/vendor/github.com/ory/fosite/access_response.go new file mode 100644 index 0000000000..0734f5f32e --- /dev/null +++ b/vendor/github.com/ory/fosite/access_response.go @@ -0,0 +1,77 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "strings" + "time" +) + +func NewAccessResponse() *AccessResponse { + return &AccessResponse{ + Extra: map[string]interface{}{}, + } +} + +type AccessResponse struct { + Extra map[string]interface{} + AccessToken string + TokenType string +} + +func (a *AccessResponse) SetScopes(scopes Arguments) { + a.SetExtra("scope", strings.Join(scopes, " ")) +} + +func (a *AccessResponse) SetExpiresIn(expiresIn time.Duration) { + a.SetExtra("expires_in", int64(expiresIn/time.Second)) +} + +func (a *AccessResponse) SetExtra(key string, value interface{}) { + a.Extra[key] = value +} + +func (a *AccessResponse) GetExtra(key string) interface{} { + return a.Extra[key] +} + +func (a *AccessResponse) SetAccessToken(token string) { + a.AccessToken = token +} + +func (a *AccessResponse) SetTokenType(name string) { + a.TokenType = name +} + +func (a *AccessResponse) GetAccessToken() string { + return a.AccessToken +} + +func (a *AccessResponse) GetTokenType() string { + return a.TokenType +} + +func (a *AccessResponse) ToMap() map[string]interface{} { + a.Extra["access_token"] = a.GetAccessToken() + a.Extra["token_type"] = a.GetTokenType() + return a.Extra +} diff --git a/vendor/github.com/ory/fosite/access_response_writer.go b/vendor/github.com/ory/fosite/access_response_writer.go new file mode 100644 index 0000000000..4508bb617d --- /dev/null +++ b/vendor/github.com/ory/fosite/access_response_writer.go @@ -0,0 +1,48 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + + "github.com/pkg/errors" +) + +func (f *Fosite) NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error) { + var err error + var tk TokenEndpointHandler + + response := NewAccessResponse() + for _, tk = range f.TokenEndpointHandlers { + if err = tk.PopulateTokenEndpointResponse(ctx, requester, response); err == nil { + } else if errors.Cause(err).Error() == ErrUnknownRequest.Error() { + } else if err != nil { + return nil, err + } + } + + if response.GetAccessToken() == "" || response.GetTokenType() == "" { + return nil, errors.WithStack(ErrServerError.WithHint("An internal server occurred while trying to complete the request.").WithDebug("Access token or token type not set by TokenEndpointHandlers.")) + } + + return response, nil +} diff --git a/vendor/github.com/ory/fosite/access_write.go b/vendor/github.com/ory/fosite/access_write.go new file mode 100644 index 0000000000..b7a1c91e4c --- /dev/null +++ b/vendor/github.com/ory/fosite/access_write.go @@ -0,0 +1,42 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "encoding/json" + "net/http" +) + +func (f *Fosite) WriteAccessResponse(rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) { + js, err := json.Marshal(responder.ToMap()) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + rw.Header().Set("Content-Type", "application/json;charset=UTF-8") + rw.Header().Set("Cache-Control", "no-store") + rw.Header().Set("Pragma", "no-cache") + + rw.WriteHeader(http.StatusOK) + rw.Write(js) +} diff --git a/vendor/github.com/ory/fosite/arguments.go b/vendor/github.com/ory/fosite/arguments.go new file mode 100644 index 0000000000..73783d657c --- /dev/null +++ b/vendor/github.com/ory/fosite/arguments.go @@ -0,0 +1,98 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import "strings" + +type Arguments []string + +// Matches performs an case-insensitive, out-of-order check that the items +// provided exist and equal all of the args in arguments. +// Note: +// - Providing a list that includes duplicate string-case items will return not +// matched. +func (r Arguments) Matches(items ...string) bool { + if len(r) != len(items) { + return false + } + + found := make(map[string]bool) + for _, item := range items { + if !StringInSlice(item, r) { + return false + } + found[item] = true + } + + return len(found) == len(r) +} + +// Has checks, in a case-insensitive manner, that all of the items +// provided exists in arguments. +func (r Arguments) Has(items ...string) bool { + for _, item := range items { + if !StringInSlice(item, r) { + return false + } + } + + return true +} + +// HasOneOf checks, in a case-insensitive manner, that one of the items +// provided exists in arguments. +func (r Arguments) HasOneOf(items ...string) bool { + for _, item := range items { + if StringInSlice(item, r) { + return true + } + } + + return false +} + +// Deprecated: Use ExactOne, Matches or MatchesExact +func (r Arguments) Exact(name string) bool { + return name == strings.Join(r, " ") +} + +// ExactOne checks, by string case, that a single argument equals the provided +// string. +func (r Arguments) ExactOne(name string) bool { + return len(r) == 1 && r[0] == name +} + +// MatchesExact checks, by order and string case, that the items provided equal +// those in arguments. +func (r Arguments) MatchesExact(items ...string) bool { + if len(r) != len(items) { + return false + } + + for i, item := range items { + if item != r[i] { + return false + } + } + + return true +} diff --git a/vendor/github.com/ory/fosite/audience_strategy.go b/vendor/github.com/ory/fosite/audience_strategy.go new file mode 100644 index 0000000000..cabcb4ddd4 --- /dev/null +++ b/vendor/github.com/ory/fosite/audience_strategy.go @@ -0,0 +1,60 @@ +package fosite + +import ( + "net/http" + "net/url" + "strings" + + "github.com/pkg/errors" + + "github.com/ory/go-convenience/stringsx" +) + +type AudienceMatchingStrategy func(haystack []string, needle []string) error + +func DefaultAudienceMatchingStrategy(haystack []string, needle []string) error { + if len(needle) == 0 { + return nil + } + + for _, n := range needle { + nu, err := url.Parse(n) + if err != nil { + return errors.WithStack(ErrInvalidRequest.WithHintf(`Unable to parse requested audience "%s".`, n).WithDebug(err.Error())) + } + + var found bool + for _, h := range haystack { + hu, err := url.Parse(h) + if err != nil { + return errors.WithStack(ErrInvalidRequest.WithHintf(`Unable to parse whitelisted audience "%s".`, h).WithDebug(err.Error())) + } + + allowedPath := strings.TrimRight(hu.Path, "/") + if nu.Scheme == hu.Scheme && + nu.Host == hu.Host && + (nu.Path == hu.Path || + nu.Path == allowedPath || + len(nu.Path) > len(allowedPath) && strings.TrimRight(nu.Path[:len(allowedPath)+1], "/")+"/" == allowedPath+"/") { + found = true + } + } + + if !found { + return errors.WithStack(ErrInvalidRequest.WithHintf(`Requested audience "%s" has not been whitelisted by the OAuth 2.0 Client.`, n)) + } + } + + return nil +} + +func (f *Fosite) validateAuthorizeAudience(r *http.Request, request *AuthorizeRequest) error { + audience := stringsx.Splitx(request.Form.Get("audience"), " ") + + if err := f.AudienceMatchingStrategy(request.Client.GetAudience(), audience); err != nil { + return err + } + + request.SetRequestedAudience(Arguments(audience)) + return nil +} diff --git a/vendor/github.com/ory/fosite/authorize_error.go b/vendor/github.com/ory/fosite/authorize_error.go new file mode 100644 index 0000000000..c7b8ecfe10 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_error.go @@ -0,0 +1,77 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "encoding/json" + "net/http" + "net/url" + + "github.com/pkg/errors" +) + +func (f *Fosite) WriteAuthorizeError(rw http.ResponseWriter, ar AuthorizeRequester, err error) { + rfcerr := ErrorToRFC6749Error(err) + if !ar.IsRedirectURIValid() { + if !f.SendDebugMessagesToClients { + rfcerr.Debug = "" + } + + js, err := json.MarshalIndent(rfcerr, "", "\t") + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + rw.Header().Set("Content-Type", "application/json") + rw.WriteHeader(rfcerr.Code) + rw.Write(js) + return + } + + redirectURI := ar.GetRedirectURI() + query := url.Values{} + query.Add("error", rfcerr.Name) + query.Add("error_description", rfcerr.Description) + query.Add("state", ar.GetState()) + if f.SendDebugMessagesToClients && rfcerr.Debug != "" { + query.Add("error_debug", rfcerr.Debug) + } + + if rfcerr.Hint != "" { + query.Add("error_hint", rfcerr.Hint) + } + + if !(len(ar.GetResponseTypes()) == 0 || ar.GetResponseTypes().ExactOne("code")) && errors.Cause(err) != ErrUnsupportedResponseType { + redirectURI.Fragment = query.Encode() + } else { + for key, values := range redirectURI.Query() { + for _, value := range values { + query.Add(key, value) + } + } + redirectURI.RawQuery = query.Encode() + } + + rw.Header().Add("Location", redirectURI.String()) + rw.WriteHeader(http.StatusFound) +} diff --git a/vendor/github.com/ory/fosite/authorize_helper.go b/vendor/github.com/ory/fosite/authorize_helper.go new file mode 100644 index 0000000000..0ac6590146 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_helper.go @@ -0,0 +1,181 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "net/url" + "regexp" + "strings" + + "github.com/asaskevich/govalidator" + "github.com/pkg/errors" +) + +// GetRedirectURIFromRequestValues extracts the redirect_uri from values but does not do any sort of validation. +// +// Considered specifications +// * https://tools.ietf.org/html/rfc6749#section-3.1 +// The endpoint URI MAY include an +// "application/x-www-form-urlencoded" formatted (per Appendix B) query +// component ([RFC3986] Section 3.4), which MUST be retained when adding +// additional query parameters. +func GetRedirectURIFromRequestValues(values url.Values) (string, error) { + // rfc6749 3.1. Authorization Endpoint + // The endpoint URI MAY include an "application/x-www-form-urlencoded" formatted (per Appendix B) query component + redirectURI, err := url.QueryUnescape(values.Get("redirect_uri")) + if err != nil { + return "", errors.WithStack(ErrInvalidRequest.WithHint(`The "redirect_uri" parameter is malformed or missing.`).WithDebug(err.Error())) + } + return redirectURI, nil +} + +// MatchRedirectURIWithClientRedirectURIs if the given uri is a registered redirect uri. Does not perform +// uri validation. +// +// Considered specifications +// * https://tools.ietf.org/html/rfc6749#section-3.1.2.3 +// If multiple redirection URIs have been registered, if only part of +// the redirection URI has been registered, or if no redirection URI has +// been registered, the client MUST include a redirection URI with the +// authorization request using the "redirect_uri" request parameter. +// +// When a redirection URI is included in an authorization request, the +// authorization server MUST compare and match the value received +// against at least one of the registered redirection URIs (or URI +// components) as defined in [RFC3986] Section 6, if any redirection +// URIs were registered. If the client registration included the full +// redirection URI, the authorization server MUST compare the two URIs +// using simple string comparison as defined in [RFC3986] Section 6.2.1. +// +// * https://tools.ietf.org/html/rfc6819#section-4.4.1.7 +// * The authorization server may also enforce the usage and validation +// of pre-registered redirect URIs (see Section 5.2.3.5). This will +// allow for early recognition of authorization "code" disclosure to +// counterfeit clients. +// * The attacker will need to use another redirect URI for its +// authorization process rather than the target web site because it +// needs to intercept the flow. So, if the authorization server +// associates the authorization "code" with the redirect URI of a +// particular end-user authorization and validates this redirect URI +// with the redirect URI passed to the token's endpoint, such an +// attack is detected (see Section 5.2.4.5). +func MatchRedirectURIWithClientRedirectURIs(rawurl string, client Client) (*url.URL, error) { + if rawurl == "" && len(client.GetRedirectURIs()) == 1 { + if redirectURIFromClient, err := url.Parse(client.GetRedirectURIs()[0]); err == nil && IsValidRedirectURI(redirectURIFromClient) { + // If no redirect_uri was given and the client has exactly one valid redirect_uri registered, use that instead + return redirectURIFromClient, nil + } + } else if rawurl != "" && isMatchingRedirectURI(rawurl, client.GetRedirectURIs()) { + // If a redirect_uri was given and the clients knows it (simple string comparison!) + // return it. + if parsed, err := url.Parse(rawurl); err == nil && IsValidRedirectURI(parsed) { + // If no redirect_uri was given and the client has exactly one valid redirect_uri registered, use that instead + return parsed, nil + } + } + + return nil, errors.WithStack(ErrInvalidRequest.WithHint(`The "redirect_uri" parameter does not match any of the OAuth 2.0 Client's pre-registered redirect urls.`)) +} + +// Match a requested redirect URI against a pool of registered client URIs +// +// Test a given redirect URI against a pool of URIs provided by a registered client. +// If the OAuth 2.0 Client has loopback URIs registered either an IPv4 URI http://127.0.0.1 or +// an IPv6 URI http://[::1] a client is allowed to request a dynamic port and the server MUST accept +// it as a valid redirection uri. +// +// https://tools.ietf.org/html/rfc8252#section-7.3 +// Native apps that are able to open a port on the loopback network +// interface without needing special permissions (typically, those on +// desktop operating systems) can use the loopback interface to receive +// the OAuth redirect. +// +// Loopback redirect URIs use the "http" scheme and are constructed with +// the loopback IP literal and whatever port the client is listening on. +func isMatchingRedirectURI(uri string, haystack []string) bool { + requested, err := url.Parse(uri) + if err != nil { + return false + } + + for _, b := range haystack { + if strings.ToLower(b) == strings.ToLower(uri) || isLoopbackURI(requested, b) { + return true + } + } + return false +} + +func isLoopbackURI(requested *url.URL, registeredURI string) bool { + registered, err := url.Parse(registeredURI) + if err != nil { + return false + } + + if registered.Scheme != "http" || !isLoopbackAddress(registered.Host) { + return false + } + + if requested.Scheme == "http" && isLoopbackAddress(requested.Host) && registered.Path == requested.Path { + return true + } + + return false +} + +// Check if address is either an IPv4 loopback or an IPv6 loopback- +// An optional port is ignored +func isLoopbackAddress(address string) bool { + match, _ := regexp.MatchString("^(127.0.0.1|\\[::1\\])(:?)(\\d*)$", address) + return match +} + +// IsValidRedirectURI validates a redirect_uri as specified in: +// +// * https://tools.ietf.org/html/rfc6749#section-3.1.2 +// * The redirection endpoint URI MUST be an absolute URI as defined by [RFC3986] Section 4.3. +// * The endpoint URI MUST NOT include a fragment component. +// * https://tools.ietf.org/html/rfc3986#section-4.3 +// absolute-URI = scheme ":" hier-part [ "?" query ] +// * https://tools.ietf.org/html/rfc6819#section-5.1.1 +func IsValidRedirectURI(redirectURI *url.URL) bool { + // We need to explicitly check for a scheme + if !govalidator.IsRequestURL(redirectURI.String()) { + return false + } + + if redirectURI.Fragment != "" { + // "The endpoint URI MUST NOT include a fragment component." + return false + } + + return true +} + +func IsRedirectURISecure(redirectURI *url.URL) bool { + return !(redirectURI.Scheme == "http" && !IsLocalhost(redirectURI)) +} + +func IsLocalhost(redirectURI *url.URL) bool { + hn := redirectURI.Hostname() + return strings.HasSuffix(hn, ".localhost") || hn == "127.0.0.1" || hn == "localhost" +} diff --git a/vendor/github.com/ory/fosite/authorize_request.go b/vendor/github.com/ory/fosite/authorize_request.go new file mode 100644 index 0000000000..dade3a3a46 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_request.go @@ -0,0 +1,88 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "net/url" +) + +// AuthorizeRequest is an implementation of AuthorizeRequester +type AuthorizeRequest struct { + ResponseTypes Arguments `json:"responseTypes" gorethink:"responseTypes"` + RedirectURI *url.URL `json:"redirectUri" gorethink:"redirectUri"` + State string `json:"state" gorethink:"state"` + HandledResponseTypes Arguments `json:"handledResponseTypes" gorethink:"handledResponseTypes"` + + Request +} + +func NewAuthorizeRequest() *AuthorizeRequest { + return &AuthorizeRequest{ + ResponseTypes: Arguments{}, + RedirectURI: &url.URL{}, + HandledResponseTypes: Arguments{}, + Request: *NewRequest(), + } +} + +func (d *AuthorizeRequest) IsRedirectURIValid() bool { + if d.GetRedirectURI() == nil { + return false + } + + raw := d.GetRedirectURI().String() + if d.GetClient() == nil { + return false + } + + redirectURI, err := MatchRedirectURIWithClientRedirectURIs(raw, d.GetClient()) + if err != nil { + return false + } + return IsValidRedirectURI(redirectURI) +} + +func (d *AuthorizeRequest) GetResponseTypes() Arguments { + return d.ResponseTypes +} + +func (d *AuthorizeRequest) GetState() string { + return d.State +} + +func (d *AuthorizeRequest) GetRedirectURI() *url.URL { + return d.RedirectURI +} + +func (d *AuthorizeRequest) SetResponseTypeHandled(name string) { + d.HandledResponseTypes = append(d.HandledResponseTypes, name) +} + +func (d *AuthorizeRequest) DidHandleAllResponseTypes() bool { + for _, rt := range d.ResponseTypes { + if !d.HandledResponseTypes.Has(rt) { + return false + } + } + + return len(d.ResponseTypes) > 0 +} diff --git a/vendor/github.com/ory/fosite/authorize_request_handler.go b/vendor/github.com/ory/fosite/authorize_request_handler.go new file mode 100644 index 0000000000..5aab12d3c2 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_request_handler.go @@ -0,0 +1,276 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "strings" + + jwt "github.com/dgrijalva/jwt-go" + "github.com/pkg/errors" + + "github.com/ory/go-convenience/stringslice" + "github.com/ory/go-convenience/stringsx" +) + +func (f *Fosite) authorizeRequestParametersFromOpenIDConnectRequest(request *AuthorizeRequest) error { + var scope Arguments = stringsx.Splitx(request.Form.Get("scope"), " ") + + // Even if a scope parameter is present in the Request Object value, a scope parameter MUST always be passed using + // the OAuth 2.0 request syntax containing the openid scope value to indicate to the underlying OAuth 2.0 logic that this is an OpenID Connect request. + // Source: http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth + if !scope.Has("openid") { + return nil + } + + if len(request.Form.Get("request")+request.Form.Get("request_uri")) == 0 { + return nil + } else if len(request.Form.Get("request")) > 0 && len(request.Form.Get("request_uri")) > 0 { + return errors.WithStack(ErrInvalidRequest.WithHint(`OpenID Connect parameters "request" and "request_uri" were both given, but you can use at most one.`)) + } + + oidcClient, ok := request.Client.(OpenIDConnectClient) + if !ok { + if len(request.Form.Get("request_uri")) > 0 { + return errors.WithStack(ErrRequestURINotSupported.WithHint(`OpenID Connect "request_uri" context was given, but the OAuth 2.0 Client does not implement advanced OpenID Connect capabilities.`)) + } + return errors.WithStack(ErrRequestNotSupported.WithHint(`OpenID Connect "request" context was given, but the OAuth 2.0 Client does not implement advanced OpenID Connect capabilities.`)) + } + + if oidcClient.GetJSONWebKeys() == nil && len(oidcClient.GetJSONWebKeysURI()) == 0 { + return errors.WithStack(ErrInvalidRequest.WithHint(`OpenID Connect "request" or "request_uri" context was given, but the OAuth 2.0 Client does not have any JSON Web Keys registered.`)) + } + + assertion := request.Form.Get("request") + if location := request.Form.Get("request_uri"); len(location) > 0 { + if !stringslice.Has(oidcClient.GetRequestURIs(), location) { + return errors.WithStack(ErrInvalidRequestURI.WithHint(fmt.Sprintf("Request URI \"%s\" is not whitelisted by the OAuth 2.0 Client.", location))) + } + + hc := f.HTTPClient + if hc == nil { + hc = http.DefaultClient + } + + response, err := hc.Get(location) + if err != nil { + return errors.WithStack(ErrInvalidRequestURI.WithHintf(`Unable to fetch OpenID Connect request parameters from "request_uri" because %s.`, err.Error())) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return errors.WithStack(ErrInvalidRequestURI.WithHintf(`Unable to fetch OpenID Connect request parameters from "request_uri" because status code "%d" was expected, but got "%d".`, http.StatusOK, response.StatusCode)) + } + + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return errors.WithStack(ErrInvalidRequestURI.WithHintf(`Unable to fetch OpenID Connect request parameters from "request_uri" because error %s occurred during body parsing.`, err)) + } + + assertion = string(body) + } + + token, err := jwt.ParseWithClaims(assertion, new(jwt.MapClaims), func(t *jwt.Token) (interface{}, error) { + if oidcClient.GetRequestObjectSigningAlgorithm() != fmt.Sprintf("%s", t.Header["alg"]) { + return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf(`The request object uses signing algorithm %s, but the requested OAuth 2.0 Client enforces signing algorithm %s.`, t.Header["alg"], oidcClient.GetRequestObjectSigningAlgorithm())) + } + + if t.Method == jwt.SigningMethodNone { + return jwt.UnsafeAllowNoneSignatureType, nil + } + + switch t.Method.(type) { + case *jwt.SigningMethodRSA: + key, err := f.findClientPublicJWK(oidcClient, t, true) + if err != nil { + return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve RSA signing key from OAuth 2.0 Client because %s.", err)) + } + return key, nil + case *jwt.SigningMethodECDSA: + key, err := f.findClientPublicJWK(oidcClient, t, false) + if err != nil { + return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve ECDSA signing key from OAuth 2.0 Client because %s.", err)) + } + return key, nil + case *jwt.SigningMethodRSAPSS: + key, err := f.findClientPublicJWK(oidcClient, t, true) + if err != nil { + return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve RSA signing key from OAuth 2.0 Client because %s.", err)) + } + return key, nil + default: + return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf(`This request object uses unsupported signing algorithm "%s"."`, t.Header["alg"])) + } + }) + if err != nil { + // Do not re-process already enhanced errors + if e, ok := errors.Cause(err).(*jwt.ValidationError); ok { + if e.Inner != nil { + return e.Inner + } + return errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to verify the request object's signature.").WithDebug(err.Error())) + } + return err + } else if err := token.Claims.Valid(); err != nil { + return errors.WithStack(ErrInvalidRequestObject.WithHint("Unable to verify the request object because its claims could not be validated, check if the expiry time is set correctly.").WithDebug(err.Error())) + } + + claims, ok := token.Claims.(*jwt.MapClaims) + if !ok { + return errors.WithStack(ErrInvalidRequestObject.WithHint("Unable to type assert claims from request object.").WithDebugf(`Got claims of type %T but expected type "*jwt.MapClaims".`, token.Claims)) + } + + for k, v := range *claims { + request.Form.Set(k, fmt.Sprintf("%s", v)) + } + + claimScope := stringsx.Splitx(request.Form.Get("scope"), " ") + for _, s := range scope { + if !stringslice.Has(claimScope, s) { + claimScope = append(claimScope, s) + } + } + + request.Form.Set("scope", strings.Join(claimScope, " ")) + return nil +} + +func (f *Fosite) validateAuthorizeRedirectURI(r *http.Request, request *AuthorizeRequest) error { + // Fetch redirect URI from request + rawRedirURI, err := GetRedirectURIFromRequestValues(request.Form) + if err != nil { + return err + } + + // Validate redirect uri + redirectURI, err := MatchRedirectURIWithClientRedirectURIs(rawRedirURI, request.Client) + if err != nil { + return err + } else if !IsValidRedirectURI(redirectURI) { + return errors.WithStack(ErrInvalidRequest.WithHintf(`The redirect URI "%s" contains an illegal character (for example #) or is otherwise invalid.`, redirectURI)) + } + request.RedirectURI = redirectURI + return nil +} + +func (f *Fosite) validateAuthorizeScope(r *http.Request, request *AuthorizeRequest) error { + scope := stringsx.Splitx(request.Form.Get("scope"), " ") + for _, permission := range scope { + if !f.ScopeStrategy(request.Client.GetScopes(), permission) { + return errors.WithStack(ErrInvalidScope.WithHintf(`The OAuth 2.0 Client is not allowed to request scope "%s".`, permission)) + } + } + request.SetRequestedScopes(scope) + + return nil +} + +func (f *Fosite) validateResponseTypes(r *http.Request, request *AuthorizeRequest) error { + // https://tools.ietf.org/html/rfc6749#section-3.1.1 + // Extension response types MAY contain a space-delimited (%x20) list of + // values, where the order of values does not matter (e.g., response + // type "a b" is the same as "b a"). The meaning of such composite + // response types is defined by their respective specifications. + responseTypes := RemoveEmpty(stringsx.Splitx(r.Form.Get("response_type"), " ")) + if len(responseTypes) == 0 { + return errors.WithStack(ErrUnsupportedResponseType.WithHint(`The request is missing the "response_type"" parameter.`)) + } + + var found bool + for _, t := range request.GetClient().GetResponseTypes() { + if Arguments(responseTypes).Matches(RemoveEmpty(stringsx.Splitx(t, " "))...) { + found = true + break + } + } + + if !found { + return errors.WithStack(ErrUnsupportedResponseType.WithHintf("The client is not allowed to request response_type \"%s\".", r.Form.Get("response_type"))) + } + + request.ResponseTypes = responseTypes + return nil +} + +func (f *Fosite) NewAuthorizeRequest(ctx context.Context, r *http.Request) (AuthorizeRequester, error) { + request := &AuthorizeRequest{ + ResponseTypes: Arguments{}, + HandledResponseTypes: Arguments{}, + Request: *NewRequest(), + } + + if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart { + return request, errors.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithDebug(err.Error())) + } + + request.Form = r.Form + + // Save state to the request to be returned in error conditions (https://github.com/ory/hydra/issues/1642) + state := request.Form.Get("state") + request.State = state + + client, err := f.Store.GetClient(ctx, request.GetRequestForm().Get("client_id")) + if err != nil { + return request, errors.WithStack(ErrInvalidClient.WithHint("The requested OAuth 2.0 Client does not exist.").WithDebug(err.Error())) + } + request.Client = client + + if err := f.authorizeRequestParametersFromOpenIDConnectRequest(request); err != nil { + return request, err + } + + if err := f.validateAuthorizeRedirectURI(r, request); err != nil { + return request, err + } + + if err := f.validateAuthorizeScope(r, request); err != nil { + return request, err + } + + if err := f.validateAuthorizeAudience(r, request); err != nil { + return request, err + } + + if len(request.Form.Get("registration")) > 0 { + return request, errors.WithStack(ErrRegistrationNotSupported) + } + + if err := f.validateResponseTypes(r, request); err != nil { + return request, err + } + + // rfc6819 4.4.1.8. Threat: CSRF Attack against redirect-uri + // The "state" parameter should be used to link the authorization + // request with the redirect URI used to deliver the access token (Section 5.3.5). + // + // https://tools.ietf.org/html/rfc6819#section-4.4.1.8 + // The "state" parameter should not be guessable + if len(state) < MinParameterEntropy { + // We're assuming that using less then 8 characters for the state can not be considered "unguessable" + return request, errors.WithStack(ErrInvalidState.WithHintf(`Request parameter "state" must be at least be %d characters long to ensure sufficient entropy.`, MinParameterEntropy)) + } + + return request, nil +} diff --git a/vendor/github.com/ory/fosite/authorize_response.go b/vendor/github.com/ory/fosite/authorize_response.go new file mode 100644 index 0000000000..c7feac3f56 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_response.go @@ -0,0 +1,77 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "net/http" + "net/url" +) + +// AuthorizeResponse is an implementation of AuthorizeResponder +type AuthorizeResponse struct { + Header http.Header + Query url.Values + Fragment url.Values + code string +} + +func NewAuthorizeResponse() *AuthorizeResponse { + return &AuthorizeResponse{ + Header: http.Header{}, + Query: url.Values{}, + Fragment: url.Values{}, + } +} + +func (a *AuthorizeResponse) GetCode() string { + return a.code +} + +func (a *AuthorizeResponse) GetHeader() http.Header { + return a.Header +} + +func (a *AuthorizeResponse) AddHeader(key, value string) { + a.Header.Add(key, value) +} + +func (a *AuthorizeResponse) GetQuery() url.Values { + return a.Query +} + +func (a *AuthorizeResponse) GetFragment() url.Values { + return a.Fragment +} + +func (a *AuthorizeResponse) AddQuery(key, value string) { + if key == "code" { + a.code = value + } + a.Query.Add(key, value) +} + +func (a *AuthorizeResponse) AddFragment(key, value string) { + if key == "code" { + a.code = value + } + a.Fragment.Add(key, value) +} diff --git a/vendor/github.com/ory/fosite/authorize_response_writer.go b/vendor/github.com/ory/fosite/authorize_response_writer.go new file mode 100644 index 0000000000..208b104c25 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_response_writer.go @@ -0,0 +1,51 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "net/http" + "net/url" + + "github.com/pkg/errors" +) + +func (f *Fosite) NewAuthorizeResponse(ctx context.Context, ar AuthorizeRequester, session Session) (AuthorizeResponder, error) { + var resp = &AuthorizeResponse{ + Header: http.Header{}, + Query: url.Values{}, + Fragment: url.Values{}, + } + + ar.SetSession(session) + for _, h := range f.AuthorizeEndpointHandlers { + if err := h.HandleAuthorizeEndpointRequest(ctx, ar, resp); err != nil { + return nil, err + } + } + + if !ar.DidHandleAllResponseTypes() { + return nil, errors.WithStack(ErrUnsupportedResponseType) + } + + return resp, nil +} diff --git a/vendor/github.com/ory/fosite/authorize_write.go b/vendor/github.com/ory/fosite/authorize_write.go new file mode 100644 index 0000000000..d2873d89a2 --- /dev/null +++ b/vendor/github.com/ory/fosite/authorize_write.go @@ -0,0 +1,72 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "net/http" + "regexp" +) + +var ( + // scopeMatch = regexp.MustCompile("scope=[^\\&]+.*$") + plusMatch = regexp.MustCompile("\\+") +) + +func (f *Fosite) WriteAuthorizeResponse(rw http.ResponseWriter, ar AuthorizeRequester, resp AuthorizeResponder) { + redir := ar.GetRedirectURI() + + // Explicit grants + q := redir.Query() + rq := resp.GetQuery() + for k := range rq { + q.Set(k, rq.Get(k)) + } + redir.RawQuery = q.Encode() + + // Set custom headers, e.g. "X-MySuperCoolCustomHeader" or "X-DONT-CACHE-ME"... + wh := rw.Header() + rh := resp.GetHeader() + for k := range rh { + wh.Set(k, rh.Get(k)) + } + + // Implicit grants + // The endpoint URI MUST NOT include a fragment component. + redir.Fragment = "" + + u := redir.String() + + fr := resp.GetFragment() + if len(fr) > 0 { + u = u + "#" + fr.Encode() + } + + u = plusMatch.ReplaceAllString(u, "%20") + + // https://tools.ietf.org/html/rfc6749#section-4.1.1 + // When a decision is established, the authorization server directs the + // user-agent to the provided client redirection URI using an HTTP + // redirection response, or by other means available to it via the + // user-agent. + wh.Set("Location", u) + rw.WriteHeader(http.StatusFound) +} diff --git a/vendor/github.com/ory/fosite/client.go b/vendor/github.com/ory/fosite/client.go new file mode 100644 index 0000000000..9a4ee32e1d --- /dev/null +++ b/vendor/github.com/ory/fosite/client.go @@ -0,0 +1,179 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import jose "gopkg.in/square/go-jose.v2" + +// Client represents a client or an app. +type Client interface { + // GetID returns the client ID. + GetID() string + + // GetHashedSecret returns the hashed secret as it is stored in the store. + GetHashedSecret() []byte + + // GetRedirectURIs returns the client's allowed redirect URIs. + GetRedirectURIs() []string + + // GetGrantTypes returns the client's allowed grant types. + GetGrantTypes() Arguments + + // GetResponseTypes returns the client's allowed response types. + // All allowed combinations of response types have to be listed, each combination having + // response types of the combination separated by a space. + GetResponseTypes() Arguments + + // GetScopes returns the scopes this client is allowed to request. + GetScopes() Arguments + + // IsPublic returns true, if this client is marked as public. + IsPublic() bool + + // GetAudience returns the allowed audience(s) for this client. + GetAudience() Arguments +} + +// OpenIDConnectClient represents a client capable of performing OpenID Connect requests. +type OpenIDConnectClient interface { + // GetRequestURIs is an array of request_uri values that are pre-registered by the RP for use at the OP. Servers MAY + // cache the contents of the files referenced by these URIs and not retrieve them at the time they are used in a request. + // OPs can require that request_uri values used be pre-registered with the require_request_uri_registration + // discovery parameter. + GetRequestURIs() []string + + // GetJSONWebKeys returns the JSON Web Key Set containing the public keys used by the client to authenticate. + GetJSONWebKeys() *jose.JSONWebKeySet + + // GetJSONWebKeys returns the URL for lookup of JSON Web Key Set containing the + // public keys used by the client to authenticate. + GetJSONWebKeysURI() string + + // JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. + // All Request Objects from this Client MUST be rejected, if not signed with this algorithm. + GetRequestObjectSigningAlgorithm() string + + // Requested Client Authentication method for the Token Endpoint. The options are client_secret_post, + // client_secret_basic, client_secret_jwt, private_key_jwt, and none. + GetTokenEndpointAuthMethod() string + + // JWS [JWS] alg algorithm [JWA] that MUST be used for signing the JWT [JWT] used to authenticate the + // Client at the Token Endpoint for the private_key_jwt and client_secret_jwt authentication methods. + GetTokenEndpointAuthSigningAlgorithm() string +} + +// DefaultClient is a simple default implementation of the Client interface. +type DefaultClient struct { + ID string `json:"id"` + Secret []byte `json:"client_secret,omitempty"` + RedirectURIs []string `json:"redirect_uris"` + GrantTypes []string `json:"grant_types"` + ResponseTypes []string `json:"response_types"` + Scopes []string `json:"scopes"` + Audience []string `json:"audience"` + Public bool `json:"public"` +} + +type DefaultOpenIDConnectClient struct { + *DefaultClient + JSONWebKeysURI string `json:"jwks_uri"` + JSONWebKeys *jose.JSONWebKeySet `json:"jwks"` + TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"` + RequestURIs []string `json:"request_uris"` + RequestObjectSigningAlgorithm string `json:"request_object_signing_alg"` + TokenEndpointAuthSigningAlgorithm string `json:"token_endpoint_auth_signing_alg"` +} + +func (c *DefaultClient) GetID() string { + return c.ID +} + +func (c *DefaultClient) IsPublic() bool { + return c.Public +} + +func (c *DefaultClient) GetAudience() Arguments { + return c.Audience +} + +func (c *DefaultClient) GetRedirectURIs() []string { + return c.RedirectURIs +} + +func (c *DefaultClient) GetHashedSecret() []byte { + return c.Secret +} + +func (c *DefaultClient) GetScopes() Arguments { + return c.Scopes +} + +func (c *DefaultClient) GetGrantTypes() Arguments { + // https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata + // + // JSON array containing a list of the OAuth 2.0 Grant Types that the Client is declaring + // that it will restrict itself to using. + // If omitted, the default is that the Client will use only the authorization_code Grant Type. + if len(c.GrantTypes) == 0 { + return Arguments{"authorization_code"} + } + return Arguments(c.GrantTypes) +} + +func (c *DefaultClient) GetResponseTypes() Arguments { + // https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata + // + // JSON array containing a list of the OAuth 2.0 response_type values that the Client is declaring + // that it will restrict itself to using. If omitted, the default is that the Client will use + // only the code Response Type. + if len(c.ResponseTypes) == 0 { + return Arguments{"code"} + } + return Arguments(c.ResponseTypes) +} + +func (c *DefaultOpenIDConnectClient) GetJSONWebKeysURI() string { + return c.JSONWebKeysURI +} + +func (c *DefaultOpenIDConnectClient) GetJSONWebKeys() *jose.JSONWebKeySet { + return c.JSONWebKeys +} + +func (c *DefaultOpenIDConnectClient) GetTokenEndpointAuthSigningAlgorithm() string { + if c.TokenEndpointAuthSigningAlgorithm == "" { + return "RS256" + } else { + return c.TokenEndpointAuthSigningAlgorithm + } +} + +func (c *DefaultOpenIDConnectClient) GetRequestObjectSigningAlgorithm() string { + return c.RequestObjectSigningAlgorithm +} + +func (c *DefaultOpenIDConnectClient) GetTokenEndpointAuthMethod() string { + return c.TokenEndpointAuthMethod +} + +func (c *DefaultOpenIDConnectClient) GetRequestURIs() []string { + return c.RequestURIs +} diff --git a/vendor/github.com/ory/fosite/client_authentication.go b/vendor/github.com/ory/fosite/client_authentication.go new file mode 100644 index 0000000000..e2b1cbb42f --- /dev/null +++ b/vendor/github.com/ory/fosite/client_authentication.go @@ -0,0 +1,294 @@ +/* + * Copyright © 2017-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @Copyright 2017-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "crypto/ecdsa" + "crypto/rsa" + "encoding/json" + "fmt" + "net/http" + "net/url" + "time" + + jwt "github.com/dgrijalva/jwt-go" + "github.com/pkg/errors" + jose "gopkg.in/square/go-jose.v2" +) + +const clientAssertionJWTBearerType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" + +func (f *Fosite) findClientPublicJWK(oidcClient OpenIDConnectClient, t *jwt.Token, expectsRSAKey bool) (interface{}, error) { + if set := oidcClient.GetJSONWebKeys(); set != nil { + return findPublicKey(t, set, expectsRSAKey) + } + + if location := oidcClient.GetJSONWebKeysURI(); len(location) > 0 { + keys, err := f.JWKSFetcherStrategy.Resolve(location, false) + if err != nil { + return nil, err + } + + if key, err := findPublicKey(t, keys, expectsRSAKey); err == nil { + return key, nil + } + + keys, err = f.JWKSFetcherStrategy.Resolve(location, true) + if err != nil { + return nil, err + } + + return findPublicKey(t, keys, expectsRSAKey) + } + + return nil, errors.WithStack(ErrInvalidClient.WithHint("The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request.")) +} + +func (f *Fosite) AuthenticateClient(ctx context.Context, r *http.Request, form url.Values) (Client, error) { + if assertionType := form.Get("client_assertion_type"); assertionType == clientAssertionJWTBearerType { + assertion := form.Get("client_assertion") + if len(assertion) == 0 { + return nil, errors.WithStack(ErrInvalidRequest.WithHintf("The client_assertion request parameter must be set when using client_assertion_type of \"%s\".", clientAssertionJWTBearerType)) + } + + var clientID string + var client Client + + token, err := jwt.ParseWithClaims(assertion, new(jwt.MapClaims), func(t *jwt.Token) (interface{}, error) { + var err error + clientID, _, err = clientCredentialsFromRequestBody(form, false) + if err != nil { + return nil, err + } + + if clientID == "" { + if claims, ok := t.Claims.(*jwt.MapClaims); !ok { + return nil, errors.WithStack(ErrRequestUnauthorized.WithHint("Unable to type assert claims from client_assertion.").WithDebugf(`Expected claims to be of type "*jwt.MapClaims" but got "%T".`, t.Claims)) + } else if sub, ok := (*claims)["sub"].(string); !ok { + return nil, errors.WithStack(ErrInvalidClient.WithHint(`The claim "sub" from the client_assertion JSON Web Token is undefined.`)) + } else { + clientID = sub + } + } + + client, err = f.Store.GetClient(ctx, clientID) + if err != nil { + return nil, errors.WithStack(ErrInvalidClient.WithDebug(err.Error())) + } + + oidcClient, ok := client.(OpenIDConnectClient) + if !ok { + return nil, errors.WithStack(ErrInvalidRequest.WithHint("The server configuration does not support OpenID Connect specific authentication methods.")) + } + + switch oidcClient.GetTokenEndpointAuthMethod() { + case "private_key_jwt": + break + case "none": + return nil, errors.WithStack(ErrInvalidClient.WithHint("This requested OAuth 2.0 client does not support client authentication, however \"client_assertion\" was provided in the request.")) + case "client_secret_post": + fallthrough + case "client_secret_basic": + return nil, errors.WithStack(ErrInvalidClient.WithHintf("This requested OAuth 2.0 client only supports client authentication method \"%s\", however \"client_assertion\" was provided in the request.", oidcClient.GetTokenEndpointAuthMethod())) + case "client_secret_jwt": + fallthrough + default: + return nil, errors.WithStack(ErrInvalidClient.WithHintf("This requested OAuth 2.0 client only supports client authentication method \"%s\", however that method is not supported by this server.", oidcClient.GetTokenEndpointAuthMethod())) + } + + if oidcClient.GetTokenEndpointAuthSigningAlgorithm() != fmt.Sprintf("%s", t.Header["alg"]) { + return nil, errors.WithStack(ErrInvalidClient.WithHintf(`The "client_assertion" uses signing algorithm "%s", but the requested OAuth 2.0 Client enforces signing algorithm "%s".`, t.Header["alg"], oidcClient.GetTokenEndpointAuthSigningAlgorithm())) + } + + if _, ok := t.Method.(*jwt.SigningMethodRSA); ok { + return f.findClientPublicJWK(oidcClient, t, true) + } else if _, ok := t.Method.(*jwt.SigningMethodECDSA); ok { + return f.findClientPublicJWK(oidcClient, t, false) + } else if _, ok := t.Method.(*jwt.SigningMethodRSAPSS); ok { + return f.findClientPublicJWK(oidcClient, t, true) + } else if _, ok := t.Method.(*jwt.SigningMethodHMAC); ok { + return nil, errors.WithStack(ErrInvalidClient.WithHint("This authorization server does not support client authentication method \"client_secret_jwt\".")) + } + + return nil, errors.WithStack(ErrInvalidClient.WithHintf(`The "client_assertion" request parameter uses unsupported signing algorithm "%s".`, t.Header["alg"])) + }) + if err != nil { + // Do not re-process already enhanced errors + if e, ok := errors.Cause(err).(*jwt.ValidationError); ok { + if e.Inner != nil { + return nil, e.Inner + } + return nil, errors.WithStack(ErrInvalidClient.WithHint("Unable to verify the integrity of the \"client_assertion\" value.").WithDebug(err.Error())) + } + return nil, err + } else if err := token.Claims.Valid(); err != nil { + return nil, errors.WithStack(ErrInvalidClient.WithHint("Unable to verify the request object because its claims could not be validated, check if the expiry time is set correctly.").WithDebug(err.Error())) + } + + claims, ok := token.Claims.(*jwt.MapClaims) + if !ok { + return nil, errors.WithStack(ErrInvalidClient.WithHint("Unable to type assert claims from request parameter \"client_assertion\".").WithDebugf(`Got claims of type %T but expected type "*jwt.MapClaims".`, token.Claims)) + } + + var jti string + if !claims.VerifyIssuer(clientID, true) { + return nil, errors.WithStack(ErrInvalidClient.WithHint("Claim \"iss\" from \"client_assertion\" must match the \"client_id\" of the OAuth 2.0 Client.")) + } else if f.TokenURL == "" { + return nil, errors.WithStack(ErrMisconfiguration.WithHint("The authorization server's token endpoint URL has not been set.")) + } else if sub, ok := (*claims)["sub"].(string); !ok || sub != clientID { + return nil, errors.WithStack(ErrInvalidClient.WithHint("Claim \"sub\" from \"client_assertion\" must match the \"client_id\" of the OAuth 2.0 Client.")) + } else if jti, ok = (*claims)["jti"].(string); !ok || len(jti) == 0 { + return nil, errors.WithStack(ErrInvalidClient.WithHint("Claim \"jti\" from \"client_assertion\" must be set but is not.")) + } else if f.Store.ClientAssertionJWTValid(context.Background(), jti) != nil { + return nil, errors.WithStack(ErrJTIKnown.WithHint("Claim \"jti\" from \"client_assertion\" MUST only be used once.")) + } + + // type conversion according to jwt.MapClaims.VerifyExpiresAt + var expiry int64 + err = nil + switch exp := (*claims)["exp"].(type) { + case float64: + expiry = int64(exp) + case json.Number: + expiry, err = exp.Int64() + default: + err = ErrInvalidClient.WithHint("Unable to type assert the expiry time from claims. This should not happen as we validate the expiry time already earlier with token.Claims.Valid()") + } + + if err != nil { + return nil, errors.WithStack(err) + } + if err := f.Store.SetClientAssertionJWT(context.Background(), jti, time.Unix(expiry, 0)); err != nil { + return nil, err + } + + if auds, ok := (*claims)["aud"].([]interface{}); !ok { + if !claims.VerifyAudience(f.TokenURL, true) { + return nil, errors.WithStack(ErrInvalidClient.WithHintf("Claim \"audience\" from \"client_assertion\" must match the authorization server's token endpoint \"%s\".", f.TokenURL)) + } + } else { + var found bool + for _, aud := range auds { + if a, ok := aud.(string); ok && a == f.TokenURL { + found = true + break + } + } + + if !found { + return nil, errors.WithStack(ErrInvalidClient.WithHintf("Claim \"audience\" from \"client_assertion\" must match the authorization server's token endpoint \"%s\".", f.TokenURL)) + } + } + + return client, nil + } else if len(assertionType) > 0 { + return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unknown client_assertion_type \"%s\".", assertionType)) + } + + clientID, clientSecret, err := clientCredentialsFromRequest(r, form) + if err != nil { + return nil, err + } + + client, err := f.Store.GetClient(ctx, clientID) + if err != nil { + return nil, errors.WithStack(ErrInvalidClient.WithDebug(err.Error())) + } + + if oidcClient, ok := client.(OpenIDConnectClient); !ok { + // If this isn't an OpenID Connect client then we actually don't care about any of this, just continue! + } else if ok && form.Get("client_id") != "" && form.Get("client_secret") != "" && oidcClient.GetTokenEndpointAuthMethod() != "client_secret_post" { + return nil, errors.WithStack(ErrInvalidClient.WithHintf("The OAuth 2.0 Client supports client authentication method \"%s\", but method \"client_secret_post\" was requested. You must configure the OAuth 2.0 client's \"token_endpoint_auth_method\" value to accept \"client_secret_post\".", oidcClient.GetTokenEndpointAuthMethod())) + } else if _, _, basicOk := r.BasicAuth(); basicOk && ok && oidcClient.GetTokenEndpointAuthMethod() != "client_secret_basic" { + return nil, errors.WithStack(ErrInvalidClient.WithHintf("The OAuth 2.0 Client supports client authentication method \"%s\", but method \"client_secret_basic\" was requested. You must configure the OAuth 2.0 client's \"token_endpoint_auth_method\" value to accept \"client_secret_basic\".", oidcClient.GetTokenEndpointAuthMethod())) + } else if ok && oidcClient.GetTokenEndpointAuthMethod() != "none" && client.IsPublic() { + return nil, errors.WithStack(ErrInvalidClient.WithHintf("The OAuth 2.0 Client supports client authentication method \"%s\", but method \"none\" was requested. You must configure the OAuth 2.0 client's \"token_endpoint_auth_method\" value to accept \"none\".", oidcClient.GetTokenEndpointAuthMethod())) + } + + if client.IsPublic() { + return client, nil + } + + // Enforce client authentication + if err := f.Hasher.Compare(ctx, client.GetHashedSecret(), []byte(clientSecret)); err != nil { + return nil, errors.WithStack(ErrInvalidClient.WithDebug(err.Error())) + } + + return client, nil +} + +func findPublicKey(t *jwt.Token, set *jose.JSONWebKeySet, expectsRSAKey bool) (interface{}, error) { + kid, ok := t.Header["kid"].(string) + if !ok { + return nil, errors.WithStack(ErrInvalidRequest.WithHint("The JSON Web Token must contain a kid header value but did not.")) + } + + keys := set.Key(kid) + if len(keys) == 0 { + return nil, errors.WithStack(ErrInvalidRequest.WithHintf("The JSON Web Token uses signing key with kid \"%s\", which could not be found.", kid)) + } + + for _, key := range keys { + if key.Use != "sig" { + continue + } + if expectsRSAKey { + if k, ok := key.Key.(*rsa.PublicKey); ok { + return k, nil + } + } else { + if k, ok := key.Key.(*ecdsa.PublicKey); ok { + return k, nil + } + } + } + + if expectsRSAKey { + return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find RSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid)) + } else { + return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find ECDSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid)) + } +} + +func clientCredentialsFromRequest(r *http.Request, form url.Values) (clientID, clientSecret string, err error) { + if id, secret, ok := r.BasicAuth(); !ok { + return clientCredentialsFromRequestBody(form, true) + } else if clientID, err = url.QueryUnescape(id); err != nil { + return "", "", errors.WithStack(ErrInvalidRequest.WithHint(`The client id in the HTTP authorization header could not be decoded from "application/x-www-form-urlencoded".`).WithDebug(err.Error())) + } else if clientSecret, err = url.QueryUnescape(secret); err != nil { + return "", "", errors.WithStack(ErrInvalidRequest.WithHint(`The client secret in the HTTP authorization header could not be decoded from "application/x-www-form-urlencoded".`).WithDebug(err.Error())) + } + + return clientID, clientSecret, nil +} + +func clientCredentialsFromRequestBody(form url.Values, forceID bool) (clientID, clientSecret string, err error) { + clientID = form.Get("client_id") + clientSecret = form.Get("client_secret") + + if clientID == "" && forceID { + return "", "", errors.WithStack(ErrInvalidRequest.WithHint("Client credentials missing or malformed in both HTTP Authorization header and HTTP POST body.")) + } + + return clientID, clientSecret, nil +} diff --git a/vendor/github.com/ory/fosite/client_authentication_jwks_strategy.go b/vendor/github.com/ory/fosite/client_authentication_jwks_strategy.go new file mode 100644 index 0000000000..3423451b60 --- /dev/null +++ b/vendor/github.com/ory/fosite/client_authentication_jwks_strategy.go @@ -0,0 +1,81 @@ +/* + * Copyright © 2017-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @Copyright 2017-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "encoding/json" + "net/http" + "sync" + + "github.com/pkg/errors" + jose "gopkg.in/square/go-jose.v2" +) + +// JWKSFetcherStrategy is a strategy which pulls (optionally caches) JSON Web Key Sets from a location, +// typically a client's jwks_uri. +type JWKSFetcherStrategy interface { + // Resolve returns the JSON Web Key Set, or an error if something went wrong. The forceRefresh, if true, forces + // the strategy to fetch the keys from the remote. If forceRefresh is false, the strategy may use a caching strategy + // to fetch the key. + Resolve(location string, forceRefresh bool) (*jose.JSONWebKeySet, error) +} + +type DefaultJWKSFetcherStrategy struct { + client *http.Client + keys map[string]jose.JSONWebKeySet + sync.Mutex +} + +func NewDefaultJWKSFetcherStrategy() JWKSFetcherStrategy { + return &DefaultJWKSFetcherStrategy{ + keys: make(map[string]jose.JSONWebKeySet), + client: http.DefaultClient, + } +} + +func (s *DefaultJWKSFetcherStrategy) Resolve(location string, forceRefresh bool) (*jose.JSONWebKeySet, error) { + s.Lock() + defer s.Unlock() + + keys, ok := s.keys[location] + if !ok || forceRefresh { + response, err := s.client.Get(location) + if err != nil { + return nil, errors.WithStack(ErrServerError.WithHintf(`Unable to fetch JSON Web Keys from location "%s" because %s"`, location, err)) + } + defer response.Body.Close() + + if response.StatusCode < 200 || response.StatusCode >= 400 { + return nil, errors.WithStack(ErrServerError.WithHintf(`Expected successful status code from location "%s", but received code "%d".`, location, response.StatusCode)) + } + + var set jose.JSONWebKeySet + if err := json.NewDecoder(response.Body).Decode(&set); err != nil { + return nil, errors.WithStack(ErrServerError.WithHintf("Unable to decode JSON Web Keys from location \"%s\" because \"%s\".", location, err)) + } + + s.keys[location] = set + return &set, nil + } + + return &keys, nil +} diff --git a/vendor/github.com/ory/fosite/client_manager.go b/vendor/github.com/ory/fosite/client_manager.go new file mode 100644 index 0000000000..d5f481709f --- /dev/null +++ b/vendor/github.com/ory/fosite/client_manager.go @@ -0,0 +1,42 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "time" +) + +// ClientManager defines the (persistent) manager interface for clients. +type ClientManager interface { + // GetClient loads the client by its ID or returns an error + // if the client does not exist or another error occurred. + GetClient(ctx context.Context, id string) (Client, error) + // ClientAssertionJWTValid returns an error if the JTI is + // known or the DB check failed and nil if the JTI is not known. + ClientAssertionJWTValid(ctx context.Context, jti string) error + // SetClientAssertionJWT marks a JTI as known for the given + // expiry time. Before inserting the new JTI, it will clean + // up any existing JTIs that have expired as those tokens can + // not be replayed due to the expiry. + SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) error +} diff --git a/vendor/github.com/ory/fosite/compose/compose.go b/vendor/github.com/ory/fosite/compose/compose.go new file mode 100644 index 0000000000..ff50f5f3c3 --- /dev/null +++ b/vendor/github.com/ory/fosite/compose/compose.go @@ -0,0 +1,122 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package compose + +import ( + "crypto/rsa" + + "github.com/ory/fosite" + "github.com/ory/fosite/token/jwt" +) + +type Factory func(config *Config, storage interface{}, strategy interface{}) interface{} + +// Compose takes a config, a storage, a strategy and handlers to instantiate an OAuth2Provider: +// +// import "github.com/ory/fosite/compose" +// +// // var storage = new(MyFositeStorage) +// var config = Config { +// AccessTokenLifespan: time.Minute * 30, +// // check Config for further configuration options +// } +// +// var strategy = NewOAuth2HMACStrategy(config) +// +// var oauth2Provider = Compose( +// config, +// storage, +// strategy, +// NewOAuth2AuthorizeExplicitHandler, +// OAuth2ClientCredentialsGrantFactory, +// // for a complete list refer to the docs of this package +// ) +// +// Compose makes use of interface{} types in order to be able to handle a all types of stores, strategies and handlers. +func Compose(config *Config, storage interface{}, strategy interface{}, hasher fosite.Hasher, factories ...Factory) fosite.OAuth2Provider { + if hasher == nil { + hasher = &fosite.BCrypt{WorkFactor: config.GetHashCost()} + } + + f := &fosite.Fosite{ + Store: storage.(fosite.Storage), + AuthorizeEndpointHandlers: fosite.AuthorizeEndpointHandlers{}, + TokenEndpointHandlers: fosite.TokenEndpointHandlers{}, + TokenIntrospectionHandlers: fosite.TokenIntrospectionHandlers{}, + RevocationHandlers: fosite.RevocationHandlers{}, + Hasher: hasher, + ScopeStrategy: config.GetScopeStrategy(), + AudienceMatchingStrategy: config.GetAudienceStrategy(), + SendDebugMessagesToClients: config.SendDebugMessagesToClients, + TokenURL: config.TokenURL, + JWKSFetcherStrategy: config.GetJWKSFetcherStrategy(), + } + + for _, factory := range factories { + res := factory(config, storage, strategy) + if ah, ok := res.(fosite.AuthorizeEndpointHandler); ok { + f.AuthorizeEndpointHandlers.Append(ah) + } + if th, ok := res.(fosite.TokenEndpointHandler); ok { + f.TokenEndpointHandlers.Append(th) + } + if tv, ok := res.(fosite.TokenIntrospector); ok { + f.TokenIntrospectionHandlers.Append(tv) + } + if rh, ok := res.(fosite.RevocationHandler); ok { + f.RevocationHandlers.Append(rh) + } + } + + return f +} + +// ComposeAllEnabled returns a fosite instance with all OAuth2 and OpenID Connect handlers enabled. +func ComposeAllEnabled(config *Config, storage interface{}, secret []byte, key *rsa.PrivateKey) fosite.OAuth2Provider { + return Compose( + config, + storage, + &CommonStrategy{ + CoreStrategy: NewOAuth2HMACStrategy(config, secret, nil), + OpenIDConnectTokenStrategy: NewOpenIDConnectStrategy(config, key), + JWTStrategy: &jwt.RS256JWTStrategy{ + PrivateKey: key, + }, + }, + nil, + + OAuth2AuthorizeExplicitFactory, + OAuth2AuthorizeImplicitFactory, + OAuth2ClientCredentialsGrantFactory, + OAuth2RefreshTokenGrantFactory, + OAuth2ResourceOwnerPasswordCredentialsFactory, + + OpenIDConnectExplicitFactory, + OpenIDConnectImplicitFactory, + OpenIDConnectHybridFactory, + OpenIDConnectRefreshFactory, + + OAuth2TokenIntrospectionFactory, + + OAuth2PKCEFactory, + ) +} diff --git a/vendor/github.com/ory/fosite/compose/compose_oauth2.go b/vendor/github.com/ory/fosite/compose/compose_oauth2.go new file mode 100644 index 0000000000..5cb4aae14c --- /dev/null +++ b/vendor/github.com/ory/fosite/compose/compose_oauth2.go @@ -0,0 +1,138 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package compose + +import ( + "github.com/ory/fosite/handler/oauth2" +) + +// OAuth2AuthorizeExplicitFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers +// an access token, refresh token and authorize code validator. +func OAuth2AuthorizeExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.AuthorizeExplicitGrantHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), + CoreStorage: storage.(oauth2.CoreStorage), + AuthCodeLifespan: config.GetAuthorizeCodeLifespan(), + RefreshTokenLifespan: config.GetRefreshTokenLifespan(), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + ScopeStrategy: config.GetScopeStrategy(), + AudienceMatchingStrategy: config.GetAudienceStrategy(), + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + IsRedirectURISecure: config.GetRedirectSecureChecker(), + RefreshTokenScopes: config.GetRefreshTokenScopes(), + } +} + +// OAuth2ClientCredentialsGrantFactory creates an OAuth2 client credentials grant handler and registers +// an access token, refresh token and authorize code validator. +func OAuth2ClientCredentialsGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.ClientCredentialsGrantHandler{ + HandleHelper: &oauth2.HandleHelper{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + AccessTokenStorage: storage.(oauth2.AccessTokenStorage), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + }, + ScopeStrategy: config.GetScopeStrategy(), + AudienceMatchingStrategy: config.GetAudienceStrategy(), + } +} + +// OAuth2RefreshTokenGrantFactory creates an OAuth2 refresh grant handler and registers +// an access token, refresh token and authorize code validator. +func OAuth2RefreshTokenGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.RefreshTokenGrantHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + RefreshTokenLifespan: config.GetRefreshTokenLifespan(), + ScopeStrategy: config.GetScopeStrategy(), + AudienceMatchingStrategy: config.GetAudienceStrategy(), + RefreshTokenScopes: config.GetRefreshTokenScopes(), + } +} + +// OAuth2AuthorizeImplicitFactory creates an OAuth2 implicit grant ("authorize implicit flow") handler and registers +// an access token, refresh token and authorize code validator. +func OAuth2AuthorizeImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.AuthorizeImplicitGrantTypeHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + AccessTokenStorage: storage.(oauth2.AccessTokenStorage), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + ScopeStrategy: config.GetScopeStrategy(), + AudienceMatchingStrategy: config.GetAudienceStrategy(), + } +} + +// OAuth2ResourceOwnerPasswordCredentialsFactory creates an OAuth2 resource owner password credentials grant handler and registers +// an access token, refresh token and authorize code validator. +func OAuth2ResourceOwnerPasswordCredentialsFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.ResourceOwnerPasswordCredentialsGrantHandler{ + ResourceOwnerPasswordCredentialsGrantStorage: storage.(oauth2.ResourceOwnerPasswordCredentialsGrantStorage), + HandleHelper: &oauth2.HandleHelper{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + AccessTokenStorage: storage.(oauth2.AccessTokenStorage), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + RefreshTokenLifespan: config.GetRefreshTokenLifespan(), + }, + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + ScopeStrategy: config.GetScopeStrategy(), + AudienceMatchingStrategy: config.GetAudienceStrategy(), + RefreshTokenScopes: config.GetRefreshTokenScopes(), + } +} + +// OAuth2TokenRevocationFactory creates an OAuth2 token revocation handler. +func OAuth2TokenRevocationFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.TokenRevocationHandler{ + TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage), + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + } +} + +// OAuth2TokenIntrospectionFactory creates an OAuth2 token introspection handler and registers +// an access token and refresh token validator. +func OAuth2TokenIntrospectionFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.CoreValidator{ + CoreStrategy: strategy.(oauth2.CoreStrategy), + CoreStorage: storage.(oauth2.CoreStorage), + ScopeStrategy: config.GetScopeStrategy(), + DisableRefreshTokenValidation: config.DisableRefreshTokenValidation, + } +} + +// OAuth2StatelessJWTIntrospectionFactory creates an OAuth2 token introspection handler and +// registers an access token validator. This can only be used to validate JWTs and does so +// statelessly, meaning it uses only the data available in the JWT itself, and does not access the +// storage implementation at all. +// +// Due to the stateless nature of this factory, THE BUILT-IN REVOCATION MECHANISMS WILL NOT WORK. +// If you need revocation, you can validate JWTs statefully, using the other factories. +func OAuth2StatelessJWTIntrospectionFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &oauth2.StatelessJWTValidator{ + JWTAccessTokenStrategy: strategy.(oauth2.JWTAccessTokenStrategy), + ScopeStrategy: config.GetScopeStrategy(), + } +} diff --git a/vendor/github.com/ory/fosite/compose/compose_openid.go b/vendor/github.com/ory/fosite/compose/compose_openid.go new file mode 100644 index 0000000000..e306f46e9c --- /dev/null +++ b/vendor/github.com/ory/fosite/compose/compose_openid.go @@ -0,0 +1,99 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package compose + +import ( + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/handler/openid" + "github.com/ory/fosite/token/jwt" +) + +// OpenIDConnectExplicitFactory creates an OpenID Connect explicit ("authorize code flow") grant handler. +// +// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler! +func OpenIDConnectExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &openid.OpenIDConnectExplicitHandler{ + OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage), + IDTokenHandleHelper: &openid.IDTokenHandleHelper{ + IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy), + }, + OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(config.AllowedPromptValues, strategy.(jwt.JWTStrategy)), + } +} + +// OpenIDConnectRefreshFactory creates a handler for refreshing openid connect tokens. +// +// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler! +func OpenIDConnectRefreshFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &openid.OpenIDConnectRefreshHandler{ + IDTokenHandleHelper: &openid.IDTokenHandleHelper{ + IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy), + }, + } +} + +// OpenIDConnectImplicitFactory creates an OpenID Connect implicit ("implicit flow") grant handler. +// +// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler! +func OpenIDConnectImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &openid.OpenIDConnectImplicitHandler{ + AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + AccessTokenStorage: storage.(oauth2.AccessTokenStorage), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + }, + ScopeStrategy: config.GetScopeStrategy(), + IDTokenHandleHelper: &openid.IDTokenHandleHelper{ + IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy), + }, + OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(config.AllowedPromptValues, strategy.(jwt.JWTStrategy)), + } +} + +// OpenIDConnectHybridFactory creates an OpenID Connect hybrid grant handler. +// +// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler! +func OpenIDConnectHybridFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &openid.OpenIDConnectHybridHandler{ + AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy), + AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), + CoreStorage: storage.(oauth2.CoreStorage), + AuthCodeLifespan: config.GetAuthorizeCodeLifespan(), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + RefreshTokenLifespan: config.GetRefreshTokenLifespan(), + IsRedirectURISecure: config.GetRedirectSecureChecker(), + }, + ScopeStrategy: config.GetScopeStrategy(), + AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{ + AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy), + AccessTokenStorage: storage.(oauth2.AccessTokenStorage), + AccessTokenLifespan: config.GetAccessTokenLifespan(), + }, + IDTokenHandleHelper: &openid.IDTokenHandleHelper{ + IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy), + }, + OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage), + OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(config.AllowedPromptValues, strategy.(jwt.JWTStrategy)), + } +} diff --git a/vendor/github.com/ory/fosite/compose/compose_pkce.go b/vendor/github.com/ory/fosite/compose/compose_pkce.go new file mode 100644 index 0000000000..6462bf214e --- /dev/null +++ b/vendor/github.com/ory/fosite/compose/compose_pkce.go @@ -0,0 +1,38 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package compose + +import ( + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/handler/pkce" +) + +// OAuth2PKCEFactory creates a PKCE handler. +func OAuth2PKCEFactory(config *Config, storage interface{}, strategy interface{}) interface{} { + return &pkce.Handler{ + AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy), + Storage: storage.(pkce.PKCERequestStorage), + Force: config.EnforcePKCE, + ForceForPublicClients: config.EnforcePKCEForPublicClients, + EnablePlainChallengeMethod: config.EnablePKCEPlainChallengeMethod, + } +} diff --git a/vendor/github.com/ory/fosite/compose/compose_strategy.go b/vendor/github.com/ory/fosite/compose/compose_strategy.go new file mode 100644 index 0000000000..327b96d3c0 --- /dev/null +++ b/vendor/github.com/ory/fosite/compose/compose_strategy.go @@ -0,0 +1,79 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package compose + +import ( + "crypto/rsa" + + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/handler/openid" + "github.com/ory/fosite/token/hmac" + "github.com/ory/fosite/token/jwt" +) + +type CommonStrategy struct { + oauth2.CoreStrategy + openid.OpenIDConnectTokenStrategy + jwt.JWTStrategy +} + +func NewOAuth2HMACStrategy(config *Config, secret []byte, rotatedSecrets [][]byte) *oauth2.HMACSHAStrategy { + return &oauth2.HMACSHAStrategy{ + Enigma: &hmac.HMACStrategy{ + GlobalSecret: secret, + RotatedGlobalSecrets: rotatedSecrets, + TokenEntropy: config.GetTokenEntropy(), + }, + AccessTokenLifespan: config.GetAccessTokenLifespan(), + AuthorizeCodeLifespan: config.GetAuthorizeCodeLifespan(), + RefreshTokenLifespan: config.GetRefreshTokenLifespan(), + } +} + +func NewOAuth2JWTStrategy(key *rsa.PrivateKey, strategy *oauth2.HMACSHAStrategy) *oauth2.DefaultJWTStrategy { + return &oauth2.DefaultJWTStrategy{ + JWTStrategy: &jwt.RS256JWTStrategy{ + PrivateKey: key, + }, + HMACSHAStrategy: strategy, + } +} + +func NewOAuth2JWTStrategyWithIssuer(key *rsa.PrivateKey, strategy *oauth2.HMACSHAStrategy, issuer string) *oauth2.DefaultJWTStrategy { + return &oauth2.DefaultJWTStrategy{ + JWTStrategy: &jwt.RS256JWTStrategy{ + PrivateKey: key, + }, + HMACSHAStrategy: strategy, + Issuer: issuer, + } +} + +func NewOpenIDConnectStrategy(config *Config, key *rsa.PrivateKey) *openid.DefaultStrategy { + return &openid.DefaultStrategy{ + JWTStrategy: &jwt.RS256JWTStrategy{ + PrivateKey: key, + }, + Expiry: config.GetIDTokenLifespan(), + Issuer: config.IDTokenIssuer, + } +} diff --git a/vendor/github.com/ory/fosite/compose/config.go b/vendor/github.com/ory/fosite/compose/config.go new file mode 100644 index 0000000000..f972283db1 --- /dev/null +++ b/vendor/github.com/ory/fosite/compose/config.go @@ -0,0 +1,184 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package compose + +import ( + "net/url" + "time" + + "github.com/ory/fosite" +) + +type Config struct { + // AccessTokenLifespan sets how long an access token is going to be valid. Defaults to one hour. + AccessTokenLifespan time.Duration + + // RefreshTokenLifespan sets how long a refresh token is going to be valid. Defaults to 30 days. Set to -1 for + // refresh tokens that never expire. + RefreshTokenLifespan time.Duration + + // AuthorizeCodeLifespan sets how long an authorize code is going to be valid. Defaults to fifteen minutes. + AuthorizeCodeLifespan time.Duration + + // IDTokenLifespan sets the default id token lifetime. Defaults to one hour. + IDTokenLifespan time.Duration + + // IDTokenIssuer sets the default issuer of the ID Token. + IDTokenIssuer string + + // HashCost sets the cost of the password hashing cost. Defaults to 12. + HashCost int + + // DisableRefreshTokenValidation sets the introspection endpoint to disable refresh token validation. + DisableRefreshTokenValidation bool + + // SendDebugMessagesToClients if set to true, includes error debug messages in response payloads. Be aware that sensitive + // data may be exposed, depending on your implementation of Fosite. Such sensitive data might include database error + // codes or other information. Proceed with caution! + SendDebugMessagesToClients bool + + // ScopeStrategy sets the scope strategy that should be supported, for example fosite.WildcardScopeStrategy. + ScopeStrategy fosite.ScopeStrategy + + // AudienceMatchingStrategy sets the audience matching strategy that should be supported, defaults to fosite.DefaultsAudienceMatchingStrategy. + AudienceMatchingStrategy fosite.AudienceMatchingStrategy + + // EnforcePKCE, if set to true, requires clients to perform authorize code flows with PKCE. Defaults to false. + EnforcePKCE bool + + // EnforcePKCEForPublicClients requires only public clients to use PKCE with the authorize code flow. Defaults to false. + EnforcePKCEForPublicClients bool + + // EnablePKCEPlainChallengeMethod sets whether or not to allow the plain challenge method (S256 should be used whenever possible, plain is really discouraged). Defaults to false. + EnablePKCEPlainChallengeMethod bool + + // AllowedPromptValues sets which OpenID Connect prompt values the server supports. Defaults to []string{"login", "none", "consent", "select_account"}. + AllowedPromptValues []string + + // TokenURL is the the URL of the Authorization Server's Token Endpoint. If the authorization server is intended + // to be compatible with the private_key_jwt client authentication method (see http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth), + // this value MUST be set. + TokenURL string + + // JWKSFetcherStrategy is responsible for fetching JSON Web Keys from remote URLs. This is required when the private_key_jwt + // client authentication method is used. Defaults to fosite.DefaultJWKSFetcherStrategy. + JWKSFetcher fosite.JWKSFetcherStrategy + + // TokenEntropy indicates the entropy of the random string, used as the "message" part of the HMAC token. + // Defaults to 32. + TokenEntropy int + + // RedirectSecureChecker is a function that returns true if the provided URL can be securely used as a redirect URL. + RedirectSecureChecker func(*url.URL) bool + + // RefreshTokenScopes defines which OAuth scopes will be given refresh tokens during the authorization code grant exchange. This defaults to "offline" and "offline_access". When set to an empty array, all exchanges will be given refresh tokens. + RefreshTokenScopes []string +} + +// GetScopeStrategy returns the scope strategy to be used. Defaults to glob scope strategy. +func (c *Config) GetScopeStrategy() fosite.ScopeStrategy { + if c.ScopeStrategy == nil { + c.ScopeStrategy = fosite.WildcardScopeStrategy + } + return c.ScopeStrategy +} + +// GetAudienceStrategy returns the scope strategy to be used. Defaults to glob scope strategy. +func (c *Config) GetAudienceStrategy() fosite.AudienceMatchingStrategy { + if c.AudienceMatchingStrategy == nil { + c.AudienceMatchingStrategy = fosite.DefaultAudienceMatchingStrategy + } + return c.AudienceMatchingStrategy +} + +// GetAuthorizeCodeLifespan returns how long an authorize code should be valid. Defaults to one fifteen minutes. +func (c *Config) GetAuthorizeCodeLifespan() time.Duration { + if c.AuthorizeCodeLifespan == 0 { + return time.Minute * 15 + } + return c.AuthorizeCodeLifespan +} + +// GeIDTokenLifespan returns how long an id token should be valid. Defaults to one hour. +func (c *Config) GetIDTokenLifespan() time.Duration { + if c.IDTokenLifespan == 0 { + return time.Hour + } + return c.IDTokenLifespan +} + +// GetAccessTokenLifespan returns how long an access token should be valid. Defaults to one hour. +func (c *Config) GetAccessTokenLifespan() time.Duration { + if c.AccessTokenLifespan == 0 { + return time.Hour + } + return c.AccessTokenLifespan +} + +// GetRefreshTokenLifespan sets how long a refresh token is going to be valid. Defaults to 30 days. Set to -1 for +// refresh tokens that never expire. +func (c *Config) GetRefreshTokenLifespan() time.Duration { + if c.RefreshTokenLifespan == 0 { + return time.Hour * 24 * 30 + } + return c.RefreshTokenLifespan +} + +// GetHashCost returns the bcrypt cost factor. Defaults to 12. +func (c *Config) GetHashCost() int { + if c.HashCost == 0 { + return fosite.DefaultBCryptWorkFactor + } + return c.HashCost +} + +// GetJWKSFetcherStrategy returns the JWKSFetcherStrategy. +func (c *Config) GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy { + if c.JWKSFetcher == nil { + c.JWKSFetcher = fosite.NewDefaultJWKSFetcherStrategy() + } + return c.JWKSFetcher +} + +// GetTokenEntropy returns the entropy of the "message" part of a HMAC Token. Defaults to 32. +func (c *Config) GetTokenEntropy() int { + if c.TokenEntropy == 0 { + return 32 + } + return c.TokenEntropy +} + +// GetTokenEntropy returns the entropy of the "message" part of a HMAC Token. Defaults to 32. +func (c *Config) GetRedirectSecureChecker() func(*url.URL) bool { + if c.RedirectSecureChecker == nil { + return fosite.IsRedirectURISecure + } + return c.RedirectSecureChecker +} + +// GetRefreshTokenScopes returns which scopes will provide refresh tokens. +func (c *Config) GetRefreshTokenScopes() []string { + if c.RefreshTokenScopes == nil { + return []string{"offline", "offline_access"} + } + return c.RefreshTokenScopes +} diff --git a/vendor/github.com/ory/fosite/context.go b/vendor/github.com/ory/fosite/context.go new file mode 100644 index 0000000000..90f9aa9b43 --- /dev/null +++ b/vendor/github.com/ory/fosite/context.go @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import "context" + +func NewContext() context.Context { + return context.Background() +} diff --git a/vendor/github.com/ory/fosite/errors.go b/vendor/github.com/ory/fosite/errors.go new file mode 100644 index 0000000000..e5a9f26ffa --- /dev/null +++ b/vendor/github.com/ory/fosite/errors.go @@ -0,0 +1,319 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "fmt" + "net/http" + + "github.com/pkg/errors" +) + +var ( + // ErrInvalidatedAuthorizeCode is an error indicating that an authorization code has been + // used previously. + ErrInvalidatedAuthorizeCode = errors.New("Authorization code has ben invalidated") + // ErrSerializationFailure is an error indicating that the transactional capable storage could not guarantee + // consistency of Update & Delete operations on the same rows between multiple sessions. + ErrSerializationFailure = errors.New("The request could not be completed due to concurrent access") + ErrUnknownRequest = &RFC6749Error{ + Name: errUnknownErrorName, + Description: "The handler is not responsible for this request", + Code: http.StatusBadRequest, + } + ErrRequestForbidden = &RFC6749Error{ + Name: errRequestForbidden, + Description: "The request is not allowed", + Hint: "You are not allowed to perform this action.", + Code: http.StatusForbidden, + } + ErrInvalidRequest = &RFC6749Error{ + Name: errInvalidRequestName, + Description: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed", + Hint: "Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.", + Code: http.StatusBadRequest, + } + ErrUnauthorizedClient = &RFC6749Error{ + Name: errUnauthorizedClientName, + Description: "The client is not authorized to request a token using this method", + Hint: "Make sure that client id and secret are correctly specified and that the client exists.", + Code: http.StatusBadRequest, + } + ErrAccessDenied = &RFC6749Error{ + Name: errAccessDeniedName, + Description: "The resource owner or authorization server denied the request", + Hint: "Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.", + Code: http.StatusForbidden, + } + ErrUnsupportedResponseType = &RFC6749Error{ + Name: errUnsupportedResponseTypeName, + Description: "The authorization server does not support obtaining a token using this method", + Code: http.StatusBadRequest, + } + ErrInvalidScope = &RFC6749Error{ + Name: errInvalidScopeName, + Description: "The requested scope is invalid, unknown, or malformed", + Code: http.StatusBadRequest, + } + ErrServerError = &RFC6749Error{ + Name: errServerErrorName, + Description: "The authorization server encountered an unexpected condition that prevented it from fulfilling the request", + Code: http.StatusInternalServerError, + } + ErrTemporarilyUnavailable = &RFC6749Error{ + Name: errTemporarilyUnavailableName, + Description: "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server", + Code: http.StatusServiceUnavailable, + } + ErrUnsupportedGrantType = &RFC6749Error{ + Name: errUnsupportedGrantTypeName, + Description: "The authorization grant type is not supported by the authorization server", + Code: http.StatusBadRequest, + } + ErrInvalidGrant = &RFC6749Error{ + Name: errInvalidGrantName, + Description: "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client", + Code: http.StatusBadRequest, + } + ErrInvalidClient = &RFC6749Error{ + Name: errInvalidClientName, + Description: "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)", + Code: http.StatusUnauthorized, + } + ErrInvalidState = &RFC6749Error{ + Name: errInvalidStateName, + Description: fmt.Sprintf("The state is missing or has less than %d characters and is therefore considered too weak", MinParameterEntropy), + Code: http.StatusBadRequest, + } + ErrMisconfiguration = &RFC6749Error{ + Name: errMisconfigurationName, + Description: "The request failed because of an internal error that is probably caused by misconfiguration", + Code: http.StatusInternalServerError, + } + ErrInsufficientEntropy = &RFC6749Error{ + Name: errInsufficientEntropyName, + Description: fmt.Sprintf("The request used a security parameter (e.g., anti-replay, anti-csrf) with insufficient entropy (minimum of %d characters)", MinParameterEntropy), + Code: http.StatusBadRequest, + } + ErrNotFound = &RFC6749Error{ + Name: errNotFoundName, + Description: "Could not find the requested resource(s)", + Code: http.StatusNotFound, + } + ErrRequestUnauthorized = &RFC6749Error{ + Name: errRequestUnauthorizedName, + Description: "The request could not be authorized", + Hint: "Check that you provided valid credentials in the right format.", + Code: http.StatusUnauthorized, + } + ErrTokenSignatureMismatch = &RFC6749Error{ + Name: errTokenSignatureMismatchName, + Description: "Token signature mismatch", + Hint: "Check that you provided a valid token in the right format.", + Code: http.StatusBadRequest, + } + ErrInvalidTokenFormat = &RFC6749Error{ + Name: errInvalidTokenFormatName, + Description: "Invalid token format", + Hint: "Check that you provided a valid token in the right format.", + Code: http.StatusBadRequest, + } + ErrTokenExpired = &RFC6749Error{ + Name: errTokenExpiredName, + Description: "Token expired", + Hint: "The token expired.", + Code: http.StatusUnauthorized, + } + ErrScopeNotGranted = &RFC6749Error{ + Name: errScopeNotGrantedName, + Description: "The token was not granted the requested scope", + Hint: "The resource owner did not grant the requested scope.", + Code: http.StatusForbidden, + } + ErrTokenClaim = &RFC6749Error{ + Name: errTokenClaimName, + Description: "The token failed validation due to a claim mismatch", + Hint: "One or more token claims failed validation.", + Code: http.StatusUnauthorized, + } + ErrInactiveToken = &RFC6749Error{ + Name: errTokenInactiveName, + Description: "Token is inactive because it is malformed, expired or otherwise invalid", + Hint: "Token validation failed.", + Code: http.StatusUnauthorized, + } + ErrRevokationClientMismatch = &RFC6749Error{ + Name: errRevokationClientMismatchName, + Description: "Token was not issued to the client making the revokation request", + Code: http.StatusBadRequest, + } + ErrLoginRequired = &RFC6749Error{ + Name: errLoginRequired, + Description: "The Authorization Server requires End-User authentication", + Code: http.StatusBadRequest, + } + ErrInteractionRequired = &RFC6749Error{ + Description: "The Authorization Server requires End-User interaction of some form to proceed", + Name: errInteractionRequired, + Code: http.StatusBadRequest, + } + ErrConsentRequired = &RFC6749Error{ + Description: "The Authorization Server requires End-User consent", + Name: errConsentRequired, + Code: http.StatusBadRequest, + } + ErrRequestNotSupported = &RFC6749Error{ + Description: "The OP does not support use of the request parameter", + Name: errRequestNotSupportedName, + Code: http.StatusBadRequest, + } + ErrRequestURINotSupported = &RFC6749Error{ + Description: "The OP does not support use of the request_uri parameter", + Name: errRequestURINotSupportedName, + Code: http.StatusBadRequest, + } + ErrRegistrationNotSupported = &RFC6749Error{ + Description: "The OP does not support use of the registration parameter", + Name: errRegistrationNotSupportedName, + Code: http.StatusBadRequest, + } + ErrInvalidRequestURI = &RFC6749Error{ + Description: "The request_uri in the Authorization Request returns an error or contains invalid data. ", + Name: errInvalidRequestURI, + Code: http.StatusBadRequest, + } + ErrInvalidRequestObject = &RFC6749Error{ + Description: "The request parameter contains an invalid Request Object. ", + Name: errInvalidRequestObject, + Code: http.StatusBadRequest, + } + ErrJTIKnown = &RFC6749Error{ + Description: "The jti was already used.", + Name: errJTIKnownName, + Code: http.StatusBadRequest, + } +) + +const ( + errInvalidRequestURI = "invalid_request_uri" + errInvalidRequestObject = "invalid_request_object" + errConsentRequired = "consent_required" + errInteractionRequired = "interaction_required" + errLoginRequired = "login_required" + errRequestUnauthorizedName = "request_unauthorized" + errRequestForbidden = "request_forbidden" + errInvalidRequestName = "invalid_request" + errUnauthorizedClientName = "unauthorized_client" + errAccessDeniedName = "access_denied" + errUnsupportedResponseTypeName = "unsupported_response_type" + errInvalidScopeName = "invalid_scope" + errServerErrorName = "server_error" + errTemporarilyUnavailableName = "temporarily_unavailable" + errUnsupportedGrantTypeName = "unsupported_grant_type" + errInvalidGrantName = "invalid_grant" + errInvalidClientName = "invalid_client" + errNotFoundName = "not_found" + errInvalidStateName = "invalid_state" + errMisconfigurationName = "misconfiguration" + errInsufficientEntropyName = "insufficient_entropy" + errInvalidTokenFormatName = "invalid_token" + errTokenSignatureMismatchName = "token_signature_mismatch" + errTokenExpiredName = "token_expired" + errScopeNotGrantedName = "scope_not_granted" + errTokenClaimName = "token_claim" + errTokenInactiveName = "token_inactive" + // errAuthorizaionCodeInactiveName = "authorization_code_inactive" + errUnknownErrorName = "error" + errRevokationClientMismatchName = "revokation_client_mismatch" + errRequestNotSupportedName = "request_not_supported" + errRequestURINotSupportedName = "request_uri_not_supported" + errRegistrationNotSupportedName = "registration_not_supported" + errJTIKnownName = "jti_known" +) + +func ErrorToRFC6749Error(err error) *RFC6749Error { + if e, ok := err.(*RFC6749Error); ok { + return e + } else if e, ok := errors.Cause(err).(*RFC6749Error); ok { + return e + } + return &RFC6749Error{ + Name: errUnknownErrorName, + Description: "The error is unrecognizable.", + Debug: err.Error(), + Code: http.StatusInternalServerError, + } +} + +type RFC6749Error struct { + Name string `json:"error"` + Description string `json:"error_description"` + Hint string `json:"error_hint,omitempty"` + Code int `json:"status_code,omitempty"` + Debug string `json:"error_debug,omitempty"` +} + +func (e *RFC6749Error) Status() string { + return http.StatusText(e.Code) +} + +func (e *RFC6749Error) Error() string { + return e.Name +} + +func (e *RFC6749Error) RequestID() string { + return "" +} + +func (e *RFC6749Error) Reason() string { + return e.Hint +} + +func (e *RFC6749Error) StatusCode() int { + return e.Code +} + +func (e *RFC6749Error) WithHintf(hint string, args ...interface{}) *RFC6749Error { + return e.WithHint(fmt.Sprintf(hint, args...)) +} + +func (e *RFC6749Error) WithHint(hint string) *RFC6749Error { + err := *e + err.Hint = hint + return &err +} + +func (e *RFC6749Error) WithDebug(debug string) *RFC6749Error { + err := *e + err.Debug = debug + return &err +} + +func (e *RFC6749Error) WithDebugf(debug string, args ...interface{}) *RFC6749Error { + return e.WithDebug(fmt.Sprintf(debug, args...)) +} + +func (e *RFC6749Error) WithDescription(description string) *RFC6749Error { + err := *e + err.Description = description + return &err +} diff --git a/vendor/github.com/ory/fosite/fosite.go b/vendor/github.com/ory/fosite/fosite.go new file mode 100644 index 0000000000..505083ec38 --- /dev/null +++ b/vendor/github.com/ory/fosite/fosite.go @@ -0,0 +1,105 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "net/http" + "reflect" +) + +// AuthorizeEndpointHandlers is a list of AuthorizeEndpointHandler +type AuthorizeEndpointHandlers []AuthorizeEndpointHandler + +// Append adds an AuthorizeEndpointHandler to this list. Ignores duplicates based on reflect.TypeOf. +func (a *AuthorizeEndpointHandlers) Append(h AuthorizeEndpointHandler) { + for _, this := range *a { + if reflect.TypeOf(this) == reflect.TypeOf(h) { + return + } + } + + *a = append(*a, h) +} + +// TokenEndpointHandlers is a list of TokenEndpointHandler +type TokenEndpointHandlers []TokenEndpointHandler + +// Append adds an TokenEndpointHandler to this list. Ignores duplicates based on reflect.TypeOf. +func (t *TokenEndpointHandlers) Append(h TokenEndpointHandler) { + for _, this := range *t { + if reflect.TypeOf(this) == reflect.TypeOf(h) { + return + } + } + + *t = append(*t, h) +} + +// TokenIntrospectionHandlers is a list of TokenValidator +type TokenIntrospectionHandlers []TokenIntrospector + +// Append adds an AccessTokenValidator to this list. Ignores duplicates based on reflect.TypeOf. +func (t *TokenIntrospectionHandlers) Append(h TokenIntrospector) { + for _, this := range *t { + if reflect.TypeOf(this) == reflect.TypeOf(h) { + return + } + } + + *t = append(*t, h) +} + +// RevocationHandlers is a list of RevocationHandler +type RevocationHandlers []RevocationHandler + +// Append adds an RevocationHandler to this list. Ignores duplicates based on reflect.TypeOf. +func (t *RevocationHandlers) Append(h RevocationHandler) { + for _, this := range *t { + if reflect.TypeOf(this) == reflect.TypeOf(h) { + return + } + } + + *t = append(*t, h) +} + +// Fosite implements OAuth2Provider. +type Fosite struct { + Store Storage + AuthorizeEndpointHandlers AuthorizeEndpointHandlers + TokenEndpointHandlers TokenEndpointHandlers + TokenIntrospectionHandlers TokenIntrospectionHandlers + RevocationHandlers RevocationHandlers + Hasher Hasher + ScopeStrategy ScopeStrategy + AudienceMatchingStrategy AudienceMatchingStrategy + JWKSFetcherStrategy JWKSFetcherStrategy + HTTPClient *http.Client + + // TokenURL is the the URL of the Authorization Server's Token Endpoint. + TokenURL string + + // SendDebugMessagesToClients if set to true, includes error debug messages in response payloads. Be aware that sensitive + // data may be exposed, depending on your implementation of Fosite. Such sensitive data might include database error + // codes or other information. Proceed with caution! + SendDebugMessagesToClients bool +} diff --git a/vendor/github.com/ory/fosite/fosite.png b/vendor/github.com/ory/fosite/fosite.png new file mode 100644 index 0000000000000000000000000000000000000000..315eb4d38c5cd7b6be8fe955fdcfecec8e77c3b2 GIT binary patch literal 43726 zcmeHw2|Scv-}hAdr$k9YvKK{`79?9)(k4lkgh?uuwPZJ=WJ!dQ>{R|J`;wg*OPG>| zim{I^WQJh|W6Ut`Wl2}>efQk|`+e^Fo}TA*KA)JrbFOoJ&+q#EzUOz&b*_v5*)v+K z8@6wNKp?Cqj%%EQKvq+L&#BCR06%G0@23O5*4rPy-~fS0iOm07<&voC1c7kYoX|LW z-lc7%bKe=#hnIhJ=Q6ddy1e$dwcuKo=P#09CM9T}h#VMxkb3dYq?bBXt9R$D`ZG=N zJzJrm0&-yb?bIQjc8kG1{IMiYs7fslx+SyrK%eIn$LE+c3)A5Sg41DAUX!G#=@MgtHmZ zjpvGQ0gMDchtRoN0xr=%S9YudXlzuUgBscKjQV&$ASl^>t}0u&H}Emy2ugKdHw!>C zL=Pn`im73upnI=fGBaWdy}eLXsGlzBb0PQkN3=@0yksP$U`sI2O^B;Et=Rmq)hUbB zkn#s=aCPaqGXy0FBv86vwRxgfRs1Xj!VN{yUolVf`mBdQ`ZiMB##ccui3`!~)NHg- z$g>dub3_PKmftg75cncS$kU9S$hBb$1X9C8Ocm|?$hi|}?m)k%fj2GEiwOb|5`aK9 z6IVg*nyDewK>r86h{8>1jz1}I?V(`8a#lgSJ$z7y*38Xj#yYD4R|FA)KDc^LTeEPJ zvV;WW2+D8Vn-=^a1gU2*Z}h(P6xGMqlnI!Z*DdK4`_=$QbK9XXHS;H&H;|CP+%Qpe ze?N3RWuZDVh4kPqU7;L)!(#sbVobx1o$n8;mu@}9JAdr)&k4vqKGd(+X!~_-0yY}~ z%I25l`P#Sv_qY$Z!s1V6%4%l7CxGJ@e_mf`3%J$*0{j&0XAzwD2{o0)pU)qy0zS_> zks3T|vlGc`ii{LTR}hQD-w&R2Wu{2Bh0d&onEKMN0VA5X8kMiWcHjNtfq181Q_)Ak zcg90*4Cn#G})j1YR$fp8+snLbL8kRJdooY zL`zn#?xzDhYad@=|0M4ZZ%=CJvi1^kG-&GEaX~70u*0G27H{-br!|FV#-g1xFBUsj z{s9qE&DWY#Fwe?l$wwVd zdn3e~_Sr9L?-}N=)OQJ_a=36$c3%)z(YmKEJ1(z*7X_*qcbrvbq4aH_XcA@*o4e0E zh>38&?k?)M=7>59DQ@bbu7A%4{^x}x^DBBxA+78^HjTs+6^94Et`YIQWc@HqPilJ{ z(_WGHy#uG!;Ndp-l;qo1q&tK0{<+!md5K}smyuOQFvzP7l%lmS$qlNqU*x-xH*gUaxdr|Q~U&RjM<#x$F{@x6WH*A~hedG>g9 znynC0zq7MH=j6G!4VjPhodK^*<|1MgGWxgRu?~86*K0UzRXO0bIn!~GXJcU~I?9IU z%YzqC7BLr~*FMAIpD6zykwQAFnM9O z2}>SdT4ac)0rm62(}N zs7l~ahN#WC7|ywTbPc4gcVOl}z(SE%n{&nMyloG%jO44^R7Qcwl!YL9tz>MBGH!=o zKq0w^XwiPv;BW7Ys#1*INUJszwF-$^ojaQ;$14YvlDlY8FLX``(XG|sonr;5kMk0A z#N6kZ_|UZLqexsL>!Z08wE5E_C9>*dyVq07lueDVc_?MpI02HT2B*sG7r4+JGq}J1 zmAP=AF)H2z1r2nWZr@)^o{!adsX&v!z4m7PZ*1Y8Kl$q!-OxhWDf4(Jds(>Iq1YgS zs{MAiO_A<+32%*3rW*&Q97#U3X8CBeh(bomzS3A;fXP&!oq*Q%!vYT5^*XYG=&H(p zTCh^p;JE0L=*QT-=$HwhOQcO2!FujD^wgz?`;Jg^gP3QiS@hlg!7BY|2jh>j<90Gq z0uUijrhC`-Rr|k?ec`sR`;nG)12(ffm%Hkws2V)gYz)nw_o7u{?;tVw(tGbO#P$+A&h<&RULcEA~Hc^}B>dF+Iek{Y%DpvqYpIVNW~dq!R) zAVNIt1>mCAeSdBO`tKJ=%E_ihC8zIC=bp~!uISoeQA;RBdo=X z-yq^Vlqn;A#5Wh*96FsFfa{GL;7OrTN9Y-zWpgt#lX}y0lXEx&o<{?RGUkFhkCSI} zUfsuP&R$eV8YaD-Y>n`+AX2B5c&^Gp%w?gF&lH~?6Q23>MUO6TQak2PVx?3+>OPe{GRqNfGmh2q z^o;LT?0Pt|eYz4fP}%}>A{t>PkX8dYyP_e$VQaSTrL zJhLJa$O&kk16Q89$nzjmjyf1#og5GtbFT~m?@O7dS>4X%6A-Nyo$Cz>QUy_K`J{91%(8M(6Lkp*}Nki z_I0U# zc+*D3u<*cx6Y!Xe(l_g~Qe)>&pXnYofq#3dH_k%{ibC(}&%8Wva|d@DX;;5Uzq7z* zE%__SLMD=;JBS27NRz%Y^0w}&S6Ya4zoE5fyVJ|bxz}L;H6SiKHYy~Q)Q*3X z=U}585K=7(L1vk$03PKzP~{jmPoPKra#Kibr;!_pw|! z!CD~1B3>CyZ7#hxl~Z3`QvbHLo3yU_nPI@~2N`0HR~;@hv*J+s)AY>jzK{29l*7z6 z=FugctFcfn&$(yCqq1Sz-&~&7dC*s<`bkw#afnB5?9qI z%WAM3*X#{NAl_igr;`p^8 zKkiFd{bR?8^ojk+Czcgpm2xUaUW1pAxQolE+q4jk{5A;UzGjXiR)M?T&(hFG*5owpi28W`$iXK`+J=R z-hDD-WqgI#eYisO`&nyJUTRGj-@JkJ7V^A^v1*!7<~%xj8#(e!BD&Oh@{p2nzu~j0 zeUm$@?PJf`r=*A!RIv8AtCwR9eEvLFHajfdUyv3K{fada4^7q>yjP%Sw?nw?#Ci8q zu4yM%Q4=qJO|$2fmc2^a;wohYI}-@wb#zJKqqN!>+6+G>S=z5DdE_d-&p$+9U+JaD z8|BbuJSiy|HqA{Oc$KtK#fMfwPPW}YEtQ;ng;nS6;Txwa{At9q<+d)RwCxmb`sC9Q zCN7^0wK<%BPvT8#X7Ubn7`WG#el;^Gp-sh>{!F)>30o6^c?e+8u1E+ zZXxF4aAj{AX4_z5XplblHQx8xqef6UNlCY1g?-Z`zXw5gYaBE?Ki@lVGu%S5)E#JC z<#|)c)4<^|dUWjtR)_U&7pwm?SG}g}LAQN%Ro#ac>Q0hZIBhFE&NYQ@6{0^VcDf+jzlS-8VDtV?cL@FVX`K;v zbsOWg8B9W|QzIo}0;$~ueqp!T=wW((s>5Y_k?fny9qrw@cI-X0;wrhO8Jg?q^7!+p z;E3`l?S^3H>43O3p9Ixox4-YvMWHW8wj~u8^Y0(xnsipyxVWLl23{Rl&FXe9&Uk8z zioW%r(ESk4R!x+&skMNx8#(R|HcI&G;S(=Iu*E^=>wTDms!Z$L6tAF=Be$EL2-@>a zGJW$7!G7s_!k3CF=9`TSLi-c+Ys+@v@1xD~UEhZmYUdsH{6l_Yd;X-&IU&`{fz)mb zf8H9_P5b?xo3}L3EF-!wEJCW$oM|c!8)w*8AxUDaiR+D0g&Ryohbc&KI)pu7Iv!+qI3s^#EbWbyImL9607x64UR7) zZLJj_P}G?{UFmSSlc_g(tVWDGh;;tI>9LGHxu)S#2kY|qn<(T>?#m6WH+k9bU1`mN zdQxGsXCo(PnEvc}T}RxZ?pPy47k;U2^M{d}V{BE-z22AOX2x@)4NN&UojH$W5o}B` z1Sxe*HX-DDLWq6N+$ zNS#sA>1o6#(;c@mgjC-tWZ!J9doDJcc$vF?@}5KeDPJK~C8$yi3}weYK`xsy)Hy%(Qthbl6bKyrToDaUlm$Gx_&u$@Wo;V4=C!doJ<2$j<6T z@9VE*t`_D^vlu?%d+K_Aid|2@qsv|` zk9F3#u~3fMjipqPPNamy-FDCVHpx@DpOI1kGUHpcb%PLC+hL1ssLf=(0k9JFXhJW21K%| zTxl|#r+NKg?2z-p7)_L&!m50$GVSRRg`xOf-BE)co7q- zA*33!d&cZmt_!bsCD}J|n*`2g+%z+>;2}bjsifI4Gc!bBR4aTH@_tBsztJT3f;}f1 zO3pq?Pg8@BT^x{fkJM{%%p34XD$C2hx}PIOOLeDh^KGO0owm>J zvwWSqOxYIGfpgQWvM<e!fPWAIY=gy4KcC8>8q1Gt?lz+mw7Y*(9(qt+;T{c8|g* zA=r1H^t>T<3kyQ_tE??#2F- zxAfjfRL+LE$$y)=tfPa2zvTxILfoY~b8?c&m1Sy1^Y!_VxtdT*EAXd?H zM)o_;FHiRK5#vu6t_2p@A`DP;xt?uDQ0p!oUPb@teQ|l^4S*oP5*GwmLj!;KzA(33 zZ{fq=)|*G>7w~?rH;??>-tv(@HGKRleHHvbJ&)2=&SSv(BjkkU8I26JOJ4j(SD(rN z1NuOzMWlQ$ho|O&#q!^PAD#W)2)Oa#7DL9u?BBbY0;a-8Wh9*PTavPXE?+5-c~Te) zJK|H9uM~(0gW(|9vZ=sK7z;OLXD*ux#Du{xNL|287z=|H3dDrLFj$~KLd;+oqy=Cm zjD;DjN}$eznSixmMXVMj5^R&-N0olT1f&K3KZ=zf-*Mm;vLIxBFTnBu_ZLJFtP3l` zwKxb5x5%q4+wd29!4UY^tK}@=_t7W|Ec3FlexVo)fSZ0xQY&fRq67b9vHlCv1#09! zRr~L#Wo1`cpJ>)zX6~-lU8{&2LP}SymM-^q5U#y)Wi9~3_M1b`4osZf3wl+0M@_jSpoS)`b0z0ji%H}CxF=46vhu|YEz{iG!LT>%J0}R331i{AS-{T4r2=BY zU>FqiU?z-(8LUd6&V!kNwE(1#42D5k0A|8in8B(9>O7bUSPK{-R`Dmk$3NsZqs8Ci zIZMJ;C5$(g19ue`3t+8Rs=d+tFaf@xIjI(Y$>3uH8^3>PE>I5hLg+rA%$798*Q;B?#amcu1{9Y&lCL? zdV>ZGJNi?5&k?d^^$%v)90|>XD&H*#w9?ItoAGoWZQtdE_}W+a}b2gvverXRVJ_sx$0EQjx=eImkKyPzf1|mQfY_+3%Zat)>ay#ok|n~bVon=R!ER!O z2p`F@Y^nvE9?9y3;ay6}OJLNbVJ>}f&fhxasEB8IY^_KBR9vTMzIw5Fz>Y3MS<*Xp zDI$g5QrSFJ13pxt3k(s2(t6!<5xFmQp||19yH>w{ot5cs4sA)ayVx`PhD}w~WE?Jn zwqK&?4Lbs@LYND`@lVt=&XvehIMU`bblrsLP}4(rk7st-j>$^I^^}w=Y3KC5&FaJE zlq&_cP4Fpt#IssO73^13;IG{7BC$QkS0U=zp)T?S4+nbw36lBZ4J%L3^vqj#mX+yv zUCQd*El1lGPHxY$?&{j`q3L)W%Qd^6%8coyvjdLFNnK)?;IU zomz2czv||2KC(J{iHxW!t9rG%FUB&^?tBGRtg3>Lgviax{L)s>q8Bc!<=Y-}-MPDU zNpEqit+D$+aXdZ`?Q@Zq{SDw`wpj9e2hXhRfH0`M1d6%;MdhmRudU zjNY&j?m;E7BT;Xz#DvD&`pCQEV(Q?T7DH-8SKGG9um{wdIP4{qxkwV9+f=&8t59iZ@^UD z;v_G+yck|M{voH?@?x{b#|$qHkVgP67&(4*1YTf6>9B3zy6bA-)hni|A6+VKVSX9- zZkIOYhK!%CQ%NO4-SGY!`={62S~f{;pmwF<{5DXNOxsqG4kek_I9%#gU|ZzBV526* z{1eCS9>k$&AKP-Qpf!(cPT^)=R3g$6(*5{Kf)UEK;D~c#I-cBF@&{ieHqAoESvL4; zsWu$9;h*_dSrQMb-FF za9jf(KX8&+AJbBGSSh_C%<85x%i{V9z(x?@-!vZUw6+&fl$Duhj%~>eiPJowBQ&h& zS~f-5TFN7Uv`xAa@#d^`+jvo2l1HZLrsl@9BOUVaFOHqW zEJFQ4Bk`_^#Mq!-$GyWAerJUsvl|JpuFhKmbJV^G>IM}H_AX2#8n}-0W!^3US%ebS z5=3W@dwu)u^CPhcYd8*S186n3ZS`qtrzc}b#h)`^?haEfLg#y54Iu3` zNTRpSlL+aGhc^^vNi8>502t?PyOT#o0c_(o4(zR%Tr2GH7K~9#!I>gaE3_K_z9@E# z(lutzmk5Vaa%4xO^o}MPXW2j=YhTThg%>=M)f~H1WFzmLJ8|oHus1&C%7!`aC7hmb zNFImNZTP~UsN@q{KXpSZ(D%}?X$vOK^&6_K_>ii;X=;`eS<|cR^P!i0uJNNq+t`;p z1qj0oZ&(#V(_SIFH_OuMX2`9bgo3Qh>@32FZnL0s@VTyp&JT!lW)3r*#}0n}-XNzh zEdBy+suIUF7(2^k^22iTBLp`lL#NjF+K&6hxNpTL70*xv@m72Bb#1b@hh2~R?@mMo z!GMGo%3Fodo(>%J%2X9-r;2o|Ev2pV=^xaIySb>(#lb7ZRR^O#JZfKw7^rceeXx1& z*y_grDg3TB;Kp?>biKf0XXgzM^Hnv7a7@3W*O zBKX`zg#jmY#ICZ7fbH29X=WOsVrau65W~erB{1G35ihP=U``V|CN@ z;5dHU)OxBnO!m>>uE1}GuvbBp5R?v@ZH$tOo_os~K`c@*Gg2Y53 zY$n;B_?rqM2@1`g+vskGXAaLOXen!@CJcIc()rEk(bH72#LJhO+_frhnV->SnU6Gc zdUK|gD|gU*(Po^KG?{!POBcHKdE7w3={Fp6bGdJ=q{Rf7! zJvmKN{mE2jtb6>lRAvtu-7^@Ff-&o&?aa`+{gK>5COErn^GJdX@;3L{wE~YEIu?&b z5*poO2gmy=2X|pwEd7giPbzIhQYCVH69_XVV?}d>aV##bc#^_Xk8zEQqao*?5MIdr z&7l%i2pM2x3(l@@mg|@e+6|%NF^1qj0PwB0fLdi6_lX+izNg=ehOE zyF;>rcJjLAx$7SvCtB*Pt;u?*{(KCZy8GHpFgayEK0w7YYzy^IADDpdpLv_;2b__`>+{Z_lI%rZ<8ZZVTN(u1)>gV0^8E3g_n!%YfO zuak@2y zwUPYYcq=75Z$DG+=WSi5J{ONB?%ql%-rR&g;8l2tXl(L8zt{eXp3L43leS&r_;Y#3 z|B&SLgHhA?Qiv+JPnO<feLA@y&^Zi%M|5IDOA#l}_Q zc^pWt!Gk@n$t7EQ2zC{iQG%;ZCy^HTvT0UU(ROj1Tu2DNaOVcGndaXy3+J)uY8s>9 zL@iK(1iB>Ns@mn+g_0BbH{?IW#7avb!(Y1eeLHtHeB3$JOYt!5T3N;rRYM3>R*6tk z)H7wj4&!{3*=yRieIpf-Vj{um4GY+Uvj{7QzA(Yp#gfr3=MB@@<4N_v(T))&`KxVo z=?e7QJ_ z2WA_0_Tzaiy_NGu)C@0|hQ^Es@$#$l#mDE1beObY9**~qv=yY{S_W44bu<+{%e|Z) zh;)7T(BvWfSSz_m%S8WRQi%}WT`H%_pb^uwd8*8y)F6Wmond6Db3uzoYrHMxL#f=3 zDcC?M-L8>O$U!*kq;TpMbF9@p)Yt&Pbk_Z&(zXk9s=Lyr1bh2Xj@FR`jMN4uSF|%C z`J}3<=3)joKN8<*;i^#}sC5_$4yQ_3^B#2czV&g(Y5rTL1>-6bSq25#H868lI~*eX zjN&^@MaQzOv}nypks}Fb2SvWZx-M>>QtlMNpVE-KVBR>GSDRw6V@g@S)WCK<^<-x7 zb$-PVKH%Uj3J zX6jxW6YW~q+Lwru(cRqD{DT(!s<&5%pHnQ*)O|nvj9g^dVt6!5ILjHB;4SV2csj{b zRC49&$U}Y07H7Y_+oxK{dUD1A18$*mwYw4ulBy8N;u)|S7{&dRiMvfpIEg>ZG!g*q2S4IUT0!t3r@)}L*}}25%r`PbHuCw`mcg$U*Uo|YJ8T2hSE1H#&L_g=EUEAh z1@=xTH#zGbCB-qkDkhdQJh(XH;*KfS4IO&P4{XnqiaQ57PB{zcFl!phS!$Yg_Xebk*nWHAI8%xwtP1szTG0 zz{_D+mdEd))3Y!C%v{Gt?UEk(#0f7Dzm30nu@WKC{4gt1(;Ql88~vtF-v^dhg*X}K z*HfnQB>UCE;= zGnIz|@F==25PTmPJiv$j1~=xKrkw~SZCz{mPLQzm8eYPMj^2BO9AU$;boOrr!|h4IEZgIDK-G+I^rc~WPM;^K#&YpsKEI(v~Vh7 zX4II{AlKT}^02LT2S>|9To>jui-}j}l@4b%+A&V}XioQ_-1bRL3#lBDcCsw{l?uUB ze~Sk`FmeF(BkpUu7kbCD!gx__w65`;Z9Ye(q@5tp_&Uzor<$euPwT%WJ2wR#Kr z>8%dpK+WX1S+AYSXQ#aZy;bBVgr?{$>8Sfnv2i^5-Y~%BqAKSN$JIQ0YAf3{W#p9R z>RQE4J;U_RG6p|vHp4!psoRjR5%`8h>vK>hbKk()pbqU(YdPyi6V6BZ&6-~6Pww^g zH)0$OfyJ6zP!FB5u<1bEmY(bnWf$wVZ+OwFbx-D-y!6>R*I>-%r%KRi*Vkhb+3lUe z(yv}$md{M7MC|@VLGtBQj$Wa@;mdE^GS!(iALnN8@z=O}E3t3*>fUD*43%wj9dDAg z${fv-Zll;Z)LNe8G>2ZryiUr>d@|UR=*YpBPK_hBkqFRJ8Shd?U#DVjaOV~-2hA)q zwQ_o$(B7GnN+}QeXDnK{Zj96!MsRmS9^LdZogl+C=o;x4&)2r?%6h6eA8yDu52;<0 z+fI}3u6XXbvd3ZX^#?|BTwYO`tM`4@I#r1vjT%B5 zX;QYOL5|)q!}PF=>N&d&#B)>(ZYTz5W>WU#s9(Ml`>7HUjWLTghfcuc3N-!%YU-OM zAFf1*$NO=`1w@xxz|o2`oUBtRrOCFY$^M0eR(kS6KrPIY9S`FJ5Vh03+^@w;a!OV? z367RjzbzgefNk??b*v%-WAG8VhoNvOd=hy}wRk4i+|;f%*r>!+`DAiw_pWS_F9V-! z^^&tS@4XY<^@@U;h9k*=y}-yjC}KtCK)WceR^nO*Mwvi{Y&n!>^7hBKXvP*9eyp=;JZ@4U-%AvM+vB)^E(! z>R6o90ogX(2i8cA4C~O%*pQ5lcDx>R%sEJKllHnGzya^Kj)<(y(cR&|c4eDx!{Y+# zg&lWd6Edq^!(Ztb(5Ya`hh}8cf;BJ4ni>m0*J23@+sP_3QqhN!He}XqsIfJ62Q2M>1TR*Kc%UC@4z0#~ z8#RZ9p{s^wr!*_ELoS`LPV#vl+=OiL$KK_^wh{sNhV>}MI`Kv~XWhq2d3=1HK)Msm zoWohW8JMC9(EHyf+^Or*36=A}Zq|Q$v{vDq`1a=>-u8X+>^&aOT7~uoTCnr!7X|l5 zgvT8JDp4voSCUzZw%d(&52}m|24*3cv@r2Xghu(B<3%6QhNW1l&(KXrGb`7MmUJsZ zmpN2eX)mteTUKTY?z|x|m<;w9Hjc@AG#dhBs})Znv@nK0%xvZxkjz*6jPn@0WDMRH z_d$n~y-f;06gQJflp_a+^;fnM{I?CyzUM{8DLa~cH~91Iu@pY!Q{ zI_Rx|UF(#p=#7!A!am}^0&iC6X?8Wc=9T7$i1#%YL%LQ_ze$(c&H^cDqE{?=zgF$i z$^)RV{1P*~0gt3U)*s@I*mP3E)1pUgZ51MZ^OS-u@FJG^0;DjIBUQTCQx9h329_3G z7BG@IR@fUx_zBC^#p*qnnfeI>>S-}k5g(RT3;@=Uy8~4SERZooFNXW#o`w2juuP%h z_6RVxNa3Hpr5U<(9PkU6seLbibbtTI7bGXZPCidZdf^9S4H_fe%^FagCYL&VC?d-;hC5S70m9sl0iD-V1xJ+cCd`(J3` z$^+j^9t_eykkwYya>0$s35*;u>#=;C2%cTnp{Q5;g_4~k}!2E@r zF#rZj1c)GmVQ^rAq>aHaDCogV7z=~70K|mBFk@8-+<6cautfX>tKi#&=9l{JKBs3Y zsCD0MWn^9m7J(JA(E#XMZ=p19cwEWJNibtOZKsz%~KF49@R)sO3s(r?3Anmt2rUf!k&*3|1%*lm8OV zvhrKlx8^m69ALh;=Gx-RegEpwe=|e=FVD4D839cRnvR#>7$rfvl&U&^S8(+!9zt{+&r7C`iGlWGoDp z3lI|q!z;qIB3vuCAC`xNf2S&0{FZMpS$WcR`Qra$E!6)VAHQYr(jCZZU?$+1=)ZqO z?~PUM&iU83-=8Tk3%chgx%lq;?4`ei0DSQl^j8d)|1$AU@aDz83pn2j + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" +) + +type AuthorizeEndpointHandler interface { + // HandleAuthorizeRequest handles an authorize endpoint request. To extend the handler's capabilities, the http request + // is passed along, if further information retrieval is required. If the handler feels that he is not responsible for + // the authorize request, he must return nil and NOT modify session nor responder neither requester. + // + // The following spec is a good example of what HandleAuthorizeRequest should do. + // * https://tools.ietf.org/html/rfc6749#section-3.1.1 + // response_type REQUIRED. + // The value MUST be one of "code" for requesting an + // authorization code as described by Section 4.1.1, "token" for + // requesting an access token (implicit grant) as described by + // Section 4.2.1, or a registered extension value as described by Section 8.4. + HandleAuthorizeEndpointRequest(ctx context.Context, requester AuthorizeRequester, responder AuthorizeResponder) error +} + +type TokenEndpointHandler interface { + // PopulateTokenEndpointResponse is responsible for setting return values and should only be executed if + // the handler's HandleTokenEndpointRequest did not return ErrUnknownRequest. + PopulateTokenEndpointResponse(ctx context.Context, requester AccessRequester, responder AccessResponder) error + + // HandleTokenEndpointRequest handles an authorize request. If the handler is not responsible for handling + // the request, this method should return ErrUnknownRequest and otherwise handle the request. + HandleTokenEndpointRequest(ctx context.Context, requester AccessRequester) error +} + +// RevocationHandler is the interface that allows token revocation for an OAuth2.0 provider. +// https://tools.ietf.org/html/rfc7009 +// +// RevokeToken is invoked after a new token revocation request is parsed. +// +// https://tools.ietf.org/html/rfc7009#section-2.1 +// If the particular +// token is a refresh token and the authorization server supports the +// revocation of access tokens, then the authorization server SHOULD +// also invalidate all access tokens based on the same authorization +// grant (see Implementation Note). If the token passed to the request +// is an access token, the server MAY revoke the respective refresh +// token as well. +type RevocationHandler interface { + // RevokeToken handles access and refresh token revocation. + RevokeToken(ctx context.Context, token string, tokenType TokenType, client Client) error +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_auth.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_auth.go new file mode 100644 index 0000000000..25b9d9e1e1 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_auth.go @@ -0,0 +1,129 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "net/url" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +// AuthorizeExplicitGrantTypeHandler is a response handler for the Authorize Code grant using the explicit grant type +// as defined in https://tools.ietf.org/html/rfc6749#section-4.1 +type AuthorizeExplicitGrantHandler struct { + AccessTokenStrategy AccessTokenStrategy + RefreshTokenStrategy RefreshTokenStrategy + AuthorizeCodeStrategy AuthorizeCodeStrategy + CoreStorage CoreStorage + //TokenRevocationStorage TokenRevocationStorage + + // AuthCodeLifespan defines the lifetime of an authorize code. + AuthCodeLifespan time.Duration + + // AccessTokenLifespan defines the lifetime of an access token. + AccessTokenLifespan time.Duration + + // RefreshTokenLifespan defines the lifetime of a refresh token. Leave to 0 for unlimited lifetime. + RefreshTokenLifespan time.Duration + + ScopeStrategy fosite.ScopeStrategy + AudienceMatchingStrategy fosite.AudienceMatchingStrategy + + // SanitationWhiteList is a whitelist of form values that are required by the token endpoint. These values + // are safe for storage in a database (cleartext). + SanitationWhiteList []string + + TokenRevocationStorage TokenRevocationStorage + + IsRedirectURISecure func(*url.URL) bool + + RefreshTokenScopes []string +} + +func (c *AuthorizeExplicitGrantHandler) secureChecker() func(*url.URL) bool { + if c.IsRedirectURISecure == nil { + c.IsRedirectURISecure = fosite.IsRedirectURISecure + } + return c.IsRedirectURISecure +} + +func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + // This let's us define multiple response types, for example open id connect's id_token + if !ar.GetResponseTypes().ExactOne("code") { + return nil + } + + // Disabled because this is already handled at the authorize_request_handler + // if !ar.GetClient().GetResponseTypes().Has("code") { + // return errors.WithStack(fosite.ErrInvalidGrant) + // } + + if !c.secureChecker()(ar.GetRedirectURI()) { + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Redirect URL is using an insecure protocol, http is only allowed for hosts with suffix `localhost`, for example: http://myapp.localhost/.")) + } + + client := ar.GetClient() + for _, scope := range ar.GetRequestedScopes() { + if !c.ScopeStrategy(client.GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + } + + if err := c.AudienceMatchingStrategy(client.GetAudience(), ar.GetRequestedAudience()); err != nil { + return err + } + + return c.IssueAuthorizeCode(ctx, ar, resp) +} + +func (c *AuthorizeExplicitGrantHandler) IssueAuthorizeCode(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + code, signature, err := c.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthCodeLifespan)) + if err := c.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.GetSanitationWhiteList())); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + resp.AddQuery("code", code) + resp.AddQuery("state", ar.GetState()) + resp.AddQuery("scope", strings.Join(ar.GetGrantedScopes(), " ")) + ar.SetResponseTypeHandled("code") + return nil +} + +func (c *AuthorizeExplicitGrantHandler) GetSanitationWhiteList() []string { + if len(c.SanitationWhiteList) > 0 { + return c.SanitationWhiteList + } + return []string{ + "code", + "redirect_uri", + } +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_token.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_token.go new file mode 100644 index 0000000000..817da93cef --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_code_token.go @@ -0,0 +1,208 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "time" + + "github.com/ory/fosite/storage" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +// HandleTokenEndpointRequest implements +// * https://tools.ietf.org/html/rfc6749#section-4.1.3 (everything) +func (c *AuthorizeExplicitGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + // grant_type REQUIRED. + // Value MUST be set to "authorization_code". + if !request.GetGrantTypes().ExactOne("authorization_code") { + return errors.WithStack(errors.WithStack(fosite.ErrUnknownRequest)) + } + + if !request.GetClient().GetGrantTypes().Has("authorization_code") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\".")) + } + + code := request.GetRequestForm().Get("code") + signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code) + authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, request.GetSession()) + if errors.Cause(err) == fosite.ErrInvalidatedAuthorizeCode { + if authorizeRequest == nil { + return fosite.ErrServerError. + WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request."). + WithDebug("GetAuthorizeCodeSession must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".") + } + + //If an authorize code is used twice, we revoke all refresh and access tokens associated with this request. + reqID := authorizeRequest.GetID() + hint := "The authorization code has already been used." + debug := "" + if revErr := c.TokenRevocationStorage.RevokeAccessToken(ctx, reqID); revErr != nil { + hint += " Additionally, an error occurred during processing the access token revocation." + debug += "Revokation of access_token lead to error " + revErr.Error() + "." + } + if revErr := c.TokenRevocationStorage.RevokeRefreshToken(ctx, reqID); revErr != nil { + hint += " Additionally, an error occurred during processing the refresh token revocation." + debug += "Revokation of refresh_token lead to error " + revErr.Error() + "." + } + return errors.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug)) + } else if err != nil && errors.Cause(err).Error() == fosite.ErrNotFound.Error() { + return errors.WithStack(fosite.ErrInvalidGrant.WithDebug(err.Error())) + } else if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + // The authorization server MUST verify that the authorization code is valid + // This needs to happen after store retrieval for the session to be hydrated properly + if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, request, code); err != nil { + return errors.WithStack(fosite.ErrInvalidGrant.WithDebug(err.Error())) + } + + // Override scopes + request.SetRequestedScopes(authorizeRequest.GetRequestedScopes()) + + // Override audiences + request.SetRequestedAudience(authorizeRequest.GetRequestedAudience()) + + // The authorization server MUST ensure that the authorization code was issued to the authenticated + // confidential client, or if the client is public, ensure that the + // code was issued to "client_id" in the request, + if authorizeRequest.GetClient().GetID() != request.GetClient().GetID() { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request.")) + } + + // ensure that the "redirect_uri" parameter is present if the + // "redirect_uri" parameter was included in the initial authorization + // request as described in Section 4.1.1, and if included ensure that + // their values are identical. + forcedRedirectURI := authorizeRequest.GetRequestForm().Get("redirect_uri") + if forcedRedirectURI != "" && forcedRedirectURI != request.GetRequestForm().Get("redirect_uri") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request.")) + } + + // Checking of POST client_id skipped, because: + // If the client type is confidential or the client was issued client + // credentials (or assigned other authentication requirements), the + // client MUST authenticate with the authorization server as described + // in Section 3.2.1. + request.SetSession(authorizeRequest.GetSession()) + request.SetID(authorizeRequest.GetID()) + + request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second)) + if c.RefreshTokenLifespan > -1 { + request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second)) + } + + return nil +} + +func canIssueRefreshToken(c *AuthorizeExplicitGrantHandler, request fosite.Requester) bool { + // Require one of the refresh token scopes, if set. + if len(c.RefreshTokenScopes) > 0 && !request.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...) { + return false + } + // Do not issue a refresh token to clients that cannot use the refresh token grant type. + if !request.GetClient().GetGrantTypes().Has("refresh_token") { + return false + } + return true +} + +func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + // grant_type REQUIRED. + // Value MUST be set to "authorization_code", as this is the explicit grant handler. + if !requester.GetGrantTypes().ExactOne("authorization_code") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + code := requester.GetRequestForm().Get("code") + signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code) + authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, requester.GetSession()) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } else if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code); err != nil { + // This needs to happen after store retrieval for the session to be hydrated properly + return errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error())) + } + + for _, scope := range authorizeRequest.GetGrantedScopes() { + requester.GrantScope(scope) + } + + for _, audience := range authorizeRequest.GetGrantedAudience() { + requester.GrantAudience(audience) + } + + access, accessSignature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, requester) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + var refresh, refreshSignature string + if canIssueRefreshToken(c, authorizeRequest) { + refresh, refreshSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + } + + ctx, err = storage.MaybeBeginTx(ctx, c.CoreStorage) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + if err := c.CoreStorage.InvalidateAuthorizeCodeSession(ctx, signature); err != nil { + if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil { + err = rollBackTxnErr + } + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } else if err := c.CoreStorage.CreateAccessTokenSession(ctx, accessSignature, requester.Sanitize([]string{})); err != nil { + if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil { + err = rollBackTxnErr + } + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } else if refreshSignature != "" { + if err := c.CoreStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil { + if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil { + err = rollBackTxnErr + } + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + } + + responder.SetAccessToken(access) + responder.SetTokenType("bearer") + responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC())) + responder.SetScopes(requester.GetGrantedScopes()) + if refresh != "" { + responder.SetExtra("refresh_token", refresh) + } + + if err := storage.MaybeCommitTx(ctx, c.CoreStorage); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_implicit.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_implicit.go new file mode 100644 index 0000000000..9e91419391 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_authorize_implicit.go @@ -0,0 +1,106 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +// AuthorizeImplicitGrantTypeHandler is a response handler for the Authorize Code grant using the implicit grant type +// as defined in https://tools.ietf.org/html/rfc6749#section-4.2 +type AuthorizeImplicitGrantTypeHandler struct { + AccessTokenStrategy AccessTokenStrategy + + // AccessTokenStorage is used to persist session data across requests. + AccessTokenStorage AccessTokenStorage + + // AccessTokenLifespan defines the lifetime of an access token. + AccessTokenLifespan time.Duration + + ScopeStrategy fosite.ScopeStrategy + AudienceMatchingStrategy fosite.AudienceMatchingStrategy +} + +func (c *AuthorizeImplicitGrantTypeHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + // This let's us define multiple response types, for example open id connect's id_token + if !ar.GetResponseTypes().ExactOne("token") { + return nil + } + + // Disabled because this is already handled at the authorize_request_handler + // if !ar.GetClient().GetResponseTypes().Has("token") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use response type token")) + // } + + if !ar.GetClient().GetGrantTypes().Has("implicit") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"implicit\".")) + } + + client := ar.GetClient() + for _, scope := range ar.GetRequestedScopes() { + if !c.ScopeStrategy(client.GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + } + + if err := c.AudienceMatchingStrategy(client.GetAudience(), ar.GetRequestedAudience()); err != nil { + return err + } + + // there is no need to check for https, because implicit flow does not require https + // https://tools.ietf.org/html/rfc6819#section-4.4.2 + + return c.IssueImplicitAccessToken(ctx, ar, resp) +} + +func (c *AuthorizeImplicitGrantTypeHandler) IssueImplicitAccessToken(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + // Only override expiry if none is set. + if ar.GetSession().GetExpiresAt(fosite.AccessToken).IsZero() { + ar.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second)) + } + + // Generate the code + token, signature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, ar) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + if err := c.AccessTokenStorage.CreateAccessTokenSession(ctx, signature, ar.Sanitize([]string{})); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + resp.AddFragment("access_token", token) + resp.AddFragment("expires_in", strconv.FormatInt(int64(getExpiresIn(ar, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC())/time.Second), 10)) + resp.AddFragment("token_type", "bearer") + resp.AddFragment("state", ar.GetState()) + resp.AddFragment("scope", strings.Join(ar.GetGrantedScopes(), " ")) + ar.SetResponseTypeHandled("token") + + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials.go new file mode 100644 index 0000000000..307d1802ce --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials.go @@ -0,0 +1,81 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type ClientCredentialsGrantHandler struct { + *HandleHelper + ScopeStrategy fosite.ScopeStrategy + AudienceMatchingStrategy fosite.AudienceMatchingStrategy +} + +// IntrospectTokenEndpointRequest implements https://tools.ietf.org/html/rfc6749#section-4.4.2 +func (c *ClientCredentialsGrantHandler) HandleTokenEndpointRequest(_ context.Context, request fosite.AccessRequester) error { + // grant_type REQUIRED. + // Value MUST be set to "client_credentials". + if !request.GetGrantTypes().ExactOne("client_credentials") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + client := request.GetClient() + for _, scope := range request.GetRequestedScopes() { + if !c.ScopeStrategy(client.GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + } + + if err := c.AudienceMatchingStrategy(client.GetAudience(), request.GetRequestedAudience()); err != nil { + return err + } + + // The client MUST authenticate with the authorization server as described in Section 3.2.1. + // This requirement is already fulfilled because fosite requires all token requests to be authenticated as described + // in https://tools.ietf.org/html/rfc6749#section-3.2.1 + if client.IsPublic() { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is marked as public and is thus not allowed to use authorization grant \"client_credentials\".")) + } + // if the client is not public, he has already been authenticated by the access request handler. + + request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan)) + return nil +} + +// PopulateTokenEndpointResponse implements https://tools.ietf.org/html/rfc6749#section-4.4.3 +func (c *ClientCredentialsGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, request fosite.AccessRequester, response fosite.AccessResponder) error { + if !request.GetGrantTypes().ExactOne("client_credentials") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !request.GetClient().GetGrantTypes().Has("client_credentials") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"client_credentials\".")) + } + + return c.IssueAccessToken(ctx, request, response) +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials_storage.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials_storage.go new file mode 100644 index 0000000000..04f0d1eeec --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_client_credentials_storage.go @@ -0,0 +1,26 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +type ClientCredentialsGrantStorage interface { + AccessTokenStorage +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_refresh.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_refresh.go new file mode 100644 index 0000000000..760a910808 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_refresh.go @@ -0,0 +1,194 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/storage" +) + +type RefreshTokenGrantHandler struct { + AccessTokenStrategy AccessTokenStrategy + RefreshTokenStrategy RefreshTokenStrategy + TokenRevocationStorage TokenRevocationStorage + + // AccessTokenLifespan defines the lifetime of an access token. + AccessTokenLifespan time.Duration + + // RefreshTokenLifespan defines the lifetime of a refresh token. + RefreshTokenLifespan time.Duration + + ScopeStrategy fosite.ScopeStrategy + AudienceMatchingStrategy fosite.AudienceMatchingStrategy + RefreshTokenScopes []string +} + +// HandleTokenEndpointRequest implements https://tools.ietf.org/html/rfc6749#section-6 +func (c *RefreshTokenGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + // grant_type REQUIRED. + // Value MUST be set to "refresh_token". + if !request.GetGrantTypes().ExactOne("refresh_token") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !request.GetClient().GetGrantTypes().Has("refresh_token") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"refresh_token\".")) + } + + refresh := request.GetRequestForm().Get("refresh_token") + signature := c.RefreshTokenStrategy.RefreshTokenSignature(refresh) + originalRequest, err := c.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, request.GetSession()) + if errors.Cause(err) == fosite.ErrNotFound { + return errors.WithStack(fosite.ErrInvalidGrant.WithDebugf("The refresh token has not been found: %s", err)) + } else if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } else if err := c.RefreshTokenStrategy.ValidateRefreshToken(ctx, originalRequest, refresh); err != nil { + // The authorization server MUST ... validate the refresh token. + // This needs to happen after store retrieval for the session to be hydrated properly + return errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error())) + } + + if !(len(c.RefreshTokenScopes) == 0 || originalRequest.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...)) { + scopeNames := strings.Join(c.RefreshTokenScopes, " or ") + hint := fmt.Sprintf("The OAuth 2.0 Client was not granted scope %s and may thus not perform the \"refresh_token\" authorization grant.", scopeNames) + return errors.WithStack(fosite.ErrScopeNotGranted.WithHint(hint)) + + } + + // The authorization server MUST ... and ensure that the refresh token was issued to the authenticated client + if originalRequest.GetClient().GetID() != request.GetClient().GetID() { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the ID during the initial token issuance.")) + } + + request.SetSession(originalRequest.GetSession().Clone()) + request.SetRequestedScopes(originalRequest.GetRequestedScopes()) + request.SetRequestedAudience(originalRequest.GetRequestedAudience()) + + for _, scope := range originalRequest.GetGrantedScopes() { + if !c.ScopeStrategy(request.GetClient().GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + request.GrantScope(scope) + } + + if err := c.AudienceMatchingStrategy(request.GetClient().GetAudience(), originalRequest.GetGrantedAudience()); err != nil { + return err + } + + for _, audience := range originalRequest.GetGrantedAudience() { + request.GrantAudience(audience) + } + + request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second)) + if c.RefreshTokenLifespan > -1 { + request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second)) + } + + return nil +} + +// PopulateTokenEndpointResponse implements https://tools.ietf.org/html/rfc6749#section-6 +func (c *RefreshTokenGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !requester.GetGrantTypes().ExactOne("refresh_token") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + accessToken, accessSignature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, requester) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + refreshToken, refreshSignature, err := c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + signature := c.RefreshTokenStrategy.RefreshTokenSignature(requester.GetRequestForm().Get("refresh_token")) + + ctx, err = storage.MaybeBeginTx(ctx, c.TokenRevocationStorage) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + ts, err := c.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, nil) + if err != nil { + return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err) + } else if err := c.TokenRevocationStorage.RevokeAccessToken(ctx, ts.GetID()); err != nil { + return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err) + } else if err := c.TokenRevocationStorage.RevokeRefreshToken(ctx, ts.GetID()); err != nil { + return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err) + } + + storeReq := requester.Sanitize([]string{}) + storeReq.SetID(ts.GetID()) + + if err := c.TokenRevocationStorage.CreateAccessTokenSession(ctx, accessSignature, storeReq); err != nil { + return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err) + } + + if err := c.TokenRevocationStorage.CreateRefreshTokenSession(ctx, refreshSignature, storeReq); err != nil { + return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err) + } + + responder.SetAccessToken(accessToken) + responder.SetTokenType("bearer") + responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC())) + responder.SetScopes(requester.GetGrantedScopes()) + responder.SetExtra("refresh_token", refreshToken) + + if err := storage.MaybeCommitTx(ctx, c.TokenRevocationStorage); err != nil { + return handleRefreshTokenEndpointResponseStorageError(ctx, false, c.TokenRevocationStorage, err) + } + + return nil +} + +func handleRefreshTokenEndpointResponseStorageError(ctx context.Context, rollback bool, store TokenRevocationStorage, storageErr error) (err error) { + defer func() { + if rollback { + if rbErr := storage.MaybeRollbackTx(ctx, store); rbErr != nil { + err = errors.WithStack(fosite.ErrServerError.WithDebug(rbErr.Error())) + } + } + }() + + if errors.Cause(storageErr) == fosite.ErrSerializationFailure { + return errors.WithStack(fosite.ErrInvalidRequest. + WithDebugf(storageErr.Error()). + WithHint("Failed to refresh token because of multiple concurrent requests using the same token which is not allowed.")) + } + + if errors.Cause(storageErr) == fosite.ErrNotFound { + return errors.WithStack(fosite.ErrInvalidRequest. + WithDebugf(storageErr.Error()). + WithHint("Failed to refresh token because of multiple concurrent requests using the same token which is not allowed.")) + } + + return errors.WithStack(fosite.ErrServerError.WithDebug(storageErr.Error())) +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner.go new file mode 100644 index 0000000000..f07b125797 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner.go @@ -0,0 +1,115 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type ResourceOwnerPasswordCredentialsGrantHandler struct { + // ResourceOwnerPasswordCredentialsGrantStorage is used to persist session data across requests. + ResourceOwnerPasswordCredentialsGrantStorage ResourceOwnerPasswordCredentialsGrantStorage + + RefreshTokenStrategy RefreshTokenStrategy + ScopeStrategy fosite.ScopeStrategy + AudienceMatchingStrategy fosite.AudienceMatchingStrategy + RefreshTokenScopes []string + + *HandleHelper +} + +// HandleTokenEndpointRequest implements https://tools.ietf.org/html/rfc6749#section-4.3.2 +func (c *ResourceOwnerPasswordCredentialsGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + // grant_type REQUIRED. + // Value MUST be set to "password". + if !request.GetGrantTypes().ExactOne("password") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !request.GetClient().GetGrantTypes().Has("password") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The client is not allowed to use authorization grant \"password\".")) + } + + client := request.GetClient() + for _, scope := range request.GetRequestedScopes() { + if !c.ScopeStrategy(client.GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + } + + if err := c.AudienceMatchingStrategy(client.GetAudience(), request.GetRequestedAudience()); err != nil { + return err + } + + username := request.GetRequestForm().Get("username") + password := request.GetRequestForm().Get("password") + if username == "" || password == "" { + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Username or password are missing from the POST body.")) + } else if err := c.ResourceOwnerPasswordCredentialsGrantStorage.Authenticate(ctx, username, password); errors.Cause(err) == fosite.ErrNotFound { + return errors.WithStack(fosite.ErrRequestUnauthorized.WithHint("Unable to authenticate the provided username and password credentials.").WithDebug(err.Error())) + } else if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + // Credentials must not be passed around, potentially leaking to the database! + delete(request.GetRequestForm(), "password") + + request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second)) + if c.RefreshTokenLifespan > -1 { + request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second)) + } + + return nil +} + +// PopulateTokenEndpointResponse implements https://tools.ietf.org/html/rfc6749#section-4.3.3 +func (c *ResourceOwnerPasswordCredentialsGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !requester.GetGrantTypes().ExactOne("password") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + var refresh, refreshSignature string + if len(c.RefreshTokenScopes) == 0 || requester.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...) { + var err error + refresh, refreshSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } else if err := c.ResourceOwnerPasswordCredentialsGrantStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + } + + if err := c.IssueAccessToken(ctx, requester, responder); err != nil { + return err + } + + if refresh != "" { + responder.SetExtra("refresh_token", refresh) + } + + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner_storage.go b/vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner_storage.go new file mode 100644 index 0000000000..23916ac66f --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/flow_resource_owner_storage.go @@ -0,0 +1,32 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" +) + +type ResourceOwnerPasswordCredentialsGrantStorage interface { + Authenticate(ctx context.Context, name string, secret string) error + AccessTokenStorage + RefreshTokenStorage +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/helper.go b/vendor/github.com/ory/fosite/handler/oauth2/helper.go new file mode 100644 index 0000000000..be650584d5 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/helper.go @@ -0,0 +1,58 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "time" + + "github.com/ory/fosite" +) + +type HandleHelper struct { + AccessTokenStrategy AccessTokenStrategy + AccessTokenStorage AccessTokenStorage + AccessTokenLifespan time.Duration + RefreshTokenLifespan time.Duration +} + +func (h *HandleHelper) IssueAccessToken(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + token, signature, err := h.AccessTokenStrategy.GenerateAccessToken(ctx, requester) + if err != nil { + return err + } else if err := h.AccessTokenStorage.CreateAccessTokenSession(ctx, signature, requester.Sanitize([]string{})); err != nil { + return err + } + + responder.SetAccessToken(token) + responder.SetTokenType("bearer") + responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, h.AccessTokenLifespan, time.Now().UTC())) + responder.SetScopes(requester.GetGrantedScopes()) + return nil +} + +func getExpiresIn(r fosite.Requester, key fosite.TokenType, defaultLifespan time.Duration, now time.Time) time.Duration { + if r.GetSession().GetExpiresAt(key).IsZero() { + return defaultLifespan + } + return time.Duration(r.GetSession().GetExpiresAt(key).UnixNano() - now.UnixNano()) +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/introspector.go b/vendor/github.com/ory/fosite/handler/oauth2/introspector.go new file mode 100644 index 0000000000..3d91b4cbcb --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/introspector.go @@ -0,0 +1,114 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type CoreValidator struct { + CoreStrategy + CoreStorage + ScopeStrategy fosite.ScopeStrategy + DisableRefreshTokenValidation bool +} + +func (c *CoreValidator) IntrospectToken(ctx context.Context, token string, tokenType fosite.TokenType, accessRequest fosite.AccessRequester, scopes []string) (fosite.TokenType, error) { + if c.DisableRefreshTokenValidation { + if err := c.introspectAccessToken(ctx, token, accessRequest, scopes); err != nil { + return "", err + } + return fosite.AccessToken, nil + } + + var err error + switch tokenType { + case fosite.RefreshToken: + if err = c.introspectRefreshToken(ctx, token, accessRequest, scopes); err == nil { + return fosite.RefreshToken, nil + } else if err = c.introspectAccessToken(ctx, token, accessRequest, scopes); err == nil { + return fosite.AccessToken, nil + } + return "", err + } + + if err = c.introspectAccessToken(ctx, token, accessRequest, scopes); err == nil { + return fosite.AccessToken, nil + } else if err := c.introspectRefreshToken(ctx, token, accessRequest, scopes); err == nil { + return fosite.RefreshToken, nil + } + + return "", err +} + +func matchScopes(ss fosite.ScopeStrategy, granted, scopes []string) error { + for _, scope := range scopes { + if scope == "" { + continue + } + + if !ss(granted, scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The request scope \"%s\" has not been granted or is not allowed to be requested.", scope)) + } + } + + return nil +} + +func (c *CoreValidator) introspectAccessToken(ctx context.Context, token string, accessRequest fosite.AccessRequester, scopes []string) error { + sig := c.CoreStrategy.AccessTokenSignature(token) + or, err := c.CoreStorage.GetAccessTokenSession(ctx, sig, accessRequest.GetSession()) + if err != nil { + return errors.WithStack(fosite.ErrRequestUnauthorized.WithDebug(err.Error())) + } else if err := c.CoreStrategy.ValidateAccessToken(ctx, or, token); err != nil { + return err + } + + if err := matchScopes(c.ScopeStrategy, or.GetGrantedScopes(), scopes); err != nil { + return err + } + + accessRequest.Merge(or) + return nil +} + +func (c *CoreValidator) introspectRefreshToken(ctx context.Context, token string, accessRequest fosite.AccessRequester, scopes []string) error { + sig := c.CoreStrategy.RefreshTokenSignature(token) + or, err := c.CoreStorage.GetRefreshTokenSession(ctx, sig, accessRequest.GetSession()) + + if err != nil { + return errors.WithStack(fosite.ErrRequestUnauthorized.WithDebug(err.Error())) + } else if err := c.CoreStrategy.ValidateRefreshToken(ctx, or, token); err != nil { + return err + } + + if err := matchScopes(c.ScopeStrategy, or.GetGrantedScopes(), scopes); err != nil { + return err + } + + accessRequest.Merge(or) + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/introspector_jwt.go b/vendor/github.com/ory/fosite/handler/oauth2/introspector_jwt.go new file mode 100644 index 0000000000..e121fcb113 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/introspector_jwt.go @@ -0,0 +1,60 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type JWTAccessTokenStrategy interface { + AccessTokenStrategy + JWTStrategy +} + +type StatelessJWTValidator struct { + JWTAccessTokenStrategy + ScopeStrategy fosite.ScopeStrategy +} + +func (v *StatelessJWTValidator) IntrospectToken(ctx context.Context, token string, tokenType fosite.TokenType, accessRequest fosite.AccessRequester, scopes []string) (fosite.TokenType, error) { + or, err := v.JWTAccessTokenStrategy.ValidateJWT(ctx, fosite.AccessToken, token) + if err != nil { + return "", err + } + + for _, scope := range scopes { + if scope == "" { + continue + } + + if !v.ScopeStrategy(or.GetGrantedScopes(), scope) { + return "", errors.WithStack(fosite.ErrInvalidScope) + } + } + + accessRequest.Merge(or) + return "", nil +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/revocation.go b/vendor/github.com/ory/fosite/handler/oauth2/revocation.go new file mode 100644 index 0000000000..e97bd35506 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/revocation.go @@ -0,0 +1,77 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type TokenRevocationHandler struct { + TokenRevocationStorage TokenRevocationStorage + RefreshTokenStrategy RefreshTokenStrategy + AccessTokenStrategy AccessTokenStrategy +} + +// RevokeToken implements https://tools.ietf.org/html/rfc7009#section-2.1 +// The token type hint indicates which token type check should be performed first. +func (r *TokenRevocationHandler) RevokeToken(ctx context.Context, token string, tokenType fosite.TokenType, client fosite.Client) error { + discoveryFuncs := []func() (request fosite.Requester, err error){ + func() (request fosite.Requester, err error) { + // Refresh token + signature := r.RefreshTokenStrategy.RefreshTokenSignature(token) + return r.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, nil) + }, + func() (request fosite.Requester, err error) { + // Access token + signature := r.AccessTokenStrategy.AccessTokenSignature(token) + return r.TokenRevocationStorage.GetAccessTokenSession(ctx, signature, nil) + }, + } + + // Token type hinting + if tokenType == fosite.AccessToken { + discoveryFuncs[0], discoveryFuncs[1] = discoveryFuncs[1], discoveryFuncs[0] + } + + var ar fosite.Requester + var err error + if ar, err = discoveryFuncs[0](); err != nil { + ar, err = discoveryFuncs[1]() + } + if err != nil { + return err + } + + if ar.GetClient().GetID() != client.GetID() { + return errors.WithStack(fosite.ErrRevokationClientMismatch) + } + + requestID := ar.GetID() + r.TokenRevocationStorage.RevokeRefreshToken(ctx, requestID) + r.TokenRevocationStorage.RevokeAccessToken(ctx, requestID) + + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/revocation_storage.go b/vendor/github.com/ory/fosite/handler/oauth2/revocation_storage.go new file mode 100644 index 0000000000..48a5dba110 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/revocation_storage.go @@ -0,0 +1,49 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" +) + +// TokenRevocationStorage provides the storage implementation +// as specified in: https://tools.ietf.org/html/rfc7009 +type TokenRevocationStorage interface { + RefreshTokenStorage + AccessTokenStorage + + // RevokeRefreshToken revokes a refresh token as specified in: + // https://tools.ietf.org/html/rfc7009#section-2.1 + // If the particular + // token is a refresh token and the authorization server supports the + // revocation of access tokens, then the authorization server SHOULD + // also invalidate all access tokens based on the same authorization + // grant (see Implementation Note). + RevokeRefreshToken(ctx context.Context, requestID string) error + + // RevokeAccessToken revokes an access token as specified in: + // https://tools.ietf.org/html/rfc7009#section-2.1 + // If the token passed to the request + // is an access token, the server MAY revoke the respective refresh + // token as well. + RevokeAccessToken(ctx context.Context, requestID string) error +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/storage.go b/vendor/github.com/ory/fosite/handler/oauth2/storage.go new file mode 100644 index 0000000000..5502119931 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/storage.go @@ -0,0 +1,68 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + + "github.com/ory/fosite" +) + +type CoreStorage interface { + AuthorizeCodeStorage + AccessTokenStorage + RefreshTokenStorage +} + +// AuthorizeCodeStorage handles storage requests related to authorization codes. +type AuthorizeCodeStorage interface { + // GetAuthorizeCodeSession stores the authorization request for a given authorization code. + CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error) + + // GetAuthorizeCodeSession hydrates the session based on the given code and returns the authorization request. + // If the authorization code has been invalidated with `InvalidateAuthorizeCodeSession`, this + // method should return the ErrInvalidatedAuthorizeCode error. + // + // Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedAuthorizeCode error! + GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (request fosite.Requester, err error) + + // InvalidateAuthorizeCodeSession is called when an authorize code is being used. The state of the authorization + // code should be set to invalid and consecutive requests to GetAuthorizeCodeSession should return the + // ErrInvalidatedAuthorizeCode error. + InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error) +} + +type AccessTokenStorage interface { + CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error) + + GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) + + DeleteAccessTokenSession(ctx context.Context, signature string) (err error) +} + +type RefreshTokenStorage interface { + CreateRefreshTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error) + + GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) + + DeleteRefreshTokenSession(ctx context.Context, signature string) (err error) +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/strategy.go b/vendor/github.com/ory/fosite/handler/oauth2/strategy.go new file mode 100644 index 0000000000..ec091a3231 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/strategy.go @@ -0,0 +1,56 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + + "github.com/ory/fosite" +) + +type CoreStrategy interface { + AccessTokenStrategy + RefreshTokenStrategy + AuthorizeCodeStrategy +} + +type JWTStrategy interface { + ValidateJWT(ctx context.Context, tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) +} + +type AccessTokenStrategy interface { + AccessTokenSignature(token string) string + GenerateAccessToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) + ValidateAccessToken(ctx context.Context, requester fosite.Requester, token string) (err error) +} + +type RefreshTokenStrategy interface { + RefreshTokenSignature(token string) string + GenerateRefreshToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) + ValidateRefreshToken(ctx context.Context, requester fosite.Requester, token string) (err error) +} + +type AuthorizeCodeStrategy interface { + AuthorizeCodeSignature(token string) string + GenerateAuthorizeCode(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) + ValidateAuthorizeCode(ctx context.Context, requester fosite.Requester, token string) (err error) +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/strategy_hmacsha.go b/vendor/github.com/ory/fosite/handler/oauth2/strategy_hmacsha.go new file mode 100644 index 0000000000..16d962b663 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/strategy_hmacsha.go @@ -0,0 +1,96 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" + enigma "github.com/ory/fosite/token/hmac" +) + +type HMACSHAStrategy struct { + Enigma *enigma.HMACStrategy + AccessTokenLifespan time.Duration + RefreshTokenLifespan time.Duration + AuthorizeCodeLifespan time.Duration +} + +func (h HMACSHAStrategy) AccessTokenSignature(token string) string { + return h.Enigma.Signature(token) +} +func (h HMACSHAStrategy) RefreshTokenSignature(token string) string { + return h.Enigma.Signature(token) +} +func (h HMACSHAStrategy) AuthorizeCodeSignature(token string) string { + return h.Enigma.Signature(token) +} + +func (h HMACSHAStrategy) GenerateAccessToken(_ context.Context, _ fosite.Requester) (token string, signature string, err error) { + return h.Enigma.Generate() +} + +func (h HMACSHAStrategy) ValidateAccessToken(_ context.Context, r fosite.Requester, token string) (err error) { + var exp = r.GetSession().GetExpiresAt(fosite.AccessToken) + if exp.IsZero() && r.GetRequestedAt().Add(h.AccessTokenLifespan).Before(time.Now().UTC()) { + return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Access token expired at \"%s\".", r.GetRequestedAt().Add(h.AccessTokenLifespan))) + } + if !exp.IsZero() && exp.Before(time.Now().UTC()) { + return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Access token expired at \"%s\".", exp)) + } + return h.Enigma.Validate(token) +} + +func (h HMACSHAStrategy) GenerateRefreshToken(_ context.Context, _ fosite.Requester) (token string, signature string, err error) { + return h.Enigma.Generate() +} + +func (h HMACSHAStrategy) ValidateRefreshToken(_ context.Context, r fosite.Requester, token string) (err error) { + var exp = r.GetSession().GetExpiresAt(fosite.RefreshToken) + if exp.IsZero() { + // Unlimited lifetime + return h.Enigma.Validate(token) + } + if !exp.IsZero() && exp.Before(time.Now().UTC()) { + return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Refresh token expired at \"%s\".", exp)) + } + return h.Enigma.Validate(token) +} + +func (h HMACSHAStrategy) GenerateAuthorizeCode(_ context.Context, _ fosite.Requester) (token string, signature string, err error) { + return h.Enigma.Generate() +} + +func (h HMACSHAStrategy) ValidateAuthorizeCode(_ context.Context, r fosite.Requester, token string) (err error) { + var exp = r.GetSession().GetExpiresAt(fosite.AuthorizeCode) + if exp.IsZero() && r.GetRequestedAt().Add(h.AuthorizeCodeLifespan).Before(time.Now().UTC()) { + return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Authorize code expired at \"%s\".", r.GetRequestedAt().Add(h.AuthorizeCodeLifespan))) + } + if !exp.IsZero() && exp.Before(time.Now().UTC()) { + return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Authorize code expired at \"%s\".", exp)) + } + + return h.Enigma.Validate(token) +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt.go b/vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt.go new file mode 100644 index 0000000000..feb33d5ad3 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt.go @@ -0,0 +1,176 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "context" + "strings" + "time" + + jwtx "github.com/dgrijalva/jwt-go" + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/token/jwt" +) + +// DefaultJWTStrategy is a JWT RS256 strategy. +type DefaultJWTStrategy struct { + jwt.JWTStrategy + HMACSHAStrategy *HMACSHAStrategy + Issuer string +} + +func (h DefaultJWTStrategy) signature(token string) string { + split := strings.Split(token, ".") + if len(split) != 3 { + return "" + } + + return split[2] +} + +func (h DefaultJWTStrategy) AccessTokenSignature(token string) string { + return h.signature(token) +} + +func (h *DefaultJWTStrategy) GenerateAccessToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) { + return h.generate(ctx, fosite.AccessToken, requester) +} + +func (h *DefaultJWTStrategy) ValidateAccessToken(ctx context.Context, _ fosite.Requester, token string) error { + _, err := h.validate(ctx, token) + return err +} + +func (h *DefaultJWTStrategy) ValidateJWT(ctx context.Context, tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) { + t, err := h.validate(ctx, token) + if err != nil { + return nil, err + } + + claims := jwt.JWTClaims{} + claims.FromMapClaims(t.Claims.(jwtx.MapClaims)) + + requester = &fosite.Request{ + Client: &fosite.DefaultClient{}, + RequestedAt: claims.IssuedAt, + Session: &JWTSession{ + JWTClaims: &claims, + JWTHeader: &jwt.Headers{ + Extra: make(map[string]interface{}), + }, + ExpiresAt: map[fosite.TokenType]time.Time{ + tokenType: claims.ExpiresAt, + }, + Subject: claims.Subject, + }, + RequestedScope: claims.Scope, + GrantedScope: claims.Scope, + } + + return +} + +func (h DefaultJWTStrategy) RefreshTokenSignature(token string) string { + return h.HMACSHAStrategy.RefreshTokenSignature(token) +} + +func (h DefaultJWTStrategy) AuthorizeCodeSignature(token string) string { + return h.HMACSHAStrategy.AuthorizeCodeSignature(token) +} + +func (h *DefaultJWTStrategy) GenerateRefreshToken(ctx context.Context, req fosite.Requester) (token string, signature string, err error) { + return h.HMACSHAStrategy.GenerateRefreshToken(ctx, req) +} + +func (h *DefaultJWTStrategy) ValidateRefreshToken(ctx context.Context, req fosite.Requester, token string) error { + return h.HMACSHAStrategy.ValidateRefreshToken(ctx, req, token) +} + +func (h *DefaultJWTStrategy) GenerateAuthorizeCode(ctx context.Context, req fosite.Requester) (token string, signature string, err error) { + return h.HMACSHAStrategy.GenerateAuthorizeCode(ctx, req) +} + +func (h *DefaultJWTStrategy) ValidateAuthorizeCode(ctx context.Context, req fosite.Requester, token string) error { + return h.HMACSHAStrategy.ValidateAuthorizeCode(ctx, req, token) +} + +func (h *DefaultJWTStrategy) validate(ctx context.Context, token string) (t *jwtx.Token, err error) { + t, err = h.JWTStrategy.Decode(ctx, token) + + if err == nil { + err = t.Claims.Valid() + } + + if err != nil { + if e, ok := errors.Cause(err).(*jwtx.ValidationError); ok { + switch e.Errors { + case jwtx.ValidationErrorMalformed: + err = errors.WithStack(fosite.ErrInvalidTokenFormat.WithDebug(err.Error())) + case jwtx.ValidationErrorUnverifiable: + err = errors.WithStack(fosite.ErrTokenSignatureMismatch.WithDebug(err.Error())) + case jwtx.ValidationErrorSignatureInvalid: + err = errors.WithStack(fosite.ErrTokenSignatureMismatch.WithDebug(err.Error())) + case jwtx.ValidationErrorAudience: + err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error())) + case jwtx.ValidationErrorExpired: + err = errors.WithStack(fosite.ErrTokenExpired.WithDebug(err.Error())) + case jwtx.ValidationErrorIssuedAt: + err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error())) + case jwtx.ValidationErrorIssuer: + err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error())) + case jwtx.ValidationErrorNotValidYet: + err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error())) + case jwtx.ValidationErrorId: + err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error())) + case jwtx.ValidationErrorClaimsInvalid: + err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error())) + default: + err = errors.WithStack(fosite.ErrRequestUnauthorized.WithDebug(err.Error())) + } + } + } + + return +} + +func (h *DefaultJWTStrategy) generate(ctx context.Context, tokenType fosite.TokenType, requester fosite.Requester) (string, string, error) { + if jwtSession, ok := requester.GetSession().(JWTSessionContainer); !ok { + return "", "", errors.Errorf("Session must be of type JWTSessionContainer but got type: %T", requester.GetSession()) + } else if jwtSession.GetJWTClaims() == nil { + return "", "", errors.New("GetTokenClaims() must not be nil") + } else { + claims := jwtSession.GetJWTClaims(). + With( + jwtSession.GetExpiresAt(tokenType), + requester.GetGrantedScopes(), + requester.GetGrantedAudience(), + ). + WithDefaults( + time.Now().UTC(), + h.Issuer, + ) + + return h.JWTStrategy.Generate(ctx, claims.ToMapClaims(), jwtSession.GetJWTHeader()) + } +} diff --git a/vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt_session.go b/vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt_session.go new file mode 100644 index 0000000000..a2bbd454ac --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/oauth2/strategy_jwt_session.go @@ -0,0 +1,105 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package oauth2 + +import ( + "time" + + "github.com/mohae/deepcopy" + + "github.com/ory/fosite" + "github.com/ory/fosite/token/jwt" +) + +type JWTSessionContainer interface { + // GetJWTClaims returns the claims. + GetJWTClaims() jwt.JWTClaimsContainer + + // GetJWTHeader returns the header. + GetJWTHeader() *jwt.Headers + + fosite.Session +} + +// JWTSession Container for the JWT session. +type JWTSession struct { + JWTClaims *jwt.JWTClaims + JWTHeader *jwt.Headers + ExpiresAt map[fosite.TokenType]time.Time + Username string + Subject string +} + +func (j *JWTSession) GetJWTClaims() jwt.JWTClaimsContainer { + if j.JWTClaims == nil { + j.JWTClaims = &jwt.JWTClaims{} + } + return j.JWTClaims +} + +func (j *JWTSession) GetJWTHeader() *jwt.Headers { + if j.JWTHeader == nil { + j.JWTHeader = &jwt.Headers{} + } + return j.JWTHeader +} + +func (s *JWTSession) SetExpiresAt(key fosite.TokenType, exp time.Time) { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[fosite.TokenType]time.Time) + } + s.ExpiresAt[key] = exp +} + +func (s *JWTSession) GetExpiresAt(key fosite.TokenType) time.Time { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[fosite.TokenType]time.Time) + } + + if _, ok := s.ExpiresAt[key]; !ok { + return time.Time{} + } + return s.ExpiresAt[key] +} + +func (s *JWTSession) GetUsername() string { + if s == nil { + return "" + } + return s.Username +} + +func (s *JWTSession) GetSubject() string { + if s == nil { + return "" + } + + return s.Subject +} + +func (s *JWTSession) Clone() fosite.Session { + if s == nil { + return nil + } + + return deepcopy.Copy(s).(fosite.Session) +} diff --git a/vendor/github.com/ory/fosite/handler/openid/errors.go b/vendor/github.com/ory/fosite/handler/openid/errors.go new file mode 100644 index 0000000000..426b28db7a --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/errors.go @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import "github.com/pkg/errors" + +var ( + ErrInvalidSession = errors.New("Session type mismatch") +) diff --git a/vendor/github.com/ory/fosite/handler/openid/flow_explicit_auth.go b/vendor/github.com/ory/fosite/handler/openid/flow_explicit_auth.go new file mode 100644 index 0000000000..8a3e8a1e40 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/flow_explicit_auth.go @@ -0,0 +1,72 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type OpenIDConnectExplicitHandler struct { + // OpenIDConnectRequestStorage is the storage for open id connect sessions. + OpenIDConnectRequestStorage OpenIDConnectRequestStorage + OpenIDConnectRequestValidator *OpenIDConnectRequestValidator + + *IDTokenHandleHelper +} + +var oidcParameters = []string{"grant_type", + "max_age", + "prompt", + "acr_values", + "id_token_hint", + "nonce", +} + +func (c *OpenIDConnectExplicitHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + if !(ar.GetGrantedScopes().Has("openid") && ar.GetResponseTypes().ExactOne("code")) { + return nil + } + + //if !ar.GetClient().GetResponseTypes().Has("id_token", "code") { + // return errors.WithStack(fosite.ErrInvalidRequest.WithDebug("The client is not allowed to use response type id_token and code")) + //} + + if len(resp.GetCode()) == 0 { + return errors.WithStack(fosite.ErrMisconfiguration.WithDebug("The authorization code has not been issued yet, indicating a broken code configuration.")) + } + + if err := c.OpenIDConnectRequestValidator.ValidatePrompt(ctx, ar); err != nil { + return err + } + + if err := c.OpenIDConnectRequestStorage.CreateOpenIDConnectSession(ctx, resp.GetCode(), ar.Sanitize(oidcParameters)); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + // there is no need to check for https, because it has already been checked by core.explicit + + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/openid/flow_explicit_token.go b/vendor/github.com/ory/fosite/handler/openid/flow_explicit_token.go new file mode 100644 index 0000000000..eb7adf1ae2 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/flow_explicit_token.go @@ -0,0 +1,76 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +func (c *OpenIDConnectExplicitHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + return errors.WithStack(fosite.ErrUnknownRequest) +} + +func (c *OpenIDConnectExplicitHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !requester.GetGrantTypes().ExactOne("authorization_code") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + authorize, err := c.OpenIDConnectRequestStorage.GetOpenIDConnectSession(ctx, requester.GetRequestForm().Get("code"), requester) + if errors.Cause(err) == ErrNoSessionFound { + return errors.WithStack(fosite.ErrUnknownRequest.WithDebug(err.Error())) + } else if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + if !authorize.GetGrantedScopes().Has("openid") { + return errors.WithStack(fosite.ErrMisconfiguration.WithDebug("An OpenID Connect session was found but the openid scope is missing, probably due to a broken code configuration.")) + } + + if !requester.GetClient().GetGrantTypes().Has("authorization_code") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"authorization_code\".")) + } + + sess, ok := requester.GetSession().(Session) + if !ok { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because session must be of type fosite/handler/openid.Session.")) + } + + claims := sess.IDTokenClaims() + if claims.Subject == "" { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because subject is an empty string.")) + } + + claims.AccessTokenHash = c.GetAccessTokenHash(ctx, requester, responder) + + // The response type `id_token` is only required when performing the implicit or hybrid flow, see: + // https://openid.net/specs/openid-connect-registration-1_0.html + // + // if !requester.GetClient().GetResponseTypes().Has("id_token") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use response type id_token")) + // } + + return c.IssueExplicitIDToken(ctx, authorize, responder) +} diff --git a/vendor/github.com/ory/fosite/handler/openid/flow_hybrid.go b/vendor/github.com/ory/fosite/handler/openid/flow_hybrid.go new file mode 100644 index 0000000000..765542054b --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/flow_hybrid.go @@ -0,0 +1,159 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + "encoding/base64" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/token/jwt" +) + +type OpenIDConnectHybridHandler struct { + AuthorizeImplicitGrantTypeHandler *oauth2.AuthorizeImplicitGrantTypeHandler + AuthorizeExplicitGrantHandler *oauth2.AuthorizeExplicitGrantHandler + IDTokenHandleHelper *IDTokenHandleHelper + ScopeStrategy fosite.ScopeStrategy + OpenIDConnectRequestValidator *OpenIDConnectRequestValidator + OpenIDConnectRequestStorage OpenIDConnectRequestStorage + + Enigma *jwt.RS256JWTStrategy +} + +func (c *OpenIDConnectHybridHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + if len(ar.GetResponseTypes()) < 2 { + return nil + } + + if !(ar.GetResponseTypes().Matches("token", "id_token", "code") || ar.GetResponseTypes().Matches("token", "code") || ar.GetResponseTypes().Matches("id_token", "code")) { + return nil + } + + // Disabled because this is already handled at the authorize_request_handler + //if ar.GetResponseTypes().Matches("token") && !ar.GetClient().GetResponseTypes().Has("token") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use the token response type")) + //} else if ar.GetResponseTypes().Matches("code") && !ar.GetClient().GetResponseTypes().Has("code") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use the code response type")) + //} else if ar.GetResponseTypes().Matches("id_token") && !ar.GetClient().GetResponseTypes().Has("id_token") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use the id_token response type")) + //} + + if nonce := ar.GetRequestForm().Get("nonce"); len(nonce) == 0 { + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Parameter \"nonce\" must be set when using the OpenID Connect Hybrid Flow.")) + } else if len(nonce) < fosite.MinParameterEntropy { + return errors.WithStack(fosite.ErrInsufficientEntropy.WithHintf("Parameter \"nonce\" is set but does not satisfy the minimum entropy of %d characters.", fosite.MinParameterEntropy)) + } + + sess, ok := ar.GetSession().(Session) + if !ok { + return errors.WithStack(ErrInvalidSession) + } + + if err := c.OpenIDConnectRequestValidator.ValidatePrompt(ctx, ar); err != nil { + return err + } + + client := ar.GetClient() + for _, scope := range ar.GetRequestedScopes() { + if !c.ScopeStrategy(client.GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + } + + claims := sess.IDTokenClaims() + if ar.GetResponseTypes().Has("code") { + if !ar.GetClient().GetGrantTypes().Has("authorization_code") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\".")) + } + + code, signature, err := c.AuthorizeExplicitGrantHandler.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar) + if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + // This is not required because the auth code flow is being handled by oauth2/flow_authorize_code_token which in turn + // sets the proper access/refresh token lifetimes. + // + // if c.AuthorizeExplicitGrantHandler.RefreshTokenLifespan > -1 { + // ar.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.AuthorizeExplicitGrantHandler.RefreshTokenLifespan).Round(time.Second)) + // } + + // This is required because we must limit the authorize code lifespan. + ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthorizeExplicitGrantHandler.AuthCodeLifespan).Round(time.Second)) + if err := c.AuthorizeExplicitGrantHandler.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.AuthorizeExplicitGrantHandler.GetSanitationWhiteList())); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + resp.AddFragment("code", code) + ar.SetResponseTypeHandled("code") + + hash, err := c.Enigma.Hash(ctx, []byte(resp.GetFragment().Get("code"))) + if err != nil { + return err + } + claims.CodeHash = base64.RawURLEncoding.EncodeToString([]byte(hash[:c.Enigma.GetSigningMethodLength()/2])) + + if ar.GetGrantedScopes().Has("openid") { + if err := c.OpenIDConnectRequestStorage.CreateOpenIDConnectSession(ctx, resp.GetCode(), ar.Sanitize(oidcParameters)); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + } + } + + if ar.GetResponseTypes().Has("token") { + if !ar.GetClient().GetGrantTypes().Has("implicit") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"implicit\".")) + } else if err := c.AuthorizeImplicitGrantTypeHandler.IssueImplicitAccessToken(ctx, ar, resp); err != nil { + return errors.WithStack(err) + } + ar.SetResponseTypeHandled("token") + + hash, err := c.Enigma.Hash(ctx, []byte(resp.GetFragment().Get("access_token"))) + if err != nil { + return err + } + claims.AccessTokenHash = base64.RawURLEncoding.EncodeToString([]byte(hash[:c.Enigma.GetSigningMethodLength()/2])) + } + + if resp.GetFragment().Get("state") == "" { + resp.AddFragment("state", ar.GetState()) + } + + if !ar.GetGrantedScopes().Has("openid") || !ar.GetResponseTypes().Has("id_token") { + ar.SetResponseTypeHandled("id_token") + return nil + } + + if err := c.IDTokenHandleHelper.IssueImplicitIDToken(ctx, ar, resp); err != nil { + return errors.WithStack(err) + } + + ar.SetResponseTypeHandled("id_token") + return nil + // there is no need to check for https, because implicit flow does not require https + // https://tools.ietf.org/html/rfc6819#section-4.4.2 +} diff --git a/vendor/github.com/ory/fosite/handler/openid/flow_implicit.go b/vendor/github.com/ory/fosite/handler/openid/flow_implicit.go new file mode 100644 index 0000000000..d9227be0ab --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/flow_implicit.go @@ -0,0 +1,111 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + "encoding/base64" + + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/token/jwt" +) + +type OpenIDConnectImplicitHandler struct { + AuthorizeImplicitGrantTypeHandler *oauth2.AuthorizeImplicitGrantTypeHandler + *IDTokenHandleHelper + ScopeStrategy fosite.ScopeStrategy + OpenIDConnectRequestValidator *OpenIDConnectRequestValidator + + RS256JWTStrategy *jwt.RS256JWTStrategy +} + +func (c *OpenIDConnectImplicitHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + if !(ar.GetGrantedScopes().Has("openid") && (ar.GetResponseTypes().Has("token", "id_token") || ar.GetResponseTypes().ExactOne("id_token"))) { + return nil + } else if ar.GetResponseTypes().Has("code") { + // hybrid flow + return nil + } + + if !ar.GetClient().GetGrantTypes().Has("implicit") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"implicit\".")) + } + + // Disabled because this is already handled at the authorize_request_handler + //if ar.GetResponseTypes().ExactOne("id_token") && !ar.GetClient().GetResponseTypes().Has("id_token") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use response type id_token")) + //} else if ar.GetResponseTypes().Matches("token", "id_token") && !ar.GetClient().GetResponseTypes().Has("token", "id_token") { + // return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use response type token and id_token")) + //} + + if nonce := ar.GetRequestForm().Get("nonce"); len(nonce) == 0 { + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Parameter \"nonce\" must be set when using the OpenID Connect Hybrid Flow.")) + } else if len(nonce) < fosite.MinParameterEntropy { + return errors.WithStack(fosite.ErrInsufficientEntropy.WithHintf("Parameter \"nonce\" is set but does not satisfy the minimum entropy of %d characters.", fosite.MinParameterEntropy)) + } + + client := ar.GetClient() + for _, scope := range ar.GetRequestedScopes() { + if !c.ScopeStrategy(client.GetScopes(), scope) { + return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope)) + } + } + + sess, ok := ar.GetSession().(Session) + if !ok { + return errors.WithStack(ErrInvalidSession) + } + + if err := c.OpenIDConnectRequestValidator.ValidatePrompt(ctx, ar); err != nil { + return err + } + + claims := sess.IDTokenClaims() + if ar.GetResponseTypes().Has("token") { + if err := c.AuthorizeImplicitGrantTypeHandler.IssueImplicitAccessToken(ctx, ar, resp); err != nil { + return errors.WithStack(err) + } + + ar.SetResponseTypeHandled("token") + hash, err := c.RS256JWTStrategy.Hash(ctx, []byte(resp.GetFragment().Get("access_token"))) + if err != nil { + return err + } + + claims.AccessTokenHash = base64.RawURLEncoding.EncodeToString([]byte(hash[:c.RS256JWTStrategy.GetSigningMethodLength()/2])) + } else { + resp.AddFragment("state", ar.GetState()) + } + + if err := c.IssueImplicitIDToken(ctx, ar, resp); err != nil { + return errors.WithStack(err) + } + + // there is no need to check for https, because implicit flow does not require https + // https://tools.ietf.org/html/rfc6819#section-4.4.2 + + ar.SetResponseTypeHandled("id_token") + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/openid/flow_refresh_token.go b/vendor/github.com/ory/fosite/handler/openid/flow_refresh_token.go new file mode 100644 index 0000000000..98b65c4a3c --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/flow_refresh_token.go @@ -0,0 +1,101 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type OpenIDConnectRefreshHandler struct { + *IDTokenHandleHelper +} + +func (c *OpenIDConnectRefreshHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + if !request.GetGrantTypes().ExactOne("refresh_token") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !request.GetGrantedScopes().Has("openid") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !request.GetClient().GetGrantTypes().Has("refresh_token") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"refresh_token\".")) + } + + // Refresh tokens can only be issued by an authorize_code which in turn disables the need to check if the id_token + // response type is enabled by the client. + // + // if !request.GetClient().GetResponseTypes().Has("id_token") { + // return errors.WithStack(fosite.ErrUnknownRequest.WithDebug("The client is not allowed to use response type id_token")) + // } + + sess, ok := request.GetSession().(Session) + if !ok { + return errors.New("Failed to generate id token because session must be of type fosite/handler/openid.Session") + } + + // We need to reset the expires at value + sess.IDTokenClaims().ExpiresAt = time.Time{} + sess.IDTokenClaims().Nonce = "" + return nil +} + +func (c *OpenIDConnectRefreshHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + if !requester.GetGrantTypes().ExactOne("refresh_token") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !requester.GetGrantedScopes().Has("openid") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + if !requester.GetClient().GetGrantTypes().Has("refresh_token") { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"refresh_token\".")) + } + + // Disabled because this is already handled at the authorize_request_handler + // if !requester.GetClient().GetResponseTypes().Has("id_token") { + // return errors.WithStack(fosite.ErrUnknownRequest.WithDebug("The client is not allowed to use response type id_token")) + // } + + sess, ok := requester.GetSession().(Session) + if !ok { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because session must be of type fosite/handler/openid.Session.")) + } + + claims := sess.IDTokenClaims() + if claims.Subject == "" { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because subject is an empty string.")) + } + + hash := c.GetAccessTokenHash(ctx, requester, responder) + + claims.AccessTokenHash = hash + + return c.IssueExplicitIDToken(ctx, requester, responder) +} diff --git a/vendor/github.com/ory/fosite/handler/openid/helper.go b/vendor/github.com/ory/fosite/handler/openid/helper.go new file mode 100644 index 0000000000..a935761224 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/helper.go @@ -0,0 +1,76 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/base64" + + "github.com/ory/fosite" +) + +type IDTokenHandleHelper struct { + IDTokenStrategy OpenIDConnectTokenStrategy +} + +func (i *IDTokenHandleHelper) GetAccessTokenHash(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) string { + token := responder.GetAccessToken() + + buffer := bytes.NewBufferString(token) + hash := sha256.New() + hash.Write(buffer.Bytes()) + hashBuf := bytes.NewBuffer(hash.Sum([]byte{})) + len := hashBuf.Len() + + return base64.RawURLEncoding.EncodeToString(hashBuf.Bytes()[:len/2]) +} + +func (i *IDTokenHandleHelper) generateIDToken(ctx context.Context, fosr fosite.Requester) (token string, err error) { + token, err = i.IDTokenStrategy.GenerateIDToken(ctx, fosr) + if err != nil { + return "", err + } + + return token, nil +} + +func (i *IDTokenHandleHelper) IssueImplicitIDToken(ctx context.Context, ar fosite.Requester, resp fosite.AuthorizeResponder) error { + token, err := i.generateIDToken(ctx, ar) + if err != nil { + return err + } + + resp.AddFragment("id_token", token) + return nil +} + +func (i *IDTokenHandleHelper) IssueExplicitIDToken(ctx context.Context, ar fosite.Requester, resp fosite.AccessResponder) error { + token, err := i.generateIDToken(ctx, ar) + if err != nil { + return err + } + + resp.SetExtra("id_token", token) + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/openid/storage.go b/vendor/github.com/ory/fosite/handler/openid/storage.go new file mode 100644 index 0000000000..6f912f697f --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/storage.go @@ -0,0 +1,45 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + + "github.com/ory/fosite" +) + +var ErrNoSessionFound = fosite.ErrNotFound + +type OpenIDConnectRequestStorage interface { + // CreateOpenIDConnectSession creates an open id connect session + // for a given authorize code. This is relevant for explicit open id connect flow. + CreateOpenIDConnectSession(ctx context.Context, authorizeCode string, requester fosite.Requester) error + + // IsOpenIDConnectSession returns error + // - nil if a session was found, + // - ErrNoSessionFound if no session was found + // - or an arbitrary error if an error occurred. + GetOpenIDConnectSession(ctx context.Context, authorizeCode string, requester fosite.Requester) (fosite.Requester, error) + + // DeleteOpenIDConnectSession removes an open id connect session from the store. + DeleteOpenIDConnectSession(ctx context.Context, authorizeCode string) error +} diff --git a/vendor/github.com/ory/fosite/handler/openid/strategy.go b/vendor/github.com/ory/fosite/handler/openid/strategy.go new file mode 100644 index 0000000000..92a81caa0d --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/strategy.go @@ -0,0 +1,32 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + + "github.com/ory/fosite" +) + +type OpenIDConnectTokenStrategy interface { + GenerateIDToken(ctx context.Context, requester fosite.Requester) (token string, err error) +} diff --git a/vendor/github.com/ory/fosite/handler/openid/strategy_jwt.go b/vendor/github.com/ory/fosite/handler/openid/strategy_jwt.go new file mode 100644 index 0000000000..b34be6f80c --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/strategy_jwt.go @@ -0,0 +1,236 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + "fmt" + "strconv" + "time" + + jwtgo "github.com/dgrijalva/jwt-go" + "github.com/mohae/deepcopy" + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/token/jwt" + "github.com/ory/go-convenience/stringslice" +) + +const defaultExpiryTime = time.Hour + +type Session interface { + IDTokenClaims() *jwt.IDTokenClaims + IDTokenHeaders() *jwt.Headers + + fosite.Session +} + +// IDTokenSession is a session container for the id token +type DefaultSession struct { + Claims *jwt.IDTokenClaims + Headers *jwt.Headers + ExpiresAt map[fosite.TokenType]time.Time + Username string + Subject string +} + +func NewDefaultSession() *DefaultSession { + return &DefaultSession{ + Claims: &jwt.IDTokenClaims{ + RequestedAt: time.Now().UTC(), + }, + Headers: &jwt.Headers{}, + } +} + +func (s *DefaultSession) Clone() fosite.Session { + if s == nil { + return nil + } + + return deepcopy.Copy(s).(fosite.Session) +} + +func (s *DefaultSession) SetExpiresAt(key fosite.TokenType, exp time.Time) { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[fosite.TokenType]time.Time) + } + s.ExpiresAt[key] = exp +} + +func (s *DefaultSession) GetExpiresAt(key fosite.TokenType) time.Time { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[fosite.TokenType]time.Time) + } + + if _, ok := s.ExpiresAt[key]; !ok { + return time.Time{} + } + return s.ExpiresAt[key] +} + +func (s *DefaultSession) GetUsername() string { + if s == nil { + return "" + } + return s.Username +} + +func (s *DefaultSession) GetSubject() string { + if s == nil { + return "" + } + + return s.Subject +} + +func (s *DefaultSession) IDTokenHeaders() *jwt.Headers { + if s.Headers == nil { + s.Headers = &jwt.Headers{} + } + return s.Headers +} + +func (s *DefaultSession) IDTokenClaims() *jwt.IDTokenClaims { + if s.Claims == nil { + s.Claims = &jwt.IDTokenClaims{} + } + return s.Claims +} + +type DefaultStrategy struct { + jwt.JWTStrategy + + Expiry time.Duration + Issuer string +} + +func (h DefaultStrategy) GenerateIDToken(ctx context.Context, requester fosite.Requester) (token string, err error) { + if h.Expiry == 0 { + h.Expiry = defaultExpiryTime + } + + sess, ok := requester.GetSession().(Session) + if !ok { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because session must be of type fosite/handler/openid.Session.")) + } + + claims := sess.IDTokenClaims() + if claims.Subject == "" { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because subject is an empty string.")) + } + + if requester.GetRequestForm().Get("grant_type") != "refresh_token" { + maxAge, err := strconv.ParseInt(requester.GetRequestForm().Get("max_age"), 10, 64) + if err != nil { + maxAge = 0 + } + + // Adds a bit of wiggle room for timing issues + if claims.AuthTime.After(time.Now().UTC().Add(time.Second * 5)) { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because authentication time is in the future.")) + } + + if maxAge > 0 { + if claims.AuthTime.IsZero() { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because authentication time claim is required when max_age is set.")) + } else if claims.RequestedAt.IsZero() { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because requested at claim is required when max_age is set.")) + } else if claims.AuthTime.Add(time.Second * time.Duration(maxAge)).Before(claims.RequestedAt) { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because authentication time does not satisfy max_age time.")) + } + } + + prompt := requester.GetRequestForm().Get("prompt") + if prompt != "" { + if claims.AuthTime.IsZero() { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Unable to determine validity of prompt parameter because auth_time is missing in id token claims.")) + } + } + + switch prompt { + case "none": + if claims.AuthTime.After(claims.RequestedAt) { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because prompt was set to \"none\" but auth_time happened after the authorization request was registered, indicating that the user was logged in during this request which is not allowed.")) + } + case "login": + if claims.AuthTime.Before(claims.RequestedAt) { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because prompt was set to \"login\" but auth_time happened before the authorization request was registered, indicating that the user was not re-authenticated which is forbidden.")) + } + } + + // If acr_values was requested but no acr value was provided in the ID token, fall back to level 0 which means least + // confidence in authentication. + if requester.GetRequestForm().Get("acr_values") != "" && claims.AuthenticationContextClassReference == "" { + claims.AuthenticationContextClassReference = "0" + } + + if tokenHintString := requester.GetRequestForm().Get("id_token_hint"); tokenHintString != "" { + tokenHint, err := h.JWTStrategy.Decode(ctx, tokenHintString) + if ve, ok := errors.Cause(err).(*jwtgo.ValidationError); ok && ve.Errors == jwtgo.ValidationErrorExpired { + // Expired ID Tokens are allowed as values to id_token_hint + } else if err != nil { + return "", errors.WithStack(fosite.ErrServerError.WithDebug(fmt.Sprintf("Unable to decode id token from id_token_hint parameter because %s.", err.Error()))) + } + + if hintClaims, ok := tokenHint.Claims.(jwtgo.MapClaims); !ok { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Unable to decode id token from id_token_hint to *jwt.StandardClaims.")) + } else if hintSub, _ := hintClaims["sub"].(string); hintSub == "" { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Provided id token from id_token_hint does not have a subject.")) + } else if hintSub != claims.Subject { + return "", errors.WithStack(fosite.ErrServerError.WithDebug(fmt.Sprintf("Subject from authorization mismatches id token subject from id_token_hint."))) + } + } + } + + if claims.ExpiresAt.IsZero() { + claims.ExpiresAt = time.Now().UTC().Add(h.Expiry) + } + + if claims.ExpiresAt.Before(time.Now().UTC()) { + return "", errors.WithStack(fosite.ErrServerError.WithDebug("Failed to generate id token because expiry claim can not be in the past.")) + } + + if claims.AuthTime.IsZero() { + claims.AuthTime = time.Now().UTC() + } + + if claims.Issuer == "" { + claims.Issuer = h.Issuer + } + + nonce := requester.GetRequestForm().Get("nonce") + // OPTIONAL. String value used to associate a Client session with an ID Token, and to mitigate replay attacks. + if len(nonce) == 0 { + } else if len(nonce) > 0 && len(nonce) < fosite.MinParameterEntropy { + // We're assuming that using less then 8 characters for the state can not be considered "unguessable" + return "", errors.WithStack(fosite.ErrInsufficientEntropy.WithHintf("Parameter \"nonce\" is set but does not satisfy the minimum entropy of %d characters.", fosite.MinParameterEntropy)) + } + + claims.Nonce = nonce + claims.Audience = stringslice.Unique(append(claims.Audience, requester.GetClient().GetID())) + claims.IssuedAt = time.Now().UTC() + + token, _, err = h.JWTStrategy.Generate(ctx, claims.ToMapClaims(), sess.IDTokenHeaders()) + return token, err +} diff --git a/vendor/github.com/ory/fosite/handler/openid/validator.go b/vendor/github.com/ory/fosite/handler/openid/validator.go new file mode 100644 index 0000000000..837999df05 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/openid/validator.go @@ -0,0 +1,168 @@ +/* + * Copyright © 2017-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @Copyright 2017-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package openid + +import ( + "context" + "strconv" + "time" + + jwtgo "github.com/dgrijalva/jwt-go" + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/token/jwt" + "github.com/ory/go-convenience/stringslice" + "github.com/ory/go-convenience/stringsx" +) + +type OpenIDConnectRequestValidator struct { + AllowedPrompt []string + Strategy jwt.JWTStrategy +} + +func NewOpenIDConnectRequestValidator(prompt []string, strategy jwt.JWTStrategy) *OpenIDConnectRequestValidator { + if len(prompt) == 0 { + prompt = []string{"login", "none", "consent", "select_account"} + } + + return &OpenIDConnectRequestValidator{ + AllowedPrompt: prompt, + Strategy: strategy, + } +} + +func (v *OpenIDConnectRequestValidator) ValidatePrompt(ctx context.Context, req fosite.AuthorizeRequester) error { + // prompt is case sensitive! + prompt := stringsx.Splitx(req.GetRequestForm().Get("prompt"), " ") + + if req.GetClient().IsPublic() { + // Threat: Malicious Client Obtains Existing Authorization by Fraud + // https://tools.ietf.org/html/rfc6819#section-4.2.3 + // + // Authorization servers should not automatically process repeat + // authorizations to public clients unless the client is validated + // using a pre-registered redirect URI + + // Client Impersonation + // https://tools.ietf.org/html/rfc8252#section-8.6# + // + // As stated in Section 10.2 of OAuth 2.0 [RFC6749], the authorization + // server SHOULD NOT process authorization requests automatically + // without user consent or interaction, except when the identity of the + // client can be assured. This includes the case where the user has + // previously approved an authorization request for a given client id -- + // unless the identity of the client can be proven, the request SHOULD + // be processed as if no previous request had been approved. + + if stringslice.Has(prompt, "none") { + if !(req.GetRedirectURI().Scheme == "https" || (fosite.IsLocalhost(req.GetRedirectURI()) && req.GetRedirectURI().Scheme == "http")) { + return errors.WithStack(fosite.ErrConsentRequired.WithHint("OAuth 2.0 Client is marked public and redirect uri is not considered secure (https missing), but \"prompt=none\" was requested.")) + } + } + } + + if !isWhitelisted(prompt, v.AllowedPrompt) { + return errors.WithStack(fosite.ErrInvalidRequest.WithHintf(`Used unknown value "%s" for prompt parameter`, prompt)) + } + + if stringslice.Has(prompt, "none") && len(prompt) > 1 { + // If this parameter contains none with any other value, an error is returned. + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Parameter \"prompt\" was set to \"none\", but contains other values as well which is not allowed.")) + } + + maxAge, err := strconv.ParseInt(req.GetRequestForm().Get("max_age"), 10, 64) + if err != nil { + maxAge = 0 + } + + session, ok := req.GetSession().(Session) + if !ok { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because session is not of type fosite/handler/openid.Session.")) + } + + claims := session.IDTokenClaims() + if claims.Subject == "" { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because session subject is empty.")) + } + + // Adds a bit of wiggle room for timing issues + if claims.AuthTime.After(time.Now().UTC().Add(time.Second * 5)) { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because authentication time is in the future.")) + } + + if maxAge > 0 { + if claims.AuthTime.IsZero() { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because authentication time claim is required when max_age is set.")) + } else if claims.RequestedAt.IsZero() { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because requested at claim is required when max_age is set.")) + } else if claims.AuthTime.Add(time.Second * time.Duration(maxAge)).Before(claims.RequestedAt) { + return errors.WithStack(fosite.ErrLoginRequired.WithDebug("Failed to validate OpenID Connect request because authentication time does not satisfy max_age time.")) + } + } + + if stringslice.Has(prompt, "none") { + if claims.AuthTime.IsZero() { + return errors.WithStack(fosite.ErrServerError.WithDebug("Failed to validate OpenID Connect request because because auth_time is missing from session.")) + } + if claims.AuthTime.After(claims.RequestedAt) { + return errors.WithStack(fosite.ErrLoginRequired.WithHint("Failed to validate OpenID Connect request because prompt was set to \"none\" but auth_time happened after the authorization request was registered, indicating that the user was logged in during this request which is not allowed.")) + } + } + + if stringslice.Has(prompt, "login") { + if claims.AuthTime.Before(claims.RequestedAt) { + return errors.WithStack(fosite.ErrLoginRequired.WithHint("Failed to validate OpenID Connect request because prompt was set to \"login\" but auth_time happened before the authorization request was registered, indicating that the user was not re-authenticated which is forbidden.")) + } + } + + idTokenHint := req.GetRequestForm().Get("id_token_hint") + if idTokenHint == "" { + return nil + } + + tokenHint, err := v.Strategy.Decode(ctx, idTokenHint) + if ve, ok := errors.Cause(err).(*jwtgo.ValidationError); ok && ve.Errors == jwtgo.ValidationErrorExpired { + // Expired tokens are ok + } else if err != nil { + return errors.WithStack(fosite.ErrInvalidRequest.WithHintf("Failed to validate OpenID Connect request as decoding id token from id_token_hint parameter failed because %s.", err.Error())) + } + + if hintClaims, ok := tokenHint.Claims.(jwtgo.MapClaims); !ok { + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Failed to validate OpenID Connect request as decoding id token from id_token_hint to *jwt.StandardClaims failed.")) + } else if hintSub, _ := hintClaims["sub"].(string); hintSub == "" { + return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Failed to validate OpenID Connect request because provided id token from id_token_hint does not have a subject.")) + } else if hintSub != claims.Subject { + return errors.WithStack(fosite.ErrLoginRequired.WithHintf("Failed to validate OpenID Connect request because subject from ID token session claims does not subject from id_token_hint.")) + } + + return nil +} + +func isWhitelisted(items []string, whiteList []string) bool { + for _, item := range items { + if !stringslice.Has(whiteList, item) { + return false + } + } + return true +} diff --git a/vendor/github.com/ory/fosite/handler/pkce/handler.go b/vendor/github.com/ory/fosite/handler/pkce/handler.go new file mode 100644 index 0000000000..0077398bc9 --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/pkce/handler.go @@ -0,0 +1,229 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package pkce + +import ( + "context" + "crypto/sha256" + "encoding/base64" + "regexp" + + "github.com/pkg/errors" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" +) + +type Handler struct { + // If set to true, clients must use PKCE. + Force bool + + // If set to true, public clients must use PKCE. + ForceForPublicClients bool + + // Whether or not to allow the plain challenge method (S256 should be used whenever possible, plain is really discouraged). + EnablePlainChallengeMethod bool + + AuthorizeCodeStrategy oauth2.AuthorizeCodeStrategy + Storage PKCERequestStorage +} + +var verifierWrongFormat = regexp.MustCompile("[^\\w\\.\\-~]") + +func (c *Handler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error { + // This let's us define multiple response types, for example open id connect's id_token + if !ar.GetResponseTypes().Has("code") { + return nil + } + + challenge := ar.GetRequestForm().Get("code_challenge") + method := ar.GetRequestForm().Get("code_challenge_method") + client := ar.GetClient() + + if err := c.validate(challenge, method, client); err != nil { + return err + } + + code := resp.GetCode() + if len(code) == 0 { + return errors.WithStack(fosite.ErrServerError.WithDebug("The PKCE handler must be loaded after the authorize code handler.")) + } + + signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code) + if err := c.Storage.CreatePKCERequestSession(ctx, signature, ar.Sanitize([]string{ + "code_challenge", + "code_challenge_method", + })); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + return nil +} + +func (c *Handler) validate(challenge, method string, client fosite.Client) error { + if challenge == "" { + // If the server requires Proof Key for Code Exchange (PKCE) by OAuth + // clients and the client does not send the "code_challenge" in + // the request, the authorization endpoint MUST return the authorization + // error response with the "error" value set to "invalid_request". The + // "error_description" or the response of "error_uri" SHOULD explain the + // nature of error, e.g., code challenge required. + if c.Force { + return errors.WithStack(fosite.ErrInvalidRequest. + WithHint("Clients must include a code_challenge when performing the authorize code flow, but it is missing."). + WithDebug("The server is configured in a way that enforces PKCE for clients.")) + } + if c.ForceForPublicClients && client.IsPublic() { + return errors.WithStack(fosite.ErrInvalidRequest. + WithHint("This client must include a code_challenge when performing the authorize code flow, but it is missing."). + WithDebug("The server is configured in a way that enforces PKCE for this client.")) + } + return nil + } + + // If the server supporting PKCE does not support the requested + // transformation, the authorization endpoint MUST return the + // authorization error response with "error" value set to + // "invalid_request". The "error_description" or the response of + // "error_uri" SHOULD explain the nature of error, e.g., transform + // algorithm not supported. + switch method { + case "S256": + break + case "plain": + fallthrough + case "": + if !c.EnablePlainChallengeMethod { + return errors.WithStack(fosite.ErrInvalidRequest. + WithHint("Clients must use code_challenge_method=S256, plain is not allowed."). + WithDebug("The server is configured in a way that enforces PKCE S256 as challenge method for clients.")) + } + default: + return errors.WithStack(fosite.ErrInvalidRequest. + WithHint("The code_challenge_method is not supported, use S256 instead.")) + } + return nil +} + +func (c *Handler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error { + if !request.GetGrantTypes().ExactOne("authorization_code") { + return errors.WithStack(fosite.ErrUnknownRequest) + } + + // code_verifier + // REQUIRED. Code verifier + // + // The "code_challenge_method" is bound to the Authorization Code when + // the Authorization Code is issued. That is the method that the token + // endpoint MUST use to verify the "code_verifier". + verifier := request.GetRequestForm().Get("code_verifier") + + code := request.GetRequestForm().Get("code") + signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code) + authorizeRequest, err := c.Storage.GetPKCERequestSession(ctx, signature, request.GetSession()) + if errors.Cause(err) == fosite.ErrNotFound { + return errors.WithStack(fosite.ErrInvalidGrant.WithHint("Unable to find initial PKCE data tied to this request").WithDebug(err.Error())) + } else if err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + if err := c.Storage.DeletePKCERequestSession(ctx, signature); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + challenge := authorizeRequest.GetRequestForm().Get("code_challenge") + method := authorizeRequest.GetRequestForm().Get("code_challenge_method") + client := authorizeRequest.GetClient() + if err := c.validate(challenge, method, client); err != nil { + return err + } + + if !c.Force && challenge == "" && verifier == "" { + return nil + } + + // NOTE: The code verifier SHOULD have enough entropy to make it + // impractical to guess the value. It is RECOMMENDED that the output of + // a suitable random number generator be used to create a 32-octet + // sequence. The octet sequence is then base64url-encoded to produce a + // 43-octet URL safe string to use as the code verifier. + + // Validation + if len(verifier) < 43 { + return errors.WithStack(fosite.ErrInvalidGrant. + WithHint("The PKCE code verifier must be at least 43 characters.")) + } else if len(verifier) > 128 { + return errors.WithStack(fosite.ErrInvalidGrant. + WithHint("The PKCE code verifier can not be longer than 128 characters.")) + } else if verifierWrongFormat.MatchString(verifier) { + return errors.WithStack(fosite.ErrInvalidGrant. + WithHint(`The PKCE code verifier must only contain [a-Z] / [0-9] / "-" / "." / "_" / "~"`)) + } + + // Upon receipt of the request at the token endpoint, the server + // verifies it by calculating the code challenge from the received + // "code_verifier" and comparing it with the previously associated + // "code_challenge", after first transforming it according to the + // "code_challenge_method" method specified by the client. + // + // If the "code_challenge_method" from Section 4.3 was "S256", the + // received "code_verifier" is hashed by SHA-256, base64url-encoded, and + // then compared to the "code_challenge", i.e.: + // + // BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge + // + // If the "code_challenge_method" from Section 4.3 was "plain", they are + // compared directly, i.e.: + // + // code_verifier == code_challenge. + // + // If the values are equal, the token endpoint MUST continue processing + // as normal (as defined by OAuth 2.0 [RFC6749]). If the values are not + // equal, an error response indicating "invalid_grant" as described in + // Section 5.2 of [RFC6749] MUST be returned. + switch method { + case "S256": + hash := sha256.New() + if _, err := hash.Write([]byte(verifier)); err != nil { + return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error())) + } + + if base64.RawURLEncoding.EncodeToString(hash.Sum([]byte{})) != challenge { + return errors.WithStack(fosite.ErrInvalidGrant. + WithHint("The PKCE code challenge did not match the code verifier.")) + } + break + case "plain": + fallthrough + default: + if verifier != challenge { + return errors.WithStack(fosite.ErrInvalidGrant. + WithHint("The PKCE code challenge did not match the code verifier.")) + } + } + + return nil +} + +func (c *Handler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error { + return nil +} diff --git a/vendor/github.com/ory/fosite/handler/pkce/storage.go b/vendor/github.com/ory/fosite/handler/pkce/storage.go new file mode 100644 index 0000000000..54826dc89c --- /dev/null +++ b/vendor/github.com/ory/fosite/handler/pkce/storage.go @@ -0,0 +1,34 @@ +/* + * Copyright © 2017-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @Copyright 2017-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package pkce + +import ( + "context" + + "github.com/ory/fosite" +) + +type PKCERequestStorage interface { + GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) + CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error + DeletePKCERequestSession(ctx context.Context, signature string) error +} diff --git a/vendor/github.com/ory/fosite/hash.go b/vendor/github.com/ory/fosite/hash.go new file mode 100644 index 0000000000..ec364060fb --- /dev/null +++ b/vendor/github.com/ory/fosite/hash.go @@ -0,0 +1,34 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import "context" + +// Hasher defines how a oauth2-compatible hasher should look like. +type Hasher interface { + // Compare compares data with a hash and returns an error + // if the two do not match. + Compare(ctx context.Context, hash, data []byte) error + + // Hash creates a hash from data or returns an error. + Hash(ctx context.Context, data []byte) ([]byte, error) +} diff --git a/vendor/github.com/ory/fosite/hash_bcrypt.go b/vendor/github.com/ory/fosite/hash_bcrypt.go new file mode 100644 index 0000000000..676ae343a9 --- /dev/null +++ b/vendor/github.com/ory/fosite/hash_bcrypt.go @@ -0,0 +1,54 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + + "github.com/pkg/errors" + "golang.org/x/crypto/bcrypt" +) + +const DefaultBCryptWorkFactor = 12 + +// BCrypt implements the Hasher interface by using BCrypt. +type BCrypt struct { + WorkFactor int +} + +func (b *BCrypt) Hash(ctx context.Context, data []byte) ([]byte, error) { + if b.WorkFactor == 0 { + b.WorkFactor = DefaultBCryptWorkFactor + } + s, err := bcrypt.GenerateFromPassword(data, b.WorkFactor) + if err != nil { + return nil, errors.WithStack(err) + } + return s, nil +} + +func (b *BCrypt) Compare(ctx context.Context, hash, data []byte) error { + if err := bcrypt.CompareHashAndPassword(hash, data); err != nil { + return errors.WithStack(err) + } + return nil +} diff --git a/vendor/github.com/ory/fosite/helper.go b/vendor/github.com/ory/fosite/helper.go new file mode 100644 index 0000000000..24d9929e12 --- /dev/null +++ b/vendor/github.com/ory/fosite/helper.go @@ -0,0 +1,46 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "strings" +) + +// StringInSlice returns true if needle exists in haystack +func StringInSlice(needle string, haystack []string) bool { + for _, b := range haystack { + if strings.ToLower(b) == strings.ToLower(needle) { + return true + } + } + return false +} + +func RemoveEmpty(args []string) (ret []string) { + for _, v := range args { + v = strings.TrimSpace(v) + if v != "" { + ret = append(ret, v) + } + } + return +} diff --git a/vendor/github.com/ory/fosite/introspect.go b/vendor/github.com/ory/fosite/introspect.go new file mode 100644 index 0000000000..c32dbe202a --- /dev/null +++ b/vendor/github.com/ory/fosite/introspect.go @@ -0,0 +1,78 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "net/http" + "strings" + + "github.com/pkg/errors" +) + +type TokenIntrospector interface { + IntrospectToken(ctx context.Context, token string, tokenType TokenType, accessRequest AccessRequester, scopes []string) (TokenType, error) +} + +func AccessTokenFromRequest(req *http.Request) string { + // According to https://tools.ietf.org/html/rfc6750 you can pass tokens through: + // - Form-Encoded Body Parameter. Recommended, more likely to appear. e.g.: Authorization: Bearer mytoken123 + // - URI Query Parameter e.g. access_token=mytoken123 + + auth := req.Header.Get("Authorization") + split := strings.SplitN(auth, " ", 2) + if len(split) != 2 || !strings.EqualFold(split[0], "bearer") { + // Nothing in Authorization header, try access_token + // Empty string returned if there's no such parameter + if err := req.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart { + return "" + } + return req.Form.Get("access_token") + } + + return split[1] +} + +func (f *Fosite) IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scopes ...string) (TokenType, AccessRequester, error) { + var found bool = false + var foundTokenType TokenType = "" + + ar := NewAccessRequest(session) + for _, validator := range f.TokenIntrospectionHandlers { + tt, err := validator.IntrospectToken(ctx, token, tokenType, ar, scopes) + if err := errors.Cause(err); err == nil { + found = true + foundTokenType = tt + } else if err.Error() == ErrUnknownRequest.Error() { + // Nothing to do + } else if err != nil { + rfcerr := ErrorToRFC6749Error(err) + return "", nil, errors.WithStack(rfcerr) + } + } + + if !found { + return "", nil, errors.WithStack(ErrRequestUnauthorized.WithHint("Unable to find a suitable validation strategy for the token, thus it is invalid.")) + } + + return foundTokenType, ar, nil +} diff --git a/vendor/github.com/ory/fosite/introspection_request_handler.go b/vendor/github.com/ory/fosite/introspection_request_handler.go new file mode 100644 index 0000000000..3ff65d3a45 --- /dev/null +++ b/vendor/github.com/ory/fosite/introspection_request_handler.go @@ -0,0 +1,189 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "net/http" + "net/url" + "strings" + + "github.com/pkg/errors" +) + +// NewIntrospectionRequest initiates token introspection as defined in +// https://tools.ietf.org/search/rfc7662#section-2.1 +// +// The protected resource calls the introspection endpoint using an HTTP +// POST [RFC7231] request with parameters sent as +// "application/x-www-form-urlencoded" data as defined in +// [W3C.REC-html5-20141028]. The protected resource sends a parameter +// representing the token along with optional parameters representing +// additional context that is known by the protected resource to aid the +// authorization server in its response. +// +// * token +// REQUIRED. The string value of the token. For access tokens, this +// is the "access_token" value returned from the token endpoint +// defined in OAuth 2.0 [RFC6749], Section 5.1. For refresh tokens, +// this is the "refresh_token" value returned from the token endpoint +// as defined in OAuth 2.0 [RFC6749], Section 5.1. Other token types +// are outside the scope of this specification. +// +// * token_type_hint +// OPTIONAL. A hint about the type of the token submitted for +// introspection. The protected resource MAY pass this parameter to +// help the authorization server optimize the token lookup. If the +// server is unable to locate the token using the given hint, it MUST +// extend its search across all of its supported token types. An +// authorization server MAY ignore this parameter, particularly if it +// is able to detect the token type automatically. Values for this +// field are defined in the "OAuth Token Type Hints" registry defined +// in OAuth Token Revocation [RFC7009]. +// +// The introspection endpoint MAY accept other OPTIONAL parameters to +// provide further context to the query. For instance, an authorization +// server may desire to know the IP address of the client accessing the +// protected resource to determine if the correct client is likely to be +// presenting the token. The definition of this or any other parameters +// are outside the scope of this specification, to be defined by service +// documentation or extensions to this specification. If the +// authorization server is unable to determine the state of the token +// without additional information, it SHOULD return an introspection +// response indicating the token is not active as described in +// Section 2.2. +// +// To prevent token scanning attacks, the endpoint MUST also require +// some form of authorization to access this endpoint, such as client +// authentication as described in OAuth 2.0 [RFC6749] or a separate +// OAuth 2.0 access token such as the bearer token described in OAuth +// 2.0 Bearer Token Usage [RFC6750]. The methods of managing and +// validating these authentication credentials are out of scope of this +// specification. +// +// For example, the following shows a protected resource calling the +// token introspection endpoint to query about an OAuth 2.0 bearer +// token. The protected resource is using a separate OAuth 2.0 bearer +// token to authorize this call. +// +// The following is a non-normative example request: +// +// POST /introspect HTTP/1.1 +// Host: server.example.com +// Accept: application/json +// Content-Type: application/x-www-form-urlencoded +// Authorization: Bearer 23410913-abewfq.123483 +// +// token=2YotnFZFEjr1zCsicMWpAA +// +// In this example, the protected resource uses a client identifier and +// client secret to authenticate itself to the introspection endpoint. +// The protected resource also sends a token type hint indicating that +// it is inquiring about an access token. +// +// The following is a non-normative example request: +// +// POST /introspect HTTP/1.1 +// Host: server.example.com +// Accept: application/json +// Content-Type: application/x-www-form-urlencoded +// Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW +// +// token=mF_9.B5f-4.1JqM&token_type_hint=access_token +func (f *Fosite) NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error) { + if r.Method != "POST" { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrInvalidRequest.WithHintf("HTTP method is \"%s\", expected \"POST\".", r.Method)) + } else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithDebug(err.Error())) + } else if len(r.PostForm) == 0 { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty.")) + } + + token := r.PostForm.Get("token") + tokenType := r.PostForm.Get("token_type_hint") + scope := r.PostForm.Get("scope") + if clientToken := AccessTokenFromRequest(r); clientToken != "" { + if token == clientToken { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("Bearer and introspection token are identical.")) + } + + if tt, _, err := f.IntrospectToken(ctx, clientToken, AccessToken, session.Clone()); err != nil { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("HTTP Authorization header missing, malformed, or credentials used are invalid.")) + } else if tt != "" && tt != AccessToken { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHintf("HTTP Authorization header did not provide a token of type \"access_token\", got type \"%s\".", tt)) + } + } else { + id, secret, ok := r.BasicAuth() + if !ok { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("HTTP Authorization header missing.")) + } + + clientID, err := url.QueryUnescape(id) + if err != nil { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("Unable to decode OAuth 2.0 Client ID from HTTP basic authorization header, make sure it is properly encoded.").WithDebug(err.Error())) + } + + clientSecret, err := url.QueryUnescape(secret) + if err != nil { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("Unable to decode OAuth 2.0 Client Secret from HTTP basic authorization header, make sure it is properly encoded.").WithDebug(err.Error())) + } + + client, err := f.Store.GetClient(ctx, clientID) + if err != nil { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("Unable to find OAuth 2.0 Client from HTTP basic authorization header.").WithDebug(err.Error())) + } + + // Enforce client authentication + if err := f.Hasher.Compare(ctx, client.GetHashedSecret(), []byte(clientSecret)); err != nil { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrRequestUnauthorized.WithHint("OAuth 2.0 Client credentials are invalid.")) + } + } + + tt, ar, err := f.IntrospectToken(ctx, token, TokenType(tokenType), session, RemoveEmpty(strings.Split(scope, " "))...) + if err != nil { + return &IntrospectionResponse{Active: false}, errors.WithStack(ErrInactiveToken.WithHint("An introspection strategy indicated that the token is inactive.").WithDebug(err.Error())) + } + + return &IntrospectionResponse{ + Active: true, + AccessRequester: ar, + TokenType: tt, + }, nil +} + +type IntrospectionResponse struct { + Active bool `json:"active"` + AccessRequester AccessRequester `json:"extra"` + TokenType TokenType `json:"token_type,omitempty"` +} + +func (r *IntrospectionResponse) IsActive() bool { + return r.Active +} + +func (r *IntrospectionResponse) GetAccessRequester() AccessRequester { + return r.AccessRequester +} + +func (r *IntrospectionResponse) GetTokenType() TokenType { + return r.TokenType +} diff --git a/vendor/github.com/ory/fosite/introspection_response_writer.go b/vendor/github.com/ory/fosite/introspection_response_writer.go new file mode 100644 index 0000000000..4eefc44056 --- /dev/null +++ b/vendor/github.com/ory/fosite/introspection_response_writer.go @@ -0,0 +1,234 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "encoding/json" + "net/http" + "strings" + + "github.com/pkg/errors" +) + +// WriteIntrospectionError responds with token metadata discovered by token introspection as defined in +// https://tools.ietf.org/search/rfc7662#section-2.2 +// +// If the protected resource uses OAuth 2.0 client credentials to +// authenticate to the introspection endpoint and its credentials are +// invalid, the authorization server responds with an HTTP 401 +// (Unauthorized) as described in Section 5.2 of OAuth 2.0 [RFC6749]. +// +// If the protected resource uses an OAuth 2.0 bearer token to authorize +// its call to the introspection endpoint and the token used for +// authorization does not contain sufficient privileges or is otherwise +// invalid for this request, the authorization server responds with an +// HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token +// Usage [RFC6750]. +// +// Note that a properly formed and authorized query for an inactive or +// otherwise invalid token (or a token the protected resource is not +// allowed to know about) is not considered an error response by this +// specification. In these cases, the authorization server MUST instead +// respond with an introspection response with the "active" field set to +// "false" as described in Section 2.2. +func (f *Fosite) WriteIntrospectionError(rw http.ResponseWriter, err error) { + if err == nil { + return + } + + switch errors.Cause(err).Error() { + case ErrInvalidRequest.Error(), ErrRequestUnauthorized.Error(): + f.writeJsonError(rw, err) + return + } + + rw.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(rw).Encode(struct { + Active bool `json:"active"` + }{Active: false}) +} + +// WriteIntrospectionResponse responds with an error if token introspection failed as defined in +// https://tools.ietf.org/search/rfc7662#section-2.3 +// +// The server responds with a JSON object [RFC7159] in "application/ +// json" format with the following top-level members. +// +// * active +// REQUIRED. Boolean indicator of whether or not the presented token +// is currently active. The specifics of a token's "active" state +// will vary depending on the implementation of the authorization +// server and the information it keeps about its tokens, but a "true" +// value return for the "active" property will generally indicate +// that a given token has been issued by this authorization server, +// has not been revoked by the resource owner, and is within its +// given time window of validity (e.g., after its issuance time and +// before its expiration time). See Section 4 for information on +// implementation of such checks. +// +// * scope +// OPTIONAL. A JSON string containing a space-separated list of +// scopes associated with this token, in the format described in +// Section 3.3 of OAuth 2.0 [RFC6749]. +// +// * client_id +// OPTIONAL. Client identifier for the OAuth 2.0 client that +// requested this token. +// +// * username +// OPTIONAL. Human-readable identifier for the resource owner who +// authorized this token. +// +// * token_type +// OPTIONAL. Type of the token as defined in Section 5.1 of OAuth +// 2.0 [RFC6749]. +// +// * exp +// OPTIONAL. Integer timestamp, measured in the number of seconds +// since January 1 1970 UTC, indicating when this token will expire, +// as defined in JWT [RFC7519]. +// +// * iat +// OPTIONAL. Integer timestamp, measured in the number of seconds +// since January 1 1970 UTC, indicating when this token was +// originally issued, as defined in JWT [RFC7519]. +// +// * nbf +// OPTIONAL. Integer timestamp, measured in the number of seconds +// since January 1 1970 UTC, indicating when this token is not to be +// used before, as defined in JWT [RFC7519]. +// +// * sub +// OPTIONAL. Subject of the token, as defined in JWT [RFC7519]. +// Usually a machine-readable identifier of the resource owner who +// authorized this token. +// +// * aud +// OPTIONAL. Service-specific string identifier or list of string +// identifiers representing the intended audience for this token, as +// defined in JWT [RFC7519]. +// +// * iss +// OPTIONAL. String representing the issuer of this token, as +// defined in JWT [RFC7519]. +// +// * jti +// OPTIONAL. String identifier for the token, as defined in JWT +// [RFC7519]. +// +// Specific implementations MAY extend this structure with their own +// service-specific response names as top-level members of this JSON +// object. Response names intended to be used across domains MUST be +// registered in the "OAuth Token Introspection Response" registry +// defined in Section 3.1. +// +// The authorization server MAY respond differently to different +// protected resources making the same request. For instance, an +// authorization server MAY limit which scopes from a given token are +// returned for each protected resource to prevent a protected resource +// from learning more about the larger network than is necessary for its +// operation. +// +// The response MAY be cached by the protected resource to improve +// performance and reduce load on the introspection endpoint, but at the +// cost of liveness of the information used by the protected resource to +// make authorization decisions. See Section 4 for more information +// regarding the trade off when the response is cached. +// +// +// For example, the following response contains a set of information +// about an active token: +// +// The following is a non-normative example response: +// +// HTTP/1.1 200 OK +// Content-Type: application/json +// +// { +// "active": true, +// "client_id": "l238j323ds-23ij4", +// "username": "jdoe", +// "scope": "read write dolphin", +// "sub": "Z5O3upPC88QrAjx00dis", +// "aud": "https://protected.example.net/resource", +// "iss": "https://server.example.com/", +// "exp": 1419356238, +// "iat": 1419350238, +// "extension_field": "twenty-seven" +// } +// +// If the introspection call is properly authorized but the token is not +// active, does not exist on this server, or the protected resource is +// not allowed to introspect this particular token, then the +// authorization server MUST return an introspection response with the +// "active" field set to "false". Note that to avoid disclosing too +// much of the authorization server's state to a third party, the +// authorization server SHOULD NOT include any additional information +// about an inactive token, including why the token is inactive. +// +// The following is a non-normative example response for a token that +// has been revoked or is otherwise invalid: +// +// HTTP/1.1 200 OK +// Content-Type: application/json +// +// { +// "active": false +// } +func (f *Fosite) WriteIntrospectionResponse(rw http.ResponseWriter, r IntrospectionResponder) { + if !r.IsActive() { + _ = json.NewEncoder(rw).Encode(&struct { + Active bool `json:"active"` + }{Active: false}) + return + } + + expiresAt := int64(0) + if !r.GetAccessRequester().GetSession().GetExpiresAt(AccessToken).IsZero() { + expiresAt = r.GetAccessRequester().GetSession().GetExpiresAt(AccessToken).Unix() + } + + rw.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(rw).Encode(struct { + Active bool `json:"active"` + ClientID string `json:"client_id,omitempty"` + Scope string `json:"scope,omitempty"` + Audience []string `json:"aud,omitempty"` + ExpiresAt int64 `json:"exp,omitempty"` + IssuedAt int64 `json:"iat,omitempty"` + Subject string `json:"sub,omitempty"` + Username string `json:"username,omitempty"` + // Session is not included per default because it might expose sensitive information. + // Session Session `json:"sess,omitempty"` + }{ + Active: true, + ClientID: r.GetAccessRequester().GetClient().GetID(), + Scope: strings.Join(r.GetAccessRequester().GetGrantedScopes(), " "), + ExpiresAt: expiresAt, + IssuedAt: r.GetAccessRequester().GetRequestedAt().Unix(), + Subject: r.GetAccessRequester().GetSession().GetSubject(), + Audience: r.GetAccessRequester().GetGrantedAudience(), + Username: r.GetAccessRequester().GetSession().GetUsername(), + // Session is not included because it might expose sensitive information. + // Session: r.GetAccessRequester().GetSession(), + }) +} diff --git a/vendor/github.com/ory/fosite/oauth2.go b/vendor/github.com/ory/fosite/oauth2.go new file mode 100644 index 0000000000..f793fcc0df --- /dev/null +++ b/vendor/github.com/ory/fosite/oauth2.go @@ -0,0 +1,318 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "net/http" + "net/url" + "time" +) + +const MinParameterEntropy = 8 + +type TokenType string + +const ( + AccessToken TokenType = "access_token" + RefreshToken TokenType = "refresh_token" + AuthorizeCode TokenType = "authorize_code" + IDToken TokenType = "id_token" +) + +// OAuth2Provider is an interface that enables you to write OAuth2 handlers with only a few lines of code. +// Check fosite.Fosite for an implementation of this interface. +type OAuth2Provider interface { + // NewAuthorizeRequest returns an AuthorizeRequest. + // + // The following specs must be considered in any implementation of this method: + // * https://tools.ietf.org/html/rfc6749#section-3.1 + // Extension response types MAY contain a space-delimited (%x20) list of + // values, where the order of values does not matter (e.g., response + // type "a b" is the same as "b a"). The meaning of such composite + // response types is defined by their respective specifications. + // * https://tools.ietf.org/html/rfc6749#section-3.1.2 + // The redirection endpoint URI MUST be an absolute URI as defined by + // [RFC3986] Section 4.3. The endpoint URI MAY include an + // "application/x-www-form-urlencoded" formatted (per Appendix B) query + // component ([RFC3986] Section 3.4), which MUST be retained when adding + // additional query parameters. The endpoint URI MUST NOT include a + // fragment component. + // * https://tools.ietf.org/html/rfc6749#section-3.1.2.2 (everything MUST be implemented) + NewAuthorizeRequest(ctx context.Context, req *http.Request) (AuthorizeRequester, error) + + // NewAuthorizeResponse iterates through all response type handlers and returns their result or + // ErrUnsupportedResponseType if none of the handler's were able to handle it. + // + // The following specs must be considered in any implementation of this method: + // * https://tools.ietf.org/html/rfc6749#section-3.1.1 + // Extension response types MAY contain a space-delimited (%x20) list of + // values, where the order of values does not matter (e.g., response + // type "a b" is the same as "b a"). The meaning of such composite + // response types is defined by their respective specifications. + // If an authorization request is missing the "response_type" parameter, + // or if the response type is not understood, the authorization server + // MUST return an error response as described in Section 4.1.2.1. + NewAuthorizeResponse(ctx context.Context, requester AuthorizeRequester, session Session) (AuthorizeResponder, error) + + // WriteAuthorizeError returns the error codes to the redirection endpoint or shows the error to the user, if no valid + // redirect uri was given. Implements rfc6749#section-4.1.2.1 + // + // The following specs must be considered in any implementation of this method: + // * https://tools.ietf.org/html/rfc6749#section-3.1.2 + // The redirection endpoint URI MUST be an absolute URI as defined by + // [RFC3986] Section 4.3. The endpoint URI MAY include an + // "application/x-www-form-urlencoded" formatted (per Appendix B) query + // component ([RFC3986] Section 3.4), which MUST be retained when adding + // additional query parameters. The endpoint URI MUST NOT include a + // fragment component. + // * https://tools.ietf.org/html/rfc6749#section-4.1.2.1 (everything) + // * https://tools.ietf.org/html/rfc6749#section-3.1.2.2 (everything MUST be implemented) + WriteAuthorizeError(rw http.ResponseWriter, requester AuthorizeRequester, err error) + + // WriteAuthorizeResponse persists the AuthorizeSession in the store and redirects the user agent to the provided + // redirect url or returns an error if storage failed. + // + // The following specs must be considered in any implementation of this method: + // * https://tools.ietf.org/html/rfc6749#rfc6749#section-4.1.2.1 + // After completing its interaction with the resource owner, the + // authorization server directs the resource owner's user-agent back to + // the client. The authorization server redirects the user-agent to the + // client's redirection endpoint previously established with the + // authorization server during the client registration process or when + // making the authorization request. + // * https://tools.ietf.org/html/rfc6749#section-3.1.2.2 (everything MUST be implemented) + WriteAuthorizeResponse(rw http.ResponseWriter, requester AuthorizeRequester, responder AuthorizeResponder) + + // NewAccessRequest creates a new access request object and validates + // various parameters. + // + // The following specs must be considered in any implementation of this method: + // * https://tools.ietf.org/html/rfc6749#section-3.2 (everything) + // * https://tools.ietf.org/html/rfc6749#section-3.2.1 (everything) + // + // Furthermore the registered handlers should implement their specs accordingly. + NewAccessRequest(ctx context.Context, req *http.Request, session Session) (AccessRequester, error) + + // NewAccessResponse creates a new access response and validates that access_token and token_type are set. + // + // The following specs must be considered in any implementation of this method: + // https://tools.ietf.org/html/rfc6749#section-5.1 + NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error) + + // WriteAccessError writes an access request error response. + // + // The following specs must be considered in any implementation of this method: + // * https://tools.ietf.org/html/rfc6749#section-5.2 (everything) + WriteAccessError(rw http.ResponseWriter, requester AccessRequester, err error) + + // WriteAccessResponse writes the access response. + // + // The following specs must be considered in any implementation of this method: + // https://tools.ietf.org/html/rfc6749#section-5.1 + WriteAccessResponse(rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) + + // NewRevocationRequest handles incoming token revocation requests and validates various parameters. + // + // The following specs must be considered in any implementation of this method: + // https://tools.ietf.org/html/rfc7009#section-2.1 + NewRevocationRequest(ctx context.Context, r *http.Request) error + + // WriteRevocationResponse writes the revoke response. + // + // The following specs must be considered in any implementation of this method: + // https://tools.ietf.org/html/rfc7009#section-2.2 + WriteRevocationResponse(rw http.ResponseWriter, err error) + + // IntrospectToken returns token metadata, if the token is valid. Tokens generated by the authorization endpoint, + // such as the authorization code, can not be introspected. + IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scope ...string) (TokenType, AccessRequester, error) + + // NewIntrospectionRequest initiates token introspection as defined in + // https://tools.ietf.org/search/rfc7662#section-2.1 + NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error) + + // WriteIntrospectionError responds with an error if token introspection failed as defined in + // https://tools.ietf.org/search/rfc7662#section-2.3 + WriteIntrospectionError(rw http.ResponseWriter, err error) + + // WriteIntrospectionResponse responds with token metadata discovered by token introspection as defined in + // https://tools.ietf.org/search/rfc7662#section-2.2 + WriteIntrospectionResponse(rw http.ResponseWriter, r IntrospectionResponder) +} + +// IntrospectionResponder is the response object that will be returned when token introspection was successful, +// for example when the client is allowed to perform token introspection. Refer to +// https://tools.ietf.org/search/rfc7662#section-2.2 for more details. +type IntrospectionResponder interface { + // IsActive returns true if the introspected token is active and false otherwise. + IsActive() bool + + // AccessRequester returns nil when IsActive() is false and the original access request object otherwise. + GetAccessRequester() AccessRequester + + // GetTokenType optionally returns the type of the token that was introspected. The could be "access_token", "refresh_token", + // or if the type can not be determined an empty string. + GetTokenType() TokenType +} + +// Requester is an abstract interface for handling requests in Fosite. +type Requester interface { + // SetID sets the unique identifier. + SetID(id string) + + // GetID returns a unique identifier. + GetID() string + + // GetRequestedAt returns the time the request was created. + GetRequestedAt() (requestedAt time.Time) + + // GetClient returns the request's client. + GetClient() (client Client) + + // GetRequestedScopes returns the request's scopes. + GetRequestedScopes() (scopes Arguments) + + // GetRequestedAudience returns the requested audiences for this request. + GetRequestedAudience() (audience Arguments) + + // SetRequestedScopes sets the request's scopes. + SetRequestedScopes(scopes Arguments) + + // SetRequestedAudience sets the requested audience. + SetRequestedAudience(audience Arguments) + + // AppendRequestedScope appends a scope to the request. + AppendRequestedScope(scope string) + + // GetGrantScopes returns all granted scopes. + GetGrantedScopes() (grantedScopes Arguments) + + // GetGrantedAudience returns all granted audiences. + GetGrantedAudience() (grantedAudience Arguments) + + // GrantScope marks a request's scope as granted. + GrantScope(scope string) + + // GrantAudience marks a request's audience as granted. + GrantAudience(audience string) + + // GetSession returns a pointer to the request's session or nil if none is set. + GetSession() (session Session) + + // SetSession sets the request's session pointer. + SetSession(session Session) + + // GetRequestForm returns the request's form input. + GetRequestForm() url.Values + + // Merge merges the argument into the method receiver. + Merge(requester Requester) + + // Sanitize returns a sanitized clone of the request which can be used for storage. + Sanitize(allowedParameters []string) Requester +} + +// AccessRequester is a token endpoint's request context. +type AccessRequester interface { + // GetGrantType returns the requests grant type. + GetGrantTypes() (grantTypes Arguments) + + Requester +} + +// AuthorizeRequester is an authorize endpoint's request context. +type AuthorizeRequester interface { + // GetResponseTypes returns the requested response types + GetResponseTypes() (responseTypes Arguments) + + // SetResponseTypeHandled marks a response_type (e.g. token or code) as handled indicating that the response type + // is supported. + SetResponseTypeHandled(responseType string) + + // DidHandleAllResponseTypes returns if all requested response types have been handled correctly + DidHandleAllResponseTypes() (didHandle bool) + + // GetRedirectURI returns the requested redirect URI + GetRedirectURI() (redirectURL *url.URL) + + // IsRedirectURIValid returns false if the redirect is not rfc-conform (i.e. missing client, not on white list, + // or malformed) + IsRedirectURIValid() (isValid bool) + + // GetState returns the request's state. + GetState() (state string) + + Requester +} + +// AccessResponder is a token endpoint's response. +type AccessResponder interface { + // SetExtra sets a key value pair for the access response. + SetExtra(key string, value interface{}) + + // GetExtra returns a key's value. + GetExtra(key string) interface{} + + SetExpiresIn(time.Duration) + + SetScopes(scopes Arguments) + + // SetAccessToken sets the responses mandatory access token. + SetAccessToken(token string) + + // SetTokenType set's the responses mandatory token type + SetTokenType(tokenType string) + + // SetAccessToken returns the responses access token. + GetAccessToken() (token string) + + // GetTokenType returns the responses token type. + GetTokenType() (token string) + + // ToMap converts the response to a map. + ToMap() map[string]interface{} +} + +// AuthorizeResponder is an authorization endpoint's response. +type AuthorizeResponder interface { + // GetCode returns the response's authorize code if set. + GetCode() string + + // GetHeader returns the response's header + GetHeader() (header http.Header) + + // AddHeader adds an header key value pair to the response + AddHeader(key, value string) + + // GetQuery returns the response's query + GetQuery() (query url.Values) + + // AddQuery adds an url query key value pair to the response + AddQuery(key, value string) + + // GetHeader returns the response's url fragments + GetFragment() (fragment url.Values) + + // AddHeader adds a key value pair to the response's url fragment + AddFragment(key, value string) +} diff --git a/vendor/github.com/ory/fosite/request.go b/vendor/github.com/ory/fosite/request.go new file mode 100644 index 0000000000..276411218c --- /dev/null +++ b/vendor/github.com/ory/fosite/request.go @@ -0,0 +1,195 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "net/url" + "time" + + "github.com/pborman/uuid" +) + +// Request is an implementation of Requester +type Request struct { + ID string `json:"id" gorethink:"id"` + RequestedAt time.Time `json:"requestedAt" gorethink:"requestedAt"` + Client Client `json:"client" gorethink:"client"` + RequestedScope Arguments `json:"scopes" gorethink:"scopes"` + GrantedScope Arguments `json:"grantedScopes" gorethink:"grantedScopes"` + Form url.Values `json:"form" gorethink:"form"` + Session Session `json:"session" gorethink:"session"` + RequestedAudience Arguments `json:"requestedAudience"` + GrantedAudience Arguments `json:"grantedAudience"` +} + +func NewRequest() *Request { + return &Request{ + Client: &DefaultClient{}, + RequestedScope: Arguments{}, + RequestedAudience: Arguments{}, + GrantedAudience: Arguments{}, + GrantedScope: Arguments{}, + Form: url.Values{}, + RequestedAt: time.Now().UTC(), + } +} + +func (a *Request) GetID() string { + if a.ID == "" { + a.ID = uuid.New() + } + return a.ID +} + +func (a *Request) SetID(id string) { + a.ID = id +} + +func (a *Request) GetRequestForm() url.Values { + return a.Form +} + +func (a *Request) GetRequestedAt() time.Time { + return a.RequestedAt +} + +func (a *Request) GetClient() Client { + return a.Client +} + +func (a *Request) GetRequestedScopes() Arguments { + return a.RequestedScope +} + +func (a *Request) SetRequestedScopes(s Arguments) { + a.RequestedScope = nil + for _, scope := range s { + a.AppendRequestedScope(scope) + } +} + +func (a *Request) SetRequestedAudience(s Arguments) { + a.RequestedAudience = nil + for _, scope := range s { + a.AppendRequestedAudience(scope) + } +} + +func (a *Request) AppendRequestedScope(scope string) { + for _, has := range a.RequestedScope { + if scope == has { + return + } + } + a.RequestedScope = append(a.RequestedScope, scope) +} + +func (a *Request) AppendRequestedAudience(audience string) { + for _, has := range a.RequestedAudience { + if audience == has { + return + } + } + a.RequestedAudience = append(a.RequestedAudience, audience) +} + +func (a *Request) GetRequestedAudience() (audience Arguments) { + return a.RequestedAudience +} + +func (a *Request) GrantAudience(audience string) { + for _, has := range a.GrantedAudience { + if audience == has { + return + } + } + a.GrantedAudience = append(a.GrantedAudience, audience) +} + +func (a *Request) GetGrantedScopes() Arguments { + return a.GrantedScope +} + +func (a *Request) GetGrantedAudience() Arguments { + return a.GrantedAudience +} + +func (a *Request) GrantScope(scope string) { + for _, has := range a.GrantedScope { + if scope == has { + return + } + } + a.GrantedScope = append(a.GrantedScope, scope) +} + +func (a *Request) SetSession(session Session) { + a.Session = session +} + +func (a *Request) GetSession() Session { + return a.Session +} + +func (a *Request) Merge(request Requester) { + for _, scope := range request.GetRequestedScopes() { + a.AppendRequestedScope(scope) + } + for _, scope := range request.GetGrantedScopes() { + a.GrantScope(scope) + } + + for _, aud := range request.GetRequestedAudience() { + a.AppendRequestedAudience(aud) + } + for _, aud := range request.GetGrantedAudience() { + a.GrantAudience(aud) + } + + a.ID = request.GetID() + a.RequestedAt = request.GetRequestedAt() + a.Client = request.GetClient() + a.Session = request.GetSession() + + for k, v := range request.GetRequestForm() { + a.Form[k] = v + } +} + +func (a *Request) Sanitize(allowedParameters []string) Requester { + b := new(Request) + allowed := map[string]bool{} + for _, v := range allowedParameters { + allowed[v] = true + } + + *b = *a + b.ID = a.GetID() + b.Form = url.Values{} + for k := range a.Form { + if _, ok := allowed[k]; ok { + b.Form.Add(k, a.Form.Get(k)) + } + } + + return b +} diff --git a/vendor/github.com/ory/fosite/revoke_handler.go b/vendor/github.com/ory/fosite/revoke_handler.go new file mode 100644 index 0000000000..3663fa122f --- /dev/null +++ b/vendor/github.com/ory/fosite/revoke_handler.go @@ -0,0 +1,129 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/pkg/errors" +) + +// NewRevocationRequest handles incoming token revocation requests and +// validates various parameters as specified in: +// https://tools.ietf.org/html/rfc7009#section-2.1 +// +// The authorization server first validates the client credentials (in +// case of a confidential client) and then verifies whether the token +// was issued to the client making the revocation request. If this +// validation fails, the request is refused and the client is informed +// of the error by the authorization server as described below. +// +// In the next step, the authorization server invalidates the token. +// The invalidation takes place immediately, and the token cannot be +// used again after the revocation. +// +// * https://tools.ietf.org/html/rfc7009#section-2.2 +// An invalid token type hint value is ignored by the authorization +// server and does not influence the revocation response. +func (f *Fosite) NewRevocationRequest(ctx context.Context, r *http.Request) error { + if r.Method != "POST" { + return errors.WithStack(ErrInvalidRequest.WithHintf("HTTP method is \"%s\", expected \"POST\".", r.Method)) + } else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart { + return errors.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithDebug(err.Error())) + } else if len(r.PostForm) == 0 { + return errors.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty.")) + } + + client, err := f.AuthenticateClient(ctx, r, r.PostForm) + if err != nil { + return err + } + + token := r.PostForm.Get("token") + tokenTypeHint := TokenType(r.PostForm.Get("token_type_hint")) + + var found bool + for _, loader := range f.RevocationHandlers { + if err := loader.RevokeToken(ctx, token, tokenTypeHint, client); err == nil { + found = true + } else if errors.Cause(err).Error() == ErrUnknownRequest.Error() { + // do nothing + } else if err != nil { + return err + } + } + + if !found { + return errors.WithStack(ErrInvalidRequest) + } + + return nil +} + +// WriteRevocationResponse writes a token revocation response as specified in: +// https://tools.ietf.org/html/rfc7009#section-2.2 +// +// The authorization server responds with HTTP status code 200 if the +// token has been revoked successfully or if the client submitted an +// invalid token. +// +// Note: invalid tokens do not cause an error response since the client +// cannot handle such an error in a reasonable way. Moreover, the +// purpose of the revocation request, invalidating the particular token, +// is already achieved. +func (f *Fosite) WriteRevocationResponse(rw http.ResponseWriter, err error) { + if err == nil { + rw.WriteHeader(http.StatusOK) + return + } + + switch errors.Cause(err).Error() { + case ErrInvalidRequest.Error(): + rw.Header().Set("Content-Type", "application/json;charset=UTF-8") + + js, err := json.Marshal(ErrInvalidRequest) + if err != nil { + http.Error(rw, fmt.Sprintf(`{"error": "%s"}`, err.Error()), http.StatusInternalServerError) + return + } + + rw.WriteHeader(ErrInvalidRequest.Code) + rw.Write(js) + case ErrInvalidClient.Error(): + rw.Header().Set("Content-Type", "application/json;charset=UTF-8") + + js, err := json.Marshal(ErrInvalidClient) + if err != nil { + http.Error(rw, fmt.Sprintf(`{"error": "%s"}`, err.Error()), http.StatusInternalServerError) + return + } + + rw.WriteHeader(ErrInvalidClient.Code) + rw.Write(js) + default: + // 200 OK + rw.WriteHeader(http.StatusOK) + } +} diff --git a/vendor/github.com/ory/fosite/scope_strategy.go b/vendor/github.com/ory/fosite/scope_strategy.go new file mode 100644 index 0000000000..22fbc10492 --- /dev/null +++ b/vendor/github.com/ory/fosite/scope_strategy.go @@ -0,0 +1,103 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import "strings" + +// ScopeStrategy is a strategy for matching scopes. +type ScopeStrategy func(haystack []string, needle string) bool + +func HierarchicScopeStrategy(haystack []string, needle string) bool { + for _, this := range haystack { + // foo == foo -> true + if this == needle { + return true + } + + // picture.read > picture -> false (scope picture includes read, write, ...) + if len(this) > len(needle) { + continue + } + + needles := strings.Split(needle, ".") + haystack := strings.Split(this, ".") + haystackLen := len(haystack) - 1 + for k, needle := range needles { + if haystackLen < k { + return true + } + + current := haystack[k] + if current != needle { + break + } + } + } + + return false +} + +func ExactScopeStrategy(haystack []string, needle string) bool { + for _, this := range haystack { + if needle == this { + return true + } + } + + return false +} + +func WildcardScopeStrategy(matchers []string, needle string) bool { + needleParts := strings.Split(needle, ".") + for _, matcher := range matchers { + matcherParts := strings.Split(matcher, ".") + + if len(matcherParts) > len(needleParts) { + continue + } + + var noteq bool + for k, c := range strings.Split(matcher, ".") { + // this is the last item and the lengths are different + if k == len(matcherParts)-1 && len(matcherParts) != len(needleParts) { + if c != "*" { + noteq = true + break + } + } + + if c == "*" && len(needleParts[k]) > 0 { + // pass because this satisfies the requirements + continue + } else if c != needleParts[k] { + noteq = true + break + } + } + + if !noteq { + return true + } + } + + return false +} diff --git a/vendor/github.com/ory/fosite/session.go b/vendor/github.com/ory/fosite/session.go new file mode 100644 index 0000000000..c551e297c6 --- /dev/null +++ b/vendor/github.com/ory/fosite/session.go @@ -0,0 +1,99 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +import ( + "time" + + "github.com/mohae/deepcopy" +) + +// Session is an interface that is used to store session data between OAuth2 requests. It can be used to look up +// when a session expires or what the subject's name was. +type Session interface { + // SetExpiresAt sets the expiration time of a token. + // + // session.SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(time.Hour)) + SetExpiresAt(key TokenType, exp time.Time) + + // GetExpiresAt returns the expiration time of a token if set, or time.IsZero() if not. + // + // session.GetExpiresAt(fosite.AccessToken) + GetExpiresAt(key TokenType) time.Time + + // GetUsername returns the username, if set. This is optional and only used during token introspection. + GetUsername() string + + // GetSubject returns the subject, if set. This is optional and only used during token introspection. + GetSubject() string + + // Clone clones the session. + Clone() Session +} + +// DefaultSession is a default implementation of the session interface. +type DefaultSession struct { + ExpiresAt map[TokenType]time.Time + Username string + Subject string +} + +func (s *DefaultSession) SetExpiresAt(key TokenType, exp time.Time) { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[TokenType]time.Time) + } + s.ExpiresAt[key] = exp +} + +func (s *DefaultSession) GetExpiresAt(key TokenType) time.Time { + if s.ExpiresAt == nil { + s.ExpiresAt = make(map[TokenType]time.Time) + } + + if _, ok := s.ExpiresAt[key]; !ok { + return time.Time{} + } + return s.ExpiresAt[key] +} + +func (s *DefaultSession) GetUsername() string { + if s == nil { + return "" + } + return s.Username +} + +func (s *DefaultSession) GetSubject() string { + if s == nil { + return "" + } + + return s.Subject +} + +func (s *DefaultSession) Clone() Session { + if s == nil { + return nil + } + + return deepcopy.Copy(s).(Session) +} diff --git a/vendor/github.com/ory/fosite/storage.go b/vendor/github.com/ory/fosite/storage.go new file mode 100644 index 0000000000..ddec91dec8 --- /dev/null +++ b/vendor/github.com/ory/fosite/storage.go @@ -0,0 +1,27 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package fosite + +// Storage defines fosite's minimal storage interface. +type Storage interface { + ClientManager +} diff --git a/vendor/github.com/ory/fosite/storage/memory.go b/vendor/github.com/ory/fosite/storage/memory.go new file mode 100644 index 0000000000..02c49ac161 --- /dev/null +++ b/vendor/github.com/ory/fosite/storage/memory.go @@ -0,0 +1,267 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package storage + +import ( + "context" + "time" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type MemoryUserRelation struct { + Username string + Password string +} + +type MemoryStore struct { + Clients map[string]fosite.Client + AuthorizeCodes map[string]StoreAuthorizeCode + IDSessions map[string]fosite.Requester + AccessTokens map[string]fosite.Requester + RefreshTokens map[string]fosite.Requester + PKCES map[string]fosite.Requester + Users map[string]MemoryUserRelation + BlacklistedJTIs map[string]time.Time + // In-memory request ID to token signatures + AccessTokenRequestIDs map[string]string + RefreshTokenRequestIDs map[string]string +} + +func NewMemoryStore() *MemoryStore { + return &MemoryStore{ + Clients: make(map[string]fosite.Client), + AuthorizeCodes: make(map[string]StoreAuthorizeCode), + IDSessions: make(map[string]fosite.Requester), + AccessTokens: make(map[string]fosite.Requester), + RefreshTokens: make(map[string]fosite.Requester), + PKCES: make(map[string]fosite.Requester), + Users: make(map[string]MemoryUserRelation), + AccessTokenRequestIDs: make(map[string]string), + RefreshTokenRequestIDs: make(map[string]string), + BlacklistedJTIs: make(map[string]time.Time), + } +} + +type StoreAuthorizeCode struct { + active bool + fosite.Requester +} + +func NewExampleStore() *MemoryStore { + return &MemoryStore{ + IDSessions: make(map[string]fosite.Requester), + Clients: map[string]fosite.Client{ + "my-client": &fosite.DefaultClient{ + ID: "my-client", + Secret: []byte(`$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO`), // = "foobar" + RedirectURIs: []string{"http://localhost:3846/callback"}, + ResponseTypes: []string{"id_token", "code", "token", "id_token token", "code id_token", "code token", "code id_token token"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scopes: []string{"fosite", "openid", "photos", "offline"}, + }, + "encoded:client": &fosite.DefaultClient{ + ID: "encoded:client", + Secret: []byte(`$2a$10$A7M8b65dSSKGHF0H2sNkn.9Z0hT8U1Nv6OWPV3teUUaczXkVkxuDS`), // = "encoded&password" + RedirectURIs: []string{"http://localhost:3846/callback"}, + ResponseTypes: []string{"id_token", "code", "token", "id_token token", "code id_token", "code token", "code id_token token"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scopes: []string{"fosite", "openid", "photos", "offline"}, + }, + }, + Users: map[string]MemoryUserRelation{ + "peter": { + // This store simply checks for equality, a real storage implementation would obviously use + // a hashing algorithm for encrypting the user password. + Username: "peter", + Password: "secret", + }, + }, + AuthorizeCodes: map[string]StoreAuthorizeCode{}, + AccessTokens: map[string]fosite.Requester{}, + RefreshTokens: map[string]fosite.Requester{}, + PKCES: map[string]fosite.Requester{}, + AccessTokenRequestIDs: map[string]string{}, + RefreshTokenRequestIDs: map[string]string{}, + } +} + +func (s *MemoryStore) CreateOpenIDConnectSession(_ context.Context, authorizeCode string, requester fosite.Requester) error { + s.IDSessions[authorizeCode] = requester + return nil +} + +func (s *MemoryStore) GetOpenIDConnectSession(_ context.Context, authorizeCode string, requester fosite.Requester) (fosite.Requester, error) { + cl, ok := s.IDSessions[authorizeCode] + if !ok { + return nil, fosite.ErrNotFound + } + return cl, nil +} + +func (s *MemoryStore) DeleteOpenIDConnectSession(_ context.Context, authorizeCode string) error { + delete(s.IDSessions, authorizeCode) + return nil +} + +func (s *MemoryStore) GetClient(_ context.Context, id string) (fosite.Client, error) { + cl, ok := s.Clients[id] + if !ok { + return nil, fosite.ErrNotFound + } + return cl, nil +} + +func (s *MemoryStore) ClientAssertionJWTValid(_ context.Context, jti string) error { + if exp, exists := s.BlacklistedJTIs[jti]; exists && exp.After(time.Now()) { + return fosite.ErrJTIKnown + } + + return nil +} + +func (s *MemoryStore) SetClientAssertionJWT(_ context.Context, jti string, exp time.Time) error { + // delete expired jtis + for j, e := range s.BlacklistedJTIs { + if e.Before(time.Now()) { + delete(s.BlacklistedJTIs, j) + } + } + + if _, exists := s.BlacklistedJTIs[jti]; exists { + return fosite.ErrJTIKnown + } + + s.BlacklistedJTIs[jti] = exp + return nil +} + +func (s *MemoryStore) CreateAuthorizeCodeSession(_ context.Context, code string, req fosite.Requester) error { + s.AuthorizeCodes[code] = StoreAuthorizeCode{active: true, Requester: req} + return nil +} + +func (s *MemoryStore) GetAuthorizeCodeSession(_ context.Context, code string, _ fosite.Session) (fosite.Requester, error) { + rel, ok := s.AuthorizeCodes[code] + if !ok { + return nil, fosite.ErrNotFound + } + if !rel.active { + return rel, fosite.ErrInvalidatedAuthorizeCode + } + + return rel.Requester, nil +} + +func (s *MemoryStore) InvalidateAuthorizeCodeSession(ctx context.Context, code string) error { + rel, ok := s.AuthorizeCodes[code] + if !ok { + return fosite.ErrNotFound + } + rel.active = false + s.AuthorizeCodes[code] = rel + return nil +} + +func (s *MemoryStore) CreatePKCERequestSession(_ context.Context, code string, req fosite.Requester) error { + s.PKCES[code] = req + return nil +} + +func (s *MemoryStore) GetPKCERequestSession(_ context.Context, code string, _ fosite.Session) (fosite.Requester, error) { + rel, ok := s.PKCES[code] + if !ok { + return nil, fosite.ErrNotFound + } + return rel, nil +} + +func (s *MemoryStore) DeletePKCERequestSession(_ context.Context, code string) error { + delete(s.PKCES, code) + return nil +} + +func (s *MemoryStore) CreateAccessTokenSession(_ context.Context, signature string, req fosite.Requester) error { + s.AccessTokens[signature] = req + s.AccessTokenRequestIDs[req.GetID()] = signature + return nil +} + +func (s *MemoryStore) GetAccessTokenSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { + rel, ok := s.AccessTokens[signature] + if !ok { + return nil, fosite.ErrNotFound + } + return rel, nil +} + +func (s *MemoryStore) DeleteAccessTokenSession(_ context.Context, signature string) error { + delete(s.AccessTokens, signature) + return nil +} + +func (s *MemoryStore) CreateRefreshTokenSession(_ context.Context, signature string, req fosite.Requester) error { + s.RefreshTokens[signature] = req + s.RefreshTokenRequestIDs[req.GetID()] = signature + return nil +} + +func (s *MemoryStore) GetRefreshTokenSession(_ context.Context, signature string, _ fosite.Session) (fosite.Requester, error) { + rel, ok := s.RefreshTokens[signature] + if !ok { + return nil, fosite.ErrNotFound + } + return rel, nil +} + +func (s *MemoryStore) DeleteRefreshTokenSession(_ context.Context, signature string) error { + delete(s.RefreshTokens, signature) + return nil +} + +func (s *MemoryStore) Authenticate(_ context.Context, name string, secret string) error { + rel, ok := s.Users[name] + if !ok { + return fosite.ErrNotFound + } + if rel.Password != secret { + return errors.New("Invalid credentials") + } + return nil +} + +func (s *MemoryStore) RevokeRefreshToken(ctx context.Context, requestID string) error { + if signature, exists := s.RefreshTokenRequestIDs[requestID]; exists { + s.DeleteRefreshTokenSession(ctx, signature) + s.DeleteAccessTokenSession(ctx, signature) + } + return nil +} + +func (s *MemoryStore) RevokeAccessToken(ctx context.Context, requestID string) error { + if signature, exists := s.AccessTokenRequestIDs[requestID]; exists { + s.DeleteAccessTokenSession(ctx, signature) + } + return nil +} diff --git a/vendor/github.com/ory/fosite/storage/transactional.go b/vendor/github.com/ory/fosite/storage/transactional.go new file mode 100644 index 0000000000..a31cee3792 --- /dev/null +++ b/vendor/github.com/ory/fosite/storage/transactional.go @@ -0,0 +1,55 @@ +package storage + +import "context" + +// A storage provider that has support for transactions should implement this interface to ensure atomicity for certain flows +// that require transactional semantics. Fosite will call these methods (when atomicity is required) if and only if the storage +// provider has implemented `Transactional`. It is expected that the storage provider will examine context for an existing transaction +// each time a database operation is to be performed. +// +// An implementation of `BeginTX` should attempt to initiate a new transaction and store that under a unique key +// in the context that can be accessible by `Commit` and `Rollback`. The "transactional aware" context will then be +// returned for further propagation, eventually to be consumed by `Commit` or `Rollback` to finish the transaction. +// +// Implementations for `Commit` & `Rollback` should look for the transaction object inside the supplied context using the same +// key used by `BeginTX`. If these methods have been called, it is expected that a txn object should be available in the provided +// context. +type Transactional interface { + BeginTX(ctx context.Context) (context.Context, error) + Commit(ctx context.Context) error + Rollback(ctx context.Context) error +} + +// MaybeBeginTx is a helper function that can be used to initiate a transaction if the supplied storage +// implements the `Transactional` interface. +func MaybeBeginTx(ctx context.Context, storage interface{}) (context.Context, error) { + // the type assertion checks whether the dynamic type of `storage` implements `Transactional` + txnStorage, transactional := storage.(Transactional) + if transactional { + return txnStorage.BeginTX(ctx) + } else { + return ctx, nil + } +} + +// MaybeCommitTx is a helper function that can be used to commit a transaction if the supplied storage +// implements the `Transactional` interface. +func MaybeCommitTx(ctx context.Context, storage interface{}) error { + txnStorage, transactional := storage.(Transactional) + if transactional { + return txnStorage.Commit(ctx) + } else { + return nil + } +} + +// MaybeRollbackTx is a helper function that can be used to rollback a transaction if the supplied storage +// implements the `Transactional` interface. +func MaybeRollbackTx(ctx context.Context, storage interface{}) error { + txnStorage, transactional := storage.(Transactional) + if transactional { + return txnStorage.Rollback(ctx) + } else { + return nil + } +} diff --git a/vendor/github.com/ory/fosite/token/hmac/bytes.go b/vendor/github.com/ory/fosite/token/hmac/bytes.go new file mode 100644 index 0000000000..62b2479e8c --- /dev/null +++ b/vendor/github.com/ory/fosite/token/hmac/bytes.go @@ -0,0 +1,38 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package hmac + +import ( + "crypto/rand" + "io" + + "github.com/pkg/errors" +) + +// RandomBytes returns n random bytes by reading from crypto/rand.Reader +func RandomBytes(n int) ([]byte, error) { + bytes := make([]byte, n) + if _, err := io.ReadFull(rand.Reader, bytes); err != nil { + return []byte{}, errors.WithStack(err) + } + return bytes, nil +} diff --git a/vendor/github.com/ory/fosite/token/hmac/hmacsha.go b/vendor/github.com/ory/fosite/token/hmac/hmacsha.go new file mode 100644 index 0000000000..4629196df4 --- /dev/null +++ b/vendor/github.com/ory/fosite/token/hmac/hmacsha.go @@ -0,0 +1,174 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +// Package hmac is the default implementation for generating and validating challenges. It uses HMAC-SHA256 to +// generate and validate challenges. + +package hmac + +import ( + "crypto/hmac" + "crypto/sha512" + "encoding/base64" + "fmt" + "strings" + "sync" + + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +// HMACStrategy is responsible for generating and validating challenges. +type HMACStrategy struct { + TokenEntropy int + GlobalSecret []byte + RotatedGlobalSecrets [][]byte + sync.Mutex +} + +const ( + // key should be at least 256 bit long, making it + minimumEntropy = 32 + + // the secrets (client and global) should each have at least 16 characters making it harder to guess them + minimumSecretLength = 32 +) + +var b64 = base64.URLEncoding.WithPadding(base64.NoPadding) + +// Generate generates a token and a matching signature or returns an error. +// This method implements rfc6819 Section 5.1.4.2.2: Use High Entropy for Secrets. +func (c *HMACStrategy) Generate() (string, string, error) { + c.Lock() + defer c.Unlock() + + if len(c.GlobalSecret) < minimumSecretLength { + return "", "", errors.Errorf("secret for signing HMAC-SHA256 is expected to be 32 byte long, got %d byte", len(c.GlobalSecret)) + } + + var signingKey [32]byte + copy(signingKey[:], c.GlobalSecret) + + if c.TokenEntropy < minimumEntropy { + c.TokenEntropy = minimumEntropy + } + + // When creating secrets not intended for usage by human users (e.g., + // client secrets or token handles), the authorization server should + // include a reasonable level of entropy in order to mitigate the risk + // of guessing attacks. The token value should be >=128 bits long and + // constructed from a cryptographically strong random or pseudo-random + // number sequence (see [RFC4086] for best current practice) generated + // by the authorization server. + tokenKey, err := RandomBytes(c.TokenEntropy) + if err != nil { + return "", "", errors.WithStack(err) + } + + signature := generateHMAC(tokenKey, &signingKey) + + encodedSignature := b64.EncodeToString(signature) + encodedToken := fmt.Sprintf("%s.%s", b64.EncodeToString(tokenKey), encodedSignature) + return encodedToken, encodedSignature, nil +} + +// Validate validates a token and returns its signature or an error if the token is not valid. +func (c *HMACStrategy) Validate(token string) (err error) { + var keys [][]byte + + if len(c.GlobalSecret) > 0 { + keys = append(keys, c.GlobalSecret) + } + + if len(c.RotatedGlobalSecrets) > 0 { + keys = append(keys, c.RotatedGlobalSecrets...) + } + + for _, key := range keys { + if err = c.validate(key, token); err == nil { + return nil + } else if errors.Cause(err) == fosite.ErrTokenSignatureMismatch { + } else { + return err + } + } + + if err == nil { + return errors.New("a secret for signing HMAC-SHA256 is expected to be defined, but none were") + } + + return err +} + +func (c *HMACStrategy) validate(secret []byte, token string) error { + if len(secret) < minimumSecretLength { + return errors.Errorf("secret for signing HMAC-SHA256 is expected to be 32 byte long, got %d byte", len(secret)) + } + + var signingKey [32]byte + copy(signingKey[:], secret) + + split := strings.Split(token, ".") + if len(split) != 2 { + return errors.WithStack(fosite.ErrInvalidTokenFormat) + } + + tokenKey := split[0] + tokenSignature := split[1] + if tokenKey == "" || tokenSignature == "" { + return errors.WithStack(fosite.ErrInvalidTokenFormat) + } + + decodedTokenSignature, err := b64.DecodeString(tokenSignature) + if err != nil { + return errors.WithStack(err) + } + + decodedTokenKey, err := b64.DecodeString(tokenKey) + if err != nil { + return errors.WithStack(err) + } + + expectedMAC := generateHMAC(decodedTokenKey, &signingKey) + if !hmac.Equal(expectedMAC, decodedTokenSignature) { + // Hash is invalid + return errors.WithStack(fosite.ErrTokenSignatureMismatch) + } + + return nil +} + +func (c *HMACStrategy) Signature(token string) string { + split := strings.Split(token, ".") + + if len(split) != 2 { + return "" + } + + return split[1] +} + +func generateHMAC(data []byte, key *[32]byte) []byte { + h := hmac.New(sha512.New512_256, key[:]) + h.Write(data) + return h.Sum(nil) +} diff --git a/vendor/github.com/ory/fosite/token/jwt/claims.go b/vendor/github.com/ory/fosite/token/jwt/claims.go new file mode 100644 index 0000000000..8ea5efb6dd --- /dev/null +++ b/vendor/github.com/ory/fosite/token/jwt/claims.go @@ -0,0 +1,95 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package jwt + +import "time" + +// Mapper is the interface used internally to map key-value pairs +type Mapper interface { + ToMap() map[string]interface{} + Add(key string, value interface{}) + Get(key string) interface{} +} + +// ToString will return a string representation of a map +func ToString(i interface{}) string { + if i == nil { + return "" + } + + if s, ok := i.(string); ok { + return s + } + + if sl, ok := i.([]string); ok { + if len(sl) == 1 { + return sl[0] + } + } + + return "" +} + +// ToTime will try to convert a given input to a time.Time structure +func ToTime(i interface{}) time.Time { + if i == nil { + return time.Time{} + } + + if t, ok := i.(int64); ok { + return time.Unix(t, 0).UTC() + } else if t, ok := i.(float64); ok { + return time.Unix(int64(t), 0).UTC() + } else if t, ok := i.(time.Time); ok { + return t + } + + return time.Time{} +} + +// Filter will filter out elemets based on keys in a given input map na key-slice +func Filter(elements map[string]interface{}, keys ...string) map[string]interface{} { + var keyIdx = make(map[string]bool) + var result = make(map[string]interface{}) + + for _, key := range keys { + keyIdx[key] = true + } + + for k, e := range elements { + if _, ok := keyIdx[k]; !ok { + result[k] = e + } + } + + return result +} + +// Copy will copy all elements in a map and return a new representational map +func Copy(elements map[string]interface{}) (result map[string]interface{}) { + result = make(map[string]interface{}, len(elements)) + for k, v := range elements { + result[k] = v + } + + return result +} diff --git a/vendor/github.com/ory/fosite/token/jwt/claims_id_token.go b/vendor/github.com/ory/fosite/token/jwt/claims_id_token.go new file mode 100644 index 0000000000..8eadc5e53c --- /dev/null +++ b/vendor/github.com/ory/fosite/token/jwt/claims_id_token.go @@ -0,0 +1,113 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package jwt + +import ( + "time" + + jwt "github.com/dgrijalva/jwt-go" + "github.com/pborman/uuid" +) + +// IDTokenClaims represent the claims used in open id connect requests +type IDTokenClaims struct { + JTI string + Issuer string + Subject string + Audience []string + Nonce string + ExpiresAt time.Time + IssuedAt time.Time + RequestedAt time.Time + AuthTime time.Time + AccessTokenHash string + AuthenticationContextClassReference string + AuthenticationMethodsReference string + CodeHash string + Extra map[string]interface{} +} + +// ToMap will transform the headers to a map structure +func (c *IDTokenClaims) ToMap() map[string]interface{} { + var ret = Copy(c.Extra) + ret["sub"] = c.Subject + ret["iss"] = c.Issuer + ret["jti"] = c.JTI + + if len(c.Audience) > 0 { + ret["aud"] = c.Audience + } else { + ret["aud"] = []string{} + } + + if len(c.Nonce) >= 0 { + ret["nonce"] = c.Nonce + } + + if len(c.AccessTokenHash) > 0 { + ret["at_hash"] = c.AccessTokenHash + } + + if len(c.JTI) == 0 { + ret["jti"] = uuid.New() + } + + if len(c.CodeHash) > 0 { + ret["c_hash"] = c.CodeHash + } + + if !c.AuthTime.IsZero() { + ret["auth_time"] = c.AuthTime.Unix() + } + + if len(c.AuthenticationContextClassReference) > 0 { + ret["acr"] = c.AuthenticationContextClassReference + } + + if len(c.AuthenticationMethodsReference) > 0 { + ret["amr"] = c.AuthenticationMethodsReference + } + + ret["iat"] = float64(c.IssuedAt.Unix()) + ret["exp"] = float64(c.ExpiresAt.Unix()) + ret["rat"] = float64(c.RequestedAt.Unix()) + return ret + +} + +// Add will add a key-value pair to the extra field +func (c *IDTokenClaims) Add(key string, value interface{}) { + if c.Extra == nil { + c.Extra = make(map[string]interface{}) + } + c.Extra[key] = value +} + +// Get will get a value from the extra field based on a given key +func (c *IDTokenClaims) Get(key string) interface{} { + return c.ToMap()[key] +} + +// ToMapClaims will return a jwt-go MapClaims representation +func (c IDTokenClaims) ToMapClaims() jwt.MapClaims { + return c.ToMap() +} diff --git a/vendor/github.com/ory/fosite/token/jwt/claims_jwt.go b/vendor/github.com/ory/fosite/token/jwt/claims_jwt.go new file mode 100644 index 0000000000..5755a46e5f --- /dev/null +++ b/vendor/github.com/ory/fosite/token/jwt/claims_jwt.go @@ -0,0 +1,194 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package jwt + +import ( + "time" + + jwt "github.com/dgrijalva/jwt-go" + "github.com/pborman/uuid" +) + +type JWTClaimsDefaults struct { + ExpiresAt time.Time + IssuedAt time.Time + Issuer string + Scope []string +} + +type JWTClaimsContainer interface { + // With returns a copy of itself with expiresAt, scope, audience set to the given values. + With(expiry time.Time, scope, audience []string) JWTClaimsContainer + + // WithDefaults returns a copy of itself with issuedAt and issuer set to the given default values. If those + // values are already set in the claims, they will not be updated. + WithDefaults(iat time.Time, issuer string) JWTClaimsContainer + + // ToMapClaims returns the claims as a github.com/dgrijalva/jwt-go.MapClaims type. + ToMapClaims() jwt.MapClaims +} + +// JWTClaims represent a token's claims. +type JWTClaims struct { + Subject string + Issuer string + Audience []string + JTI string + IssuedAt time.Time + NotBefore time.Time + ExpiresAt time.Time + Scope []string + Extra map[string]interface{} +} + +func (c *JWTClaims) With(expiry time.Time, scope, audience []string) JWTClaimsContainer { + c.ExpiresAt = expiry + c.Scope = scope + c.Audience = audience + return c +} + +func (c *JWTClaims) WithDefaults(iat time.Time, issuer string) JWTClaimsContainer { + if c.IssuedAt.IsZero() { + c.IssuedAt = iat + } + + if c.Issuer == "" { + c.Issuer = issuer + } + return c +} + +// ToMap will transform the headers to a map structure +func (c *JWTClaims) ToMap() map[string]interface{} { + var ret = Copy(c.Extra) + + ret["jti"] = c.JTI + if c.JTI == "" { + ret["jti"] = uuid.New() + } + + ret["sub"] = c.Subject + ret["iss"] = c.Issuer + ret["aud"] = c.Audience + + if !c.IssuedAt.IsZero() { + ret["iat"] = float64(c.IssuedAt.Unix()) // jwt-go does not support int64 as datatype + } + + if !c.NotBefore.IsZero() { + ret["nbf"] = float64(c.NotBefore.Unix()) // jwt-go does not support int64 as datatype + } + + ret["exp"] = float64(c.ExpiresAt.Unix()) // jwt-go does not support int64 as datatype + + if c.Scope != nil { + ret["scp"] = c.Scope + } + + return ret +} + +// FromMap will set the claims based on a mapping +func (c *JWTClaims) FromMap(m map[string]interface{}) { + c.Extra = make(map[string]interface{}) + for k, v := range m { + switch k { + case "jti": + if s, ok := v.(string); ok { + c.JTI = s + } + case "sub": + if s, ok := v.(string); ok { + c.Subject = s + } + case "iss": + if s, ok := v.(string); ok { + c.Issuer = s + } + case "aud": + if s, ok := v.(string); ok { + c.Audience = []string{s} + } else if s, ok := v.([]string); ok { + c.Audience = s + } + case "iat": + switch v.(type) { + case float64: + c.IssuedAt = time.Unix(int64(v.(float64)), 0).UTC() + case int64: + c.IssuedAt = time.Unix(v.(int64), 0).UTC() + } + case "nbf": + switch v.(type) { + case float64: + c.NotBefore = time.Unix(int64(v.(float64)), 0).UTC() + case int64: + c.NotBefore = time.Unix(v.(int64), 0).UTC() + } + case "exp": + switch v.(type) { + case float64: + c.ExpiresAt = time.Unix(int64(v.(float64)), 0).UTC() + case int64: + c.ExpiresAt = time.Unix(v.(int64), 0).UTC() + } + case "scp": + switch v.(type) { + case []string: + c.Scope = v.([]string) + case []interface{}: + c.Scope = make([]string, len(v.([]interface{}))) + for i, vi := range v.([]interface{}) { + if s, ok := vi.(string); ok { + c.Scope[i] = s + } + } + } + default: + c.Extra[k] = v + } + } +} + +// Add will add a key-value pair to the extra field +func (c *JWTClaims) Add(key string, value interface{}) { + if c.Extra == nil { + c.Extra = make(map[string]interface{}) + } + c.Extra[key] = value +} + +// Get will get a value from the extra field based on a given key +func (c JWTClaims) Get(key string) interface{} { + return c.ToMap()[key] +} + +// ToMapClaims will return a jwt-go MapClaims representation +func (c JWTClaims) ToMapClaims() jwt.MapClaims { + return c.ToMap() +} + +// FromMapClaims will populate claims from a jwt-go MapClaims representation +func (c *JWTClaims) FromMapClaims(mc jwt.MapClaims) { + c.FromMap(mc) +} diff --git a/vendor/github.com/ory/fosite/token/jwt/header.go b/vendor/github.com/ory/fosite/token/jwt/header.go new file mode 100644 index 0000000000..01e8916bc3 --- /dev/null +++ b/vendor/github.com/ory/fosite/token/jwt/header.go @@ -0,0 +1,66 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package jwt + +import jwt "github.com/dgrijalva/jwt-go" + +// Headers is the jwt headers +type Headers struct { + Extra map[string]interface{} +} + +func NewHeaders() *Headers { + return &Headers{Extra: map[string]interface{}{}} +} + +// ToMap will transform the headers to a map structure +func (h *Headers) ToMap() map[string]interface{} { + var filter = map[string]bool{"alg": true, "typ": true} + var extra = map[string]interface{}{} + + // filter known values from extra. + for k, v := range h.Extra { + if _, ok := filter[k]; !ok { + extra[k] = v + } + } + + return extra +} + +// Add will add a key-value pair to the extra field +func (h *Headers) Add(key string, value interface{}) { + if h.Extra == nil { + h.Extra = make(map[string]interface{}) + } + h.Extra[key] = value +} + +// Get will get a value from the extra field based on a given key +func (h *Headers) Get(key string) interface{} { + return h.Extra[key] +} + +// ToMapClaims will return a jwt-go MapClaims representaion +func (h Headers) ToMapClaims() jwt.MapClaims { + return h.ToMap() +} diff --git a/vendor/github.com/ory/fosite/token/jwt/jwt.go b/vendor/github.com/ory/fosite/token/jwt/jwt.go new file mode 100644 index 0000000000..5ac82b13fb --- /dev/null +++ b/vendor/github.com/ory/fosite/token/jwt/jwt.go @@ -0,0 +1,218 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +// Package jwt is able to generate and validate json web tokens. +// Follows https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32 + +package jwt + +import ( + "context" + "crypto/ecdsa" + "crypto/rsa" + "crypto/sha256" + "fmt" + "strings" + + jwt "github.com/dgrijalva/jwt-go" + "github.com/pkg/errors" + + "github.com/ory/fosite" +) + +type JWTStrategy interface { + Generate(ctx context.Context, claims jwt.Claims, header Mapper) (string, string, error) + Validate(ctx context.Context, token string) (string, error) + Hash(ctx context.Context, in []byte) ([]byte, error) + Decode(ctx context.Context, token string) (*jwt.Token, error) + GetSignature(ctx context.Context, token string) (string, error) + GetSigningMethodLength() int +} + +// RS256JWTStrategy is responsible for generating and validating JWT challenges +type RS256JWTStrategy struct { + PrivateKey *rsa.PrivateKey +} + +// Generate generates a new authorize code or returns an error. set secret +func (j *RS256JWTStrategy) Generate(ctx context.Context, claims jwt.Claims, header Mapper) (string, string, error) { + if header == nil || claims == nil { + return "", "", errors.New("Either claims or header is nil.") + } + + token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + token.Header = assign(token.Header, header.ToMap()) + + var sig, sstr string + var err error + if sstr, err = token.SigningString(); err != nil { + return "", "", errors.WithStack(err) + } + + if sig, err = token.Method.Sign(sstr, j.PrivateKey); err != nil { + return "", "", errors.WithStack(err) + } + + return fmt.Sprintf("%s.%s", sstr, sig), sig, nil +} + +// Validate validates a token and returns its signature or an error if the token is not valid. +func (j *RS256JWTStrategy) Validate(ctx context.Context, token string) (string, error) { + if _, err := j.Decode(ctx, token); err != nil { + return "", errors.WithStack(err) + } + + return j.GetSignature(ctx, token) +} + +// Decode will decode a JWT token +func (j *RS256JWTStrategy) Decode(ctx context.Context, token string) (*jwt.Token, error) { + // Parse the token. + parsedToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { + if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok { + return nil, errors.Errorf("Unexpected signing method: %v", t.Header["alg"]) + } + return &j.PrivateKey.PublicKey, nil + }) + + if err != nil { + return parsedToken, errors.WithStack(err) + } else if !parsedToken.Valid { + return parsedToken, errors.WithStack(fosite.ErrInactiveToken) + } + + return parsedToken, err +} + +// GetSignature will return the signature of a token +func (j *RS256JWTStrategy) GetSignature(ctx context.Context, token string) (string, error) { + split := strings.Split(token, ".") + if len(split) != 3 { + return "", errors.New("Header, body and signature must all be set") + } + return split[2], nil +} + +// Hash will return a given hash based on the byte input or an error upon fail +func (j *RS256JWTStrategy) Hash(ctx context.Context, in []byte) ([]byte, error) { + // SigningMethodRS256 + hash := sha256.New() + _, err := hash.Write(in) + if err != nil { + return []byte{}, errors.WithStack(err) + } + return hash.Sum([]byte{}), nil +} + +// GetSigningMethodLength will return the length of the signing method +func (j *RS256JWTStrategy) GetSigningMethodLength() int { + return jwt.SigningMethodRS256.Hash.Size() +} + +// ES256JWTStrategy is responsible for generating and validating JWT challenges +type ES256JWTStrategy struct { + PrivateKey *ecdsa.PrivateKey +} + +// Generate generates a new authorize code or returns an error. set secret +func (j *ES256JWTStrategy) Generate(ctx context.Context, claims jwt.Claims, header Mapper) (string, string, error) { + if header == nil || claims == nil { + return "", "", errors.New("Either claims or header is nil.") + } + + token := jwt.NewWithClaims(jwt.SigningMethodES256, claims) + token.Header = assign(token.Header, header.ToMap()) + + var sig, sstr string + var err error + if sstr, err = token.SigningString(); err != nil { + return "", "", errors.WithStack(err) + } + + if sig, err = token.Method.Sign(sstr, j.PrivateKey); err != nil { + return "", "", errors.WithStack(err) + } + + return fmt.Sprintf("%s.%s", sstr, sig), sig, nil +} + +// Validate validates a token and returns its signature or an error if the token is not valid. +func (j *ES256JWTStrategy) Validate(ctx context.Context, token string) (string, error) { + if _, err := j.Decode(ctx, token); err != nil { + return "", errors.WithStack(err) + } + + return j.GetSignature(ctx, token) +} + +// Decode will decode a JWT token +func (j *ES256JWTStrategy) Decode(ctx context.Context, token string) (*jwt.Token, error) { + // Parse the token. + parsedToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { + if _, ok := t.Method.(*jwt.SigningMethodECDSA); !ok { + return nil, errors.Errorf("Unexpected signing method: %v", t.Header["alg"]) + } + return &j.PrivateKey.PublicKey, nil + }) + + if err != nil { + return parsedToken, errors.WithStack(err) + } else if !parsedToken.Valid { + return parsedToken, errors.WithStack(fosite.ErrInactiveToken) + } + + return parsedToken, err +} + +// GetSignature will return the signature of a token +func (j *ES256JWTStrategy) GetSignature(ctx context.Context, token string) (string, error) { + split := strings.Split(token, ".") + if len(split) != 3 { + return "", errors.New("Header, body and signature must all be set") + } + return split[2], nil +} + +// Hash will return a given hash based on the byte input or an error upon fail +func (j *ES256JWTStrategy) Hash(ctx context.Context, in []byte) ([]byte, error) { + // SigningMethodES256 + hash := sha256.New() + _, err := hash.Write(in) + if err != nil { + return []byte{}, errors.WithStack(err) + } + return hash.Sum([]byte{}), nil +} + +// GetSigningMethodLength will return the length of the signing method +func (j *ES256JWTStrategy) GetSigningMethodLength() int { + return jwt.SigningMethodES256.Hash.Size() +} + +func assign(a, b map[string]interface{}) map[string]interface{} { + for k, w := range b { + if _, ok := a[k]; ok { + continue + } + a[k] = w + } + return a +} diff --git a/vendor/github.com/ory/fosite/tools.go b/vendor/github.com/ory/fosite/tools.go new file mode 100644 index 0000000000..cadb559da4 --- /dev/null +++ b/vendor/github.com/ory/fosite/tools.go @@ -0,0 +1,9 @@ +// +build tools + +package fosite + +import ( + _ "github.com/mattn/goveralls" + + _ "github.com/ory/go-acc" +) diff --git a/vendor/github.com/ory/go-acc/.gitignore b/vendor/github.com/ory/go-acc/.gitignore new file mode 100644 index 0000000000..80e850b87c --- /dev/null +++ b/vendor/github.com/ory/go-acc/.gitignore @@ -0,0 +1,7 @@ +.idea +*.iml +.cover +*.log +*.exe +cover.out +vendor/ \ No newline at end of file diff --git a/vendor/github.com/ory/go-acc/.travis.yml b/vendor/github.com/ory/go-acc/.travis.yml new file mode 100644 index 0000000000..06d53a1b0d --- /dev/null +++ b/vendor/github.com/ory/go-acc/.travis.yml @@ -0,0 +1,18 @@ +language: go + +go_import_path: github.com/ory/go-acc + +go: + - 1.8 + +env: + - GO15VENDOREXPERIMENT=1 + +install: + - go get ./... + +script: + - go install . + - go-acc github.com/ory/go-acc + - go-acc github.com/ory/go-acc/... + - go-acc $(go list github.com/ory/go-acc/...) \ No newline at end of file diff --git a/vendor/github.com/ory/go-acc/CONTRIBUTING.md b/vendor/github.com/ory/go-acc/CONTRIBUTING.md new file mode 100644 index 0000000000..38f527dfa8 --- /dev/null +++ b/vendor/github.com/ory/go-acc/CONTRIBUTING.md @@ -0,0 +1,119 @@ +# Contribution Guide + +We welcome and encourage community contributions to this project. + +Since the project is still unstable, there are specific priorities for development. Pull requests that do not address these priorities will not be accepted until this project is production ready. + +Please familiarize yourself with the Contribution Guidelines and Project Roadmap before contributing. + +There are many ways to help this projects besides contributing code: + + - Fix bugs or file issues + - Improve the documentation + + + +**Table of Contents** + +- [Contributing Code](#contributing-code) +- [Code Style](#code-style) +- [Developer’s Certificate of Origin](#developer%E2%80%99s-certificate-of-origin) +- [Pull request procedure](#pull-request-procedure) +- [Conduct](#conduct) + + + +## Contributing Code + +Unless you are fixing a known bug, we **strongly** recommend discussing it with the core team via a GitHub issue before getting started to ensure your work is consistent with this project's roadmap and architecture. + +All contributions are made via pull request. Note that **all patches from all contributors get reviewed**. After a pull request is made other contributors will offer feedback, and if the patch passes review a maintainer will accept it with a comment. When pull requests fail testing, authors are expected to update their pull requests to address the failures until the tests pass and the pull request merges successfully. + +At least one review from a maintainer is required for all patches (even patches from maintainers). + +Reviewers should leave a "LGTM" comment once they are satisfied with the patch. If the patch was submitted by a maintainer with write access, the pull request should be merged by the submitter after review. + +## Code Style + +Please follow these guidelines when formatting source code: + +* Go code should match the output of `gofmt -s` + +## Developer’s Certificate of Origin + +All contributions must include acceptance of the DCO: + +```text +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +To accept the DCO, simply add this line to each commit message with your name and email address (`git commit -s` will do this for you): + +```text +Signed-off-by: Jane Example +``` + +For legal reasons, no anonymous or pseudonymous contributions are accepted ([contact us](mailto:aeneas@ory.am) if this is an issue). + +## Pull request procedure + +To make a pull request, you will need a GitHub account; if you are unclear on this process, see GitHub's documentation on [forking](https://help.github.com/articles/fork-a-repo) and [pull requests](https://help.github.com/articles/using-pull-requests). Pull requests should be targeted at the `master` branch. Before creating a pull request, go through this checklist: + +1. Create a feature branch off of `master` so that changes do not get mixed up. +1. [Rebase](https://git-scm.com/book/en/Git-Branching-Rebasing) your local changes against the `master` branch. +1. Run the full project test suite with the `go test $(glide novendor)` (or equivalent) command and confirm that it passes. +1. Run `gofmt -s` (if the project is written in Go). +1. Accept the Developer's Certificate of Origin on all commits (see above). +1. Ensure that each commit has a subsystem prefix (ex: `controller: `). + +Pull requests will be treated as "review requests," and maintainers will give feedback on the style and substance of the patch. + +Normally, all pull requests must include tests that test your change. Occasionally, a change will be very difficult to test for. In those cases, please include a note in your commit message explaining why. + +## Conduct + +Whether you are a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristic. +* Please avoid using nicknames that might detract from a friendly, safe and welcoming environment for all. +* Be kind and courteous. There is no need to be mean or rude. +* We will exclude you from interaction if you insult, demean or harass anyone. In particular, we do not tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or a member of this project's core team immediately. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome. + +We welcome discussion about creating a welcoming, safe, and productive environment for the community. If you have any questions, feedback, or concerns please let us know with a GitHub issue. diff --git a/vendor/github.com/ory/go-acc/LICENSE b/vendor/github.com/ory/go-acc/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/github.com/ory/go-acc/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ory/go-acc/README.md b/vendor/github.com/ory/go-acc/README.md new file mode 100644 index 0000000000..17ebeed2c8 --- /dev/null +++ b/vendor/github.com/ory/go-acc/README.md @@ -0,0 +1,33 @@ +# go-acc + +A tool for reporting accurate Code Coverage in Golang. It is a cross platform (osx, windows, linux) adaption of the following bash script: + +```bash +touch ./coverage.tmp +echo 'mode: atomic' > coverage.txt +go list ./... | grep -v /cmd | grep -v /vendor | xargs -n1 -I{} sh -c 'go test -race -covermode=atomic -coverprofile=coverage.tmp -coverpkg $(go list ./... | grep -v /vendor | tr "\n" ",") {} && tail -n +2 coverage.tmp >> coverage.txt || exit 255' && rm coverage.tmp +``` + +## Installation & Usage + +``` +$ go get github.com/ory/go-acc +$ go-acc +A tool for reporting accurate Code Coverage in Golang. + +Usage: + go-acc [flags] + +Examples: +$ go-acc github.com/some/package +$ go-acc -o my-coverfile.txt github.com/some/package +$ go-acc ./... +$ go-acc $(glide novendor) + +Flags: + --covermode string Which code coverage mode to use (default "atomic") + --ignore strings Will ignore packages that contains any of these strings + -o, --output string Location for the output file (default "coverage.txt") + -t, --toggle Help message for toggle + +``` diff --git a/vendor/github.com/ory/go-acc/cmd/root.go b/vendor/github.com/ory/go-acc/cmd/root.go new file mode 100644 index 0000000000..99958c7b0c --- /dev/null +++ b/vendor/github.com/ory/go-acc/cmd/root.go @@ -0,0 +1,234 @@ +package cmd + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + + "github.com/ory/x/cmdx" + "github.com/ory/x/flagx" + "github.com/pborman/uuid" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// RootCmd represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "go-acc ", + Short: "Receive accurate code coverage reports for Golang (Go)", + Args: cobra.MinimumNArgs(1), + Example: `$ go-acc github.com/some/package +$ go-acc -o my-coverfile.txt github.com/some/package +$ go-acc ./... +$ go-acc $(glide novendor) +$ go-acc --ignore pkga,pkgb . + +You can pass all flags defined by "go test" after "--": +$ go-acc . -- -short -v -failfast + +You can pick an alternative go test binary using: + +GO_TEST_BINARY="go test" +GO_TEST_BINARY="gotest" +`, + Run: func(cmd *cobra.Command, args []string) { + mode := flagx.MustGetString(cmd, "covermode") + if flagx.MustGetBool(cmd, "verbose") { + fmt.Println("Flag -v has been deprecated, use `go-acc -- -v` instead!") + } + + ignores := flagx.MustGetStringSlice(cmd, "ignore") + payload := "mode: " + mode + "\n" + + var packages []string + var passthrough []string + + for _, a := range args { + if len(a) == 0 { + continue + } + + // The first tag indicates that we're now passing through all tags + if a[0] == '-' || len(passthrough) > 0 { + passthrough = append(passthrough, a) + continue + } + + if len(a) > 4 && a[len(a)-4:] == "/..." { + var buf bytes.Buffer + c := exec.Command("go", "list", a) + c.Stdout = &buf + c.Stderr = &buf + cmdx.Must(c.Run(), "unable to run go list") + + var add []string + for _, s := range strings.Split(buf.String(), "\n") { + // Remove go system messages, e.g. messages from go mod like + // go: finding ... + // go: downloading ... + // go: extracting ... + if len(s) > 0 && !strings.HasPrefix(s, "go: ") { + // Test if package name contains ignore string + ignore := false + for _, ignoreStr := range ignores { + if strings.Contains(s, ignoreStr) { + ignore = true + break + } + } + + if !ignore { + add = append(add, s) + } + } + } + + packages = append(packages, add...) + } else { + packages = append(packages, a) + } + } + + files := make([]string, len(packages)) + for k, pkg := range packages { + files[k] = filepath.Join(os.TempDir(), uuid.New()) + ".cc.tmp" + + gotest := os.Getenv("GO_TEST_BINARY") + if gotest == "" { + gotest = "go test" + } + + gt := strings.Split(gotest, " ") + if len(gt) != 2 { + gt = append(gt, "") + } + + var c *exec.Cmd + ca := append(append( + []string{ + gt[1], + "-covermode=" + mode, + "-coverprofile=" + files[k], + "-coverpkg=" + strings.Join(packages, ","), + }, + passthrough...), + pkg) + c = exec.Command(gt[0], ca...) + + stderr, err := c.StderrPipe() + if err != nil { + fatalf("%s", err) + } + stdout, err := c.StdoutPipe() + if err != nil { + fatalf("%s", err) + } + + if err := c.Start(); err != nil { + fatalf("%s", err) + } + + var wg sync.WaitGroup + wg.Add(2) + go scan(&wg, stderr) + go scan(&wg, stdout) + + if err := c.Wait(); err != nil { + fatalf("%s", err) + } + + wg.Wait() + } + + for _, file := range files { + if _, err := os.Stat(file); os.IsNotExist(err) { + continue + } + + p, err := ioutil.ReadFile(file) + if err != nil { + fatalf("%s", err) + } + + ps := strings.Split(string(p), "\n") + payload += strings.Join(ps[1:], "\n") + } + + output, err := cmd.Flags().GetString("output") + if err != nil { + fatalf("%s", err) + } + + if err := ioutil.WriteFile(output, []byte(payload), 0644); err != nil { + fatalf("%s", err) + } + }, +} + +func scan(wg *sync.WaitGroup, r io.ReadCloser) { + defer wg.Done() + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "warning: no packages being tested depend on matches for pattern") { + continue + } + fmt.Println(strings.Split(line, "% of statements in")[0]) + } +} + +// Execute adds all child commands to the root command sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + if err := RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + RootCmd.Flags().BoolP("verbose", "v", false, "Does nothing, there for compatibility") + RootCmd.Flags().StringP("output", "o", "coverage.txt", "Location for the output file") + RootCmd.Flags().String("covermode", "atomic", "Which code coverage mode to use") + RootCmd.Flags().StringSlice("ignore", []string{}, "Will ignore packages that contains any of these strings") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + viper.AutomaticEnv() // read in environment variables that match + +} + +func fatalf(msg string, args ...interface{}) { + fmt.Printf(msg, args...) + fmt.Println("") + os.Exit(1) +} + +type filter struct { + dtl io.Writer +} + +func (f *filter) Write(p []byte) (n int, err error) { + for _, ppp := range strings.Split(string(p), "\n") { + if strings.Contains(ppp, "warning: no packages being tested depend on matches for pattern") { + continue + } else { + nn, err := f.dtl.Write(p) + n = n + nn + if err != nil { + return n, err + } + } + } + return len(p), nil +} diff --git a/vendor/github.com/ory/go-acc/coverage.txt b/vendor/github.com/ory/go-acc/coverage.txt new file mode 100644 index 0000000000..79b28a0b6b --- /dev/null +++ b/vendor/github.com/ory/go-acc/coverage.txt @@ -0,0 +1 @@ +mode: atomic diff --git a/vendor/github.com/ory/go-acc/go.mod b/vendor/github.com/ory/go-acc/go.mod new file mode 100644 index 0000000000..34f4905ea3 --- /dev/null +++ b/vendor/github.com/ory/go-acc/go.mod @@ -0,0 +1,10 @@ +module github.com/ory/go-acc + +require ( + github.com/ory/x v0.0.85 + github.com/pborman/uuid v1.2.0 + github.com/spf13/cobra v0.0.5 + github.com/spf13/viper v1.3.2 +) + +go 1.13 diff --git a/vendor/github.com/ory/go-acc/go.sum b/vendor/github.com/ory/go-acc/go.sum new file mode 100644 index 0000000000..8ad7d8247d --- /dev/null +++ b/vendor/github.com/ory/go-acc/go.sum @@ -0,0 +1,680 @@ +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.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= +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/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= +github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY= +github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4= +github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs= +github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4= +github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY= +github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w= +github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI= +github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI= +github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk= +github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw= +github.com/gobuffalo/buffalo-plugins v1.6.11/go.mod h1:eAA6xJIL8OuynJZ8amXjRmHND6YiusVAaJdHDN1Lu8Q= +github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGpjlKoAcAANdCgoR960= +github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U= +github.com/gobuffalo/buffalo-plugins v1.9.4/go.mod h1:grCV6DGsQlVzQwk6XdgcL3ZPgLm9BVxlBmXPMF8oBHI= +github.com/gobuffalo/buffalo-plugins v1.10.0/go.mod h1:4osg8d9s60txLuGwXnqH+RCjPHj9K466cDFRl3PErHI= +github.com/gobuffalo/buffalo-plugins v1.11.0/go.mod h1:rtIvAYRjYibgmWhnjKmo7OadtnxuMG5ZQLr25ozAzjg= +github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8= +github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc= +github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.6.10/go.mod h1:X0CFllQjTV5ogsnUrg+Oks2yTI+PU2dGYBJOEI2D1Uo= +github.com/gobuffalo/envy v1.6.11/go.mod h1:Fiq52W7nrHGDggFPhn2ZCcHw4u/rqXkqo+i7FB6EAcg= +github.com/gobuffalo/envy v1.6.12/go.mod h1:qJNrJhKkZpEW0glh5xP2syQHH5kgdmgsKss2Kk8PTP0= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw= +github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ= +github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs= +github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk= +github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A= +github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0= +github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY= +github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8= +github.com/gobuffalo/events v1.1.9/go.mod h1:/0nf8lMtP5TkgNbzYxR6Bl4GzBy5s5TebgNTdRfRbPM= +github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc= +github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= +github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI= +github.com/gobuffalo/flect v0.0.0-20181210151238-24a2b68e0316/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= +github.com/gobuffalo/flect v0.0.0-20190104192022-4af577e09bf2/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= +github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794/go.mod h1:397QT6v05LkZkn07oJXXT6y9FCfwC8Pug0WA2/2mE9k= +github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g= +github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= +github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= +github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= +github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= +github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= +github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE= +github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI= +github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA= +github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w= +github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU= +github.com/gobuffalo/genny v0.0.0-20181107223128-f18346459dbe/go.mod h1:utQD3aKKEsdb03oR+Vi/6ztQb1j7pO10N3OBoowRcSU= +github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng= +github.com/gobuffalo/genny v0.0.0-20181119162812-e8ff4adce8bb/go.mod h1:BA9htSe4bZwBDJLe8CUkoqkypq3hn3+CkoHqVOW718E= +github.com/gobuffalo/genny v0.0.0-20181127225641-2d959acc795b/go.mod h1:l54xLXNkteX/PdZ+HlgPk1qtcrgeOr3XUBBPDbH+7CQ= +github.com/gobuffalo/genny v0.0.0-20181128191930-77e34f71ba2a/go.mod h1:FW/D9p7cEEOqxYA71/hnrkOWm62JZ5ZNxcNIVJEaWBU= +github.com/gobuffalo/genny v0.0.0-20181203165245-fda8bcce96b1/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= +github.com/gobuffalo/genny v0.0.0-20181203201232-849d2c9534ea/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= +github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= +github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8= +github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM= +github.com/gobuffalo/genny v0.0.0-20190104222617-a71664fc38e7/go.mod h1:QPsQ1FnhEsiU8f+O0qKWXz2RE4TiDqLVChWkBuh1WaY= +github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5/go.mod h1:CIaHCrSIuJ4il6ka3Hub4DR4adDrGoXGEEt2FbBxoIo= +github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I= +github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY= +github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI= +github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E= +github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w= +github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw= +github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0= +github.com/gobuffalo/licenser v0.0.0-20181109171355-91a2a7aac9a7/go.mod h1:m+Ygox92pi9bdg+gVaycvqE8RVSjZp7mWw75+K5NPHk= +github.com/gobuffalo/licenser v0.0.0-20181128165715-cc7305f8abed/go.mod h1:oU9F9UCE+AzI/MueCKZamsezGOOHfSirltllOVeRTAE= +github.com/gobuffalo/licenser v0.0.0-20181203160806-fe900bbede07/go.mod h1:ph6VDNvOzt1CdfaWC+9XwcBnlSTBz2j49PBwum6RFaU= +github.com/gobuffalo/licenser v0.0.0-20181211173111-f8a311c51159/go.mod h1:ve/Ue99DRuvnTaLq2zKa6F4KtHiYf7W046tDjuGYPfM= +github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo= +github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= +github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= +github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew= +github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I= +github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U= +github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw= +github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM= +github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE= +github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg= +github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE= +github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8= +github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d/go.mod h1:KKsH44nIK2gA8p0PJmRT9GvWJUdphkDUA8AJEvFWiqM= +github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0= +github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No= +github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo= +github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ= +github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4= +github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME= +github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c= +github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= +github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= +github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= +github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= +github.com/gobuffalo/packd v0.0.0-20181124090624-311c6248e5fb/go.mod h1:Foenia9ZvITEvG05ab6XpiD5EfBHPL8A6hush8SJ0o8= +github.com/gobuffalo/packd v0.0.0-20181207120301-c49825f8f6f4/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= +github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= +github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24= +github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI= +github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE= +github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU= +github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw= +github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0= +github.com/gobuffalo/packr v1.22.0/go.mod h1:Qr3Wtxr3+HuQEwWqlLnNW4t1oTvK+7Gc/Rnoi/lDFvA= +github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes= +github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc= +github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w= +github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf4wVM9HELaHEu+3fk= +github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8= +github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA= +github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8= +github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs= +github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.23+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.30+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.31+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plush v3.7.32+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= +github.com/gobuffalo/plushgen v0.0.0-20181128164830-d29dcb966cb2/go.mod h1:r9QwptTFnuvSaSRjpSp4S2/4e2D3tJhARYbvEBcKSb4= +github.com/gobuffalo/plushgen v0.0.0-20181203163832-9fc4964505c2/go.mod h1:opEdT33AA2HdrIwK1aibqnTJDVVKXC02Bar/GT1YRVs= +github.com/gobuffalo/plushgen v0.0.0-20181207152837-eedb135bd51b/go.mod h1:Lcw7HQbEVm09sAQrCLzIxuhFbB3nAgp4c55E+UlynR0= +github.com/gobuffalo/plushgen v0.0.0-20190104222512-177cd2b872b3/go.mod h1:tYxCozi8X62bpZyKXYHw1ncx2ZtT2nFvG42kuLwYjoc= +github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= +github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= +github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= +github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= +github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= +github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA= +github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc= +github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24= +github.com/gobuffalo/release v1.0.72/go.mod h1:NP5NXgg/IX3M5XmHmWR99D687/3Dt9qZtTK/Lbwc1hU= +github.com/gobuffalo/release v1.1.1/go.mod h1:Sluak1Xd6kcp6snkluR1jeXAogdJZpFFRzTYRs/2uwg= +github.com/gobuffalo/release v1.1.3/go.mod h1:CuXc5/m+4zuq8idoDt1l4va0AXAn/OSs08uHOfMVr8E= +github.com/gobuffalo/release v1.1.6/go.mod h1:18naWa3kBsqO0cItXZNJuefCKOENpbbUIqRL1g+p6z0= +github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA= +github.com/gobuffalo/syncx v0.0.0-20181120191700-98333ab04150/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags v2.0.14+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/tags v2.0.15+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= +github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= +github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= +github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= +github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc= +github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= +github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/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/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +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/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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= +github.com/google/uuid v1.1.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/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +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/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= +github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= +github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= +github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs= +github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c= +github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88= +github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk= +github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc= +github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= +github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I= +github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= +github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0= +github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4= +github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs= +github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A= +github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y= +github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= +github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28= +github.com/ory/x v0.0.85 h1:AslLr2Efv6f7AT1tzn0RuX+sOri6h74phSh5lSeMqC4= +github.com/ory/x v0.0.85/go.mod h1:s44V8t3xyjWZREcU+mWlp4h302rTuM4aLXcW+y5FbQ8= +github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +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_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= +github.com/santhosh-tekuri/jsonschema/v2 v2.1.0/go.mod h1:yzJzKUGV4RbWqWIBBP4wSOBqavX5saE02yirLS0OTyg= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= +github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= +github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= +github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.2.1 h1:bIcUwXqLseLF3BDAZduuNfekWG87ibtFxi59Bq+oI9M= +github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= +github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= +github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +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.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180830192347-182538f80094/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +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/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180816102801-aaf60122140d/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/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/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/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180831094639-fa5fdf94c789/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBmaiBH81O8BugSjHeTFg= +golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181022134430-8a28ead16f52/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181024145615-5cd93ef61a7c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026064943-731415f00dce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190116161447-11f53e031339/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-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII= +golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +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/tools v0.0.0-20180221164845-07fd8470d635/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-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181107215632-34b416bd17b3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181119130350-139d099f6620/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181127195227-b4e97c0ed882/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181203210056-e5f3ab76ea4b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181205224935-3576414c54a4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181206194817-bcd4e47d0288/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181207183836-8bc39b988060/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181212172921-837e80568c09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190102213336-ca9055ed7d04/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/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-20190118193359-16909d206f00/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-20190624190245-7f2218787638/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-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/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/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-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +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/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= +gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +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= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/vendor/github.com/ory/go-acc/main.go b/vendor/github.com/ory/go-acc/main.go new file mode 100644 index 0000000000..41b1257c71 --- /dev/null +++ b/vendor/github.com/ory/go-acc/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/ory/go-acc/cmd" + +func main() { + cmd.Execute() +} diff --git a/vendor/github.com/ory/go-convenience/LICENSE b/vendor/github.com/ory/go-convenience/LICENSE new file mode 100644 index 0000000000..8a3ab522a8 --- /dev/null +++ b/vendor/github.com/ory/go-convenience/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 ORY + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ory/go-convenience/stringslice/filter.go b/vendor/github.com/ory/go-convenience/stringslice/filter.go new file mode 100644 index 0000000000..28413c5247 --- /dev/null +++ b/vendor/github.com/ory/go-convenience/stringslice/filter.go @@ -0,0 +1,34 @@ +package stringslice + +import ( + "strings" + "unicode" +) + +// Filter applies the provided filter function and removes all items from the slice for which the filter function returns true. +// This function uses append and might cause +func Filter(values []string, filter func(string) bool) (ret []string) { + for _, value := range values { + if !filter(value) { + ret = append(ret, value) + } + } + + if ret == nil { + return []string{} + } + + return +} + +// TrimEmptyFilter applies the strings.TrimFunc function and removes all empty strings +func TrimEmptyFilter(values []string, trim func(rune) bool) (ret []string) { + return Filter(values, func(value string) bool { + return strings.TrimFunc(value, trim) == "" + }) +} + +// TrimSpaceEmptyFilter applies the strings.TrimSpace function and removes all empty strings +func TrimSpaceEmptyFilter(values []string) []string { + return TrimEmptyFilter(values, unicode.IsSpace) +} diff --git a/vendor/github.com/ory/go-convenience/stringslice/has.go b/vendor/github.com/ory/go-convenience/stringslice/has.go new file mode 100644 index 0000000000..e695fad693 --- /dev/null +++ b/vendor/github.com/ory/go-convenience/stringslice/has.go @@ -0,0 +1,23 @@ +package stringslice + +import "strings" + +// Has returns true if the needle is in the haystack (case-sensitive) +func Has(haystack []string, needle string) bool { + for _, current := range haystack { + if current == needle { + return true + } + } + return false +} + +// HasI returns true if the needle is in the haystack (case-insensitive) +func HasI(haystack []string, needle string) bool { + for _, current := range haystack { + if strings.ToLower(current) == strings.ToLower(needle) { + return true + } + } + return false +} diff --git a/vendor/github.com/ory/go-convenience/stringslice/merge.go b/vendor/github.com/ory/go-convenience/stringslice/merge.go new file mode 100644 index 0000000000..f1ff3d344e --- /dev/null +++ b/vendor/github.com/ory/go-convenience/stringslice/merge.go @@ -0,0 +1,10 @@ +package stringslice + +func Merge(parts ...[]string) []string { + var result []string + for _, part := range parts { + result = append(result, part...) + } + + return result +} diff --git a/vendor/github.com/ory/go-convenience/stringslice/unique.go b/vendor/github.com/ory/go-convenience/stringslice/unique.go new file mode 100644 index 0000000000..3320ec1d0e --- /dev/null +++ b/vendor/github.com/ory/go-convenience/stringslice/unique.go @@ -0,0 +1,15 @@ +package stringslice + +func Unique(i []string) []string { + u := make([]string, 0, len(i)) + m := make(map[string]bool) + + for _, val := range i { + if _, ok := m[val]; !ok { + m[val] = true + u = append(u, val) + } + } + + return u +} diff --git a/vendor/github.com/ory/go-convenience/stringsx/coalesce.go b/vendor/github.com/ory/go-convenience/stringsx/coalesce.go new file mode 100644 index 0000000000..3a5edc64d8 --- /dev/null +++ b/vendor/github.com/ory/go-convenience/stringsx/coalesce.go @@ -0,0 +1,11 @@ +package stringsx + +// Coalesce returns the first non-empty string value +func Coalesce(str ...string) string { + for _, s := range str { + if s != "" { + return s + } + } + return "" +} diff --git a/vendor/github.com/ory/go-convenience/stringsx/split.go b/vendor/github.com/ory/go-convenience/stringsx/split.go new file mode 100644 index 0000000000..9c6b3d5c25 --- /dev/null +++ b/vendor/github.com/ory/go-convenience/stringsx/split.go @@ -0,0 +1,13 @@ +package stringsx + +import "strings" + +// Splitx is a special case of strings.Split +// which returns an empty slice if the string is empty +func Splitx(s, sep string) []string { + if s == "" { + return []string{} + } + + return strings.Split(s, sep) +} diff --git a/vendor/github.com/ory/x/LICENSE b/vendor/github.com/ory/x/LICENSE new file mode 100644 index 0000000000..5dc7ada59c --- /dev/null +++ b/vendor/github.com/ory/x/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017-2018 Aeneas Rekkas + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ory/x/cmdx/args.go b/vendor/github.com/ory/x/cmdx/args.go new file mode 100644 index 0000000000..8158ebeee3 --- /dev/null +++ b/vendor/github.com/ory/x/cmdx/args.go @@ -0,0 +1,35 @@ +package cmdx + +import ( + "github.com/spf13/cobra" +) + +// MinArgs fatals if args does not satisfy min. +func MinArgs(cmd *cobra.Command, args []string, min int) { + if len(args) < min { + Fatalf(`%s + +Expected at least %d command line arguments but only got %d.`, cmd.UsageString(), min, len(args)) + } +} + +// ExactArgs fatals if args does not equal l. +func ExactArgs(cmd *cobra.Command, args []string, l int) { + if len(args) < l { + Fatalf(`%s + +Expected exactly %d command line arguments but got %d.`, cmd.UsageString(), l, len(args)) + } +} + +// RangeArgs fatals if args does not satisfy any of the lengths set in r. +func RangeArgs(cmd *cobra.Command, args []string, r []int) { + for _, a := range r { + if len(args) == a { + return + } + } + Fatalf(`%s + +Expected exact %v command line arguments but got %d.`, cmd.UsageString(), r, len(args)) +} diff --git a/vendor/github.com/ory/x/cmdx/env.go b/vendor/github.com/ory/x/cmdx/env.go new file mode 100644 index 0000000000..de3ac0533d --- /dev/null +++ b/vendor/github.com/ory/x/cmdx/env.go @@ -0,0 +1,28 @@ +package cmdx + +// EnvVarExamplesHelpMessage returns a string containing documentation on how to use environment variables. +func EnvVarExamplesHelpMessage(name string) string { + return `This command exposes a variety of controls via environment variables. Here are some examples on how to +configure environment variables: + +Linux / macOS: + $ export FOO=bar + $ export BAZ=bar + $ ` + name + ` ... + + $ FOO=bar BAZ=bar ` + name + ` ... + +Docker: + $ docker run -e FOO=bar -e BAZ=bar ... + +Windows (cmd): + > set FOO=bar + > set BAZ=bar + > ` + name + ` ... + +Windows (powershell): + > $env:FOO = "bar" + > $env:BAZ = "bar" + > ` + name + ` +` +} diff --git a/vendor/github.com/ory/x/cmdx/helper.go b/vendor/github.com/ory/x/cmdx/helper.go new file mode 100644 index 0000000000..aafa21f656 --- /dev/null +++ b/vendor/github.com/ory/x/cmdx/helper.go @@ -0,0 +1,81 @@ +package cmdx + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// ErrNilDependency is returned if a dependency is missing. +var ErrNilDependency = errors.New("a dependency was expected to be defined but is nil. Please open an issue with the stack trace") + +// Must fatals with the optional message if err is not nil. +func Must(err error, message string, args ...interface{}) { + if err == nil { + return + } + + _, _ = fmt.Fprintf(os.Stderr, message+"\n", args...) + os.Exit(1) +} + +// CheckResponse fatals if err is nil or the response.StatusCode does not match the expectedStatusCode +func CheckResponse(err error, expectedStatusCode int, response *http.Response) { + Must(err, "Command failed because error occurred: %s", err) + + if response.StatusCode != expectedStatusCode { + out, err := ioutil.ReadAll(response.Body) + if err != nil { + out = []byte{} + } + pretty, err := json.MarshalIndent(json.RawMessage(out), "", "\t") + if err == nil { + out = pretty + } + + Fatalf( + `Command failed because status code %d was expected but code %d was received. + +Response payload: + +%s`, + expectedStatusCode, + response.StatusCode, + out, + ) + } +} + +// FormatResponse takes an object and prints a json.MarshalIdent version of it or fatals. +func FormatResponse(o interface{}) string { + out, err := json.MarshalIndent(o, "", "\t") + Must(err, `Command failed because an error occurred while prettifying output: %s`, err) + return string(out) +} + +// Fatalf prints to os.Stderr and exists with code 1. +func Fatalf(message string, args ...interface{}) { + if len(args) > 0 { + _, _ = fmt.Fprintf(os.Stderr, message+"\n", args...) + } else { + _, _ = fmt.Fprintln(os.Stderr, message) + } + os.Exit(1) +} + +// ExpectDependency expects every dependency to be not nil or it fatals. +func ExpectDependency(logger logrus.FieldLogger, dependencies ...interface{}) { + if logger == nil { + panic("missing logger for dependency check") + } + for _, d := range dependencies { + if d == nil { + logger.WithError(errors.WithStack(ErrNilDependency)).Fatalf("A fatal issue occurred.") + } + } +} diff --git a/vendor/github.com/ory/x/cmdx/version.go b/vendor/github.com/ory/x/cmdx/version.go new file mode 100644 index 0000000000..11cfd0e519 --- /dev/null +++ b/vendor/github.com/ory/x/cmdx/version.go @@ -0,0 +1,56 @@ +/* + * Copyright © 2015-2018 Aeneas Rekkas + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Aeneas Rekkas + * @Copyright 2015-2018 Aeneas Rekkas + * @license Apache-2.0 + * + */ + +package cmdx + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +// Version returns a *cobra.Command that handles the `version` command. +func Version(gitTag, gitHash, buildTime *string) *cobra.Command { + return &cobra.Command{ + Use: "version", + Short: "Show the build version, build time, and git hash", + Run: func(cmd *cobra.Command, args []string) { + if len(*gitTag) == 0 { + fmt.Fprintln(os.Stderr, "Unable to determine version because the build process did not properly configure it.") + } else { + fmt.Printf("Version: %s\n", *gitTag) + } + + if len(*gitHash) == 0 { + fmt.Fprintln(os.Stderr, "Unable to determine build commit because the build process did not properly configure it.") + } else { + fmt.Printf("Build Commit: %s\n", *gitHash) + } + + if len(*buildTime) == 0 { + fmt.Fprintln(os.Stderr, "Unable to determine build timestamp because the build process did not properly configure it.") + } else { + fmt.Printf("Build Timestamp: %s\n", *buildTime) + } + }, + } +} diff --git a/vendor/github.com/ory/x/flagx/flagx.go b/vendor/github.com/ory/x/flagx/flagx.go new file mode 100644 index 0000000000..54c72dc8bd --- /dev/null +++ b/vendor/github.com/ory/x/flagx/flagx.go @@ -0,0 +1,54 @@ +package flagx + +import ( + "time" + + "github.com/spf13/cobra" + + "github.com/ory/x/cmdx" +) + +// MustGetBool returns a bool flag or fatals if an error occurs. +func MustGetBool(cmd *cobra.Command, name string) bool { + ok, err := cmd.Flags().GetBool(name) + if err != nil { + cmdx.Fatalf(err.Error()) + } + return ok +} + +// MustGetString returns a string flag or fatals if an error occurs. +func MustGetString(cmd *cobra.Command, name string) string { + s, err := cmd.Flags().GetString(name) + if err != nil { + cmdx.Fatalf(err.Error()) + } + return s +} + +// MustGetDuration returns a time.Duration flag or fatals if an error occurs. +func MustGetDuration(cmd *cobra.Command, name string) time.Duration { + d, err := cmd.Flags().GetDuration(name) + if err != nil { + cmdx.Fatalf(err.Error()) + } + return d +} + +// MustGetStringSlice returns a []string flag or fatals if an error occurs. +func MustGetStringSlice(cmd *cobra.Command, name string) []string { + ss, err := cmd.Flags().GetStringSlice(name) + if err != nil { + cmdx.Fatalf(err.Error()) + } + return ss +} + +// MustGetInt returns a int flag or fatals if an error occurs. +func MustGetInt(cmd *cobra.Command, name string) int { + ss, err := cmd.Flags().GetInt(name) + if err != nil { + cmdx.Fatalf(err.Error()) + } + return ss +} diff --git a/vendor/github.com/pborman/uuid/.travis.yml b/vendor/github.com/pborman/uuid/.travis.yml new file mode 100644 index 0000000000..3deb4a1243 --- /dev/null +++ b/vendor/github.com/pborman/uuid/.travis.yml @@ -0,0 +1,10 @@ +language: go + +go: + - "1.9" + - "1.10" + - "1.11" + - tip + +script: + - go test -v ./... diff --git a/vendor/github.com/pborman/uuid/CONTRIBUTING.md b/vendor/github.com/pborman/uuid/CONTRIBUTING.md new file mode 100644 index 0000000000..04fdf09f13 --- /dev/null +++ b/vendor/github.com/pborman/uuid/CONTRIBUTING.md @@ -0,0 +1,10 @@ +# How to contribute + +We definitely welcome patches and contribution to this project! + +### Legal requirements + +In order to protect both you and ourselves, you will need to sign the +[Contributor License Agreement](https://cla.developers.google.com/clas). + +You may have already signed it for other Google projects. diff --git a/vendor/github.com/pborman/uuid/CONTRIBUTORS b/vendor/github.com/pborman/uuid/CONTRIBUTORS new file mode 100644 index 0000000000..b382a04eda --- /dev/null +++ b/vendor/github.com/pborman/uuid/CONTRIBUTORS @@ -0,0 +1 @@ +Paul Borman diff --git a/vendor/github.com/pborman/uuid/LICENSE b/vendor/github.com/pborman/uuid/LICENSE new file mode 100644 index 0000000000..5dc68268d9 --- /dev/null +++ b/vendor/github.com/pborman/uuid/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009,2014 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pborman/uuid/README.md b/vendor/github.com/pborman/uuid/README.md new file mode 100644 index 0000000000..810ad40dc9 --- /dev/null +++ b/vendor/github.com/pborman/uuid/README.md @@ -0,0 +1,15 @@ +This project was automatically exported from code.google.com/p/go-uuid + +# uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master) +The uuid package generates and inspects UUIDs based on [RFC 4122](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services. + +This package now leverages the github.com/google/uuid package (which is based off an earlier version of this package). + +###### Install +`go get github.com/pborman/uuid` + +###### Documentation +[![GoDoc](https://godoc.org/github.com/pborman/uuid?status.svg)](http://godoc.org/github.com/pborman/uuid) + +Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here: +http://godoc.org/github.com/pborman/uuid diff --git a/vendor/github.com/pborman/uuid/dce.go b/vendor/github.com/pborman/uuid/dce.go new file mode 100644 index 0000000000..50a0f2d099 --- /dev/null +++ b/vendor/github.com/pborman/uuid/dce.go @@ -0,0 +1,84 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "fmt" + "os" +) + +// A Domain represents a Version 2 domain +type Domain byte + +// Domain constants for DCE Security (Version 2) UUIDs. +const ( + Person = Domain(0) + Group = Domain(1) + Org = Domain(2) +) + +// NewDCESecurity returns a DCE Security (Version 2) UUID. +// +// The domain should be one of Person, Group or Org. +// On a POSIX system the id should be the users UID for the Person +// domain and the users GID for the Group. The meaning of id for +// the domain Org or on non-POSIX systems is site defined. +// +// For a given domain/id pair the same token may be returned for up to +// 7 minutes and 10 seconds. +func NewDCESecurity(domain Domain, id uint32) UUID { + uuid := NewUUID() + if uuid != nil { + uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 + uuid[9] = byte(domain) + binary.BigEndian.PutUint32(uuid[0:], id) + } + return uuid +} + +// NewDCEPerson returns a DCE Security (Version 2) UUID in the person +// domain with the id returned by os.Getuid. +// +// NewDCEPerson(Person, uint32(os.Getuid())) +func NewDCEPerson() UUID { + return NewDCESecurity(Person, uint32(os.Getuid())) +} + +// NewDCEGroup returns a DCE Security (Version 2) UUID in the group +// domain with the id returned by os.Getgid. +// +// NewDCEGroup(Group, uint32(os.Getgid())) +func NewDCEGroup() UUID { + return NewDCESecurity(Group, uint32(os.Getgid())) +} + +// Domain returns the domain for a Version 2 UUID or false. +func (uuid UUID) Domain() (Domain, bool) { + if v, _ := uuid.Version(); v != 2 { + return 0, false + } + return Domain(uuid[9]), true +} + +// Id returns the id for a Version 2 UUID or false. +func (uuid UUID) Id() (uint32, bool) { + if v, _ := uuid.Version(); v != 2 { + return 0, false + } + return binary.BigEndian.Uint32(uuid[0:4]), true +} + +func (d Domain) String() string { + switch d { + case Person: + return "Person" + case Group: + return "Group" + case Org: + return "Org" + } + return fmt.Sprintf("Domain%d", int(d)) +} diff --git a/vendor/github.com/pborman/uuid/doc.go b/vendor/github.com/pborman/uuid/doc.go new file mode 100644 index 0000000000..727d761674 --- /dev/null +++ b/vendor/github.com/pborman/uuid/doc.go @@ -0,0 +1,13 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The uuid package generates and inspects UUIDs. +// +// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security +// Services. +// +// This package is a partial wrapper around the github.com/google/uuid package. +// This package represents a UUID as []byte while github.com/google/uuid +// represents a UUID as [16]byte. +package uuid diff --git a/vendor/github.com/pborman/uuid/go.mod b/vendor/github.com/pborman/uuid/go.mod new file mode 100644 index 0000000000..099fc7de0d --- /dev/null +++ b/vendor/github.com/pborman/uuid/go.mod @@ -0,0 +1,3 @@ +module github.com/pborman/uuid + +require github.com/google/uuid v1.0.0 diff --git a/vendor/github.com/pborman/uuid/go.sum b/vendor/github.com/pborman/uuid/go.sum new file mode 100644 index 0000000000..db2574a9c3 --- /dev/null +++ b/vendor/github.com/pborman/uuid/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/vendor/github.com/pborman/uuid/hash.go b/vendor/github.com/pborman/uuid/hash.go new file mode 100644 index 0000000000..a0420c1ef3 --- /dev/null +++ b/vendor/github.com/pborman/uuid/hash.go @@ -0,0 +1,53 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "crypto/md5" + "crypto/sha1" + "hash" +) + +// Well known Name Space IDs and UUIDs +var ( + NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") + NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") + NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") + NIL = Parse("00000000-0000-0000-0000-000000000000") +) + +// NewHash returns a new UUID derived from the hash of space concatenated with +// data generated by h. The hash should be at least 16 byte in length. The +// first 16 bytes of the hash are used to form the UUID. The version of the +// UUID will be the lower 4 bits of version. NewHash is used to implement +// NewMD5 and NewSHA1. +func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { + h.Reset() + h.Write(space) + h.Write([]byte(data)) + s := h.Sum(nil) + uuid := make([]byte, 16) + copy(uuid, s) + uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) + uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant + return uuid +} + +// NewMD5 returns a new MD5 (Version 3) UUID based on the +// supplied name space and data. +// +// NewHash(md5.New(), space, data, 3) +func NewMD5(space UUID, data []byte) UUID { + return NewHash(md5.New(), space, data, 3) +} + +// NewSHA1 returns a new SHA1 (Version 5) UUID based on the +// supplied name space and data. +// +// NewHash(sha1.New(), space, data, 5) +func NewSHA1(space UUID, data []byte) UUID { + return NewHash(sha1.New(), space, data, 5) +} diff --git a/vendor/github.com/pborman/uuid/marshal.go b/vendor/github.com/pborman/uuid/marshal.go new file mode 100644 index 0000000000..35b89352ad --- /dev/null +++ b/vendor/github.com/pborman/uuid/marshal.go @@ -0,0 +1,85 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "errors" + "fmt" + + guuid "github.com/google/uuid" +) + +// MarshalText implements encoding.TextMarshaler. +func (u UUID) MarshalText() ([]byte, error) { + if len(u) != 16 { + return nil, nil + } + var js [36]byte + encodeHex(js[:], u) + return js[:], nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *UUID) UnmarshalText(data []byte) error { + if len(data) == 0 { + return nil + } + id := Parse(string(data)) + if id == nil { + return errors.New("invalid UUID") + } + *u = id + return nil +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (u UUID) MarshalBinary() ([]byte, error) { + return u[:], nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (u *UUID) UnmarshalBinary(data []byte) error { + if len(data) == 0 { + return nil + } + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + var id [16]byte + copy(id[:], data) + *u = id[:] + return nil +} + +// MarshalText implements encoding.TextMarshaler. +func (u Array) MarshalText() ([]byte, error) { + var js [36]byte + encodeHex(js[:], u[:]) + return js[:], nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (u *Array) UnmarshalText(data []byte) error { + id, err := guuid.ParseBytes(data) + if err != nil { + return err + } + *u = Array(id) + return nil +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (u Array) MarshalBinary() ([]byte, error) { + return u[:], nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (u *Array) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + copy(u[:], data) + return nil +} diff --git a/vendor/github.com/pborman/uuid/node.go b/vendor/github.com/pborman/uuid/node.go new file mode 100644 index 0000000000..e524e0101b --- /dev/null +++ b/vendor/github.com/pborman/uuid/node.go @@ -0,0 +1,50 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + guuid "github.com/google/uuid" +) + +// NodeInterface returns the name of the interface from which the NodeID was +// derived. The interface "user" is returned if the NodeID was set by +// SetNodeID. +func NodeInterface() string { + return guuid.NodeInterface() +} + +// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. +// If name is "" then the first usable interface found will be used or a random +// Node ID will be generated. If a named interface cannot be found then false +// is returned. +// +// SetNodeInterface never fails when name is "". +func SetNodeInterface(name string) bool { + return guuid.SetNodeInterface(name) +} + +// NodeID returns a slice of a copy of the current Node ID, setting the Node ID +// if not already set. +func NodeID() []byte { + return guuid.NodeID() +} + +// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes +// of id are used. If id is less than 6 bytes then false is returned and the +// Node ID is not set. +func SetNodeID(id []byte) bool { + return guuid.SetNodeID(id) +} + +// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is +// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) NodeID() []byte { + if len(uuid) != 16 { + return nil + } + node := make([]byte, 6) + copy(node, uuid[10:]) + return node +} diff --git a/vendor/github.com/pborman/uuid/sql.go b/vendor/github.com/pborman/uuid/sql.go new file mode 100644 index 0000000000..929c3847e2 --- /dev/null +++ b/vendor/github.com/pborman/uuid/sql.go @@ -0,0 +1,68 @@ +// Copyright 2015 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "database/sql/driver" + "errors" + "fmt" +) + +// Scan implements sql.Scanner so UUIDs can be read from databases transparently +// Currently, database types that map to string and []byte are supported. Please +// consult database-specific driver documentation for matching types. +func (uuid *UUID) Scan(src interface{}) error { + switch src.(type) { + case string: + // if an empty UUID comes from a table, we return a null UUID + if src.(string) == "" { + return nil + } + + // see uuid.Parse for required string format + parsed := Parse(src.(string)) + + if parsed == nil { + return errors.New("Scan: invalid UUID format") + } + + *uuid = parsed + case []byte: + b := src.([]byte) + + // if an empty UUID comes from a table, we return a null UUID + if len(b) == 0 { + return nil + } + + // assumes a simple slice of bytes if 16 bytes + // otherwise attempts to parse + if len(b) == 16 { + parsed := make([]byte, 16) + copy(parsed, b) + *uuid = UUID(parsed) + } else { + u := Parse(string(b)) + + if u == nil { + return errors.New("Scan: invalid UUID format") + } + + *uuid = u + } + + default: + return fmt.Errorf("Scan: unable to scan type %T into UUID", src) + } + + return nil +} + +// Value implements sql.Valuer so that UUIDs can be written to databases +// transparently. Currently, UUIDs map to strings. Please consult +// database-specific driver documentation for matching types. +func (uuid UUID) Value() (driver.Value, error) { + return uuid.String(), nil +} diff --git a/vendor/github.com/pborman/uuid/time.go b/vendor/github.com/pborman/uuid/time.go new file mode 100644 index 0000000000..5c0960d872 --- /dev/null +++ b/vendor/github.com/pborman/uuid/time.go @@ -0,0 +1,57 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + + guuid "github.com/google/uuid" +) + +// A Time represents a time as the number of 100's of nanoseconds since 15 Oct +// 1582. +type Time = guuid.Time + +// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and +// clock sequence as well as adjusting the clock sequence as needed. An error +// is returned if the current time cannot be determined. +func GetTime() (Time, uint16, error) { return guuid.GetTime() } + +// ClockSequence returns the current clock sequence, generating one if not +// already set. The clock sequence is only used for Version 1 UUIDs. +// +// The uuid package does not use global static storage for the clock sequence or +// the last time a UUID was generated. Unless SetClockSequence a new random +// clock sequence is generated the first time a clock sequence is requested by +// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated +// for +func ClockSequence() int { return guuid.ClockSequence() } + +// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to +// -1 causes a new sequence to be generated. +func SetClockSequence(seq int) { guuid.SetClockSequence(seq) } + +// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in +// uuid. It returns false if uuid is not valid. The time is only well defined +// for version 1 and 2 UUIDs. +func (uuid UUID) Time() (Time, bool) { + if len(uuid) != 16 { + return 0, false + } + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + return Time(time), true +} + +// ClockSequence returns the clock sequence encoded in uuid. It returns false +// if uuid is not valid. The clock sequence is only well defined for version 1 +// and 2 UUIDs. +func (uuid UUID) ClockSequence() (int, bool) { + if len(uuid) != 16 { + return 0, false + } + return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true +} diff --git a/vendor/github.com/pborman/uuid/util.go b/vendor/github.com/pborman/uuid/util.go new file mode 100644 index 0000000000..255b5e2485 --- /dev/null +++ b/vendor/github.com/pborman/uuid/util.go @@ -0,0 +1,32 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +// xvalues returns the value of a byte as a hexadecimal digit or 255. +var xvalues = [256]byte{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +} + +// xtob converts the the first two hex bytes of x into a byte. +func xtob(x string) (byte, bool) { + b1 := xvalues[x[0]] + b2 := xvalues[x[1]] + return (b1 << 4) | b2, b1 != 255 && b2 != 255 +} diff --git a/vendor/github.com/pborman/uuid/uuid.go b/vendor/github.com/pborman/uuid/uuid.go new file mode 100644 index 0000000000..3370004207 --- /dev/null +++ b/vendor/github.com/pborman/uuid/uuid.go @@ -0,0 +1,162 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "io" + + guuid "github.com/google/uuid" +) + +// Array is a pass-by-value UUID that can be used as an effecient key in a map. +type Array [16]byte + +// UUID converts uuid into a slice. +func (uuid Array) UUID() UUID { + return uuid[:] +} + +// String returns the string representation of uuid, +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func (uuid Array) String() string { + return guuid.UUID(uuid).String() +} + +// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC +// 4122. +type UUID []byte + +// A Version represents a UUIDs version. +type Version = guuid.Version + +// A Variant represents a UUIDs variant. +type Variant = guuid.Variant + +// Constants returned by Variant. +const ( + Invalid = guuid.Invalid // Invalid UUID + RFC4122 = guuid.RFC4122 // The variant specified in RFC4122 + Reserved = guuid.Reserved // Reserved, NCS backward compatibility. + Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility. + Future = guuid.Future // Reserved for future definition. +) + +var rander = rand.Reader // random function + +// New returns a new random (version 4) UUID as a string. It is a convenience +// function for NewRandom().String(). +func New() string { + return NewRandom().String() +} + +// Parse decodes s into a UUID or returns nil. See github.com/google/uuid for +// the formats parsed. +func Parse(s string) UUID { + gu, err := guuid.Parse(s) + if err == nil { + return gu[:] + } + return nil +} + +// ParseBytes is like Parse, except it parses a byte slice instead of a string. +func ParseBytes(b []byte) (UUID, error) { + gu, err := guuid.ParseBytes(b) + if err == nil { + return gu[:], nil + } + return nil, err +} + +// Equal returns true if uuid1 and uuid2 are equal. +func Equal(uuid1, uuid2 UUID) bool { + return bytes.Equal(uuid1, uuid2) +} + +// Array returns an array representation of uuid that can be used as a map key. +// Array panics if uuid is not valid. +func (uuid UUID) Array() Array { + if len(uuid) != 16 { + panic("invalid uuid") + } + var a Array + copy(a[:], uuid) + return a +} + +// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// , or "" if uuid is invalid. +func (uuid UUID) String() string { + if len(uuid) != 16 { + return "" + } + var buf [36]byte + encodeHex(buf[:], uuid) + return string(buf[:]) +} + +// URN returns the RFC 2141 URN form of uuid, +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. +func (uuid UUID) URN() string { + if len(uuid) != 16 { + return "" + } + var buf [36 + 9]byte + copy(buf[:], "urn:uuid:") + encodeHex(buf[9:], uuid) + return string(buf[:]) +} + +func encodeHex(dst []byte, uuid UUID) { + hex.Encode(dst[:], uuid[:4]) + dst[8] = '-' + hex.Encode(dst[9:13], uuid[4:6]) + dst[13] = '-' + hex.Encode(dst[14:18], uuid[6:8]) + dst[18] = '-' + hex.Encode(dst[19:23], uuid[8:10]) + dst[23] = '-' + hex.Encode(dst[24:], uuid[10:]) +} + +// Variant returns the variant encoded in uuid. It returns Invalid if +// uuid is invalid. +func (uuid UUID) Variant() Variant { + if len(uuid) != 16 { + return Invalid + } + switch { + case (uuid[8] & 0xc0) == 0x80: + return RFC4122 + case (uuid[8] & 0xe0) == 0xc0: + return Microsoft + case (uuid[8] & 0xe0) == 0xe0: + return Future + default: + return Reserved + } +} + +// Version returns the version of uuid. It returns false if uuid is not +// valid. +func (uuid UUID) Version() (Version, bool) { + if len(uuid) != 16 { + return 0, false + } + return Version(uuid[6] >> 4), true +} + +// SetRand sets the random number generator to r, which implements io.Reader. +// If r.Read returns an error when the package requests random data then +// a panic will be issued. +// +// Calling SetRand with nil sets the random number generator to the default +// generator. +func SetRand(r io.Reader) { + guuid.SetRand(r) +} diff --git a/vendor/github.com/pborman/uuid/version1.go b/vendor/github.com/pborman/uuid/version1.go new file mode 100644 index 0000000000..7af948da79 --- /dev/null +++ b/vendor/github.com/pborman/uuid/version1.go @@ -0,0 +1,23 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + guuid "github.com/google/uuid" +) + +// NewUUID returns a Version 1 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewUUID returns nil. If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewUUID returns nil. +func NewUUID() UUID { + gu, err := guuid.NewUUID() + if err == nil { + return UUID(gu[:]) + } + return nil +} diff --git a/vendor/github.com/pborman/uuid/version4.go b/vendor/github.com/pborman/uuid/version4.go new file mode 100644 index 0000000000..b459d46d13 --- /dev/null +++ b/vendor/github.com/pborman/uuid/version4.go @@ -0,0 +1,26 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import guuid "github.com/google/uuid" + +// Random returns a Random (Version 4) UUID or panics. +// +// The strength of the UUIDs is based on the strength of the crypto/rand +// package. +// +// A note about uniqueness derived from the UUID Wikipedia entry: +// +// Randomly generated UUIDs have 122 random bits. One's annual risk of being +// hit by a meteorite is estimated to be one chance in 17 billion, that +// means the probability is about 0.00000000006 (6 × 10−11), +// equivalent to the odds of creating a few tens of trillions of UUIDs in a +// year and having one duplicate. +func NewRandom() UUID { + if gu, err := guuid.NewRandom(); err == nil { + return UUID(gu[:]) + } + return nil +} diff --git a/vendor/github.com/satori/go.uuid/.travis.yml b/vendor/github.com/satori/go.uuid/.travis.yml new file mode 100644 index 0000000000..20dd53b8d3 --- /dev/null +++ b/vendor/github.com/satori/go.uuid/.travis.yml @@ -0,0 +1,23 @@ +language: go +sudo: false +go: + - 1.2 + - 1.3 + - 1.4 + - 1.5 + - 1.6 + - 1.7 + - 1.8 + - 1.9 + - tip +matrix: + allow_failures: + - go: tip + fast_finish: true +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -service=travis-ci +notifications: + email: false diff --git a/vendor/github.com/satori/go.uuid/LICENSE b/vendor/github.com/satori/go.uuid/LICENSE new file mode 100644 index 0000000000..926d549870 --- /dev/null +++ b/vendor/github.com/satori/go.uuid/LICENSE @@ -0,0 +1,20 @@ +Copyright (C) 2013-2018 by Maxim Bublis + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/satori/go.uuid/README.md b/vendor/github.com/satori/go.uuid/README.md new file mode 100644 index 0000000000..7b1a722dff --- /dev/null +++ b/vendor/github.com/satori/go.uuid/README.md @@ -0,0 +1,65 @@ +# UUID package for Go language + +[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid) +[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid) +[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid) + +This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs. + +With 100% test coverage and benchmarks out of box. + +Supported versions: +* Version 1, based on timestamp and MAC address (RFC 4122) +* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1) +* Version 3, based on MD5 hashing (RFC 4122) +* Version 4, based on random numbers (RFC 4122) +* Version 5, based on SHA-1 hashing (RFC 4122) + +## Installation + +Use the `go` command: + + $ go get github.com/satori/go.uuid + +## Requirements + +UUID package requires Go >= 1.2. + +## Example + +```go +package main + +import ( + "fmt" + "github.com/satori/go.uuid" +) + +func main() { + // Creating UUID Version 4 + u1 := uuid.NewV4() + fmt.Printf("UUIDv4: %s\n", u1) + + // Parsing UUID from string input + u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + if err != nil { + fmt.Printf("Something gone wrong: %s", err) + } + fmt.Printf("Successfully parsed: %s", u2) +} +``` + +## Documentation + +[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project. + +## Links +* [RFC 4122](http://tools.ietf.org/html/rfc4122) +* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) + +## Copyright + +Copyright (C) 2013-2018 by Maxim Bublis . + +UUID package released under MIT License. +See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details. diff --git a/vendor/github.com/satori/go.uuid/codec.go b/vendor/github.com/satori/go.uuid/codec.go new file mode 100644 index 0000000000..656892c53e --- /dev/null +++ b/vendor/github.com/satori/go.uuid/codec.go @@ -0,0 +1,206 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "bytes" + "encoding/hex" + "fmt" +) + +// FromBytes returns UUID converted from raw byte slice input. +// It will return error if the slice isn't 16 bytes long. +func FromBytes(input []byte) (u UUID, err error) { + err = u.UnmarshalBinary(input) + return +} + +// FromBytesOrNil returns UUID converted from raw byte slice input. +// Same behavior as FromBytes, but returns a Nil UUID on error. +func FromBytesOrNil(input []byte) UUID { + uuid, err := FromBytes(input) + if err != nil { + return Nil + } + return uuid +} + +// FromString returns UUID parsed from string input. +// Input is expected in a form accepted by UnmarshalText. +func FromString(input string) (u UUID, err error) { + err = u.UnmarshalText([]byte(input)) + return +} + +// FromStringOrNil returns UUID parsed from string input. +// Same behavior as FromString, but returns a Nil UUID on error. +func FromStringOrNil(input string) UUID { + uuid, err := FromString(input) + if err != nil { + return Nil + } + return uuid +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The encoding is the same as returned by String. +func (u UUID) MarshalText() (text []byte, err error) { + text = []byte(u.String()) + return +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// Following formats are supported: +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" +// "6ba7b8109dad11d180b400c04fd430c8" +// ABNF for supported UUID text representation follows: +// uuid := canonical | hashlike | braced | urn +// plain := canonical | hashlike +// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct +// hashlike := 12hexoct +// braced := '{' plain '}' +// urn := URN ':' UUID-NID ':' plain +// URN := 'urn' +// UUID-NID := 'uuid' +// 12hexoct := 6hexoct 6hexoct +// 6hexoct := 4hexoct 2hexoct +// 4hexoct := 2hexoct 2hexoct +// 2hexoct := hexoct hexoct +// hexoct := hexdig hexdig +// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | +// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | +// 'A' | 'B' | 'C' | 'D' | 'E' | 'F' +func (u *UUID) UnmarshalText(text []byte) (err error) { + switch len(text) { + case 32: + return u.decodeHashLike(text) + case 36: + return u.decodeCanonical(text) + case 38: + return u.decodeBraced(text) + case 41: + fallthrough + case 45: + return u.decodeURN(text) + default: + return fmt.Errorf("uuid: incorrect UUID length: %s", text) + } +} + +// decodeCanonical decodes UUID string in format +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8". +func (u *UUID) decodeCanonical(t []byte) (err error) { + if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' { + return fmt.Errorf("uuid: incorrect UUID format %s", t) + } + + src := t[:] + dst := u[:] + + for i, byteGroup := range byteGroups { + if i > 0 { + src = src[1:] // skip dash + } + _, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup]) + if err != nil { + return + } + src = src[byteGroup:] + dst = dst[byteGroup/2:] + } + + return +} + +// decodeHashLike decodes UUID string in format +// "6ba7b8109dad11d180b400c04fd430c8". +func (u *UUID) decodeHashLike(t []byte) (err error) { + src := t[:] + dst := u[:] + + if _, err = hex.Decode(dst, src); err != nil { + return err + } + return +} + +// decodeBraced decodes UUID string in format +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format +// "{6ba7b8109dad11d180b400c04fd430c8}". +func (u *UUID) decodeBraced(t []byte) (err error) { + l := len(t) + + if t[0] != '{' || t[l-1] != '}' { + return fmt.Errorf("uuid: incorrect UUID format %s", t) + } + + return u.decodePlain(t[1 : l-1]) +} + +// decodeURN decodes UUID string in format +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format +// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8". +func (u *UUID) decodeURN(t []byte) (err error) { + total := len(t) + + urn_uuid_prefix := t[:9] + + if !bytes.Equal(urn_uuid_prefix, urnPrefix) { + return fmt.Errorf("uuid: incorrect UUID format: %s", t) + } + + return u.decodePlain(t[9:total]) +} + +// decodePlain decodes UUID string in canonical format +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format +// "6ba7b8109dad11d180b400c04fd430c8". +func (u *UUID) decodePlain(t []byte) (err error) { + switch len(t) { + case 32: + return u.decodeHashLike(t) + case 36: + return u.decodeCanonical(t) + default: + return fmt.Errorf("uuid: incorrrect UUID length: %s", t) + } +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (u UUID) MarshalBinary() (data []byte, err error) { + data = u.Bytes() + return +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +// It will return error if the slice isn't 16 bytes long. +func (u *UUID) UnmarshalBinary(data []byte) (err error) { + if len(data) != Size { + err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) + return + } + copy(u[:], data) + + return +} diff --git a/vendor/github.com/satori/go.uuid/generator.go b/vendor/github.com/satori/go.uuid/generator.go new file mode 100644 index 0000000000..3f2f1da2dc --- /dev/null +++ b/vendor/github.com/satori/go.uuid/generator.go @@ -0,0 +1,239 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "crypto/md5" + "crypto/rand" + "crypto/sha1" + "encoding/binary" + "hash" + "net" + "os" + "sync" + "time" +) + +// Difference in 100-nanosecond intervals between +// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). +const epochStart = 122192928000000000 + +var ( + global = newDefaultGenerator() + + epochFunc = unixTimeFunc + posixUID = uint32(os.Getuid()) + posixGID = uint32(os.Getgid()) +) + +// NewV1 returns UUID based on current timestamp and MAC address. +func NewV1() UUID { + return global.NewV1() +} + +// NewV2 returns DCE Security UUID based on POSIX UID/GID. +func NewV2(domain byte) UUID { + return global.NewV2(domain) +} + +// NewV3 returns UUID based on MD5 hash of namespace UUID and name. +func NewV3(ns UUID, name string) UUID { + return global.NewV3(ns, name) +} + +// NewV4 returns random generated UUID. +func NewV4() UUID { + return global.NewV4() +} + +// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. +func NewV5(ns UUID, name string) UUID { + return global.NewV5(ns, name) +} + +// Generator provides interface for generating UUIDs. +type Generator interface { + NewV1() UUID + NewV2(domain byte) UUID + NewV3(ns UUID, name string) UUID + NewV4() UUID + NewV5(ns UUID, name string) UUID +} + +// Default generator implementation. +type generator struct { + storageOnce sync.Once + storageMutex sync.Mutex + + lastTime uint64 + clockSequence uint16 + hardwareAddr [6]byte +} + +func newDefaultGenerator() Generator { + return &generator{} +} + +// NewV1 returns UUID based on current timestamp and MAC address. +func (g *generator) NewV1() UUID { + u := UUID{} + + timeNow, clockSeq, hardwareAddr := g.getStorage() + + binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) + binary.BigEndian.PutUint16(u[8:], clockSeq) + + copy(u[10:], hardwareAddr) + + u.SetVersion(V1) + u.SetVariant(VariantRFC4122) + + return u +} + +// NewV2 returns DCE Security UUID based on POSIX UID/GID. +func (g *generator) NewV2(domain byte) UUID { + u := UUID{} + + timeNow, clockSeq, hardwareAddr := g.getStorage() + + switch domain { + case DomainPerson: + binary.BigEndian.PutUint32(u[0:], posixUID) + case DomainGroup: + binary.BigEndian.PutUint32(u[0:], posixGID) + } + + binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) + binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) + binary.BigEndian.PutUint16(u[8:], clockSeq) + u[9] = domain + + copy(u[10:], hardwareAddr) + + u.SetVersion(V2) + u.SetVariant(VariantRFC4122) + + return u +} + +// NewV3 returns UUID based on MD5 hash of namespace UUID and name. +func (g *generator) NewV3(ns UUID, name string) UUID { + u := newFromHash(md5.New(), ns, name) + u.SetVersion(V3) + u.SetVariant(VariantRFC4122) + + return u +} + +// NewV4 returns random generated UUID. +func (g *generator) NewV4() UUID { + u := UUID{} + g.safeRandom(u[:]) + u.SetVersion(V4) + u.SetVariant(VariantRFC4122) + + return u +} + +// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. +func (g *generator) NewV5(ns UUID, name string) UUID { + u := newFromHash(sha1.New(), ns, name) + u.SetVersion(V5) + u.SetVariant(VariantRFC4122) + + return u +} + +func (g *generator) initStorage() { + g.initClockSequence() + g.initHardwareAddr() +} + +func (g *generator) initClockSequence() { + buf := make([]byte, 2) + g.safeRandom(buf) + g.clockSequence = binary.BigEndian.Uint16(buf) +} + +func (g *generator) initHardwareAddr() { + interfaces, err := net.Interfaces() + if err == nil { + for _, iface := range interfaces { + if len(iface.HardwareAddr) >= 6 { + copy(g.hardwareAddr[:], iface.HardwareAddr) + return + } + } + } + + // Initialize hardwareAddr randomly in case + // of real network interfaces absence + g.safeRandom(g.hardwareAddr[:]) + + // Set multicast bit as recommended in RFC 4122 + g.hardwareAddr[0] |= 0x01 +} + +func (g *generator) safeRandom(dest []byte) { + if _, err := rand.Read(dest); err != nil { + panic(err) + } +} + +// Returns UUID v1/v2 storage state. +// Returns epoch timestamp, clock sequence, and hardware address. +func (g *generator) getStorage() (uint64, uint16, []byte) { + g.storageOnce.Do(g.initStorage) + + g.storageMutex.Lock() + defer g.storageMutex.Unlock() + + timeNow := epochFunc() + // Clock changed backwards since last UUID generation. + // Should increase clock sequence. + if timeNow <= g.lastTime { + g.clockSequence++ + } + g.lastTime = timeNow + + return timeNow, g.clockSequence, g.hardwareAddr[:] +} + +// Returns difference in 100-nanosecond intervals between +// UUID epoch (October 15, 1582) and current time. +// This is default epoch calculation function. +func unixTimeFunc() uint64 { + return epochStart + uint64(time.Now().UnixNano()/100) +} + +// Returns UUID based on hashing of namespace UUID and name. +func newFromHash(h hash.Hash, ns UUID, name string) UUID { + u := UUID{} + h.Write(ns[:]) + h.Write([]byte(name)) + copy(u[:], h.Sum(nil)) + + return u +} diff --git a/vendor/github.com/satori/go.uuid/sql.go b/vendor/github.com/satori/go.uuid/sql.go new file mode 100644 index 0000000000..56759d3905 --- /dev/null +++ b/vendor/github.com/satori/go.uuid/sql.go @@ -0,0 +1,78 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "database/sql/driver" + "fmt" +) + +// Value implements the driver.Valuer interface. +func (u UUID) Value() (driver.Value, error) { + return u.String(), nil +} + +// Scan implements the sql.Scanner interface. +// A 16-byte slice is handled by UnmarshalBinary, while +// a longer byte slice or a string is handled by UnmarshalText. +func (u *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + if len(src) == Size { + return u.UnmarshalBinary(src) + } + return u.UnmarshalText(src) + + case string: + return u.UnmarshalText([]byte(src)) + } + + return fmt.Errorf("uuid: cannot convert %T to UUID", src) +} + +// NullUUID can be used with the standard sql package to represent a +// UUID value that can be NULL in the database +type NullUUID struct { + UUID UUID + Valid bool +} + +// Value implements the driver.Valuer interface. +func (u NullUUID) Value() (driver.Value, error) { + if !u.Valid { + return nil, nil + } + // Delegate to UUID Value function + return u.UUID.Value() +} + +// Scan implements the sql.Scanner interface. +func (u *NullUUID) Scan(src interface{}) error { + if src == nil { + u.UUID, u.Valid = Nil, false + return nil + } + + // Delegate to UUID Scan function + u.Valid = true + return u.UUID.Scan(src) +} diff --git a/vendor/github.com/satori/go.uuid/uuid.go b/vendor/github.com/satori/go.uuid/uuid.go new file mode 100644 index 0000000000..a2b8e2ca2a --- /dev/null +++ b/vendor/github.com/satori/go.uuid/uuid.go @@ -0,0 +1,161 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Package uuid provides implementation of Universally Unique Identifier (UUID). +// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and +// version 2 (as specified in DCE 1.1). +package uuid + +import ( + "bytes" + "encoding/hex" +) + +// Size of a UUID in bytes. +const Size = 16 + +// UUID representation compliant with specification +// described in RFC 4122. +type UUID [Size]byte + +// UUID versions +const ( + _ byte = iota + V1 + V2 + V3 + V4 + V5 +) + +// UUID layout variants. +const ( + VariantNCS byte = iota + VariantRFC4122 + VariantMicrosoft + VariantFuture +) + +// UUID DCE domains. +const ( + DomainPerson = iota + DomainGroup + DomainOrg +) + +// String parse helpers. +var ( + urnPrefix = []byte("urn:uuid:") + byteGroups = []int{8, 4, 4, 4, 12} +) + +// Nil is special form of UUID that is specified to have all +// 128 bits set to zero. +var Nil = UUID{} + +// Predefined namespace UUIDs. +var ( + NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) + NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) + NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) + NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) +) + +// Equal returns true if u1 and u2 equals, otherwise returns false. +func Equal(u1 UUID, u2 UUID) bool { + return bytes.Equal(u1[:], u2[:]) +} + +// Version returns algorithm version used to generate UUID. +func (u UUID) Version() byte { + return u[6] >> 4 +} + +// Variant returns UUID layout variant. +func (u UUID) Variant() byte { + switch { + case (u[8] >> 7) == 0x00: + return VariantNCS + case (u[8] >> 6) == 0x02: + return VariantRFC4122 + case (u[8] >> 5) == 0x06: + return VariantMicrosoft + case (u[8] >> 5) == 0x07: + fallthrough + default: + return VariantFuture + } +} + +// Bytes returns bytes slice representation of UUID. +func (u UUID) Bytes() []byte { + return u[:] +} + +// Returns canonical string representation of UUID: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func (u UUID) String() string { + buf := make([]byte, 36) + + hex.Encode(buf[0:8], u[0:4]) + buf[8] = '-' + hex.Encode(buf[9:13], u[4:6]) + buf[13] = '-' + hex.Encode(buf[14:18], u[6:8]) + buf[18] = '-' + hex.Encode(buf[19:23], u[8:10]) + buf[23] = '-' + hex.Encode(buf[24:], u[10:]) + + return string(buf) +} + +// SetVersion sets version bits. +func (u *UUID) SetVersion(v byte) { + u[6] = (u[6] & 0x0f) | (v << 4) +} + +// SetVariant sets variant bits. +func (u *UUID) SetVariant(v byte) { + switch v { + case VariantNCS: + u[8] = (u[8]&(0xff>>1) | (0x00 << 7)) + case VariantRFC4122: + u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) + case VariantMicrosoft: + u[8] = (u[8]&(0xff>>3) | (0x06 << 5)) + case VariantFuture: + fallthrough + default: + u[8] = (u[8]&(0xff>>3) | (0x07 << 5)) + } +} + +// Must is a helper that wraps a call to a function returning (UUID, error) +// and panics if the error is non-nil. It is intended for use in variable +// initializations such as +// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")); +func Must(u UUID, err error) UUID { + if err != nil { + panic(err) + } + return u +} diff --git a/vendor/github.com/sirupsen/logrus/.gitignore b/vendor/github.com/sirupsen/logrus/.gitignore new file mode 100644 index 0000000000..6b7d7d1e8b --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.gitignore @@ -0,0 +1,2 @@ +logrus +vendor diff --git a/vendor/github.com/sirupsen/logrus/.travis.yml b/vendor/github.com/sirupsen/logrus/.travis.yml new file mode 100644 index 0000000000..848938a6d4 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/.travis.yml @@ -0,0 +1,25 @@ +language: go +go_import_path: github.com/sirupsen/logrus +git: + depth: 1 +env: + - GO111MODULE=on + - GO111MODULE=off +go: [ 1.11.x, 1.12.x ] +os: [ linux, osx ] +matrix: + exclude: + - go: 1.12.x + env: GO111MODULE=off + - go: 1.11.x + os: osx +install: + - ./travis/install.sh + - if [[ "$GO111MODULE" == "on" ]]; then go mod download; fi + - if [[ "$GO111MODULE" == "off" ]]; then go get github.com/stretchr/testify/assert golang.org/x/sys/unix github.com/konsorten/go-windows-terminal-sequences; fi +script: + - ./travis/cross_build.sh + - export GOMAXPROCS=4 + - export GORACE=halt_on_error=1 + - go test -race -v ./... + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md new file mode 100644 index 0000000000..51a7ab0cab --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md @@ -0,0 +1,200 @@ +# 1.4.2 + * Fixes build break for plan9, nacl, solaris +# 1.4.1 +This new release introduces: + * Enhance TextFormatter to not print caller information when they are empty (#944) + * Remove dependency on golang.org/x/crypto (#932, #943) + +Fixes: + * Fix Entry.WithContext method to return a copy of the initial entry (#941) + +# 1.4.0 +This new release introduces: + * Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848). + * Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter (#909, #911) + * Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919). + +Fixes: + * Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893). + * Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903) + * Fix infinite recursion on unknown `Level.String()` (#907) + * Fix race condition in `getCaller` (#916). + + +# 1.3.0 +This new release introduces: + * Log, Logf, Logln functions for Logger and Entry that take a Level + +Fixes: + * Building prometheus node_exporter on AIX (#840) + * Race condition in TextFormatter (#468) + * Travis CI import path (#868) + * Remove coloured output on Windows (#862) + * Pointer to func as field in JSONFormatter (#870) + * Properly marshal Levels (#873) + +# 1.2.0 +This new release introduces: + * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued + * A new trace level named `Trace` whose level is below `Debug` + * A configurable exit function to be called upon a Fatal trace + * The `Level` object now implements `encoding.TextUnmarshaler` interface + +# 1.1.1 +This is a bug fix release. + * fix the build break on Solaris + * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized + +# 1.1.0 +This new release introduces: + * several fixes: + * a fix for a race condition on entry formatting + * proper cleanup of previously used entries before putting them back in the pool + * the extra new line at the end of message in text formatter has been removed + * a new global public API to check if a level is activated: IsLevelEnabled + * the following methods have been added to the Logger object + * IsLevelEnabled + * SetFormatter + * SetOutput + * ReplaceHooks + * introduction of go module + * an indent configuration for the json formatter + * output colour support for windows + * the field sort function is now configurable for text formatter + * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater + +# 1.0.6 + +This new release introduces: + * a new api WithTime which allows to easily force the time of the log entry + which is mostly useful for logger wrapper + * a fix reverting the immutability of the entry given as parameter to the hooks + a new configuration field of the json formatter in order to put all the fields + in a nested dictionnary + * a new SetOutput method in the Logger + * a new configuration of the textformatter to configure the name of the default keys + * a new configuration of the text formatter to disable the level truncation + +# 1.0.5 + +* Fix hooks race (#707) +* Fix panic deadlock (#695) + +# 1.0.4 + +* Fix race when adding hooks (#612) +* Fix terminal check in AppEngine (#635) + +# 1.0.3 + +* Replace example files with testable examples + +# 1.0.2 + +* bug: quote non-string values in text formatter (#583) +* Make (*Logger) SetLevel a public method + +# 1.0.1 + +* bug: fix escaping in text formatter (#575) + +# 1.0.0 + +* Officially changed name to lower-case +* bug: colors on Windows 10 (#541) +* bug: fix race in accessing level (#512) + +# 0.11.5 + +* feature: add writer and writerlevel to entry (#372) + +# 0.11.4 + +* bug: fix undefined variable on solaris (#493) + +# 0.11.3 + +* formatter: configure quoting of empty values (#484) +* formatter: configure quoting character (default is `"`) (#484) +* bug: fix not importing io correctly in non-linux environments (#481) + +# 0.11.2 + +* bug: fix windows terminal detection (#476) + +# 0.11.1 + +* bug: fix tty detection with custom out (#471) + +# 0.11.0 + +* performance: Use bufferpool to allocate (#370) +* terminal: terminal detection for app-engine (#343) +* feature: exit handler (#375) + +# 0.10.0 + +* feature: Add a test hook (#180) +* feature: `ParseLevel` is now case-insensitive (#326) +* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) +* performance: avoid re-allocations on `WithFields` (#335) + +# 0.9.0 + +* logrus/text_formatter: don't emit empty msg +* logrus/hooks/airbrake: move out of main repository +* logrus/hooks/sentry: move out of main repository +* logrus/hooks/papertrail: move out of main repository +* logrus/hooks/bugsnag: move out of main repository +* logrus/core: run tests with `-race` +* logrus/core: detect TTY based on `stderr` +* logrus/core: support `WithError` on logger +* logrus/core: Solaris support + +# 0.8.7 + +* logrus/core: fix possible race (#216) +* logrus/doc: small typo fixes and doc improvements + + +# 0.8.6 + +* hooks/raven: allow passing an initialized client + +# 0.8.5 + +* logrus/core: revert #208 + +# 0.8.4 + +* formatter/text: fix data race (#218) + +# 0.8.3 + +* logrus/core: fix entry log level (#208) +* logrus/core: improve performance of text formatter by 40% +* logrus/core: expose `LevelHooks` type +* logrus/core: add support for DragonflyBSD and NetBSD +* formatter/text: print structs more verbosely + +# 0.8.2 + +* logrus: fix more Fatal family functions + +# 0.8.1 + +* logrus: fix not exiting on `Fatalf` and `Fatalln` + +# 0.8.0 + +* logrus: defaults to stderr instead of stdout +* hooks/sentry: add special field for `*http.Request` +* formatter/text: ignore Windows for colors + +# 0.7.3 + +* formatter/\*: allow configuration of timestamp layout + +# 0.7.2 + +* formatter/text: Add configuration option for time format (#158) diff --git a/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/sirupsen/logrus/LICENSE new file mode 100644 index 0000000000..f090cb42f3 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md new file mode 100644 index 0000000000..a4796eb07d --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/README.md @@ -0,0 +1,495 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. + +**Seeing weird case-sensitive problems?** It's in the past been possible to +import Logrus as both upper- and lower-case. Due to the Go package environment, +this caused issues in the community and we needed a standard. Some environments +experienced problems with the upper-case variant, so the lower-case was decided. +Everything using `logrus` will need to use the lower-case: +`github.com/sirupsen/logrus`. Any package that isn't, should be changed. + +To fix Glide, see [these +comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). +For an in-depth explanation of the casing issue, see [this +comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). + +**Are you interested in assisting in maintaining Logrus?** Currently I have a +lot of obligations, and I am unable to provide Logrus with the maintainership it +needs. If you'd like to help, please reach out to me at `simon at author's +username dot com`. + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +``` +To ensure this behaviour even if a TTY is attached, set your formatter as follows: + +```go + log.SetFormatter(&log.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) +``` + +#### Logging Method Name + +If you wish to add the calling method as a field, instruct the logger via: +```go +log.SetReportCaller(true) +``` +This adds the caller as 'method' like so: + +```json +{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", +"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} +``` + +```text +time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin +``` +Note that this does add measurable overhead - the cost will depend on the version of Go, but is +between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your +environment via benchmarks: +``` +go test -bench=.*CallerTracing +``` + + +#### Case-sensitivity + +The organization's name was changed to lower-case--and this will not be changed +back. If you are getting import conflicts due to case sensitivity, please use +the lower-case import: `github.com/sirupsen/logrus`. + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/sirupsen/logrus" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "os" + "github.com/sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stdout + + // You could set this to any `io.Writer` such as a file + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging through logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Default Fields + +Often it's helpful to have fields _always_ attached to log statements in an +application or parts of one. For example, you may want to always log the +`request_id` and `user_ip` in the context of a request. Instead of writing +`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +every line, you can create a `logrus.Entry` to pass around instead: + +```go +requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger.Warn("something not great happened") +``` + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/sirupsen/logrus" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook(123, "xyz", "production")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` +Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). + +A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) + + +#### Level logging + +Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Trace("Something very low level.") +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true`. For Windows, see + [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). + * When colors are enabled, levels are truncated to 4 characters by default. To disable + truncation set the `DisableLevelTruncation` field to `true`. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). +* `logrus.JSONFormatter`. Logs fields as JSON. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + +Third party logging formatters: + +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. +* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html). +* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. +* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. +* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. +* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +This means that we can override the standard library logger easily: + +```go +logger := logrus.New() +logger.Formatter = &logrus.JSONFormatter{} + +// Use logrus for standard log output +// Note that `log` here references stdlib's log +// Not logrus imported under the name `log`. +log.SetOutput(logger.Writer()) +``` + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + +#### Tools + +| Tool | Description | +| ---- | ----------- | +|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| +|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | + +#### Testing + +Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: + +* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook +* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): + +```go +import( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSomething(t*testing.T){ + logger, hook := test.NewNullLogger() + logger.Error("Helloerror") + + assert.Equal(t, 1, len(hook.Entries)) + assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal(t, "Helloerror", hook.LastEntry().Message) + + hook.Reset() + assert.Nil(t, hook.LastEntry()) +} +``` + +#### Fatal handlers + +Logrus can register one or more functions that will be called when any `fatal` +level message is logged. The registered handlers will be executed before +logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need +to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. + +``` +... +handler := func() { + // gracefully shutdown something... +} +logrus.RegisterExitHandler(handler) +... +``` + +#### Thread safety + +By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. +If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. + +Situation when locking is not needed includes: + +* You have no hooks registered, or hooks calling is already thread-safe. + +* Writing to logger.Out is already thread-safe, for example: + + 1) logger.Out is protected by locks. + + 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) + + (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go new file mode 100644 index 0000000000..8fd189e1cc --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/alt_exit.go @@ -0,0 +1,76 @@ +package logrus + +// The following code was sourced and modified from the +// https://github.com/tebeka/atexit package governed by the following license: +// +// Copyright (c) 2012 Miki Tebeka . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import ( + "fmt" + "os" +) + +var handlers = []func(){} + +func runHandler(handler func()) { + defer func() { + if err := recover(); err != nil { + fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) + } + }() + + handler() +} + +func runHandlers() { + for _, handler := range handlers { + runHandler(handler) + } +} + +// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) +func Exit(code int) { + runHandlers() + os.Exit(code) +} + +// RegisterExitHandler appends a Logrus Exit handler to the list of handlers, +// call logrus.Exit to invoke all handlers. The handlers will also be invoked when +// any Fatal log entry is made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func RegisterExitHandler(handler func()) { + handlers = append(handlers, handler) +} + +// DeferExitHandler prepends a Logrus Exit handler to the list of handlers, +// call logrus.Exit to invoke all handlers. The handlers will also be invoked when +// any Fatal log entry is made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func DeferExitHandler(handler func()) { + handlers = append([]func(){handler}, handlers...) +} diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml new file mode 100644 index 0000000000..96c2ce15f8 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/appveyor.yml @@ -0,0 +1,14 @@ +version: "{build}" +platform: x64 +clone_folder: c:\gopath\src\github.com\sirupsen\logrus +environment: + GOPATH: c:\gopath +branches: + only: + - master +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - go version +build_script: + - go get -t + - go test diff --git a/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go new file mode 100644 index 0000000000..da67aba06d --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/doc.go @@ -0,0 +1,26 @@ +/* +Package logrus is a structured logger for Go, completely API compatible with the standard library logger. + + +The simplest way to use Logrus is simply the package-level exported logger: + + package main + + import ( + log "github.com/sirupsen/logrus" + ) + + func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "number": 1, + "size": 10, + }).Info("A walrus appears") + } + +Output: + time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 + +For a full guide visit https://github.com/sirupsen/logrus +*/ +package logrus diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go new file mode 100644 index 0000000000..63e25583cb --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -0,0 +1,407 @@ +package logrus + +import ( + "bytes" + "context" + "fmt" + "os" + "reflect" + "runtime" + "strings" + "sync" + "time" +) + +var ( + bufferPool *sync.Pool + + // qualified package name, cached at first use + logrusPackage string + + // Positions in the call stack when tracing to report the calling method + minimumCallerDepth int + + // Used for caller information initialisation + callerInitOnce sync.Once +) + +const ( + maximumCallerDepth int = 25 + knownLogrusFrames int = 4 +) + +func init() { + bufferPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + } + + // start at the bottom of the stack before the package-name cache is primed + minimumCallerDepth = 1 +} + +// Defines the key when adding errors using WithError. +var ErrorKey = "error" + +// An entry is the final or intermediate Logrus logging entry. It contains all +// the fields passed with WithField{,s}. It's finally logged when Trace, Debug, +// Info, Warn, Error, Fatal or Panic is called on it. These objects can be +// reused and passed around as much as you wish to avoid field duplication. +type Entry struct { + Logger *Logger + + // Contains all the fields set by the user. + Data Fields + + // Time at which the log entry was created + Time time.Time + + // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic + // This field will be set on entry firing and the value will be equal to the one in Logger struct field. + Level Level + + // Calling method, with package name + Caller *runtime.Frame + + // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic + Message string + + // When formatter is called in entry.log(), a Buffer may be set to entry + Buffer *bytes.Buffer + + // Contains the context set by the user. Useful for hook processing etc. + Context context.Context + + // err may contain a field formatting error + err string +} + +func NewEntry(logger *Logger) *Entry { + return &Entry{ + Logger: logger, + // Default is three fields, plus one optional. Give a little extra room. + Data: make(Fields, 6), + } +} + +// Returns the string representation from the reader and ultimately the +// formatter. +func (entry *Entry) String() (string, error) { + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + return "", err + } + str := string(serialized) + return str, nil +} + +// Add an error as single field (using the key defined in ErrorKey) to the Entry. +func (entry *Entry) WithError(err error) *Entry { + return entry.WithField(ErrorKey, err) +} + +// Add a context to the Entry. +func (entry *Entry) WithContext(ctx context.Context) *Entry { + return &Entry{Logger: entry.Logger, Data: entry.Data, Time: entry.Time, err: entry.err, Context: ctx} +} + +// Add a single field to the Entry. +func (entry *Entry) WithField(key string, value interface{}) *Entry { + return entry.WithFields(Fields{key: value}) +} + +// Add a map of fields to the Entry. +func (entry *Entry) WithFields(fields Fields) *Entry { + data := make(Fields, len(entry.Data)+len(fields)) + for k, v := range entry.Data { + data[k] = v + } + fieldErr := entry.err + for k, v := range fields { + isErrField := false + if t := reflect.TypeOf(v); t != nil { + switch t.Kind() { + case reflect.Func: + isErrField = true + case reflect.Ptr: + isErrField = t.Elem().Kind() == reflect.Func + } + } + if isErrField { + tmp := fmt.Sprintf("can not add field %q", k) + if fieldErr != "" { + fieldErr = entry.err + ", " + tmp + } else { + fieldErr = tmp + } + } else { + data[k] = v + } + } + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context} +} + +// Overrides the time of the Entry. +func (entry *Entry) WithTime(t time.Time) *Entry { + return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err, Context: entry.Context} +} + +// getPackageName reduces a fully qualified function name to the package name +// There really ought to be to be a better way... +func getPackageName(f string) string { + for { + lastPeriod := strings.LastIndex(f, ".") + lastSlash := strings.LastIndex(f, "/") + if lastPeriod > lastSlash { + f = f[:lastPeriod] + } else { + break + } + } + + return f +} + +// getCaller retrieves the name of the first non-logrus calling function +func getCaller() *runtime.Frame { + + // cache this package's fully-qualified name + callerInitOnce.Do(func() { + pcs := make([]uintptr, 2) + _ = runtime.Callers(0, pcs) + logrusPackage = getPackageName(runtime.FuncForPC(pcs[1]).Name()) + + // now that we have the cache, we can skip a minimum count of known-logrus functions + // XXX this is dubious, the number of frames may vary + minimumCallerDepth = knownLogrusFrames + }) + + // Restrict the lookback frames to avoid runaway lookups + pcs := make([]uintptr, maximumCallerDepth) + depth := runtime.Callers(minimumCallerDepth, pcs) + frames := runtime.CallersFrames(pcs[:depth]) + + for f, again := frames.Next(); again; f, again = frames.Next() { + pkg := getPackageName(f.Function) + + // If the caller isn't part of this package, we're done + if pkg != logrusPackage { + return &f + } + } + + // if we got here, we failed to find the caller's context + return nil +} + +func (entry Entry) HasCaller() (has bool) { + return entry.Logger != nil && + entry.Logger.ReportCaller && + entry.Caller != nil +} + +// This function is not declared with a pointer value because otherwise +// race conditions will occur when using multiple goroutines +func (entry Entry) log(level Level, msg string) { + var buffer *bytes.Buffer + + // Default to now, but allow users to override if they want. + // + // We don't have to worry about polluting future calls to Entry#log() + // with this assignment because this function is declared with a + // non-pointer receiver. + if entry.Time.IsZero() { + entry.Time = time.Now() + } + + entry.Level = level + entry.Message = msg + if entry.Logger.ReportCaller { + entry.Caller = getCaller() + } + + entry.fireHooks() + + buffer = bufferPool.Get().(*bytes.Buffer) + buffer.Reset() + defer bufferPool.Put(buffer) + entry.Buffer = buffer + + entry.write() + + entry.Buffer = nil + + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) + } +} + +func (entry *Entry) fireHooks() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + err := entry.Logger.Hooks.Fire(entry.Level, entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + } +} + +func (entry *Entry) write() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + } else { + _, err = entry.Logger.Out.Write(serialized) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + } +} + +func (entry *Entry) Log(level Level, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.log(level, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Trace(args ...interface{}) { + entry.Log(TraceLevel, args...) +} + +func (entry *Entry) Debug(args ...interface{}) { + entry.Log(DebugLevel, args...) +} + +func (entry *Entry) Print(args ...interface{}) { + entry.Info(args...) +} + +func (entry *Entry) Info(args ...interface{}) { + entry.Log(InfoLevel, args...) +} + +func (entry *Entry) Warn(args ...interface{}) { + entry.Log(WarnLevel, args...) +} + +func (entry *Entry) Warning(args ...interface{}) { + entry.Warn(args...) +} + +func (entry *Entry) Error(args ...interface{}) { + entry.Log(ErrorLevel, args...) +} + +func (entry *Entry) Fatal(args ...interface{}) { + entry.Log(FatalLevel, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panic(args ...interface{}) { + entry.Log(PanicLevel, args...) + panic(fmt.Sprint(args...)) +} + +// Entry Printf family functions + +func (entry *Entry) Logf(level Level, format string, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.Log(level, fmt.Sprintf(format, args...)) + } +} + +func (entry *Entry) Tracef(format string, args ...interface{}) { + entry.Logf(TraceLevel, format, args...) +} + +func (entry *Entry) Debugf(format string, args ...interface{}) { + entry.Logf(DebugLevel, format, args...) +} + +func (entry *Entry) Infof(format string, args ...interface{}) { + entry.Logf(InfoLevel, format, args...) +} + +func (entry *Entry) Printf(format string, args ...interface{}) { + entry.Infof(format, args...) +} + +func (entry *Entry) Warnf(format string, args ...interface{}) { + entry.Logf(WarnLevel, format, args...) +} + +func (entry *Entry) Warningf(format string, args ...interface{}) { + entry.Warnf(format, args...) +} + +func (entry *Entry) Errorf(format string, args ...interface{}) { + entry.Logf(ErrorLevel, format, args...) +} + +func (entry *Entry) Fatalf(format string, args ...interface{}) { + entry.Logf(FatalLevel, format, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicf(format string, args ...interface{}) { + entry.Logf(PanicLevel, format, args...) +} + +// Entry Println family functions + +func (entry *Entry) Logln(level Level, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.Log(level, entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Traceln(args ...interface{}) { + entry.Logln(TraceLevel, args...) +} + +func (entry *Entry) Debugln(args ...interface{}) { + entry.Logln(DebugLevel, args...) +} + +func (entry *Entry) Infoln(args ...interface{}) { + entry.Logln(InfoLevel, args...) +} + +func (entry *Entry) Println(args ...interface{}) { + entry.Infoln(args...) +} + +func (entry *Entry) Warnln(args ...interface{}) { + entry.Logln(WarnLevel, args...) +} + +func (entry *Entry) Warningln(args ...interface{}) { + entry.Warnln(args...) +} + +func (entry *Entry) Errorln(args ...interface{}) { + entry.Logln(ErrorLevel, args...) +} + +func (entry *Entry) Fatalln(args ...interface{}) { + entry.Logln(FatalLevel, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicln(args ...interface{}) { + entry.Logln(PanicLevel, args...) +} + +// Sprintlnn => Sprint no newline. This is to get the behavior of how +// fmt.Sprintln where spaces are always added between operands, regardless of +// their type. Instead of vendoring the Sprintln implementation to spare a +// string allocation, we do the simplest thing. +func (entry *Entry) sprintlnn(args ...interface{}) string { + msg := fmt.Sprintln(args...) + return msg[:len(msg)-1] +} diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go new file mode 100644 index 0000000000..62fc2f2193 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -0,0 +1,225 @@ +package logrus + +import ( + "context" + "io" + "time" +) + +var ( + // std is the name of the standard logger in stdlib `log` + std = New() +) + +func StandardLogger() *Logger { + return std +} + +// SetOutput sets the standard logger output. +func SetOutput(out io.Writer) { + std.SetOutput(out) +} + +// SetFormatter sets the standard logger formatter. +func SetFormatter(formatter Formatter) { + std.SetFormatter(formatter) +} + +// SetReportCaller sets whether the standard logger will include the calling +// method as a field. +func SetReportCaller(include bool) { + std.SetReportCaller(include) +} + +// SetLevel sets the standard logger level. +func SetLevel(level Level) { + std.SetLevel(level) +} + +// GetLevel returns the standard logger level. +func GetLevel() Level { + return std.GetLevel() +} + +// IsLevelEnabled checks if the log level of the standard logger is greater than the level param +func IsLevelEnabled(level Level) bool { + return std.IsLevelEnabled(level) +} + +// AddHook adds a hook to the standard logger hooks. +func AddHook(hook Hook) { + std.AddHook(hook) +} + +// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. +func WithError(err error) *Entry { + return std.WithField(ErrorKey, err) +} + +// WithContext creates an entry from the standard logger and adds a context to it. +func WithContext(ctx context.Context) *Entry { + return std.WithContext(ctx) +} + +// WithField creates an entry from the standard logger and adds a field to +// it. If you want multiple fields, use `WithFields`. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithField(key string, value interface{}) *Entry { + return std.WithField(key, value) +} + +// WithFields creates an entry from the standard logger and adds multiple +// fields to it. This is simply a helper for `WithField`, invoking it +// once for each field. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithFields(fields Fields) *Entry { + return std.WithFields(fields) +} + +// WithTime creats an entry from the standard logger and overrides the time of +// logs generated with it. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithTime(t time.Time) *Entry { + return std.WithTime(t) +} + +// Trace logs a message at level Trace on the standard logger. +func Trace(args ...interface{}) { + std.Trace(args...) +} + +// Debug logs a message at level Debug on the standard logger. +func Debug(args ...interface{}) { + std.Debug(args...) +} + +// Print logs a message at level Info on the standard logger. +func Print(args ...interface{}) { + std.Print(args...) +} + +// Info logs a message at level Info on the standard logger. +func Info(args ...interface{}) { + std.Info(args...) +} + +// Warn logs a message at level Warn on the standard logger. +func Warn(args ...interface{}) { + std.Warn(args...) +} + +// Warning logs a message at level Warn on the standard logger. +func Warning(args ...interface{}) { + std.Warning(args...) +} + +// Error logs a message at level Error on the standard logger. +func Error(args ...interface{}) { + std.Error(args...) +} + +// Panic logs a message at level Panic on the standard logger. +func Panic(args ...interface{}) { + std.Panic(args...) +} + +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatal(args ...interface{}) { + std.Fatal(args...) +} + +// Tracef logs a message at level Trace on the standard logger. +func Tracef(format string, args ...interface{}) { + std.Tracef(format, args...) +} + +// Debugf logs a message at level Debug on the standard logger. +func Debugf(format string, args ...interface{}) { + std.Debugf(format, args...) +} + +// Printf logs a message at level Info on the standard logger. +func Printf(format string, args ...interface{}) { + std.Printf(format, args...) +} + +// Infof logs a message at level Info on the standard logger. +func Infof(format string, args ...interface{}) { + std.Infof(format, args...) +} + +// Warnf logs a message at level Warn on the standard logger. +func Warnf(format string, args ...interface{}) { + std.Warnf(format, args...) +} + +// Warningf logs a message at level Warn on the standard logger. +func Warningf(format string, args ...interface{}) { + std.Warningf(format, args...) +} + +// Errorf logs a message at level Error on the standard logger. +func Errorf(format string, args ...interface{}) { + std.Errorf(format, args...) +} + +// Panicf logs a message at level Panic on the standard logger. +func Panicf(format string, args ...interface{}) { + std.Panicf(format, args...) +} + +// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalf(format string, args ...interface{}) { + std.Fatalf(format, args...) +} + +// Traceln logs a message at level Trace on the standard logger. +func Traceln(args ...interface{}) { + std.Traceln(args...) +} + +// Debugln logs a message at level Debug on the standard logger. +func Debugln(args ...interface{}) { + std.Debugln(args...) +} + +// Println logs a message at level Info on the standard logger. +func Println(args ...interface{}) { + std.Println(args...) +} + +// Infoln logs a message at level Info on the standard logger. +func Infoln(args ...interface{}) { + std.Infoln(args...) +} + +// Warnln logs a message at level Warn on the standard logger. +func Warnln(args ...interface{}) { + std.Warnln(args...) +} + +// Warningln logs a message at level Warn on the standard logger. +func Warningln(args ...interface{}) { + std.Warningln(args...) +} + +// Errorln logs a message at level Error on the standard logger. +func Errorln(args ...interface{}) { + std.Errorln(args...) +} + +// Panicln logs a message at level Panic on the standard logger. +func Panicln(args ...interface{}) { + std.Panicln(args...) +} + +// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalln(args ...interface{}) { + std.Fatalln(args...) +} diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go new file mode 100644 index 0000000000..408883773e --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -0,0 +1,78 @@ +package logrus + +import "time" + +// Default key names for the default fields +const ( + defaultTimestampFormat = time.RFC3339 + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" + FieldKeyLogrusError = "logrus_error" + FieldKeyFunc = "func" + FieldKeyFile = "file" +) + +// The Formatter interface is used to implement a custom Formatter. It takes an +// `Entry`. It exposes all the fields, including the default ones: +// +// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. +// * `entry.Data["time"]`. The timestamp. +// * `entry.Data["level"]. The level the entry was logged at. +// +// Any additional fields added with `WithField` or `WithFields` are also in +// `entry.Data`. Format is expected to return an array of bytes which are then +// logged to `logger.Out`. +type Formatter interface { + Format(*Entry) ([]byte, error) +} + +// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when +// dumping it. If this code wasn't there doing: +// +// logrus.WithField("level", 1).Info("hello") +// +// Would just silently drop the user provided level. Instead with this code +// it'll logged as: +// +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// +// It's not exported because it's still using Data in an opinionated way. It's to +// avoid code duplication between the two default formatters. +func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { + timeKey := fieldMap.resolve(FieldKeyTime) + if t, ok := data[timeKey]; ok { + data["fields."+timeKey] = t + delete(data, timeKey) + } + + msgKey := fieldMap.resolve(FieldKeyMsg) + if m, ok := data[msgKey]; ok { + data["fields."+msgKey] = m + delete(data, msgKey) + } + + levelKey := fieldMap.resolve(FieldKeyLevel) + if l, ok := data[levelKey]; ok { + data["fields."+levelKey] = l + delete(data, levelKey) + } + + logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) + if l, ok := data[logrusErrKey]; ok { + data["fields."+logrusErrKey] = l + delete(data, logrusErrKey) + } + + // If reportCaller is not set, 'func' will not conflict. + if reportCaller { + funcKey := fieldMap.resolve(FieldKeyFunc) + if l, ok := data[funcKey]; ok { + data["fields."+funcKey] = l + } + fileKey := fieldMap.resolve(FieldKeyFile) + if l, ok := data[fileKey]; ok { + data["fields."+fileKey] = l + } + } +} diff --git a/vendor/github.com/sirupsen/logrus/go.mod b/vendor/github.com/sirupsen/logrus/go.mod new file mode 100644 index 0000000000..12fdf98984 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/go.mod @@ -0,0 +1,10 @@ +module github.com/sirupsen/logrus + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.1 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.2.2 + golang.org/x/sys v0.0.0-20190422165155-953cdadca894 +) diff --git a/vendor/github.com/sirupsen/logrus/go.sum b/vendor/github.com/sirupsen/logrus/go.sum new file mode 100644 index 0000000000..596c318b9f --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/go.sum @@ -0,0 +1,16 @@ +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/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +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/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go new file mode 100644 index 0000000000..3f151cdc39 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/hooks.go @@ -0,0 +1,34 @@ +package logrus + +// A hook to be fired when logging on the logging levels returned from +// `Levels()` on your implementation of the interface. Note that this is not +// fired in a goroutine or a channel with workers, you should handle such +// functionality yourself if your call is non-blocking and you don't wish for +// the logging calls for levels returned from `Levels()` to block. +type Hook interface { + Levels() []Level + Fire(*Entry) error +} + +// Internal type for storing the hooks on a logger instance. +type LevelHooks map[Level][]Hook + +// Add a hook to an instance of logger. This is called with +// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. +func (hooks LevelHooks) Add(hook Hook) { + for _, level := range hook.Levels() { + hooks[level] = append(hooks[level], hook) + } +} + +// Fire all the hooks for the passed level. Used by `entry.log` to fire +// appropriate hooks for a log entry. +func (hooks LevelHooks) Fire(level Level, entry *Entry) error { + for _, hook := range hooks[level] { + if err := hook.Fire(entry); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go new file mode 100644 index 0000000000..098a21a067 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -0,0 +1,121 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" + "runtime" +) + +type fieldKey string + +// FieldMap allows customization of the key names for default fields. +type FieldMap map[fieldKey]string + +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + +// JSONFormatter formats logs into parsable json +type JSONFormatter struct { + // TimestampFormat sets the format used for marshaling timestamps. + TimestampFormat string + + // DisableTimestamp allows disabling automatic timestamps in output + DisableTimestamp bool + + // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. + DataKey string + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message", + // FieldKeyFunc: "@caller", + // }, + // } + FieldMap FieldMap + + // CallerPrettyfier can be set by the user to modify the content + // of the function and file keys in the json data when ReportCaller is + // activated. If any of the returned value is the empty string the + // corresponding key will be removed from json fields. + CallerPrettyfier func(*runtime.Frame) (function string, file string) + + // PrettyPrint will indent all json logs + PrettyPrint bool +} + +// Format renders a single log entry +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields, len(entry.Data)+4) + for k, v := range entry.Data { + switch v := v.(type) { + case error: + // Otherwise errors are ignored by `encoding/json` + // https://github.com/sirupsen/logrus/issues/137 + data[k] = v.Error() + default: + data[k] = v + } + } + + if f.DataKey != "" { + newData := make(Fields, 4) + newData[f.DataKey] = data + data = newData + } + + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + + if entry.err != "" { + data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err + } + if !f.DisableTimestamp { + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + } + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() + if entry.HasCaller() { + funcVal := entry.Caller.Function + fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + if f.CallerPrettyfier != nil { + funcVal, fileVal = f.CallerPrettyfier(entry.Caller) + } + if funcVal != "" { + data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal + } + if fileVal != "" { + data[f.FieldMap.resolve(FieldKeyFile)] = fileVal + } + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + encoder := json.NewEncoder(b) + if f.PrettyPrint { + encoder.SetIndent("", " ") + } + if err := encoder.Encode(data); err != nil { + return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err) + } + + return b.Bytes(), nil +} diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go new file mode 100644 index 0000000000..c0c0b1e559 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -0,0 +1,351 @@ +package logrus + +import ( + "context" + "io" + "os" + "sync" + "sync/atomic" + "time" +) + +type Logger struct { + // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a + // file, or leave it default which is `os.Stderr`. You can also set this to + // something more adventurous, such as logging to Kafka. + Out io.Writer + // Hooks for the logger instance. These allow firing events based on logging + // levels and log entries. For example, to send errors to an error tracking + // service, log to StatsD or dump the core on fatal errors. + Hooks LevelHooks + // All log entries pass through the formatter before logged to Out. The + // included formatters are `TextFormatter` and `JSONFormatter` for which + // TextFormatter is the default. In development (when a TTY is attached) it + // logs with colors, but to a file it wouldn't. You can easily implement your + // own that implements the `Formatter` interface, see the `README` or included + // formatters for examples. + Formatter Formatter + + // Flag for whether to log caller info (off by default) + ReportCaller bool + + // The logging level the logger should log at. This is typically (and defaults + // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be + // logged. + Level Level + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap + // Reusable empty entry + entryPool sync.Pool + // Function to exit the application, defaults to `os.Exit()` + ExitFunc exitFunc +} + +type exitFunc func(int) + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true +} + +// Creates a new logger. Configuration should be set by changing `Formatter`, +// `Out` and `Hooks` directly on the default logger instance. You can also just +// instantiate your own: +// +// var log = &Logger{ +// Out: os.Stderr, +// Formatter: new(JSONFormatter), +// Hooks: make(LevelHooks), +// Level: logrus.DebugLevel, +// } +// +// It's recommended to make this a global instance called `log`. +func New() *Logger { + return &Logger{ + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, + ExitFunc: os.Exit, + ReportCaller: false, + } +} + +func (logger *Logger) newEntry() *Entry { + entry, ok := logger.entryPool.Get().(*Entry) + if ok { + return entry + } + return NewEntry(logger) +} + +func (logger *Logger) releaseEntry(entry *Entry) { + entry.Data = map[string]interface{}{} + logger.entryPool.Put(entry) +} + +// Adds a field to the log entry, note that it doesn't log until you call +// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. +// If you want multiple fields, use `WithFields`. +func (logger *Logger) WithField(key string, value interface{}) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithField(key, value) +} + +// Adds a struct of fields to the log entry. All it does is call `WithField` for +// each `Field`. +func (logger *Logger) WithFields(fields Fields) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithFields(fields) +} + +// Add an error as single field to the log entry. All it does is call +// `WithError` for the given `error`. +func (logger *Logger) WithError(err error) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithError(err) +} + +// Add a context to the log entry. +func (logger *Logger) WithContext(ctx context.Context) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithContext(ctx) +} + +// Overrides the time of the log entry. +func (logger *Logger) WithTime(t time.Time) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithTime(t) +} + +func (logger *Logger) Logf(level Level, format string, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Logf(level, format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Tracef(format string, args ...interface{}) { + logger.Logf(TraceLevel, format, args...) +} + +func (logger *Logger) Debugf(format string, args ...interface{}) { + logger.Logf(DebugLevel, format, args...) +} + +func (logger *Logger) Infof(format string, args ...interface{}) { + logger.Logf(InfoLevel, format, args...) +} + +func (logger *Logger) Printf(format string, args ...interface{}) { + entry := logger.newEntry() + entry.Printf(format, args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnf(format string, args ...interface{}) { + logger.Logf(WarnLevel, format, args...) +} + +func (logger *Logger) Warningf(format string, args ...interface{}) { + logger.Warnf(format, args...) +} + +func (logger *Logger) Errorf(format string, args ...interface{}) { + logger.Logf(ErrorLevel, format, args...) +} + +func (logger *Logger) Fatalf(format string, args ...interface{}) { + logger.Logf(FatalLevel, format, args...) + logger.Exit(1) +} + +func (logger *Logger) Panicf(format string, args ...interface{}) { + logger.Logf(PanicLevel, format, args...) +} + +func (logger *Logger) Log(level Level, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Log(level, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Trace(args ...interface{}) { + logger.Log(TraceLevel, args...) +} + +func (logger *Logger) Debug(args ...interface{}) { + logger.Log(DebugLevel, args...) +} + +func (logger *Logger) Info(args ...interface{}) { + logger.Log(InfoLevel, args...) +} + +func (logger *Logger) Print(args ...interface{}) { + entry := logger.newEntry() + entry.Print(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warn(args ...interface{}) { + logger.Log(WarnLevel, args...) +} + +func (logger *Logger) Warning(args ...interface{}) { + logger.Warn(args...) +} + +func (logger *Logger) Error(args ...interface{}) { + logger.Log(ErrorLevel, args...) +} + +func (logger *Logger) Fatal(args ...interface{}) { + logger.Log(FatalLevel, args...) + logger.Exit(1) +} + +func (logger *Logger) Panic(args ...interface{}) { + logger.Log(PanicLevel, args...) +} + +func (logger *Logger) Logln(level Level, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Logln(level, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Traceln(args ...interface{}) { + logger.Logln(TraceLevel, args...) +} + +func (logger *Logger) Debugln(args ...interface{}) { + logger.Logln(DebugLevel, args...) +} + +func (logger *Logger) Infoln(args ...interface{}) { + logger.Logln(InfoLevel, args...) +} + +func (logger *Logger) Println(args ...interface{}) { + entry := logger.newEntry() + entry.Println(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnln(args ...interface{}) { + logger.Logln(WarnLevel, args...) +} + +func (logger *Logger) Warningln(args ...interface{}) { + logger.Warnln(args...) +} + +func (logger *Logger) Errorln(args ...interface{}) { + logger.Logln(ErrorLevel, args...) +} + +func (logger *Logger) Fatalln(args ...interface{}) { + logger.Logln(FatalLevel, args...) + logger.Exit(1) +} + +func (logger *Logger) Panicln(args ...interface{}) { + logger.Logln(PanicLevel, args...) +} + +func (logger *Logger) Exit(code int) { + runHandlers() + if logger.ExitFunc == nil { + logger.ExitFunc = os.Exit + } + logger.ExitFunc(code) +} + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} + +func (logger *Logger) level() Level { + return Level(atomic.LoadUint32((*uint32)(&logger.Level))) +} + +// SetLevel sets the logger level. +func (logger *Logger) SetLevel(level Level) { + atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) +} + +// GetLevel returns the logger level. +func (logger *Logger) GetLevel() Level { + return logger.level() +} + +// AddHook adds a hook to the logger hooks. +func (logger *Logger) AddHook(hook Hook) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Hooks.Add(hook) +} + +// IsLevelEnabled checks if the log level of the logger is greater than the level param +func (logger *Logger) IsLevelEnabled(level Level) bool { + return logger.level() >= level +} + +// SetFormatter sets the logger formatter. +func (logger *Logger) SetFormatter(formatter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Formatter = formatter +} + +// SetOutput sets the logger output. +func (logger *Logger) SetOutput(output io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = output +} + +func (logger *Logger) SetReportCaller(reportCaller bool) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.ReportCaller = reportCaller +} + +// ReplaceHooks replaces the logger hooks and returns the old ones +func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { + logger.mu.Lock() + oldHooks := logger.Hooks + logger.Hooks = hooks + logger.mu.Unlock() + return oldHooks +} diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go new file mode 100644 index 0000000000..8644761f73 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -0,0 +1,186 @@ +package logrus + +import ( + "fmt" + "log" + "strings" +) + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Level type +type Level uint32 + +// Convert the Level to a string. E.g. PanicLevel becomes "panic". +func (level Level) String() string { + if b, err := level.MarshalText(); err == nil { + return string(b) + } else { + return "unknown" + } +} + +// ParseLevel takes a string level and returns the Logrus log level constant. +func ParseLevel(lvl string) (Level, error) { + switch strings.ToLower(lvl) { + case "panic": + return PanicLevel, nil + case "fatal": + return FatalLevel, nil + case "error": + return ErrorLevel, nil + case "warn", "warning": + return WarnLevel, nil + case "info": + return InfoLevel, nil + case "debug": + return DebugLevel, nil + case "trace": + return TraceLevel, nil + } + + var l Level + return l, fmt.Errorf("not a valid logrus Level: %q", lvl) +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (level *Level) UnmarshalText(text []byte) error { + l, err := ParseLevel(string(text)) + if err != nil { + return err + } + + *level = Level(l) + + return nil +} + +func (level Level) MarshalText() ([]byte, error) { + switch level { + case TraceLevel: + return []byte("trace"), nil + case DebugLevel: + return []byte("debug"), nil + case InfoLevel: + return []byte("info"), nil + case WarnLevel: + return []byte("warning"), nil + case ErrorLevel: + return []byte("error"), nil + case FatalLevel: + return []byte("fatal"), nil + case PanicLevel: + return []byte("panic"), nil + } + + return nil, fmt.Errorf("not a valid logrus level %d", level) +} + +// A constant exposing all logging levels +var AllLevels = []Level{ + PanicLevel, + FatalLevel, + ErrorLevel, + WarnLevel, + InfoLevel, + DebugLevel, + TraceLevel, +} + +// These are the different logging levels. You can set the logging level to log +// on your instance of logger, obtained with `logrus.New()`. +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel Level = iota + // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel + // TraceLevel level. Designates finer-grained informational events than the Debug. + TraceLevel +) + +// Won't compile if StdLogger can't be realized by a log.Logger +var ( + _ StdLogger = &log.Logger{} + _ StdLogger = &Entry{} + _ StdLogger = &Logger{} +) + +// StdLogger is what your logrus-enabled library should take, that way +// it'll accept a stdlib logger and a logrus logger. There's no standard +// interface, this is the closest we get, unfortunately. +type StdLogger interface { + Print(...interface{}) + Printf(string, ...interface{}) + Println(...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + Fatalln(...interface{}) + + Panic(...interface{}) + Panicf(string, ...interface{}) + Panicln(...interface{}) +} + +// The FieldLogger interface generalizes the Entry and Logger types +type FieldLogger interface { + WithField(key string, value interface{}) *Entry + WithFields(fields Fields) *Entry + WithError(err error) *Entry + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Printf(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Warningf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) + Panicf(format string, args ...interface{}) + + Debug(args ...interface{}) + Info(args ...interface{}) + Print(args ...interface{}) + Warn(args ...interface{}) + Warning(args ...interface{}) + Error(args ...interface{}) + Fatal(args ...interface{}) + Panic(args ...interface{}) + + Debugln(args ...interface{}) + Infoln(args ...interface{}) + Println(args ...interface{}) + Warnln(args ...interface{}) + Warningln(args ...interface{}) + Errorln(args ...interface{}) + Fatalln(args ...interface{}) + Panicln(args ...interface{}) + + // IsDebugEnabled() bool + // IsInfoEnabled() bool + // IsWarnEnabled() bool + // IsErrorEnabled() bool + // IsFatalEnabled() bool + // IsPanicEnabled() bool +} + +// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is +// here for consistancy. Do not use. Use Logger or Entry instead. +type Ext1FieldLogger interface { + FieldLogger + Tracef(format string, args ...interface{}) + Trace(args ...interface{}) + Traceln(args ...interface{}) +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go new file mode 100644 index 0000000000..2403de9819 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go @@ -0,0 +1,11 @@ +// +build appengine + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return true +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go new file mode 100644 index 0000000000..3c4f43f91c --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go @@ -0,0 +1,13 @@ +// +build darwin dragonfly freebsd netbsd openbsd + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TIOCGETA + +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + return err == nil +} + diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go new file mode 100644 index 0000000000..97af92c68e --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go @@ -0,0 +1,11 @@ +// +build js nacl plan9 + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go new file mode 100644 index 0000000000..3293fb3caa --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go @@ -0,0 +1,17 @@ +// +build !appengine,!js,!windows,!nacl,!plan9 + +package logrus + +import ( + "io" + "os" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return isTerminal(int(v.Fd())) + default: + return false + } +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go new file mode 100644 index 0000000000..f6710b3bd0 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go @@ -0,0 +1,11 @@ +package logrus + +import ( + "golang.org/x/sys/unix" +) + +// IsTerminal returns true if the given file descriptor is a terminal. +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermio(fd, unix.TCGETA) + return err == nil +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go new file mode 100644 index 0000000000..355dc966f0 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go @@ -0,0 +1,13 @@ +// +build linux aix + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS + +func isTerminal(fd int) bool { + _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + return err == nil +} + diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go new file mode 100644 index 0000000000..572889db21 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go @@ -0,0 +1,34 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func initTerminal(w io.Writer) { + switch v := w.(type) { + case *os.File: + sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) + } +} + +func checkIfTerminal(w io.Writer) bool { + var ret bool + switch v := w.(type) { + case *os.File: + var mode uint32 + err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) + ret = (err == nil) + default: + ret = false + } + if ret { + initTerminal(w) + } + return ret +} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go new file mode 100644 index 0000000000..e01587c437 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -0,0 +1,295 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "runtime" + "sort" + "strings" + "sync" + "time" +) + +const ( + red = 31 + yellow = 33 + blue = 36 + gray = 37 +) + +var baseTimestamp time.Time + +func init() { + baseTimestamp = time.Now() +} + +// TextFormatter formats logs into text +type TextFormatter struct { + // Set to true to bypass checking for a TTY before outputting colors. + ForceColors bool + + // Force disabling colors. + DisableColors bool + + // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ + EnvironmentOverrideColors bool + + // Disable timestamp logging. useful when output is redirected to logging + // system that already adds timestamps. + DisableTimestamp bool + + // Enable logging the full timestamp when a TTY is attached instead of just + // the time passed since beginning of execution. + FullTimestamp bool + + // TimestampFormat to use for display when a full timestamp is printed + TimestampFormat string + + // The fields are sorted by default for a consistent output. For applications + // that log extremely frequently and don't use the JSON formatter this may not + // be desired. + DisableSorting bool + + // The keys sorting function, when uninitialized it uses sort.Strings. + SortingFunc func([]string) + + // Disables the truncation of the level text to 4 characters. + DisableLevelTruncation bool + + // QuoteEmptyFields will wrap empty fields in quotes if true + QuoteEmptyFields bool + + // Whether the logger's out is to a terminal + isTerminal bool + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &TextFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message"}} + FieldMap FieldMap + + // CallerPrettyfier can be set by the user to modify the content + // of the function and file keys in the data when ReportCaller is + // activated. If any of the returned value is the empty string the + // corresponding key will be removed from fields. + CallerPrettyfier func(*runtime.Frame) (function string, file string) + + terminalInitOnce sync.Once +} + +func (f *TextFormatter) init(entry *Entry) { + if entry.Logger != nil { + f.isTerminal = checkIfTerminal(entry.Logger.Out) + } +} + +func (f *TextFormatter) isColored() bool { + isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows")) + + if f.EnvironmentOverrideColors { + if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { + isColored = true + } else if ok && force == "0" { + isColored = false + } else if os.Getenv("CLICOLOR") == "0" { + isColored = false + } + } + + return isColored && !f.DisableColors +} + +// Format renders a single log entry +func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields) + for k, v := range entry.Data { + data[k] = v + } + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + keys := make([]string, 0, len(data)) + for k := range data { + keys = append(keys, k) + } + + var funcVal, fileVal string + + fixedKeys := make([]string, 0, 4+len(data)) + if !f.DisableTimestamp { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) + } + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) + if entry.Message != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) + } + if entry.err != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) + } + if entry.HasCaller() { + if f.CallerPrettyfier != nil { + funcVal, fileVal = f.CallerPrettyfier(entry.Caller) + } else { + funcVal = entry.Caller.Function + fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + } + + if funcVal != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc)) + } + if fileVal != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile)) + } + } + + if !f.DisableSorting { + if f.SortingFunc == nil { + sort.Strings(keys) + fixedKeys = append(fixedKeys, keys...) + } else { + if !f.isColored() { + fixedKeys = append(fixedKeys, keys...) + f.SortingFunc(fixedKeys) + } else { + f.SortingFunc(keys) + } + } + } else { + fixedKeys = append(fixedKeys, keys...) + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + f.terminalInitOnce.Do(func() { f.init(entry) }) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + if f.isColored() { + f.printColored(b, entry, keys, data, timestampFormat) + } else { + + for _, key := range fixedKeys { + var value interface{} + switch { + case key == f.FieldMap.resolve(FieldKeyTime): + value = entry.Time.Format(timestampFormat) + case key == f.FieldMap.resolve(FieldKeyLevel): + value = entry.Level.String() + case key == f.FieldMap.resolve(FieldKeyMsg): + value = entry.Message + case key == f.FieldMap.resolve(FieldKeyLogrusError): + value = entry.err + case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): + value = funcVal + case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): + value = fileVal + default: + value = data[key] + } + f.appendKeyValue(b, key, value) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) { + var levelColor int + switch entry.Level { + case DebugLevel, TraceLevel: + levelColor = gray + case WarnLevel: + levelColor = yellow + case ErrorLevel, FatalLevel, PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String()) + if !f.DisableLevelTruncation { + levelText = levelText[0:4] + } + + // Remove a single newline if it already exists in the message to keep + // the behavior of logrus text_formatter the same as the stdlib log package + entry.Message = strings.TrimSuffix(entry.Message, "\n") + + caller := "" + if entry.HasCaller() { + funcVal := fmt.Sprintf("%s()", entry.Caller.Function) + fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + + if f.CallerPrettyfier != nil { + funcVal, fileVal = f.CallerPrettyfier(entry.Caller) + } + + if fileVal == "" { + caller = funcVal + } else if funcVal == "" { + caller = fileVal + } else { + caller = fileVal + " " + funcVal + } + } + + if f.DisableTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) + } else if !f.FullTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) + } else { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) + } + for _, k := range keys { + v := data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) + } +} + +func (f *TextFormatter) needsQuoting(text string) bool { + if f.QuoteEmptyFields && len(text) == 0 { + return true + } + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { + return true + } + } + return false +} + +func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + if b.Len() > 0 { + b.WriteByte(' ') + } + b.WriteString(key) + b.WriteByte('=') + f.appendValue(b, value) +} + +func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { + stringVal, ok := value.(string) + if !ok { + stringVal = fmt.Sprint(value) + } + + if !f.needsQuoting(stringVal) { + b.WriteString(stringVal) + } else { + b.WriteString(fmt.Sprintf("%q", stringVal)) + } +} diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go new file mode 100644 index 0000000000..9e1f751359 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/writer.go @@ -0,0 +1,64 @@ +package logrus + +import ( + "bufio" + "io" + "runtime" +) + +func (logger *Logger) Writer() *io.PipeWriter { + return logger.WriterLevel(InfoLevel) +} + +func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { + return NewEntry(logger).WriterLevel(level) +} + +func (entry *Entry) Writer() *io.PipeWriter { + return entry.WriterLevel(InfoLevel) +} + +func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { + reader, writer := io.Pipe() + + var printFunc func(args ...interface{}) + + switch level { + case TraceLevel: + printFunc = entry.Trace + case DebugLevel: + printFunc = entry.Debug + case InfoLevel: + printFunc = entry.Info + case WarnLevel: + printFunc = entry.Warn + case ErrorLevel: + printFunc = entry.Error + case FatalLevel: + printFunc = entry.Fatal + case PanicLevel: + printFunc = entry.Panic + default: + printFunc = entry.Print + } + + go entry.writerScanner(reader, printFunc) + runtime.SetFinalizer(writer, writerFinalizer) + + return writer +} + +func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + printFunc(scanner.Text()) + } + if err := scanner.Err(); err != nil { + entry.Errorf("Error while reading from Writer: %s", err) + } + reader.Close() +} + +func writerFinalizer(writer *io.PipeWriter) { + writer.Close() +} diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go new file mode 100644 index 0000000000..c7f8c7e64e --- /dev/null +++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go @@ -0,0 +1,222 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// In Go 1.13, the ed25519 package was promoted to the standard library as +// crypto/ed25519, and this package became a wrapper for the standard library one. +// +// +build !go1.13 + +// Package ed25519 implements the Ed25519 signature algorithm. See +// https://ed25519.cr.yp.to/. +// +// These functions are also compatible with the “Ed25519” function defined in +// RFC 8032. However, unlike RFC 8032's formulation, this package's private key +// representation includes a public key suffix to make multiple signing +// operations with the same key more efficient. This package refers to the RFC +// 8032 private key as the “seed”. +package ed25519 + +// This code is a port of the public domain, “ref10” implementation of ed25519 +// from SUPERCOP. + +import ( + "bytes" + "crypto" + cryptorand "crypto/rand" + "crypto/sha512" + "errors" + "io" + "strconv" + + "golang.org/x/crypto/ed25519/internal/edwards25519" +) + +const ( + // PublicKeySize is the size, in bytes, of public keys as used in this package. + PublicKeySize = 32 + // PrivateKeySize is the size, in bytes, of private keys as used in this package. + PrivateKeySize = 64 + // SignatureSize is the size, in bytes, of signatures generated and verified by this package. + SignatureSize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 32 +) + +// PublicKey is the type of Ed25519 public keys. +type PublicKey []byte + +// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. +type PrivateKey []byte + +// Public returns the PublicKey corresponding to priv. +func (priv PrivateKey) Public() crypto.PublicKey { + publicKey := make([]byte, PublicKeySize) + copy(publicKey, priv[32:]) + return PublicKey(publicKey) +} + +// Seed returns the private key seed corresponding to priv. It is provided for +// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds +// in this package. +func (priv PrivateKey) Seed() []byte { + seed := make([]byte, SeedSize) + copy(seed, priv[:32]) + return seed +} + +// Sign signs the given message with priv. +// Ed25519 performs two passes over messages to be signed and therefore cannot +// handle pre-hashed messages. Thus opts.HashFunc() must return zero to +// indicate the message hasn't been hashed. This can be achieved by passing +// crypto.Hash(0) as the value for opts. +func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("ed25519: cannot sign hashed message") + } + + return Sign(priv, message), nil +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { + if rand == nil { + rand = cryptorand.Reader + } + + seed := make([]byte, SeedSize) + if _, err := io.ReadFull(rand, seed); err != nil { + return nil, nil, err + } + + privateKey := NewKeyFromSeed(seed) + publicKey := make([]byte, PublicKeySize) + copy(publicKey, privateKey[32:]) + + return publicKey, privateKey, nil +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + if l := len(seed); l != SeedSize { + panic("ed25519: bad seed length: " + strconv.Itoa(l)) + } + + digest := sha512.Sum512(seed) + digest[0] &= 248 + digest[31] &= 127 + digest[31] |= 64 + + var A edwards25519.ExtendedGroupElement + var hBytes [32]byte + copy(hBytes[:], digest[:]) + edwards25519.GeScalarMultBase(&A, &hBytes) + var publicKeyBytes [32]byte + A.ToBytes(&publicKeyBytes) + + privateKey := make([]byte, PrivateKeySize) + copy(privateKey, seed) + copy(privateKey[32:], publicKeyBytes[:]) + + return privateKey +} + +// Sign signs the message with privateKey and returns a signature. It will +// panic if len(privateKey) is not PrivateKeySize. +func Sign(privateKey PrivateKey, message []byte) []byte { + if l := len(privateKey); l != PrivateKeySize { + panic("ed25519: bad private key length: " + strconv.Itoa(l)) + } + + h := sha512.New() + h.Write(privateKey[:32]) + + var digest1, messageDigest, hramDigest [64]byte + var expandedSecretKey [32]byte + h.Sum(digest1[:0]) + copy(expandedSecretKey[:], digest1[:]) + expandedSecretKey[0] &= 248 + expandedSecretKey[31] &= 63 + expandedSecretKey[31] |= 64 + + h.Reset() + h.Write(digest1[32:]) + h.Write(message) + h.Sum(messageDigest[:0]) + + var messageDigestReduced [32]byte + edwards25519.ScReduce(&messageDigestReduced, &messageDigest) + var R edwards25519.ExtendedGroupElement + edwards25519.GeScalarMultBase(&R, &messageDigestReduced) + + var encodedR [32]byte + R.ToBytes(&encodedR) + + h.Reset() + h.Write(encodedR[:]) + h.Write(privateKey[32:]) + h.Write(message) + h.Sum(hramDigest[:0]) + var hramDigestReduced [32]byte + edwards25519.ScReduce(&hramDigestReduced, &hramDigest) + + var s [32]byte + edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) + + signature := make([]byte, SignatureSize) + copy(signature[:], encodedR[:]) + copy(signature[32:], s[:]) + + return signature +} + +// Verify reports whether sig is a valid signature of message by publicKey. It +// will panic if len(publicKey) is not PublicKeySize. +func Verify(publicKey PublicKey, message, sig []byte) bool { + if l := len(publicKey); l != PublicKeySize { + panic("ed25519: bad public key length: " + strconv.Itoa(l)) + } + + if len(sig) != SignatureSize || sig[63]&224 != 0 { + return false + } + + var A edwards25519.ExtendedGroupElement + var publicKeyBytes [32]byte + copy(publicKeyBytes[:], publicKey) + if !A.FromBytes(&publicKeyBytes) { + return false + } + edwards25519.FeNeg(&A.X, &A.X) + edwards25519.FeNeg(&A.T, &A.T) + + h := sha512.New() + h.Write(sig[:32]) + h.Write(publicKey[:]) + h.Write(message) + var digest [64]byte + h.Sum(digest[:0]) + + var hReduced [32]byte + edwards25519.ScReduce(&hReduced, &digest) + + var R edwards25519.ProjectiveGroupElement + var s [32]byte + copy(s[:], sig[32:]) + + // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in + // the range [0, order) in order to prevent signature malleability. + if !edwards25519.ScMinimal(&s) { + return false + } + + edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) + + var checkR [32]byte + R.ToBytes(&checkR) + return bytes.Equal(sig[:32], checkR[:]) +} diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519_go113.go b/vendor/golang.org/x/crypto/ed25519/ed25519_go113.go new file mode 100644 index 0000000000..d1448d8d22 --- /dev/null +++ b/vendor/golang.org/x/crypto/ed25519/ed25519_go113.go @@ -0,0 +1,73 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.13 + +// Package ed25519 implements the Ed25519 signature algorithm. See +// https://ed25519.cr.yp.to/. +// +// These functions are also compatible with the “Ed25519” function defined in +// RFC 8032. However, unlike RFC 8032's formulation, this package's private key +// representation includes a public key suffix to make multiple signing +// operations with the same key more efficient. This package refers to the RFC +// 8032 private key as the “seed”. +// +// Beginning with Go 1.13, the functionality of this package was moved to the +// standard library as crypto/ed25519. This package only acts as a compatibility +// wrapper. +package ed25519 + +import ( + "crypto/ed25519" + "io" +) + +const ( + // PublicKeySize is the size, in bytes, of public keys as used in this package. + PublicKeySize = 32 + // PrivateKeySize is the size, in bytes, of private keys as used in this package. + PrivateKeySize = 64 + // SignatureSize is the size, in bytes, of signatures generated and verified by this package. + SignatureSize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 32 +) + +// PublicKey is the type of Ed25519 public keys. +// +// This type is an alias for crypto/ed25519's PublicKey type. +// See the crypto/ed25519 package for the methods on this type. +type PublicKey = ed25519.PublicKey + +// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. +// +// This type is an alias for crypto/ed25519's PrivateKey type. +// See the crypto/ed25519 package for the methods on this type. +type PrivateKey = ed25519.PrivateKey + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { + return ed25519.GenerateKey(rand) +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + return ed25519.NewKeyFromSeed(seed) +} + +// Sign signs the message with privateKey and returns a signature. It will +// panic if len(privateKey) is not PrivateKeySize. +func Sign(privateKey PrivateKey, message []byte) []byte { + return ed25519.Sign(privateKey, message) +} + +// Verify reports whether sig is a valid signature of message by publicKey. It +// will panic if len(publicKey) is not PublicKeySize. +func Verify(publicKey PublicKey, message, sig []byte) bool { + return ed25519.Verify(publicKey, message, sig) +} diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go new file mode 100644 index 0000000000..e39f086c1d --- /dev/null +++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go @@ -0,0 +1,1422 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +// These values are from the public domain, “ref10” implementation of ed25519 +// from SUPERCOP. + +// d is a constant in the Edwards curve equation. +var d = FieldElement{ + -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116, +} + +// d2 is 2*d. +var d2 = FieldElement{ + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199, +} + +// SqrtM1 is the square-root of -1 in the field. +var SqrtM1 = FieldElement{ + -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482, +} + +// A is a constant in the Montgomery-form of curve25519. +var A = FieldElement{ + 486662, 0, 0, 0, 0, 0, 0, 0, 0, 0, +} + +// bi contains precomputed multiples of the base-point. See the Ed25519 paper +// for a discussion about how these values are used. +var bi = [8]PreComputedGroupElement{ + { + FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + FieldElement{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + FieldElement{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}, + }, + { + FieldElement{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + FieldElement{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + FieldElement{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}, + }, + { + FieldElement{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + FieldElement{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + FieldElement{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}, + }, + { + FieldElement{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + FieldElement{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + FieldElement{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}, + }, + { + FieldElement{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877}, + FieldElement{-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951}, + FieldElement{4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}, + }, + { + FieldElement{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436}, + FieldElement{25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918}, + FieldElement{23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}, + }, + { + FieldElement{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800}, + FieldElement{-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305}, + FieldElement{-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}, + }, + { + FieldElement{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876}, + FieldElement{-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619}, + FieldElement{-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}, + }, +} + +// base contains precomputed multiples of the base-point. See the Ed25519 paper +// for a discussion about how these values are used. +var base = [32][8]PreComputedGroupElement{ + { + { + FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + FieldElement{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + FieldElement{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}, + }, + { + FieldElement{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303}, + FieldElement{-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081}, + FieldElement{26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}, + }, + { + FieldElement{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + FieldElement{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + FieldElement{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}, + }, + { + FieldElement{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540}, + FieldElement{23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397}, + FieldElement{7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}, + }, + { + FieldElement{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + FieldElement{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + FieldElement{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}, + }, + { + FieldElement{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777}, + FieldElement{-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737}, + FieldElement{-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}, + }, + { + FieldElement{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + FieldElement{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + FieldElement{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}, + }, + { + FieldElement{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726}, + FieldElement{-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955}, + FieldElement{27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}, + }, + }, + { + { + FieldElement{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171}, + FieldElement{27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510}, + FieldElement{17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}, + }, + { + FieldElement{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639}, + FieldElement{29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963}, + FieldElement{5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}, + }, + { + FieldElement{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568}, + FieldElement{12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335}, + FieldElement{25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}, + }, + { + FieldElement{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007}, + FieldElement{-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772}, + FieldElement{-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}, + }, + { + FieldElement{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567}, + FieldElement{13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686}, + FieldElement{21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}, + }, + { + FieldElement{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887}, + FieldElement{-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954}, + FieldElement{-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}, + }, + { + FieldElement{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833}, + FieldElement{-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532}, + FieldElement{-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}, + }, + { + FieldElement{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268}, + FieldElement{33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214}, + FieldElement{1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}, + }, + }, + { + { + FieldElement{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800}, + FieldElement{4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645}, + FieldElement{-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}, + }, + { + FieldElement{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933}, + FieldElement{-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182}, + FieldElement{-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}, + }, + { + FieldElement{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991}, + FieldElement{20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880}, + FieldElement{9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}, + }, + { + FieldElement{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295}, + FieldElement{19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788}, + FieldElement{8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}, + }, + { + FieldElement{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026}, + FieldElement{11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347}, + FieldElement{-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}, + }, + { + FieldElement{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395}, + FieldElement{-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278}, + FieldElement{1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}, + }, + { + FieldElement{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995}, + FieldElement{-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596}, + FieldElement{-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}, + }, + { + FieldElement{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060}, + FieldElement{11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608}, + FieldElement{-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}, + }, + }, + { + { + FieldElement{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389}, + FieldElement{-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016}, + FieldElement{-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}, + }, + { + FieldElement{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505}, + FieldElement{14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553}, + FieldElement{-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}, + }, + { + FieldElement{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220}, + FieldElement{12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631}, + FieldElement{-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}, + }, + { + FieldElement{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556}, + FieldElement{14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749}, + FieldElement{236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}, + }, + { + FieldElement{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391}, + FieldElement{5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253}, + FieldElement{20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}, + }, + { + FieldElement{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958}, + FieldElement{-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082}, + FieldElement{-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}, + }, + { + FieldElement{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521}, + FieldElement{-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807}, + FieldElement{23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}, + }, + { + FieldElement{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134}, + FieldElement{-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455}, + FieldElement{27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}, + }, + }, + { + { + FieldElement{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069}, + FieldElement{-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746}, + FieldElement{24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}, + }, + { + FieldElement{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837}, + FieldElement{8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906}, + FieldElement{-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}, + }, + { + FieldElement{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817}, + FieldElement{10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098}, + FieldElement{10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}, + }, + { + FieldElement{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504}, + FieldElement{-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727}, + FieldElement{28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}, + }, + { + FieldElement{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003}, + FieldElement{-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605}, + FieldElement{-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}, + }, + { + FieldElement{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701}, + FieldElement{-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683}, + FieldElement{29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}, + }, + { + FieldElement{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563}, + FieldElement{-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260}, + FieldElement{-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}, + }, + { + FieldElement{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672}, + FieldElement{23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686}, + FieldElement{-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}, + }, + }, + { + { + FieldElement{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182}, + FieldElement{-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277}, + FieldElement{14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}, + }, + { + FieldElement{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474}, + FieldElement{-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539}, + FieldElement{-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}, + }, + { + FieldElement{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970}, + FieldElement{19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756}, + FieldElement{-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}, + }, + { + FieldElement{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683}, + FieldElement{-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655}, + FieldElement{-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}, + }, + { + FieldElement{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125}, + FieldElement{-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839}, + FieldElement{-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}, + }, + { + FieldElement{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294}, + FieldElement{-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899}, + FieldElement{-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}, + }, + { + FieldElement{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294}, + FieldElement{-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949}, + FieldElement{-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}, + }, + { + FieldElement{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420}, + FieldElement{-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940}, + FieldElement{29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}, + }, + }, + { + { + FieldElement{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567}, + FieldElement{20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127}, + FieldElement{-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}, + }, + { + FieldElement{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887}, + FieldElement{22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964}, + FieldElement{16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}, + }, + { + FieldElement{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244}, + FieldElement{24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999}, + FieldElement{-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}, + }, + { + FieldElement{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274}, + FieldElement{-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236}, + FieldElement{-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}, + }, + { + FieldElement{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761}, + FieldElement{-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884}, + FieldElement{-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}, + }, + { + FieldElement{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638}, + FieldElement{-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490}, + FieldElement{-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}, + }, + { + FieldElement{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736}, + FieldElement{10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124}, + FieldElement{-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}, + }, + { + FieldElement{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029}, + FieldElement{6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048}, + FieldElement{28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}, + }, + }, + { + { + FieldElement{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593}, + FieldElement{26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071}, + FieldElement{-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}, + }, + { + FieldElement{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687}, + FieldElement{-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441}, + FieldElement{-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}, + }, + { + FieldElement{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460}, + FieldElement{-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007}, + FieldElement{-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}, + }, + { + FieldElement{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005}, + FieldElement{-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674}, + FieldElement{4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}, + }, + { + FieldElement{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590}, + FieldElement{-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957}, + FieldElement{-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}, + }, + { + FieldElement{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740}, + FieldElement{-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122}, + FieldElement{-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}, + }, + { + FieldElement{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885}, + FieldElement{26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140}, + FieldElement{19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}, + }, + { + FieldElement{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155}, + FieldElement{19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260}, + FieldElement{19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}, + }, + }, + { + { + FieldElement{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677}, + FieldElement{32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815}, + FieldElement{22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}, + }, + { + FieldElement{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203}, + FieldElement{-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208}, + FieldElement{1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}, + }, + { + FieldElement{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850}, + FieldElement{-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389}, + FieldElement{-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}, + }, + { + FieldElement{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689}, + FieldElement{14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880}, + FieldElement{5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}, + }, + { + FieldElement{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632}, + FieldElement{-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412}, + FieldElement{20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}, + }, + { + FieldElement{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038}, + FieldElement{-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232}, + FieldElement{-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}, + }, + { + FieldElement{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856}, + FieldElement{23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738}, + FieldElement{15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}, + }, + { + FieldElement{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718}, + FieldElement{-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697}, + FieldElement{-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}, + }, + }, + { + { + FieldElement{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912}, + FieldElement{-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358}, + FieldElement{3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}, + }, + { + FieldElement{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307}, + FieldElement{-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977}, + FieldElement{-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}, + }, + { + FieldElement{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644}, + FieldElement{-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616}, + FieldElement{-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}, + }, + { + FieldElement{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099}, + FieldElement{29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341}, + FieldElement{-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}, + }, + { + FieldElement{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646}, + FieldElement{31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425}, + FieldElement{-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}, + }, + { + FieldElement{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743}, + FieldElement{-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822}, + FieldElement{-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}, + }, + { + FieldElement{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985}, + FieldElement{9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702}, + FieldElement{-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}, + }, + { + FieldElement{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293}, + FieldElement{27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100}, + FieldElement{19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}, + }, + }, + { + { + FieldElement{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186}, + FieldElement{2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610}, + FieldElement{-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}, + }, + { + FieldElement{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220}, + FieldElement{915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025}, + FieldElement{32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}, + }, + { + FieldElement{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992}, + FieldElement{-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027}, + FieldElement{21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}, + }, + { + FieldElement{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901}, + FieldElement{31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952}, + FieldElement{19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}, + }, + { + FieldElement{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390}, + FieldElement{32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730}, + FieldElement{2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}, + }, + { + FieldElement{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180}, + FieldElement{-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272}, + FieldElement{-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}, + }, + { + FieldElement{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970}, + FieldElement{-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772}, + FieldElement{-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}, + }, + { + FieldElement{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750}, + FieldElement{20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373}, + FieldElement{32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}, + }, + }, + { + { + FieldElement{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144}, + FieldElement{-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195}, + FieldElement{5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}, + }, + { + FieldElement{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684}, + FieldElement{-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518}, + FieldElement{-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}, + }, + { + FieldElement{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793}, + FieldElement{-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794}, + FieldElement{580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}, + }, + { + FieldElement{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921}, + FieldElement{13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518}, + FieldElement{2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}, + }, + { + FieldElement{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278}, + FieldElement{-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024}, + FieldElement{4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}, + }, + { + FieldElement{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783}, + FieldElement{27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717}, + FieldElement{6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}, + }, + { + FieldElement{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333}, + FieldElement{16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048}, + FieldElement{22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}, + }, + { + FieldElement{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760}, + FieldElement{-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757}, + FieldElement{-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}, + }, + }, + { + { + FieldElement{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468}, + FieldElement{3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184}, + FieldElement{10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}, + }, + { + FieldElement{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066}, + FieldElement{24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882}, + FieldElement{13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}, + }, + { + FieldElement{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101}, + FieldElement{29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279}, + FieldElement{-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}, + }, + { + FieldElement{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709}, + FieldElement{20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714}, + FieldElement{-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}, + }, + { + FieldElement{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464}, + FieldElement{12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847}, + FieldElement{13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}, + }, + { + FieldElement{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414}, + FieldElement{-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158}, + FieldElement{17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}, + }, + { + FieldElement{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415}, + FieldElement{-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459}, + FieldElement{-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}, + }, + { + FieldElement{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412}, + FieldElement{-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743}, + FieldElement{-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}, + }, + }, + { + { + FieldElement{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022}, + FieldElement{18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429}, + FieldElement{-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}, + }, + { + FieldElement{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861}, + FieldElement{10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000}, + FieldElement{-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}, + }, + { + FieldElement{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815}, + FieldElement{29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642}, + FieldElement{10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}, + }, + { + FieldElement{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574}, + FieldElement{-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742}, + FieldElement{-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}, + }, + { + FieldElement{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020}, + FieldElement{-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772}, + FieldElement{3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}, + }, + { + FieldElement{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953}, + FieldElement{-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218}, + FieldElement{-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}, + }, + { + FieldElement{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073}, + FieldElement{-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325}, + FieldElement{-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}, + }, + { + FieldElement{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870}, + FieldElement{-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863}, + FieldElement{-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}, + }, + }, + { + { + FieldElement{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267}, + FieldElement{-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663}, + FieldElement{22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}, + }, + { + FieldElement{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673}, + FieldElement{15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943}, + FieldElement{15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}, + }, + { + FieldElement{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238}, + FieldElement{11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064}, + FieldElement{14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}, + }, + { + FieldElement{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052}, + FieldElement{-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904}, + FieldElement{29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}, + }, + { + FieldElement{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979}, + FieldElement{-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841}, + FieldElement{10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}, + }, + { + FieldElement{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324}, + FieldElement{-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940}, + FieldElement{10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}, + }, + { + FieldElement{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184}, + FieldElement{14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114}, + FieldElement{30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}, + }, + { + FieldElement{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784}, + FieldElement{-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091}, + FieldElement{-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}, + }, + }, + { + { + FieldElement{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208}, + FieldElement{10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864}, + FieldElement{17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}, + }, + { + FieldElement{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233}, + FieldElement{26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212}, + FieldElement{-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}, + }, + { + FieldElement{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068}, + FieldElement{9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397}, + FieldElement{-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}, + }, + { + FieldElement{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889}, + FieldElement{32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038}, + FieldElement{14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}, + }, + { + FieldElement{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875}, + FieldElement{-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905}, + FieldElement{-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}, + }, + { + FieldElement{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818}, + FieldElement{27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714}, + FieldElement{10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}, + }, + { + FieldElement{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931}, + FieldElement{-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024}, + FieldElement{-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}, + }, + { + FieldElement{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204}, + FieldElement{20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817}, + FieldElement{27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}, + }, + }, + { + { + FieldElement{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504}, + FieldElement{-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768}, + FieldElement{-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}, + }, + { + FieldElement{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790}, + FieldElement{1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438}, + FieldElement{-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}, + }, + { + FieldElement{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971}, + FieldElement{31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905}, + FieldElement{29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}, + }, + { + FieldElement{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409}, + FieldElement{6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499}, + FieldElement{-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}, + }, + { + FieldElement{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664}, + FieldElement{-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324}, + FieldElement{-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}, + }, + { + FieldElement{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990}, + FieldElement{-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914}, + FieldElement{-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}, + }, + { + FieldElement{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257}, + FieldElement{-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433}, + FieldElement{-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}, + }, + { + FieldElement{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045}, + FieldElement{11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093}, + FieldElement{-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}, + }, + }, + { + { + FieldElement{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191}, + FieldElement{-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507}, + FieldElement{-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}, + }, + { + FieldElement{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018}, + FieldElement{-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109}, + FieldElement{-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}, + }, + { + FieldElement{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528}, + FieldElement{8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625}, + FieldElement{-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}, + }, + { + FieldElement{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033}, + FieldElement{27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866}, + FieldElement{21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}, + }, + { + FieldElement{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075}, + FieldElement{26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347}, + FieldElement{-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}, + }, + { + FieldElement{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165}, + FieldElement{-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588}, + FieldElement{-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}, + }, + { + FieldElement{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017}, + FieldElement{-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883}, + FieldElement{21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}, + }, + { + FieldElement{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043}, + FieldElement{29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663}, + FieldElement{-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}, + }, + }, + { + { + FieldElement{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860}, + FieldElement{2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466}, + FieldElement{-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}, + }, + { + FieldElement{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997}, + FieldElement{-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295}, + FieldElement{-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}, + }, + { + FieldElement{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385}, + FieldElement{18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109}, + FieldElement{2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}, + }, + { + FieldElement{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424}, + FieldElement{-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185}, + FieldElement{7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}, + }, + { + FieldElement{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325}, + FieldElement{10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593}, + FieldElement{696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}, + }, + { + FieldElement{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644}, + FieldElement{17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801}, + FieldElement{26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}, + }, + { + FieldElement{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884}, + FieldElement{-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577}, + FieldElement{-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}, + }, + { + FieldElement{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473}, + FieldElement{-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644}, + FieldElement{-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}, + }, + }, + { + { + FieldElement{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599}, + FieldElement{-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768}, + FieldElement{-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}, + }, + { + FieldElement{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328}, + FieldElement{-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369}, + FieldElement{20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}, + }, + { + FieldElement{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815}, + FieldElement{-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025}, + FieldElement{-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}, + }, + { + FieldElement{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448}, + FieldElement{6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981}, + FieldElement{30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}, + }, + { + FieldElement{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501}, + FieldElement{17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073}, + FieldElement{-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}, + }, + { + FieldElement{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845}, + FieldElement{-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211}, + FieldElement{18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}, + }, + { + FieldElement{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096}, + FieldElement{33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803}, + FieldElement{-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}, + }, + { + FieldElement{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965}, + FieldElement{-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505}, + FieldElement{18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}, + }, + }, + { + { + FieldElement{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782}, + FieldElement{5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900}, + FieldElement{-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}, + }, + { + FieldElement{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208}, + FieldElement{8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232}, + FieldElement{17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}, + }, + { + FieldElement{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271}, + FieldElement{-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326}, + FieldElement{-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}, + }, + { + FieldElement{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300}, + FieldElement{8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570}, + FieldElement{15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}, + }, + { + FieldElement{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994}, + FieldElement{-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913}, + FieldElement{31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}, + }, + { + FieldElement{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730}, + FieldElement{842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096}, + FieldElement{-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}, + }, + { + FieldElement{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411}, + FieldElement{-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905}, + FieldElement{-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}, + }, + { + FieldElement{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870}, + FieldElement{-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498}, + FieldElement{12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}, + }, + }, + { + { + FieldElement{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677}, + FieldElement{10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647}, + FieldElement{-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}, + }, + { + FieldElement{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468}, + FieldElement{21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375}, + FieldElement{-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}, + }, + { + FieldElement{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725}, + FieldElement{-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612}, + FieldElement{-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}, + }, + { + FieldElement{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944}, + FieldElement{30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928}, + FieldElement{9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}, + }, + { + FieldElement{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139}, + FieldElement{-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963}, + FieldElement{-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}, + }, + { + FieldElement{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734}, + FieldElement{-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680}, + FieldElement{-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}, + }, + { + FieldElement{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931}, + FieldElement{-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654}, + FieldElement{22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}, + }, + { + FieldElement{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180}, + FieldElement{-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684}, + FieldElement{-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}, + }, + }, + { + { + FieldElement{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501}, + FieldElement{-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413}, + FieldElement{6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}, + }, + { + FieldElement{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874}, + FieldElement{22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962}, + FieldElement{-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}, + }, + { + FieldElement{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152}, + FieldElement{9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063}, + FieldElement{7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}, + }, + { + FieldElement{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146}, + FieldElement{-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183}, + FieldElement{-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}, + }, + { + FieldElement{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421}, + FieldElement{-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622}, + FieldElement{-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}, + }, + { + FieldElement{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663}, + FieldElement{31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753}, + FieldElement{4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}, + }, + { + FieldElement{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862}, + FieldElement{-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118}, + FieldElement{26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}, + }, + { + FieldElement{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380}, + FieldElement{16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824}, + FieldElement{28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}, + }, + }, + { + { + FieldElement{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438}, + FieldElement{-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584}, + FieldElement{-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}, + }, + { + FieldElement{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471}, + FieldElement{18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610}, + FieldElement{19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}, + }, + { + FieldElement{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650}, + FieldElement{14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369}, + FieldElement{19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}, + }, + { + FieldElement{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462}, + FieldElement{-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793}, + FieldElement{-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}, + }, + { + FieldElement{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226}, + FieldElement{18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019}, + FieldElement{-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}, + }, + { + FieldElement{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171}, + FieldElement{-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132}, + FieldElement{-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}, + }, + { + FieldElement{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181}, + FieldElement{-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210}, + FieldElement{-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}, + }, + { + FieldElement{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935}, + FieldElement{24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105}, + FieldElement{-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}, + }, + }, + { + { + FieldElement{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852}, + FieldElement{5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581}, + FieldElement{-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}, + }, + { + FieldElement{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844}, + FieldElement{10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025}, + FieldElement{27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}, + }, + { + FieldElement{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068}, + FieldElement{4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192}, + FieldElement{-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}, + }, + { + FieldElement{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259}, + FieldElement{-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426}, + FieldElement{-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}, + }, + { + FieldElement{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305}, + FieldElement{13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832}, + FieldElement{28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}, + }, + { + FieldElement{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011}, + FieldElement{24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447}, + FieldElement{17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}, + }, + { + FieldElement{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245}, + FieldElement{-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859}, + FieldElement{28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}, + }, + { + FieldElement{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707}, + FieldElement{10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848}, + FieldElement{-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}, + }, + }, + { + { + FieldElement{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391}, + FieldElement{15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215}, + FieldElement{-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}, + }, + { + FieldElement{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713}, + FieldElement{21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849}, + FieldElement{-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}, + }, + { + FieldElement{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940}, + FieldElement{-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031}, + FieldElement{-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}, + }, + { + FieldElement{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243}, + FieldElement{-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116}, + FieldElement{-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}, + }, + { + FieldElement{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509}, + FieldElement{-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883}, + FieldElement{15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}, + }, + { + FieldElement{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660}, + FieldElement{4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273}, + FieldElement{-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}, + }, + { + FieldElement{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560}, + FieldElement{-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135}, + FieldElement{2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}, + }, + { + FieldElement{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739}, + FieldElement{18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756}, + FieldElement{-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}, + }, + }, + { + { + FieldElement{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347}, + FieldElement{-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028}, + FieldElement{21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}, + }, + { + FieldElement{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799}, + FieldElement{-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609}, + FieldElement{-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}, + }, + { + FieldElement{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989}, + FieldElement{-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523}, + FieldElement{4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}, + }, + { + FieldElement{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045}, + FieldElement{19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377}, + FieldElement{24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}, + }, + { + FieldElement{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016}, + FieldElement{510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426}, + FieldElement{18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}, + }, + { + FieldElement{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396}, + FieldElement{9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080}, + FieldElement{12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}, + }, + { + FieldElement{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275}, + FieldElement{11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074}, + FieldElement{20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}, + }, + { + FieldElement{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717}, + FieldElement{-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101}, + FieldElement{24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}, + }, + }, + { + { + FieldElement{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632}, + FieldElement{-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415}, + FieldElement{-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}, + }, + { + FieldElement{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876}, + FieldElement{22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625}, + FieldElement{-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}, + }, + { + FieldElement{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164}, + FieldElement{26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595}, + FieldElement{-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}, + }, + { + FieldElement{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858}, + FieldElement{15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193}, + FieldElement{8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}, + }, + { + FieldElement{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942}, + FieldElement{-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635}, + FieldElement{21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}, + }, + { + FieldElement{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935}, + FieldElement{-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415}, + FieldElement{-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}, + }, + { + FieldElement{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018}, + FieldElement{4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778}, + FieldElement{366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}, + }, + { + FieldElement{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385}, + FieldElement{18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503}, + FieldElement{476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}, + }, + }, + { + { + FieldElement{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056}, + FieldElement{-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838}, + FieldElement{24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}, + }, + { + FieldElement{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691}, + FieldElement{-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118}, + FieldElement{-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}, + }, + { + FieldElement{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269}, + FieldElement{-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904}, + FieldElement{-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}, + }, + { + FieldElement{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193}, + FieldElement{-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910}, + FieldElement{-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}, + }, + { + FieldElement{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667}, + FieldElement{25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481}, + FieldElement{-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}, + }, + { + FieldElement{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640}, + FieldElement{-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278}, + FieldElement{-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}, + }, + { + FieldElement{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272}, + FieldElement{17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012}, + FieldElement{-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}, + }, + { + FieldElement{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046}, + FieldElement{13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345}, + FieldElement{-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}, + }, + }, + { + { + FieldElement{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937}, + FieldElement{31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636}, + FieldElement{-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}, + }, + { + FieldElement{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429}, + FieldElement{-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576}, + FieldElement{31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}, + }, + { + FieldElement{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490}, + FieldElement{-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104}, + FieldElement{33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}, + }, + { + FieldElement{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275}, + FieldElement{-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511}, + FieldElement{22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}, + }, + { + FieldElement{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439}, + FieldElement{23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939}, + FieldElement{-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}, + }, + { + FieldElement{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310}, + FieldElement{3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608}, + FieldElement{-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}, + }, + { + FieldElement{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101}, + FieldElement{21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418}, + FieldElement{18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}, + }, + { + FieldElement{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356}, + FieldElement{9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996}, + FieldElement{-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}, + }, + }, + { + { + FieldElement{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728}, + FieldElement{-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658}, + FieldElement{-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}, + }, + { + FieldElement{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001}, + FieldElement{-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766}, + FieldElement{18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}, + }, + { + FieldElement{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458}, + FieldElement{-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628}, + FieldElement{-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}, + }, + { + FieldElement{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062}, + FieldElement{25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616}, + FieldElement{31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}, + }, + { + FieldElement{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383}, + FieldElement{-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814}, + FieldElement{-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}, + }, + { + FieldElement{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417}, + FieldElement{2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222}, + FieldElement{33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}, + }, + { + FieldElement{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597}, + FieldElement{23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970}, + FieldElement{1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}, + }, + { + FieldElement{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647}, + FieldElement{13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511}, + FieldElement{-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}, + }, + }, + { + { + FieldElement{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834}, + FieldElement{-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461}, + FieldElement{29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}, + }, + { + FieldElement{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516}, + FieldElement{-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547}, + FieldElement{-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}, + }, + { + FieldElement{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038}, + FieldElement{-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741}, + FieldElement{16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}, + }, + { + FieldElement{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747}, + FieldElement{-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323}, + FieldElement{31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}, + }, + { + FieldElement{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373}, + FieldElement{15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228}, + FieldElement{-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}, + }, + { + FieldElement{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399}, + FieldElement{11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831}, + FieldElement{-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}, + }, + { + FieldElement{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313}, + FieldElement{-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958}, + FieldElement{-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}, + }, + { + FieldElement{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743}, + FieldElement{29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684}, + FieldElement{-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}, + }, + }, +} diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go new file mode 100644 index 0000000000..fd03c252af --- /dev/null +++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go @@ -0,0 +1,1793 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +import "encoding/binary" + +// This code is a port of the public domain, “ref10” implementation of ed25519 +// from SUPERCOP. + +// FieldElement represents an element of the field GF(2^255 - 19). An element +// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 +// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on +// context. +type FieldElement [10]int32 + +var zero FieldElement + +func FeZero(fe *FieldElement) { + copy(fe[:], zero[:]) +} + +func FeOne(fe *FieldElement) { + FeZero(fe) + fe[0] = 1 +} + +func FeAdd(dst, a, b *FieldElement) { + dst[0] = a[0] + b[0] + dst[1] = a[1] + b[1] + dst[2] = a[2] + b[2] + dst[3] = a[3] + b[3] + dst[4] = a[4] + b[4] + dst[5] = a[5] + b[5] + dst[6] = a[6] + b[6] + dst[7] = a[7] + b[7] + dst[8] = a[8] + b[8] + dst[9] = a[9] + b[9] +} + +func FeSub(dst, a, b *FieldElement) { + dst[0] = a[0] - b[0] + dst[1] = a[1] - b[1] + dst[2] = a[2] - b[2] + dst[3] = a[3] - b[3] + dst[4] = a[4] - b[4] + dst[5] = a[5] - b[5] + dst[6] = a[6] - b[6] + dst[7] = a[7] - b[7] + dst[8] = a[8] - b[8] + dst[9] = a[9] - b[9] +} + +func FeCopy(dst, src *FieldElement) { + copy(dst[:], src[:]) +} + +// Replace (f,g) with (g,g) if b == 1; +// replace (f,g) with (f,g) if b == 0. +// +// Preconditions: b in {0,1}. +func FeCMove(f, g *FieldElement, b int32) { + b = -b + f[0] ^= b & (f[0] ^ g[0]) + f[1] ^= b & (f[1] ^ g[1]) + f[2] ^= b & (f[2] ^ g[2]) + f[3] ^= b & (f[3] ^ g[3]) + f[4] ^= b & (f[4] ^ g[4]) + f[5] ^= b & (f[5] ^ g[5]) + f[6] ^= b & (f[6] ^ g[6]) + f[7] ^= b & (f[7] ^ g[7]) + f[8] ^= b & (f[8] ^ g[8]) + f[9] ^= b & (f[9] ^ g[9]) +} + +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +func load4(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +func FeFromBytes(dst *FieldElement, src *[32]byte) { + h0 := load4(src[:]) + h1 := load3(src[4:]) << 6 + h2 := load3(src[7:]) << 5 + h3 := load3(src[10:]) << 3 + h4 := load3(src[13:]) << 2 + h5 := load4(src[16:]) + h6 := load3(src[20:]) << 7 + h7 := load3(src[23:]) << 5 + h8 := load3(src[26:]) << 4 + h9 := (load3(src[29:]) & 8388607) << 2 + + FeCombine(dst, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +// FeToBytes marshals h to s. +// Preconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Write p=2^255-19; q=floor(h/p). +// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). +// +// Proof: +// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. +// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. +// +// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). +// Then 0> 25 + q = (h[0] + q) >> 26 + q = (h[1] + q) >> 25 + q = (h[2] + q) >> 26 + q = (h[3] + q) >> 25 + q = (h[4] + q) >> 26 + q = (h[5] + q) >> 25 + q = (h[6] + q) >> 26 + q = (h[7] + q) >> 25 + q = (h[8] + q) >> 26 + q = (h[9] + q) >> 25 + + // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. + h[0] += 19 * q + // Goal: Output h-2^255 q, which is between 0 and 2^255-20. + + carry[0] = h[0] >> 26 + h[1] += carry[0] + h[0] -= carry[0] << 26 + carry[1] = h[1] >> 25 + h[2] += carry[1] + h[1] -= carry[1] << 25 + carry[2] = h[2] >> 26 + h[3] += carry[2] + h[2] -= carry[2] << 26 + carry[3] = h[3] >> 25 + h[4] += carry[3] + h[3] -= carry[3] << 25 + carry[4] = h[4] >> 26 + h[5] += carry[4] + h[4] -= carry[4] << 26 + carry[5] = h[5] >> 25 + h[6] += carry[5] + h[5] -= carry[5] << 25 + carry[6] = h[6] >> 26 + h[7] += carry[6] + h[6] -= carry[6] << 26 + carry[7] = h[7] >> 25 + h[8] += carry[7] + h[7] -= carry[7] << 25 + carry[8] = h[8] >> 26 + h[9] += carry[8] + h[8] -= carry[8] << 26 + carry[9] = h[9] >> 25 + h[9] -= carry[9] << 25 + // h10 = carry9 + + // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; + // evidently 2^255 h10-2^255 q = 0. + // Goal: Output h[0]+...+2^230 h[9]. + + s[0] = byte(h[0] >> 0) + s[1] = byte(h[0] >> 8) + s[2] = byte(h[0] >> 16) + s[3] = byte((h[0] >> 24) | (h[1] << 2)) + s[4] = byte(h[1] >> 6) + s[5] = byte(h[1] >> 14) + s[6] = byte((h[1] >> 22) | (h[2] << 3)) + s[7] = byte(h[2] >> 5) + s[8] = byte(h[2] >> 13) + s[9] = byte((h[2] >> 21) | (h[3] << 5)) + s[10] = byte(h[3] >> 3) + s[11] = byte(h[3] >> 11) + s[12] = byte((h[3] >> 19) | (h[4] << 6)) + s[13] = byte(h[4] >> 2) + s[14] = byte(h[4] >> 10) + s[15] = byte(h[4] >> 18) + s[16] = byte(h[5] >> 0) + s[17] = byte(h[5] >> 8) + s[18] = byte(h[5] >> 16) + s[19] = byte((h[5] >> 24) | (h[6] << 1)) + s[20] = byte(h[6] >> 7) + s[21] = byte(h[6] >> 15) + s[22] = byte((h[6] >> 23) | (h[7] << 3)) + s[23] = byte(h[7] >> 5) + s[24] = byte(h[7] >> 13) + s[25] = byte((h[7] >> 21) | (h[8] << 4)) + s[26] = byte(h[8] >> 4) + s[27] = byte(h[8] >> 12) + s[28] = byte((h[8] >> 20) | (h[9] << 6)) + s[29] = byte(h[9] >> 2) + s[30] = byte(h[9] >> 10) + s[31] = byte(h[9] >> 18) +} + +func FeIsNegative(f *FieldElement) byte { + var s [32]byte + FeToBytes(&s, f) + return s[0] & 1 +} + +func FeIsNonZero(f *FieldElement) int32 { + var s [32]byte + FeToBytes(&s, f) + var x uint8 + for _, b := range s { + x |= b + } + x |= x >> 4 + x |= x >> 2 + x |= x >> 1 + return int32(x & 1) +} + +// FeNeg sets h = -f +// +// Preconditions: +// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func FeNeg(h, f *FieldElement) { + h[0] = -f[0] + h[1] = -f[1] + h[2] = -f[2] + h[3] = -f[3] + h[4] = -f[4] + h[5] = -f[5] + h[6] = -f[6] + h[7] = -f[7] + h[8] = -f[8] + h[9] = -f[9] +} + +func FeCombine(h *FieldElement, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { + var c0, c1, c2, c3, c4, c5, c6, c7, c8, c9 int64 + + /* + |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 + */ + + c0 = (h0 + (1 << 25)) >> 26 + h1 += c0 + h0 -= c0 << 26 + c4 = (h4 + (1 << 25)) >> 26 + h5 += c4 + h4 -= c4 << 26 + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.51*2^58 */ + /* |h5| <= 1.51*2^58 */ + + c1 = (h1 + (1 << 24)) >> 25 + h2 += c1 + h1 -= c1 << 25 + c5 = (h5 + (1 << 24)) >> 25 + h6 += c5 + h5 -= c5 << 25 + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.21*2^59 */ + /* |h6| <= 1.21*2^59 */ + + c2 = (h2 + (1 << 25)) >> 26 + h3 += c2 + h2 -= c2 << 26 + c6 = (h6 + (1 << 25)) >> 26 + h7 += c6 + h6 -= c6 << 26 + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.51*2^58 */ + /* |h7| <= 1.51*2^58 */ + + c3 = (h3 + (1 << 24)) >> 25 + h4 += c3 + h3 -= c3 << 25 + c7 = (h7 + (1 << 24)) >> 25 + h8 += c7 + h7 -= c7 << 25 + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.52*2^33 */ + /* |h8| <= 1.52*2^33 */ + + c4 = (h4 + (1 << 25)) >> 26 + h5 += c4 + h4 -= c4 << 26 + c8 = (h8 + (1 << 25)) >> 26 + h9 += c8 + h8 -= c8 << 26 + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.51*2^58 */ + + c9 = (h9 + (1 << 24)) >> 25 + h0 += c9 * 19 + h9 -= c9 << 25 + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.8*2^37 */ + + c0 = (h0 + (1 << 25)) >> 26 + h1 += c0 + h0 -= c0 << 26 + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// FeMul calculates h = f * g +// Can overlap h with f or g. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Notes on implementation strategy: +// +// Using schoolbook multiplication. +// Karatsuba would save a little in some cost models. +// +// Most multiplications by 2 and 19 are 32-bit precomputations; +// cheaper than 64-bit postcomputations. +// +// There is one remaining multiplication by 19 in the carry chain; +// one *19 precomputation can be merged into this, +// but the resulting data flow is considerably less clean. +// +// There are 12 carries below. +// 10 of them are 2-way parallelizable and vectorizable. +// Can get away with 11 carries, but then data flow is much deeper. +// +// With tighter constraints on inputs, can squeeze carries into int32. +func FeMul(h, f, g *FieldElement) { + f0 := int64(f[0]) + f1 := int64(f[1]) + f2 := int64(f[2]) + f3 := int64(f[3]) + f4 := int64(f[4]) + f5 := int64(f[5]) + f6 := int64(f[6]) + f7 := int64(f[7]) + f8 := int64(f[8]) + f9 := int64(f[9]) + + f1_2 := int64(2 * f[1]) + f3_2 := int64(2 * f[3]) + f5_2 := int64(2 * f[5]) + f7_2 := int64(2 * f[7]) + f9_2 := int64(2 * f[9]) + + g0 := int64(g[0]) + g1 := int64(g[1]) + g2 := int64(g[2]) + g3 := int64(g[3]) + g4 := int64(g[4]) + g5 := int64(g[5]) + g6 := int64(g[6]) + g7 := int64(g[7]) + g8 := int64(g[8]) + g9 := int64(g[9]) + + g1_19 := int64(19 * g[1]) /* 1.4*2^29 */ + g2_19 := int64(19 * g[2]) /* 1.4*2^30; still ok */ + g3_19 := int64(19 * g[3]) + g4_19 := int64(19 * g[4]) + g5_19 := int64(19 * g[5]) + g6_19 := int64(19 * g[6]) + g7_19 := int64(19 * g[7]) + g8_19 := int64(19 * g[8]) + g9_19 := int64(19 * g[9]) + + h0 := f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*g1_19 + h1 := f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19 + h2 := f0*g2 + f1_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*g3_19 + h3 := f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19 + h4 := f0*g4 + f1_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*g5_19 + h5 := f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19 + h6 := f0*g6 + f1_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*g7_19 + h7 := f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19 + h8 := f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19 + h9 := f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0 + + FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +func feSquare(f *FieldElement) (h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { + f0 := int64(f[0]) + f1 := int64(f[1]) + f2 := int64(f[2]) + f3 := int64(f[3]) + f4 := int64(f[4]) + f5 := int64(f[5]) + f6 := int64(f[6]) + f7 := int64(f[7]) + f8 := int64(f[8]) + f9 := int64(f[9]) + f0_2 := int64(2 * f[0]) + f1_2 := int64(2 * f[1]) + f2_2 := int64(2 * f[2]) + f3_2 := int64(2 * f[3]) + f4_2 := int64(2 * f[4]) + f5_2 := int64(2 * f[5]) + f6_2 := int64(2 * f[6]) + f7_2 := int64(2 * f[7]) + f5_38 := 38 * f5 // 1.31*2^30 + f6_19 := 19 * f6 // 1.31*2^30 + f7_38 := 38 * f7 // 1.31*2^30 + f8_19 := 19 * f8 // 1.31*2^30 + f9_38 := 38 * f9 // 1.31*2^30 + + h0 = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38 + h1 = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19 + h2 = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19 + h3 = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38 + h4 = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38 + h5 = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19 + h6 = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19 + h7 = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38 + h8 = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38 + h9 = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5 + + return +} + +// FeSquare calculates h = f*f. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func FeSquare(h, f *FieldElement) { + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f) + FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +// FeSquare2 sets h = 2 * f * f +// +// Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +// See fe_mul.c for discussion of implementation strategy. +func FeSquare2(h, f *FieldElement) { + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f) + + h0 += h0 + h1 += h1 + h2 += h2 + h3 += h3 + h4 += h4 + h5 += h5 + h6 += h6 + h7 += h7 + h8 += h8 + h9 += h9 + + FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +func FeInvert(out, z *FieldElement) { + var t0, t1, t2, t3 FieldElement + var i int + + FeSquare(&t0, z) // 2^1 + FeSquare(&t1, &t0) // 2^2 + for i = 1; i < 2; i++ { // 2^3 + FeSquare(&t1, &t1) + } + FeMul(&t1, z, &t1) // 2^3 + 2^0 + FeMul(&t0, &t0, &t1) // 2^3 + 2^1 + 2^0 + FeSquare(&t2, &t0) // 2^4 + 2^2 + 2^1 + FeMul(&t1, &t1, &t2) // 2^4 + 2^3 + 2^2 + 2^1 + 2^0 + FeSquare(&t2, &t1) // 5,4,3,2,1 + for i = 1; i < 5; i++ { // 9,8,7,6,5 + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0 + FeSquare(&t2, &t1) // 10..1 + for i = 1; i < 10; i++ { // 19..10 + FeSquare(&t2, &t2) + } + FeMul(&t2, &t2, &t1) // 19..0 + FeSquare(&t3, &t2) // 20..1 + for i = 1; i < 20; i++ { // 39..20 + FeSquare(&t3, &t3) + } + FeMul(&t2, &t3, &t2) // 39..0 + FeSquare(&t2, &t2) // 40..1 + for i = 1; i < 10; i++ { // 49..10 + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) // 49..0 + FeSquare(&t2, &t1) // 50..1 + for i = 1; i < 50; i++ { // 99..50 + FeSquare(&t2, &t2) + } + FeMul(&t2, &t2, &t1) // 99..0 + FeSquare(&t3, &t2) // 100..1 + for i = 1; i < 100; i++ { // 199..100 + FeSquare(&t3, &t3) + } + FeMul(&t2, &t3, &t2) // 199..0 + FeSquare(&t2, &t2) // 200..1 + for i = 1; i < 50; i++ { // 249..50 + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) // 249..0 + FeSquare(&t1, &t1) // 250..1 + for i = 1; i < 5; i++ { // 254..5 + FeSquare(&t1, &t1) + } + FeMul(out, &t1, &t0) // 254..5,3,1,0 +} + +func fePow22523(out, z *FieldElement) { + var t0, t1, t2 FieldElement + var i int + + FeSquare(&t0, z) + for i = 1; i < 1; i++ { + FeSquare(&t0, &t0) + } + FeSquare(&t1, &t0) + for i = 1; i < 2; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t1, z, &t1) + FeMul(&t0, &t0, &t1) + FeSquare(&t0, &t0) + for i = 1; i < 1; i++ { + FeSquare(&t0, &t0) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t1, &t0) + for i = 1; i < 5; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t1, &t0) + for i = 1; i < 10; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t1, &t1, &t0) + FeSquare(&t2, &t1) + for i = 1; i < 20; i++ { + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) + FeSquare(&t1, &t1) + for i = 1; i < 10; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t1, &t0) + for i = 1; i < 50; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t1, &t1, &t0) + FeSquare(&t2, &t1) + for i = 1; i < 100; i++ { + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) + FeSquare(&t1, &t1) + for i = 1; i < 50; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t0, &t0) + for i = 1; i < 2; i++ { + FeSquare(&t0, &t0) + } + FeMul(out, &t0, z) +} + +// Group elements are members of the elliptic curve -x^2 + y^2 = 1 + d * x^2 * +// y^2 where d = -121665/121666. +// +// Several representations are used: +// ProjectiveGroupElement: (X:Y:Z) satisfying x=X/Z, y=Y/Z +// ExtendedGroupElement: (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT +// CompletedGroupElement: ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T +// PreComputedGroupElement: (y+x,y-x,2dxy) + +type ProjectiveGroupElement struct { + X, Y, Z FieldElement +} + +type ExtendedGroupElement struct { + X, Y, Z, T FieldElement +} + +type CompletedGroupElement struct { + X, Y, Z, T FieldElement +} + +type PreComputedGroupElement struct { + yPlusX, yMinusX, xy2d FieldElement +} + +type CachedGroupElement struct { + yPlusX, yMinusX, Z, T2d FieldElement +} + +func (p *ProjectiveGroupElement) Zero() { + FeZero(&p.X) + FeOne(&p.Y) + FeOne(&p.Z) +} + +func (p *ProjectiveGroupElement) Double(r *CompletedGroupElement) { + var t0 FieldElement + + FeSquare(&r.X, &p.X) + FeSquare(&r.Z, &p.Y) + FeSquare2(&r.T, &p.Z) + FeAdd(&r.Y, &p.X, &p.Y) + FeSquare(&t0, &r.Y) + FeAdd(&r.Y, &r.Z, &r.X) + FeSub(&r.Z, &r.Z, &r.X) + FeSub(&r.X, &t0, &r.Y) + FeSub(&r.T, &r.T, &r.Z) +} + +func (p *ProjectiveGroupElement) ToBytes(s *[32]byte) { + var recip, x, y FieldElement + + FeInvert(&recip, &p.Z) + FeMul(&x, &p.X, &recip) + FeMul(&y, &p.Y, &recip) + FeToBytes(s, &y) + s[31] ^= FeIsNegative(&x) << 7 +} + +func (p *ExtendedGroupElement) Zero() { + FeZero(&p.X) + FeOne(&p.Y) + FeOne(&p.Z) + FeZero(&p.T) +} + +func (p *ExtendedGroupElement) Double(r *CompletedGroupElement) { + var q ProjectiveGroupElement + p.ToProjective(&q) + q.Double(r) +} + +func (p *ExtendedGroupElement) ToCached(r *CachedGroupElement) { + FeAdd(&r.yPlusX, &p.Y, &p.X) + FeSub(&r.yMinusX, &p.Y, &p.X) + FeCopy(&r.Z, &p.Z) + FeMul(&r.T2d, &p.T, &d2) +} + +func (p *ExtendedGroupElement) ToProjective(r *ProjectiveGroupElement) { + FeCopy(&r.X, &p.X) + FeCopy(&r.Y, &p.Y) + FeCopy(&r.Z, &p.Z) +} + +func (p *ExtendedGroupElement) ToBytes(s *[32]byte) { + var recip, x, y FieldElement + + FeInvert(&recip, &p.Z) + FeMul(&x, &p.X, &recip) + FeMul(&y, &p.Y, &recip) + FeToBytes(s, &y) + s[31] ^= FeIsNegative(&x) << 7 +} + +func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool { + var u, v, v3, vxx, check FieldElement + + FeFromBytes(&p.Y, s) + FeOne(&p.Z) + FeSquare(&u, &p.Y) + FeMul(&v, &u, &d) + FeSub(&u, &u, &p.Z) // y = y^2-1 + FeAdd(&v, &v, &p.Z) // v = dy^2+1 + + FeSquare(&v3, &v) + FeMul(&v3, &v3, &v) // v3 = v^3 + FeSquare(&p.X, &v3) + FeMul(&p.X, &p.X, &v) + FeMul(&p.X, &p.X, &u) // x = uv^7 + + fePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8) + FeMul(&p.X, &p.X, &v3) + FeMul(&p.X, &p.X, &u) // x = uv^3(uv^7)^((q-5)/8) + + var tmpX, tmp2 [32]byte + + FeSquare(&vxx, &p.X) + FeMul(&vxx, &vxx, &v) + FeSub(&check, &vxx, &u) // vx^2-u + if FeIsNonZero(&check) == 1 { + FeAdd(&check, &vxx, &u) // vx^2+u + if FeIsNonZero(&check) == 1 { + return false + } + FeMul(&p.X, &p.X, &SqrtM1) + + FeToBytes(&tmpX, &p.X) + for i, v := range tmpX { + tmp2[31-i] = v + } + } + + if FeIsNegative(&p.X) != (s[31] >> 7) { + FeNeg(&p.X, &p.X) + } + + FeMul(&p.T, &p.X, &p.Y) + return true +} + +func (p *CompletedGroupElement) ToProjective(r *ProjectiveGroupElement) { + FeMul(&r.X, &p.X, &p.T) + FeMul(&r.Y, &p.Y, &p.Z) + FeMul(&r.Z, &p.Z, &p.T) +} + +func (p *CompletedGroupElement) ToExtended(r *ExtendedGroupElement) { + FeMul(&r.X, &p.X, &p.T) + FeMul(&r.Y, &p.Y, &p.Z) + FeMul(&r.Z, &p.Z, &p.T) + FeMul(&r.T, &p.X, &p.Y) +} + +func (p *PreComputedGroupElement) Zero() { + FeOne(&p.yPlusX) + FeOne(&p.yMinusX) + FeZero(&p.xy2d) +} + +func geAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yPlusX) + FeMul(&r.Y, &r.Y, &q.yMinusX) + FeMul(&r.T, &q.T2d, &p.T) + FeMul(&r.X, &p.Z, &q.Z) + FeAdd(&t0, &r.X, &r.X) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeAdd(&r.Z, &t0, &r.T) + FeSub(&r.T, &t0, &r.T) +} + +func geSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yMinusX) + FeMul(&r.Y, &r.Y, &q.yPlusX) + FeMul(&r.T, &q.T2d, &p.T) + FeMul(&r.X, &p.Z, &q.Z) + FeAdd(&t0, &r.X, &r.X) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeSub(&r.Z, &t0, &r.T) + FeAdd(&r.T, &t0, &r.T) +} + +func geMixedAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yPlusX) + FeMul(&r.Y, &r.Y, &q.yMinusX) + FeMul(&r.T, &q.xy2d, &p.T) + FeAdd(&t0, &p.Z, &p.Z) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeAdd(&r.Z, &t0, &r.T) + FeSub(&r.T, &t0, &r.T) +} + +func geMixedSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yMinusX) + FeMul(&r.Y, &r.Y, &q.yPlusX) + FeMul(&r.T, &q.xy2d, &p.T) + FeAdd(&t0, &p.Z, &p.Z) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeSub(&r.Z, &t0, &r.T) + FeAdd(&r.T, &t0, &r.T) +} + +func slide(r *[256]int8, a *[32]byte) { + for i := range r { + r[i] = int8(1 & (a[i>>3] >> uint(i&7))) + } + + for i := range r { + if r[i] != 0 { + for b := 1; b <= 6 && i+b < 256; b++ { + if r[i+b] != 0 { + if r[i]+(r[i+b]<= -15 { + r[i] -= r[i+b] << uint(b) + for k := i + b; k < 256; k++ { + if r[k] == 0 { + r[k] = 1 + break + } + r[k] = 0 + } + } else { + break + } + } + } + } + } +} + +// GeDoubleScalarMultVartime sets r = a*A + b*B +// where a = a[0]+256*a[1]+...+256^31 a[31]. +// and b = b[0]+256*b[1]+...+256^31 b[31]. +// B is the Ed25519 base point (x,4/5) with x positive. +func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *[32]byte, A *ExtendedGroupElement, b *[32]byte) { + var aSlide, bSlide [256]int8 + var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A + var t CompletedGroupElement + var u, A2 ExtendedGroupElement + var i int + + slide(&aSlide, a) + slide(&bSlide, b) + + A.ToCached(&Ai[0]) + A.Double(&t) + t.ToExtended(&A2) + + for i := 0; i < 7; i++ { + geAdd(&t, &A2, &Ai[i]) + t.ToExtended(&u) + u.ToCached(&Ai[i+1]) + } + + r.Zero() + + for i = 255; i >= 0; i-- { + if aSlide[i] != 0 || bSlide[i] != 0 { + break + } + } + + for ; i >= 0; i-- { + r.Double(&t) + + if aSlide[i] > 0 { + t.ToExtended(&u) + geAdd(&t, &u, &Ai[aSlide[i]/2]) + } else if aSlide[i] < 0 { + t.ToExtended(&u) + geSub(&t, &u, &Ai[(-aSlide[i])/2]) + } + + if bSlide[i] > 0 { + t.ToExtended(&u) + geMixedAdd(&t, &u, &bi[bSlide[i]/2]) + } else if bSlide[i] < 0 { + t.ToExtended(&u) + geMixedSub(&t, &u, &bi[(-bSlide[i])/2]) + } + + t.ToProjective(r) + } +} + +// equal returns 1 if b == c and 0 otherwise, assuming that b and c are +// non-negative. +func equal(b, c int32) int32 { + x := uint32(b ^ c) + x-- + return int32(x >> 31) +} + +// negative returns 1 if b < 0 and 0 otherwise. +func negative(b int32) int32 { + return (b >> 31) & 1 +} + +func PreComputedGroupElementCMove(t, u *PreComputedGroupElement, b int32) { + FeCMove(&t.yPlusX, &u.yPlusX, b) + FeCMove(&t.yMinusX, &u.yMinusX, b) + FeCMove(&t.xy2d, &u.xy2d, b) +} + +func selectPoint(t *PreComputedGroupElement, pos int32, b int32) { + var minusT PreComputedGroupElement + bNegative := negative(b) + bAbs := b - (((-bNegative) & b) << 1) + + t.Zero() + for i := int32(0); i < 8; i++ { + PreComputedGroupElementCMove(t, &base[pos][i], equal(bAbs, i+1)) + } + FeCopy(&minusT.yPlusX, &t.yMinusX) + FeCopy(&minusT.yMinusX, &t.yPlusX) + FeNeg(&minusT.xy2d, &t.xy2d) + PreComputedGroupElementCMove(t, &minusT, bNegative) +} + +// GeScalarMultBase computes h = a*B, where +// a = a[0]+256*a[1]+...+256^31 a[31] +// B is the Ed25519 base point (x,4/5) with x positive. +// +// Preconditions: +// a[31] <= 127 +func GeScalarMultBase(h *ExtendedGroupElement, a *[32]byte) { + var e [64]int8 + + for i, v := range a { + e[2*i] = int8(v & 15) + e[2*i+1] = int8((v >> 4) & 15) + } + + // each e[i] is between 0 and 15 and e[63] is between 0 and 7. + + carry := int8(0) + for i := 0; i < 63; i++ { + e[i] += carry + carry = (e[i] + 8) >> 4 + e[i] -= carry << 4 + } + e[63] += carry + // each e[i] is between -8 and 8. + + h.Zero() + var t PreComputedGroupElement + var r CompletedGroupElement + for i := int32(1); i < 64; i += 2 { + selectPoint(&t, i/2, int32(e[i])) + geMixedAdd(&r, h, &t) + r.ToExtended(h) + } + + var s ProjectiveGroupElement + + h.Double(&r) + r.ToProjective(&s) + s.Double(&r) + r.ToProjective(&s) + s.Double(&r) + r.ToProjective(&s) + s.Double(&r) + r.ToExtended(h) + + for i := int32(0); i < 64; i += 2 { + selectPoint(&t, i/2, int32(e[i])) + geMixedAdd(&r, h, &t) + r.ToExtended(h) + } +} + +// The scalars are GF(2^252 + 27742317777372353535851937790883648493). + +// Input: +// a[0]+256*a[1]+...+256^31*a[31] = a +// b[0]+256*b[1]+...+256^31*b[31] = b +// c[0]+256*c[1]+...+256^31*c[31] = c +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +func ScMulAdd(s, a, b, c *[32]byte) { + a0 := 2097151 & load3(a[:]) + a1 := 2097151 & (load4(a[2:]) >> 5) + a2 := 2097151 & (load3(a[5:]) >> 2) + a3 := 2097151 & (load4(a[7:]) >> 7) + a4 := 2097151 & (load4(a[10:]) >> 4) + a5 := 2097151 & (load3(a[13:]) >> 1) + a6 := 2097151 & (load4(a[15:]) >> 6) + a7 := 2097151 & (load3(a[18:]) >> 3) + a8 := 2097151 & load3(a[21:]) + a9 := 2097151 & (load4(a[23:]) >> 5) + a10 := 2097151 & (load3(a[26:]) >> 2) + a11 := (load4(a[28:]) >> 7) + b0 := 2097151 & load3(b[:]) + b1 := 2097151 & (load4(b[2:]) >> 5) + b2 := 2097151 & (load3(b[5:]) >> 2) + b3 := 2097151 & (load4(b[7:]) >> 7) + b4 := 2097151 & (load4(b[10:]) >> 4) + b5 := 2097151 & (load3(b[13:]) >> 1) + b6 := 2097151 & (load4(b[15:]) >> 6) + b7 := 2097151 & (load3(b[18:]) >> 3) + b8 := 2097151 & load3(b[21:]) + b9 := 2097151 & (load4(b[23:]) >> 5) + b10 := 2097151 & (load3(b[26:]) >> 2) + b11 := (load4(b[28:]) >> 7) + c0 := 2097151 & load3(c[:]) + c1 := 2097151 & (load4(c[2:]) >> 5) + c2 := 2097151 & (load3(c[5:]) >> 2) + c3 := 2097151 & (load4(c[7:]) >> 7) + c4 := 2097151 & (load4(c[10:]) >> 4) + c5 := 2097151 & (load3(c[13:]) >> 1) + c6 := 2097151 & (load4(c[15:]) >> 6) + c7 := 2097151 & (load3(c[18:]) >> 3) + c8 := 2097151 & load3(c[21:]) + c9 := 2097151 & (load4(c[23:]) >> 5) + c10 := 2097151 & (load3(c[26:]) >> 2) + c11 := (load4(c[28:]) >> 7) + var carry [23]int64 + + s0 := c0 + a0*b0 + s1 := c1 + a0*b1 + a1*b0 + s2 := c2 + a0*b2 + a1*b1 + a2*b0 + s3 := c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0 + s4 := c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0 + s5 := c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0 + s6 := c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0 + s7 := c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0 + s8 := c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0 + s9 := c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0 + s10 := c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0 + s11 := c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0 + s12 := a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1 + s13 := a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2 + s14 := a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3 + s15 := a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4 + s16 := a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5 + s17 := a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6 + s18 := a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7 + s19 := a8*b11 + a9*b10 + a10*b9 + a11*b8 + s20 := a9*b11 + a10*b10 + a11*b9 + s21 := a10*b11 + a11*b10 + s22 := a11 * b11 + s23 := int64(0) + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + carry[18] = (s18 + (1 << 20)) >> 21 + s19 += carry[18] + s18 -= carry[18] << 21 + carry[20] = (s20 + (1 << 20)) >> 21 + s21 += carry[20] + s20 -= carry[20] << 21 + carry[22] = (s22 + (1 << 20)) >> 21 + s23 += carry[22] + s22 -= carry[22] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + carry[17] = (s17 + (1 << 20)) >> 21 + s18 += carry[17] + s17 -= carry[17] << 21 + carry[19] = (s19 + (1 << 20)) >> 21 + s20 += carry[19] + s19 -= carry[19] << 21 + carry[21] = (s21 + (1 << 20)) >> 21 + s22 += carry[21] + s21 -= carry[21] << 21 + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + s[0] = byte(s0 >> 0) + s[1] = byte(s0 >> 8) + s[2] = byte((s0 >> 16) | (s1 << 5)) + s[3] = byte(s1 >> 3) + s[4] = byte(s1 >> 11) + s[5] = byte((s1 >> 19) | (s2 << 2)) + s[6] = byte(s2 >> 6) + s[7] = byte((s2 >> 14) | (s3 << 7)) + s[8] = byte(s3 >> 1) + s[9] = byte(s3 >> 9) + s[10] = byte((s3 >> 17) | (s4 << 4)) + s[11] = byte(s4 >> 4) + s[12] = byte(s4 >> 12) + s[13] = byte((s4 >> 20) | (s5 << 1)) + s[14] = byte(s5 >> 7) + s[15] = byte((s5 >> 15) | (s6 << 6)) + s[16] = byte(s6 >> 2) + s[17] = byte(s6 >> 10) + s[18] = byte((s6 >> 18) | (s7 << 3)) + s[19] = byte(s7 >> 5) + s[20] = byte(s7 >> 13) + s[21] = byte(s8 >> 0) + s[22] = byte(s8 >> 8) + s[23] = byte((s8 >> 16) | (s9 << 5)) + s[24] = byte(s9 >> 3) + s[25] = byte(s9 >> 11) + s[26] = byte((s9 >> 19) | (s10 << 2)) + s[27] = byte(s10 >> 6) + s[28] = byte((s10 >> 14) | (s11 << 7)) + s[29] = byte(s11 >> 1) + s[30] = byte(s11 >> 9) + s[31] = byte(s11 >> 17) +} + +// Input: +// s[0]+256*s[1]+...+256^63*s[63] = s +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = s mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +func ScReduce(out *[32]byte, s *[64]byte) { + s0 := 2097151 & load3(s[:]) + s1 := 2097151 & (load4(s[2:]) >> 5) + s2 := 2097151 & (load3(s[5:]) >> 2) + s3 := 2097151 & (load4(s[7:]) >> 7) + s4 := 2097151 & (load4(s[10:]) >> 4) + s5 := 2097151 & (load3(s[13:]) >> 1) + s6 := 2097151 & (load4(s[15:]) >> 6) + s7 := 2097151 & (load3(s[18:]) >> 3) + s8 := 2097151 & load3(s[21:]) + s9 := 2097151 & (load4(s[23:]) >> 5) + s10 := 2097151 & (load3(s[26:]) >> 2) + s11 := 2097151 & (load4(s[28:]) >> 7) + s12 := 2097151 & (load4(s[31:]) >> 4) + s13 := 2097151 & (load3(s[34:]) >> 1) + s14 := 2097151 & (load4(s[36:]) >> 6) + s15 := 2097151 & (load3(s[39:]) >> 3) + s16 := 2097151 & load3(s[42:]) + s17 := 2097151 & (load4(s[44:]) >> 5) + s18 := 2097151 & (load3(s[47:]) >> 2) + s19 := 2097151 & (load4(s[49:]) >> 7) + s20 := 2097151 & (load4(s[52:]) >> 4) + s21 := 2097151 & (load3(s[55:]) >> 1) + s22 := 2097151 & (load4(s[57:]) >> 6) + s23 := (load4(s[60:]) >> 3) + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + var carry [17]int64 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + out[0] = byte(s0 >> 0) + out[1] = byte(s0 >> 8) + out[2] = byte((s0 >> 16) | (s1 << 5)) + out[3] = byte(s1 >> 3) + out[4] = byte(s1 >> 11) + out[5] = byte((s1 >> 19) | (s2 << 2)) + out[6] = byte(s2 >> 6) + out[7] = byte((s2 >> 14) | (s3 << 7)) + out[8] = byte(s3 >> 1) + out[9] = byte(s3 >> 9) + out[10] = byte((s3 >> 17) | (s4 << 4)) + out[11] = byte(s4 >> 4) + out[12] = byte(s4 >> 12) + out[13] = byte((s4 >> 20) | (s5 << 1)) + out[14] = byte(s5 >> 7) + out[15] = byte((s5 >> 15) | (s6 << 6)) + out[16] = byte(s6 >> 2) + out[17] = byte(s6 >> 10) + out[18] = byte((s6 >> 18) | (s7 << 3)) + out[19] = byte(s7 >> 5) + out[20] = byte(s7 >> 13) + out[21] = byte(s8 >> 0) + out[22] = byte(s8 >> 8) + out[23] = byte((s8 >> 16) | (s9 << 5)) + out[24] = byte(s9 >> 3) + out[25] = byte(s9 >> 11) + out[26] = byte((s9 >> 19) | (s10 << 2)) + out[27] = byte(s10 >> 6) + out[28] = byte((s10 >> 14) | (s11 << 7)) + out[29] = byte(s11 >> 1) + out[30] = byte(s11 >> 9) + out[31] = byte(s11 >> 17) +} + +// order is the order of Curve25519 in little-endian form. +var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000} + +// ScMinimal returns true if the given scalar is less than the order of the +// curve. +func ScMinimal(scalar *[32]byte) bool { + for i := 3; ; i-- { + v := binary.LittleEndian.Uint64(scalar[i*8:]) + if v > order[i] { + return false + } else if v < order[i] { + break + } else if i == 0 { + return false + } + } + + return true +} diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go new file mode 100644 index 0000000000..593f653008 --- /dev/null +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -0,0 +1,77 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC +2898 / PKCS #5 v2.0. + +A key derivation function is useful when encrypting data based on a password +or any other not-fully-random data. It uses a pseudorandom function to derive +a secure encryption key based on the password. + +While v2.0 of the standard defines only one pseudorandom function to use, +HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved +Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To +choose, you can pass the `New` functions from the different SHA packages to +pbkdf2.Key. +*/ +package pbkdf2 // import "golang.org/x/crypto/pbkdf2" + +import ( + "crypto/hmac" + "hash" +) + +// Key derives a key from the password, salt and iteration count, returning a +// []byte of length keylen that can be used as cryptographic key. The key is +// derived based on the method described as PBKDF2 with the HMAC variant using +// the supplied hash function. +// +// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you +// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by +// doing: +// +// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) +// +// Remember to get a good random salt. At least 8 bytes is recommended by the +// RFC. +// +// Using a higher iteration count will increase the cost of an exhaustive +// search but will also make derivation proportionally slower. +func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { + prf := hmac.New(h, password) + hashLen := prf.Size() + numBlocks := (keyLen + hashLen - 1) / hashLen + + var buf [4]byte + dk := make([]byte, 0, numBlocks*hashLen) + U := make([]byte, hashLen) + for block := 1; block <= numBlocks; block++ { + // N.B.: || means concatenation, ^ means XOR + // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter + // U_1 = PRF(password, salt || uint(i)) + prf.Reset() + prf.Write(salt) + buf[0] = byte(block >> 24) + buf[1] = byte(block >> 16) + buf[2] = byte(block >> 8) + buf[3] = byte(block) + prf.Write(buf[:4]) + dk = prf.Sum(dk) + T := dk[len(dk)-hashLen:] + copy(U, T) + + // U_n = PRF(password, U_(n-1)) + for n := 2; n <= iter; n++ { + prf.Reset() + prf.Write(U) + U = U[:0] + U = prf.Sum(U) + for x := range U { + T[x] ^= U[x] + } + } + } + return dk[:keyLen] +} diff --git a/vendor/golang.org/x/tools/cover/profile.go b/vendor/golang.org/x/tools/cover/profile.go new file mode 100644 index 0000000000..0bb3541774 --- /dev/null +++ b/vendor/golang.org/x/tools/cover/profile.go @@ -0,0 +1,256 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cover provides support for parsing coverage profiles +// generated by "go test -coverprofile=cover.out". +package cover // import "golang.org/x/tools/cover" + +import ( + "bufio" + "errors" + "fmt" + "math" + "os" + "sort" + "strconv" + "strings" +) + +// Profile represents the profiling data for a specific file. +type Profile struct { + FileName string + Mode string + Blocks []ProfileBlock +} + +// ProfileBlock represents a single block of profiling data. +type ProfileBlock struct { + StartLine, StartCol int + EndLine, EndCol int + NumStmt, Count int +} + +type byFileName []*Profile + +func (p byFileName) Len() int { return len(p) } +func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName } +func (p byFileName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// ParseProfiles parses profile data in the specified file and returns a +// Profile for each source file described therein. +func ParseProfiles(fileName string) ([]*Profile, error) { + pf, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer pf.Close() + + files := make(map[string]*Profile) + buf := bufio.NewReader(pf) + // First line is "mode: foo", where foo is "set", "count", or "atomic". + // Rest of file is in the format + // encoding/base64/base64.go:34.44,37.40 3 1 + // where the fields are: name.go:line.column,line.column numberOfStatements count + s := bufio.NewScanner(buf) + mode := "" + for s.Scan() { + line := s.Text() + if mode == "" { + const p = "mode: " + if !strings.HasPrefix(line, p) || line == p { + return nil, fmt.Errorf("bad mode line: %v", line) + } + mode = line[len(p):] + continue + } + fn, b, err := parseLine(line) + if err != nil { + return nil, fmt.Errorf("line %q doesn't match expected format: %v", line, err) + } + p := files[fn] + if p == nil { + p = &Profile{ + FileName: fn, + Mode: mode, + } + files[fn] = p + } + p.Blocks = append(p.Blocks, b) + } + if err := s.Err(); err != nil { + return nil, err + } + for _, p := range files { + sort.Sort(blocksByStart(p.Blocks)) + // Merge samples from the same location. + j := 1 + for i := 1; i < len(p.Blocks); i++ { + b := p.Blocks[i] + last := p.Blocks[j-1] + if b.StartLine == last.StartLine && + b.StartCol == last.StartCol && + b.EndLine == last.EndLine && + b.EndCol == last.EndCol { + if b.NumStmt != last.NumStmt { + return nil, fmt.Errorf("inconsistent NumStmt: changed from %d to %d", last.NumStmt, b.NumStmt) + } + if mode == "set" { + p.Blocks[j-1].Count |= b.Count + } else { + p.Blocks[j-1].Count += b.Count + } + continue + } + p.Blocks[j] = b + j++ + } + p.Blocks = p.Blocks[:j] + } + // Generate a sorted slice. + profiles := make([]*Profile, 0, len(files)) + for _, profile := range files { + profiles = append(profiles, profile) + } + sort.Sort(byFileName(profiles)) + return profiles, nil +} + +// parseLine parses a line from a coverage file. +// It is equivalent to the regex +// ^(.+):([0-9]+)\.([0-9]+),([0-9]+)\.([0-9]+) ([0-9]+) ([0-9]+)$ +// +// However, it is much faster: https://golang.org/cl/179377 +func parseLine(l string) (fileName string, block ProfileBlock, err error) { + end := len(l) + + b := ProfileBlock{} + b.Count, end, err = seekBack(l, ' ', end, "Count") + if err != nil { + return "", b, err + } + b.NumStmt, end, err = seekBack(l, ' ', end, "NumStmt") + if err != nil { + return "", b, err + } + b.EndCol, end, err = seekBack(l, '.', end, "EndCol") + if err != nil { + return "", b, err + } + b.EndLine, end, err = seekBack(l, ',', end, "EndLine") + if err != nil { + return "", b, err + } + b.StartCol, end, err = seekBack(l, '.', end, "StartCol") + if err != nil { + return "", b, err + } + b.StartLine, end, err = seekBack(l, ':', end, "StartLine") + if err != nil { + return "", b, err + } + fn := l[0:end] + if fn == "" { + return "", b, errors.New("a FileName cannot be blank") + } + return fn, b, nil +} + +// seekBack searches backwards from end to find sep in l, then returns the +// value between sep and end as an integer. +// If seekBack fails, the returned error will reference what. +func seekBack(l string, sep byte, end int, what string) (value int, nextSep int, err error) { + // Since we're seeking backwards and we know only ASCII is legal for these values, + // we can ignore the possibility of non-ASCII characters. + for start := end - 1; start >= 0; start-- { + if l[start] == sep { + i, err := strconv.Atoi(l[start+1 : end]) + if err != nil { + return 0, 0, fmt.Errorf("couldn't parse %q: %v", what, err) + } + if i < 0 { + return 0, 0, fmt.Errorf("negative values are not allowed for %s, found %d", what, i) + } + return i, start, nil + } + } + return 0, 0, fmt.Errorf("couldn't find a %s before %s", string(sep), what) +} + +type blocksByStart []ProfileBlock + +func (b blocksByStart) Len() int { return len(b) } +func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b blocksByStart) Less(i, j int) bool { + bi, bj := b[i], b[j] + return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol +} + +// Boundary represents the position in a source file of the beginning or end of a +// block as reported by the coverage profile. In HTML mode, it will correspond to +// the opening or closing of a tag and will be used to colorize the source +type Boundary struct { + Offset int // Location as a byte offset in the source file. + Start bool // Is this the start of a block? + Count int // Event count from the cover profile. + Norm float64 // Count normalized to [0..1]. +} + +// Boundaries returns a Profile as a set of Boundary objects within the provided src. +func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { + // Find maximum count. + max := 0 + for _, b := range p.Blocks { + if b.Count > max { + max = b.Count + } + } + // Divisor for normalization. + divisor := math.Log(float64(max)) + + // boundary returns a Boundary, populating the Norm field with a normalized Count. + boundary := func(offset int, start bool, count int) Boundary { + b := Boundary{Offset: offset, Start: start, Count: count} + if !start || count == 0 { + return b + } + if max <= 1 { + b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS. + } else if count > 0 { + b.Norm = math.Log(float64(count)) / divisor + } + return b + } + + line, col := 1, 2 // TODO: Why is this 2? + for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); { + b := p.Blocks[bi] + if b.StartLine == line && b.StartCol == col { + boundaries = append(boundaries, boundary(si, true, b.Count)) + } + if b.EndLine == line && b.EndCol == col || line > b.EndLine { + boundaries = append(boundaries, boundary(si, false, 0)) + bi++ + continue // Don't advance through src; maybe the next block starts here. + } + if src[si] == '\n' { + line++ + col = 0 + } + col++ + si++ + } + sort.Sort(boundariesByPos(boundaries)) + return +} + +type boundariesByPos []Boundary + +func (b boundariesByPos) Len() int { return len(b) } +func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b boundariesByPos) Less(i, j int) bool { + if b[i].Offset == b[j].Offset { + return !b[i].Start && b[j].Start + } + return b[i].Offset < b[j].Offset +} diff --git a/vendor/gopkg.in/square/go-jose.v2/.gitcookies.sh.enc b/vendor/gopkg.in/square/go-jose.v2/.gitcookies.sh.enc new file mode 100644 index 0000000000..730e569b06 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/.gitcookies.sh.enc @@ -0,0 +1 @@ +'|&{tU|gG(Cy=+c:u:/p#~["4!nADK merged.coverprofile +- $HOME/gopath/bin/goveralls -coverprofile merged.coverprofile -service=travis-ci diff --git a/vendor/gopkg.in/square/go-jose.v2/BUG-BOUNTY.md b/vendor/gopkg.in/square/go-jose.v2/BUG-BOUNTY.md new file mode 100644 index 0000000000..3305db0f65 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/BUG-BOUNTY.md @@ -0,0 +1,10 @@ +Serious about security +====================== + +Square recognizes the important contributions the security research community +can make. We therefore encourage reporting security issues with the code +contained in this repository. + +If you believe you have discovered a security vulnerability, please follow the +guidelines at . + diff --git a/vendor/gopkg.in/square/go-jose.v2/CONTRIBUTING.md b/vendor/gopkg.in/square/go-jose.v2/CONTRIBUTING.md new file mode 100644 index 0000000000..61b183651c --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing + +If you would like to contribute code to go-jose you can do so through GitHub by +forking the repository and sending a pull request. + +When submitting code, please make every effort to follow existing conventions +and style in order to keep the code as readable as possible. Please also make +sure all tests pass by running `go test`, and format your code with `go fmt`. +We also recommend using `golint` and `errcheck`. + +Before your code can be accepted into the project you must also sign the +[Individual Contributor License Agreement][1]. + + [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1 diff --git a/vendor/gopkg.in/square/go-jose.v2/LICENSE b/vendor/gopkg.in/square/go-jose.v2/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/gopkg.in/square/go-jose.v2/README.md b/vendor/gopkg.in/square/go-jose.v2/README.md new file mode 100644 index 0000000000..1791bfa8f6 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/README.md @@ -0,0 +1,118 @@ +# Go JOSE + +[![godoc](http://img.shields.io/badge/godoc-version_1-blue.svg?style=flat)](https://godoc.org/gopkg.in/square/go-jose.v1) +[![godoc](http://img.shields.io/badge/godoc-version_2-blue.svg?style=flat)](https://godoc.org/gopkg.in/square/go-jose.v2) +[![license](http://img.shields.io/badge/license-apache_2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/square/go-jose/master/LICENSE) +[![build](https://travis-ci.org/square/go-jose.svg?branch=v2)](https://travis-ci.org/square/go-jose) +[![coverage](https://coveralls.io/repos/github/square/go-jose/badge.svg?branch=v2)](https://coveralls.io/r/square/go-jose) + +Package jose aims to provide an implementation of the Javascript Object Signing +and Encryption set of standards. This includes support for JSON Web Encryption, +JSON Web Signature, and JSON Web Token standards. + +**Disclaimer**: This library contains encryption software that is subject to +the U.S. Export Administration Regulations. You may not export, re-export, +transfer or download this code or any part of it in violation of any United +States law, directive or regulation. In particular this software may not be +exported or re-exported in any form or on any media to Iran, North Sudan, +Syria, Cuba, or North Korea, or to denied persons or entities mentioned on any +US maintained blocked list. + +## Overview + +The implementation follows the +[JSON Web Encryption](http://dx.doi.org/10.17487/RFC7516) (RFC 7516), +[JSON Web Signature](http://dx.doi.org/10.17487/RFC7515) (RFC 7515), and +[JSON Web Token](http://dx.doi.org/10.17487/RFC7519) (RFC 7519). +Tables of supported algorithms are shown below. The library supports both +the compact and full serialization formats, and has optional support for +multiple recipients. It also comes with a small command-line utility +([`jose-util`](https://github.com/square/go-jose/tree/v2/jose-util)) +for dealing with JOSE messages in a shell. + +**Note**: We use a forked version of the `encoding/json` package from the Go +standard library which uses case-sensitive matching for member names (instead +of [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html)). +This is to avoid differences in interpretation of messages between go-jose and +libraries in other languages. + +### Versions + +We use [gopkg.in](https://gopkg.in) for versioning. + +[Version 2](https://gopkg.in/square/go-jose.v2) +([branch](https://github.com/square/go-jose/tree/v2), +[doc](https://godoc.org/gopkg.in/square/go-jose.v2)) is the current version: + + import "gopkg.in/square/go-jose.v2" + +The old `v1` branch ([go-jose.v1](https://gopkg.in/square/go-jose.v1)) will +still receive backported bug fixes and security fixes, but otherwise +development is frozen. All new feature development takes place on the `v2` +branch. Version 2 also contains additional sub-packages such as the +[jwt](https://godoc.org/gopkg.in/square/go-jose.v2/jwt) implementation +contributed by [@shaxbee](https://github.com/shaxbee). + +### Supported algorithms + +See below for a table of supported algorithms. Algorithm identifiers match +the names in the [JSON Web Algorithms](http://dx.doi.org/10.17487/RFC7518) +standard where possible. The Godoc reference has a list of constants. + + Key encryption | Algorithm identifier(s) + :------------------------- | :------------------------------ + RSA-PKCS#1v1.5 | RSA1_5 + RSA-OAEP | RSA-OAEP, RSA-OAEP-256 + AES key wrap | A128KW, A192KW, A256KW + AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW + ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW + ECDH-ES (direct) | ECDH-ES1 + Direct encryption | dir1 + +1. Not supported in multi-recipient mode + + Signing / MAC | Algorithm identifier(s) + :------------------------- | :------------------------------ + RSASSA-PKCS#1v1.5 | RS256, RS384, RS512 + RSASSA-PSS | PS256, PS384, PS512 + HMAC | HS256, HS384, HS512 + ECDSA | ES256, ES384, ES512 + Ed25519 | EdDSA2 + +2. Only available in version 2 of the package + + Content encryption | Algorithm identifier(s) + :------------------------- | :------------------------------ + AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 + AES-GCM | A128GCM, A192GCM, A256GCM + + Compression | Algorithm identifiers(s) + :------------------------- | ------------------------------- + DEFLATE (RFC 1951) | DEF + +### Supported key types + +See below for a table of supported key types. These are understood by the +library, and can be passed to corresponding functions such as `NewEncrypter` or +`NewSigner`. Each of these keys can also be wrapped in a JWK if desired, which +allows attaching a key id. + + Algorithm(s) | Corresponding types + :------------------------- | ------------------------------- + RSA | *[rsa.PublicKey](http://golang.org/pkg/crypto/rsa/#PublicKey), *[rsa.PrivateKey](http://golang.org/pkg/crypto/rsa/#PrivateKey) + ECDH, ECDSA | *[ecdsa.PublicKey](http://golang.org/pkg/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](http://golang.org/pkg/crypto/ecdsa/#PrivateKey) + EdDSA1 | [ed25519.PublicKey](https://godoc.org/golang.org/x/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://godoc.org/golang.org/x/crypto/ed25519#PrivateKey) + AES, HMAC | []byte + +1. Only available in version 2 of the package + +## Examples + +[![godoc](http://img.shields.io/badge/godoc-version_1-blue.svg?style=flat)](https://godoc.org/gopkg.in/square/go-jose.v1) +[![godoc](http://img.shields.io/badge/godoc-version_2-blue.svg?style=flat)](https://godoc.org/gopkg.in/square/go-jose.v2) + +Examples can be found in the Godoc +reference for this package. The +[`jose-util`](https://github.com/square/go-jose/tree/v2/jose-util) +subdirectory also contains a small command-line utility which might be useful +as an example. diff --git a/vendor/gopkg.in/square/go-jose.v2/asymmetric.go b/vendor/gopkg.in/square/go-jose.v2/asymmetric.go new file mode 100644 index 0000000000..b69aa0369c --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/asymmetric.go @@ -0,0 +1,592 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jose + +import ( + "crypto" + "crypto/aes" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "errors" + "fmt" + "math/big" + + "golang.org/x/crypto/ed25519" + josecipher "gopkg.in/square/go-jose.v2/cipher" + "gopkg.in/square/go-jose.v2/json" +) + +// A generic RSA-based encrypter/verifier +type rsaEncrypterVerifier struct { + publicKey *rsa.PublicKey +} + +// A generic RSA-based decrypter/signer +type rsaDecrypterSigner struct { + privateKey *rsa.PrivateKey +} + +// A generic EC-based encrypter/verifier +type ecEncrypterVerifier struct { + publicKey *ecdsa.PublicKey +} + +type edEncrypterVerifier struct { + publicKey ed25519.PublicKey +} + +// A key generator for ECDH-ES +type ecKeyGenerator struct { + size int + algID string + publicKey *ecdsa.PublicKey +} + +// A generic EC-based decrypter/signer +type ecDecrypterSigner struct { + privateKey *ecdsa.PrivateKey +} + +type edDecrypterSigner struct { + privateKey ed25519.PrivateKey +} + +// newRSARecipient creates recipientKeyInfo based on the given key. +func newRSARecipient(keyAlg KeyAlgorithm, publicKey *rsa.PublicKey) (recipientKeyInfo, error) { + // Verify that key management algorithm is supported by this encrypter + switch keyAlg { + case RSA1_5, RSA_OAEP, RSA_OAEP_256: + default: + return recipientKeyInfo{}, ErrUnsupportedAlgorithm + } + + if publicKey == nil { + return recipientKeyInfo{}, errors.New("invalid public key") + } + + return recipientKeyInfo{ + keyAlg: keyAlg, + keyEncrypter: &rsaEncrypterVerifier{ + publicKey: publicKey, + }, + }, nil +} + +// newRSASigner creates a recipientSigInfo based on the given key. +func newRSASigner(sigAlg SignatureAlgorithm, privateKey *rsa.PrivateKey) (recipientSigInfo, error) { + // Verify that key management algorithm is supported by this encrypter + switch sigAlg { + case RS256, RS384, RS512, PS256, PS384, PS512: + default: + return recipientSigInfo{}, ErrUnsupportedAlgorithm + } + + if privateKey == nil { + return recipientSigInfo{}, errors.New("invalid private key") + } + + return recipientSigInfo{ + sigAlg: sigAlg, + publicKey: staticPublicKey(&JSONWebKey{ + Key: privateKey.Public(), + }), + signer: &rsaDecrypterSigner{ + privateKey: privateKey, + }, + }, nil +} + +func newEd25519Signer(sigAlg SignatureAlgorithm, privateKey ed25519.PrivateKey) (recipientSigInfo, error) { + if sigAlg != EdDSA { + return recipientSigInfo{}, ErrUnsupportedAlgorithm + } + + if privateKey == nil { + return recipientSigInfo{}, errors.New("invalid private key") + } + return recipientSigInfo{ + sigAlg: sigAlg, + publicKey: staticPublicKey(&JSONWebKey{ + Key: privateKey.Public(), + }), + signer: &edDecrypterSigner{ + privateKey: privateKey, + }, + }, nil +} + +// newECDHRecipient creates recipientKeyInfo based on the given key. +func newECDHRecipient(keyAlg KeyAlgorithm, publicKey *ecdsa.PublicKey) (recipientKeyInfo, error) { + // Verify that key management algorithm is supported by this encrypter + switch keyAlg { + case ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW: + default: + return recipientKeyInfo{}, ErrUnsupportedAlgorithm + } + + if publicKey == nil || !publicKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) { + return recipientKeyInfo{}, errors.New("invalid public key") + } + + return recipientKeyInfo{ + keyAlg: keyAlg, + keyEncrypter: &ecEncrypterVerifier{ + publicKey: publicKey, + }, + }, nil +} + +// newECDSASigner creates a recipientSigInfo based on the given key. +func newECDSASigner(sigAlg SignatureAlgorithm, privateKey *ecdsa.PrivateKey) (recipientSigInfo, error) { + // Verify that key management algorithm is supported by this encrypter + switch sigAlg { + case ES256, ES384, ES512: + default: + return recipientSigInfo{}, ErrUnsupportedAlgorithm + } + + if privateKey == nil { + return recipientSigInfo{}, errors.New("invalid private key") + } + + return recipientSigInfo{ + sigAlg: sigAlg, + publicKey: staticPublicKey(&JSONWebKey{ + Key: privateKey.Public(), + }), + signer: &ecDecrypterSigner{ + privateKey: privateKey, + }, + }, nil +} + +// Encrypt the given payload and update the object. +func (ctx rsaEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) { + encryptedKey, err := ctx.encrypt(cek, alg) + if err != nil { + return recipientInfo{}, err + } + + return recipientInfo{ + encryptedKey: encryptedKey, + header: &rawHeader{}, + }, nil +} + +// Encrypt the given payload. Based on the key encryption algorithm, +// this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256). +func (ctx rsaEncrypterVerifier) encrypt(cek []byte, alg KeyAlgorithm) ([]byte, error) { + switch alg { + case RSA1_5: + return rsa.EncryptPKCS1v15(RandReader, ctx.publicKey, cek) + case RSA_OAEP: + return rsa.EncryptOAEP(sha1.New(), RandReader, ctx.publicKey, cek, []byte{}) + case RSA_OAEP_256: + return rsa.EncryptOAEP(sha256.New(), RandReader, ctx.publicKey, cek, []byte{}) + } + + return nil, ErrUnsupportedAlgorithm +} + +// Decrypt the given payload and return the content encryption key. +func (ctx rsaDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) { + return ctx.decrypt(recipient.encryptedKey, headers.getAlgorithm(), generator) +} + +// Decrypt the given payload. Based on the key encryption algorithm, +// this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256). +func (ctx rsaDecrypterSigner) decrypt(jek []byte, alg KeyAlgorithm, generator keyGenerator) ([]byte, error) { + // Note: The random reader on decrypt operations is only used for blinding, + // so stubbing is meanlingless (hence the direct use of rand.Reader). + switch alg { + case RSA1_5: + defer func() { + // DecryptPKCS1v15SessionKey sometimes panics on an invalid payload + // because of an index out of bounds error, which we want to ignore. + // This has been fixed in Go 1.3.1 (released 2014/08/13), the recover() + // only exists for preventing crashes with unpatched versions. + // See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k + // See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33 + _ = recover() + }() + + // Perform some input validation. + keyBytes := ctx.privateKey.PublicKey.N.BitLen() / 8 + if keyBytes != len(jek) { + // Input size is incorrect, the encrypted payload should always match + // the size of the public modulus (e.g. using a 2048 bit key will + // produce 256 bytes of output). Reject this since it's invalid input. + return nil, ErrCryptoFailure + } + + cek, _, err := generator.genKey() + if err != nil { + return nil, ErrCryptoFailure + } + + // When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to + // prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing + // the Million Message Attack on Cryptographic Message Syntax". We are + // therefore deliberately ignoring errors here. + _ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, ctx.privateKey, jek, cek) + + return cek, nil + case RSA_OAEP: + // Use rand.Reader for RSA blinding + return rsa.DecryptOAEP(sha1.New(), rand.Reader, ctx.privateKey, jek, []byte{}) + case RSA_OAEP_256: + // Use rand.Reader for RSA blinding + return rsa.DecryptOAEP(sha256.New(), rand.Reader, ctx.privateKey, jek, []byte{}) + } + + return nil, ErrUnsupportedAlgorithm +} + +// Sign the given payload +func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) { + var hash crypto.Hash + + switch alg { + case RS256, PS256: + hash = crypto.SHA256 + case RS384, PS384: + hash = crypto.SHA384 + case RS512, PS512: + hash = crypto.SHA512 + default: + return Signature{}, ErrUnsupportedAlgorithm + } + + hasher := hash.New() + + // According to documentation, Write() on hash never fails + _, _ = hasher.Write(payload) + hashed := hasher.Sum(nil) + + var out []byte + var err error + + switch alg { + case RS256, RS384, RS512: + out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed) + case PS256, PS384, PS512: + out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthEqualsHash, + }) + } + + if err != nil { + return Signature{}, err + } + + return Signature{ + Signature: out, + protected: &rawHeader{}, + }, nil +} + +// Verify the given payload +func (ctx rsaEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error { + var hash crypto.Hash + + switch alg { + case RS256, PS256: + hash = crypto.SHA256 + case RS384, PS384: + hash = crypto.SHA384 + case RS512, PS512: + hash = crypto.SHA512 + default: + return ErrUnsupportedAlgorithm + } + + hasher := hash.New() + + // According to documentation, Write() on hash never fails + _, _ = hasher.Write(payload) + hashed := hasher.Sum(nil) + + switch alg { + case RS256, RS384, RS512: + return rsa.VerifyPKCS1v15(ctx.publicKey, hash, hashed, signature) + case PS256, PS384, PS512: + return rsa.VerifyPSS(ctx.publicKey, hash, hashed, signature, nil) + } + + return ErrUnsupportedAlgorithm +} + +// Encrypt the given payload and update the object. +func (ctx ecEncrypterVerifier) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) { + switch alg { + case ECDH_ES: + // ECDH-ES mode doesn't wrap a key, the shared secret is used directly as the key. + return recipientInfo{ + header: &rawHeader{}, + }, nil + case ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW: + default: + return recipientInfo{}, ErrUnsupportedAlgorithm + } + + generator := ecKeyGenerator{ + algID: string(alg), + publicKey: ctx.publicKey, + } + + switch alg { + case ECDH_ES_A128KW: + generator.size = 16 + case ECDH_ES_A192KW: + generator.size = 24 + case ECDH_ES_A256KW: + generator.size = 32 + } + + kek, header, err := generator.genKey() + if err != nil { + return recipientInfo{}, err + } + + block, err := aes.NewCipher(kek) + if err != nil { + return recipientInfo{}, err + } + + jek, err := josecipher.KeyWrap(block, cek) + if err != nil { + return recipientInfo{}, err + } + + return recipientInfo{ + encryptedKey: jek, + header: &header, + }, nil +} + +// Get key size for EC key generator +func (ctx ecKeyGenerator) keySize() int { + return ctx.size +} + +// Get a content encryption key for ECDH-ES +func (ctx ecKeyGenerator) genKey() ([]byte, rawHeader, error) { + priv, err := ecdsa.GenerateKey(ctx.publicKey.Curve, RandReader) + if err != nil { + return nil, rawHeader{}, err + } + + out := josecipher.DeriveECDHES(ctx.algID, []byte{}, []byte{}, priv, ctx.publicKey, ctx.size) + + b, err := json.Marshal(&JSONWebKey{ + Key: &priv.PublicKey, + }) + if err != nil { + return nil, nil, err + } + + headers := rawHeader{ + headerEPK: makeRawMessage(b), + } + + return out, headers, nil +} + +// Decrypt the given payload and return the content encryption key. +func (ctx ecDecrypterSigner) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) { + epk, err := headers.getEPK() + if err != nil { + return nil, errors.New("square/go-jose: invalid epk header") + } + if epk == nil { + return nil, errors.New("square/go-jose: missing epk header") + } + + publicKey, ok := epk.Key.(*ecdsa.PublicKey) + if publicKey == nil || !ok { + return nil, errors.New("square/go-jose: invalid epk header") + } + + if !ctx.privateKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) { + return nil, errors.New("square/go-jose: invalid public key in epk header") + } + + apuData, err := headers.getAPU() + if err != nil { + return nil, errors.New("square/go-jose: invalid apu header") + } + apvData, err := headers.getAPV() + if err != nil { + return nil, errors.New("square/go-jose: invalid apv header") + } + + deriveKey := func(algID string, size int) []byte { + return josecipher.DeriveECDHES(algID, apuData.bytes(), apvData.bytes(), ctx.privateKey, publicKey, size) + } + + var keySize int + + algorithm := headers.getAlgorithm() + switch algorithm { + case ECDH_ES: + // ECDH-ES uses direct key agreement, no key unwrapping necessary. + return deriveKey(string(headers.getEncryption()), generator.keySize()), nil + case ECDH_ES_A128KW: + keySize = 16 + case ECDH_ES_A192KW: + keySize = 24 + case ECDH_ES_A256KW: + keySize = 32 + default: + return nil, ErrUnsupportedAlgorithm + } + + key := deriveKey(string(algorithm), keySize) + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + return josecipher.KeyUnwrap(block, recipient.encryptedKey) +} + +func (ctx edDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) { + if alg != EdDSA { + return Signature{}, ErrUnsupportedAlgorithm + } + + sig, err := ctx.privateKey.Sign(RandReader, payload, crypto.Hash(0)) + if err != nil { + return Signature{}, err + } + + return Signature{ + Signature: sig, + protected: &rawHeader{}, + }, nil +} + +func (ctx edEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error { + if alg != EdDSA { + return ErrUnsupportedAlgorithm + } + ok := ed25519.Verify(ctx.publicKey, payload, signature) + if !ok { + return errors.New("square/go-jose: ed25519 signature failed to verify") + } + return nil +} + +// Sign the given payload +func (ctx ecDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) { + var expectedBitSize int + var hash crypto.Hash + + switch alg { + case ES256: + expectedBitSize = 256 + hash = crypto.SHA256 + case ES384: + expectedBitSize = 384 + hash = crypto.SHA384 + case ES512: + expectedBitSize = 521 + hash = crypto.SHA512 + } + + curveBits := ctx.privateKey.Curve.Params().BitSize + if expectedBitSize != curveBits { + return Signature{}, fmt.Errorf("square/go-jose: expected %d bit key, got %d bits instead", expectedBitSize, curveBits) + } + + hasher := hash.New() + + // According to documentation, Write() on hash never fails + _, _ = hasher.Write(payload) + hashed := hasher.Sum(nil) + + r, s, err := ecdsa.Sign(RandReader, ctx.privateKey, hashed) + if err != nil { + return Signature{}, err + } + + keyBytes := curveBits / 8 + if curveBits%8 > 0 { + keyBytes++ + } + + // We serialize the outputs (r and s) into big-endian byte arrays and pad + // them with zeros on the left to make sure the sizes work out. Both arrays + // must be keyBytes long, and the output must be 2*keyBytes long. + rBytes := r.Bytes() + rBytesPadded := make([]byte, keyBytes) + copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) + + sBytes := s.Bytes() + sBytesPadded := make([]byte, keyBytes) + copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) + + out := append(rBytesPadded, sBytesPadded...) + + return Signature{ + Signature: out, + protected: &rawHeader{}, + }, nil +} + +// Verify the given payload +func (ctx ecEncrypterVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error { + var keySize int + var hash crypto.Hash + + switch alg { + case ES256: + keySize = 32 + hash = crypto.SHA256 + case ES384: + keySize = 48 + hash = crypto.SHA384 + case ES512: + keySize = 66 + hash = crypto.SHA512 + default: + return ErrUnsupportedAlgorithm + } + + if len(signature) != 2*keySize { + return fmt.Errorf("square/go-jose: invalid signature size, have %d bytes, wanted %d", len(signature), 2*keySize) + } + + hasher := hash.New() + + // According to documentation, Write() on hash never fails + _, _ = hasher.Write(payload) + hashed := hasher.Sum(nil) + + r := big.NewInt(0).SetBytes(signature[:keySize]) + s := big.NewInt(0).SetBytes(signature[keySize:]) + + match := ecdsa.Verify(ctx.publicKey, hashed, r, s) + if !match { + return errors.New("square/go-jose: ecdsa signature failed to verify") + } + + return nil +} diff --git a/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go b/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go new file mode 100644 index 0000000000..126b85ce25 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/cipher/cbc_hmac.go @@ -0,0 +1,196 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package josecipher + +import ( + "bytes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "crypto/subtle" + "encoding/binary" + "errors" + "hash" +) + +const ( + nonceBytes = 16 +) + +// NewCBCHMAC instantiates a new AEAD based on CBC+HMAC. +func NewCBCHMAC(key []byte, newBlockCipher func([]byte) (cipher.Block, error)) (cipher.AEAD, error) { + keySize := len(key) / 2 + integrityKey := key[:keySize] + encryptionKey := key[keySize:] + + blockCipher, err := newBlockCipher(encryptionKey) + if err != nil { + return nil, err + } + + var hash func() hash.Hash + switch keySize { + case 16: + hash = sha256.New + case 24: + hash = sha512.New384 + case 32: + hash = sha512.New + } + + return &cbcAEAD{ + hash: hash, + blockCipher: blockCipher, + authtagBytes: keySize, + integrityKey: integrityKey, + }, nil +} + +// An AEAD based on CBC+HMAC +type cbcAEAD struct { + hash func() hash.Hash + authtagBytes int + integrityKey []byte + blockCipher cipher.Block +} + +func (ctx *cbcAEAD) NonceSize() int { + return nonceBytes +} + +func (ctx *cbcAEAD) Overhead() int { + // Maximum overhead is block size (for padding) plus auth tag length, where + // the length of the auth tag is equivalent to the key size. + return ctx.blockCipher.BlockSize() + ctx.authtagBytes +} + +// Seal encrypts and authenticates the plaintext. +func (ctx *cbcAEAD) Seal(dst, nonce, plaintext, data []byte) []byte { + // Output buffer -- must take care not to mangle plaintext input. + ciphertext := make([]byte, uint64(len(plaintext))+uint64(ctx.Overhead()))[:len(plaintext)] + copy(ciphertext, plaintext) + ciphertext = padBuffer(ciphertext, ctx.blockCipher.BlockSize()) + + cbc := cipher.NewCBCEncrypter(ctx.blockCipher, nonce) + + cbc.CryptBlocks(ciphertext, ciphertext) + authtag := ctx.computeAuthTag(data, nonce, ciphertext) + + ret, out := resize(dst, uint64(len(dst))+uint64(len(ciphertext))+uint64(len(authtag))) + copy(out, ciphertext) + copy(out[len(ciphertext):], authtag) + + return ret +} + +// Open decrypts and authenticates the ciphertext. +func (ctx *cbcAEAD) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + if len(ciphertext) < ctx.authtagBytes { + return nil, errors.New("square/go-jose: invalid ciphertext (too short)") + } + + offset := len(ciphertext) - ctx.authtagBytes + expectedTag := ctx.computeAuthTag(data, nonce, ciphertext[:offset]) + match := subtle.ConstantTimeCompare(expectedTag, ciphertext[offset:]) + if match != 1 { + return nil, errors.New("square/go-jose: invalid ciphertext (auth tag mismatch)") + } + + cbc := cipher.NewCBCDecrypter(ctx.blockCipher, nonce) + + // Make copy of ciphertext buffer, don't want to modify in place + buffer := append([]byte{}, []byte(ciphertext[:offset])...) + + if len(buffer)%ctx.blockCipher.BlockSize() > 0 { + return nil, errors.New("square/go-jose: invalid ciphertext (invalid length)") + } + + cbc.CryptBlocks(buffer, buffer) + + // Remove padding + plaintext, err := unpadBuffer(buffer, ctx.blockCipher.BlockSize()) + if err != nil { + return nil, err + } + + ret, out := resize(dst, uint64(len(dst))+uint64(len(plaintext))) + copy(out, plaintext) + + return ret, nil +} + +// Compute an authentication tag +func (ctx *cbcAEAD) computeAuthTag(aad, nonce, ciphertext []byte) []byte { + buffer := make([]byte, uint64(len(aad))+uint64(len(nonce))+uint64(len(ciphertext))+8) + n := 0 + n += copy(buffer, aad) + n += copy(buffer[n:], nonce) + n += copy(buffer[n:], ciphertext) + binary.BigEndian.PutUint64(buffer[n:], uint64(len(aad))*8) + + // According to documentation, Write() on hash.Hash never fails. + hmac := hmac.New(ctx.hash, ctx.integrityKey) + _, _ = hmac.Write(buffer) + + return hmac.Sum(nil)[:ctx.authtagBytes] +} + +// resize ensures the the given slice has a capacity of at least n bytes. +// If the capacity of the slice is less than n, a new slice is allocated +// and the existing data will be copied. +func resize(in []byte, n uint64) (head, tail []byte) { + if uint64(cap(in)) >= n { + head = in[:n] + } else { + head = make([]byte, n) + copy(head, in) + } + + tail = head[len(in):] + return +} + +// Apply padding +func padBuffer(buffer []byte, blockSize int) []byte { + missing := blockSize - (len(buffer) % blockSize) + ret, out := resize(buffer, uint64(len(buffer))+uint64(missing)) + padding := bytes.Repeat([]byte{byte(missing)}, missing) + copy(out, padding) + return ret +} + +// Remove padding +func unpadBuffer(buffer []byte, blockSize int) ([]byte, error) { + if len(buffer)%blockSize != 0 { + return nil, errors.New("square/go-jose: invalid padding") + } + + last := buffer[len(buffer)-1] + count := int(last) + + if count == 0 || count > blockSize || count > len(buffer) { + return nil, errors.New("square/go-jose: invalid padding") + } + + padding := bytes.Repeat([]byte{last}, count) + if !bytes.HasSuffix(buffer, padding) { + return nil, errors.New("square/go-jose: invalid padding") + } + + return buffer[:len(buffer)-count], nil +} diff --git a/vendor/gopkg.in/square/go-jose.v2/cipher/concat_kdf.go b/vendor/gopkg.in/square/go-jose.v2/cipher/concat_kdf.go new file mode 100644 index 0000000000..f62c3bdba5 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/cipher/concat_kdf.go @@ -0,0 +1,75 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package josecipher + +import ( + "crypto" + "encoding/binary" + "hash" + "io" +) + +type concatKDF struct { + z, info []byte + i uint32 + cache []byte + hasher hash.Hash +} + +// NewConcatKDF builds a KDF reader based on the given inputs. +func NewConcatKDF(hash crypto.Hash, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo []byte) io.Reader { + buffer := make([]byte, uint64(len(algID))+uint64(len(ptyUInfo))+uint64(len(ptyVInfo))+uint64(len(supPubInfo))+uint64(len(supPrivInfo))) + n := 0 + n += copy(buffer, algID) + n += copy(buffer[n:], ptyUInfo) + n += copy(buffer[n:], ptyVInfo) + n += copy(buffer[n:], supPubInfo) + copy(buffer[n:], supPrivInfo) + + hasher := hash.New() + + return &concatKDF{ + z: z, + info: buffer, + hasher: hasher, + cache: []byte{}, + i: 1, + } +} + +func (ctx *concatKDF) Read(out []byte) (int, error) { + copied := copy(out, ctx.cache) + ctx.cache = ctx.cache[copied:] + + for copied < len(out) { + ctx.hasher.Reset() + + // Write on a hash.Hash never fails + _ = binary.Write(ctx.hasher, binary.BigEndian, ctx.i) + _, _ = ctx.hasher.Write(ctx.z) + _, _ = ctx.hasher.Write(ctx.info) + + hash := ctx.hasher.Sum(nil) + chunkCopied := copy(out[copied:], hash) + copied += chunkCopied + ctx.cache = hash[chunkCopied:] + + ctx.i++ + } + + return copied, nil +} diff --git a/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go b/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go new file mode 100644 index 0000000000..093c646740 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go @@ -0,0 +1,86 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package josecipher + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "encoding/binary" +) + +// DeriveECDHES derives a shared encryption key using ECDH/ConcatKDF as described in JWE/JWA. +// It is an error to call this function with a private/public key that are not on the same +// curve. Callers must ensure that the keys are valid before calling this function. Output +// size may be at most 1<<16 bytes (64 KiB). +func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, size int) []byte { + if size > 1<<16 { + panic("ECDH-ES output size too large, must be less than or equal to 1<<16") + } + + // algId, partyUInfo, partyVInfo inputs must be prefixed with the length + algID := lengthPrefixed([]byte(alg)) + ptyUInfo := lengthPrefixed(apuData) + ptyVInfo := lengthPrefixed(apvData) + + // suppPubInfo is the encoded length of the output size in bits + supPubInfo := make([]byte, 4) + binary.BigEndian.PutUint32(supPubInfo, uint32(size)*8) + + if !priv.PublicKey.Curve.IsOnCurve(pub.X, pub.Y) { + panic("public key not on same curve as private key") + } + + z, _ := priv.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes()) + zBytes := z.Bytes() + + // Note that calling z.Bytes() on a big.Int may strip leading zero bytes from + // the returned byte array. This can lead to a problem where zBytes will be + // shorter than expected which breaks the key derivation. Therefore we must pad + // to the full length of the expected coordinate here before calling the KDF. + octSize := dSize(priv.Curve) + if len(zBytes) != octSize { + zBytes = append(bytes.Repeat([]byte{0}, octSize-len(zBytes)), zBytes...) + } + + reader := NewConcatKDF(crypto.SHA256, zBytes, algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{}) + key := make([]byte, size) + + // Read on the KDF will never fail + _, _ = reader.Read(key) + + return key +} + +// dSize returns the size in octets for a coordinate on a elliptic curve. +func dSize(curve elliptic.Curve) int { + order := curve.Params().P + bitLen := order.BitLen() + size := bitLen / 8 + if bitLen%8 != 0 { + size++ + } + return size +} + +func lengthPrefixed(data []byte) []byte { + out := make([]byte, len(data)+4) + binary.BigEndian.PutUint32(out, uint32(len(data))) + copy(out[4:], data) + return out +} diff --git a/vendor/gopkg.in/square/go-jose.v2/cipher/key_wrap.go b/vendor/gopkg.in/square/go-jose.v2/cipher/key_wrap.go new file mode 100644 index 0000000000..1d36d50151 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/cipher/key_wrap.go @@ -0,0 +1,109 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package josecipher + +import ( + "crypto/cipher" + "crypto/subtle" + "encoding/binary" + "errors" +) + +var defaultIV = []byte{0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6} + +// KeyWrap implements NIST key wrapping; it wraps a content encryption key (cek) with the given block cipher. +func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) { + if len(cek)%8 != 0 { + return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks") + } + + n := len(cek) / 8 + r := make([][]byte, n) + + for i := range r { + r[i] = make([]byte, 8) + copy(r[i], cek[i*8:]) + } + + buffer := make([]byte, 16) + tBytes := make([]byte, 8) + copy(buffer, defaultIV) + + for t := 0; t < 6*n; t++ { + copy(buffer[8:], r[t%n]) + + block.Encrypt(buffer, buffer) + + binary.BigEndian.PutUint64(tBytes, uint64(t+1)) + + for i := 0; i < 8; i++ { + buffer[i] = buffer[i] ^ tBytes[i] + } + copy(r[t%n], buffer[8:]) + } + + out := make([]byte, (n+1)*8) + copy(out, buffer[:8]) + for i := range r { + copy(out[(i+1)*8:], r[i]) + } + + return out, nil +} + +// KeyUnwrap implements NIST key unwrapping; it unwraps a content encryption key (cek) with the given block cipher. +func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) { + if len(ciphertext)%8 != 0 { + return nil, errors.New("square/go-jose: key wrap input must be 8 byte blocks") + } + + n := (len(ciphertext) / 8) - 1 + r := make([][]byte, n) + + for i := range r { + r[i] = make([]byte, 8) + copy(r[i], ciphertext[(i+1)*8:]) + } + + buffer := make([]byte, 16) + tBytes := make([]byte, 8) + copy(buffer[:8], ciphertext[:8]) + + for t := 6*n - 1; t >= 0; t-- { + binary.BigEndian.PutUint64(tBytes, uint64(t+1)) + + for i := 0; i < 8; i++ { + buffer[i] = buffer[i] ^ tBytes[i] + } + copy(buffer[8:], r[t%n]) + + block.Decrypt(buffer, buffer) + + copy(r[t%n], buffer[8:]) + } + + if subtle.ConstantTimeCompare(buffer[:8], defaultIV) == 0 { + return nil, errors.New("square/go-jose: failed to unwrap key") + } + + out := make([]byte, n*8) + for i := range r { + copy(out[i*8:], r[i]) + } + + return out, nil +} diff --git a/vendor/gopkg.in/square/go-jose.v2/crypter.go b/vendor/gopkg.in/square/go-jose.v2/crypter.go new file mode 100644 index 0000000000..d24cabf6b6 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/crypter.go @@ -0,0 +1,541 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jose + +import ( + "crypto/ecdsa" + "crypto/rsa" + "errors" + "fmt" + "reflect" + + "gopkg.in/square/go-jose.v2/json" +) + +// Encrypter represents an encrypter which produces an encrypted JWE object. +type Encrypter interface { + Encrypt(plaintext []byte) (*JSONWebEncryption, error) + EncryptWithAuthData(plaintext []byte, aad []byte) (*JSONWebEncryption, error) + Options() EncrypterOptions +} + +// A generic content cipher +type contentCipher interface { + keySize() int + encrypt(cek []byte, aad, plaintext []byte) (*aeadParts, error) + decrypt(cek []byte, aad []byte, parts *aeadParts) ([]byte, error) +} + +// A key generator (for generating/getting a CEK) +type keyGenerator interface { + keySize() int + genKey() ([]byte, rawHeader, error) +} + +// A generic key encrypter +type keyEncrypter interface { + encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) // Encrypt a key +} + +// A generic key decrypter +type keyDecrypter interface { + decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) // Decrypt a key +} + +// A generic encrypter based on the given key encrypter and content cipher. +type genericEncrypter struct { + contentAlg ContentEncryption + compressionAlg CompressionAlgorithm + cipher contentCipher + recipients []recipientKeyInfo + keyGenerator keyGenerator + extraHeaders map[HeaderKey]interface{} +} + +type recipientKeyInfo struct { + keyID string + keyAlg KeyAlgorithm + keyEncrypter keyEncrypter +} + +// EncrypterOptions represents options that can be set on new encrypters. +type EncrypterOptions struct { + Compression CompressionAlgorithm + + // Optional map of additional keys to be inserted into the protected header + // of a JWS object. Some specifications which make use of JWS like to insert + // additional values here. All values must be JSON-serializable. + ExtraHeaders map[HeaderKey]interface{} +} + +// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it +// if necessary. It returns itself and so can be used in a fluent style. +func (eo *EncrypterOptions) WithHeader(k HeaderKey, v interface{}) *EncrypterOptions { + if eo.ExtraHeaders == nil { + eo.ExtraHeaders = map[HeaderKey]interface{}{} + } + eo.ExtraHeaders[k] = v + return eo +} + +// WithContentType adds a content type ("cty") header and returns the updated +// EncrypterOptions. +func (eo *EncrypterOptions) WithContentType(contentType ContentType) *EncrypterOptions { + return eo.WithHeader(HeaderContentType, contentType) +} + +// WithType adds a type ("typ") header and returns the updated EncrypterOptions. +func (eo *EncrypterOptions) WithType(typ ContentType) *EncrypterOptions { + return eo.WithHeader(HeaderType, typ) +} + +// Recipient represents an algorithm/key to encrypt messages to. +// +// PBES2Count and PBES2Salt correspond with the "p2c" and "p2s" headers used +// on the password-based encryption algorithms PBES2-HS256+A128KW, +// PBES2-HS384+A192KW, and PBES2-HS512+A256KW. If they are not provided a safe +// default of 100000 will be used for the count and a 128-bit random salt will +// be generated. +type Recipient struct { + Algorithm KeyAlgorithm + Key interface{} + KeyID string + PBES2Count int + PBES2Salt []byte +} + +// NewEncrypter creates an appropriate encrypter based on the key type +func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions) (Encrypter, error) { + encrypter := &genericEncrypter{ + contentAlg: enc, + recipients: []recipientKeyInfo{}, + cipher: getContentCipher(enc), + } + if opts != nil { + encrypter.compressionAlg = opts.Compression + encrypter.extraHeaders = opts.ExtraHeaders + } + + if encrypter.cipher == nil { + return nil, ErrUnsupportedAlgorithm + } + + var keyID string + var rawKey interface{} + switch encryptionKey := rcpt.Key.(type) { + case JSONWebKey: + keyID, rawKey = encryptionKey.KeyID, encryptionKey.Key + case *JSONWebKey: + keyID, rawKey = encryptionKey.KeyID, encryptionKey.Key + case OpaqueKeyEncrypter: + keyID, rawKey = encryptionKey.KeyID(), encryptionKey + default: + rawKey = encryptionKey + } + + switch rcpt.Algorithm { + case DIRECT: + // Direct encryption mode must be treated differently + if reflect.TypeOf(rawKey) != reflect.TypeOf([]byte{}) { + return nil, ErrUnsupportedKeyType + } + if encrypter.cipher.keySize() != len(rawKey.([]byte)) { + return nil, ErrInvalidKeySize + } + encrypter.keyGenerator = staticKeyGenerator{ + key: rawKey.([]byte), + } + recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, rawKey.([]byte)) + recipientInfo.keyID = keyID + if rcpt.KeyID != "" { + recipientInfo.keyID = rcpt.KeyID + } + encrypter.recipients = []recipientKeyInfo{recipientInfo} + return encrypter, nil + case ECDH_ES: + // ECDH-ES (w/o key wrapping) is similar to DIRECT mode + typeOf := reflect.TypeOf(rawKey) + if typeOf != reflect.TypeOf(&ecdsa.PublicKey{}) { + return nil, ErrUnsupportedKeyType + } + encrypter.keyGenerator = ecKeyGenerator{ + size: encrypter.cipher.keySize(), + algID: string(enc), + publicKey: rawKey.(*ecdsa.PublicKey), + } + recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, rawKey.(*ecdsa.PublicKey)) + recipientInfo.keyID = keyID + if rcpt.KeyID != "" { + recipientInfo.keyID = rcpt.KeyID + } + encrypter.recipients = []recipientKeyInfo{recipientInfo} + return encrypter, nil + default: + // Can just add a standard recipient + encrypter.keyGenerator = randomKeyGenerator{ + size: encrypter.cipher.keySize(), + } + err := encrypter.addRecipient(rcpt) + return encrypter, err + } +} + +// NewMultiEncrypter creates a multi-encrypter based on the given parameters +func NewMultiEncrypter(enc ContentEncryption, rcpts []Recipient, opts *EncrypterOptions) (Encrypter, error) { + cipher := getContentCipher(enc) + + if cipher == nil { + return nil, ErrUnsupportedAlgorithm + } + if rcpts == nil || len(rcpts) == 0 { + return nil, fmt.Errorf("square/go-jose: recipients is nil or empty") + } + + encrypter := &genericEncrypter{ + contentAlg: enc, + recipients: []recipientKeyInfo{}, + cipher: cipher, + keyGenerator: randomKeyGenerator{ + size: cipher.keySize(), + }, + } + + if opts != nil { + encrypter.compressionAlg = opts.Compression + } + + for _, recipient := range rcpts { + err := encrypter.addRecipient(recipient) + if err != nil { + return nil, err + } + } + + return encrypter, nil +} + +func (ctx *genericEncrypter) addRecipient(recipient Recipient) (err error) { + var recipientInfo recipientKeyInfo + + switch recipient.Algorithm { + case DIRECT, ECDH_ES: + return fmt.Errorf("square/go-jose: key algorithm '%s' not supported in multi-recipient mode", recipient.Algorithm) + } + + recipientInfo, err = makeJWERecipient(recipient.Algorithm, recipient.Key) + if recipient.KeyID != "" { + recipientInfo.keyID = recipient.KeyID + } + + switch recipient.Algorithm { + case PBES2_HS256_A128KW, PBES2_HS384_A192KW, PBES2_HS512_A256KW: + if sr, ok := recipientInfo.keyEncrypter.(*symmetricKeyCipher); ok { + sr.p2c = recipient.PBES2Count + sr.p2s = recipient.PBES2Salt + } + } + + if err == nil { + ctx.recipients = append(ctx.recipients, recipientInfo) + } + return err +} + +func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKeyInfo, error) { + switch encryptionKey := encryptionKey.(type) { + case *rsa.PublicKey: + return newRSARecipient(alg, encryptionKey) + case *ecdsa.PublicKey: + return newECDHRecipient(alg, encryptionKey) + case []byte: + return newSymmetricRecipient(alg, encryptionKey) + case string: + return newSymmetricRecipient(alg, []byte(encryptionKey)) + case *JSONWebKey: + recipient, err := makeJWERecipient(alg, encryptionKey.Key) + recipient.keyID = encryptionKey.KeyID + return recipient, err + } + if encrypter, ok := encryptionKey.(OpaqueKeyEncrypter); ok { + return newOpaqueKeyEncrypter(alg, encrypter) + } + return recipientKeyInfo{}, ErrUnsupportedKeyType +} + +// newDecrypter creates an appropriate decrypter based on the key type +func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) { + switch decryptionKey := decryptionKey.(type) { + case *rsa.PrivateKey: + return &rsaDecrypterSigner{ + privateKey: decryptionKey, + }, nil + case *ecdsa.PrivateKey: + return &ecDecrypterSigner{ + privateKey: decryptionKey, + }, nil + case []byte: + return &symmetricKeyCipher{ + key: decryptionKey, + }, nil + case string: + return &symmetricKeyCipher{ + key: []byte(decryptionKey), + }, nil + case JSONWebKey: + return newDecrypter(decryptionKey.Key) + case *JSONWebKey: + return newDecrypter(decryptionKey.Key) + } + if okd, ok := decryptionKey.(OpaqueKeyDecrypter); ok { + return &opaqueKeyDecrypter{decrypter: okd}, nil + } + return nil, ErrUnsupportedKeyType +} + +// Implementation of encrypt method producing a JWE object. +func (ctx *genericEncrypter) Encrypt(plaintext []byte) (*JSONWebEncryption, error) { + return ctx.EncryptWithAuthData(plaintext, nil) +} + +// Implementation of encrypt method producing a JWE object. +func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JSONWebEncryption, error) { + obj := &JSONWebEncryption{} + obj.aad = aad + + obj.protected = &rawHeader{} + err := obj.protected.set(headerEncryption, ctx.contentAlg) + if err != nil { + return nil, err + } + + obj.recipients = make([]recipientInfo, len(ctx.recipients)) + + if len(ctx.recipients) == 0 { + return nil, fmt.Errorf("square/go-jose: no recipients to encrypt to") + } + + cek, headers, err := ctx.keyGenerator.genKey() + if err != nil { + return nil, err + } + + obj.protected.merge(&headers) + + for i, info := range ctx.recipients { + recipient, err := info.keyEncrypter.encryptKey(cek, info.keyAlg) + if err != nil { + return nil, err + } + + err = recipient.header.set(headerAlgorithm, info.keyAlg) + if err != nil { + return nil, err + } + + if info.keyID != "" { + err = recipient.header.set(headerKeyID, info.keyID) + if err != nil { + return nil, err + } + } + obj.recipients[i] = recipient + } + + if len(ctx.recipients) == 1 { + // Move per-recipient headers into main protected header if there's + // only a single recipient. + obj.protected.merge(obj.recipients[0].header) + obj.recipients[0].header = nil + } + + if ctx.compressionAlg != NONE { + plaintext, err = compress(ctx.compressionAlg, plaintext) + if err != nil { + return nil, err + } + + err = obj.protected.set(headerCompression, ctx.compressionAlg) + if err != nil { + return nil, err + } + } + + for k, v := range ctx.extraHeaders { + b, err := json.Marshal(v) + if err != nil { + return nil, err + } + (*obj.protected)[k] = makeRawMessage(b) + } + + authData := obj.computeAuthData() + parts, err := ctx.cipher.encrypt(cek, authData, plaintext) + if err != nil { + return nil, err + } + + obj.iv = parts.iv + obj.ciphertext = parts.ciphertext + obj.tag = parts.tag + + return obj, nil +} + +func (ctx *genericEncrypter) Options() EncrypterOptions { + return EncrypterOptions{ + Compression: ctx.compressionAlg, + ExtraHeaders: ctx.extraHeaders, + } +} + +// Decrypt and validate the object and return the plaintext. Note that this +// function does not support multi-recipient, if you desire multi-recipient +// decryption use DecryptMulti instead. +func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) { + headers := obj.mergedHeaders(nil) + + if len(obj.recipients) > 1 { + return nil, errors.New("square/go-jose: too many recipients in payload; expecting only one") + } + + critical, err := headers.getCritical() + if err != nil { + return nil, fmt.Errorf("square/go-jose: invalid crit header") + } + + if len(critical) > 0 { + return nil, fmt.Errorf("square/go-jose: unsupported crit header") + } + + decrypter, err := newDecrypter(decryptionKey) + if err != nil { + return nil, err + } + + cipher := getContentCipher(headers.getEncryption()) + if cipher == nil { + return nil, fmt.Errorf("square/go-jose: unsupported enc value '%s'", string(headers.getEncryption())) + } + + generator := randomKeyGenerator{ + size: cipher.keySize(), + } + + parts := &aeadParts{ + iv: obj.iv, + ciphertext: obj.ciphertext, + tag: obj.tag, + } + + authData := obj.computeAuthData() + + var plaintext []byte + recipient := obj.recipients[0] + recipientHeaders := obj.mergedHeaders(&recipient) + + cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator) + if err == nil { + // Found a valid CEK -- let's try to decrypt. + plaintext, err = cipher.decrypt(cek, authData, parts) + } + + if plaintext == nil { + return nil, ErrCryptoFailure + } + + // The "zip" header parameter may only be present in the protected header. + if comp := obj.protected.getCompression(); comp != "" { + plaintext, err = decompress(comp, plaintext) + } + + return plaintext, err +} + +// DecryptMulti decrypts and validates the object and returns the plaintexts, +// with support for multiple recipients. It returns the index of the recipient +// for which the decryption was successful, the merged headers for that recipient, +// and the plaintext. +func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) { + globalHeaders := obj.mergedHeaders(nil) + + critical, err := globalHeaders.getCritical() + if err != nil { + return -1, Header{}, nil, fmt.Errorf("square/go-jose: invalid crit header") + } + + if len(critical) > 0 { + return -1, Header{}, nil, fmt.Errorf("square/go-jose: unsupported crit header") + } + + decrypter, err := newDecrypter(decryptionKey) + if err != nil { + return -1, Header{}, nil, err + } + + encryption := globalHeaders.getEncryption() + cipher := getContentCipher(encryption) + if cipher == nil { + return -1, Header{}, nil, fmt.Errorf("square/go-jose: unsupported enc value '%s'", string(encryption)) + } + + generator := randomKeyGenerator{ + size: cipher.keySize(), + } + + parts := &aeadParts{ + iv: obj.iv, + ciphertext: obj.ciphertext, + tag: obj.tag, + } + + authData := obj.computeAuthData() + + index := -1 + var plaintext []byte + var headers rawHeader + + for i, recipient := range obj.recipients { + recipientHeaders := obj.mergedHeaders(&recipient) + + cek, err := decrypter.decryptKey(recipientHeaders, &recipient, generator) + if err == nil { + // Found a valid CEK -- let's try to decrypt. + plaintext, err = cipher.decrypt(cek, authData, parts) + if err == nil { + index = i + headers = recipientHeaders + break + } + } + } + + if plaintext == nil || err != nil { + return -1, Header{}, nil, ErrCryptoFailure + } + + // The "zip" header parameter may only be present in the protected header. + if comp := obj.protected.getCompression(); comp != "" { + plaintext, err = decompress(comp, plaintext) + } + + sanitized, err := headers.sanitized() + if err != nil { + return -1, Header{}, nil, fmt.Errorf("square/go-jose: failed to sanitize header: %v", err) + } + + return index, sanitized, plaintext, err +} diff --git a/vendor/gopkg.in/square/go-jose.v2/doc.go b/vendor/gopkg.in/square/go-jose.v2/doc.go new file mode 100644 index 0000000000..dd1387f3f0 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/doc.go @@ -0,0 +1,27 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + +Package jose aims to provide an implementation of the Javascript Object Signing +and Encryption set of standards. It implements encryption and signing based on +the JSON Web Encryption and JSON Web Signature standards, with optional JSON +Web Token support available in a sub-package. The library supports both the +compact and full serialization formats, and has optional support for multiple +recipients. + +*/ +package jose diff --git a/vendor/gopkg.in/square/go-jose.v2/encoding.go b/vendor/gopkg.in/square/go-jose.v2/encoding.go new file mode 100644 index 0000000000..70f7385c41 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/encoding.go @@ -0,0 +1,185 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jose + +import ( + "bytes" + "compress/flate" + "encoding/base64" + "encoding/binary" + "io" + "math/big" + "strings" + "unicode" + + "gopkg.in/square/go-jose.v2/json" +) + +// Helper function to serialize known-good objects. +// Precondition: value is not a nil pointer. +func mustSerializeJSON(value interface{}) []byte { + out, err := json.Marshal(value) + if err != nil { + panic(err) + } + // We never want to serialize the top-level value "null," since it's not a + // valid JOSE message. But if a caller passes in a nil pointer to this method, + // MarshalJSON will happily serialize it as the top-level value "null". If + // that value is then embedded in another operation, for instance by being + // base64-encoded and fed as input to a signing algorithm + // (https://github.com/square/go-jose/issues/22), the result will be + // incorrect. Because this method is intended for known-good objects, and a nil + // pointer is not a known-good object, we are free to panic in this case. + // Note: It's not possible to directly check whether the data pointed at by an + // interface is a nil pointer, so we do this hacky workaround. + // https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I + if string(out) == "null" { + panic("Tried to serialize a nil pointer.") + } + return out +} + +// Strip all newlines and whitespace +func stripWhitespace(data string) string { + buf := strings.Builder{} + buf.Grow(len(data)) + for _, r := range data { + if !unicode.IsSpace(r) { + buf.WriteRune(r) + } + } + return buf.String() +} + +// Perform compression based on algorithm +func compress(algorithm CompressionAlgorithm, input []byte) ([]byte, error) { + switch algorithm { + case DEFLATE: + return deflate(input) + default: + return nil, ErrUnsupportedAlgorithm + } +} + +// Perform decompression based on algorithm +func decompress(algorithm CompressionAlgorithm, input []byte) ([]byte, error) { + switch algorithm { + case DEFLATE: + return inflate(input) + default: + return nil, ErrUnsupportedAlgorithm + } +} + +// Compress with DEFLATE +func deflate(input []byte) ([]byte, error) { + output := new(bytes.Buffer) + + // Writing to byte buffer, err is always nil + writer, _ := flate.NewWriter(output, 1) + _, _ = io.Copy(writer, bytes.NewBuffer(input)) + + err := writer.Close() + return output.Bytes(), err +} + +// Decompress with DEFLATE +func inflate(input []byte) ([]byte, error) { + output := new(bytes.Buffer) + reader := flate.NewReader(bytes.NewBuffer(input)) + + _, err := io.Copy(output, reader) + if err != nil { + return nil, err + } + + err = reader.Close() + return output.Bytes(), err +} + +// byteBuffer represents a slice of bytes that can be serialized to url-safe base64. +type byteBuffer struct { + data []byte +} + +func newBuffer(data []byte) *byteBuffer { + if data == nil { + return nil + } + return &byteBuffer{ + data: data, + } +} + +func newFixedSizeBuffer(data []byte, length int) *byteBuffer { + if len(data) > length { + panic("square/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)") + } + pad := make([]byte, length-len(data)) + return newBuffer(append(pad, data...)) +} + +func newBufferFromInt(num uint64) *byteBuffer { + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, num) + return newBuffer(bytes.TrimLeft(data, "\x00")) +} + +func (b *byteBuffer) MarshalJSON() ([]byte, error) { + return json.Marshal(b.base64()) +} + +func (b *byteBuffer) UnmarshalJSON(data []byte) error { + var encoded string + err := json.Unmarshal(data, &encoded) + if err != nil { + return err + } + + if encoded == "" { + return nil + } + + decoded, err := base64.RawURLEncoding.DecodeString(encoded) + if err != nil { + return err + } + + *b = *newBuffer(decoded) + + return nil +} + +func (b *byteBuffer) base64() string { + return base64.RawURLEncoding.EncodeToString(b.data) +} + +func (b *byteBuffer) bytes() []byte { + // Handling nil here allows us to transparently handle nil slices when serializing. + if b == nil { + return nil + } + return b.data +} + +func (b byteBuffer) bigInt() *big.Int { + return new(big.Int).SetBytes(b.data) +} + +func (b byteBuffer) toInt() int { + return int(b.bigInt().Int64()) +} diff --git a/vendor/gopkg.in/square/go-jose.v2/json/LICENSE b/vendor/gopkg.in/square/go-jose.v2/json/LICENSE new file mode 100644 index 0000000000..7448756763 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/json/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/square/go-jose.v2/json/README.md b/vendor/gopkg.in/square/go-jose.v2/json/README.md new file mode 100644 index 0000000000..86de5e5581 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/json/README.md @@ -0,0 +1,13 @@ +# Safe JSON + +This repository contains a fork of the `encoding/json` package from Go 1.6. + +The following changes were made: + +* Object deserialization uses case-sensitive member name matching instead of + [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html). + This is to avoid differences in the interpretation of JOSE messages between + go-jose and libraries written in other languages. +* When deserializing a JSON object, we check for duplicate keys and reject the + input whenever we detect a duplicate. Rather than trying to work with malformed + data, we prefer to reject it right away. diff --git a/vendor/gopkg.in/square/go-jose.v2/json/decode.go b/vendor/gopkg.in/square/go-jose.v2/json/decode.go new file mode 100644 index 0000000000..37457e5a83 --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/json/decode.go @@ -0,0 +1,1183 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "errors" + "fmt" + "reflect" + "runtime" + "strconv" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. +// Unmarshal will only set exported fields of the struct. +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a string-keyed map, Unmarshal first +// establishes a map to use, If the map is nil, Unmarshal allocates a new map. +// Otherwise Unmarshal reuses the existing map, keeping existing entries. +// Unmarshal then stores key-value pairs from the JSON object into the map. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +// +func Unmarshal(data []byte, v interface{}) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by objects +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes +} + +func (e *UnmarshalTypeError) Error() string { + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// (No longer used; kept for compatibility.) +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Ptr { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v interface{}) (err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + err = r.(error) + } + }() + + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + d.value(rv) + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// isValidNumber reports whether s is a valid JSON number literal. +func isValidNumber(s string) bool { + // This function implements the JSON numbers grammar. + // See https://tools.ietf.org/html/rfc7159#section-6 + // and http://json.org/number.gif + + if s == "" { + return false + } + + // Optional - + if s[0] == '-' { + s = s[1:] + if s == "" { + return false + } + } + + // Digits + switch { + default: + return false + + case s[0] == '0': + s = s[1:] + + case '1' <= s[0] && s[0] <= '9': + s = s[1:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // . followed by 1 or more digits. + if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { + s = s[2:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { + s = s[1:] + if s[0] == '+' || s[0] == '-' { + s = s[1:] + if s == "" { + return false + } + } + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // Make sure we are at the end. + return s == "" +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // read offset in data + scan scanner + nextscan scanner // for calls to nextValue + savedError error + useNumber bool +} + +// errPhase is used for errors that should not happen unless +// there is a bug in the JSON decoder or something is editing +// the data slice while the decoder executes. +var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?") + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + return d +} + +// error aborts the decoding by panicking with err. +func (d *decodeState) error(err error) { + panic(err) +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = err + } +} + +// next cuts off and returns the next full JSON value in d.data[d.off:]. +// The next value is known to be an object or array, not a literal. +func (d *decodeState) next() []byte { + c := d.data[d.off] + item, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // Our scanner has seen the opening brace/bracket + // and thinks we're still in the middle of the object. + // invent a closing brace/bracket to get it out. + if c == '{' { + d.scan.step(&d.scan, '}') + } else { + d.scan.step(&d.scan, ']') + } + + return item +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +// It updates d.off and returns the new scan code. +func (d *decodeState) scanWhile(op int) int { + var newOp int + for { + if d.off >= len(d.data) { + newOp = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } else { + c := d.data[d.off] + d.off++ + newOp = d.scan.step(&d.scan, c) + } + if newOp != op { + break + } + } + return newOp +} + +// value decodes a JSON value from d.data[d.off:] into the value. +// it updates d.off to point past the decoded value. +func (d *decodeState) value(v reflect.Value) { + if !v.IsValid() { + _, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // d.scan thinks we're still at the beginning of the item. + // Feed in an empty string - the shortest, simplest value - + // so that it knows we got to the end of the value. + if d.scan.redo { + // rewind. + d.scan.redo = false + d.scan.step = stateBeginValue + } + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + + n := len(d.scan.parseState) + if n > 0 && d.scan.parseState[n-1] == parseObjectKey { + // d.scan thinks we just read an object key; finish the object + d.scan.step(&d.scan, ':') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '}') + } + + return + } + + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(v) + + case scanBeginObject: + d.object(v) + + case scanBeginLiteral: + d.literal(v) + } +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() interface{} { + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(reflect.Value{}) + + case scanBeginObject: + d.object(reflect.Value{}) + + case scanBeginLiteral: + switch v := d.literalInterface().(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// if it encounters an Unmarshaler, indirect stops and returns that. +// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. +func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + v = v.Elem() + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into the value v. +// the first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) { + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) + d.off-- + d.next() + return + } + + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + v.Set(reflect.ValueOf(d.arrayInterface())) + return + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) + d.off-- + d.next() + return + case reflect.Array: + case reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + d.value(v.Index(i)) + } else { + // Ran out of fixed array: skip. + d.value(reflect.Value{}) + } + i++ + + // Next token must be , or ]. + op = d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + if op != scanArrayValue { + d.error(errPhase) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } +} + +var nullLiteral = []byte("null") + +// object consumes an object from d.data[d.off-1:], decoding into the value v. +// the first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) { + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + v = pv + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + v.Set(reflect.ValueOf(d.objectInterface())) + return + } + + // Check type of target: struct or map[string]T + switch v.Kind() { + case reflect.Map: + // map must have string kind + t := v.Type() + if t.Key().Kind() != reflect.String { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + + default: + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + + var mapElem reflect.Value + keys := map[string]bool{} + + for { + // Read opening " of string key or closing }. + op := d.scanWhile(scanSkipSpace) + if op == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if op != scanBeginLiteral { + d.error(errPhase) + } + + // Read key. + start := d.off - 1 + op = d.scanWhile(scanContinue) + item := d.data[start : d.off-1] + key, ok := unquote(item) + if !ok { + d.error(errPhase) + } + + // Check for duplicate keys. + _, ok = keys[key] + if !ok { + keys[key] = true + } else { + d.error(fmt.Errorf("json: duplicate key '%s' in object", key)) + } + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, []byte(key)) { + f = ff + break + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + } + } + + // Read : before value. + if op == scanSkipSpace { + op = d.scanWhile(scanSkipSpace) + } + if op != scanObjectKey { + d.error(errPhase) + } + + // Read value. + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + d.literalStore(nullLiteral, subv, false) + case string: + d.literalStore([]byte(qv), subv, true) + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + d.value(subv) + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kv := reflect.ValueOf(key).Convert(v.Type().Key()) + v.SetMapIndex(kv, subv) + } + + // Next token must be , or }. + op = d.scanWhile(scanSkipSpace) + if op == scanEndObject { + break + } + if op != scanObjectValue { + d.error(errPhase) + } + } +} + +// literal consumes a literal from d.data[d.off-1:], decoding into the value v. +// The first byte of the literal has been read already +// (that's how the caller knows it's a literal). +func (d *decodeState) literal(v reflect.Value) { + // All bytes inside literal return scanContinue op code. + start := d.off - 1 + op := d.scanWhile(scanContinue) + + // Scan read one byte too far; back up. + d.off-- + d.scan.undo(op) + + d.literalStore(d.data[start:d.off], v, false) +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (interface{}, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return + } + wantptr := item[0] == 'n' // null + u, ut, pv := d.indirect(v, wantptr) + if u != nil { + err := u.UnmarshalJSON(item) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + } + return + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + err := ut.UnmarshalText(s) + if err != nil { + d.error(err) + } + return + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + switch v.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := c == 't' + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + v.SetString(s) + if !isValidNumber(s) { + d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) + } + break + } + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) + } + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetFloat(n) + } + } +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() interface{} { + switch d.scanWhile(scanSkipSpace) { + default: + d.error(errPhase) + panic("unreachable") + case scanBeginArray: + return d.arrayInterface() + case scanBeginObject: + return d.objectInterface() + case scanBeginLiteral: + return d.literalInterface() + } +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []interface{} { + var v = make([]interface{}, 0) + for { + // Look ahead for ] - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + op = d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + if op != scanArrayValue { + d.error(errPhase) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]interface{} { + m := make(map[string]interface{}) + keys := map[string]bool{} + + for { + // Read opening " of string key or closing }. + op := d.scanWhile(scanSkipSpace) + if op == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if op != scanBeginLiteral { + d.error(errPhase) + } + + // Read string key. + start := d.off - 1 + op = d.scanWhile(scanContinue) + item := d.data[start : d.off-1] + key, ok := unquote(item) + if !ok { + d.error(errPhase) + } + + // Check for duplicate keys. + _, ok = keys[key] + if !ok { + keys[key] = true + } else { + d.error(fmt.Errorf("json: duplicate key '%s' in object", key)) + } + + // Read : before value. + if op == scanSkipSpace { + op = d.scanWhile(scanSkipSpace) + } + if op != scanObjectKey { + d.error(errPhase) + } + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + op = d.scanWhile(scanSkipSpace) + if op == scanEndObject { + break + } + if op != scanObjectValue { + d.error(errPhase) + } + } + return m +} + +// literalInterface is like literal but returns an interface value. +func (d *decodeState) literalInterface() interface{} { + // All bytes inside literal return scanContinue op code. + start := d.off - 1 + op := d.scanWhile(scanContinue) + + // Scan read one byte too far; back up. + d.off-- + d.scan.undo(op) + item := d.data[start:d.off] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + d.error(errPhase) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + d.error(errPhase) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + r, err := strconv.ParseUint(string(s[2:6]), 16, 64) + if err != nil { + return -1 + } + return rune(r) +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/gopkg.in/square/go-jose.v2/json/encode.go b/vendor/gopkg.in/square/go-jose.v2/json/encode.go new file mode 100644 index 0000000000..1dae8bb7cd --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/json/encode.go @@ -0,0 +1,1197 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON objects as defined in +// RFC 4627. The mapping between JSON objects and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" +// to keep some browsers from misinterpreting JSON output as HTML. +// Ampersand "&" is also escaped to "\u0026" for the same reason. +// +// Array and slice values encode as JSON arrays, except that +// []byte encodes as a base64-encoded string, and a nil slice +// encodes as the null JSON object. +// +// Struct values encode as JSON objects. Each exported struct field +// becomes a member of the object unless +// - the field's tag is "-", or +// - the field is empty and its tag specifies the "omitempty" option. +// The empty values are false, 0, any +// nil pointer or interface value, and any array, slice, map, or string of +// length zero. The object's default key string is the struct field name +// but can be specified in the struct field's tag value. The "json" key in +// the struct field's tag value is the key name, followed by an optional comma +// and options. Examples: +// +// // Field is ignored by this package. +// Field int `json:"-"` +// +// // Field appears in JSON as key "myName". +// Field int `json:"myName"` +// +// // Field appears in JSON as key "myName" and +// // the field is omitted from the object if its value is empty, +// // as defined above. +// Field int `json:"myName,omitempty"` +// +// // Field appears in JSON as key "Field" (the default), but +// // the field is skipped if empty. +// // Note the leading comma. +// Field int `json:",omitempty"` +// +// The "string" option signals that a field is stored as JSON inside a +// JSON-encoded string. It applies only to fields of string, floating point, +// integer, or boolean types. This extra level of encoding is sometimes used +// when communicating with JavaScript programs: +// +// Int64String int64 `json:",string"` +// +// The key name will be used if it's a non-empty string consisting of +// only Unicode letters, digits, dollar signs, percent signs, hyphens, +// underscores and slashes. +// +// Anonymous struct fields are usually marshaled as if their inner exported fields +// were fields in the outer struct, subject to the usual Go visibility rules amended +// as described in the next paragraph. +// An anonymous struct field with a name given in its JSON tag is treated as +// having that name, rather than being anonymous. +// An anonymous struct field of interface type is treated the same as having +// that type as its name, rather than being anonymous. +// +// The Go visibility rules for struct fields are amended for JSON when +// deciding which field to marshal or unmarshal. If there are +// multiple fields at the same level, and that level is the least +// nested (and would therefore be the nesting level selected by the +// usual Go rules), the following extra rules apply: +// +// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, +// even if there are multiple untagged fields that would otherwise conflict. +// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. +// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. +// +// Handling of anonymous struct fields is new in Go 1.1. +// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of +// an anonymous struct field in both current and earlier versions, give the field +// a JSON tag of "-". +// +// Map values encode as JSON objects. +// The map's key type must be string; the map keys are used as JSON object +// keys, subject to the UTF-8 coercion described for string values above. +// +// Pointer values encode as the value pointed to. +// A nil pointer encodes as the null JSON object. +// +// Interface values encode as the value contained in the interface. +// A nil interface value encodes as the null JSON object. +// +// Channel, complex, and function values cannot be encoded in JSON. +// Attempting to encode such a value causes Marshal to return +// an UnsupportedTypeError. +// +// JSON cannot represent cyclic data structures and Marshal does not +// handle them. Passing cyclic structures to Marshal will result in +// an infinite recursion. +// +func Marshal(v interface{}) ([]byte, error) { + e := &encodeState{} + err := e.marshal(v) + if err != nil { + return nil, err + } + return e.Bytes(), nil +} + +// MarshalIndent is like Marshal but applies Indent to format the output. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + b, err := Marshal(v) + if err != nil { + return nil, err + } + var buf bytes.Buffer + err = Indent(&buf, b, prefix, indent) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 +// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 +// so that the JSON will be safe to embed inside HTML