From 45333d24802d3b68c199c9f9ac852bc1f031dd08 Mon Sep 17 00:00:00 2001 From: Justin Cormack Date: Wed, 1 Nov 2017 12:14:20 +0000 Subject: [PATCH] Update dependencies to use sirupsen not Sirupsen That entailed a few other fixes, eg small Notary API changes. Signed-off-by: Justin Cormack --- circle.yml => .circleci/config.yml | 6 +- Makefile | 2 +- cmd/moby/build.go | 4 +- cmd/moby/main.go | 2 +- src/moby/build.go | 2 +- src/moby/config.go | 2 +- src/moby/docker.go | 4 +- src/moby/image.go | 2 +- src/moby/linuxkit.go | 2 +- src/moby/output.go | 2 +- src/moby/trust.go | 14 +- vendor.conf | 13 +- .../Sirupsen/logrus/terminal_appengine.go | 10 - .../Sirupsen/logrus/terminal_bsd.go | 10 - .../Sirupsen/logrus/terminal_notwindows.go | 28 - .../Sirupsen/logrus/terminal_solaris.go | 21 - .../Sirupsen/logrus/terminal_windows.go | 33 - .../containerd/reference/reference.go | 10 +- .../containerd/containerd/vendor.conf | 11 +- .../github.com/docker/distribution/README.md | 3 +- .../github.com/docker/distribution/blobs.go | 4 +- .../docker/distribution/context/context.go | 85 - .../docker/distribution/context/doc.go | 89 -- .../docker/distribution/context/http.go | 366 ----- .../docker/distribution/context/logger.go | 116 -- .../docker/distribution/context/trace.go | 104 -- .../docker/distribution/context/util.go | 24 - .../docker/distribution/context/version.go | 16 - .../github.com/docker/distribution/errors.go | 2 +- .../docker/distribution/manifests.go | 2 +- .../distribution/reference/reference.go | 2 +- .../docker/distribution/registry.go | 18 +- .../registry/api/errcode/handler.go | 6 +- .../distribution/registry/api/v2/urls.go | 116 +- .../registry/client/auth/session.go | 33 +- .../registry/client/blob_writer.go | 2 +- .../registry/client/repository.go | 51 +- .../cache/cachedblobdescriptorstore.go | 30 +- .../registry/storage/cache/memory/memory.go | 2 +- vendor/github.com/docker/distribution/tags.go | 2 +- .../docker/distribution/vendor.conf | 18 +- vendor/github.com/docker/docker/README.md | 69 +- vendor/github.com/docker/docker/api/README.md | 8 +- vendor/github.com/docker/docker/api/common.go | 56 +- vendor/github.com/docker/docker/api/names.go | 9 - .../docker/docker/api/types/client.go | 16 +- .../docker/docker/api/types/configs.go | 1 - .../api/types/container/container_wait.go | 12 + .../docker/api/types/container/host_config.go | 39 +- .../docker/docker/api/types/events/events.go | 2 + .../docker/docker/api/types/filters/parse.go | 280 ++-- .../docker/docker/api/types/mount/mount.go | 4 +- .../docker/docker/api/types/plugin.go | 2 +- .../docker/api/types/plugin_responses.go | 8 - .../docker/docker/api/types/swarm/common.go | 2 +- .../docker/docker/api/types/swarm/secret.go | 3 +- .../docker/docker/api/types/swarm/task.go | 31 +- .../docker/docker/api/types/time/timestamp.go | 4 +- .../docker/docker/api/types/types.go | 1 + .../docker/docker/api/types/volume.go | 16 +- .../docker/docker/client/checkpoint_list.go | 6 +- .../github.com/docker/docker/client/client.go | 88 +- .../docker/docker/client/config_inspect.go | 6 +- .../docker/docker/client/config_list.go | 2 +- .../docker/docker/client/config_remove.go | 2 +- .../docker/docker/client/container_commit.go | 2 +- .../docker/docker/client/container_create.go | 2 +- .../docker/docker/client/container_exec.go | 2 +- .../docker/docker/client/container_inspect.go | 11 +- .../docker/docker/client/container_remove.go | 2 +- .../github.com/docker/docker/client/errors.go | 251 +-- .../github.com/docker/docker/client/hijack.go | 19 +- .../docker/docker/client/image_build.go | 12 +- .../docker/docker/client/image_create.go | 4 + .../docker/docker/client/image_import.go | 4 + .../docker/docker/client/image_inspect.go | 6 +- .../docker/docker/client/image_pull.go | 4 + .../docker/docker/client/image_remove.go | 4 +- .../docker/docker/client/image_search.go | 2 +- .../docker/docker/client/interface.go | 2 +- .../docker/docker/client/network_inspect.go | 6 +- .../docker/docker/client/network_remove.go | 2 +- .../docker/docker/client/node_inspect.go | 6 +- .../docker/docker/client/node_list.go | 2 +- .../docker/docker/client/node_remove.go | 2 +- .../docker/docker/client/parse_logs.go | 41 - .../github.com/docker/docker/client/ping.go | 8 +- .../docker/docker/client/plugin_inspect.go | 6 +- .../docker/docker/client/plugin_list.go | 2 +- .../docker/docker/client/plugin_remove.go | 2 +- .../docker/docker/client/request.go | 2 +- .../docker/docker/client/secret_inspect.go | 6 +- .../docker/docker/client/secret_list.go | 2 +- .../docker/docker/client/secret_remove.go | 2 +- .../docker/docker/client/service_create.go | 20 +- .../docker/docker/client/service_inspect.go | 6 +- .../docker/docker/client/service_list.go | 2 +- .../docker/docker/client/service_remove.go | 2 +- .../docker/docker/client/task_inspect.go | 7 +- .../docker/docker/client/task_list.go | 2 +- .../docker/docker/client/tlsconfig_clone.go | 11 + .../tlsconfig_clone_go17.go | 6 +- .../docker/docker/client/transport.go | 8 - .../github.com/docker/docker/client/utils.go | 2 +- .../docker/docker/client/volume_inspect.go | 16 +- .../docker/docker/client/volume_remove.go | 2 +- .../github.com/docker/docker/hack/README.md | 60 + .../hack/integration-cli-on-swarm/README.md | 69 + .../agent/vendor.conf | 2 + vendor/github.com/docker/docker/pkg/README.md | 11 - .../docker/docker/pkg/ioutils/buffer.go | 51 - .../docker/docker/pkg/ioutils/bytespipe.go | 186 --- .../docker/docker/pkg/ioutils/fswriters.go | 162 -- .../docker/docker/pkg/ioutils/readers.go | 154 -- .../docker/docker/pkg/ioutils/temp_unix.go | 10 - .../docker/docker/pkg/ioutils/temp_windows.go | 18 - .../docker/docker/pkg/ioutils/writeflusher.go | 92 -- .../docker/docker/pkg/ioutils/writers.go | 66 - .../docker/docker/pkg/longpath/longpath.go | 26 - .../docker/docker/pkg/mount/flags.go | 149 -- .../docker/docker/pkg/mount/flags_freebsd.go | 49 - .../docker/docker/pkg/mount/flags_linux.go | 87 -- .../docker/pkg/mount/flags_unsupported.go | 31 - .../docker/docker/pkg/mount/mount.go | 86 -- .../docker/pkg/mount/mounter_freebsd.go | 59 - .../docker/docker/pkg/mount/mounter_linux.go | 56 - .../docker/pkg/mount/mounter_solaris.go | 33 - .../docker/pkg/mount/mounter_unsupported.go | 11 - .../docker/docker/pkg/mount/mountinfo.go | 54 - .../docker/pkg/mount/mountinfo_freebsd.go | 41 - .../docker/pkg/mount/mountinfo_linux.go | 95 -- .../docker/pkg/mount/mountinfo_solaris.go | 37 - .../docker/pkg/mount/mountinfo_unsupported.go | 12 - .../docker/pkg/mount/mountinfo_windows.go | 6 - .../docker/pkg/mount/sharedsubtree_linux.go | 69 - .../docker/pkg/mount/sharedsubtree_solaris.go | 58 - .../docker/docker/pkg/system/chtimes.go | 35 - .../docker/docker/pkg/system/chtimes_unix.go | 14 - .../docker/pkg/system/chtimes_windows.go | 27 - .../docker/docker/pkg/system/errors.go | 10 - .../docker/pkg/system/events_windows.go | 85 - .../docker/docker/pkg/system/exitcode.go | 33 - .../docker/docker/pkg/system/filesys.go | 67 - .../docker/pkg/system/filesys_windows.go | 298 ---- .../docker/docker/pkg/system/init.go | 22 - .../docker/docker/pkg/system/init_windows.go | 17 - .../docker/docker/pkg/system/lcow_unix.go | 8 - .../docker/docker/pkg/system/lcow_windows.go | 6 - .../docker/docker/pkg/system/lstat_unix.go | 17 - .../docker/docker/pkg/system/lstat_windows.go | 14 - .../docker/docker/pkg/system/meminfo.go | 17 - .../docker/docker/pkg/system/meminfo_linux.go | 65 - .../docker/pkg/system/meminfo_solaris.go | 129 -- .../docker/pkg/system/meminfo_unsupported.go | 8 - .../docker/pkg/system/meminfo_windows.go | 45 - .../docker/docker/pkg/system/mknod.go | 22 - .../docker/docker/pkg/system/mknod_windows.go | 13 - .../docker/docker/pkg/system/path.go | 21 - .../docker/docker/pkg/system/path_unix.go | 9 - .../docker/docker/pkg/system/path_windows.go | 33 - .../docker/docker/pkg/system/process_unix.go | 22 - .../github.com/docker/docker/pkg/system/rm.go | 80 - .../docker/docker/pkg/system/stat_darwin.go | 13 - .../docker/docker/pkg/system/stat_freebsd.go | 13 - .../docker/docker/pkg/system/stat_linux.go | 19 - .../docker/docker/pkg/system/stat_openbsd.go | 13 - .../docker/docker/pkg/system/stat_solaris.go | 13 - .../docker/docker/pkg/system/stat_unix.go | 58 - .../docker/docker/pkg/system/stat_windows.go | 49 - .../docker/docker/pkg/system/syscall_unix.go | 17 - .../docker/pkg/system/syscall_windows.go | 122 -- .../docker/docker/pkg/system/umask.go | 13 - .../docker/docker/pkg/system/umask_windows.go | 9 - .../docker/pkg/system/utimes_freebsd.go | 22 - .../docker/docker/pkg/system/utimes_linux.go | 26 - .../docker/pkg/system/utimes_unsupported.go | 10 - .../docker/docker/pkg/system/xattrs_linux.go | 63 - .../docker/pkg/system/xattrs_unsupported.go | 13 - .../docker/pkg/tlsconfig/tlsconfig_clone.go | 11 - vendor/github.com/docker/docker/vendor.conf | 60 +- .../go-connections/tlsconfig/certpool_go17.go | 3 - .../tlsconfig/certpool_other.go | 2 - .../docker/go-connections/tlsconfig/config.go | 2 - vendor/github.com/docker/libtrust/LICENSE | 191 --- vendor/github.com/docker/libtrust/README.md | 18 - .../docker/libtrust/certificates.go | 175 --- vendor/github.com/docker/libtrust/doc.go | 9 - vendor/github.com/docker/libtrust/ec_key.go | 428 ----- vendor/github.com/docker/libtrust/filter.go | 50 - vendor/github.com/docker/libtrust/hash.go | 56 - vendor/github.com/docker/libtrust/jsonsign.go | 657 -------- vendor/github.com/docker/libtrust/key.go | 253 --- .../github.com/docker/libtrust/key_files.go | 255 --- .../github.com/docker/libtrust/key_manager.go | 175 --- vendor/github.com/docker/libtrust/rsa_key.go | 427 ----- vendor/github.com/docker/libtrust/util.go | 363 ----- .../github.com/docker/notary/client/client.go | 1014 ------------ .../github.com/docker/notary/client/repo.go | 29 - .../docker/notary/client/repo_pkcs11.go | 34 - .../{Sirupsen => sirupsen}/logrus/LICENSE | 0 .../{Sirupsen => sirupsen}/logrus/README.md | 86 +- .../{Sirupsen => sirupsen}/logrus/alt_exit.go | 0 .../{Sirupsen => sirupsen}/logrus/doc.go | 4 +- .../{Sirupsen => sirupsen}/logrus/entry.go | 37 +- .../{Sirupsen => sirupsen}/logrus/exported.go | 4 +- .../logrus/formatter.go | 2 +- .../{Sirupsen => sirupsen}/logrus/hooks.go | 0 .../logrus/json_formatter.go | 13 +- .../{Sirupsen => sirupsen}/logrus/logger.go | 53 +- .../{Sirupsen => sirupsen}/logrus/logrus.go | 2 +- .../sirupsen/logrus/terminal_bsd.go | 10 + .../logrus/terminal_linux.go | 6 +- .../logrus/text_formatter.go | 60 +- .../{Sirupsen => sirupsen}/logrus/writer.go | 0 .../notary/LICENSE | 2 +- .../notary/README.md | 39 +- .../notary/client/changelist/change.go | 44 +- .../notary/client/changelist/changelist.go | 5 + .../client/changelist/file_changelist.go | 9 +- .../notary/client/changelist/interface.go | 7 +- .../notary/client/client.go | 1374 +++++++++++++++++ .../notary/client/delegations.go | 87 +- .../notary/client/errors.go | 48 + .../notary/client/helpers.go | 74 +- .../notary/client/interface.go | 47 + .../theupdateframework/notary/client/repo.go | 18 + .../notary/client/repo_pkcs11.go | 25 + .../notary/client/tufclient.go | 164 +- .../notary/client/witness.go | 23 +- .../notary/const.go | 57 +- .../notary/const_nowindows.go | 0 .../notary/const_windows.go | 0 .../notary/cryptoservice/certificate.go | 12 +- .../notary/cryptoservice/crypto_service.go | 78 +- .../theupdateframework/notary/fips.go | 13 + .../notary/notary.go | 5 + .../notary/storage/errors.go | 0 .../notary/storage/filestore.go | 106 +- .../notary/storage/httpstore.go | 56 +- .../notary/storage/interfaces.go | 8 +- .../notary/storage/memorystore.go | 39 +- .../notary/storage/offlinestore.go | 8 +- .../notary/trustmanager/errors.go | 31 + .../notary/trustmanager/interfaces.go | 42 +- .../notary/trustmanager/keys.go | 240 +++ .../notary/trustmanager/keystore.go | 151 +- .../notary/trustmanager/yubikey/import.go | 12 +- .../notary/trustmanager/yubikey/non_pkcs11.go | 0 .../trustmanager/yubikey/pkcs11_darwin.go | 0 .../trustmanager/yubikey/pkcs11_interface.go | 0 .../trustmanager/yubikey/pkcs11_linux.go | 0 .../trustmanager/yubikey/yubikeystore.go | 102 +- .../notary/trustpinning/certs.go | 31 +- .../notary/trustpinning/trustpin.go | 62 +- .../notary/tuf/LICENSE | 0 .../notary/tuf/README.md | 0 .../notary/tuf/builder.go | 136 +- .../notary/tuf/data/errors.go | 4 +- .../notary/tuf/data/keys.go | 10 +- .../notary/tuf/data/roles.go | 47 +- .../notary/tuf/data/root.go | 12 +- .../notary/tuf/data/serializer.go | 0 .../notary/tuf/data/snapshot.go | 34 +- .../notary/tuf/data/targets.go | 8 +- .../notary/tuf/data/timestamp.go | 12 +- .../notary/tuf/data/types.go | 113 +- .../notary/tuf/signed/ed25519.go | 22 +- .../notary/tuf/signed/errors.go | 6 +- .../notary/tuf/signed/interface.go | 14 +- .../notary/tuf/signed/sign.go | 8 +- .../notary/tuf/signed/verifiers.go | 23 +- .../notary/tuf/signed/verify.go | 27 +- .../notary/tuf/tuf.go | 271 ++-- .../notary/tuf/utils/pkcs8.go | 341 ++++ .../notary/tuf/utils/role_sort.go | 0 .../notary/tuf/utils/stack.go | 0 .../notary/tuf/utils/utils.go | 65 +- .../notary/tuf/utils/x509.go | 190 +-- .../notary/tuf/validation/errors.go | 0 .../theupdateframework/notary/vendor.conf | 59 + vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 + .../x/crypto/ssh/terminal/terminal.go | 951 ++++++++++++ .../golang.org/x/crypto/ssh/terminal/util.go | 119 ++ .../x/crypto/ssh/terminal/util_bsd.go | 12 + .../x/crypto/ssh/terminal/util_linux.go | 11 + .../x/crypto/ssh/terminal/util_plan9.go | 58 + .../x/crypto/ssh/terminal/util_solaris.go | 73 + .../x/crypto/ssh/terminal/util_windows.go | 155 ++ 288 files changed, 5855 insertions(+), 10377 deletions(-) rename circle.yml => .circleci/config.yml (87%) delete mode 100644 vendor/github.com/Sirupsen/logrus/terminal_appengine.go delete mode 100644 vendor/github.com/Sirupsen/logrus/terminal_bsd.go delete mode 100644 vendor/github.com/Sirupsen/logrus/terminal_notwindows.go delete mode 100644 vendor/github.com/Sirupsen/logrus/terminal_solaris.go delete mode 100644 vendor/github.com/Sirupsen/logrus/terminal_windows.go delete mode 100644 vendor/github.com/docker/distribution/context/context.go delete mode 100644 vendor/github.com/docker/distribution/context/doc.go delete mode 100644 vendor/github.com/docker/distribution/context/http.go delete mode 100644 vendor/github.com/docker/distribution/context/logger.go delete mode 100644 vendor/github.com/docker/distribution/context/trace.go delete mode 100644 vendor/github.com/docker/distribution/context/util.go delete mode 100644 vendor/github.com/docker/distribution/context/version.go delete mode 100644 vendor/github.com/docker/docker/api/names.go delete mode 100644 vendor/github.com/docker/docker/client/parse_logs.go create mode 100644 vendor/github.com/docker/docker/client/tlsconfig_clone.go rename vendor/github.com/docker/docker/{pkg/tlsconfig => client}/tlsconfig_clone_go17.go (89%) create mode 100644 vendor/github.com/docker/docker/hack/README.md create mode 100644 vendor/github.com/docker/docker/hack/integration-cli-on-swarm/README.md create mode 100644 vendor/github.com/docker/docker/hack/integration-cli-on-swarm/agent/vendor.conf delete mode 100644 vendor/github.com/docker/docker/pkg/README.md delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/buffer.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/fswriters.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/readers.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writers.go delete mode 100644 vendor/github.com/docker/docker/pkg/longpath/longpath.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/flags.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/flags_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mount.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/chtimes.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/chtimes_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/chtimes_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/errors.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/events_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/exitcode.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/filesys.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/filesys_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/init.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/init_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/lcow_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/lcow_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/lstat_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/lstat_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/meminfo_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/mknod.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/mknod_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/path.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/path_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/path_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/process_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/rm.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_darwin.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_freebsd.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_openbsd.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_solaris.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/stat_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/syscall_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/syscall_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/umask.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/umask_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/utimes_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/xattrs_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go delete mode 100644 vendor/github.com/docker/libtrust/LICENSE delete mode 100644 vendor/github.com/docker/libtrust/README.md delete mode 100644 vendor/github.com/docker/libtrust/certificates.go delete mode 100644 vendor/github.com/docker/libtrust/doc.go delete mode 100644 vendor/github.com/docker/libtrust/ec_key.go delete mode 100644 vendor/github.com/docker/libtrust/filter.go delete mode 100644 vendor/github.com/docker/libtrust/hash.go delete mode 100644 vendor/github.com/docker/libtrust/jsonsign.go delete mode 100644 vendor/github.com/docker/libtrust/key.go delete mode 100644 vendor/github.com/docker/libtrust/key_files.go delete mode 100644 vendor/github.com/docker/libtrust/key_manager.go delete mode 100644 vendor/github.com/docker/libtrust/rsa_key.go delete mode 100644 vendor/github.com/docker/libtrust/util.go delete mode 100644 vendor/github.com/docker/notary/client/client.go delete mode 100644 vendor/github.com/docker/notary/client/repo.go delete mode 100644 vendor/github.com/docker/notary/client/repo_pkcs11.go rename vendor/github.com/{Sirupsen => sirupsen}/logrus/LICENSE (100%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/README.md (85%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/alt_exit.go (100%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/doc.go (83%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/entry.go (87%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/exported.go (99%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/formatter.go (96%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/hooks.go (100%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/json_formatter.go (78%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/logger.go (87%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/logrus.go (99%) create mode 100644 vendor/github.com/sirupsen/logrus/terminal_bsd.go rename vendor/github.com/{Sirupsen => sirupsen}/logrus/terminal_linux.go (70%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/text_formatter.go (82%) rename vendor/github.com/{Sirupsen => sirupsen}/logrus/writer.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/LICENSE (99%) rename vendor/github.com/{docker => theupdateframework}/notary/README.md (73%) rename vendor/github.com/{docker => theupdateframework}/notary/client/changelist/change.go (64%) rename vendor/github.com/{docker => theupdateframework}/notary/client/changelist/changelist.go (94%) rename vendor/github.com/{docker => theupdateframework}/notary/client/changelist/file_changelist.go (96%) rename vendor/github.com/{docker => theupdateframework}/notary/client/changelist/interface.go (93%) create mode 100644 vendor/github.com/theupdateframework/notary/client/client.go rename vendor/github.com/{docker => theupdateframework}/notary/client/delegations.go (75%) create mode 100644 vendor/github.com/theupdateframework/notary/client/errors.go rename vendor/github.com/{docker => theupdateframework}/notary/client/helpers.go (77%) create mode 100644 vendor/github.com/theupdateframework/notary/client/interface.go create mode 100644 vendor/github.com/theupdateframework/notary/client/repo.go create mode 100644 vendor/github.com/theupdateframework/notary/client/repo_pkcs11.go rename vendor/github.com/{docker => theupdateframework}/notary/client/tufclient.go (59%) rename vendor/github.com/{docker => theupdateframework}/notary/client/witness.go (76%) rename vendor/github.com/{docker => theupdateframework}/notary/const.go (57%) rename vendor/github.com/{docker => theupdateframework}/notary/const_nowindows.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/const_windows.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/cryptoservice/certificate.go (65%) rename vendor/github.com/{docker => theupdateframework}/notary/cryptoservice/crypto_service.go (67%) create mode 100644 vendor/github.com/theupdateframework/notary/fips.go rename vendor/github.com/{docker => theupdateframework}/notary/notary.go (70%) rename vendor/github.com/{docker => theupdateframework}/notary/storage/errors.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/storage/filestore.go (58%) rename vendor/github.com/{docker => theupdateframework}/notary/storage/httpstore.go (83%) rename vendor/github.com/{docker => theupdateframework}/notary/storage/interfaces.go (85%) rename vendor/github.com/{docker => theupdateframework}/notary/storage/memorystore.go (77%) rename vendor/github.com/{docker => theupdateframework}/notary/storage/offlinestore.go (84%) create mode 100644 vendor/github.com/theupdateframework/notary/trustmanager/errors.go rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/interfaces.go (59%) create mode 100644 vendor/github.com/theupdateframework/notary/trustmanager/keys.go rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/keystore.go (59%) rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/yubikey/import.go (83%) rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/yubikey/non_pkcs11.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/yubikey/pkcs11_darwin.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/yubikey/pkcs11_interface.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/yubikey/pkcs11_linux.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/trustmanager/yubikey/yubikeystore.go (95%) rename vendor/github.com/{docker => theupdateframework}/notary/trustpinning/certs.go (92%) rename vendor/github.com/{docker => theupdateframework}/notary/trustpinning/trustpin.go (63%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/LICENSE (100%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/README.md (100%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/builder.go (80%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/errors.go (93%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/keys.go (97%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/roles.go (89%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/root.go (90%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/serializer.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/snapshot.go (81%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/targets.go (94%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/timestamp.go (91%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/data/types.go (73%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/signed/ed25519.go (79%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/signed/errors.go (94%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/signed/interface.go (80%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/signed/sign.go (95%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/signed/verifiers.go (92%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/signed/verify.go (77%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/tuf.go (82%) create mode 100644 vendor/github.com/theupdateframework/notary/tuf/utils/pkcs8.go rename vendor/github.com/{docker => theupdateframework}/notary/tuf/utils/role_sort.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/utils/stack.go (100%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/utils/utils.go (62%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/utils/x509.go (80%) rename vendor/github.com/{docker => theupdateframework}/notary/tuf/validation/errors.go (100%) create mode 100644 vendor/github.com/theupdateframework/notary/vendor.conf create mode 100644 vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/terminal.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_linux.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/util_windows.go diff --git a/circle.yml b/.circleci/config.yml similarity index 87% rename from circle.yml rename to .circleci/config.yml index 43cd44290..bf157454d 100644 --- a/circle.yml +++ b/.circleci/config.yml @@ -1,7 +1,8 @@ version: 2 -executorType: machine jobs: build: + machine: + image: circleci/classic:201710-02 environment: GOPATH: /home/circleci/.go_workspace working_directory: $GOPATH/src/github.com/moby/tool @@ -10,7 +11,8 @@ jobs: - run: name: "Lint" command: | - GOMETALINTER_SHA=7f9672e7ea538b8682e83395d50b12f09bb17b91 + go version + GOMETALINTER_SHA=cc4415ed09f7073d595ee504cad4d98b71a3038e go get -d github.com/alecthomas/gometalinter cd $GOPATH/src/github.com/alecthomas/gometalinter git checkout -q "$GOMETALINTER_SHA" diff --git a/Makefile b/Makefile index 9c5487544..67ee94185 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ test: dist/moby rm dist/moby test.tar .PHONY: all -all: lint test moby +all: lint test dist/moby .PHONY: install install: dist/moby diff --git a/cmd/moby/build.go b/cmd/moby/build.go index 405330260..110944ce5 100644 --- a/cmd/moby/build.go +++ b/cmd/moby/build.go @@ -12,8 +12,8 @@ import ( "strconv" "strings" - log "github.com/Sirupsen/logrus" "github.com/moby/tool/src/moby" + log "github.com/sirupsen/logrus" ) const defaultNameForStdin = "moby" @@ -176,7 +176,7 @@ func build(args []string) { buffer := new(bytes.Buffer) response, err := http.Get(arg) if err != nil { - log.Fatal("Cannot fetch remote yaml file: %v", err) + log.Fatalf("Cannot fetch remote yaml file: %v", err) } defer response.Body.Close() _, err = io.Copy(buffer, response.Body) diff --git a/cmd/moby/main.go b/cmd/moby/main.go index 91befa2dc..8fa32e4a1 100644 --- a/cmd/moby/main.go +++ b/cmd/moby/main.go @@ -6,8 +6,8 @@ import ( "os" "path/filepath" - log "github.com/Sirupsen/logrus" "github.com/moby/tool/src/moby" + log "github.com/sirupsen/logrus" ) var ( diff --git a/src/moby/build.go b/src/moby/build.go index cdde471ff..56892ae18 100644 --- a/src/moby/build.go +++ b/src/moby/build.go @@ -14,7 +14,7 @@ import ( "strconv" "strings" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" ) diff --git a/src/moby/config.go b/src/moby/config.go index df3032675..2a66efa98 100644 --- a/src/moby/config.go +++ b/src/moby/config.go @@ -8,11 +8,11 @@ import ( "strconv" "strings" - log "github.com/Sirupsen/logrus" "github.com/containerd/containerd/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/opencontainers/runtime-spec/specs-go" + log "github.com/sirupsen/logrus" "github.com/xeipuuv/gojsonschema" "gopkg.in/yaml.v2" ) diff --git a/src/moby/docker.go b/src/moby/docker.go index f8f2134fe..640cf8119 100644 --- a/src/moby/docker.go +++ b/src/moby/docker.go @@ -13,12 +13,12 @@ import ( "os/exec" "strings" - log "github.com/Sirupsen/logrus" "github.com/containerd/containerd/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" + log "github.com/sirupsen/logrus" "golang.org/x/net/context" ) @@ -181,7 +181,7 @@ func dockerInspectImage(cli *client.Client, ref *reference.Spec, trustedPull boo inspect, _, err := cli.ImageInspectWithRaw(context.Background(), ref.String()) if err != nil { - if client.IsErrImageNotFound(err) { + if client.IsErrNotFound(err) { pullErr := dockerPull(ref, true, trustedPull) if pullErr != nil { return types.ImageInspect{}, pullErr diff --git a/src/moby/image.go b/src/moby/image.go index e60b25556..9f2a3504e 100644 --- a/src/moby/image.go +++ b/src/moby/image.go @@ -10,9 +10,9 @@ import ( "path" "strings" - log "github.com/Sirupsen/logrus" "github.com/containerd/containerd/reference" "github.com/opencontainers/runtime-spec/specs-go" + log "github.com/sirupsen/logrus" ) type tarWriter interface { diff --git a/src/moby/linuxkit.go b/src/moby/linuxkit.go index fcc6efa42..3317f1ed6 100644 --- a/src/moby/linuxkit.go +++ b/src/moby/linuxkit.go @@ -10,7 +10,7 @@ import ( "os/exec" "path/filepath" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) var linuxkitYaml = map[string]string{"mkimage": ` diff --git a/src/moby/output.go b/src/moby/output.go index 62ad1b4b6..155589476 100644 --- a/src/moby/output.go +++ b/src/moby/output.go @@ -8,8 +8,8 @@ import ( "os" "runtime" - log "github.com/Sirupsen/logrus" "github.com/moby/tool/src/initrd" + log "github.com/sirupsen/logrus" ) const ( diff --git a/src/moby/trust.go b/src/moby/trust.go index a1fa726f2..97fdbea54 100644 --- a/src/moby/trust.go +++ b/src/moby/trust.go @@ -15,20 +15,20 @@ import ( "strings" "time" - log "github.com/Sirupsen/logrus" "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/client/auth" "github.com/docker/distribution/registry/client/auth/challenge" "github.com/docker/distribution/registry/client/transport" - notaryClient "github.com/docker/notary/client" - "github.com/docker/notary/trustpinning" - "github.com/docker/notary/tuf/data" "github.com/opencontainers/go-digest" + log "github.com/sirupsen/logrus" + notaryClient "github.com/theupdateframework/notary/client" + "github.com/theupdateframework/notary/trustpinning" + "github.com/theupdateframework/notary/tuf/data" ) var ( // ReleasesRole is the role named "releases" - ReleasesRole = path.Join(data.CanonicalTargetsRole, "releases") + ReleasesRole = data.RoleName(path.Join(data.CanonicalTargetsRole.String(), "releases")) ) // TrustedReference parses an image string, and does a notary lookup to verify and retrieve the signed digest reference @@ -69,9 +69,9 @@ func TrustedReference(image string) (reference.Reference, error) { rt = nil } - nRepo, err := notaryClient.NewNotaryRepository( + nRepo, err := notaryClient.NewFileCachedRepository( trustDirectory(), - gun, + data.GUN(gun), server, rt, nil, diff --git a/vendor.conf b/vendor.conf index 6f780ff38..30c42f889 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,20 +1,19 @@ -github.com/Sirupsen/logrus 10f801ebc38b33738c9d17d50860f484a0988ff5 github.com/agl/ed25519 5312a61534124124185d41f09206b9fef1d88403 -github.com/containerd/containerd v1.0.0-beta.1 -github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621 -github.com/docker/docker 6978a6e25a2e6063f280ec842bd0f3eae99426e1 +github.com/containerd/containerd v1.0.0-beta.2 +github.com/docker/distribution 3800056b8832cf6075e78b282ac010131d8687bc +github.com/docker/docker ba99c19b593bdb9e7b90793681fe89b0a91781ed github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06 -github.com/docker/go-connections e15c02316c12de00874640cd76311849de2aeed5 +github.com/docker/go-connections v0.3.0 github.com/docker/go-units v0.3.1 -github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a -github.com/docker/notary v0.4.2 github.com/gogo/protobuf v0.4 github.com/gorilla/mux 4c1c3952b7d9d0a061a3fa7b36fd373ba0398ebc github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 github.com/opencontainers/image-spec v1.0.0 github.com/opencontainers/runtime-spec v1.0.0 github.com/pkg/errors v0.8.0 +github.com/sirupsen/logrus v1.0.3 github.com/surma/gocpio fcb68777e7dc4ea43ffce871b552c0d073c17495 +github.com/theupdateframework/notary c3574cbdf09c9b52ffd364451d1c793b129edb0a github.com/xeipuuv/gojsonpointer 6fe8760cad3569743d51ddbb243b26f8456742dc github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45 github.com/xeipuuv/gojsonschema 702b404897d4364af44dc8dcabc9815947942325 diff --git a/vendor/github.com/Sirupsen/logrus/terminal_appengine.go b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go deleted file mode 100644 index e011a8694..000000000 --- a/vendor/github.com/Sirupsen/logrus/terminal_appengine.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build appengine - -package logrus - -import "io" - -// IsTerminal returns true if stderr's file descriptor is a terminal. -func IsTerminal(f io.Writer) bool { - return true -} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go deleted file mode 100644 index 5f6be4d3c..000000000 --- a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build darwin freebsd openbsd netbsd dragonfly -// +build !appengine - -package logrus - -import "syscall" - -const ioctlReadTermios = syscall.TIOCGETA - -type Termios syscall.Termios diff --git a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go deleted file mode 100644 index 190297abf..000000000 --- a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go +++ /dev/null @@ -1,28 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 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 linux darwin freebsd openbsd netbsd dragonfly -// +build !appengine - -package logrus - -import ( - "io" - "os" - "syscall" - "unsafe" -) - -// IsTerminal returns true if stderr's file descriptor is a terminal. -func IsTerminal(f io.Writer) bool { - var termios Termios - switch v := f.(type) { - case *os.File: - _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) - return err == 0 - default: - return false - } -} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go deleted file mode 100644 index 3c86b1abe..000000000 --- a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go +++ /dev/null @@ -1,21 +0,0 @@ -// +build solaris,!appengine - -package logrus - -import ( - "io" - "os" - - "golang.org/x/sys/unix" -) - -// IsTerminal returns true if the given file descriptor is a terminal. -func IsTerminal(f io.Writer) bool { - switch v := f.(type) { - case *os.File: - _, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA) - return err == nil - default: - return false - } -} diff --git a/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/github.com/Sirupsen/logrus/terminal_windows.go deleted file mode 100644 index 05d2f91f1..000000000 --- a/vendor/github.com/Sirupsen/logrus/terminal_windows.go +++ /dev/null @@ -1,33 +0,0 @@ -// Based on ssh/terminal: -// Copyright 2011 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 windows,!appengine - -package logrus - -import ( - "io" - "os" - "syscall" - "unsafe" -) - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var ( - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") -) - -// IsTerminal returns true if stderr's file descriptor is a terminal. -func IsTerminal(f io.Writer) bool { - switch v := f.(type) { - case *os.File: - var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 - default: - return false - } -} diff --git a/vendor/github.com/containerd/containerd/reference/reference.go b/vendor/github.com/containerd/containerd/reference/reference.go index d31dff523..55c43b881 100644 --- a/vendor/github.com/containerd/containerd/reference/reference.go +++ b/vendor/github.com/containerd/containerd/reference/reference.go @@ -12,8 +12,11 @@ import ( ) var ( - ErrInvalid = errors.New("invalid reference") - ErrObjectRequired = errors.New("object required") + // ErrInvalid is returned when there is an invalid reference + ErrInvalid = errors.New("invalid reference") + // ErrObjectRequired is returned when the object is required + ErrObjectRequired = errors.New("object required") + // ErrHostnameRequired is returned when the hostname is required ErrHostnameRequired = errors.New("hostname required") ) @@ -138,7 +141,6 @@ func SplitObject(obj string) (tag string, dgst digest.Digest) { parts := strings.SplitAfterN(obj, "@", 2) if len(parts) < 2 { return parts[0], "" - } else { - return parts[0], digest.Digest(parts[1]) } + return parts[0], digest.Digest(parts[1]) } diff --git a/vendor/github.com/containerd/containerd/vendor.conf b/vendor/github.com/containerd/containerd/vendor.conf index abb7383d5..725f94a54 100644 --- a/vendor/github.com/containerd/containerd/vendor.conf +++ b/vendor/github.com/containerd/containerd/vendor.conf @@ -1,7 +1,7 @@ github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6 -github.com/containerd/go-runc b3c048c028ddd789c6f9510c597f8b9c62f25359 -github.com/containerd/console b28c739c79ce69d017e3691ad3664568d68e95c6 -github.com/containerd/cgroups 5933ab4dc4f7caa3a73a1dc141bd11f42b5c9163 +github.com/containerd/go-runc 633fd07c086ff591adaa2849278764771d791f6f +github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e +github.com/containerd/cgroups 9c238e632e80d94f71a067c3deb9b34b1886ef18 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 @@ -16,7 +16,7 @@ github.com/docker/go-units v0.3.1 github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8 github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55 github.com/opencontainers/runtime-spec v1.0.0 -github.com/opencontainers/runc 593914b8bd5448a93f7c3e4902a03408b6d5c0ce +github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d github.com/sirupsen/logrus v1.0.0 github.com/containerd/btrfs cc52c4dea2ce11a44e6639e561bb5c2af9ada9e3 github.com/stretchr/testify v1.1.4 @@ -28,7 +28,7 @@ golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 google.golang.org/grpc v1.3.0 github.com/pkg/errors v0.8.0 github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 -golang.org/x/sys 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce https://github.com/golang/sys +golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993 https://github.com/golang/sys github.com/opencontainers/image-spec v1.0.0 github.com/containerd/continuity cf279e6ac893682272b4479d4c67fd3abf878b4e golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c @@ -38,7 +38,6 @@ github.com/Microsoft/go-winio v0.4.4 github.com/Microsoft/hcsshim v0.6.3 github.com/Microsoft/opengcs v0.3.2 github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd -github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 github.com/dmcgowan/go-tar 2e2c51242e8993c50445dab7c03c8e7febddd0cf diff --git a/vendor/github.com/docker/distribution/README.md b/vendor/github.com/docker/distribution/README.md index a6e8db0fb..998878850 100644 --- a/vendor/github.com/docker/distribution/README.md +++ b/vendor/github.com/docker/distribution/README.md @@ -76,8 +76,7 @@ may be the better choice. For those who have previously deployed their own registry based on the Registry 1.0 implementation and wish to deploy a Registry 2.0 while retaining images, data migration is required. A tool to assist with migration efforts has been -created. For more information see [docker/migrator] -(https://github.com/docker/migrator). +created. For more information see [docker/migrator](https://github.com/docker/migrator). ## Contribute diff --git a/vendor/github.com/docker/distribution/blobs.go b/vendor/github.com/docker/distribution/blobs.go index 79c5fb33b..145b07853 100644 --- a/vendor/github.com/docker/distribution/blobs.go +++ b/vendor/github.com/docker/distribution/blobs.go @@ -1,13 +1,13 @@ package distribution import ( + "context" "errors" "fmt" "io" "net/http" "time" - "github.com/docker/distribution/context" "github.com/docker/distribution/reference" "github.com/opencontainers/go-digest" ) @@ -152,7 +152,7 @@ type BlobProvider interface { // BlobServer can serve blobs via http. type BlobServer interface { - // ServeBlob attempts to serve the blob, identifed by dgst, via http. The + // ServeBlob attempts to serve the blob, identified by dgst, via http. The // service may decide to redirect the client elsewhere or serve the data // directly. // diff --git a/vendor/github.com/docker/distribution/context/context.go b/vendor/github.com/docker/distribution/context/context.go deleted file mode 100644 index 23cbf5b54..000000000 --- a/vendor/github.com/docker/distribution/context/context.go +++ /dev/null @@ -1,85 +0,0 @@ -package context - -import ( - "sync" - - "github.com/docker/distribution/uuid" - "golang.org/x/net/context" -) - -// Context is a copy of Context from the golang.org/x/net/context package. -type Context interface { - context.Context -} - -// instanceContext is a context that provides only an instance id. It is -// provided as the main background context. -type instanceContext struct { - Context - id string // id of context, logged as "instance.id" - once sync.Once // once protect generation of the id -} - -func (ic *instanceContext) Value(key interface{}) interface{} { - if key == "instance.id" { - ic.once.Do(func() { - // We want to lazy initialize the UUID such that we don't - // call a random generator from the package initialization - // code. For various reasons random could not be available - // https://github.com/docker/distribution/issues/782 - ic.id = uuid.Generate().String() - }) - return ic.id - } - - return ic.Context.Value(key) -} - -var background = &instanceContext{ - Context: context.Background(), -} - -// Background returns a non-nil, empty Context. The background context -// provides a single key, "instance.id" that is globally unique to the -// process. -func Background() Context { - return background -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. Use context Values only for request-scoped data that transits processes -// and APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key, val interface{}) Context { - return context.WithValue(parent, key, val) -} - -// stringMapContext is a simple context implementation that checks a map for a -// key, falling back to a parent if not present. -type stringMapContext struct { - context.Context - m map[string]interface{} -} - -// WithValues returns a context that proxies lookups through a map. Only -// supports string keys. -func WithValues(ctx context.Context, m map[string]interface{}) context.Context { - mo := make(map[string]interface{}, len(m)) // make our own copy. - for k, v := range m { - mo[k] = v - } - - return stringMapContext{ - Context: ctx, - m: mo, - } -} - -func (smc stringMapContext) Value(key interface{}) interface{} { - if ks, ok := key.(string); ok { - if v, ok := smc.m[ks]; ok { - return v - } - } - - return smc.Context.Value(key) -} diff --git a/vendor/github.com/docker/distribution/context/doc.go b/vendor/github.com/docker/distribution/context/doc.go deleted file mode 100644 index 3b4ab8882..000000000 --- a/vendor/github.com/docker/distribution/context/doc.go +++ /dev/null @@ -1,89 +0,0 @@ -// Package context provides several utilities for working with -// golang.org/x/net/context in http requests. Primarily, the focus is on -// logging relevant request information but this package is not limited to -// that purpose. -// -// The easiest way to get started is to get the background context: -// -// ctx := context.Background() -// -// The returned context should be passed around your application and be the -// root of all other context instances. If the application has a version, this -// line should be called before anything else: -// -// ctx := context.WithVersion(context.Background(), version) -// -// The above will store the version in the context and will be available to -// the logger. -// -// Logging -// -// The most useful aspect of this package is GetLogger. This function takes -// any context.Context interface and returns the current logger from the -// context. Canonical usage looks like this: -// -// GetLogger(ctx).Infof("something interesting happened") -// -// GetLogger also takes optional key arguments. The keys will be looked up in -// the context and reported with the logger. The following example would -// return a logger that prints the version with each log message: -// -// ctx := context.Context(context.Background(), "version", version) -// GetLogger(ctx, "version").Infof("this log message has a version field") -// -// The above would print out a log message like this: -// -// INFO[0000] this log message has a version field version=v2.0.0-alpha.2.m -// -// When used with WithLogger, we gain the ability to decorate the context with -// loggers that have information from disparate parts of the call stack. -// Following from the version example, we can build a new context with the -// configured logger such that we always print the version field: -// -// ctx = WithLogger(ctx, GetLogger(ctx, "version")) -// -// Since the logger has been pushed to the context, we can now get the version -// field for free with our log messages. Future calls to GetLogger on the new -// context will have the version field: -// -// GetLogger(ctx).Infof("this log message has a version field") -// -// This becomes more powerful when we start stacking loggers. Let's say we -// have the version logger from above but also want a request id. Using the -// context above, in our request scoped function, we place another logger in -// the context: -// -// ctx = context.WithValue(ctx, "http.request.id", "unique id") // called when building request context -// ctx = WithLogger(ctx, GetLogger(ctx, "http.request.id")) -// -// When GetLogger is called on the new context, "http.request.id" will be -// included as a logger field, along with the original "version" field: -// -// INFO[0000] this log message has a version field http.request.id=unique id version=v2.0.0-alpha.2.m -// -// Note that this only affects the new context, the previous context, with the -// version field, can be used independently. Put another way, the new logger, -// added to the request context, is unique to that context and can have -// request scoped varaibles. -// -// HTTP Requests -// -// This package also contains several methods for working with http requests. -// The concepts are very similar to those described above. We simply place the -// request in the context using WithRequest. This makes the request variables -// available. GetRequestLogger can then be called to get request specific -// variables in a log line: -// -// ctx = WithRequest(ctx, req) -// GetRequestLogger(ctx).Infof("request variables") -// -// Like above, if we want to include the request data in all log messages in -// the context, we push the logger to a new context and use that one: -// -// ctx = WithLogger(ctx, GetRequestLogger(ctx)) -// -// The concept is fairly powerful and ensures that calls throughout the stack -// can be traced in log messages. Using the fields like "http.request.id", one -// can analyze call flow for a particular request with a simple grep of the -// logs. -package context diff --git a/vendor/github.com/docker/distribution/context/http.go b/vendor/github.com/docker/distribution/context/http.go deleted file mode 100644 index 7fe9b8ab0..000000000 --- a/vendor/github.com/docker/distribution/context/http.go +++ /dev/null @@ -1,366 +0,0 @@ -package context - -import ( - "errors" - "net" - "net/http" - "strings" - "sync" - "time" - - log "github.com/Sirupsen/logrus" - "github.com/docker/distribution/uuid" - "github.com/gorilla/mux" -) - -// Common errors used with this package. -var ( - ErrNoRequestContext = errors.New("no http request in context") - ErrNoResponseWriterContext = errors.New("no http response in context") -) - -func parseIP(ipStr string) net.IP { - ip := net.ParseIP(ipStr) - if ip == nil { - log.Warnf("invalid remote IP address: %q", ipStr) - } - return ip -} - -// RemoteAddr extracts the remote address of the request, taking into -// account proxy headers. -func RemoteAddr(r *http.Request) string { - if prior := r.Header.Get("X-Forwarded-For"); prior != "" { - proxies := strings.Split(prior, ",") - if len(proxies) > 0 { - remoteAddr := strings.Trim(proxies[0], " ") - if parseIP(remoteAddr) != nil { - return remoteAddr - } - } - } - // X-Real-Ip is less supported, but worth checking in the - // absence of X-Forwarded-For - if realIP := r.Header.Get("X-Real-Ip"); realIP != "" { - if parseIP(realIP) != nil { - return realIP - } - } - - return r.RemoteAddr -} - -// RemoteIP extracts the remote IP of the request, taking into -// account proxy headers. -func RemoteIP(r *http.Request) string { - addr := RemoteAddr(r) - - // Try parsing it as "IP:port" - if ip, _, err := net.SplitHostPort(addr); err == nil { - return ip - } - - return addr -} - -// WithRequest places the request on the context. The context of the request -// is assigned a unique id, available at "http.request.id". The request itself -// is available at "http.request". Other common attributes are available under -// the prefix "http.request.". If a request is already present on the context, -// this method will panic. -func WithRequest(ctx Context, r *http.Request) Context { - if ctx.Value("http.request") != nil { - // NOTE(stevvooe): This needs to be considered a programming error. It - // is unlikely that we'd want to have more than one request in - // context. - panic("only one request per context") - } - - return &httpRequestContext{ - Context: ctx, - startedAt: time.Now(), - id: uuid.Generate().String(), - r: r, - } -} - -// GetRequest returns the http request in the given context. Returns -// ErrNoRequestContext if the context does not have an http request associated -// with it. -func GetRequest(ctx Context) (*http.Request, error) { - if r, ok := ctx.Value("http.request").(*http.Request); r != nil && ok { - return r, nil - } - return nil, ErrNoRequestContext -} - -// GetRequestID attempts to resolve the current request id, if possible. An -// error is return if it is not available on the context. -func GetRequestID(ctx Context) string { - return GetStringValue(ctx, "http.request.id") -} - -// WithResponseWriter returns a new context and response writer that makes -// interesting response statistics available within the context. -func WithResponseWriter(ctx Context, w http.ResponseWriter) (Context, http.ResponseWriter) { - if closeNotifier, ok := w.(http.CloseNotifier); ok { - irwCN := &instrumentedResponseWriterCN{ - instrumentedResponseWriter: instrumentedResponseWriter{ - ResponseWriter: w, - Context: ctx, - }, - CloseNotifier: closeNotifier, - } - - return irwCN, irwCN - } - - irw := instrumentedResponseWriter{ - ResponseWriter: w, - Context: ctx, - } - return &irw, &irw -} - -// GetResponseWriter returns the http.ResponseWriter from the provided -// context. If not present, ErrNoResponseWriterContext is returned. The -// returned instance provides instrumentation in the context. -func GetResponseWriter(ctx Context) (http.ResponseWriter, error) { - v := ctx.Value("http.response") - - rw, ok := v.(http.ResponseWriter) - if !ok || rw == nil { - return nil, ErrNoResponseWriterContext - } - - return rw, nil -} - -// getVarsFromRequest let's us change request vars implementation for testing -// and maybe future changes. -var getVarsFromRequest = mux.Vars - -// WithVars extracts gorilla/mux vars and makes them available on the returned -// context. Variables are available at keys with the prefix "vars.". For -// example, if looking for the variable "name", it can be accessed as -// "vars.name". Implementations that are accessing values need not know that -// the underlying context is implemented with gorilla/mux vars. -func WithVars(ctx Context, r *http.Request) Context { - return &muxVarsContext{ - Context: ctx, - vars: getVarsFromRequest(r), - } -} - -// GetRequestLogger returns a logger that contains fields from the request in -// the current context. If the request is not available in the context, no -// fields will display. Request loggers can safely be pushed onto the context. -func GetRequestLogger(ctx Context) Logger { - return GetLogger(ctx, - "http.request.id", - "http.request.method", - "http.request.host", - "http.request.uri", - "http.request.referer", - "http.request.useragent", - "http.request.remoteaddr", - "http.request.contenttype") -} - -// GetResponseLogger reads the current response stats and builds a logger. -// Because the values are read at call time, pushing a logger returned from -// this function on the context will lead to missing or invalid data. Only -// call this at the end of a request, after the response has been written. -func GetResponseLogger(ctx Context) Logger { - l := getLogrusLogger(ctx, - "http.response.written", - "http.response.status", - "http.response.contenttype") - - duration := Since(ctx, "http.request.startedat") - - if duration > 0 { - l = l.WithField("http.response.duration", duration.String()) - } - - return l -} - -// httpRequestContext makes information about a request available to context. -type httpRequestContext struct { - Context - - startedAt time.Time - id string - r *http.Request -} - -// Value returns a keyed element of the request for use in the context. To get -// the request itself, query "request". For other components, access them as -// "request.". For example, r.RequestURI -func (ctx *httpRequestContext) Value(key interface{}) interface{} { - if keyStr, ok := key.(string); ok { - if keyStr == "http.request" { - return ctx.r - } - - if !strings.HasPrefix(keyStr, "http.request.") { - goto fallback - } - - parts := strings.Split(keyStr, ".") - - if len(parts) != 3 { - goto fallback - } - - switch parts[2] { - case "uri": - return ctx.r.RequestURI - case "remoteaddr": - return RemoteAddr(ctx.r) - case "method": - return ctx.r.Method - case "host": - return ctx.r.Host - case "referer": - referer := ctx.r.Referer() - if referer != "" { - return referer - } - case "useragent": - return ctx.r.UserAgent() - case "id": - return ctx.id - case "startedat": - return ctx.startedAt - case "contenttype": - ct := ctx.r.Header.Get("Content-Type") - if ct != "" { - return ct - } - } - } - -fallback: - return ctx.Context.Value(key) -} - -type muxVarsContext struct { - Context - vars map[string]string -} - -func (ctx *muxVarsContext) Value(key interface{}) interface{} { - if keyStr, ok := key.(string); ok { - if keyStr == "vars" { - return ctx.vars - } - - if strings.HasPrefix(keyStr, "vars.") { - keyStr = strings.TrimPrefix(keyStr, "vars.") - } - - if v, ok := ctx.vars[keyStr]; ok { - return v - } - } - - return ctx.Context.Value(key) -} - -// instrumentedResponseWriterCN provides response writer information in a -// context. It implements http.CloseNotifier so that users can detect -// early disconnects. -type instrumentedResponseWriterCN struct { - instrumentedResponseWriter - http.CloseNotifier -} - -// instrumentedResponseWriter provides response writer information in a -// context. This variant is only used in the case where CloseNotifier is not -// implemented by the parent ResponseWriter. -type instrumentedResponseWriter struct { - http.ResponseWriter - Context - - mu sync.Mutex - status int - written int64 -} - -func (irw *instrumentedResponseWriter) Write(p []byte) (n int, err error) { - n, err = irw.ResponseWriter.Write(p) - - irw.mu.Lock() - irw.written += int64(n) - - // Guess the likely status if not set. - if irw.status == 0 { - irw.status = http.StatusOK - } - - irw.mu.Unlock() - - return -} - -func (irw *instrumentedResponseWriter) WriteHeader(status int) { - irw.ResponseWriter.WriteHeader(status) - - irw.mu.Lock() - irw.status = status - irw.mu.Unlock() -} - -func (irw *instrumentedResponseWriter) Flush() { - if flusher, ok := irw.ResponseWriter.(http.Flusher); ok { - flusher.Flush() - } -} - -func (irw *instrumentedResponseWriter) Value(key interface{}) interface{} { - if keyStr, ok := key.(string); ok { - if keyStr == "http.response" { - return irw - } - - if !strings.HasPrefix(keyStr, "http.response.") { - goto fallback - } - - parts := strings.Split(keyStr, ".") - - if len(parts) != 3 { - goto fallback - } - - irw.mu.Lock() - defer irw.mu.Unlock() - - switch parts[2] { - case "written": - return irw.written - case "status": - return irw.status - case "contenttype": - contentType := irw.Header().Get("Content-Type") - if contentType != "" { - return contentType - } - } - } - -fallback: - return irw.Context.Value(key) -} - -func (irw *instrumentedResponseWriterCN) Value(key interface{}) interface{} { - if keyStr, ok := key.(string); ok { - if keyStr == "http.response" { - return irw - } - } - - return irw.instrumentedResponseWriter.Value(key) -} diff --git a/vendor/github.com/docker/distribution/context/logger.go b/vendor/github.com/docker/distribution/context/logger.go deleted file mode 100644 index fbb6a0511..000000000 --- a/vendor/github.com/docker/distribution/context/logger.go +++ /dev/null @@ -1,116 +0,0 @@ -package context - -import ( - "fmt" - - "github.com/Sirupsen/logrus" - "runtime" -) - -// Logger provides a leveled-logging interface. -type Logger interface { - // standard logger methods - Print(args ...interface{}) - Printf(format string, args ...interface{}) - Println(args ...interface{}) - - Fatal(args ...interface{}) - Fatalf(format string, args ...interface{}) - Fatalln(args ...interface{}) - - Panic(args ...interface{}) - Panicf(format string, args ...interface{}) - Panicln(args ...interface{}) - - // Leveled methods, from logrus - Debug(args ...interface{}) - Debugf(format string, args ...interface{}) - Debugln(args ...interface{}) - - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - Errorln(args ...interface{}) - - Info(args ...interface{}) - Infof(format string, args ...interface{}) - Infoln(args ...interface{}) - - Warn(args ...interface{}) - Warnf(format string, args ...interface{}) - Warnln(args ...interface{}) -} - -// WithLogger creates a new context with provided logger. -func WithLogger(ctx Context, logger Logger) Context { - return WithValue(ctx, "logger", logger) -} - -// GetLoggerWithField returns a logger instance with the specified field key -// and value without affecting the context. Extra specified keys will be -// resolved from the context. -func GetLoggerWithField(ctx Context, key, value interface{}, keys ...interface{}) Logger { - return getLogrusLogger(ctx, keys...).WithField(fmt.Sprint(key), value) -} - -// GetLoggerWithFields returns a logger instance with the specified fields -// without affecting the context. Extra specified keys will be resolved from -// the context. -func GetLoggerWithFields(ctx Context, fields map[interface{}]interface{}, keys ...interface{}) Logger { - // must convert from interface{} -> interface{} to string -> interface{} for logrus. - lfields := make(logrus.Fields, len(fields)) - for key, value := range fields { - lfields[fmt.Sprint(key)] = value - } - - return getLogrusLogger(ctx, keys...).WithFields(lfields) -} - -// GetLogger returns the logger from the current context, if present. If one -// or more keys are provided, they will be resolved on the context and -// included in the logger. While context.Value takes an interface, any key -// argument passed to GetLogger will be passed to fmt.Sprint when expanded as -// a logging key field. If context keys are integer constants, for example, -// its recommended that a String method is implemented. -func GetLogger(ctx Context, keys ...interface{}) Logger { - return getLogrusLogger(ctx, keys...) -} - -// GetLogrusLogger returns the logrus logger for the context. If one more keys -// are provided, they will be resolved on the context and included in the -// logger. Only use this function if specific logrus functionality is -// required. -func getLogrusLogger(ctx Context, keys ...interface{}) *logrus.Entry { - var logger *logrus.Entry - - // Get a logger, if it is present. - loggerInterface := ctx.Value("logger") - if loggerInterface != nil { - if lgr, ok := loggerInterface.(*logrus.Entry); ok { - logger = lgr - } - } - - if logger == nil { - fields := logrus.Fields{} - - // Fill in the instance id, if we have it. - instanceID := ctx.Value("instance.id") - if instanceID != nil { - fields["instance.id"] = instanceID - } - - fields["go.version"] = runtime.Version() - // If no logger is found, just return the standard logger. - logger = logrus.StandardLogger().WithFields(fields) - } - - fields := logrus.Fields{} - for _, key := range keys { - v := ctx.Value(key) - if v != nil { - fields[fmt.Sprint(key)] = v - } - } - - return logger.WithFields(fields) -} diff --git a/vendor/github.com/docker/distribution/context/trace.go b/vendor/github.com/docker/distribution/context/trace.go deleted file mode 100644 index 721964a84..000000000 --- a/vendor/github.com/docker/distribution/context/trace.go +++ /dev/null @@ -1,104 +0,0 @@ -package context - -import ( - "runtime" - "time" - - "github.com/docker/distribution/uuid" -) - -// WithTrace allocates a traced timing span in a new context. This allows a -// caller to track the time between calling WithTrace and the returned done -// function. When the done function is called, a log message is emitted with a -// "trace.duration" field, corresponding to the elapsed time and a -// "trace.func" field, corresponding to the function that called WithTrace. -// -// The logging keys "trace.id" and "trace.parent.id" are provided to implement -// dapper-like tracing. This function should be complemented with a WithSpan -// method that could be used for tracing distributed RPC calls. -// -// The main benefit of this function is to post-process log messages or -// intercept them in a hook to provide timing data. Trace ids and parent ids -// can also be linked to provide call tracing, if so required. -// -// Here is an example of the usage: -// -// func timedOperation(ctx Context) { -// ctx, done := WithTrace(ctx) -// defer done("this will be the log message") -// // ... function body ... -// } -// -// If the function ran for roughly 1s, such a usage would emit a log message -// as follows: -// -// INFO[0001] this will be the log message trace.duration=1.004575763s trace.func=github.com/docker/distribution/context.traceOperation trace.id= ... -// -// Notice that the function name is automatically resolved, along with the -// package and a trace id is emitted that can be linked with parent ids. -func WithTrace(ctx Context) (Context, func(format string, a ...interface{})) { - if ctx == nil { - ctx = Background() - } - - pc, file, line, _ := runtime.Caller(1) - f := runtime.FuncForPC(pc) - ctx = &traced{ - Context: ctx, - id: uuid.Generate().String(), - start: time.Now(), - parent: GetStringValue(ctx, "trace.id"), - fnname: f.Name(), - file: file, - line: line, - } - - return ctx, func(format string, a ...interface{}) { - GetLogger(ctx, - "trace.duration", - "trace.id", - "trace.parent.id", - "trace.func", - "trace.file", - "trace.line"). - Debugf(format, a...) - } -} - -// traced represents a context that is traced for function call timing. It -// also provides fast lookup for the various attributes that are available on -// the trace. -type traced struct { - Context - id string - parent string - start time.Time - fnname string - file string - line int -} - -func (ts *traced) Value(key interface{}) interface{} { - switch key { - case "trace.start": - return ts.start - case "trace.duration": - return time.Since(ts.start) - case "trace.id": - return ts.id - case "trace.parent.id": - if ts.parent == "" { - return nil // must return nil to signal no parent. - } - - return ts.parent - case "trace.func": - return ts.fnname - case "trace.file": - return ts.file - case "trace.line": - return ts.line - } - - return ts.Context.Value(key) -} diff --git a/vendor/github.com/docker/distribution/context/util.go b/vendor/github.com/docker/distribution/context/util.go deleted file mode 100644 index cb9ef52e3..000000000 --- a/vendor/github.com/docker/distribution/context/util.go +++ /dev/null @@ -1,24 +0,0 @@ -package context - -import ( - "time" -) - -// Since looks up key, which should be a time.Time, and returns the duration -// since that time. If the key is not found, the value returned will be zero. -// This is helpful when inferring metrics related to context execution times. -func Since(ctx Context, key interface{}) time.Duration { - if startedAt, ok := ctx.Value(key).(time.Time); ok { - return time.Since(startedAt) - } - return 0 -} - -// GetStringValue returns a string value from the context. The empty string -// will be returned if not found. -func GetStringValue(ctx Context, key interface{}) (value string) { - if valuev, ok := ctx.Value(key).(string); ok { - value = valuev - } - return value -} diff --git a/vendor/github.com/docker/distribution/context/version.go b/vendor/github.com/docker/distribution/context/version.go deleted file mode 100644 index 746cda02e..000000000 --- a/vendor/github.com/docker/distribution/context/version.go +++ /dev/null @@ -1,16 +0,0 @@ -package context - -// WithVersion stores the application version in the context. The new context -// gets a logger to ensure log messages are marked with the application -// version. -func WithVersion(ctx Context, version string) Context { - ctx = WithValue(ctx, "version", version) - // push a new logger onto the stack - return WithLogger(ctx, GetLogger(ctx, "version")) -} - -// GetVersion returns the application version from the context. An empty -// string may returned if the version was not set on the context. -func GetVersion(ctx Context) string { - return GetStringValue(ctx, "version") -} diff --git a/vendor/github.com/docker/distribution/errors.go b/vendor/github.com/docker/distribution/errors.go index 2062a06fb..020d33258 100644 --- a/vendor/github.com/docker/distribution/errors.go +++ b/vendor/github.com/docker/distribution/errors.go @@ -77,7 +77,7 @@ func (err ErrManifestUnknownRevision) Error() string { type ErrManifestUnverified struct{} func (ErrManifestUnverified) Error() string { - return fmt.Sprintf("unverified manifest") + return "unverified manifest" } // ErrManifestVerification provides a type to collect errors encountered diff --git a/vendor/github.com/docker/distribution/manifests.go b/vendor/github.com/docker/distribution/manifests.go index 2c99f25d3..1816baea1 100644 --- a/vendor/github.com/docker/distribution/manifests.go +++ b/vendor/github.com/docker/distribution/manifests.go @@ -1,10 +1,10 @@ package distribution import ( + "context" "fmt" "mime" - "github.com/docker/distribution/context" "github.com/opencontainers/go-digest" ) diff --git a/vendor/github.com/docker/distribution/reference/reference.go b/vendor/github.com/docker/distribution/reference/reference.go index fd3510e9e..2f66cca87 100644 --- a/vendor/github.com/docker/distribution/reference/reference.go +++ b/vendor/github.com/docker/distribution/reference/reference.go @@ -15,7 +15,7 @@ // tag := /[\w][\w.-]{0,127}/ // // digest := digest-algorithm ":" digest-hex -// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ] +// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* // digest-algorithm-separator := /[+.-_]/ // digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ // digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value diff --git a/vendor/github.com/docker/distribution/registry.go b/vendor/github.com/docker/distribution/registry.go index 1da1d533f..a3a80ab88 100644 --- a/vendor/github.com/docker/distribution/registry.go +++ b/vendor/github.com/docker/distribution/registry.go @@ -1,7 +1,8 @@ package distribution import ( - "github.com/docker/distribution/context" + "context" + "github.com/docker/distribution/reference" ) @@ -72,6 +73,21 @@ func (o WithTagOption) Apply(m ManifestService) error { return nil } +// WithManifestMediaTypes lists the media types the client wishes +// the server to provide. +func WithManifestMediaTypes(mediaTypes []string) ManifestServiceOption { + return WithManifestMediaTypesOption{mediaTypes} +} + +// WithManifestMediaTypesOption holds a list of accepted media types +type WithManifestMediaTypesOption struct{ MediaTypes []string } + +// Apply conforms to the ManifestServiceOption interface +func (o WithManifestMediaTypesOption) Apply(m ManifestService) error { + // no implementation + return nil +} + // Repository is a named collection of manifests and layers. type Repository interface { // Named returns the name of the repository. diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/handler.go b/vendor/github.com/docker/distribution/registry/api/errcode/handler.go index 49a64a86e..d77e70473 100644 --- a/vendor/github.com/docker/distribution/registry/api/errcode/handler.go +++ b/vendor/github.com/docker/distribution/registry/api/errcode/handler.go @@ -36,9 +36,5 @@ func ServeJSON(w http.ResponseWriter, err error) error { w.WriteHeader(sc) - if err := json.NewEncoder(w).Encode(err); err != nil { - return err - } - - return nil + return json.NewEncoder(w).Encode(err) } diff --git a/vendor/github.com/docker/distribution/registry/api/v2/urls.go b/vendor/github.com/docker/distribution/registry/api/v2/urls.go index e2e242eab..1337bdb12 100644 --- a/vendor/github.com/docker/distribution/registry/api/v2/urls.go +++ b/vendor/github.com/docker/distribution/registry/api/v2/urls.go @@ -1,10 +1,9 @@ package v2 import ( - "net" + "fmt" "net/http" "net/url" - "strconv" "strings" "github.com/docker/distribution/reference" @@ -48,66 +47,42 @@ func NewURLBuilderFromString(root string, relative bool) (*URLBuilder, error) { // NewURLBuilderFromRequest uses information from an *http.Request to // construct the root url. func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder { - var scheme string - - forwardedProto := r.Header.Get("X-Forwarded-Proto") - // TODO: log the error - forwardedHeader, _, _ := parseForwardedHeader(r.Header.Get("Forwarded")) - - switch { - case len(forwardedProto) > 0: - scheme = forwardedProto - case len(forwardedHeader["proto"]) > 0: - scheme = forwardedHeader["proto"] - case r.TLS != nil: - scheme = "https" - case len(r.URL.Scheme) > 0: - scheme = r.URL.Scheme - default: + var ( scheme = "http" + host = r.Host + ) + + if r.TLS != nil { + scheme = "https" + } else if len(r.URL.Scheme) > 0 { + scheme = r.URL.Scheme } - host := r.Host - - if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 { - // According to the Apache mod_proxy docs, X-Forwarded-Host can be a - // comma-separated list of hosts, to which each proxy appends the - // requested host. We want to grab the first from this comma-separated - // list. - hosts := strings.SplitN(forwardedHost, ",", 2) - host = strings.TrimSpace(hosts[0]) - } else if addr, exists := forwardedHeader["for"]; exists { - host = addr - } else if h, exists := forwardedHeader["host"]; exists { - host = h - } - - portLessHost, port := host, "" - if !isIPv6Address(portLessHost) { - // with go 1.6, this would treat the last part of IPv6 address as a port - portLessHost, port, _ = net.SplitHostPort(host) - } - if forwardedPort := r.Header.Get("X-Forwarded-Port"); len(port) == 0 && len(forwardedPort) > 0 { - ports := strings.SplitN(forwardedPort, ",", 2) - forwardedPort = strings.TrimSpace(ports[0]) - if _, err := strconv.ParseInt(forwardedPort, 10, 32); err == nil { - port = forwardedPort + // Handle fowarded headers + // Prefer "Forwarded" header as defined by rfc7239 if given + // see https://tools.ietf.org/html/rfc7239 + if forwarded := r.Header.Get("Forwarded"); len(forwarded) > 0 { + forwardedHeader, _, err := parseForwardedHeader(forwarded) + if err == nil { + if fproto := forwardedHeader["proto"]; len(fproto) > 0 { + scheme = fproto + } + if fhost := forwardedHeader["host"]; len(fhost) > 0 { + host = fhost + } } - } - - if len(portLessHost) > 0 { - host = portLessHost - } - if len(port) > 0 { - // remove enclosing brackets of ipv6 address otherwise they will be duplicated - if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' { - host = host[1 : len(host)-1] + } else { + if forwardedProto := r.Header.Get("X-Forwarded-Proto"); len(forwardedProto) > 0 { + scheme = forwardedProto + } + if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 { + // According to the Apache mod_proxy docs, X-Forwarded-Host can be a + // comma-separated list of hosts, to which each proxy appends the + // requested host. We want to grab the first from this comma-separated + // list. + hosts := strings.SplitN(forwardedHost, ",", 2) + host = strings.TrimSpace(hosts[0]) } - // JoinHostPort properly encloses ipv6 addresses in square brackets - host = net.JoinHostPort(host, port) - } else if isIPv6Address(host) && host[0] != '[' { - // ipv6 needs to be enclosed in square brackets in urls - host = "[" + host + "]" } basePath := routeDescriptorsMap[RouteNameBase].Path @@ -175,6 +150,8 @@ func (ub *URLBuilder) BuildManifestURL(ref reference.Named) (string, error) { tagOrDigest = v.Tag() case reference.Digested: tagOrDigest = v.Digest().String() + default: + return "", fmt.Errorf("reference must have a tag or digest") } manifestURL, err := route.URL("name", ref.Name(), "reference", tagOrDigest) @@ -287,28 +264,3 @@ func appendValues(u string, values ...url.Values) string { return appendValuesURL(up, values...).String() } - -// isIPv6Address returns true if given string is a valid IPv6 address. No port is allowed. The address may be -// enclosed in square brackets. -func isIPv6Address(host string) bool { - if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' { - host = host[1 : len(host)-1] - } - // The IPv6 scoped addressing zone identifier starts after the last percent sign. - if i := strings.LastIndexByte(host, '%'); i > 0 { - host = host[:i] - } - ip := net.ParseIP(host) - if ip == nil { - return false - } - if ip.To16() == nil { - return false - } - if ip.To4() == nil { - return true - } - // dot can be present in ipv4-mapped address, it needs to come after a colon though - i := strings.IndexAny(host, ":.") - return i >= 0 && host[i] == ':' -} diff --git a/vendor/github.com/docker/distribution/registry/client/auth/session.go b/vendor/github.com/docker/distribution/registry/client/auth/session.go index 3ca5e8b3e..db86c9b06 100644 --- a/vendor/github.com/docker/distribution/registry/client/auth/session.go +++ b/vendor/github.com/docker/distribution/registry/client/auth/session.go @@ -10,7 +10,6 @@ import ( "sync" "time" - "github.com/Sirupsen/logrus" "github.com/docker/distribution/registry/client" "github.com/docker/distribution/registry/client/auth/challenge" "github.com/docker/distribution/registry/client/transport" @@ -135,6 +134,8 @@ type tokenHandler struct { tokenLock sync.Mutex tokenCache string tokenExpiration time.Time + + logger Logger } // Scope is a type which is serializable to a string @@ -176,6 +177,18 @@ func (rs RegistryScope) String() string { return fmt.Sprintf("registry:%s:%s", rs.Name, strings.Join(rs.Actions, ",")) } +// Logger defines the injectable logging interface, used on TokenHandlers. +type Logger interface { + Debugf(format string, args ...interface{}) +} + +func logDebugf(logger Logger, format string, args ...interface{}) { + if logger == nil { + return + } + logger.Debugf(format, args...) +} + // TokenHandlerOptions is used to configure a new token handler type TokenHandlerOptions struct { Transport http.RoundTripper @@ -185,6 +198,7 @@ type TokenHandlerOptions struct { ForceOAuth bool ClientID string Scopes []Scope + Logger Logger } // An implementation of clock for providing real time data. @@ -220,6 +234,7 @@ func NewTokenHandlerWithOptions(options TokenHandlerOptions) AuthenticationHandl clientID: options.ClientID, scopes: options.Scopes, clock: realClock{}, + logger: options.Logger, } return handler @@ -264,6 +279,9 @@ func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...s } var addedScopes bool for _, scope := range additionalScopes { + if hasScope(scopes, scope) { + continue + } scopes = append(scopes, scope) addedScopes = true } @@ -287,6 +305,15 @@ func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...s return th.tokenCache, nil } +func hasScope(scopes []string, scope string) bool { + for _, s := range scopes { + if s == scope { + return true + } + } + return false +} + type postTokenResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` @@ -348,7 +375,7 @@ func (th *tokenHandler) fetchTokenWithOAuth(realm *url.URL, refreshToken, servic if tr.ExpiresIn < minimumTokenLifetimeSeconds { // The default/minimum lifetime. tr.ExpiresIn = minimumTokenLifetimeSeconds - logrus.Debugf("Increasing token expiration to: %d seconds", tr.ExpiresIn) + logDebugf(th.logger, "Increasing token expiration to: %d seconds", tr.ExpiresIn) } if tr.IssuedAt.IsZero() { @@ -439,7 +466,7 @@ func (th *tokenHandler) fetchTokenWithBasicAuth(realm *url.URL, service string, if tr.ExpiresIn < minimumTokenLifetimeSeconds { // The default/minimum lifetime. tr.ExpiresIn = minimumTokenLifetimeSeconds - logrus.Debugf("Increasing token expiration to: %d seconds", tr.ExpiresIn) + logDebugf(th.logger, "Increasing token expiration to: %d seconds", tr.ExpiresIn) } if tr.IssuedAt.IsZero() { diff --git a/vendor/github.com/docker/distribution/registry/client/blob_writer.go b/vendor/github.com/docker/distribution/registry/client/blob_writer.go index e3ffcb00f..695bf852f 100644 --- a/vendor/github.com/docker/distribution/registry/client/blob_writer.go +++ b/vendor/github.com/docker/distribution/registry/client/blob_writer.go @@ -2,6 +2,7 @@ package client import ( "bytes" + "context" "fmt" "io" "io/ioutil" @@ -9,7 +10,6 @@ import ( "time" "github.com/docker/distribution" - "github.com/docker/distribution/context" ) type httpBlobUpload struct { diff --git a/vendor/github.com/docker/distribution/registry/client/repository.go b/vendor/github.com/docker/distribution/registry/client/repository.go index b82a968e2..ed29cf3f5 100644 --- a/vendor/github.com/docker/distribution/registry/client/repository.go +++ b/vendor/github.com/docker/distribution/registry/client/repository.go @@ -2,6 +2,7 @@ package client import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -14,7 +15,6 @@ import ( "time" "github.com/docker/distribution" - "github.com/docker/distribution/context" "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/registry/client/transport" @@ -62,7 +62,7 @@ func checkHTTPRedirect(req *http.Request, via []*http.Request) error { } // NewRegistry creates a registry namespace which can be used to get a listing of repositories -func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTripper) (Registry, error) { +func NewRegistry(baseURL string, transport http.RoundTripper) (Registry, error) { ub, err := v2.NewURLBuilderFromString(baseURL, false) if err != nil { return nil, err @@ -75,9 +75,8 @@ func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTrippe } return ®istry{ - client: client, - ub: ub, - context: ctx, + client: client, + ub: ub, }, nil } @@ -133,7 +132,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri } // NewRepository creates a new Repository for the given repository name and base URL. -func NewRepository(ctx context.Context, name reference.Named, baseURL string, transport http.RoundTripper) (distribution.Repository, error) { +func NewRepository(name reference.Named, baseURL string, transport http.RoundTripper) (distribution.Repository, error) { ub, err := v2.NewURLBuilderFromString(baseURL, false) if err != nil { return nil, err @@ -146,10 +145,9 @@ func NewRepository(ctx context.Context, name reference.Named, baseURL string, tr } return &repository{ - client: client, - ub: ub, - name: name, - context: ctx, + client: client, + ub: ub, + name: name, }, nil } @@ -190,19 +188,17 @@ func (r *repository) Manifests(ctx context.Context, options ...distribution.Mani func (r *repository) Tags(ctx context.Context) distribution.TagService { return &tags{ - client: r.client, - ub: r.ub, - context: r.context, - name: r.Named(), + client: r.client, + ub: r.ub, + name: r.Named(), } } // tags implements remote tagging operations. type tags struct { - client *http.Client - ub *v2.URLBuilder - context context.Context - name reference.Named + client *http.Client + ub *v2.URLBuilder + name reference.Named } // All returns all tags @@ -321,7 +317,8 @@ func (t *tags) Get(ctx context.Context, tag string) (distribution.Descriptor, er defer resp.Body.Close() switch { - case resp.StatusCode >= 200 && resp.StatusCode < 400: + case resp.StatusCode >= 200 && resp.StatusCode < 400 && len(resp.Header.Get("Docker-Content-Digest")) > 0: + // if the response is a success AND a Docker-Content-Digest can be retrieved from the headers return descriptorFromResponse(resp) default: // if the response is an error - there will be no body to decode. @@ -421,18 +418,22 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis ref reference.Named err error contentDgst *digest.Digest + mediaTypes []string ) for _, option := range options { - if opt, ok := option.(distribution.WithTagOption); ok { + switch opt := option.(type) { + case distribution.WithTagOption: digestOrTag = opt.Tag ref, err = reference.WithTag(ms.name, opt.Tag) if err != nil { return nil, err } - } else if opt, ok := option.(contentDigestOption); ok { + case contentDigestOption: contentDgst = opt.digest - } else { + case distribution.WithManifestMediaTypesOption: + mediaTypes = opt.MediaTypes + default: err := option.Apply(ms) if err != nil { return nil, err @@ -448,6 +449,10 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis } } + if len(mediaTypes) == 0 { + mediaTypes = distribution.ManifestMediaTypes() + } + u, err := ms.ub.BuildManifestURL(ref) if err != nil { return nil, err @@ -458,7 +463,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis return nil, err } - for _, t := range distribution.ManifestMediaTypes() { + for _, t := range mediaTypes { req.Header.Add("Accept", t) } diff --git a/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go b/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go index f647616bc..cdc34f5fe 100644 --- a/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go +++ b/vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go @@ -1,10 +1,10 @@ package cache import ( - "github.com/docker/distribution/context" - "github.com/opencontainers/go-digest" + "context" "github.com/docker/distribution" + "github.com/opencontainers/go-digest" ) // Metrics is used to hold metric counters @@ -16,12 +16,20 @@ type Metrics struct { Misses uint64 } +// Logger can be provided on the MetricsTracker to log errors. +// +// Usually, this is just a proxy to dcontext.GetLogger. +type Logger interface { + Errorf(format string, args ...interface{}) +} + // MetricsTracker represents a metric tracker // which simply counts the number of hits and misses. type MetricsTracker interface { Hit() Miss() Metrics() Metrics + Logger(context.Context) Logger } type cachedBlobStatter struct { @@ -53,7 +61,7 @@ func (cbds *cachedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (di desc, err := cbds.cache.Stat(ctx, dgst) if err != nil { if err != distribution.ErrBlobUnknown { - context.GetLogger(ctx).Errorf("error retrieving descriptor from cache: %v", err) + logErrorf(ctx, cbds.tracker, "error retrieving descriptor from cache: %v", err) } goto fallback @@ -73,7 +81,7 @@ fallback: } if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil { - context.GetLogger(ctx).Errorf("error adding descriptor %v to cache: %v", desc.Digest, err) + logErrorf(ctx, cbds.tracker, "error adding descriptor %v to cache: %v", desc.Digest, err) } return desc, err @@ -95,7 +103,19 @@ func (cbds *cachedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) er func (cbds *cachedBlobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil { - context.GetLogger(ctx).Errorf("error adding descriptor %v to cache: %v", desc.Digest, err) + logErrorf(ctx, cbds.tracker, "error adding descriptor %v to cache: %v", desc.Digest, err) } return nil } + +func logErrorf(ctx context.Context, tracker MetricsTracker, format string, args ...interface{}) { + if tracker == nil { + return + } + + logger := tracker.Logger(ctx) + if logger == nil { + return + } + logger.Errorf(format, args...) +} diff --git a/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go b/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go index b2fcaf4e8..42d94d9bd 100644 --- a/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go +++ b/vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go @@ -1,10 +1,10 @@ package memory import ( + "context" "sync" "github.com/docker/distribution" - "github.com/docker/distribution/context" "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/storage/cache" "github.com/opencontainers/go-digest" diff --git a/vendor/github.com/docker/distribution/tags.go b/vendor/github.com/docker/distribution/tags.go index 503056596..f22df2b85 100644 --- a/vendor/github.com/docker/distribution/tags.go +++ b/vendor/github.com/docker/distribution/tags.go @@ -1,7 +1,7 @@ package distribution import ( - "github.com/docker/distribution/context" + "context" ) // TagService provides access to information about tagged objects. diff --git a/vendor/github.com/docker/distribution/vendor.conf b/vendor/github.com/docker/distribution/vendor.conf index 443b4bcfe..d67edd779 100644 --- a/vendor/github.com/docker/distribution/vendor.conf +++ b/vendor/github.com/docker/distribution/vendor.conf @@ -1,19 +1,21 @@ -github.com/Azure/azure-sdk-for-go c6f0533defaaaa26ea4dff3c9774e36033088112 -github.com/Sirupsen/logrus d26492970760ca5d33129d2d799e34be5c4782eb +github.com/Azure/azure-sdk-for-go 088007b3b08cc02b27f2eadfdcd870958460ce7e +github.com/Azure/go-autorest ec5f4903f77ed9927ac95b19ab8e44ada64c1356 +github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4 github.com/aws/aws-sdk-go c6fc52983ea2375810aa38ddb5370e9cdf611716 -github.com/bshuster-repo/logrus-logstash-hook 5f729f2fb50a301153cae84ff5c58981d51c095a +github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274 github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702 github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782 github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2 +github.com/dgrijalva/jwt-go a601269ab70c205d26370c16f7c81e9017c14e04 github.com/docker/goamz f0a21f5b2e12f83a505ecf79b633bb2035cf6f85 github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21 github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257 github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c -github.com/golang/protobuf/proto 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3 +github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3 github.com/gorilla/context 14f550f51af52180c2eefed15e5fd18d63c0a64a github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b -github.com/gorilla/mux e444e69cbd2e2e3e0749a2f3c717cec491552bbf +github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604 github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39 @@ -21,15 +23,15 @@ github.com/mitchellh/mapstructure 482a9fd5fa83e8c4e7817413b80f3eb8feec03ef github.com/ncw/swift b964f2ca856aac39885e258ad25aec08d5f64ee6 github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064 github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842 -github.com/stevvooe/resumable 51ad44105773cafcbe91927f70ac68e1bf78f8b4 -github.com/xenolf/lego/acme a9d8cec0e6563575e5868a005359ac97911b5985 +github.com/stevvooe/resumable 2aaf90b2ceea5072cb503ef2a620b08ff3119870 +github.com/xenolf/lego a9d8cec0e6563575e5868a005359ac97911b5985 github.com/yvasiyarov/go-metrics 57bccd1ccd43f94bb17fdd8bf3007059b802f85e github.com/yvasiyarov/gorelic a9bba5b9ab508a086f9a12b8c51fab68478e2128 github.com/yvasiyarov/newrelic_platform_go b21fdbd4370f3717f3bbd2bf41c223bc273068e6 golang.org/x/crypto c10c31b5e94b6f7a0283272dc2bb27163dcea24b golang.org/x/net 4876518f9e71663000c348837735820161a42df7 golang.org/x/oauth2 045497edb6234273d67dbc25da3f2ddbc4c4cacf -golang.org/x/time/rate a4bde12657593d5e90d0533a3e4fd95e635124cb +golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb google.golang.org/api 9bf6e6e569ff057f75d9604a46c52928f17d2b54 google.golang.org/appengine 12d5545dc1cfa6047a286d5e853841b6471f4c19 google.golang.org/cloud 975617b05ea8a58727e6c1a06b6161ff4185a9f2 diff --git a/vendor/github.com/docker/docker/README.md b/vendor/github.com/docker/docker/README.md index 533d7717d..534fd97db 100644 --- a/vendor/github.com/docker/docker/README.md +++ b/vendor/github.com/docker/docker/README.md @@ -1,70 +1,38 @@ -### Docker users, see [Moby and Docker](https://mobyproject.org/#moby-and-docker) to clarify the relationship between the projects - -### Docker maintainers and contributors, see [Transitioning to Moby](#transitioning-to-moby) for more details - The Moby Project ================ ![Moby Project logo](docs/static_files/moby-project-logo.png "The Moby Project") -Moby is an open-source project created by Docker to advance the software containerization movement. -It provides a “Lego set” of dozens of components, the framework for assembling them into custom container-based systems, and a place for all container enthusiasts to experiment and exchange ideas. +Moby is an open-source project created by Docker to enable and accelerate software containerization. -# Moby - -## Overview - -At the core of Moby is a framework to assemble specialized container systems. -It provides: - -- A library of containerized components for all vital aspects of a container system: OS, container runtime, orchestration, infrastructure management, networking, storage, security, build, image distribution, etc. -- Tools to assemble the components into runnable artifacts for a variety of platforms and architectures: bare metal (both x86 and Arm); executables for Linux, Mac and Windows; VM images for popular cloud and virtualization providers. -- A set of reference assemblies which can be used as-is, modified, or used as inspiration to create your own. - -All Moby components are containers, so creating new components is as easy as building a new OCI-compatible container. +It provides a "Lego set" of toolkit components, the framework for assembling them into custom container-based systems, and a place for all container enthusiasts and professionals to experiment and exchange ideas. +Components include container build tools, a container registry, orchestration tools, a runtime and more, and these can be used as building blocks in conjunction with other tools and projects. ## Principles -Moby is an open project guided by strong principles, but modular, flexible and without too strong an opinion on user experience, so it is open to the community to help set its direction. -The guiding principles are: +Moby is an open project guided by strong principles, aiming to be modular, flexible and without too strong an opinion on user experience. +It is open to the community to help set its direction. +- Modular: the project includes lots of components that have well-defined functions and APIs that work together. - Batteries included but swappable: Moby includes enough components to build fully featured container system, but its modular architecture ensures that most of the components can be swapped by different implementations. -- Usable security: Moby will provide secure defaults without compromising usability. -- Container centric: Moby is built with containers, for running containers. - -With Moby, you should be able to describe all the components of your distributed application, from the high-level configuration files down to the kernel you would like to use and build and deploy it easily. - -Moby uses [containerd](https://github.com/containerd/containerd) as the default container runtime. +- Usable security: Moby provides secure defaults without compromising usability. +- Developer focused: The APIs are intended to be functional and useful to build powerful tools. +They are not necessarily intended as end user tools but as components aimed at developers. +Documentation and UX is aimed at developers not end users. ## Audience -Moby is recommended for anyone who wants to assemble a container-based system. This includes: +The Moby Project is intended for engineers, integrators and enthusiasts looking to modify, hack, fix, experiment, invent and build systems based on containers. +It is not for people looking for a commercially supported system, but for people who want to work and learn with open source code. -- Hackers who want to customize or patch their Docker build -- System engineers or integrators building a container system -- Infrastructure providers looking to adapt existing container systems to their environment -- Container enthusiasts who want to experiment with the latest container tech -- Open-source developers looking to test their project in a variety of different systems -- Anyone curious about Docker internals and how it’s built +## Relationship with Docker -Moby is NOT recommended for: +The components and tools in the Moby Project are initially the open source components that Docker and the community have built for the Docker Project. +New projects can be added if they fit with the community goals. Docker is committed to using Moby as the upstream for the Docker Product. +However, other projects are also encouraged to use Moby as an upstream, and to reuse the components in diverse ways, and all these uses will be treated in the same way. External maintainers and contributors are welcomed. -- Application developers looking for an easy way to run their applications in containers. We recommend Docker CE instead. -- Enterprise IT and development teams looking for a ready-to-use, commercially supported container platform. We recommend Docker EE instead. -- Anyone curious about containers and looking for an easy way to learn. We recommend the [docker.com](https://www.docker.com/) website instead. - -# Transitioning to Moby - -Docker is transitioning all of its open source collaborations to the Moby project going forward. -During the transition, all open source activity should continue as usual. - -We are proposing the following list of changes: - -- splitting up the engine into more open components -- removing the docker UI, SDK etc to keep them in the Docker org -- clarifying that the project is not limited to the engine, but to the assembly of all the individual components of the Docker platform -- open-source new tools & components which we currently use to assemble the Docker product, but could benefit the community -- defining an open, community-centric governance inspired by the Fedora project (a very successful example of balancing the needs of the community with the constraints of the primary corporate sponsor) +The Moby project is not intended as a location for support or feature requests for Docker products, but as a place for contributors to work on open source code, fix bugs, and make the code more useful. +The releases are supported by the maintainers, community and users, on a best efforts basis only, and are not intended for customers who want enterprise or commercial support; Docker EE is the appropriate product for these use cases. ----- @@ -82,7 +50,6 @@ violate applicable laws. For more information, please see https://www.bis.doc.gov - Licensing ========= Moby is licensed under the Apache License, Version 2.0. See diff --git a/vendor/github.com/docker/docker/api/README.md b/vendor/github.com/docker/docker/api/README.md index bb8813252..f136c3433 100644 --- a/vendor/github.com/docker/docker/api/README.md +++ b/vendor/github.com/docker/docker/api/README.md @@ -10,7 +10,7 @@ It consists of various components in this repository: - `client/` The Go client used by the command-line client. It can also be used by third-party Go programs. - `daemon/` The daemon, which serves the API. -## Swagger definition +## Swagger definition The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to: @@ -20,7 +20,7 @@ The API is defined by the [Swagger](http://swagger.io/specification/) definition ## Updating the API documentation -The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, you'll need to edit this file to represent the change in the documentation. +The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation. The file is split into two main sections: @@ -29,9 +29,9 @@ The file is split into two main sections: To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section. -There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919) +There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919). -`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful for when you are making edits to ensure you are doing the right thing. +`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing. ## Viewing the API documentation diff --git a/vendor/github.com/docker/docker/api/common.go b/vendor/github.com/docker/docker/api/common.go index 859daf602..d0229e038 100644 --- a/vendor/github.com/docker/docker/api/common.go +++ b/vendor/github.com/docker/docker/api/common.go @@ -1,65 +1,11 @@ package api -import ( - "encoding/json" - "encoding/pem" - "fmt" - "os" - "path/filepath" - - "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/pkg/system" - "github.com/docker/libtrust" -) - // Common constants for daemon and client. const ( // DefaultVersion of Current REST API - DefaultVersion string = "1.31" + DefaultVersion string = "1.34" // NoBaseImageSpecifier is the symbol used by the FROM // command to specify that no base image is to be used. NoBaseImageSpecifier string = "scratch" ) - -// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, -// otherwise generates a new one -func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { - err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700, "") - if err != nil { - return nil, err - } - trustKey, err := libtrust.LoadKeyFile(trustKeyPath) - if err == libtrust.ErrKeyFileDoesNotExist { - trustKey, err = libtrust.GenerateECP256PrivateKey() - if err != nil { - return nil, fmt.Errorf("Error generating key: %s", err) - } - encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath)) - if err != nil { - return nil, fmt.Errorf("Error serializing key: %s", err) - } - if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil { - return nil, fmt.Errorf("Error saving key file: %s", err) - } - } else if err != nil { - return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) - } - return trustKey, nil -} - -func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) { - if ext == ".json" || ext == ".jwk" { - encoded, err = json.Marshal(key) - if err != nil { - return nil, fmt.Errorf("unable to encode private key JWK: %s", err) - } - } else { - pemBlock, err := key.PEMBlock() - if err != nil { - return nil, fmt.Errorf("unable to encode private key PEM: %s", err) - } - encoded = pem.EncodeToMemory(pemBlock) - } - return -} diff --git a/vendor/github.com/docker/docker/api/names.go b/vendor/github.com/docker/docker/api/names.go deleted file mode 100644 index f147d1f4c..000000000 --- a/vendor/github.com/docker/docker/api/names.go +++ /dev/null @@ -1,9 +0,0 @@ -package api - -import "regexp" - -// RestrictedNameChars collects the characters allowed to represent a name, normally used to validate container and volume names. -const RestrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]` - -// RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters. -var RestrictedNamePattern = regexp.MustCompile(`^` + RestrictedNameChars + `+$`) diff --git a/vendor/github.com/docker/docker/api/types/client.go b/vendor/github.com/docker/docker/api/types/client.go index 18a1263f1..db37f1fe4 100644 --- a/vendor/github.com/docker/docker/api/types/client.go +++ b/vendor/github.com/docker/docker/api/types/client.go @@ -179,10 +179,7 @@ type ImageBuildOptions struct { ExtraHosts []string // List of extra hosts Target string SessionID string - - // TODO @jhowardmsft LCOW Support: This will require extending to include - // `Platform string`, but is ommited for now as it's hard-coded temporarily - // to avoid API changes. + Platform string } // ImageBuildResponse holds information @@ -195,7 +192,8 @@ type ImageBuildResponse struct { // ImageCreateOptions holds information to create images. type ImageCreateOptions struct { - RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. + Platform string // Platform is the target platform of the image if it needs to be pulled from the registry. } // ImageImportSource holds source information for ImageImport @@ -206,9 +204,10 @@ type ImageImportSource struct { // ImageImportOptions holds information to import images from the client host. type ImageImportOptions struct { - Tag string // Tag is the name to tag this image with. This attribute is deprecated. - Message string // Message is the message to tag the image with - Changes []string // Changes are the raw changes to apply to this image + Tag string // Tag is the name to tag this image with. This attribute is deprecated. + Message string // Message is the message to tag the image with + Changes []string // Changes are the raw changes to apply to this image + Platform string // Platform is the target platform of the image } // ImageListOptions holds parameters to filter the list of images with. @@ -229,6 +228,7 @@ type ImagePullOptions struct { All bool RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry PrivilegeFunc RequestPrivilegeFunc + Platform string } // RequestPrivilegeFunc is a function interface that diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go index e4d2ce6e3..20c19f213 100644 --- a/vendor/github.com/docker/docker/api/types/configs.go +++ b/vendor/github.com/docker/docker/api/types/configs.go @@ -16,7 +16,6 @@ type ContainerCreateConfig struct { HostConfig *container.HostConfig NetworkingConfig *network.NetworkingConfig AdjustCPUShares bool - Platform string } // ContainerRmConfig holds arguments for the container remove diff --git a/vendor/github.com/docker/docker/api/types/container/container_wait.go b/vendor/github.com/docker/docker/api/types/container/container_wait.go index 77ecdbaf7..47fb17578 100644 --- a/vendor/github.com/docker/docker/api/types/container/container_wait.go +++ b/vendor/github.com/docker/docker/api/types/container/container_wait.go @@ -7,10 +7,22 @@ package container // See hack/generate-swagger-api.sh // ---------------------------------------------------------------------------- +// ContainerWaitOKBodyError container waiting error, if any +// swagger:model ContainerWaitOKBodyError +type ContainerWaitOKBodyError struct { + + // Details of an error + Message string `json:"Message,omitempty"` +} + // ContainerWaitOKBody container wait o k body // swagger:model ContainerWaitOKBody type ContainerWaitOKBody struct { + // error + // Required: true + Error *ContainerWaitOKBodyError `json:"Error"` + // Exit code of the container // Required: true StatusCode int64 `json:"StatusCode"` diff --git a/vendor/github.com/docker/docker/api/types/container/host_config.go b/vendor/github.com/docker/docker/api/types/container/host_config.go index 9fea9eb04..bb421b388 100644 --- a/vendor/github.com/docker/docker/api/types/container/host_config.go +++ b/vendor/github.com/docker/docker/api/types/container/host_config.go @@ -23,41 +23,46 @@ func (i Isolation) IsDefault() bool { // IpcMode represents the container ipc stack. type IpcMode string -// IsPrivate indicates whether the container uses its private ipc stack. +// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. func (n IpcMode) IsPrivate() bool { - return !(n.IsHost() || n.IsContainer()) + return n == "private" } -// IsHost indicates whether the container uses the host's ipc stack. +// IsHost indicates whether the container shares the host's ipc namespace. func (n IpcMode) IsHost() bool { return n == "host" } -// IsContainer indicates whether the container uses a container's ipc stack. +// IsShareable indicates whether the container's ipc namespace can be shared with another container. +func (n IpcMode) IsShareable() bool { + return n == "shareable" +} + +// IsContainer indicates whether the container uses another container's ipc namespace. func (n IpcMode) IsContainer() bool { parts := strings.SplitN(string(n), ":", 2) return len(parts) > 1 && parts[0] == "container" } -// Valid indicates whether the ipc stack is valid. +// IsNone indicates whether container IpcMode is set to "none". +func (n IpcMode) IsNone() bool { + return n == "none" +} + +// IsEmpty indicates whether container IpcMode is empty +func (n IpcMode) IsEmpty() bool { + return n == "" +} + +// Valid indicates whether the ipc mode is valid. func (n IpcMode) Valid() bool { - parts := strings.Split(string(n), ":") - switch mode := parts[0]; mode { - case "", "host": - case "container": - if len(parts) != 2 || parts[1] == "" { - return false - } - default: - return false - } - return true + return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() } // Container returns the name of the container ipc stack is going to be used. func (n IpcMode) Container() string { parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { + if len(parts) > 1 && parts[0] == "container" { return parts[1] } return "" diff --git a/vendor/github.com/docker/docker/api/types/events/events.go b/vendor/github.com/docker/docker/api/types/events/events.go index 5f5f54034..e292565b6 100644 --- a/vendor/github.com/docker/docker/api/types/events/events.go +++ b/vendor/github.com/docker/docker/api/types/events/events.go @@ -19,6 +19,8 @@ const ( NodeEventType = "node" // SecretEventType is the event type that secrets generate SecretEventType = "secret" + // ConfigEventType is the event type that configs generate + ConfigEventType = "config" ) // Actor describes something that generates events, diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go index beec3d494..d45d0528f 100644 --- a/vendor/github.com/docker/docker/api/types/filters/parse.go +++ b/vendor/github.com/docker/docker/api/types/filters/parse.go @@ -1,38 +1,45 @@ -// Package filters provides helper function to parse and handle command line -// filter, used for example in docker ps or docker images commands. +/*Package filters provides tools for encoding a mapping of keys to a set of +multiple values. +*/ package filters import ( "encoding/json" "errors" - "fmt" "regexp" "strings" "github.com/docker/docker/api/types/versions" ) -// Args stores filter arguments as map key:{map key: bool}. -// It contains an aggregation of the map of arguments (which are in the form -// of -f 'key=value') based on the key, and stores values for the same key -// in a map with string keys and boolean values. -// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu' -// the args will be {"image.name":{"ubuntu":true},"label":{"label1=1":true,"label2=2":true}} +// Args stores a mapping of keys to a set of multiple values. type Args struct { fields map[string]map[string]bool } -// NewArgs initializes a new Args struct. -func NewArgs() Args { - return Args{fields: map[string]map[string]bool{}} +// KeyValuePair are used to initialize a new Args +type KeyValuePair struct { + Key string + Value string } -// ParseFlag parses the argument to the filter flag. Like +// Arg creates a new KeyValuePair for initializing Args +func Arg(key, value string) KeyValuePair { + return KeyValuePair{Key: key, Value: value} +} + +// NewArgs returns a new Args populated with the initial args +func NewArgs(initialArgs ...KeyValuePair) Args { + args := Args{fields: map[string]map[string]bool{}} + for _, arg := range initialArgs { + args.Add(arg.Key, arg.Value) + } + return args +} + +// ParseFlag parses a key=value string and adds it to an Args. // -// `docker ps -f 'created=today' -f 'image.name=ubuntu*'` -// -// If prev map is provided, then it is appended to, and returned. By default a new -// map is created. +// Deprecated: Use Args.Add() func ParseFlag(arg string, prev Args) (Args, error) { filters := prev if len(arg) == 0 { @@ -53,74 +60,95 @@ func ParseFlag(arg string, prev Args) (Args, error) { return filters, nil } -// ErrBadFormat is an error returned in case of bad format for a filter. +// ErrBadFormat is an error returned when a filter is not in the form key=value +// +// Deprecated: this error will be removed in a future version var ErrBadFormat = errors.New("bad format of filter (expected name=value)") -// ToParam packs the Args into a string for easy transport from client to server. +// ToParam encodes the Args as args JSON encoded string +// +// Deprecated: use ToJSON func ToParam(a Args) (string, error) { - // this way we don't URL encode {}, just empty space + return ToJSON(a) +} + +// MarshalJSON returns a JSON byte representation of the Args +func (args Args) MarshalJSON() ([]byte, error) { + if len(args.fields) == 0 { + return []byte{}, nil + } + return json.Marshal(args.fields) +} + +// ToJSON returns the Args as a JSON encoded string +func ToJSON(a Args) (string, error) { if a.Len() == 0 { return "", nil } - - buf, err := json.Marshal(a.fields) - if err != nil { - return "", err - } - return string(buf), nil + buf, err := json.Marshal(a) + return string(buf), err } -// ToParamWithVersion packs the Args into a string for easy transport from client to server. -// The generated string will depend on the specified version (corresponding to the API version). +// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 +// then the encoded format will use an older legacy format where the values are a +// list of strings, instead of a set. +// +// Deprecated: Use ToJSON func ToParamWithVersion(version string, a Args) (string, error) { - // this way we don't URL encode {}, just empty space if a.Len() == 0 { return "", nil } - // for daemons older than v1.10, filter must be of the form map[string][]string - var buf []byte - var err error if version != "" && versions.LessThan(version, "1.22") { - buf, err = json.Marshal(convertArgsToSlice(a.fields)) - } else { - buf, err = json.Marshal(a.fields) + buf, err := json.Marshal(convertArgsToSlice(a.fields)) + return string(buf), err } - if err != nil { - return "", err - } - return string(buf), nil + + return ToJSON(a) } -// FromParam unpacks the filter Args. +// FromParam decodes a JSON encoded string into Args +// +// Deprecated: use FromJSON func FromParam(p string) (Args, error) { - if len(p) == 0 { - return NewArgs(), nil - } - - r := strings.NewReader(p) - d := json.NewDecoder(r) - - m := map[string]map[string]bool{} - if err := d.Decode(&m); err != nil { - r.Seek(0, 0) - - // Allow parsing old arguments in slice format. - // Because other libraries might be sending them in this format. - deprecated := map[string][]string{} - if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil { - m = deprecatedArgs(deprecated) - } else { - return NewArgs(), err - } - } - return Args{m}, nil + return FromJSON(p) } -// Get returns the list of values associates with a field. -// It returns a slice of strings to keep backwards compatibility with old code. -func (filters Args) Get(field string) []string { - values := filters.fields[field] +// FromJSON decodes a JSON encoded string into Args +func FromJSON(p string) (Args, error) { + args := NewArgs() + + if p == "" { + return args, nil + } + + raw := []byte(p) + err := json.Unmarshal(raw, &args) + if err == nil { + return args, nil + } + + // Fallback to parsing arguments in the legacy slice format + deprecated := map[string][]string{} + if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { + return args, err + } + + args.fields = deprecatedArgs(deprecated) + return args, nil +} + +// UnmarshalJSON populates the Args from JSON encode bytes +func (args Args) UnmarshalJSON(raw []byte) error { + if len(raw) == 0 { + return nil + } + return json.Unmarshal(raw, &args.fields) +} + +// Get returns the list of values associated with the key +func (args Args) Get(key string) []string { + values := args.fields[key] if values == nil { return make([]string, 0) } @@ -131,37 +159,34 @@ func (filters Args) Get(field string) []string { return slice } -// Add adds a new value to a filter field. -func (filters Args) Add(name, value string) { - if _, ok := filters.fields[name]; ok { - filters.fields[name][value] = true +// Add a new value to the set of values +func (args Args) Add(key, value string) { + if _, ok := args.fields[key]; ok { + args.fields[key][value] = true } else { - filters.fields[name] = map[string]bool{value: true} + args.fields[key] = map[string]bool{value: true} } } -// Del removes a value from a filter field. -func (filters Args) Del(name, value string) { - if _, ok := filters.fields[name]; ok { - delete(filters.fields[name], value) - if len(filters.fields[name]) == 0 { - delete(filters.fields, name) +// Del removes a value from the set +func (args Args) Del(key, value string) { + if _, ok := args.fields[key]; ok { + delete(args.fields[key], value) + if len(args.fields[key]) == 0 { + delete(args.fields, key) } } } -// Len returns the number of fields in the arguments. -func (filters Args) Len() int { - return len(filters.fields) +// Len returns the number of keys in the mapping +func (args Args) Len() int { + return len(args.fields) } -// MatchKVList returns true if the values for the specified field matches the ones -// from the sources. -// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, -// field is 'label' and sources are {'label1': '1', 'label2': '2'} -// it returns true. -func (filters Args) MatchKVList(field string, sources map[string]string) bool { - fieldValues := filters.fields[field] +// MatchKVList returns true if all the pairs in sources exist as key=value +// pairs in the mapping at key, or if there are no values at key. +func (args Args) MatchKVList(key string, sources map[string]string) bool { + fieldValues := args.fields[key] //do not filter if there is no filter set or cannot determine filter if len(fieldValues) == 0 { @@ -172,8 +197,8 @@ func (filters Args) MatchKVList(field string, sources map[string]string) bool { return false } - for name2match := range fieldValues { - testKV := strings.SplitN(name2match, "=", 2) + for value := range fieldValues { + testKV := strings.SplitN(value, "=", 2) v, ok := sources[testKV[0]] if !ok { @@ -187,16 +212,13 @@ func (filters Args) MatchKVList(field string, sources map[string]string) bool { return true } -// Match returns true if the values for the specified field matches the source string -// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}}, -// field is 'image.name' and source is 'ubuntu' -// it returns true. -func (filters Args) Match(field, source string) bool { - if filters.ExactMatch(field, source) { +// Match returns true if any of the values at key match the source string +func (args Args) Match(field, source string) bool { + if args.ExactMatch(field, source) { return true } - fieldValues := filters.fields[field] + fieldValues := args.fields[field] for name2match := range fieldValues { match, err := regexp.MatchString(name2match, source) if err != nil { @@ -209,9 +231,9 @@ func (filters Args) Match(field, source string) bool { return false } -// ExactMatch returns true if the source matches exactly one of the filters. -func (filters Args) ExactMatch(field, source string) bool { - fieldValues, ok := filters.fields[field] +// ExactMatch returns true if the source matches exactly one of the values. +func (args Args) ExactMatch(key, source string) bool { + fieldValues, ok := args.fields[key] //do not filter if there is no filter set or cannot determine filter if !ok || len(fieldValues) == 0 { return true @@ -221,14 +243,15 @@ func (filters Args) ExactMatch(field, source string) bool { return fieldValues[source] } -// UniqueExactMatch returns true if there is only one filter and the source matches exactly this one. -func (filters Args) UniqueExactMatch(field, source string) bool { - fieldValues := filters.fields[field] +// UniqueExactMatch returns true if there is only one value and the source +// matches exactly the value. +func (args Args) UniqueExactMatch(key, source string) bool { + fieldValues := args.fields[key] //do not filter if there is no filter set or cannot determine filter if len(fieldValues) == 0 { return true } - if len(filters.fields[field]) != 1 { + if len(args.fields[key]) != 1 { return false } @@ -236,14 +259,14 @@ func (filters Args) UniqueExactMatch(field, source string) bool { return fieldValues[source] } -// FuzzyMatch returns true if the source matches exactly one of the filters, -// or the source has one of the filters as a prefix. -func (filters Args) FuzzyMatch(field, source string) bool { - if filters.ExactMatch(field, source) { +// FuzzyMatch returns true if the source matches exactly one value, or the +// source has one of the values as a prefix. +func (args Args) FuzzyMatch(key, source string) bool { + if args.ExactMatch(key, source) { return true } - fieldValues := filters.fields[field] + fieldValues := args.fields[key] for prefix := range fieldValues { if strings.HasPrefix(source, prefix) { return true @@ -252,30 +275,47 @@ func (filters Args) FuzzyMatch(field, source string) bool { return false } -// Include returns true if the name of the field to filter is in the filters. -func (filters Args) Include(field string) bool { - _, ok := filters.fields[field] +// Include returns true if the key exists in the mapping +// +// Deprecated: use Contains +func (args Args) Include(field string) bool { + _, ok := args.fields[field] return ok } -// Validate ensures that all the fields in the filter are valid. -// It returns an error as soon as it finds an invalid field. -func (filters Args) Validate(accepted map[string]bool) error { - for name := range filters.fields { +// Contains returns true if the key exists in the mapping +func (args Args) Contains(field string) bool { + _, ok := args.fields[field] + return ok +} + +type invalidFilter string + +func (e invalidFilter) Error() string { + return "Invalid filter '" + string(e) + "'" +} + +func (invalidFilter) InvalidParameter() {} + +// Validate compared the set of accepted keys against the keys in the mapping. +// An error is returned if any mapping keys are not in the accepted set. +func (args Args) Validate(accepted map[string]bool) error { + for name := range args.fields { if !accepted[name] { - return fmt.Errorf("Invalid filter '%s'", name) + return invalidFilter(name) } } return nil } -// WalkValues iterates over the list of filtered values for a field. -// It stops the iteration if it finds an error and it returns that error. -func (filters Args) WalkValues(field string, op func(value string) error) error { - if _, ok := filters.fields[field]; !ok { +// WalkValues iterates over the list of values for a key in the mapping and calls +// op() for each value. If op returns an error the iteration stops and the +// error is returned. +func (args Args) WalkValues(field string, op func(value string) error) error { + if _, ok := args.fields[field]; !ok { return nil } - for v := range filters.fields[field] { + for v := range args.fields[field] { if err := op(v); err != nil { return err } diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go index 2744f85d6..b7d133cd8 100644 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -15,6 +15,8 @@ const ( TypeVolume Type = "volume" // TypeTmpfs is the type for mounting tmpfs TypeTmpfs Type = "tmpfs" + // TypeNamedPipe is the type for mounting Windows named pipes + TypeNamedPipe Type = "npipe" ) // Mount represents a mount (volume). @@ -65,7 +67,7 @@ var Propagations = []Propagation{ type Consistency string const ( - // ConsistencyFull guarantees bind-mount-like consistency + // ConsistencyFull guarantees bind mount-like consistency ConsistencyFull Consistency = "consistent" // ConsistencyCached mounts can cache read data and FS structure ConsistencyCached Consistency = "cached" diff --git a/vendor/github.com/docker/docker/api/types/plugin.go b/vendor/github.com/docker/docker/api/types/plugin.go index ed3c2c26e..cab333e01 100644 --- a/vendor/github.com/docker/docker/api/types/plugin.go +++ b/vendor/github.com/docker/docker/api/types/plugin.go @@ -11,7 +11,7 @@ type Plugin struct { // Required: true Config PluginConfig `json:"Config"` - // True when the plugin is running. False when the plugin is not running, only installed. + // True if the plugin is running. False if the plugin is not running, only installed. // Required: true Enabled bool `json:"Enabled"` diff --git a/vendor/github.com/docker/docker/api/types/plugin_responses.go b/vendor/github.com/docker/docker/api/types/plugin_responses.go index 1c6461f2d..18f743fcd 100644 --- a/vendor/github.com/docker/docker/api/types/plugin_responses.go +++ b/vendor/github.com/docker/docker/api/types/plugin_responses.go @@ -9,14 +9,6 @@ import ( // PluginsListResponse contains the response for the Engine API type PluginsListResponse []*Plugin -const ( - authzDriver = "AuthzDriver" - graphDriver = "GraphDriver" - ipamDriver = "IpamDriver" - networkDriver = "NetworkDriver" - volumeDriver = "VolumeDriver" -) - // UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error { versionIndex := len(p) diff --git a/vendor/github.com/docker/docker/api/types/swarm/common.go b/vendor/github.com/docker/docker/api/types/swarm/common.go index 54af82b31..2834cf202 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/common.go +++ b/vendor/github.com/docker/docker/api/types/swarm/common.go @@ -20,7 +20,7 @@ type Annotations struct { Labels map[string]string `json:"Labels"` } -// Driver represents a driver (network, logging). +// Driver represents a driver (network, logging, secrets backend). type Driver struct { Name string `json:",omitempty"` Options map[string]string `json:",omitempty"` diff --git a/vendor/github.com/docker/docker/api/types/swarm/secret.go b/vendor/github.com/docker/docker/api/types/swarm/secret.go index fdb238888..f9b1e9266 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/secret.go +++ b/vendor/github.com/docker/docker/api/types/swarm/secret.go @@ -12,7 +12,8 @@ type Secret struct { // SecretSpec represents a secret specification from a secret in swarm type SecretSpec struct { Annotations - Data []byte `json:",omitempty"` + Data []byte `json:",omitempty"` + Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store } // SecretReferenceFileTarget is a file target in a secret reference diff --git a/vendor/github.com/docker/docker/api/types/swarm/task.go b/vendor/github.com/docker/docker/api/types/swarm/task.go index 1712c06cf..ff11b07e7 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/task.go +++ b/vendor/github.com/docker/docker/api/types/swarm/task.go @@ -51,6 +51,7 @@ type Task struct { Status TaskStatus `json:",omitempty"` DesiredState TaskState `json:",omitempty"` NetworksAttachments []NetworkAttachment `json:",omitempty"` + GenericResources []GenericResource `json:",omitempty"` } // TaskSpec represents the spec of a task. @@ -79,8 +80,34 @@ type TaskSpec struct { // Resources represents resources (CPU/Memory). type Resources struct { - NanoCPUs int64 `json:",omitempty"` - MemoryBytes int64 `json:",omitempty"` + NanoCPUs int64 `json:",omitempty"` + MemoryBytes int64 `json:",omitempty"` + GenericResources []GenericResource `json:",omitempty"` +} + +// GenericResource represents a "user defined" resource which can +// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1) +type GenericResource struct { + NamedResourceSpec *NamedGenericResource `json:",omitempty"` + DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"` +} + +// NamedGenericResource represents a "user defined" resource which is defined +// as a string. +// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) +// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...) +type NamedGenericResource struct { + Kind string `json:",omitempty"` + Value string `json:",omitempty"` +} + +// DiscreteGenericResource represents a "user defined" resource which is defined +// as an integer +// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) +// Value is used to count the resource (SSD=5, HDD=3, ...) +type DiscreteGenericResource struct { + Kind string `json:",omitempty"` + Value int64 `json:",omitempty"` } // ResourceRequirements represents resources requirements. diff --git a/vendor/github.com/docker/docker/api/types/time/timestamp.go b/vendor/github.com/docker/docker/api/types/time/timestamp.go index 9aa9702da..ed9c1168b 100644 --- a/vendor/github.com/docker/docker/api/types/time/timestamp.go +++ b/vendor/github.com/docker/docker/api/types/time/timestamp.go @@ -29,10 +29,8 @@ func GetTimestamp(value string, reference time.Time) (string, error) { } var format string - var parseInLocation bool - // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation - parseInLocation = !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) + parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) if strings.Contains(value, ".") { if parseInLocation { diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go index c96df2733..f7ac77297 100644 --- a/vendor/github.com/docker/docker/api/types/types.go +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -168,6 +168,7 @@ type Info struct { RegistryConfig *registry.ServiceConfig NCPU int MemTotal int64 + GenericResources []swarm.GenericResource DockerRootDir string HTTPProxy string `json:"HttpProxy"` HTTPSProxy string `json:"HttpsProxy"` diff --git a/vendor/github.com/docker/docker/api/types/volume.go b/vendor/github.com/docker/docker/api/types/volume.go index a69b0cfb1..b5ee96a50 100644 --- a/vendor/github.com/docker/docker/api/types/volume.go +++ b/vendor/github.com/docker/docker/api/types/volume.go @@ -7,7 +7,7 @@ package types // swagger:model Volume type Volume struct { - // Time volume was created. + // Date/Time the volume was created. CreatedAt string `json:"CreatedAt,omitempty"` // Name of the volume driver used by the volume. @@ -47,15 +47,23 @@ type Volume struct { UsageData *VolumeUsageData `json:"UsageData,omitempty"` } -// VolumeUsageData volume usage data +// VolumeUsageData Usage details about the volume. This information is used by the +// `GET /system/df` endpoint, and omitted in other endpoints. +// // swagger:model VolumeUsageData type VolumeUsageData struct { - // The number of containers referencing this volume. + // The number of containers referencing this volume. This field + // is set to `-1` if the reference-count is not available. + // // Required: true RefCount int64 `json:"RefCount"` - // The disk space used by the volume (local driver only) + // Amount of disk space used by the volume (in bytes). This information + // is only available for volumes created with the `"local"` volume + // driver. For volumes created with other volume drivers, this field + // is set to `-1` ("not available") + // // Required: true Size int64 `json:"Size"` } diff --git a/vendor/github.com/docker/docker/client/checkpoint_list.go b/vendor/github.com/docker/docker/client/checkpoint_list.go index ffe44bc97..9835bad5c 100644 --- a/vendor/github.com/docker/docker/client/checkpoint_list.go +++ b/vendor/github.com/docker/docker/client/checkpoint_list.go @@ -2,7 +2,6 @@ package client import ( "encoding/json" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -20,10 +19,7 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return checkpoints, containerNotFoundError{container} - } - return checkpoints, err + return checkpoints, wrapResponseError(err, resp, "container", container) } err = json.NewDecoder(resp.body).Decode(&checkpoints) diff --git a/vendor/github.com/docker/docker/client/client.go b/vendor/github.com/docker/docker/client/client.go index 7e1453172..893124853 100644 --- a/vendor/github.com/docker/docker/client/client.go +++ b/vendor/github.com/docker/docker/client/client.go @@ -1,10 +1,6 @@ /* Package client is a Go client for the Docker Engine API. -The "docker" command uses this package to communicate with the daemon. It can also -be used by your own Go applications to do anything the command-line interface does -- running containers, pulling images, managing swarms, etc. - For more information about the Engine API, see the documentation: https://docs.docker.com/engine/reference/api/ @@ -51,6 +47,7 @@ import ( "net/http" "net/url" "os" + "path" "path/filepath" "strings" @@ -159,18 +156,18 @@ func NewEnvClient() (*Client, error) { // highly recommended that you set a version or your client may break if the // server is upgraded. func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) { - proto, addr, basePath, err := ParseHost(host) + hostURL, err := ParseHostURL(host) if err != nil { return nil, err } if client != nil { - if _, ok := client.Transport.(*http.Transport); !ok { + if _, ok := client.Transport.(http.RoundTripper); !ok { return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport) } } else { transport := new(http.Transport) - sockets.ConfigureTransport(transport, proto, addr) + sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host) client = &http.Client{ Transport: transport, CheckRedirect: CheckRedirect, @@ -188,28 +185,24 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map scheme = "https" } + // TODO: store URL instead of proto/addr/basePath return &Client{ scheme: scheme, host: host, - proto: proto, - addr: addr, - basePath: basePath, + proto: hostURL.Scheme, + addr: hostURL.Host, + basePath: hostURL.Path, client: client, version: version, customHTTPHeaders: httpHeaders, }, nil } -// Close ensures that transport.Client is closed -// especially needed while using NewClient with *http.Client = nil -// for example -// client.NewClient("unix:///var/run/docker.sock", nil, "v1.18", map[string]string{"User-Agent": "engine-api-cli-1.0"}) +// Close the transport used by the client func (cli *Client) Close() error { - if t, ok := cli.client.Transport.(*http.Transport); ok { t.CloseIdleConnections() } - return nil } @@ -219,37 +212,27 @@ func (cli *Client) getAPIPath(p string, query url.Values) string { var apiPath string if cli.version != "" { v := strings.TrimPrefix(cli.version, "v") - apiPath = cli.basePath + "/v" + v + p + apiPath = path.Join(cli.basePath, "/v"+v, p) } else { - apiPath = cli.basePath + p + apiPath = path.Join(cli.basePath, p) } - - u := &url.URL{ - Path: apiPath, - } - if len(query) > 0 { - u.RawQuery = query.Encode() - } - return u.String() + return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String() } -// ClientVersion returns the version string associated with this -// instance of the Client. Note that this value can be changed -// via the DOCKER_API_VERSION env var. -// This operation doesn't acquire a mutex. +// ClientVersion returns the API version used by this client. func (cli *Client) ClientVersion() string { return cli.version } -// NegotiateAPIVersion updates the version string associated with this -// instance of the Client to match the latest version the server supports +// NegotiateAPIVersion queries the API and updates the version to match the +// API version. Any errors are silently ignored. func (cli *Client) NegotiateAPIVersion(ctx context.Context) { ping, _ := cli.Ping(ctx) cli.NegotiateAPIVersionPing(ping) } -// NegotiateAPIVersionPing updates the version string associated with this -// instance of the Client to match the latest version the server supports +// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion +// if the ping version is less than the default version. func (cli *Client) NegotiateAPIVersionPing(p types.Ping) { if cli.manualOverride { return @@ -265,23 +248,34 @@ func (cli *Client) NegotiateAPIVersionPing(p types.Ping) { cli.version = api.DefaultVersion } - // if server version is lower than the maximum version supported by the Client, downgrade - if versions.LessThan(p.APIVersion, api.DefaultVersion) { + // if server version is lower than the client version, downgrade + if versions.LessThan(p.APIVersion, cli.version) { cli.version = p.APIVersion } } -// DaemonHost returns the host associated with this instance of the Client. -// This operation doesn't acquire a mutex. +// DaemonHost returns the host address used by the client func (cli *Client) DaemonHost() string { return cli.host } -// ParseHost verifies that the given host strings is valid. +// ParseHost parses a url string, validates the strings is a host url, and returns +// the parsed host as: protocol, address, and base path +// Deprecated: use ParseHostURL func ParseHost(host string) (string, string, string, error) { + hostURL, err := ParseHostURL(host) + if err != nil { + return "", "", "", err + } + return hostURL.Scheme, hostURL.Host, hostURL.Path, nil +} + +// ParseHostURL parses a url string, validates the string is a host url, and +// returns the parsed URL +func ParseHostURL(host string) (*url.URL, error) { protoAddrParts := strings.SplitN(host, "://", 2) if len(protoAddrParts) == 1 { - return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host) + return nil, fmt.Errorf("unable to parse docker host `%s`", host) } var basePath string @@ -289,16 +283,19 @@ func ParseHost(host string) (string, string, string, error) { if proto == "tcp" { parsed, err := url.Parse("tcp://" + addr) if err != nil { - return "", "", "", err + return nil, err } addr = parsed.Host basePath = parsed.Path } - return proto, addr, basePath, nil + return &url.URL{ + Scheme: proto, + Host: addr, + Path: basePath, + }, nil } -// CustomHTTPHeaders returns the custom http headers associated with this -// instance of the Client. This operation doesn't acquire a mutex. +// CustomHTTPHeaders returns the custom http headers stored by the client. func (cli *Client) CustomHTTPHeaders() map[string]string { m := make(map[string]string) for k, v := range cli.customHTTPHeaders { @@ -307,8 +304,7 @@ func (cli *Client) CustomHTTPHeaders() map[string]string { return m } -// SetCustomHTTPHeaders updates the custom http headers associated with this -// instance of the Client. This operation doesn't acquire a mutex. +// SetCustomHTTPHeaders that will be set on every HTTP request made by the client. func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) { cli.customHTTPHeaders = headers } diff --git a/vendor/github.com/docker/docker/client/config_inspect.go b/vendor/github.com/docker/docker/client/config_inspect.go index ebb6d636c..b44d6fdd7 100644 --- a/vendor/github.com/docker/docker/client/config_inspect.go +++ b/vendor/github.com/docker/docker/client/config_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" "golang.org/x/net/context" @@ -17,10 +16,7 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C } resp, err := cli.get(ctx, "/configs/"+id, nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return swarm.Config{}, nil, configNotFoundError{id} - } - return swarm.Config{}, nil, err + return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/config_list.go b/vendor/github.com/docker/docker/client/config_list.go index 8483ca14d..57febc9ff 100644 --- a/vendor/github.com/docker/docker/client/config_list.go +++ b/vendor/github.com/docker/docker/client/config_list.go @@ -18,7 +18,7 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/config_remove.go b/vendor/github.com/docker/docker/client/config_remove.go index 726b5c853..e025d44f7 100644 --- a/vendor/github.com/docker/docker/client/config_remove.go +++ b/vendor/github.com/docker/docker/client/config_remove.go @@ -9,5 +9,5 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error { } resp, err := cli.delete(ctx, "/configs/"+id, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "config", id) } diff --git a/vendor/github.com/docker/docker/client/container_commit.go b/vendor/github.com/docker/docker/client/container_commit.go index 531d796ee..b3b16abfd 100644 --- a/vendor/github.com/docker/docker/client/container_commit.go +++ b/vendor/github.com/docker/docker/client/container_commit.go @@ -39,7 +39,7 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option for _, change := range options.Changes { query.Add("changes", change) } - if options.Pause != true { + if !options.Pause { query.Set("pause", "0") } diff --git a/vendor/github.com/docker/docker/client/container_create.go b/vendor/github.com/docker/docker/client/container_create.go index 6841b0b28..bd817e7fd 100644 --- a/vendor/github.com/docker/docker/client/container_create.go +++ b/vendor/github.com/docker/docker/client/container_create.go @@ -45,7 +45,7 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config serverResp, err := cli.post(ctx, "/containers/create", query, body, nil) if err != nil { if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") { - return response, imageNotFoundError{config.Image} + return response, objectNotFoundError{object: "image", id: config.Image} } return response, err } diff --git a/vendor/github.com/docker/docker/client/container_exec.go b/vendor/github.com/docker/docker/client/container_exec.go index 0665c54fb..29670d02e 100644 --- a/vendor/github.com/docker/docker/client/container_exec.go +++ b/vendor/github.com/docker/docker/client/container_exec.go @@ -35,7 +35,7 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config // It returns a types.HijackedConnection with the hijacked connection // and the a reader to get output. It's up to the called to close // the hijacked connection by calling types.HijackedResponse.Close. -func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error) { +func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) { headers := map[string][]string{"Content-Type": {"application/json"}} return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, headers) } diff --git a/vendor/github.com/docker/docker/client/container_inspect.go b/vendor/github.com/docker/docker/client/container_inspect.go index 17f180974..a15db14be 100644 --- a/vendor/github.com/docker/docker/client/container_inspect.go +++ b/vendor/github.com/docker/docker/client/container_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -15,10 +14,7 @@ import ( func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) { serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return types.ContainerJSON{}, containerNotFoundError{containerID} - } - return types.ContainerJSON{}, err + return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID) } var response types.ContainerJSON @@ -35,10 +31,7 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri } serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return types.ContainerJSON{}, nil, containerNotFoundError{containerID} - } - return types.ContainerJSON{}, nil, err + return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/container_remove.go b/vendor/github.com/docker/docker/client/container_remove.go index 3a79590ce..070108bf3 100644 --- a/vendor/github.com/docker/docker/client/container_remove.go +++ b/vendor/github.com/docker/docker/client/container_remove.go @@ -23,5 +23,5 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "container", containerID) } diff --git a/vendor/github.com/docker/docker/client/errors.go b/vendor/github.com/docker/docker/client/errors.go index e0effafc0..e41b728d3 100644 --- a/vendor/github.com/docker/docker/client/errors.go +++ b/vendor/github.com/docker/docker/client/errors.go @@ -3,6 +3,8 @@ package client import ( "fmt" + "net/http" + "github.com/docker/docker/api/types/versions" "github.com/pkg/errors" ) @@ -36,95 +38,37 @@ type notFound interface { NotFound() bool // Is the error a NotFound error } -// IsErrNotFound returns true if the error is caused with an -// object (image, container, network, volume, …) is not found in the docker host. +// IsErrNotFound returns true if the error is a NotFound error, which is returned +// by the API when some object is not found. func IsErrNotFound(err error) bool { te, ok := err.(notFound) return ok && te.NotFound() } -// imageNotFoundError implements an error returned when an image is not in the docker host. -type imageNotFoundError struct { - imageID string +type objectNotFoundError struct { + object string + id string } -// NotFound indicates that this error type is of NotFound -func (e imageNotFoundError) NotFound() bool { +func (e objectNotFoundError) NotFound() bool { return true } -// Error returns a string representation of an imageNotFoundError -func (e imageNotFoundError) Error() string { - return fmt.Sprintf("Error: No such image: %s", e.imageID) +func (e objectNotFoundError) Error() string { + return fmt.Sprintf("Error: No such %s: %s", e.object, e.id) } -// IsErrImageNotFound returns true if the error is caused -// when an image is not found in the docker host. -func IsErrImageNotFound(err error) bool { - return IsErrNotFound(err) -} - -// containerNotFoundError implements an error returned when a container is not in the docker host. -type containerNotFoundError struct { - containerID string -} - -// NotFound indicates that this error type is of NotFound -func (e containerNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of a containerNotFoundError -func (e containerNotFoundError) Error() string { - return fmt.Sprintf("Error: No such container: %s", e.containerID) -} - -// IsErrContainerNotFound returns true if the error is caused -// when a container is not found in the docker host. -func IsErrContainerNotFound(err error) bool { - return IsErrNotFound(err) -} - -// networkNotFoundError implements an error returned when a network is not in the docker host. -type networkNotFoundError struct { - networkID string -} - -// NotFound indicates that this error type is of NotFound -func (e networkNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of a networkNotFoundError -func (e networkNotFoundError) Error() string { - return fmt.Sprintf("Error: No such network: %s", e.networkID) -} - -// IsErrNetworkNotFound returns true if the error is caused -// when a network is not found in the docker host. -func IsErrNetworkNotFound(err error) bool { - return IsErrNotFound(err) -} - -// volumeNotFoundError implements an error returned when a volume is not in the docker host. -type volumeNotFoundError struct { - volumeID string -} - -// NotFound indicates that this error type is of NotFound -func (e volumeNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of a volumeNotFoundError -func (e volumeNotFoundError) Error() string { - return fmt.Sprintf("Error: No such volume: %s", e.volumeID) -} - -// IsErrVolumeNotFound returns true if the error is caused -// when a volume is not found in the docker host. -func IsErrVolumeNotFound(err error) bool { - return IsErrNotFound(err) +func wrapResponseError(err error, resp serverResponse, object, id string) error { + switch { + case err == nil: + return nil + case resp.statusCode == http.StatusNotFound: + return objectNotFoundError{object: object, id: id} + case resp.statusCode == http.StatusNotImplemented: + return notImplementedError{message: err.Error()} + default: + return err + } } // unauthorizedError represents an authorization error in a remote registry. @@ -144,72 +88,6 @@ func IsErrUnauthorized(err error) bool { return ok } -// nodeNotFoundError implements an error returned when a node is not found. -type nodeNotFoundError struct { - nodeID string -} - -// Error returns a string representation of a nodeNotFoundError -func (e nodeNotFoundError) Error() string { - return fmt.Sprintf("Error: No such node: %s", e.nodeID) -} - -// NotFound indicates that this error type is of NotFound -func (e nodeNotFoundError) NotFound() bool { - return true -} - -// IsErrNodeNotFound returns true if the error is caused -// when a node is not found. -func IsErrNodeNotFound(err error) bool { - _, ok := err.(nodeNotFoundError) - return ok -} - -// serviceNotFoundError implements an error returned when a service is not found. -type serviceNotFoundError struct { - serviceID string -} - -// Error returns a string representation of a serviceNotFoundError -func (e serviceNotFoundError) Error() string { - return fmt.Sprintf("Error: No such service: %s", e.serviceID) -} - -// NotFound indicates that this error type is of NotFound -func (e serviceNotFoundError) NotFound() bool { - return true -} - -// IsErrServiceNotFound returns true if the error is caused -// when a service is not found. -func IsErrServiceNotFound(err error) bool { - _, ok := err.(serviceNotFoundError) - return ok -} - -// taskNotFoundError implements an error returned when a task is not found. -type taskNotFoundError struct { - taskID string -} - -// Error returns a string representation of a taskNotFoundError -func (e taskNotFoundError) Error() string { - return fmt.Sprintf("Error: No such task: %s", e.taskID) -} - -// NotFound indicates that this error type is of NotFound -func (e taskNotFoundError) NotFound() bool { - return true -} - -// IsErrTaskNotFound returns true if the error is caused -// when a task is not found. -func IsErrTaskNotFound(err error) bool { - _, ok := err.(taskNotFoundError) - return ok -} - type pluginPermissionDenied struct { name string } @@ -225,76 +103,31 @@ func IsErrPluginPermissionDenied(err error) bool { return ok } +type notImplementedError struct { + message string +} + +func (e notImplementedError) Error() string { + return e.message +} + +func (e notImplementedError) NotImplemented() bool { + return true +} + +// IsErrNotImplemented returns true if the error is a NotImplemented error. +// This is returned by the API when a requested feature has not been +// implemented. +func IsErrNotImplemented(err error) bool { + te, ok := err.(notImplementedError) + return ok && te.NotImplemented() +} + // NewVersionError returns an error if the APIVersion required // if less than the current supported version func (cli *Client) NewVersionError(APIrequired, feature string) error { - if versions.LessThan(cli.version, APIrequired) { + if cli.version != "" && versions.LessThan(cli.version, APIrequired) { return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version) } return nil } - -// secretNotFoundError implements an error returned when a secret is not found. -type secretNotFoundError struct { - name string -} - -// Error returns a string representation of a secretNotFoundError -func (e secretNotFoundError) Error() string { - return fmt.Sprintf("Error: no such secret: %s", e.name) -} - -// NotFound indicates that this error type is of NotFound -func (e secretNotFoundError) NotFound() bool { - return true -} - -// IsErrSecretNotFound returns true if the error is caused -// when a secret is not found. -func IsErrSecretNotFound(err error) bool { - _, ok := err.(secretNotFoundError) - return ok -} - -// configNotFoundError implements an error returned when a config is not found. -type configNotFoundError struct { - name string -} - -// Error returns a string representation of a configNotFoundError -func (e configNotFoundError) Error() string { - return fmt.Sprintf("Error: no such config: %s", e.name) -} - -// NotFound indicates that this error type is of NotFound -func (e configNotFoundError) NotFound() bool { - return true -} - -// IsErrConfigNotFound returns true if the error is caused -// when a config is not found. -func IsErrConfigNotFound(err error) bool { - _, ok := err.(configNotFoundError) - return ok -} - -// pluginNotFoundError implements an error returned when a plugin is not in the docker host. -type pluginNotFoundError struct { - name string -} - -// NotFound indicates that this error type is of NotFound -func (e pluginNotFoundError) NotFound() bool { - return true -} - -// Error returns a string representation of a pluginNotFoundError -func (e pluginNotFoundError) Error() string { - return fmt.Sprintf("Error: No such plugin: %s", e.name) -} - -// IsErrPluginNotFound returns true if the error is caused -// when a plugin is not found in the docker host. -func IsErrPluginNotFound(err error) bool { - return IsErrNotFound(err) -} diff --git a/vendor/github.com/docker/docker/client/hijack.go b/vendor/github.com/docker/docker/client/hijack.go index 346c74ae8..d04cebdcf 100644 --- a/vendor/github.com/docker/docker/client/hijack.go +++ b/vendor/github.com/docker/docker/client/hijack.go @@ -12,7 +12,6 @@ import ( "time" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/tlsconfig" "github.com/docker/go-connections/sockets" "github.com/pkg/errors" "golang.org/x/net/context" @@ -71,7 +70,7 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con timeout := dialer.Timeout if !dialer.Deadline.IsZero() { - deadlineTimeout := dialer.Deadline.Sub(time.Now()) + deadlineTimeout := time.Until(dialer.Deadline) if timeout == 0 || deadlineTimeout < timeout { timeout = deadlineTimeout } @@ -115,7 +114,7 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con // from the hostname we're connecting to. if config.ServerName == "" { // Make a copy to avoid polluting argument or default. - config = tlsconfig.Clone(config) + config = tlsConfigClone(config) config.ServerName = hostname } @@ -177,12 +176,14 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, e // Server hijacks the connection, error 'connection closed' expected resp, err := clientconn.Do(req) - if err != nil { - return nil, err - } - if resp.StatusCode != http.StatusSwitchingProtocols { - resp.Body.Close() - return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode) + if err != httputil.ErrPersistEOF { + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusSwitchingProtocols { + resp.Body.Close() + return nil, fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode) + } } c, br := clientconn.Hijack() diff --git a/vendor/github.com/docker/docker/client/image_build.go b/vendor/github.com/docker/docker/client/image_build.go index 44a215f90..cd0f54d13 100644 --- a/vendor/github.com/docker/docker/client/image_build.go +++ b/vendor/github.com/docker/docker/client/image_build.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "strconv" + "strings" "golang.org/x/net/context" @@ -29,6 +30,13 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio return types.ImageBuildResponse{}, err } headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) + + if options.Platform != "" { + if err := cli.NewVersionError("1.32", "platform"); err != nil { + return types.ImageBuildResponse{}, err + } + query.Set("platform", options.Platform) + } headers.Set("Content-Type", "application/x-tar") serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers) @@ -123,6 +131,8 @@ func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (ur if options.SessionID != "" { query.Set("session", options.SessionID) } - + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } return query, nil } diff --git a/vendor/github.com/docker/docker/client/image_create.go b/vendor/github.com/docker/docker/client/image_create.go index 4436abb0d..fb5447b9b 100644 --- a/vendor/github.com/docker/docker/client/image_create.go +++ b/vendor/github.com/docker/docker/client/image_create.go @@ -3,6 +3,7 @@ package client import ( "io" "net/url" + "strings" "golang.org/x/net/context" @@ -21,6 +22,9 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti query := url.Values{} query.Set("fromImage", reference.FamiliarName(ref)) query.Set("tag", getAPITagFromNamedRef(ref)) + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if err != nil { return nil, err diff --git a/vendor/github.com/docker/docker/client/image_import.go b/vendor/github.com/docker/docker/client/image_import.go index d7dedd823..ab55ddbac 100644 --- a/vendor/github.com/docker/docker/client/image_import.go +++ b/vendor/github.com/docker/docker/client/image_import.go @@ -3,6 +3,7 @@ package client import ( "io" "net/url" + "strings" "golang.org/x/net/context" @@ -25,6 +26,9 @@ func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSour query.Set("repo", ref) query.Set("tag", options.Tag) query.Set("message", options.Message) + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } for _, change := range options.Changes { query.Add("changes", change) } diff --git a/vendor/github.com/docker/docker/client/image_inspect.go b/vendor/github.com/docker/docker/client/image_inspect.go index b3a64ce2f..1bc591990 100644 --- a/vendor/github.com/docker/docker/client/image_inspect.go +++ b/vendor/github.com/docker/docker/client/image_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -14,10 +13,7 @@ import ( func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (types.ImageInspect, []byte, error) { serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return types.ImageInspect{}, nil, imageNotFoundError{imageID} - } - return types.ImageInspect{}, nil, err + return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/image_pull.go b/vendor/github.com/docker/docker/client/image_pull.go index a72b9bf7f..92942d2e5 100644 --- a/vendor/github.com/docker/docker/client/image_pull.go +++ b/vendor/github.com/docker/docker/client/image_pull.go @@ -4,6 +4,7 @@ import ( "io" "net/http" "net/url" + "strings" "golang.org/x/net/context" @@ -30,6 +31,9 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.I if !options.All { query.Set("tag", getAPITagFromNamedRef(ref)) } + if options.Platform != "" { + query.Set("platform", strings.ToLower(options.Platform)) + } resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { diff --git a/vendor/github.com/docker/docker/client/image_remove.go b/vendor/github.com/docker/docker/client/image_remove.go index 6921209ee..81d6c5438 100644 --- a/vendor/github.com/docker/docker/client/image_remove.go +++ b/vendor/github.com/docker/docker/client/image_remove.go @@ -19,12 +19,12 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type query.Set("noprune", "1") } + var dels []types.ImageDeleteResponseItem resp, err := cli.delete(ctx, "/images/"+imageID, query, nil) if err != nil { - return nil, err + return dels, wrapResponseError(err, resp, "image", imageID) } - var dels []types.ImageDeleteResponseItem err = json.NewDecoder(resp.body).Decode(&dels) ensureReaderClosed(resp) return dels, err diff --git a/vendor/github.com/docker/docker/client/image_search.go b/vendor/github.com/docker/docker/client/image_search.go index b0fcd5c23..5566e9255 100644 --- a/vendor/github.com/docker/docker/client/image_search.go +++ b/vendor/github.com/docker/docker/client/image_search.go @@ -21,7 +21,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I query.Set("limit", fmt.Sprintf("%d", options.Limit)) if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return results, err } diff --git a/vendor/github.com/docker/docker/client/interface.go b/vendor/github.com/docker/docker/client/interface.go index acd4de1db..dd8b388cf 100644 --- a/vendor/github.com/docker/docker/client/interface.go +++ b/vendor/github.com/docker/docker/client/interface.go @@ -45,7 +45,7 @@ type ContainerAPIClient interface { ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) ContainerDiff(ctx context.Context, container string) ([]container.ContainerChangeResponseItem, error) - ContainerExecAttach(ctx context.Context, execID string, config types.ExecConfig) (types.HijackedResponse, error) + ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) ContainerExecResize(ctx context.Context, execID string, options types.ResizeOptions) error diff --git a/vendor/github.com/docker/docker/client/network_inspect.go b/vendor/github.com/docker/docker/client/network_inspect.go index 848c9799f..afabe6597 100644 --- a/vendor/github.com/docker/docker/client/network_inspect.go +++ b/vendor/github.com/docker/docker/client/network_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -33,10 +32,7 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, } resp, err = cli.get(ctx, "/networks/"+networkID, query, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return networkResource, nil, networkNotFoundError{networkID} - } - return networkResource, nil, err + return networkResource, nil, wrapResponseError(err, resp, "network", networkID) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/network_remove.go b/vendor/github.com/docker/docker/client/network_remove.go index 6bd674892..0811b5b51 100644 --- a/vendor/github.com/docker/docker/client/network_remove.go +++ b/vendor/github.com/docker/docker/client/network_remove.go @@ -6,5 +6,5 @@ import "golang.org/x/net/context" func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "network", networkID) } diff --git a/vendor/github.com/docker/docker/client/node_inspect.go b/vendor/github.com/docker/docker/client/node_inspect.go index abf505d29..791d2c006 100644 --- a/vendor/github.com/docker/docker/client/node_inspect.go +++ b/vendor/github.com/docker/docker/client/node_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" "golang.org/x/net/context" @@ -14,10 +13,7 @@ import ( func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) { serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return swarm.Node{}, nil, nodeNotFoundError{nodeID} - } - return swarm.Node{}, nil, err + return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/node_list.go b/vendor/github.com/docker/docker/client/node_list.go index 3e8440f08..fed22992c 100644 --- a/vendor/github.com/docker/docker/client/node_list.go +++ b/vendor/github.com/docker/docker/client/node_list.go @@ -15,7 +15,7 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions) query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err diff --git a/vendor/github.com/docker/docker/client/node_remove.go b/vendor/github.com/docker/docker/client/node_remove.go index 0a77f3d57..adbf52feb 100644 --- a/vendor/github.com/docker/docker/client/node_remove.go +++ b/vendor/github.com/docker/docker/client/node_remove.go @@ -17,5 +17,5 @@ func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types. resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "node", nodeID) } diff --git a/vendor/github.com/docker/docker/client/parse_logs.go b/vendor/github.com/docker/docker/client/parse_logs.go deleted file mode 100644 index e427f80a7..000000000 --- a/vendor/github.com/docker/docker/client/parse_logs.go +++ /dev/null @@ -1,41 +0,0 @@ -package client - -// parse_logs.go contains utility helpers for getting information out of docker -// log lines. really, it only contains ParseDetails right now. maybe in the -// future there will be some desire to parse log messages back into a struct? -// that would go here if we did - -import ( - "net/url" - "strings" - - "github.com/pkg/errors" -) - -// ParseLogDetails takes a details string of key value pairs in the form -// "k=v,l=w", where the keys and values are url query escaped, and each pair -// is separated by a comma, returns a map. returns an error if the details -// string is not in a valid format -// the exact form of details encoding is implemented in -// api/server/httputils/write_log_stream.go -func ParseLogDetails(details string) (map[string]string, error) { - pairs := strings.Split(details, ",") - detailsMap := make(map[string]string, len(pairs)) - for _, pair := range pairs { - p := strings.SplitN(pair, "=", 2) - // if there is no equals sign, we will only get 1 part back - if len(p) != 2 { - return nil, errors.New("invalid details format") - } - k, err := url.QueryUnescape(p[0]) - if err != nil { - return nil, err - } - v, err := url.QueryUnescape(p[1]) - if err != nil { - return nil, err - } - detailsMap[k] = v - } - return detailsMap, nil -} diff --git a/vendor/github.com/docker/docker/client/ping.go b/vendor/github.com/docker/docker/client/ping.go index a4c2e2c4d..0b6e450da 100644 --- a/vendor/github.com/docker/docker/client/ping.go +++ b/vendor/github.com/docker/docker/client/ping.go @@ -1,6 +1,8 @@ package client import ( + "path" + "github.com/docker/docker/api/types" "golang.org/x/net/context" ) @@ -8,7 +10,7 @@ import ( // Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { var ping types.Ping - req, err := cli.buildRequest("GET", cli.basePath+"/_ping", nil, nil) + req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) if err != nil { return ping, err } @@ -26,7 +28,5 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { } ping.OSType = serverResp.header.Get("OSType") } - - err = cli.checkResponseErr(serverResp) - return ping, err + return ping, cli.checkResponseErr(serverResp) } diff --git a/vendor/github.com/docker/docker/client/plugin_inspect.go b/vendor/github.com/docker/docker/client/plugin_inspect.go index 89f39ee2c..6a6fc18df 100644 --- a/vendor/github.com/docker/docker/client/plugin_inspect.go +++ b/vendor/github.com/docker/docker/client/plugin_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -14,10 +13,7 @@ import ( func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return nil, nil, pluginNotFoundError{name} - } - return nil, nil, err + return nil, nil, wrapResponseError(err, resp, "plugin", name) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/plugin_list.go b/vendor/github.com/docker/docker/client/plugin_list.go index 3acde3b96..78dbeb8be 100644 --- a/vendor/github.com/docker/docker/client/plugin_list.go +++ b/vendor/github.com/docker/docker/client/plugin_list.go @@ -23,7 +23,7 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.P } resp, err := cli.get(ctx, "/plugins", query, nil) if err != nil { - return plugins, err + return plugins, wrapResponseError(err, resp, "plugin", "") } err = json.NewDecoder(resp.body).Decode(&plugins) diff --git a/vendor/github.com/docker/docker/client/plugin_remove.go b/vendor/github.com/docker/docker/client/plugin_remove.go index b017e4d34..b498c4820 100644 --- a/vendor/github.com/docker/docker/client/plugin_remove.go +++ b/vendor/github.com/docker/docker/client/plugin_remove.go @@ -16,5 +16,5 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options types. resp, err := cli.delete(ctx, "/plugins/"+name, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "plugin", name) } diff --git a/vendor/github.com/docker/docker/client/request.go b/vendor/github.com/docker/docker/client/request.go index 3e7d43fea..615d0b989 100644 --- a/vendor/github.com/docker/docker/client/request.go +++ b/vendor/github.com/docker/docker/client/request.go @@ -203,7 +203,7 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error { return err } if len(body) == 0 { - return fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) + return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) } var ct string diff --git a/vendor/github.com/docker/docker/client/secret_inspect.go b/vendor/github.com/docker/docker/client/secret_inspect.go index 9b602972b..6927ea96f 100644 --- a/vendor/github.com/docker/docker/client/secret_inspect.go +++ b/vendor/github.com/docker/docker/client/secret_inspect.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" "golang.org/x/net/context" @@ -17,10 +16,7 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S } resp, err := cli.get(ctx, "/secrets/"+id, nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return swarm.Secret{}, nil, secretNotFoundError{id} - } - return swarm.Secret{}, nil, err + return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/secret_list.go b/vendor/github.com/docker/docker/client/secret_list.go index 0d33ecfbc..fdee6e2e0 100644 --- a/vendor/github.com/docker/docker/client/secret_list.go +++ b/vendor/github.com/docker/docker/client/secret_list.go @@ -18,7 +18,7 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/secret_remove.go b/vendor/github.com/docker/docker/client/secret_remove.go index c5e37af17..9b4ee71e2 100644 --- a/vendor/github.com/docker/docker/client/secret_remove.go +++ b/vendor/github.com/docker/docker/client/secret_remove.go @@ -9,5 +9,5 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error { } resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "secret", id) } diff --git a/vendor/github.com/docker/docker/client/service_create.go b/vendor/github.com/docker/docker/client/service_create.go index a36839443..834709d1f 100644 --- a/vendor/github.com/docker/docker/client/service_create.go +++ b/vendor/github.com/docker/docker/client/service_create.go @@ -3,11 +3,12 @@ package client import ( "encoding/json" "fmt" + "strings" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" - "github.com/opencontainers/go-digest" + digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" "golang.org/x/net/context" ) @@ -85,21 +86,30 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, return response, err } -func imageDigestAndPlatforms(ctx context.Context, cli *Client, image, encodedAuth string) (string, []swarm.Platform, error) { +func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) { distributionInspect, err := cli.DistributionInspect(ctx, image, encodedAuth) - imageWithDigest := image var platforms []swarm.Platform if err != nil { return "", nil, err } - imageWithDigest = imageWithDigestString(image, distributionInspect.Descriptor.Digest) + imageWithDigest := imageWithDigestString(image, distributionInspect.Descriptor.Digest) if len(distributionInspect.Platforms) > 0 { platforms = make([]swarm.Platform, 0, len(distributionInspect.Platforms)) for _, p := range distributionInspect.Platforms { + // clear architecture field for arm. This is a temporary patch to address + // https://github.com/docker/swarmkit/issues/2294. The issue is that while + // image manifests report "arm" as the architecture, the node reports + // something like "armv7l" (includes the variant), which causes arm images + // to stop working with swarm mode. This patch removes the architecture + // constraint for arm images to ensure tasks get scheduled. + arch := p.Architecture + if strings.ToLower(arch) == "arm" { + arch = "" + } platforms = append(platforms, swarm.Platform{ - Architecture: p.Architecture, + Architecture: arch, OS: p.OS, }) } diff --git a/vendor/github.com/docker/docker/client/service_inspect.go b/vendor/github.com/docker/docker/client/service_inspect.go index d7e051e3a..3e9699e5e 100644 --- a/vendor/github.com/docker/docker/client/service_inspect.go +++ b/vendor/github.com/docker/docker/client/service_inspect.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -19,10 +18,7 @@ func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults)) serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return swarm.Service{}, nil, serviceNotFoundError{serviceID} - } - return swarm.Service{}, nil, err + return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/service_list.go b/vendor/github.com/docker/docker/client/service_list.go index c29e6d407..eb3ff9739 100644 --- a/vendor/github.com/docker/docker/client/service_list.go +++ b/vendor/github.com/docker/docker/client/service_list.go @@ -15,7 +15,7 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/service_remove.go b/vendor/github.com/docker/docker/client/service_remove.go index a9331f92c..ad992c01d 100644 --- a/vendor/github.com/docker/docker/client/service_remove.go +++ b/vendor/github.com/docker/docker/client/service_remove.go @@ -6,5 +6,5 @@ import "golang.org/x/net/context" func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error { resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "service", serviceID) } diff --git a/vendor/github.com/docker/docker/client/task_inspect.go b/vendor/github.com/docker/docker/client/task_inspect.go index bc8058fc3..dc08cedb9 100644 --- a/vendor/github.com/docker/docker/client/task_inspect.go +++ b/vendor/github.com/docker/docker/client/task_inspect.go @@ -4,10 +4,8 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" ) @@ -15,10 +13,7 @@ import ( func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) { serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil) if err != nil { - if serverResp.statusCode == http.StatusNotFound { - return swarm.Task{}, nil, taskNotFoundError{taskID} - } - return swarm.Task{}, nil, err + return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID) } defer ensureReaderClosed(serverResp) diff --git a/vendor/github.com/docker/docker/client/task_list.go b/vendor/github.com/docker/docker/client/task_list.go index 66324da95..01bd69525 100644 --- a/vendor/github.com/docker/docker/client/task_list.go +++ b/vendor/github.com/docker/docker/client/task_list.go @@ -15,7 +15,7 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions) query := url.Values{} if options.Filters.Len() > 0 { - filterJSON, err := filters.ToParam(options.Filters) + filterJSON, err := filters.ToJSON(options.Filters) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/tlsconfig_clone.go b/vendor/github.com/docker/docker/client/tlsconfig_clone.go new file mode 100644 index 000000000..99b6be1ce --- /dev/null +++ b/vendor/github.com/docker/docker/client/tlsconfig_clone.go @@ -0,0 +1,11 @@ +// +build go1.8 + +package client + +import "crypto/tls" + +// tlsConfigClone returns a clone of tls.Config. This function is provided for +// compatibility for go1.7 that doesn't include this method in stdlib. +func tlsConfigClone(c *tls.Config) *tls.Config { + return c.Clone() +} diff --git a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone_go17.go b/vendor/github.com/docker/docker/client/tlsconfig_clone_go17.go similarity index 89% rename from vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone_go17.go rename to vendor/github.com/docker/docker/client/tlsconfig_clone_go17.go index 0d5b448fe..b837b2ade 100644 --- a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone_go17.go +++ b/vendor/github.com/docker/docker/client/tlsconfig_clone_go17.go @@ -1,12 +1,12 @@ // +build go1.7,!go1.8 -package tlsconfig +package client import "crypto/tls" -// Clone returns a clone of tls.Config. This function is provided for +// tlsConfigClone returns a clone of tls.Config. This function is provided for // compatibility for go1.7 that doesn't include this method in stdlib. -func Clone(c *tls.Config) *tls.Config { +func tlsConfigClone(c *tls.Config) *tls.Config { return &tls.Config{ Rand: c.Rand, Time: c.Time, diff --git a/vendor/github.com/docker/docker/client/transport.go b/vendor/github.com/docker/docker/client/transport.go index 401ab15d3..73f6ef7b4 100644 --- a/vendor/github.com/docker/docker/client/transport.go +++ b/vendor/github.com/docker/docker/client/transport.go @@ -5,14 +5,6 @@ import ( "net/http" ) -// transportFunc allows us to inject a mock transport for testing. We define it -// here so we can detect the tlsconfig and return nil for only this type. -type transportFunc func(*http.Request) (*http.Response, error) - -func (tf transportFunc) RoundTrip(req *http.Request) (*http.Response, error) { - return tf(req) -} - // resolveTLSConfig attempts to resolve the TLS configuration from the // RoundTripper. func resolveTLSConfig(transport http.RoundTripper) *tls.Config { diff --git a/vendor/github.com/docker/docker/client/utils.go b/vendor/github.com/docker/docker/client/utils.go index f3d8877df..137705065 100644 --- a/vendor/github.com/docker/docker/client/utils.go +++ b/vendor/github.com/docker/docker/client/utils.go @@ -24,7 +24,7 @@ func getDockerOS(serverHeader string) string { func getFiltersQuery(f filters.Args) (url.Values, error) { query := url.Values{} if f.Len() > 0 { - filterJSON, err := filters.ToParam(f) + filterJSON, err := filters.ToJSON(f) if err != nil { return query, err } diff --git a/vendor/github.com/docker/docker/client/volume_inspect.go b/vendor/github.com/docker/docker/client/volume_inspect.go index 3860e9b22..988934384 100644 --- a/vendor/github.com/docker/docker/client/volume_inspect.go +++ b/vendor/github.com/docker/docker/client/volume_inspect.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "io/ioutil" - "net/http" + "path" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -18,13 +18,17 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo // VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) { + // The empty ID needs to be handled here because with an empty ID the + // request url will not contain a trailing / which calls the volume list API + // instead of volume inspect + if volumeID == "" { + return types.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID} + } + var volume types.Volume - resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) + resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil) if err != nil { - if resp.statusCode == http.StatusNotFound { - return volume, nil, volumeNotFoundError{volumeID} - } - return volume, nil, err + return volume, nil, wrapResponseError(err, resp, "volume", volumeID) } defer ensureReaderClosed(resp) diff --git a/vendor/github.com/docker/docker/client/volume_remove.go b/vendor/github.com/docker/docker/client/volume_remove.go index 6c26575b4..3ffb8bcf2 100644 --- a/vendor/github.com/docker/docker/client/volume_remove.go +++ b/vendor/github.com/docker/docker/client/volume_remove.go @@ -17,5 +17,5 @@ func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool } resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil) ensureReaderClosed(resp) - return err + return wrapResponseError(err, resp, "volume", volumeID) } diff --git a/vendor/github.com/docker/docker/hack/README.md b/vendor/github.com/docker/docker/hack/README.md new file mode 100644 index 000000000..9e588db25 --- /dev/null +++ b/vendor/github.com/docker/docker/hack/README.md @@ -0,0 +1,60 @@ +## About + +This directory contains a collection of scripts used to build and manage this +repository. If there are any issues regarding the intention of a particular +script (or even part of a certain script), please reach out to us. +It may help us either refine our current scripts, or add on new ones +that are appropriate for a given use case. + +## DinD (dind.sh) + +DinD is a wrapper script which allows Docker to be run inside a Docker +container. DinD requires the container to +be run with privileged mode enabled. + +## Generate Authors (generate-authors.sh) + +Generates AUTHORS; a file with all the names and corresponding emails of +individual contributors. AUTHORS can be found in the home directory of +this repository. + +## Make + +There are two make files, each with different extensions. Neither are supposed +to be called directly; only invoke `make`. Both scripts run inside a Docker +container. + +### make.ps1 + +- The Windows native build script that uses PowerShell semantics; it is limited +unlike `hack\make.sh` since it does not provide support for the full set of +operations provided by the Linux counterpart, `make.sh`. However, `make.ps1` +does provide support for local Windows development and Windows to Windows CI. +More information is found within `make.ps1` by the author, @jhowardmsft + +### make.sh + +- Referenced via `make test` when running tests on a local machine, +or directly referenced when running tests inside a Docker development container. +- When running on a local machine, `make test` to run all tests found in +`test`, `test-unit`, `test-integration`, and `test-docker-py` on +your local machine. The default timeout is set in `make.sh` to 60 minutes +(`${TIMEOUT:=60m}`), since it currently takes up to an hour to run +all of the tests. +- When running inside a Docker development container, `hack/make.sh` does +not have a single target that runs all the tests. You need to provide a +single command line with multiple targets that performs the same thing. +An example referenced from [Run targets inside a development container](https://docs.docker.com/opensource/project/test-and-docs/#run-targets-inside-a-development-container): `root@5f8630b873fe:/go/src/github.com/moby/moby# hack/make.sh dynbinary binary cross test-unit test-integration test-docker-py` +- For more information related to testing outside the scope of this README, +refer to +[Run tests and test documentation](https://docs.docker.com/opensource/project/test-and-docs/) + +## Release (release.sh) + +Releases any bundles built by `make` on a public AWS S3 bucket. +For information regarding configuration, please view `release.sh`. + +## Vendor (vendor.sh) + +A shell script that is a wrapper around Vndr. For information on how to use +this, please refer to [vndr's README](https://github.com/LK4D4/vndr/blob/master/README.md) diff --git a/vendor/github.com/docker/docker/hack/integration-cli-on-swarm/README.md b/vendor/github.com/docker/docker/hack/integration-cli-on-swarm/README.md new file mode 100644 index 000000000..1cea52526 --- /dev/null +++ b/vendor/github.com/docker/docker/hack/integration-cli-on-swarm/README.md @@ -0,0 +1,69 @@ +# Integration Testing on Swarm + +IT on Swarm allows you to execute integration test in parallel across a Docker Swarm cluster + +## Architecture + +### Master service + + - Works as a funker caller + - Calls a worker funker (`-worker-service`) with a chunk of `-check.f` filter strings (passed as a file via `-input` flag, typically `/mnt/input`) + +### Worker service + + - Works as a funker callee + - Executes an equivalent of `TESTFLAGS=-check.f TestFoo|TestBar|TestBaz ... make test-integration-cli` using the bind-mounted API socket (`docker.sock`) + +### Client + + - Controls master and workers via `docker stack` + - No need to have a local daemon + +Typically, the master and workers are supposed to be running on a cloud environment, +while the client is supposed to be running on a laptop, e.g. Docker for Mac/Windows. + +## Requirement + + - Docker daemon 1.13 or later + - Private registry for distributed execution with multiple nodes + +## Usage + +### Step 1: Prepare images + + $ make build-integration-cli-on-swarm + +Following environment variables are known to work in this step: + + - `BUILDFLAGS` + - `DOCKER_INCREMENTAL_BINARY` + +Note: during the transition into Moby Project, you might need to create a symbolic link `$GOPATH/src/github.com/docker/docker` to `$GOPATH/src/github.com/moby/moby`. + +### Step 2: Execute tests + + $ ./hack/integration-cli-on-swarm/integration-cli-on-swarm -replicas 40 -push-worker-image YOUR_REGISTRY.EXAMPLE.COM/integration-cli-worker:latest + +Following environment variables are known to work in this step: + + - `DOCKER_GRAPHDRIVER` + - `DOCKER_EXPERIMENTAL` + +#### Flags + +Basic flags: + + - `-replicas N`: the number of worker service replicas. i.e. degree of parallelism. + - `-chunks N`: the number of chunks. By default, `chunks` == `replicas`. + - `-push-worker-image REGISTRY/IMAGE:TAG`: push the worker image to the registry. Note that if you have only single node and hence you do not need a private registry, you do not need to specify `-push-worker-image`. + +Experimental flags for mitigating makespan nonuniformity: + + - `-shuffle`: Shuffle the test filter strings + +Flags for debugging IT on Swarm itself: + + - `-rand-seed N`: the random seed. This flag is useful for deterministic replaying. By default(0), the timestamp is used. + - `-filters-file FILE`: the file contains `-check.f` strings. By default, the file is automatically generated. + - `-dry-run`: skip the actual workload + - `keep-executor`: do not auto-remove executor containers, which is used for running privileged programs on Swarm diff --git a/vendor/github.com/docker/docker/hack/integration-cli-on-swarm/agent/vendor.conf b/vendor/github.com/docker/docker/hack/integration-cli-on-swarm/agent/vendor.conf new file mode 100644 index 000000000..efd6d6d04 --- /dev/null +++ b/vendor/github.com/docker/docker/hack/integration-cli-on-swarm/agent/vendor.conf @@ -0,0 +1,2 @@ +# dependencies specific to worker (i.e. github.com/docker/docker/...) are not vendored here +github.com/bfirsh/funker-go eaa0a2e06f30e72c9a0b7f858951e581e26ef773 diff --git a/vendor/github.com/docker/docker/pkg/README.md b/vendor/github.com/docker/docker/pkg/README.md deleted file mode 100644 index c4b78a8ad..000000000 --- a/vendor/github.com/docker/docker/pkg/README.md +++ /dev/null @@ -1,11 +0,0 @@ -pkg/ is a collection of utility packages used by the Docker project without being specific to its internals. - -Utility packages are kept separate from the docker core codebase to keep it as small and concise as possible. -If some utilities grow larger and their APIs stabilize, they may be moved to their own repository under the -Docker organization, to facilitate re-use by other projects. However that is not the priority. - -The directory `pkg` is named after the same directory in the camlistore project. Since Brad is a core -Go maintainer, we thought it made sense to copy his methods for organizing Go code :) Thanks Brad! - -Because utility packages are small and neatly separated from the rest of the codebase, they are a good -place to start for aspiring maintainers and contributors. Get in touch if you want to help maintain them! diff --git a/vendor/github.com/docker/docker/pkg/ioutils/buffer.go b/vendor/github.com/docker/docker/pkg/ioutils/buffer.go deleted file mode 100644 index 3d737b3e1..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/buffer.go +++ /dev/null @@ -1,51 +0,0 @@ -package ioutils - -import ( - "errors" - "io" -) - -var errBufferFull = errors.New("buffer is full") - -type fixedBuffer struct { - buf []byte - pos int - lastRead int -} - -func (b *fixedBuffer) Write(p []byte) (int, error) { - n := copy(b.buf[b.pos:cap(b.buf)], p) - b.pos += n - - if n < len(p) { - if b.pos == cap(b.buf) { - return n, errBufferFull - } - return n, io.ErrShortWrite - } - return n, nil -} - -func (b *fixedBuffer) Read(p []byte) (int, error) { - n := copy(p, b.buf[b.lastRead:b.pos]) - b.lastRead += n - return n, nil -} - -func (b *fixedBuffer) Len() int { - return b.pos - b.lastRead -} - -func (b *fixedBuffer) Cap() int { - return cap(b.buf) -} - -func (b *fixedBuffer) Reset() { - b.pos = 0 - b.lastRead = 0 - b.buf = b.buf[:0] -} - -func (b *fixedBuffer) String() string { - return string(b.buf[b.lastRead:b.pos]) -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go b/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go deleted file mode 100644 index 72a04f349..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go +++ /dev/null @@ -1,186 +0,0 @@ -package ioutils - -import ( - "errors" - "io" - "sync" -) - -// maxCap is the highest capacity to use in byte slices that buffer data. -const maxCap = 1e6 - -// minCap is the lowest capacity to use in byte slices that buffer data -const minCap = 64 - -// blockThreshold is the minimum number of bytes in the buffer which will cause -// a write to BytesPipe to block when allocating a new slice. -const blockThreshold = 1e6 - -var ( - // ErrClosed is returned when Write is called on a closed BytesPipe. - ErrClosed = errors.New("write to closed BytesPipe") - - bufPools = make(map[int]*sync.Pool) - bufPoolsLock sync.Mutex -) - -// BytesPipe is io.ReadWriteCloser which works similarly to pipe(queue). -// All written data may be read at most once. Also, BytesPipe allocates -// and releases new byte slices to adjust to current needs, so the buffer -// won't be overgrown after peak loads. -type BytesPipe struct { - mu sync.Mutex - wait *sync.Cond - buf []*fixedBuffer - bufLen int - closeErr error // error to return from next Read. set to nil if not closed. -} - -// NewBytesPipe creates new BytesPipe, initialized by specified slice. -// If buf is nil, then it will be initialized with slice which cap is 64. -// buf will be adjusted in a way that len(buf) == 0, cap(buf) == cap(buf). -func NewBytesPipe() *BytesPipe { - bp := &BytesPipe{} - bp.buf = append(bp.buf, getBuffer(minCap)) - bp.wait = sync.NewCond(&bp.mu) - return bp -} - -// Write writes p to BytesPipe. -// It can allocate new []byte slices in a process of writing. -func (bp *BytesPipe) Write(p []byte) (int, error) { - bp.mu.Lock() - - written := 0 -loop0: - for { - if bp.closeErr != nil { - bp.mu.Unlock() - return written, ErrClosed - } - - if len(bp.buf) == 0 { - bp.buf = append(bp.buf, getBuffer(64)) - } - // get the last buffer - b := bp.buf[len(bp.buf)-1] - - n, err := b.Write(p) - written += n - bp.bufLen += n - - // errBufferFull is an error we expect to get if the buffer is full - if err != nil && err != errBufferFull { - bp.wait.Broadcast() - bp.mu.Unlock() - return written, err - } - - // if there was enough room to write all then break - if len(p) == n { - break - } - - // more data: write to the next slice - p = p[n:] - - // make sure the buffer doesn't grow too big from this write - for bp.bufLen >= blockThreshold { - bp.wait.Wait() - if bp.closeErr != nil { - continue loop0 - } - } - - // add new byte slice to the buffers slice and continue writing - nextCap := b.Cap() * 2 - if nextCap > maxCap { - nextCap = maxCap - } - bp.buf = append(bp.buf, getBuffer(nextCap)) - } - bp.wait.Broadcast() - bp.mu.Unlock() - return written, nil -} - -// CloseWithError causes further reads from a BytesPipe to return immediately. -func (bp *BytesPipe) CloseWithError(err error) error { - bp.mu.Lock() - if err != nil { - bp.closeErr = err - } else { - bp.closeErr = io.EOF - } - bp.wait.Broadcast() - bp.mu.Unlock() - return nil -} - -// Close causes further reads from a BytesPipe to return immediately. -func (bp *BytesPipe) Close() error { - return bp.CloseWithError(nil) -} - -// Read reads bytes from BytesPipe. -// Data could be read only once. -func (bp *BytesPipe) Read(p []byte) (n int, err error) { - bp.mu.Lock() - if bp.bufLen == 0 { - if bp.closeErr != nil { - bp.mu.Unlock() - return 0, bp.closeErr - } - bp.wait.Wait() - if bp.bufLen == 0 && bp.closeErr != nil { - err := bp.closeErr - bp.mu.Unlock() - return 0, err - } - } - - for bp.bufLen > 0 { - b := bp.buf[0] - read, _ := b.Read(p) // ignore error since fixedBuffer doesn't really return an error - n += read - bp.bufLen -= read - - if b.Len() == 0 { - // it's empty so return it to the pool and move to the next one - returnBuffer(b) - bp.buf[0] = nil - bp.buf = bp.buf[1:] - } - - if len(p) == read { - break - } - - p = p[read:] - } - - bp.wait.Broadcast() - bp.mu.Unlock() - return -} - -func returnBuffer(b *fixedBuffer) { - b.Reset() - bufPoolsLock.Lock() - pool := bufPools[b.Cap()] - bufPoolsLock.Unlock() - if pool != nil { - pool.Put(b) - } -} - -func getBuffer(size int) *fixedBuffer { - bufPoolsLock.Lock() - pool, ok := bufPools[size] - if !ok { - pool = &sync.Pool{New: func() interface{} { return &fixedBuffer{buf: make([]byte, 0, size)} }} - bufPools[size] = pool - } - bufPoolsLock.Unlock() - return pool.Get().(*fixedBuffer) -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go b/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go deleted file mode 100644 index a56c46265..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go +++ /dev/null @@ -1,162 +0,0 @@ -package ioutils - -import ( - "io" - "io/ioutil" - "os" - "path/filepath" -) - -// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a -// temporary file and closing it atomically changes the temporary file to -// destination path. Writing and closing concurrently is not allowed. -func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { - f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename)) - if err != nil { - return nil, err - } - - abspath, err := filepath.Abs(filename) - if err != nil { - return nil, err - } - return &atomicFileWriter{ - f: f, - fn: abspath, - perm: perm, - }, nil -} - -// AtomicWriteFile atomically writes data to a file named by filename. -func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { - f, err := NewAtomicFileWriter(filename, perm) - if err != nil { - return err - } - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - f.(*atomicFileWriter).writeErr = err - } - if err1 := f.Close(); err == nil { - err = err1 - } - return err -} - -type atomicFileWriter struct { - f *os.File - fn string - writeErr error - perm os.FileMode -} - -func (w *atomicFileWriter) Write(dt []byte) (int, error) { - n, err := w.f.Write(dt) - if err != nil { - w.writeErr = err - } - return n, err -} - -func (w *atomicFileWriter) Close() (retErr error) { - defer func() { - if retErr != nil || w.writeErr != nil { - os.Remove(w.f.Name()) - } - }() - if err := w.f.Sync(); err != nil { - w.f.Close() - return err - } - if err := w.f.Close(); err != nil { - return err - } - if err := os.Chmod(w.f.Name(), w.perm); err != nil { - return err - } - if w.writeErr == nil { - return os.Rename(w.f.Name(), w.fn) - } - return nil -} - -// AtomicWriteSet is used to atomically write a set -// of files and ensure they are visible at the same time. -// Must be committed to a new directory. -type AtomicWriteSet struct { - root string -} - -// NewAtomicWriteSet creates a new atomic write set to -// atomically create a set of files. The given directory -// is used as the base directory for storing files before -// commit. If no temporary directory is given the system -// default is used. -func NewAtomicWriteSet(tmpDir string) (*AtomicWriteSet, error) { - td, err := ioutil.TempDir(tmpDir, "write-set-") - if err != nil { - return nil, err - } - - return &AtomicWriteSet{ - root: td, - }, nil -} - -// WriteFile writes a file to the set, guaranteeing the file -// has been synced. -func (ws *AtomicWriteSet) WriteFile(filename string, data []byte, perm os.FileMode) error { - f, err := ws.FileWriter(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil { - return err - } - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - } - if err1 := f.Close(); err == nil { - err = err1 - } - return err -} - -type syncFileCloser struct { - *os.File -} - -func (w syncFileCloser) Close() error { - err := w.File.Sync() - if err1 := w.File.Close(); err == nil { - err = err1 - } - return err -} - -// FileWriter opens a file writer inside the set. The file -// should be synced and closed before calling commit. -func (ws *AtomicWriteSet) FileWriter(name string, flag int, perm os.FileMode) (io.WriteCloser, error) { - f, err := os.OpenFile(filepath.Join(ws.root, name), flag, perm) - if err != nil { - return nil, err - } - return syncFileCloser{f}, nil -} - -// Cancel cancels the set and removes all temporary data -// created in the set. -func (ws *AtomicWriteSet) Cancel() error { - return os.RemoveAll(ws.root) -} - -// Commit moves all created files to the target directory. The -// target directory must not exist and the parent of the target -// directory must exist. -func (ws *AtomicWriteSet) Commit(target string) error { - return os.Rename(ws.root, target) -} - -// String returns the location the set is writing to. -func (ws *AtomicWriteSet) String() string { - return ws.root -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/readers.go b/vendor/github.com/docker/docker/pkg/ioutils/readers.go deleted file mode 100644 index 63f3c07f4..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/readers.go +++ /dev/null @@ -1,154 +0,0 @@ -package ioutils - -import ( - "crypto/sha256" - "encoding/hex" - "io" - - "golang.org/x/net/context" -) - -type readCloserWrapper struct { - io.Reader - closer func() error -} - -func (r *readCloserWrapper) Close() error { - return r.closer() -} - -// NewReadCloserWrapper returns a new io.ReadCloser. -func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { - return &readCloserWrapper{ - Reader: r, - closer: closer, - } -} - -type readerErrWrapper struct { - reader io.Reader - closer func() -} - -func (r *readerErrWrapper) Read(p []byte) (int, error) { - n, err := r.reader.Read(p) - if err != nil { - r.closer() - } - return n, err -} - -// NewReaderErrWrapper returns a new io.Reader. -func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader { - return &readerErrWrapper{ - reader: r, - closer: closer, - } -} - -// HashData returns the sha256 sum of src. -func HashData(src io.Reader) (string, error) { - h := sha256.New() - if _, err := io.Copy(h, src); err != nil { - return "", err - } - return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil -} - -// OnEOFReader wraps an io.ReadCloser and a function -// the function will run at the end of file or close the file. -type OnEOFReader struct { - Rc io.ReadCloser - Fn func() -} - -func (r *OnEOFReader) Read(p []byte) (n int, err error) { - n, err = r.Rc.Read(p) - if err == io.EOF { - r.runFunc() - } - return -} - -// Close closes the file and run the function. -func (r *OnEOFReader) Close() error { - err := r.Rc.Close() - r.runFunc() - return err -} - -func (r *OnEOFReader) runFunc() { - if fn := r.Fn; fn != nil { - fn() - r.Fn = nil - } -} - -// cancelReadCloser wraps an io.ReadCloser with a context for cancelling read -// operations. -type cancelReadCloser struct { - cancel func() - pR *io.PipeReader // Stream to read from - pW *io.PipeWriter -} - -// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the -// context is cancelled. The returned io.ReadCloser must be closed when it is -// no longer needed. -func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser { - pR, pW := io.Pipe() - - // Create a context used to signal when the pipe is closed - doneCtx, cancel := context.WithCancel(context.Background()) - - p := &cancelReadCloser{ - cancel: cancel, - pR: pR, - pW: pW, - } - - go func() { - _, err := io.Copy(pW, in) - select { - case <-ctx.Done(): - // If the context was closed, p.closeWithError - // was already called. Calling it again would - // change the error that Read returns. - default: - p.closeWithError(err) - } - in.Close() - }() - go func() { - for { - select { - case <-ctx.Done(): - p.closeWithError(ctx.Err()) - case <-doneCtx.Done(): - return - } - } - }() - - return p -} - -// Read wraps the Read method of the pipe that provides data from the wrapped -// ReadCloser. -func (p *cancelReadCloser) Read(buf []byte) (n int, err error) { - return p.pR.Read(buf) -} - -// closeWithError closes the wrapper and its underlying reader. It will -// cause future calls to Read to return err. -func (p *cancelReadCloser) closeWithError(err error) { - p.pW.CloseWithError(err) - p.cancel() -} - -// Close closes the wrapper its underlying reader. It will cause -// future calls to Read to return io.EOF. -func (p *cancelReadCloser) Close() error { - p.closeWithError(io.EOF) - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go b/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go deleted file mode 100644 index 1539ad21b..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build !windows - -package ioutils - -import "io/ioutil" - -// TempDir on Unix systems is equivalent to ioutil.TempDir. -func TempDir(dir, prefix string) (string, error) { - return ioutil.TempDir(dir, prefix) -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go b/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go deleted file mode 100644 index c258e5fdd..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build windows - -package ioutils - -import ( - "io/ioutil" - - "github.com/docker/docker/pkg/longpath" -) - -// TempDir is the equivalent of ioutil.TempDir, except that the result is in Windows longpath format. -func TempDir(dir, prefix string) (string, error) { - tempDir, err := ioutil.TempDir(dir, prefix) - if err != nil { - return "", err - } - return longpath.AddPrefix(tempDir), nil -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go b/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go deleted file mode 100644 index 52a4901ad..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go +++ /dev/null @@ -1,92 +0,0 @@ -package ioutils - -import ( - "io" - "sync" -) - -// WriteFlusher wraps the Write and Flush operation ensuring that every write -// is a flush. In addition, the Close method can be called to intercept -// Read/Write calls if the targets lifecycle has already ended. -type WriteFlusher struct { - w io.Writer - flusher flusher - flushed chan struct{} - flushedOnce sync.Once - closed chan struct{} - closeLock sync.Mutex -} - -type flusher interface { - Flush() -} - -var errWriteFlusherClosed = io.EOF - -func (wf *WriteFlusher) Write(b []byte) (n int, err error) { - select { - case <-wf.closed: - return 0, errWriteFlusherClosed - default: - } - - n, err = wf.w.Write(b) - wf.Flush() // every write is a flush. - return n, err -} - -// Flush the stream immediately. -func (wf *WriteFlusher) Flush() { - select { - case <-wf.closed: - return - default: - } - - wf.flushedOnce.Do(func() { - close(wf.flushed) - }) - wf.flusher.Flush() -} - -// Flushed returns the state of flushed. -// If it's flushed, return true, or else it return false. -func (wf *WriteFlusher) Flushed() bool { - // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to - // be used to detect whether or a response code has been issued or not. - // Another hook should be used instead. - var flushed bool - select { - case <-wf.flushed: - flushed = true - default: - } - return flushed -} - -// Close closes the write flusher, disallowing any further writes to the -// target. After the flusher is closed, all calls to write or flush will -// result in an error. -func (wf *WriteFlusher) Close() error { - wf.closeLock.Lock() - defer wf.closeLock.Unlock() - - select { - case <-wf.closed: - return errWriteFlusherClosed - default: - close(wf.closed) - } - return nil -} - -// NewWriteFlusher returns a new WriteFlusher. -func NewWriteFlusher(w io.Writer) *WriteFlusher { - var fl flusher - if f, ok := w.(flusher); ok { - fl = f - } else { - fl = &NopFlusher{} - } - return &WriteFlusher{w: w, flusher: fl, closed: make(chan struct{}), flushed: make(chan struct{})} -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writers.go b/vendor/github.com/docker/docker/pkg/ioutils/writers.go deleted file mode 100644 index ccc7f9c23..000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/writers.go +++ /dev/null @@ -1,66 +0,0 @@ -package ioutils - -import "io" - -// NopWriter represents a type which write operation is nop. -type NopWriter struct{} - -func (*NopWriter) Write(buf []byte) (int, error) { - return len(buf), nil -} - -type nopWriteCloser struct { - io.Writer -} - -func (w *nopWriteCloser) Close() error { return nil } - -// NopWriteCloser returns a nopWriteCloser. -func NopWriteCloser(w io.Writer) io.WriteCloser { - return &nopWriteCloser{w} -} - -// NopFlusher represents a type which flush operation is nop. -type NopFlusher struct{} - -// Flush is a nop operation. -func (f *NopFlusher) Flush() {} - -type writeCloserWrapper struct { - io.Writer - closer func() error -} - -func (r *writeCloserWrapper) Close() error { - return r.closer() -} - -// NewWriteCloserWrapper returns a new io.WriteCloser. -func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { - return &writeCloserWrapper{ - Writer: r, - closer: closer, - } -} - -// WriteCounter wraps a concrete io.Writer and hold a count of the number -// of bytes written to the writer during a "session". -// This can be convenient when write return is masked -// (e.g., json.Encoder.Encode()) -type WriteCounter struct { - Count int64 - Writer io.Writer -} - -// NewWriteCounter returns a new WriteCounter. -func NewWriteCounter(w io.Writer) *WriteCounter { - return &WriteCounter{ - Writer: w, - } -} - -func (wc *WriteCounter) Write(p []byte) (count int, err error) { - count, err = wc.Writer.Write(p) - wc.Count += int64(count) - return -} diff --git a/vendor/github.com/docker/docker/pkg/longpath/longpath.go b/vendor/github.com/docker/docker/pkg/longpath/longpath.go deleted file mode 100644 index 9b15bfff4..000000000 --- a/vendor/github.com/docker/docker/pkg/longpath/longpath.go +++ /dev/null @@ -1,26 +0,0 @@ -// longpath introduces some constants and helper functions for handling long paths -// in Windows, which are expected to be prepended with `\\?\` and followed by either -// a drive letter, a UNC server\share, or a volume identifier. - -package longpath - -import ( - "strings" -) - -// Prefix is the longpath prefix for Windows file paths. -const Prefix = `\\?\` - -// AddPrefix will add the Windows long path prefix to the path provided if -// it does not already have it. -func AddPrefix(path string) string { - if !strings.HasPrefix(path, Prefix) { - if strings.HasPrefix(path, `\\`) { - // This is a UNC path, so we need to add 'UNC' to the path as well. - path = Prefix + `UNC` + path[1:] - } else { - path = Prefix + path - } - } - return path -} diff --git a/vendor/github.com/docker/docker/pkg/mount/flags.go b/vendor/github.com/docker/docker/pkg/mount/flags.go deleted file mode 100644 index 607dbed43..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/flags.go +++ /dev/null @@ -1,149 +0,0 @@ -package mount - -import ( - "fmt" - "strings" -) - -var flags = map[string]struct { - clear bool - flag int -}{ - "defaults": {false, 0}, - "ro": {false, RDONLY}, - "rw": {true, RDONLY}, - "suid": {true, NOSUID}, - "nosuid": {false, NOSUID}, - "dev": {true, NODEV}, - "nodev": {false, NODEV}, - "exec": {true, NOEXEC}, - "noexec": {false, NOEXEC}, - "sync": {false, SYNCHRONOUS}, - "async": {true, SYNCHRONOUS}, - "dirsync": {false, DIRSYNC}, - "remount": {false, REMOUNT}, - "mand": {false, MANDLOCK}, - "nomand": {true, MANDLOCK}, - "atime": {true, NOATIME}, - "noatime": {false, NOATIME}, - "diratime": {true, NODIRATIME}, - "nodiratime": {false, NODIRATIME}, - "bind": {false, BIND}, - "rbind": {false, RBIND}, - "unbindable": {false, UNBINDABLE}, - "runbindable": {false, RUNBINDABLE}, - "private": {false, PRIVATE}, - "rprivate": {false, RPRIVATE}, - "shared": {false, SHARED}, - "rshared": {false, RSHARED}, - "slave": {false, SLAVE}, - "rslave": {false, RSLAVE}, - "relatime": {false, RELATIME}, - "norelatime": {true, RELATIME}, - "strictatime": {false, STRICTATIME}, - "nostrictatime": {true, STRICTATIME}, -} - -var validFlags = map[string]bool{ - "": true, - "size": true, - "mode": true, - "uid": true, - "gid": true, - "nr_inodes": true, - "nr_blocks": true, - "mpol": true, -} - -var propagationFlags = map[string]bool{ - "bind": true, - "rbind": true, - "unbindable": true, - "runbindable": true, - "private": true, - "rprivate": true, - "shared": true, - "rshared": true, - "slave": true, - "rslave": true, -} - -// MergeTmpfsOptions merge mount options to make sure there is no duplicate. -func MergeTmpfsOptions(options []string) ([]string, error) { - // We use collisions maps to remove duplicates. - // For flag, the key is the flag value (the key for propagation flag is -1) - // For data=value, the key is the data - flagCollisions := map[int]bool{} - dataCollisions := map[string]bool{} - - var newOptions []string - // We process in reverse order - for i := len(options) - 1; i >= 0; i-- { - option := options[i] - if option == "defaults" { - continue - } - if f, ok := flags[option]; ok && f.flag != 0 { - // There is only one propagation mode - key := f.flag - if propagationFlags[option] { - key = -1 - } - // Check to see if there is collision for flag - if !flagCollisions[key] { - // We prepend the option and add to collision map - newOptions = append([]string{option}, newOptions...) - flagCollisions[key] = true - } - continue - } - opt := strings.SplitN(option, "=", 2) - if len(opt) != 2 || !validFlags[opt[0]] { - return nil, fmt.Errorf("Invalid tmpfs option %q", opt) - } - if !dataCollisions[opt[0]] { - // We prepend the option and add to collision map - newOptions = append([]string{option}, newOptions...) - dataCollisions[opt[0]] = true - } - } - - return newOptions, nil -} - -// Parse fstab type mount options into mount() flags -// and device specific data -func parseOptions(options string) (int, string) { - var ( - flag int - data []string - ) - - for _, o := range strings.Split(options, ",") { - // If the option does not exist in the flags table or the flag - // is not supported on the platform, - // then it is a data value for a specific fs type - if f, exists := flags[o]; exists && f.flag != 0 { - if f.clear { - flag &= ^f.flag - } else { - flag |= f.flag - } - } else { - data = append(data, o) - } - } - return flag, strings.Join(data, ",") -} - -// ParseTmpfsOptions parse fstab type mount options into flags and data -func ParseTmpfsOptions(options string) (int, string, error) { - flags, data := parseOptions(options) - for _, o := range strings.Split(data, ",") { - opt := strings.SplitN(o, "=", 2) - if !validFlags[opt[0]] { - return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt) - } - } - return flags, data, nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go deleted file mode 100644 index 5f76f331b..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build freebsd,cgo - -package mount - -/* -#include -*/ -import "C" - -const ( - // RDONLY will mount the filesystem as read-only. - RDONLY = C.MNT_RDONLY - - // NOSUID will not allow set-user-identifier or set-group-identifier bits to - // take effect. - NOSUID = C.MNT_NOSUID - - // NOEXEC will not allow execution of any binaries on the mounted file system. - NOEXEC = C.MNT_NOEXEC - - // SYNCHRONOUS will allow any I/O to the file system to be done synchronously. - SYNCHRONOUS = C.MNT_SYNCHRONOUS - - // NOATIME will not update the file access time when reading from a file. - NOATIME = C.MNT_NOATIME -) - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NODEV = 0 - NODIRATIME = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIVE = 0 - RELATIME = 0 - REMOUNT = 0 - STRICTATIME = 0 - mntDetach = 0 -) diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_linux.go b/vendor/github.com/docker/docker/pkg/mount/flags_linux.go deleted file mode 100644 index 25f466183..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/flags_linux.go +++ /dev/null @@ -1,87 +0,0 @@ -package mount - -import ( - "syscall" -) - -const ( - // RDONLY will mount the file system read-only. - RDONLY = syscall.MS_RDONLY - - // NOSUID will not allow set-user-identifier or set-group-identifier bits to - // take effect. - NOSUID = syscall.MS_NOSUID - - // NODEV will not interpret character or block special devices on the file - // system. - NODEV = syscall.MS_NODEV - - // NOEXEC will not allow execution of any binaries on the mounted file system. - NOEXEC = syscall.MS_NOEXEC - - // SYNCHRONOUS will allow I/O to the file system to be done synchronously. - SYNCHRONOUS = syscall.MS_SYNCHRONOUS - - // DIRSYNC will force all directory updates within the file system to be done - // synchronously. This affects the following system calls: create, link, - // unlink, symlink, mkdir, rmdir, mknod and rename. - DIRSYNC = syscall.MS_DIRSYNC - - // REMOUNT will attempt to remount an already-mounted file system. This is - // commonly used to change the mount flags for a file system, especially to - // make a readonly file system writeable. It does not change device or mount - // point. - REMOUNT = syscall.MS_REMOUNT - - // MANDLOCK will force mandatory locks on a filesystem. - MANDLOCK = syscall.MS_MANDLOCK - - // NOATIME will not update the file access time when reading from a file. - NOATIME = syscall.MS_NOATIME - - // NODIRATIME will not update the directory access time. - NODIRATIME = syscall.MS_NODIRATIME - - // BIND remounts a subtree somewhere else. - BIND = syscall.MS_BIND - - // RBIND remounts a subtree and all possible submounts somewhere else. - RBIND = syscall.MS_BIND | syscall.MS_REC - - // UNBINDABLE creates a mount which cannot be cloned through a bind operation. - UNBINDABLE = syscall.MS_UNBINDABLE - - // RUNBINDABLE marks the entire mount tree as UNBINDABLE. - RUNBINDABLE = syscall.MS_UNBINDABLE | syscall.MS_REC - - // PRIVATE creates a mount which carries no propagation abilities. - PRIVATE = syscall.MS_PRIVATE - - // RPRIVATE marks the entire mount tree as PRIVATE. - RPRIVATE = syscall.MS_PRIVATE | syscall.MS_REC - - // SLAVE creates a mount which receives propagation from its master, but not - // vice versa. - SLAVE = syscall.MS_SLAVE - - // RSLAVE marks the entire mount tree as SLAVE. - RSLAVE = syscall.MS_SLAVE | syscall.MS_REC - - // SHARED creates a mount which provides the ability to create mirrors of - // that mount such that mounts and unmounts within any of the mirrors - // propagate to the other mirrors. - SHARED = syscall.MS_SHARED - - // RSHARED marks the entire mount tree as SHARED. - RSHARED = syscall.MS_SHARED | syscall.MS_REC - - // RELATIME updates inode access times relative to modify or change time. - RELATIME = syscall.MS_RELATIME - - // STRICTATIME allows to explicitly request full atime updates. This makes - // it possible for the kernel to default to relatime or noatime but still - // allow userspace to override it. - STRICTATIME = syscall.MS_STRICTATIME - - mntDetach = syscall.MNT_DETACH -) diff --git a/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go deleted file mode 100644 index 9ed741e3f..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go +++ /dev/null @@ -1,31 +0,0 @@ -// +build !linux,!freebsd freebsd,!cgo solaris,!cgo - -package mount - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NOATIME = 0 - NODEV = 0 - NODIRATIME = 0 - NOEXEC = 0 - NOSUID = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIME = 0 - RELATIVE = 0 - REMOUNT = 0 - STRICTATIME = 0 - SYNCHRONOUS = 0 - RDONLY = 0 - mntDetach = 0 -) diff --git a/vendor/github.com/docker/docker/pkg/mount/mount.go b/vendor/github.com/docker/docker/pkg/mount/mount.go deleted file mode 100644 index c9fdfd694..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mount.go +++ /dev/null @@ -1,86 +0,0 @@ -package mount - -import ( - "sort" - "strings" -) - -// GetMounts retrieves a list of mounts for the current running process. -func GetMounts() ([]*Info, error) { - return parseMountTable() -} - -// Mounted determines if a specified mountpoint has been mounted. -// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. -func Mounted(mountpoint string) (bool, error) { - entries, err := parseMountTable() - if err != nil { - return false, err - } - - // Search the table for the mountpoint - for _, e := range entries { - if e.Mountpoint == mountpoint { - return true, nil - } - } - return false, nil -} - -// Mount will mount filesystem according to the specified configuration, on the -// condition that the target path is *not* already mounted. Options must be -// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See -// flags.go for supported option flags. -func Mount(device, target, mType, options string) error { - flag, _ := parseOptions(options) - if flag&REMOUNT != REMOUNT { - if mounted, err := Mounted(target); err != nil || mounted { - return err - } - } - return ForceMount(device, target, mType, options) -} - -// ForceMount will mount a filesystem according to the specified configuration, -// *regardless* if the target path is not already mounted. Options must be -// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See -// flags.go for supported option flags. -func ForceMount(device, target, mType, options string) error { - flag, data := parseOptions(options) - return mount(device, target, mType, uintptr(flag), data) -} - -// Unmount lazily unmounts a filesystem on supported platforms, otherwise -// does a normal unmount. -func Unmount(target string) error { - if mounted, err := Mounted(target); err != nil || !mounted { - return err - } - return unmount(target, mntDetach) -} - -// RecursiveUnmount unmounts the target and all mounts underneath, starting with -// the deepsest mount first. -func RecursiveUnmount(target string) error { - mounts, err := GetMounts() - if err != nil { - return err - } - - // Make the deepest mount be first - sort.Sort(sort.Reverse(byMountpoint(mounts))) - - for i, m := range mounts { - if !strings.HasPrefix(m.Mountpoint, target) { - continue - } - if err := Unmount(m.Mountpoint); err != nil && i == len(mounts)-1 { - if mounted, err := Mounted(m.Mountpoint); err != nil || mounted { - return err - } - // Ignore errors for submounts and continue trying to unmount others - // The final unmount should fail if there ane any submounts remaining - } - } - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go deleted file mode 100644 index bb870e6f5..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go +++ /dev/null @@ -1,59 +0,0 @@ -package mount - -/* -#include -#include -#include -#include -#include -#include -*/ -import "C" - -import ( - "fmt" - "strings" - "syscall" - "unsafe" -) - -func allocateIOVecs(options []string) []C.struct_iovec { - out := make([]C.struct_iovec, len(options)) - for i, option := range options { - out[i].iov_base = unsafe.Pointer(C.CString(option)) - out[i].iov_len = C.size_t(len(option) + 1) - } - return out -} - -func mount(device, target, mType string, flag uintptr, data string) error { - isNullFS := false - - xs := strings.Split(data, ",") - for _, x := range xs { - if x == "bind" { - isNullFS = true - } - } - - options := []string{"fspath", target} - if isNullFS { - options = append(options, "fstype", "nullfs", "target", device) - } else { - options = append(options, "fstype", mType, "from", device) - } - rawOptions := allocateIOVecs(options) - for _, rawOption := range rawOptions { - defer C.free(rawOption.iov_base) - } - - if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { - reason := C.GoString(C.strerror(*C.__error())) - return fmt.Errorf("Failed to call nmount: %s", reason) - } - return nil -} - -func unmount(target string, flag int) error { - return syscall.Unmount(target, flag) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go b/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go deleted file mode 100644 index 3ef2ce6f0..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go +++ /dev/null @@ -1,56 +0,0 @@ -package mount - -import ( - "syscall" -) - -const ( - // ptypes is the set propagation types. - ptypes = syscall.MS_SHARED | syscall.MS_PRIVATE | syscall.MS_SLAVE | syscall.MS_UNBINDABLE - - // pflags is the full set valid flags for a change propagation call. - pflags = ptypes | syscall.MS_REC | syscall.MS_SILENT - - // broflags is the combination of bind and read only - broflags = syscall.MS_BIND | syscall.MS_RDONLY -) - -// isremount returns true if either device name or flags identify a remount request, false otherwise. -func isremount(device string, flags uintptr) bool { - switch { - // We treat device "" and "none" as a remount request to provide compatibility with - // requests that don't explicitly set MS_REMOUNT such as those manipulating bind mounts. - case flags&syscall.MS_REMOUNT != 0, device == "", device == "none": - return true - default: - return false - } -} - -func mount(device, target, mType string, flags uintptr, data string) error { - oflags := flags &^ ptypes - if !isremount(device, flags) { - // Initial call applying all non-propagation flags. - if err := syscall.Mount(device, target, mType, oflags, data); err != nil { - return err - } - } - - if flags&ptypes != 0 { - // Change the propagation type. - if err := syscall.Mount("", target, "", flags&pflags, ""); err != nil { - return err - } - } - - if oflags&broflags == broflags { - // Remount the bind to apply read only. - return syscall.Mount("", target, "", oflags|syscall.MS_REMOUNT, "") - } - - return nil -} - -func unmount(target string, flag int) error { - return syscall.Unmount(target, flag) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go b/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go deleted file mode 100644 index c684aa81f..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build solaris,cgo - -package mount - -import ( - "golang.org/x/sys/unix" - "unsafe" -) - -// #include -// #include -// #include -// int Mount(const char *spec, const char *dir, int mflag, -// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) { -// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen); -// } -import "C" - -func mount(device, target, mType string, flag uintptr, data string) error { - spec := C.CString(device) - dir := C.CString(target) - fstype := C.CString(mType) - _, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0) - C.free(unsafe.Pointer(spec)) - C.free(unsafe.Pointer(dir)) - C.free(unsafe.Pointer(fstype)) - return err -} - -func unmount(target string, flag int) error { - err := unix.Unmount(target, flag) - return err -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go deleted file mode 100644 index a2a3bb457..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo - -package mount - -func mount(device, target, mType string, flag uintptr, data string) error { - panic("Not implemented") -} - -func unmount(target string, flag int) error { - panic("Not implemented") -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo.go deleted file mode 100644 index ff4cc1d86..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo.go +++ /dev/null @@ -1,54 +0,0 @@ -package mount - -// Info reveals information about a particular mounted filesystem. This -// struct is populated from the content in the /proc//mountinfo file. -type Info struct { - // ID is a unique identifier of the mount (may be reused after umount). - ID int - - // Parent indicates the ID of the mount parent (or of self for the top of the - // mount tree). - Parent int - - // Major indicates one half of the device ID which identifies the device class. - Major int - - // Minor indicates one half of the device ID which identifies a specific - // instance of device. - Minor int - - // Root of the mount within the filesystem. - Root string - - // Mountpoint indicates the mount point relative to the process's root. - Mountpoint string - - // Opts represents mount-specific options. - Opts string - - // Optional represents optional fields. - Optional string - - // Fstype indicates the type of filesystem, such as EXT3. - Fstype string - - // Source indicates filesystem specific information or "none". - Source string - - // VfsOpts represents per super block options. - VfsOpts string -} - -type byMountpoint []*Info - -func (by byMountpoint) Len() int { - return len(by) -} - -func (by byMountpoint) Less(i, j int) bool { - return by[i].Mountpoint < by[j].Mountpoint -} - -func (by byMountpoint) Swap(i, j int) { - by[i], by[j] = by[j], by[i] -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go deleted file mode 100644 index 4f32edcd9..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go +++ /dev/null @@ -1,41 +0,0 @@ -package mount - -/* -#include -#include -#include -*/ -import "C" - -import ( - "fmt" - "reflect" - "unsafe" -) - -// Parse /proc/self/mountinfo because comparing Dev and ino does not work from -// bind mounts. -func parseMountTable() ([]*Info, error) { - var rawEntries *C.struct_statfs - - count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) - if count == 0 { - return nil, fmt.Errorf("Failed to call getmntinfo") - } - - var entries []C.struct_statfs - header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) - header.Cap = count - header.Len = count - header.Data = uintptr(unsafe.Pointer(rawEntries)) - - var out []*Info - for _, entry := range entries { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) - mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) - mountinfo.Fstype = C.GoString(&entry.f_fstypename[0]) - out = append(out, &mountinfo) - } - return out, nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go deleted file mode 100644 index be69fee1d..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go +++ /dev/null @@ -1,95 +0,0 @@ -// +build linux - -package mount - -import ( - "bufio" - "fmt" - "io" - "os" - "strings" -) - -const ( - /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - - (1) mount ID: unique identifier of the mount (may be reused after umount) - (2) parent ID: ID of parent (or of self for the top of the mount tree) - (3) major:minor: value of st_dev for files on filesystem - (4) root: root of the mount within the filesystem - (5) mount point: mount point relative to the process's root - (6) mount options: per mount options - (7) optional fields: zero or more fields of the form "tag[:value]" - (8) separator: marks the end of the optional fields - (9) filesystem type: name of filesystem of the form "type[.subtype]" - (10) mount source: filesystem specific information or "none" - (11) super options: per super block options*/ - mountinfoFormat = "%d %d %d:%d %s %s %s %s" -) - -// Parse /proc/self/mountinfo because comparing Dev and ino does not work from -// bind mounts -func parseMountTable() ([]*Info, error) { - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} - -func parseInfoFile(r io.Reader) ([]*Info, error) { - var ( - s = bufio.NewScanner(r) - out = []*Info{} - ) - - for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - - var ( - p = &Info{} - text = s.Text() - optionalFields string - ) - - if _, err := fmt.Sscanf(text, mountinfoFormat, - &p.ID, &p.Parent, &p.Major, &p.Minor, - &p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil { - return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) - } - // Safe as mountinfo encodes mountpoints with spaces as \040. - index := strings.Index(text, " - ") - postSeparatorFields := strings.Fields(text[index+3:]) - if len(postSeparatorFields) < 3 { - return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) - } - - if optionalFields != "-" { - p.Optional = optionalFields - } - - p.Fstype = postSeparatorFields[0] - p.Source = postSeparatorFields[1] - p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") - out = append(out, p) - } - return out, nil -} - -// PidMountInfo collects the mounts for a specific process ID. If the process -// ID is unknown, it is better to use `GetMounts` which will inspect -// "/proc/self/mountinfo" instead. -func PidMountInfo(pid int) ([]*Info, error) { - f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go deleted file mode 100644 index ad9ab57f8..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go +++ /dev/null @@ -1,37 +0,0 @@ -// +build solaris,cgo - -package mount - -/* -#include -#include -*/ -import "C" - -import ( - "fmt" -) - -func parseMountTable() ([]*Info, error) { - mnttab := C.fopen(C.CString(C.MNTTAB), C.CString("r")) - if mnttab == nil { - return nil, fmt.Errorf("Failed to open %s", C.MNTTAB) - } - - var out []*Info - var mp C.struct_mnttab - - ret := C.getmntent(mnttab, &mp) - for ret == 0 { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(mp.mnt_mountp) - mountinfo.Source = C.GoString(mp.mnt_special) - mountinfo.Fstype = C.GoString(mp.mnt_fstype) - mountinfo.Opts = C.GoString(mp.mnt_mntopts) - out = append(out, &mountinfo) - ret = C.getmntent(mnttab, &mp) - } - - C.fclose(mnttab) - return out, nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go deleted file mode 100644 index 7fbcf1921..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo - -package mount - -import ( - "fmt" - "runtime" -) - -func parseMountTable() ([]*Info, error) { - return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go deleted file mode 100644 index dab8a37ed..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package mount - -func parseMountTable() ([]*Info, error) { - // Do NOT return an error! - return nil, nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go deleted file mode 100644 index 8ceec84bc..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go +++ /dev/null @@ -1,69 +0,0 @@ -// +build linux - -package mount - -// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "shared") -} - -// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "rshared") -} - -// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. -// See the supported options in flags.go for further reference. -func MakePrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "private") -} - -// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeRPrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "rprivate") -} - -// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "slave") -} - -// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "rslave") -} - -// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "unbindable") -} - -// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount -// option enabled. See the supported options in flags.go for further reference. -func MakeRUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "runbindable") -} - -func ensureMountedAs(mountPoint, options string) error { - mounted, err := Mounted(mountPoint) - if err != nil { - return err - } - - if !mounted { - if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { - return err - } - } - if _, err = Mounted(mountPoint); err != nil { - return err - } - - return ForceMount("", mountPoint, "none", options) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go deleted file mode 100644 index 09f6b03cb..000000000 --- a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go +++ /dev/null @@ -1,58 +0,0 @@ -// +build solaris - -package mount - -// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "shared") -} - -// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "rshared") -} - -// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. -// See the supported options in flags.go for further reference. -func MakePrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "private") -} - -// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeRPrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "rprivate") -} - -// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "slave") -} - -// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "rslave") -} - -// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "unbindable") -} - -// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount -// option enabled. See the supported options in flags.go for further reference. -func MakeRUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "runbindable") -} - -func ensureMountedAs(mountPoint, options string) error { - // TODO: Solaris does not support bind mounts. - // Evaluate lofs and also look at the relevant - // mount flags to be supported. - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/chtimes.go b/vendor/github.com/docker/docker/pkg/system/chtimes.go deleted file mode 100644 index 056d19954..000000000 --- a/vendor/github.com/docker/docker/pkg/system/chtimes.go +++ /dev/null @@ -1,35 +0,0 @@ -package system - -import ( - "os" - "time" -) - -// Chtimes changes the access time and modified time of a file at the given path -func Chtimes(name string, atime time.Time, mtime time.Time) error { - unixMinTime := time.Unix(0, 0) - unixMaxTime := maxTime - - // If the modified time is prior to the Unix Epoch, or after the - // end of Unix Time, os.Chtimes has undefined behavior - // default to Unix Epoch in this case, just in case - - if atime.Before(unixMinTime) || atime.After(unixMaxTime) { - atime = unixMinTime - } - - if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) { - mtime = unixMinTime - } - - if err := os.Chtimes(name, atime, mtime); err != nil { - return err - } - - // Take platform specific action for setting create time. - if err := setCTime(name, mtime); err != nil { - return err - } - - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go b/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go deleted file mode 100644 index 09d58bcbf..000000000 --- a/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build !windows - -package system - -import ( - "time" -) - -//setCTime will set the create time on a file. On Unix, the create -//time is updated as a side effect of setting the modified time, so -//no action is required. -func setCTime(path string, ctime time.Time) error { - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go b/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go deleted file mode 100644 index 294586846..000000000 --- a/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -// +build windows - -package system - -import ( - "syscall" - "time" -) - -//setCTime will set the create time on a file. On Windows, this requires -//calling SetFileTime and explicitly including the create time. -func setCTime(path string, ctime time.Time) error { - ctimespec := syscall.NsecToTimespec(ctime.UnixNano()) - pathp, e := syscall.UTF16PtrFromString(path) - if e != nil { - return e - } - h, e := syscall.CreateFile(pathp, - syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil, - syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) - if e != nil { - return e - } - defer syscall.Close(h) - c := syscall.NsecToFiletime(syscall.TimespecToNsec(ctimespec)) - return syscall.SetFileTime(h, &c, nil, nil) -} diff --git a/vendor/github.com/docker/docker/pkg/system/errors.go b/vendor/github.com/docker/docker/pkg/system/errors.go deleted file mode 100644 index 288318985..000000000 --- a/vendor/github.com/docker/docker/pkg/system/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package system - -import ( - "errors" -) - -var ( - // ErrNotSupportedPlatform means the platform is not supported. - ErrNotSupportedPlatform = errors.New("platform and architecture is not supported") -) diff --git a/vendor/github.com/docker/docker/pkg/system/events_windows.go b/vendor/github.com/docker/docker/pkg/system/events_windows.go deleted file mode 100644 index 3ec6d2215..000000000 --- a/vendor/github.com/docker/docker/pkg/system/events_windows.go +++ /dev/null @@ -1,85 +0,0 @@ -package system - -// This file implements syscalls for Win32 events which are not implemented -// in golang. - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var ( - procCreateEvent = modkernel32.NewProc("CreateEventW") - procOpenEvent = modkernel32.NewProc("OpenEventW") - procSetEvent = modkernel32.NewProc("SetEvent") - procResetEvent = modkernel32.NewProc("ResetEvent") - procPulseEvent = modkernel32.NewProc("PulseEvent") -) - -// CreateEvent implements win32 CreateEventW func in golang. It will create an event object. -func CreateEvent(eventAttributes *syscall.SecurityAttributes, manualReset bool, initialState bool, name string) (handle syscall.Handle, err error) { - namep, _ := syscall.UTF16PtrFromString(name) - var _p1 uint32 - if manualReset { - _p1 = 1 - } - var _p2 uint32 - if initialState { - _p2 = 1 - } - r0, _, e1 := procCreateEvent.Call(uintptr(unsafe.Pointer(eventAttributes)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(namep))) - use(unsafe.Pointer(namep)) - handle = syscall.Handle(r0) - if handle == syscall.InvalidHandle { - err = e1 - } - return -} - -// OpenEvent implements win32 OpenEventW func in golang. It opens an event object. -func OpenEvent(desiredAccess uint32, inheritHandle bool, name string) (handle syscall.Handle, err error) { - namep, _ := syscall.UTF16PtrFromString(name) - var _p1 uint32 - if inheritHandle { - _p1 = 1 - } - r0, _, e1 := procOpenEvent.Call(uintptr(desiredAccess), uintptr(_p1), uintptr(unsafe.Pointer(namep))) - use(unsafe.Pointer(namep)) - handle = syscall.Handle(r0) - if handle == syscall.InvalidHandle { - err = e1 - } - return -} - -// SetEvent implements win32 SetEvent func in golang. -func SetEvent(handle syscall.Handle) (err error) { - return setResetPulse(handle, procSetEvent) -} - -// ResetEvent implements win32 ResetEvent func in golang. -func ResetEvent(handle syscall.Handle) (err error) { - return setResetPulse(handle, procResetEvent) -} - -// PulseEvent implements win32 PulseEvent func in golang. -func PulseEvent(handle syscall.Handle) (err error) { - return setResetPulse(handle, procPulseEvent) -} - -func setResetPulse(handle syscall.Handle, proc *windows.LazyProc) (err error) { - r0, _, _ := proc.Call(uintptr(handle)) - if r0 != 0 { - err = syscall.Errno(r0) - } - return -} - -var temp unsafe.Pointer - -// use ensures a variable is kept alive without the GC freeing while still needed -func use(p unsafe.Pointer) { - temp = p -} diff --git a/vendor/github.com/docker/docker/pkg/system/exitcode.go b/vendor/github.com/docker/docker/pkg/system/exitcode.go deleted file mode 100644 index 60f0514b1..000000000 --- a/vendor/github.com/docker/docker/pkg/system/exitcode.go +++ /dev/null @@ -1,33 +0,0 @@ -package system - -import ( - "fmt" - "os/exec" - "syscall" -) - -// GetExitCode returns the ExitStatus of the specified error if its type is -// exec.ExitError, returns 0 and an error otherwise. -func GetExitCode(err error) (int, error) { - exitCode := 0 - if exiterr, ok := err.(*exec.ExitError); ok { - if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { - return procExit.ExitStatus(), nil - } - } - return exitCode, fmt.Errorf("failed to get exit code") -} - -// ProcessExitCode process the specified error and returns the exit status code -// if the error was of type exec.ExitError, returns nothing otherwise. -func ProcessExitCode(err error) (exitCode int) { - if err != nil { - var exiterr error - if exitCode, exiterr = GetExitCode(err); exiterr != nil { - // TODO: Fix this so we check the error's text. - // we've failed to retrieve exit code, so we set it to 127 - exitCode = 127 - } - } - return -} diff --git a/vendor/github.com/docker/docker/pkg/system/filesys.go b/vendor/github.com/docker/docker/pkg/system/filesys.go deleted file mode 100644 index 102565f76..000000000 --- a/vendor/github.com/docker/docker/pkg/system/filesys.go +++ /dev/null @@ -1,67 +0,0 @@ -// +build !windows - -package system - -import ( - "io/ioutil" - "os" - "path/filepath" -) - -// MkdirAllWithACL is a wrapper for MkdirAll on unix systems. -func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { - return MkdirAll(path, perm, sddl) -} - -// MkdirAll creates a directory named path along with any necessary parents, -// with permission specified by attribute perm for all dir created. -func MkdirAll(path string, perm os.FileMode, sddl string) error { - return os.MkdirAll(path, perm) -} - -// IsAbs is a platform-specific wrapper for filepath.IsAbs. -func IsAbs(path string) bool { - return filepath.IsAbs(path) -} - -// The functions below here are wrappers for the equivalents in the os and ioutils packages. -// They are passthrough on Unix platforms, and only relevant on Windows. - -// CreateSequential creates the named file with mode 0666 (before umask), truncating -// it if it already exists. If successful, methods on the returned -// File can be used for I/O; the associated file descriptor has mode -// O_RDWR. -// If there is an error, it will be of type *PathError. -func CreateSequential(name string) (*os.File, error) { - return os.Create(name) -} - -// OpenSequential opens the named file for reading. If successful, methods on -// the returned file can be used for reading; the associated file -// descriptor has mode O_RDONLY. -// If there is an error, it will be of type *PathError. -func OpenSequential(name string) (*os.File, error) { - return os.Open(name) -} - -// OpenFileSequential is the generalized open call; most users will use Open -// or Create instead. It opens the named file with specified flag -// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, -// methods on the returned File can be used for I/O. -// If there is an error, it will be of type *PathError. -func OpenFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) { - return os.OpenFile(name, flag, perm) -} - -// TempFileSequential creates a new temporary file in the directory dir -// with a name beginning with prefix, opens the file for reading -// and writing, and returns the resulting *os.File. -// If dir is the empty string, TempFile uses the default directory -// for temporary files (see os.TempDir). -// Multiple programs calling TempFile simultaneously -// will not choose the same file. The caller can use f.Name() -// to find the pathname of the file. It is the caller's responsibility -// to remove the file when no longer needed. -func TempFileSequential(dir, prefix string) (f *os.File, err error) { - return ioutil.TempFile(dir, prefix) -} diff --git a/vendor/github.com/docker/docker/pkg/system/filesys_windows.go b/vendor/github.com/docker/docker/pkg/system/filesys_windows.go deleted file mode 100644 index 20117db91..000000000 --- a/vendor/github.com/docker/docker/pkg/system/filesys_windows.go +++ /dev/null @@ -1,298 +0,0 @@ -// +build windows - -package system - -import ( - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "sync" - "syscall" - "time" - "unsafe" - - winio "github.com/Microsoft/go-winio" -) - -const ( - // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System - SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" - // SddlNtvmAdministratorsLocalSystem is NT VIRTUAL MACHINE\Virtual Machines plus local administrators plus NT AUTHORITY\System - SddlNtvmAdministratorsLocalSystem = "D:P(A;OICI;GA;;;S-1-5-83-0)(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" -) - -// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory -// with an appropriate SDDL defined ACL. -func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { - return mkdirall(path, true, sddl) -} - -// MkdirAll implementation that is volume path aware for Windows. -func MkdirAll(path string, _ os.FileMode, sddl string) error { - return mkdirall(path, false, sddl) -} - -// mkdirall is a custom version of os.MkdirAll modified for use on Windows -// so that it is both volume path aware, and can create a directory with -// a DACL. -func mkdirall(path string, applyACL bool, sddl string) error { - if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { - return nil - } - - // The rest of this method is largely copied from os.MkdirAll and should be kept - // as-is to ensure compatibility. - - // Fast path: if we can tell whether path is a directory or file, stop with success or error. - dir, err := os.Stat(path) - if err == nil { - if dir.IsDir() { - return nil - } - return &os.PathError{ - Op: "mkdir", - Path: path, - Err: syscall.ENOTDIR, - } - } - - // Slow path: make sure parent exists and then call Mkdir for path. - i := len(path) - for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. - i-- - } - - j := i - for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. - j-- - } - - if j > 1 { - // Create parent - err = mkdirall(path[0:j-1], false, sddl) - if err != nil { - return err - } - } - - // Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result. - if applyACL { - err = mkdirWithACL(path, sddl) - } else { - err = os.Mkdir(path, 0) - } - - if err != nil { - // Handle arguments like "foo/." by - // double-checking that directory doesn't exist. - dir, err1 := os.Lstat(path) - if err1 == nil && dir.IsDir() { - return nil - } - return err - } - return nil -} - -// mkdirWithACL creates a new directory. If there is an error, it will be of -// type *PathError. . -// -// This is a modified and combined version of os.Mkdir and syscall.Mkdir -// in golang to cater for creating a directory am ACL permitting full -// access, with inheritance, to any subfolder/file for Built-in Administrators -// and Local System. -func mkdirWithACL(name string, sddl string) error { - sa := syscall.SecurityAttributes{Length: 0} - - sd, err := winio.SddlToSecurityDescriptor(sddl) - if err != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: err} - } - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0])) - - namep, err := syscall.UTF16PtrFromString(name) - if err != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: err} - } - - e := syscall.CreateDirectory(namep, &sa) - if e != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: e} - } - return nil -} - -// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows, -// golang filepath.IsAbs does not consider a path \windows\system32 as absolute -// as it doesn't start with a drive-letter/colon combination. However, in -// docker we need to verify things such as WORKDIR /windows/system32 in -// a Dockerfile (which gets translated to \windows\system32 when being processed -// by the daemon. This SHOULD be treated as absolute from a docker processing -// perspective. -func IsAbs(path string) bool { - if !filepath.IsAbs(path) { - if !strings.HasPrefix(path, string(os.PathSeparator)) { - return false - } - } - return true -} - -// The origin of the functions below here are the golang OS and syscall packages, -// slightly modified to only cope with files, not directories due to the -// specific use case. -// -// The alteration is to allow a file on Windows to be opened with -// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating -// the standby list, particularly when accessing large files such as layer.tar. - -// CreateSequential creates the named file with mode 0666 (before umask), truncating -// it if it already exists. If successful, methods on the returned -// File can be used for I/O; the associated file descriptor has mode -// O_RDWR. -// If there is an error, it will be of type *PathError. -func CreateSequential(name string) (*os.File, error) { - return OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0) -} - -// OpenSequential opens the named file for reading. If successful, methods on -// the returned file can be used for reading; the associated file -// descriptor has mode O_RDONLY. -// If there is an error, it will be of type *PathError. -func OpenSequential(name string) (*os.File, error) { - return OpenFileSequential(name, os.O_RDONLY, 0) -} - -// OpenFileSequential is the generalized open call; most users will use Open -// or Create instead. -// If there is an error, it will be of type *PathError. -func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) { - if name == "" { - return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT} - } - r, errf := syscallOpenFileSequential(name, flag, 0) - if errf == nil { - return r, nil - } - return nil, &os.PathError{Op: "open", Path: name, Err: errf} -} - -func syscallOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { - r, e := syscallOpenSequential(name, flag|syscall.O_CLOEXEC, 0) - if e != nil { - return nil, e - } - return os.NewFile(uintptr(r), name), nil -} - -func makeInheritSa() *syscall.SecurityAttributes { - var sa syscall.SecurityAttributes - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - return &sa -} - -func syscallOpenSequential(path string, mode int, _ uint32) (fd syscall.Handle, err error) { - if len(path) == 0 { - return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND - } - pathp, err := syscall.UTF16PtrFromString(path) - if err != nil { - return syscall.InvalidHandle, err - } - var access uint32 - switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) { - case syscall.O_RDONLY: - access = syscall.GENERIC_READ - case syscall.O_WRONLY: - access = syscall.GENERIC_WRITE - case syscall.O_RDWR: - access = syscall.GENERIC_READ | syscall.GENERIC_WRITE - } - if mode&syscall.O_CREAT != 0 { - access |= syscall.GENERIC_WRITE - } - if mode&syscall.O_APPEND != 0 { - access &^= syscall.GENERIC_WRITE - access |= syscall.FILE_APPEND_DATA - } - sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE) - var sa *syscall.SecurityAttributes - if mode&syscall.O_CLOEXEC == 0 { - sa = makeInheritSa() - } - var createmode uint32 - switch { - case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL): - createmode = syscall.CREATE_NEW - case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC): - createmode = syscall.CREATE_ALWAYS - case mode&syscall.O_CREAT == syscall.O_CREAT: - createmode = syscall.OPEN_ALWAYS - case mode&syscall.O_TRUNC == syscall.O_TRUNC: - createmode = syscall.TRUNCATE_EXISTING - default: - createmode = syscall.OPEN_EXISTING - } - // Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang. - //https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx - const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN - h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0) - return h, e -} - -// Helpers for TempFileSequential -var rand uint32 -var randmu sync.Mutex - -func reseed() uint32 { - return uint32(time.Now().UnixNano() + int64(os.Getpid())) -} -func nextSuffix() string { - randmu.Lock() - r := rand - if r == 0 { - r = reseed() - } - r = r*1664525 + 1013904223 // constants from Numerical Recipes - rand = r - randmu.Unlock() - return strconv.Itoa(int(1e9 + r%1e9))[1:] -} - -// TempFileSequential is a copy of ioutil.TempFile, modified to use sequential -// file access. Below is the original comment from golang: -// TempFile creates a new temporary file in the directory dir -// with a name beginning with prefix, opens the file for reading -// and writing, and returns the resulting *os.File. -// If dir is the empty string, TempFile uses the default directory -// for temporary files (see os.TempDir). -// Multiple programs calling TempFile simultaneously -// will not choose the same file. The caller can use f.Name() -// to find the pathname of the file. It is the caller's responsibility -// to remove the file when no longer needed. -func TempFileSequential(dir, prefix string) (f *os.File, err error) { - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - name := filepath.Join(dir, prefix+nextSuffix()) - f, err = OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - break - } - return -} diff --git a/vendor/github.com/docker/docker/pkg/system/init.go b/vendor/github.com/docker/docker/pkg/system/init.go deleted file mode 100644 index 17935088d..000000000 --- a/vendor/github.com/docker/docker/pkg/system/init.go +++ /dev/null @@ -1,22 +0,0 @@ -package system - -import ( - "syscall" - "time" - "unsafe" -) - -// Used by chtimes -var maxTime time.Time - -func init() { - // chtimes initialization - if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { - // This is a 64 bit timespec - // os.Chtimes limits time to the following - maxTime = time.Unix(0, 1<<63-1) - } else { - // This is a 32 bit timespec - maxTime = time.Unix(1<<31-1, 0) - } -} diff --git a/vendor/github.com/docker/docker/pkg/system/init_windows.go b/vendor/github.com/docker/docker/pkg/system/init_windows.go deleted file mode 100644 index 019c66441..000000000 --- a/vendor/github.com/docker/docker/pkg/system/init_windows.go +++ /dev/null @@ -1,17 +0,0 @@ -package system - -import "os" - -// LCOWSupported determines if Linux Containers on Windows are supported. -// Note: This feature is in development (06/17) and enabled through an -// environment variable. At a future time, it will be enabled based -// on build number. @jhowardmsft -var lcowSupported = false - -func init() { - // LCOW initialization - if os.Getenv("LCOW_SUPPORTED") != "" { - lcowSupported = true - } - -} diff --git a/vendor/github.com/docker/docker/pkg/system/lcow_unix.go b/vendor/github.com/docker/docker/pkg/system/lcow_unix.go deleted file mode 100644 index cff33bb40..000000000 --- a/vendor/github.com/docker/docker/pkg/system/lcow_unix.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !windows - -package system - -// LCOWSupported returns true if Linux containers on Windows are supported. -func LCOWSupported() bool { - return false -} diff --git a/vendor/github.com/docker/docker/pkg/system/lcow_windows.go b/vendor/github.com/docker/docker/pkg/system/lcow_windows.go deleted file mode 100644 index e54d01e69..000000000 --- a/vendor/github.com/docker/docker/pkg/system/lcow_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package system - -// LCOWSupported returns true if Linux containers on Windows are supported. -func LCOWSupported() bool { - return lcowSupported -} diff --git a/vendor/github.com/docker/docker/pkg/system/lstat_unix.go b/vendor/github.com/docker/docker/pkg/system/lstat_unix.go deleted file mode 100644 index 62fda5bac..000000000 --- a/vendor/github.com/docker/docker/pkg/system/lstat_unix.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !windows - -package system - -import "syscall" - -// Lstat takes a path to a file and returns -// a system.StatT type pertaining to that file. -// -// Throws an error if the file does not exist -func Lstat(path string) (*StatT, error) { - s := &syscall.Stat_t{} - if err := syscall.Lstat(path, s); err != nil { - return nil, err - } - return fromStatT(s) -} diff --git a/vendor/github.com/docker/docker/pkg/system/lstat_windows.go b/vendor/github.com/docker/docker/pkg/system/lstat_windows.go deleted file mode 100644 index e51df0daf..000000000 --- a/vendor/github.com/docker/docker/pkg/system/lstat_windows.go +++ /dev/null @@ -1,14 +0,0 @@ -package system - -import "os" - -// Lstat calls os.Lstat to get a fileinfo interface back. -// This is then copied into our own locally defined structure. -func Lstat(path string) (*StatT, error) { - fi, err := os.Lstat(path) - if err != nil { - return nil, err - } - - return fromStatT(&fi) -} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo.go b/vendor/github.com/docker/docker/pkg/system/meminfo.go deleted file mode 100644 index 3b6e947e6..000000000 --- a/vendor/github.com/docker/docker/pkg/system/meminfo.go +++ /dev/null @@ -1,17 +0,0 @@ -package system - -// MemInfo contains memory statistics of the host system. -type MemInfo struct { - // Total usable RAM (i.e. physical RAM minus a few reserved bits and the - // kernel binary code). - MemTotal int64 - - // Amount of free memory. - MemFree int64 - - // Total amount of swap space available. - SwapTotal int64 - - // Amount of swap space that is currently unused. - SwapFree int64 -} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go b/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go deleted file mode 100644 index 385f1d5e7..000000000 --- a/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go +++ /dev/null @@ -1,65 +0,0 @@ -package system - -import ( - "bufio" - "io" - "os" - "strconv" - "strings" - - "github.com/docker/go-units" -) - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - file, err := os.Open("/proc/meminfo") - if err != nil { - return nil, err - } - defer file.Close() - return parseMemInfo(file) -} - -// parseMemInfo parses the /proc/meminfo file into -// a MemInfo object given an io.Reader to the file. -// Throws error if there are problems reading from the file -func parseMemInfo(reader io.Reader) (*MemInfo, error) { - meminfo := &MemInfo{} - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - // Expected format: ["MemTotal:", "1234", "kB"] - parts := strings.Fields(scanner.Text()) - - // Sanity checks: Skip malformed entries. - if len(parts) < 3 || parts[2] != "kB" { - continue - } - - // Convert to bytes. - size, err := strconv.Atoi(parts[1]) - if err != nil { - continue - } - bytes := int64(size) * units.KiB - - switch parts[0] { - case "MemTotal:": - meminfo.MemTotal = bytes - case "MemFree:": - meminfo.MemFree = bytes - case "SwapTotal:": - meminfo.SwapTotal = bytes - case "SwapFree:": - meminfo.SwapFree = bytes - } - - } - - // Handle errors that may have occurred during the reading of the file. - if err := scanner.Err(); err != nil { - return nil, err - } - - return meminfo, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go b/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go deleted file mode 100644 index 925776e78..000000000 --- a/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go +++ /dev/null @@ -1,129 +0,0 @@ -// +build solaris,cgo - -package system - -import ( - "fmt" - "unsafe" -) - -// #cgo CFLAGS: -std=c99 -// #cgo LDFLAGS: -lkstat -// #include -// #include -// #include -// #include -// #include -// #include -// struct swaptable *allocSwaptable(int num) { -// struct swaptable *st; -// struct swapent *swapent; -// st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int)); -// swapent = st->swt_ent; -// for (int i = 0; i < num; i++,swapent++) { -// swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char)); -// } -// st->swt_n = num; -// return st; -//} -// void freeSwaptable (struct swaptable *st) { -// struct swapent *swapent = st->swt_ent; -// for (int i = 0; i < st->swt_n; i++,swapent++) { -// free(swapent->ste_path); -// } -// free(st); -// } -// swapent_t getSwapEnt(swapent_t *ent, int i) { -// return ent[i]; -// } -// int64_t getPpKernel() { -// int64_t pp_kernel = 0; -// kstat_ctl_t *ksc; -// kstat_t *ks; -// kstat_named_t *knp; -// kid_t kid; -// -// if ((ksc = kstat_open()) == NULL) { -// return -1; -// } -// if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) { -// return -1; -// } -// if (((kid = kstat_read(ksc, ks, NULL)) == -1) || -// ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) { -// return -1; -// } -// switch (knp->data_type) { -// case KSTAT_DATA_UINT64: -// pp_kernel = knp->value.ui64; -// break; -// case KSTAT_DATA_UINT32: -// pp_kernel = knp->value.ui32; -// break; -// } -// pp_kernel *= sysconf(_SC_PAGESIZE); -// return (pp_kernel > 0 ? pp_kernel : -1); -// } -import "C" - -// Get the system memory info using sysconf same as prtconf -func getTotalMem() int64 { - pagesize := C.sysconf(C._SC_PAGESIZE) - npages := C.sysconf(C._SC_PHYS_PAGES) - return int64(pagesize * npages) -} - -func getFreeMem() int64 { - pagesize := C.sysconf(C._SC_PAGESIZE) - npages := C.sysconf(C._SC_AVPHYS_PAGES) - return int64(pagesize * npages) -} - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - - ppKernel := C.getPpKernel() - MemTotal := getTotalMem() - MemFree := getFreeMem() - SwapTotal, SwapFree, err := getSysSwap() - - if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 || - SwapFree < 0 { - return nil, fmt.Errorf("error getting system memory info %v\n", err) - } - - meminfo := &MemInfo{} - // Total memory is total physical memory less than memory locked by kernel - meminfo.MemTotal = MemTotal - int64(ppKernel) - meminfo.MemFree = MemFree - meminfo.SwapTotal = SwapTotal - meminfo.SwapFree = SwapFree - - return meminfo, nil -} - -func getSysSwap() (int64, int64, error) { - var tSwap int64 - var fSwap int64 - var diskblksPerPage int64 - num, err := C.swapctl(C.SC_GETNSWP, nil) - if err != nil { - return -1, -1, err - } - st := C.allocSwaptable(num) - _, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st)) - if err != nil { - C.freeSwaptable(st) - return -1, -1, err - } - - diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT) - for i := 0; i < int(num); i++ { - swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i)) - tSwap += int64(swapent.ste_pages) * diskblksPerPage - fSwap += int64(swapent.ste_free) * diskblksPerPage - } - C.freeSwaptable(st) - return tSwap, fSwap, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go b/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go deleted file mode 100644 index 3ce019dff..000000000 --- a/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !linux,!windows,!solaris - -package system - -// ReadMemInfo is not supported on platforms other than linux and windows. -func ReadMemInfo() (*MemInfo, error) { - return nil, ErrNotSupportedPlatform -} diff --git a/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go b/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go deleted file mode 100644 index 883944a4c..000000000 --- a/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go +++ /dev/null @@ -1,45 +0,0 @@ -package system - -import ( - "unsafe" - - "golang.org/x/sys/windows" -) - -var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - - procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") -) - -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx -type memorystatusex struct { - dwLength uint32 - dwMemoryLoad uint32 - ullTotalPhys uint64 - ullAvailPhys uint64 - ullTotalPageFile uint64 - ullAvailPageFile uint64 - ullTotalVirtual uint64 - ullAvailVirtual uint64 - ullAvailExtendedVirtual uint64 -} - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - msi := &memorystatusex{ - dwLength: 64, - } - r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi))) - if r1 == 0 { - return &MemInfo{}, nil - } - return &MemInfo{ - MemTotal: int64(msi.ullTotalPhys), - MemFree: int64(msi.ullAvailPhys), - SwapTotal: int64(msi.ullTotalPageFile), - SwapFree: int64(msi.ullAvailPageFile), - }, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/mknod.go b/vendor/github.com/docker/docker/pkg/system/mknod.go deleted file mode 100644 index 73958182b..000000000 --- a/vendor/github.com/docker/docker/pkg/system/mknod.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build !windows - -package system - -import ( - "syscall" -) - -// Mknod creates a filesystem node (file, device special file or named pipe) named path -// with attributes specified by mode and dev. -func Mknod(path string, mode uint32, dev int) error { - return syscall.Mknod(path, mode, dev) -} - -// Mkdev is used to build the value of linux devices (in /dev/) which specifies major -// and minor number of the newly created device special file. -// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. -// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, -// then the top 12 bits of the minor. -func Mkdev(major int64, minor int64) uint32 { - return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff)) -} diff --git a/vendor/github.com/docker/docker/pkg/system/mknod_windows.go b/vendor/github.com/docker/docker/pkg/system/mknod_windows.go deleted file mode 100644 index 2e863c021..000000000 --- a/vendor/github.com/docker/docker/pkg/system/mknod_windows.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build windows - -package system - -// Mknod is not implemented on Windows. -func Mknod(path string, mode uint32, dev int) error { - return ErrNotSupportedPlatform -} - -// Mkdev is not implemented on Windows. -func Mkdev(major int64, minor int64) uint32 { - panic("Mkdev not implemented on Windows.") -} diff --git a/vendor/github.com/docker/docker/pkg/system/path.go b/vendor/github.com/docker/docker/pkg/system/path.go deleted file mode 100644 index f634a6be6..000000000 --- a/vendor/github.com/docker/docker/pkg/system/path.go +++ /dev/null @@ -1,21 +0,0 @@ -package system - -import "runtime" - -const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -// DefaultPathEnv is unix style list of directories to search for -// executables. Each directory is separated from the next by a colon -// ':' character . -func DefaultPathEnv(platform string) string { - if runtime.GOOS == "windows" { - if platform != runtime.GOOS && LCOWSupported() { - return defaultUnixPathEnv - } - // Deliberately empty on Windows containers on Windows as the default path will be set by - // the container. Docker has no context of what the default path should be. - return "" - } - return defaultUnixPathEnv - -} diff --git a/vendor/github.com/docker/docker/pkg/system/path_unix.go b/vendor/github.com/docker/docker/pkg/system/path_unix.go deleted file mode 100644 index f3762e69d..000000000 --- a/vendor/github.com/docker/docker/pkg/system/path_unix.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !windows - -package system - -// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, -// is the system drive. This is a no-op on Linux. -func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) { - return path, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/path_windows.go b/vendor/github.com/docker/docker/pkg/system/path_windows.go deleted file mode 100644 index aab891522..000000000 --- a/vendor/github.com/docker/docker/pkg/system/path_windows.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build windows - -package system - -import ( - "fmt" - "path/filepath" - "strings" -) - -// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. -// This is used, for example, when validating a user provided path in docker cp. -// If a drive letter is supplied, it must be the system drive. The drive letter -// is always removed. Also, it translates it to OS semantics (IOW / to \). We -// need the path in this syntax so that it can ultimately be concatenated with -// a Windows long-path which doesn't support drive-letters. Examples: -// C: --> Fail -// C:\ --> \ -// a --> a -// /a --> \a -// d:\ --> Fail -func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) { - if len(path) == 2 && string(path[1]) == ":" { - return "", fmt.Errorf("No relative path specified in %q", path) - } - if !filepath.IsAbs(path) || len(path) < 2 { - return filepath.FromSlash(path), nil - } - if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { - return "", fmt.Errorf("The specified path is not on the system drive (C:)") - } - return filepath.FromSlash(path[2:]), nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/process_unix.go b/vendor/github.com/docker/docker/pkg/system/process_unix.go deleted file mode 100644 index c99d796d1..000000000 --- a/vendor/github.com/docker/docker/pkg/system/process_unix.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build linux freebsd solaris darwin - -package system - -import ( - "syscall" -) - -// IsProcessAlive returns true if process with a given pid is running. -func IsProcessAlive(pid int) bool { - err := syscall.Kill(pid, syscall.Signal(0)) - if err == nil || err == syscall.EPERM { - return true - } - - return false -} - -// KillProcess force-stops a process. -func KillProcess(pid int) { - syscall.Kill(pid, syscall.SIGKILL) -} diff --git a/vendor/github.com/docker/docker/pkg/system/rm.go b/vendor/github.com/docker/docker/pkg/system/rm.go deleted file mode 100644 index 101b569a5..000000000 --- a/vendor/github.com/docker/docker/pkg/system/rm.go +++ /dev/null @@ -1,80 +0,0 @@ -package system - -import ( - "os" - "syscall" - "time" - - "github.com/docker/docker/pkg/mount" - "github.com/pkg/errors" -) - -// EnsureRemoveAll wraps `os.RemoveAll` to check for specific errors that can -// often be remedied. -// Only use `EnsureRemoveAll` if you really want to make every effort to remove -// a directory. -// -// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there -// can be a race between reading directory entries and then actually attempting -// to remove everything in the directory. -// These types of errors do not need to be returned since it's ok for the dir to -// be gone we can just retry the remove operation. -// -// This should not return a `os.ErrNotExist` kind of error under any circumstances -func EnsureRemoveAll(dir string) error { - notExistErr := make(map[string]bool) - - // track retries - exitOnErr := make(map[string]int) - maxRetry := 5 - - // Attempt to unmount anything beneath this dir first - mount.RecursiveUnmount(dir) - - for { - err := os.RemoveAll(dir) - if err == nil { - return err - } - - pe, ok := err.(*os.PathError) - if !ok { - return err - } - - if os.IsNotExist(err) { - if notExistErr[pe.Path] { - return err - } - notExistErr[pe.Path] = true - - // There is a race where some subdir can be removed but after the parent - // dir entries have been read. - // So the path could be from `os.Remove(subdir)` - // If the reported non-existent path is not the passed in `dir` we - // should just retry, but otherwise return with no error. - if pe.Path == dir { - return nil - } - continue - } - - if pe.Err != syscall.EBUSY { - return err - } - - if mounted, _ := mount.Mounted(pe.Path); mounted { - if e := mount.Unmount(pe.Path); e != nil { - if mounted, _ := mount.Mounted(pe.Path); mounted { - return errors.Wrapf(e, "error while removing %s", dir) - } - } - } - - if exitOnErr[pe.Path] == maxRetry { - return err - } - exitOnErr[pe.Path]++ - time.Sleep(100 * time.Millisecond) - } -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_darwin.go b/vendor/github.com/docker/docker/pkg/system/stat_darwin.go deleted file mode 100644 index 715f05b93..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_darwin.go +++ /dev/null @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtimespec}, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go b/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go deleted file mode 100644 index 715f05b93..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go +++ /dev/null @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtimespec}, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_linux.go b/vendor/github.com/docker/docker/pkg/system/stat_linux.go deleted file mode 100644 index 66bf6e28e..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_linux.go +++ /dev/null @@ -1,19 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtim}, nil -} - -// FromStatT converts a syscall.Stat_t type to a system.Stat_t type -// This is exposed on Linux as pkg/archive/changes uses it. -func FromStatT(s *syscall.Stat_t) (*StatT, error) { - return fromStatT(s) -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go b/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go deleted file mode 100644 index b607dea94..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go +++ /dev/null @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtim}, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_solaris.go b/vendor/github.com/docker/docker/pkg/system/stat_solaris.go deleted file mode 100644 index b607dea94..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_solaris.go +++ /dev/null @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtim}, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_unix.go b/vendor/github.com/docker/docker/pkg/system/stat_unix.go deleted file mode 100644 index 6208e7460..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_unix.go +++ /dev/null @@ -1,58 +0,0 @@ -// +build !windows - -package system - -import "syscall" - -// StatT type contains status of a file. It contains metadata -// like permission, owner, group, size, etc about a file. -type StatT struct { - mode uint32 - uid uint32 - gid uint32 - rdev uint64 - size int64 - mtim syscall.Timespec -} - -// Mode returns file's permission mode. -func (s StatT) Mode() uint32 { - return s.mode -} - -// UID returns file's user id of owner. -func (s StatT) UID() uint32 { - return s.uid -} - -// GID returns file's group id of owner. -func (s StatT) GID() uint32 { - return s.gid -} - -// Rdev returns file's device ID (if it's special file). -func (s StatT) Rdev() uint64 { - return s.rdev -} - -// Size returns file's size. -func (s StatT) Size() int64 { - return s.size -} - -// Mtim returns file's last modification time. -func (s StatT) Mtim() syscall.Timespec { - return s.mtim -} - -// Stat takes a path to a file and returns -// a system.StatT type pertaining to that file. -// -// Throws an error if the file does not exist -func Stat(path string) (*StatT, error) { - s := &syscall.Stat_t{} - if err := syscall.Stat(path, s); err != nil { - return nil, err - } - return fromStatT(s) -} diff --git a/vendor/github.com/docker/docker/pkg/system/stat_windows.go b/vendor/github.com/docker/docker/pkg/system/stat_windows.go deleted file mode 100644 index 6c6397268..000000000 --- a/vendor/github.com/docker/docker/pkg/system/stat_windows.go +++ /dev/null @@ -1,49 +0,0 @@ -package system - -import ( - "os" - "time" -) - -// StatT type contains status of a file. It contains metadata -// like permission, size, etc about a file. -type StatT struct { - mode os.FileMode - size int64 - mtim time.Time -} - -// Size returns file's size. -func (s StatT) Size() int64 { - return s.size -} - -// Mode returns file's permission mode. -func (s StatT) Mode() os.FileMode { - return os.FileMode(s.mode) -} - -// Mtim returns file's last modification time. -func (s StatT) Mtim() time.Time { - return time.Time(s.mtim) -} - -// Stat takes a path to a file and returns -// a system.StatT type pertaining to that file. -// -// Throws an error if the file does not exist -func Stat(path string) (*StatT, error) { - fi, err := os.Stat(path) - if err != nil { - return nil, err - } - return fromStatT(&fi) -} - -// fromStatT converts a os.FileInfo type to a system.StatT type -func fromStatT(fi *os.FileInfo) (*StatT, error) { - return &StatT{ - size: (*fi).Size(), - mode: (*fi).Mode(), - mtim: (*fi).ModTime()}, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/syscall_unix.go b/vendor/github.com/docker/docker/pkg/system/syscall_unix.go deleted file mode 100644 index 3ae912846..000000000 --- a/vendor/github.com/docker/docker/pkg/system/syscall_unix.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build linux freebsd - -package system - -import "syscall" - -// Unmount is a platform-specific helper function to call -// the unmount syscall. -func Unmount(dest string) error { - return syscall.Unmount(dest, 0) -} - -// CommandLineToArgv should not be used on Unix. -// It simply returns commandLine in the only element in the returned array. -func CommandLineToArgv(commandLine string) ([]string, error) { - return []string{commandLine}, nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go deleted file mode 100644 index c328a6fb8..000000000 --- a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go +++ /dev/null @@ -1,122 +0,0 @@ -package system - -import ( - "syscall" - "unsafe" - - "github.com/Sirupsen/logrus" -) - -var ( - ntuserApiset = syscall.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") - procGetVersionExW = modkernel32.NewProc("GetVersionExW") - procGetProductInfo = modkernel32.NewProc("GetProductInfo") -) - -// OSVersion is a wrapper for Windows version information -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx -type OSVersion struct { - Version uint32 - MajorVersion uint8 - MinorVersion uint8 - Build uint16 -} - -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx -type osVersionInfoEx struct { - OSVersionInfoSize uint32 - MajorVersion uint32 - MinorVersion uint32 - BuildNumber uint32 - PlatformID uint32 - CSDVersion [128]uint16 - ServicePackMajor uint16 - ServicePackMinor uint16 - SuiteMask uint16 - ProductType byte - Reserve byte -} - -// GetOSVersion gets the operating system version on Windows. Note that -// docker.exe must be manifested to get the correct version information. -func GetOSVersion() OSVersion { - var err error - osv := OSVersion{} - osv.Version, err = syscall.GetVersion() - if err != nil { - // GetVersion never fails. - panic(err) - } - osv.MajorVersion = uint8(osv.Version & 0xFF) - osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) - osv.Build = uint16(osv.Version >> 16) - return osv -} - -// IsWindowsClient returns true if the SKU is client -// @engine maintainers - this function should not be removed or modified as it -// is used to enforce licensing restrictions on Windows. -func IsWindowsClient() bool { - osviex := &osVersionInfoEx{OSVersionInfoSize: 284} - r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex))) - if r1 == 0 { - logrus.Warnf("GetVersionExW failed - assuming server SKU: %v", err) - return false - } - const verNTWorkstation = 0x00000001 - return osviex.ProductType == verNTWorkstation -} - -// IsIoTCore returns true if the currently running image is based off of -// Windows 10 IoT Core. -// @engine maintainers - this function should not be removed or modified as it -// is used to enforce licensing restrictions on Windows. -func IsIoTCore() bool { - var returnedProductType uint32 - r1, _, err := procGetProductInfo.Call(6, 1, 0, 0, uintptr(unsafe.Pointer(&returnedProductType))) - if r1 == 0 { - logrus.Warnf("GetProductInfo failed - assuming this is not IoT: %v", err) - return false - } - const productIoTUAP = 0x0000007B - const productIoTUAPCommercial = 0x00000083 - return returnedProductType == productIoTUAP || returnedProductType == productIoTUAPCommercial -} - -// Unmount is a platform-specific helper function to call -// the unmount syscall. Not supported on Windows -func Unmount(dest string) error { - return nil -} - -// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array. -func CommandLineToArgv(commandLine string) ([]string, error) { - var argc int32 - - argsPtr, err := syscall.UTF16PtrFromString(commandLine) - if err != nil { - return nil, err - } - - argv, err := syscall.CommandLineToArgv(argsPtr, &argc) - if err != nil { - return nil, err - } - defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv)))) - - newArgs := make([]string, argc) - for i, v := range (*argv)[:argc] { - newArgs[i] = string(syscall.UTF16ToString((*v)[:])) - } - - return newArgs, nil -} - -// HasWin32KSupport determines whether containers that depend on win32k can -// run on this machine. Win32k is the driver used to implement windowing. -func HasWin32KSupport() bool { - // For now, check for ntuser API support on the host. In the future, a host - // may support win32k in containers even if the host does not support ntuser - // APIs. - return ntuserApiset.Load() == nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/umask.go b/vendor/github.com/docker/docker/pkg/system/umask.go deleted file mode 100644 index 3d0146b01..000000000 --- a/vendor/github.com/docker/docker/pkg/system/umask.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !windows - -package system - -import ( - "syscall" -) - -// Umask sets current process's file mode creation mask to newmask -// and returns oldmask. -func Umask(newmask int) (oldmask int, err error) { - return syscall.Umask(newmask), nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/umask_windows.go b/vendor/github.com/docker/docker/pkg/system/umask_windows.go deleted file mode 100644 index 13f1de176..000000000 --- a/vendor/github.com/docker/docker/pkg/system/umask_windows.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build windows - -package system - -// Umask is not supported on the windows platform. -func Umask(newmask int) (oldmask int, err error) { - // should not be called on cli code path - return 0, ErrNotSupportedPlatform -} diff --git a/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go b/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go deleted file mode 100644 index e2eac3b55..000000000 --- a/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go +++ /dev/null @@ -1,22 +0,0 @@ -package system - -import ( - "syscall" - "unsafe" -) - -// LUtimesNano is used to change access and modification time of the specified path. -// It's used for symbol link file because syscall.UtimesNano doesn't support a NOFOLLOW flag atm. -func LUtimesNano(path string, ts []syscall.Timespec) error { - var _path *byte - _path, err := syscall.BytePtrFromString(path) - if err != nil { - return err - } - - if _, _, err := syscall.Syscall(syscall.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != syscall.ENOSYS { - return err - } - - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/utimes_linux.go b/vendor/github.com/docker/docker/pkg/system/utimes_linux.go deleted file mode 100644 index fc8a1aba9..000000000 --- a/vendor/github.com/docker/docker/pkg/system/utimes_linux.go +++ /dev/null @@ -1,26 +0,0 @@ -package system - -import ( - "syscall" - "unsafe" -) - -// LUtimesNano is used to change access and modification time of the specified path. -// It's used for symbol link file because syscall.UtimesNano doesn't support a NOFOLLOW flag atm. -func LUtimesNano(path string, ts []syscall.Timespec) error { - // These are not currently available in syscall - atFdCwd := -100 - atSymLinkNoFollow := 0x100 - - var _path *byte - _path, err := syscall.BytePtrFromString(path) - if err != nil { - return err - } - - if _, _, err := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(atFdCwd), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), uintptr(atSymLinkNoFollow), 0, 0); err != 0 && err != syscall.ENOSYS { - return err - } - - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go b/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go deleted file mode 100644 index 139714544..000000000 --- a/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build !linux,!freebsd - -package system - -import "syscall" - -// LUtimesNano is only supported on linux and freebsd. -func LUtimesNano(path string, ts []syscall.Timespec) error { - return ErrNotSupportedPlatform -} diff --git a/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go b/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go deleted file mode 100644 index d2e2c0579..000000000 --- a/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go +++ /dev/null @@ -1,63 +0,0 @@ -package system - -import ( - "syscall" - "unsafe" -) - -// Lgetxattr retrieves the value of the extended attribute identified by attr -// and associated with the given path in the file system. -// It will returns a nil slice and nil error if the xattr is not set. -func Lgetxattr(path string, attr string) ([]byte, error) { - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return nil, err - } - attrBytes, err := syscall.BytePtrFromString(attr) - if err != nil { - return nil, err - } - - dest := make([]byte, 128) - destBytes := unsafe.Pointer(&dest[0]) - sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - if errno == syscall.ENODATA { - return nil, nil - } - if errno == syscall.ERANGE { - dest = make([]byte, sz) - destBytes := unsafe.Pointer(&dest[0]) - sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - } - if errno != 0 { - return nil, errno - } - - return dest[:sz], nil -} - -var _zero uintptr - -// Lsetxattr sets the value of the extended attribute identified by attr -// and associated with the given path in the file system. -func Lsetxattr(path string, attr string, data []byte, flags int) error { - pathBytes, err := syscall.BytePtrFromString(path) - if err != nil { - return err - } - attrBytes, err := syscall.BytePtrFromString(attr) - if err != nil { - return err - } - var dataBytes unsafe.Pointer - if len(data) > 0 { - dataBytes = unsafe.Pointer(&data[0]) - } else { - dataBytes = unsafe.Pointer(&_zero) - } - _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0) - if errno != 0 { - return errno - } - return nil -} diff --git a/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go b/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go deleted file mode 100644 index 0114f2227..000000000 --- a/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !linux - -package system - -// Lgetxattr is not supported on platforms other than linux. -func Lgetxattr(path string, attr string) ([]byte, error) { - return nil, ErrNotSupportedPlatform -} - -// Lsetxattr is not supported on platforms other than linux. -func Lsetxattr(path string, attr string, data []byte, flags int) error { - return ErrNotSupportedPlatform -} diff --git a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go b/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go deleted file mode 100644 index e4dec3a5d..000000000 --- a/vendor/github.com/docker/docker/pkg/tlsconfig/tlsconfig_clone.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build go1.8 - -package tlsconfig - -import "crypto/tls" - -// Clone returns a clone of tls.Config. This function is provided for -// compatibility for go1.7 that doesn't include this method in stdlib. -func Clone(c *tls.Config) *tls.Config { - return c.Clone() -} diff --git a/vendor/github.com/docker/docker/vendor.conf b/vendor/github.com/docker/docker/vendor.conf index 98db7a977..f5a6002d5 100644 --- a/vendor/github.com/docker/docker/vendor.conf +++ b/vendor/github.com/docker/docker/vendor.conf @@ -1,33 +1,37 @@ # the following lines are in sorted order, FYI -github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62 -github.com/Microsoft/hcsshim v0.5.25 -github.com/Microsoft/go-winio v0.4.2 -github.com/Sirupsen/logrus v0.11.0 +github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 +github.com/Microsoft/hcsshim v0.6.5 +github.com/Microsoft/go-winio v0.4.5 github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git github.com/gorilla/context v1.1 github.com/gorilla/mux v1.1 -github.com/jhowardmsft/opengcs v0.0.9 +github.com/Microsoft/opengcs v0.3.4 github.com/kr/pty 5cf931ef8f github.com/mattn/go-shellwords v1.0.3 +github.com/sirupsen/logrus v1.0.3 github.com/tchap/go-patricia v2.2.6 github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 -golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 +golang.org/x/sys 8dbc5d05d6edcc104950cc299a1ce6641235bc86 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987 github.com/pmezard/go-difflib v1.0.0 +github.com/gotestyourself/gotestyourself v1.1.0 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 github.com/imdario/mergo 0.2.1 golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0 +github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8 +github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2 + #get libnetwork packages -github.com/docker/libnetwork 6426d1e66f33c0b0c8bb135b7ee547447f54d043 -github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894 +github.com/docker/libnetwork 72fd7e5495eba86e28012e39b5ed63ef9ca9a97b +github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b @@ -50,7 +54,7 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 # get graph and distribution packages -github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621 +github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c github.com/vbatts/tar-split v0.10.1 github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb @@ -61,20 +65,19 @@ github.com/pborman/uuid v1.0 google.golang.org/grpc v1.3.0 # When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly -github.com/opencontainers/runc 2d41c047c83e09a6d61d464906feb2a2f3c52aa4 https://github.com/docker/runc -github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe -github.com/opencontainers/runtime-spec d42f1eb741e6361e858d83fc75aa6893b66292c4 # specs - +github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d +github.com/opencontainers/runtime-spec v1.0.0 +github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 # libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json) -github.com/coreos/go-systemd v4 +github.com/coreos/go-systemd v15 github.com/godbus/dbus v4.0.0 github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 # gelf logging driver deps -github.com/Graylog2/go-gelf 7029da823dad4ef3a876df61065156acb703b2ea +github.com/Graylog2/go-gelf v2 github.com/fluent/fluent-logger-golang v1.2.1 # fluent-logger-golang deps @@ -82,7 +85,7 @@ github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972 github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c # fsnotify -github.com/fsnotify/fsnotify v1.2.11 +github.com/fsnotify/fsnotify v1.4.2 # awslogs deps github.com/aws/aws-sdk-go v1.4.22 @@ -100,17 +103,22 @@ github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 # containerd -github.com/containerd/containerd 3addd840653146c90a254301d6c3a663c7fd6429 -github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4 github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d -github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb +github.com/containerd/containerd 992280e8e265f491f7a624ab82f3e238be086e49 +github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6 +github.com/containerd/continuity 35d55c5e8dd23b32037d56cf97174aff3efdfa83 +github.com/containerd/cgroups f7dd103d3e4e696aa67152f6b4ddd1779a3455a9 +github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e +github.com/containerd/go-runc ed1cbe1fc31f5fb2359d3a54b6330d1a097858b7 +github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 +github.com/dmcgowan/go-tar 2e2c51242e8993c50445dab7c03c8e7febddd0cf # cluster -github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb +github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0 github.com/gogo/protobuf v0.4 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e -golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 +golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990 @@ -135,4 +143,12 @@ github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github. # metrics github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18 -github.com/opencontainers/selinux v1.0.0-rc1 +github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd + +# archive/tar +# mkdir -p ./vendor/archive +# git clone git://github.com/tonistiigi/go-1.git ./go +# git --git-dir ./go/.git --work-tree ./go checkout revert-prefix-ignore +# cp -a go/src/archive/tar ./vendor/archive/tar +# rm -rf ./go +# vndr diff --git a/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go b/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go index 1d5fa4c76..1ca0965e0 100644 --- a/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go +++ b/vendor/github.com/docker/go-connections/tlsconfig/certpool_go17.go @@ -5,8 +5,6 @@ package tlsconfig import ( "crypto/x509" "runtime" - - "github.com/Sirupsen/logrus" ) // SystemCertPool returns a copy of the system cert pool, @@ -14,7 +12,6 @@ import ( func SystemCertPool() (*x509.CertPool, error) { certpool, err := x509.SystemCertPool() if err != nil && runtime.GOOS == "windows" { - logrus.Infof("Unable to use system certificate pool: %v", err) return x509.NewCertPool(), nil } return certpool, err diff --git a/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go b/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go index 262c95e8c..9ca974539 100644 --- a/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go +++ b/vendor/github.com/docker/go-connections/tlsconfig/certpool_other.go @@ -5,12 +5,10 @@ package tlsconfig import ( "crypto/x509" - "github.com/Sirupsen/logrus" ) // SystemCertPool returns an new empty cert pool, // accessing system cert pool is supported in go 1.7 func SystemCertPool() (*x509.CertPool, error) { - logrus.Warn("Unable to use system certificate pool: requires building with go 1.7 or later") return x509.NewCertPool(), nil } diff --git a/vendor/github.com/docker/go-connections/tlsconfig/config.go b/vendor/github.com/docker/go-connections/tlsconfig/config.go index ad4b112ab..1b31bbb8b 100644 --- a/vendor/github.com/docker/go-connections/tlsconfig/config.go +++ b/vendor/github.com/docker/go-connections/tlsconfig/config.go @@ -13,7 +13,6 @@ import ( "io/ioutil" "os" - "github.com/Sirupsen/logrus" "github.com/pkg/errors" ) @@ -106,7 +105,6 @@ func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) { if !certPool.AppendCertsFromPEM(pem) { return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile) } - logrus.Debugf("Trusting %d certs", len(certPool.Subjects())) return certPool, nil } diff --git a/vendor/github.com/docker/libtrust/LICENSE b/vendor/github.com/docker/libtrust/LICENSE deleted file mode 100644 index 27448585a..000000000 --- a/vendor/github.com/docker/libtrust/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - 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 - - Copyright 2014 Docker, 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. diff --git a/vendor/github.com/docker/libtrust/README.md b/vendor/github.com/docker/libtrust/README.md deleted file mode 100644 index 8e7db3818..000000000 --- a/vendor/github.com/docker/libtrust/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# libtrust - -Libtrust is library for managing authentication and authorization using public key cryptography. - -Authentication is handled using the identity attached to the public key. -Libtrust provides multiple methods to prove possession of the private key associated with an identity. - - TLS x509 certificates - - Signature verification - - Key Challenge - -Authorization and access control is managed through a distributed trust graph. -Trust servers are used as the authorities of the trust graph and allow caching portions of the graph for faster access. - -## Copyright and license - -Code and documentation copyright 2014 Docker, inc. Code released under the Apache 2.0 license. -Docs released under Creative commons. - diff --git a/vendor/github.com/docker/libtrust/certificates.go b/vendor/github.com/docker/libtrust/certificates.go deleted file mode 100644 index 3dcca33cb..000000000 --- a/vendor/github.com/docker/libtrust/certificates.go +++ /dev/null @@ -1,175 +0,0 @@ -package libtrust - -import ( - "crypto/rand" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "io/ioutil" - "math/big" - "net" - "time" -) - -type certTemplateInfo struct { - commonName string - domains []string - ipAddresses []net.IP - isCA bool - clientAuth bool - serverAuth bool -} - -func generateCertTemplate(info *certTemplateInfo) *x509.Certificate { - // Generate a certificate template which is valid from the past week to - // 10 years from now. The usage of the certificate depends on the - // specified fields in the given certTempInfo object. - var ( - keyUsage x509.KeyUsage - extKeyUsage []x509.ExtKeyUsage - ) - - if info.isCA { - keyUsage = x509.KeyUsageCertSign - } - - if info.clientAuth { - extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageClientAuth) - } - - if info.serverAuth { - extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth) - } - - return &x509.Certificate{ - SerialNumber: big.NewInt(0), - Subject: pkix.Name{ - CommonName: info.commonName, - }, - NotBefore: time.Now().Add(-time.Hour * 24 * 7), - NotAfter: time.Now().Add(time.Hour * 24 * 365 * 10), - DNSNames: info.domains, - IPAddresses: info.ipAddresses, - IsCA: info.isCA, - KeyUsage: keyUsage, - ExtKeyUsage: extKeyUsage, - BasicConstraintsValid: info.isCA, - } -} - -func generateCert(pub PublicKey, priv PrivateKey, subInfo, issInfo *certTemplateInfo) (cert *x509.Certificate, err error) { - pubCertTemplate := generateCertTemplate(subInfo) - privCertTemplate := generateCertTemplate(issInfo) - - certDER, err := x509.CreateCertificate( - rand.Reader, pubCertTemplate, privCertTemplate, - pub.CryptoPublicKey(), priv.CryptoPrivateKey(), - ) - if err != nil { - return nil, fmt.Errorf("failed to create certificate: %s", err) - } - - cert, err = x509.ParseCertificate(certDER) - if err != nil { - return nil, fmt.Errorf("failed to parse certificate: %s", err) - } - - return -} - -// GenerateSelfSignedServerCert creates a self-signed certificate for the -// given key which is to be used for TLS servers with the given domains and -// IP addresses. -func GenerateSelfSignedServerCert(key PrivateKey, domains []string, ipAddresses []net.IP) (*x509.Certificate, error) { - info := &certTemplateInfo{ - commonName: key.KeyID(), - domains: domains, - ipAddresses: ipAddresses, - serverAuth: true, - } - - return generateCert(key.PublicKey(), key, info, info) -} - -// GenerateSelfSignedClientCert creates a self-signed certificate for the -// given key which is to be used for TLS clients. -func GenerateSelfSignedClientCert(key PrivateKey) (*x509.Certificate, error) { - info := &certTemplateInfo{ - commonName: key.KeyID(), - clientAuth: true, - } - - return generateCert(key.PublicKey(), key, info, info) -} - -// GenerateCACert creates a certificate which can be used as a trusted -// certificate authority. -func GenerateCACert(signer PrivateKey, trustedKey PublicKey) (*x509.Certificate, error) { - subjectInfo := &certTemplateInfo{ - commonName: trustedKey.KeyID(), - isCA: true, - } - issuerInfo := &certTemplateInfo{ - commonName: signer.KeyID(), - } - - return generateCert(trustedKey, signer, subjectInfo, issuerInfo) -} - -// GenerateCACertPool creates a certificate authority pool to be used for a -// TLS configuration. Any self-signed certificates issued by the specified -// trusted keys will be verified during a TLS handshake -func GenerateCACertPool(signer PrivateKey, trustedKeys []PublicKey) (*x509.CertPool, error) { - certPool := x509.NewCertPool() - - for _, trustedKey := range trustedKeys { - cert, err := GenerateCACert(signer, trustedKey) - if err != nil { - return nil, fmt.Errorf("failed to generate CA certificate: %s", err) - } - - certPool.AddCert(cert) - } - - return certPool, nil -} - -// LoadCertificateBundle loads certificates from the given file. The file should be pem encoded -// containing one or more certificates. The expected pem type is "CERTIFICATE". -func LoadCertificateBundle(filename string) ([]*x509.Certificate, error) { - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - certificates := []*x509.Certificate{} - var block *pem.Block - block, b = pem.Decode(b) - for ; block != nil; block, b = pem.Decode(b) { - if block.Type == "CERTIFICATE" { - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, err - } - certificates = append(certificates, cert) - } else { - return nil, fmt.Errorf("invalid pem block type: %s", block.Type) - } - } - - return certificates, nil -} - -// LoadCertificatePool loads a CA pool from the given file. The file should be pem encoded -// containing one or more certificates. The expected pem type is "CERTIFICATE". -func LoadCertificatePool(filename string) (*x509.CertPool, error) { - certs, err := LoadCertificateBundle(filename) - if err != nil { - return nil, err - } - pool := x509.NewCertPool() - for _, cert := range certs { - pool.AddCert(cert) - } - return pool, nil -} diff --git a/vendor/github.com/docker/libtrust/doc.go b/vendor/github.com/docker/libtrust/doc.go deleted file mode 100644 index ec5d2159c..000000000 --- a/vendor/github.com/docker/libtrust/doc.go +++ /dev/null @@ -1,9 +0,0 @@ -/* -Package libtrust provides an interface for managing authentication and -authorization using public key cryptography. Authentication is handled -using the identity attached to the public key and verified through TLS -x509 certificates, a key challenge, or signature. Authorization and -access control is managed through a trust graph distributed between -both remote trust servers and locally cached and managed data. -*/ -package libtrust diff --git a/vendor/github.com/docker/libtrust/ec_key.go b/vendor/github.com/docker/libtrust/ec_key.go deleted file mode 100644 index 00bbe4b3c..000000000 --- a/vendor/github.com/docker/libtrust/ec_key.go +++ /dev/null @@ -1,428 +0,0 @@ -package libtrust - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/x509" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "io" - "math/big" -) - -/* - * EC DSA PUBLIC KEY - */ - -// ecPublicKey implements a libtrust.PublicKey using elliptic curve digital -// signature algorithms. -type ecPublicKey struct { - *ecdsa.PublicKey - curveName string - signatureAlgorithm *signatureAlgorithm - extended map[string]interface{} -} - -func fromECPublicKey(cryptoPublicKey *ecdsa.PublicKey) (*ecPublicKey, error) { - curve := cryptoPublicKey.Curve - - switch { - case curve == elliptic.P256(): - return &ecPublicKey{cryptoPublicKey, "P-256", es256, map[string]interface{}{}}, nil - case curve == elliptic.P384(): - return &ecPublicKey{cryptoPublicKey, "P-384", es384, map[string]interface{}{}}, nil - case curve == elliptic.P521(): - return &ecPublicKey{cryptoPublicKey, "P-521", es512, map[string]interface{}{}}, nil - default: - return nil, errors.New("unsupported elliptic curve") - } -} - -// KeyType returns the key type for elliptic curve keys, i.e., "EC". -func (k *ecPublicKey) KeyType() string { - return "EC" -} - -// CurveName returns the elliptic curve identifier. -// Possible values are "P-256", "P-384", and "P-521". -func (k *ecPublicKey) CurveName() string { - return k.curveName -} - -// KeyID returns a distinct identifier which is unique to this Public Key. -func (k *ecPublicKey) KeyID() string { - return keyIDFromCryptoKey(k) -} - -func (k *ecPublicKey) String() string { - return fmt.Sprintf("EC Public Key <%s>", k.KeyID()) -} - -// Verify verifyies the signature of the data in the io.Reader using this -// PublicKey. The alg parameter should identify the digital signature -// algorithm which was used to produce the signature and should be supported -// by this public key. Returns a nil error if the signature is valid. -func (k *ecPublicKey) Verify(data io.Reader, alg string, signature []byte) error { - // For EC keys there is only one supported signature algorithm depending - // on the curve parameters. - if k.signatureAlgorithm.HeaderParam() != alg { - return fmt.Errorf("unable to verify signature: EC Public Key with curve %q does not support signature algorithm %q", k.curveName, alg) - } - - // signature is the concatenation of (r, s), base64Url encoded. - sigLength := len(signature) - expectedOctetLength := 2 * ((k.Params().BitSize + 7) >> 3) - if sigLength != expectedOctetLength { - return fmt.Errorf("signature length is %d octets long, should be %d", sigLength, expectedOctetLength) - } - - rBytes, sBytes := signature[:sigLength/2], signature[sigLength/2:] - r := new(big.Int).SetBytes(rBytes) - s := new(big.Int).SetBytes(sBytes) - - hasher := k.signatureAlgorithm.HashID().New() - _, err := io.Copy(hasher, data) - if err != nil { - return fmt.Errorf("error reading data to sign: %s", err) - } - hash := hasher.Sum(nil) - - if !ecdsa.Verify(k.PublicKey, hash, r, s) { - return errors.New("invalid signature") - } - - return nil -} - -// CryptoPublicKey returns the internal object which can be used as a -// crypto.PublicKey for use with other standard library operations. The type -// is either *rsa.PublicKey or *ecdsa.PublicKey -func (k *ecPublicKey) CryptoPublicKey() crypto.PublicKey { - return k.PublicKey -} - -func (k *ecPublicKey) toMap() map[string]interface{} { - jwk := make(map[string]interface{}) - for k, v := range k.extended { - jwk[k] = v - } - jwk["kty"] = k.KeyType() - jwk["kid"] = k.KeyID() - jwk["crv"] = k.CurveName() - - xBytes := k.X.Bytes() - yBytes := k.Y.Bytes() - octetLength := (k.Params().BitSize + 7) >> 3 - // MUST include leading zeros in the output so that x, y are each - // *octetLength* bytes long. - xBuf := make([]byte, octetLength-len(xBytes), octetLength) - yBuf := make([]byte, octetLength-len(yBytes), octetLength) - xBuf = append(xBuf, xBytes...) - yBuf = append(yBuf, yBytes...) - - jwk["x"] = joseBase64UrlEncode(xBuf) - jwk["y"] = joseBase64UrlEncode(yBuf) - - return jwk -} - -// MarshalJSON serializes this Public Key using the JWK JSON serialization format for -// elliptic curve keys. -func (k *ecPublicKey) MarshalJSON() (data []byte, err error) { - return json.Marshal(k.toMap()) -} - -// PEMBlock serializes this Public Key to DER-encoded PKIX format. -func (k *ecPublicKey) PEMBlock() (*pem.Block, error) { - derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey) - if err != nil { - return nil, fmt.Errorf("unable to serialize EC PublicKey to DER-encoded PKIX format: %s", err) - } - k.extended["kid"] = k.KeyID() // For display purposes. - return createPemBlock("PUBLIC KEY", derBytes, k.extended) -} - -func (k *ecPublicKey) AddExtendedField(field string, value interface{}) { - k.extended[field] = value -} - -func (k *ecPublicKey) GetExtendedField(field string) interface{} { - v, ok := k.extended[field] - if !ok { - return nil - } - return v -} - -func ecPublicKeyFromMap(jwk map[string]interface{}) (*ecPublicKey, error) { - // JWK key type (kty) has already been determined to be "EC". - // Need to extract 'crv', 'x', 'y', and 'kid' and check for - // consistency. - - // Get the curve identifier value. - crv, err := stringFromMap(jwk, "crv") - if err != nil { - return nil, fmt.Errorf("JWK EC Public Key curve identifier: %s", err) - } - - var ( - curve elliptic.Curve - sigAlg *signatureAlgorithm - ) - - switch { - case crv == "P-256": - curve = elliptic.P256() - sigAlg = es256 - case crv == "P-384": - curve = elliptic.P384() - sigAlg = es384 - case crv == "P-521": - curve = elliptic.P521() - sigAlg = es512 - default: - return nil, fmt.Errorf("JWK EC Public Key curve identifier not supported: %q\n", crv) - } - - // Get the X and Y coordinates for the public key point. - xB64Url, err := stringFromMap(jwk, "x") - if err != nil { - return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err) - } - x, err := parseECCoordinate(xB64Url, curve) - if err != nil { - return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err) - } - - yB64Url, err := stringFromMap(jwk, "y") - if err != nil { - return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err) - } - y, err := parseECCoordinate(yB64Url, curve) - if err != nil { - return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err) - } - - key := &ecPublicKey{ - PublicKey: &ecdsa.PublicKey{Curve: curve, X: x, Y: y}, - curveName: crv, signatureAlgorithm: sigAlg, - } - - // Key ID is optional too, but if it exists, it should match the key. - _, ok := jwk["kid"] - if ok { - kid, err := stringFromMap(jwk, "kid") - if err != nil { - return nil, fmt.Errorf("JWK EC Public Key ID: %s", err) - } - if kid != key.KeyID() { - return nil, fmt.Errorf("JWK EC Public Key ID does not match: %s", kid) - } - } - - key.extended = jwk - - return key, nil -} - -/* - * EC DSA PRIVATE KEY - */ - -// ecPrivateKey implements a JWK Private Key using elliptic curve digital signature -// algorithms. -type ecPrivateKey struct { - ecPublicKey - *ecdsa.PrivateKey -} - -func fromECPrivateKey(cryptoPrivateKey *ecdsa.PrivateKey) (*ecPrivateKey, error) { - publicKey, err := fromECPublicKey(&cryptoPrivateKey.PublicKey) - if err != nil { - return nil, err - } - - return &ecPrivateKey{*publicKey, cryptoPrivateKey}, nil -} - -// PublicKey returns the Public Key data associated with this Private Key. -func (k *ecPrivateKey) PublicKey() PublicKey { - return &k.ecPublicKey -} - -func (k *ecPrivateKey) String() string { - return fmt.Sprintf("EC Private Key <%s>", k.KeyID()) -} - -// Sign signs the data read from the io.Reader using a signature algorithm supported -// by the elliptic curve private key. If the specified hashing algorithm is -// supported by this key, that hash function is used to generate the signature -// otherwise the the default hashing algorithm for this key is used. Returns -// the signature and the name of the JWK signature algorithm used, e.g., -// "ES256", "ES384", "ES512". -func (k *ecPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) { - // Generate a signature of the data using the internal alg. - // The given hashId is only a suggestion, and since EC keys only support - // on signature/hash algorithm given the curve name, we disregard it for - // the elliptic curve JWK signature implementation. - hasher := k.signatureAlgorithm.HashID().New() - _, err = io.Copy(hasher, data) - if err != nil { - return nil, "", fmt.Errorf("error reading data to sign: %s", err) - } - hash := hasher.Sum(nil) - - r, s, err := ecdsa.Sign(rand.Reader, k.PrivateKey, hash) - if err != nil { - return nil, "", fmt.Errorf("error producing signature: %s", err) - } - rBytes, sBytes := r.Bytes(), s.Bytes() - octetLength := (k.ecPublicKey.Params().BitSize + 7) >> 3 - // MUST include leading zeros in the output - rBuf := make([]byte, octetLength-len(rBytes), octetLength) - sBuf := make([]byte, octetLength-len(sBytes), octetLength) - - rBuf = append(rBuf, rBytes...) - sBuf = append(sBuf, sBytes...) - - signature = append(rBuf, sBuf...) - alg = k.signatureAlgorithm.HeaderParam() - - return -} - -// CryptoPrivateKey returns the internal object which can be used as a -// crypto.PublicKey for use with other standard library operations. The type -// is either *rsa.PublicKey or *ecdsa.PublicKey -func (k *ecPrivateKey) CryptoPrivateKey() crypto.PrivateKey { - return k.PrivateKey -} - -func (k *ecPrivateKey) toMap() map[string]interface{} { - jwk := k.ecPublicKey.toMap() - - dBytes := k.D.Bytes() - // The length of this octet string MUST be ceiling(log-base-2(n)/8) - // octets (where n is the order of the curve). This is because the private - // key d must be in the interval [1, n-1] so the bitlength of d should be - // no larger than the bitlength of n-1. The easiest way to find the octet - // length is to take bitlength(n-1), add 7 to force a carry, and shift this - // bit sequence right by 3, which is essentially dividing by 8 and adding - // 1 if there is any remainder. Thus, the private key value d should be - // output to (bitlength(n-1)+7)>>3 octets. - n := k.ecPublicKey.Params().N - octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3 - // Create a buffer with the necessary zero-padding. - dBuf := make([]byte, octetLength-len(dBytes), octetLength) - dBuf = append(dBuf, dBytes...) - - jwk["d"] = joseBase64UrlEncode(dBuf) - - return jwk -} - -// MarshalJSON serializes this Private Key using the JWK JSON serialization format for -// elliptic curve keys. -func (k *ecPrivateKey) MarshalJSON() (data []byte, err error) { - return json.Marshal(k.toMap()) -} - -// PEMBlock serializes this Private Key to DER-encoded PKIX format. -func (k *ecPrivateKey) PEMBlock() (*pem.Block, error) { - derBytes, err := x509.MarshalECPrivateKey(k.PrivateKey) - if err != nil { - return nil, fmt.Errorf("unable to serialize EC PrivateKey to DER-encoded PKIX format: %s", err) - } - k.extended["keyID"] = k.KeyID() // For display purposes. - return createPemBlock("EC PRIVATE KEY", derBytes, k.extended) -} - -func ecPrivateKeyFromMap(jwk map[string]interface{}) (*ecPrivateKey, error) { - dB64Url, err := stringFromMap(jwk, "d") - if err != nil { - return nil, fmt.Errorf("JWK EC Private Key: %s", err) - } - - // JWK key type (kty) has already been determined to be "EC". - // Need to extract the public key information, then extract the private - // key value 'd'. - publicKey, err := ecPublicKeyFromMap(jwk) - if err != nil { - return nil, err - } - - d, err := parseECPrivateParam(dB64Url, publicKey.Curve) - if err != nil { - return nil, fmt.Errorf("JWK EC Private Key d-param: %s", err) - } - - key := &ecPrivateKey{ - ecPublicKey: *publicKey, - PrivateKey: &ecdsa.PrivateKey{ - PublicKey: *publicKey.PublicKey, - D: d, - }, - } - - return key, nil -} - -/* - * Key Generation Functions. - */ - -func generateECPrivateKey(curve elliptic.Curve) (k *ecPrivateKey, err error) { - k = new(ecPrivateKey) - k.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader) - if err != nil { - return nil, err - } - - k.ecPublicKey.PublicKey = &k.PrivateKey.PublicKey - k.extended = make(map[string]interface{}) - - return -} - -// GenerateECP256PrivateKey generates a key pair using elliptic curve P-256. -func GenerateECP256PrivateKey() (PrivateKey, error) { - k, err := generateECPrivateKey(elliptic.P256()) - if err != nil { - return nil, fmt.Errorf("error generating EC P-256 key: %s", err) - } - - k.curveName = "P-256" - k.signatureAlgorithm = es256 - - return k, nil -} - -// GenerateECP384PrivateKey generates a key pair using elliptic curve P-384. -func GenerateECP384PrivateKey() (PrivateKey, error) { - k, err := generateECPrivateKey(elliptic.P384()) - if err != nil { - return nil, fmt.Errorf("error generating EC P-384 key: %s", err) - } - - k.curveName = "P-384" - k.signatureAlgorithm = es384 - - return k, nil -} - -// GenerateECP521PrivateKey generates aß key pair using elliptic curve P-521. -func GenerateECP521PrivateKey() (PrivateKey, error) { - k, err := generateECPrivateKey(elliptic.P521()) - if err != nil { - return nil, fmt.Errorf("error generating EC P-521 key: %s", err) - } - - k.curveName = "P-521" - k.signatureAlgorithm = es512 - - return k, nil -} diff --git a/vendor/github.com/docker/libtrust/filter.go b/vendor/github.com/docker/libtrust/filter.go deleted file mode 100644 index 5b2b4fca6..000000000 --- a/vendor/github.com/docker/libtrust/filter.go +++ /dev/null @@ -1,50 +0,0 @@ -package libtrust - -import ( - "path/filepath" -) - -// FilterByHosts filters the list of PublicKeys to only those which contain a -// 'hosts' pattern which matches the given host. If *includeEmpty* is true, -// then keys which do not specify any hosts are also returned. -func FilterByHosts(keys []PublicKey, host string, includeEmpty bool) ([]PublicKey, error) { - filtered := make([]PublicKey, 0, len(keys)) - - for _, pubKey := range keys { - var hosts []string - switch v := pubKey.GetExtendedField("hosts").(type) { - case []string: - hosts = v - case []interface{}: - for _, value := range v { - h, ok := value.(string) - if !ok { - continue - } - hosts = append(hosts, h) - } - } - - if len(hosts) == 0 { - if includeEmpty { - filtered = append(filtered, pubKey) - } - continue - } - - // Check if any hosts match pattern - for _, hostPattern := range hosts { - match, err := filepath.Match(hostPattern, host) - if err != nil { - return nil, err - } - - if match { - filtered = append(filtered, pubKey) - continue - } - } - } - - return filtered, nil -} diff --git a/vendor/github.com/docker/libtrust/hash.go b/vendor/github.com/docker/libtrust/hash.go deleted file mode 100644 index a2df787dd..000000000 --- a/vendor/github.com/docker/libtrust/hash.go +++ /dev/null @@ -1,56 +0,0 @@ -package libtrust - -import ( - "crypto" - _ "crypto/sha256" // Registrer SHA224 and SHA256 - _ "crypto/sha512" // Registrer SHA384 and SHA512 - "fmt" -) - -type signatureAlgorithm struct { - algHeaderParam string - hashID crypto.Hash -} - -func (h *signatureAlgorithm) HeaderParam() string { - return h.algHeaderParam -} - -func (h *signatureAlgorithm) HashID() crypto.Hash { - return h.hashID -} - -var ( - rs256 = &signatureAlgorithm{"RS256", crypto.SHA256} - rs384 = &signatureAlgorithm{"RS384", crypto.SHA384} - rs512 = &signatureAlgorithm{"RS512", crypto.SHA512} - es256 = &signatureAlgorithm{"ES256", crypto.SHA256} - es384 = &signatureAlgorithm{"ES384", crypto.SHA384} - es512 = &signatureAlgorithm{"ES512", crypto.SHA512} -) - -func rsaSignatureAlgorithmByName(alg string) (*signatureAlgorithm, error) { - switch { - case alg == "RS256": - return rs256, nil - case alg == "RS384": - return rs384, nil - case alg == "RS512": - return rs512, nil - default: - return nil, fmt.Errorf("RSA Digital Signature Algorithm %q not supported", alg) - } -} - -func rsaPKCS1v15SignatureAlgorithmForHashID(hashID crypto.Hash) *signatureAlgorithm { - switch { - case hashID == crypto.SHA512: - return rs512 - case hashID == crypto.SHA384: - return rs384 - case hashID == crypto.SHA256: - fallthrough - default: - return rs256 - } -} diff --git a/vendor/github.com/docker/libtrust/jsonsign.go b/vendor/github.com/docker/libtrust/jsonsign.go deleted file mode 100644 index cb2ca9a76..000000000 --- a/vendor/github.com/docker/libtrust/jsonsign.go +++ /dev/null @@ -1,657 +0,0 @@ -package libtrust - -import ( - "bytes" - "crypto" - "crypto/x509" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "sort" - "time" - "unicode" -) - -var ( - // ErrInvalidSignContent is used when the content to be signed is invalid. - ErrInvalidSignContent = errors.New("invalid sign content") - - // ErrInvalidJSONContent is used when invalid json is encountered. - ErrInvalidJSONContent = errors.New("invalid json content") - - // ErrMissingSignatureKey is used when the specified signature key - // does not exist in the JSON content. - ErrMissingSignatureKey = errors.New("missing signature key") -) - -type jsHeader struct { - JWK PublicKey `json:"jwk,omitempty"` - Algorithm string `json:"alg"` - Chain []string `json:"x5c,omitempty"` -} - -type jsSignature struct { - Header jsHeader `json:"header"` - Signature string `json:"signature"` - Protected string `json:"protected,omitempty"` -} - -type jsSignaturesSorted []jsSignature - -func (jsbkid jsSignaturesSorted) Swap(i, j int) { jsbkid[i], jsbkid[j] = jsbkid[j], jsbkid[i] } -func (jsbkid jsSignaturesSorted) Len() int { return len(jsbkid) } - -func (jsbkid jsSignaturesSorted) Less(i, j int) bool { - ki, kj := jsbkid[i].Header.JWK.KeyID(), jsbkid[j].Header.JWK.KeyID() - si, sj := jsbkid[i].Signature, jsbkid[j].Signature - - if ki == kj { - return si < sj - } - - return ki < kj -} - -type signKey struct { - PrivateKey - Chain []*x509.Certificate -} - -// JSONSignature represents a signature of a json object. -type JSONSignature struct { - payload string - signatures []jsSignature - indent string - formatLength int - formatTail []byte -} - -func newJSONSignature() *JSONSignature { - return &JSONSignature{ - signatures: make([]jsSignature, 0, 1), - } -} - -// Payload returns the encoded payload of the signature. This -// payload should not be signed directly -func (js *JSONSignature) Payload() ([]byte, error) { - return joseBase64UrlDecode(js.payload) -} - -func (js *JSONSignature) protectedHeader() (string, error) { - protected := map[string]interface{}{ - "formatLength": js.formatLength, - "formatTail": joseBase64UrlEncode(js.formatTail), - "time": time.Now().UTC().Format(time.RFC3339), - } - protectedBytes, err := json.Marshal(protected) - if err != nil { - return "", err - } - - return joseBase64UrlEncode(protectedBytes), nil -} - -func (js *JSONSignature) signBytes(protectedHeader string) ([]byte, error) { - buf := make([]byte, len(js.payload)+len(protectedHeader)+1) - copy(buf, protectedHeader) - buf[len(protectedHeader)] = '.' - copy(buf[len(protectedHeader)+1:], js.payload) - return buf, nil -} - -// Sign adds a signature using the given private key. -func (js *JSONSignature) Sign(key PrivateKey) error { - protected, err := js.protectedHeader() - if err != nil { - return err - } - signBytes, err := js.signBytes(protected) - if err != nil { - return err - } - sigBytes, algorithm, err := key.Sign(bytes.NewReader(signBytes), crypto.SHA256) - if err != nil { - return err - } - - js.signatures = append(js.signatures, jsSignature{ - Header: jsHeader{ - JWK: key.PublicKey(), - Algorithm: algorithm, - }, - Signature: joseBase64UrlEncode(sigBytes), - Protected: protected, - }) - - return nil -} - -// SignWithChain adds a signature using the given private key -// and setting the x509 chain. The public key of the first element -// in the chain must be the public key corresponding with the sign key. -func (js *JSONSignature) SignWithChain(key PrivateKey, chain []*x509.Certificate) error { - // Ensure key.Chain[0] is public key for key - //key.Chain.PublicKey - //key.PublicKey().CryptoPublicKey() - - // Verify chain - protected, err := js.protectedHeader() - if err != nil { - return err - } - signBytes, err := js.signBytes(protected) - if err != nil { - return err - } - sigBytes, algorithm, err := key.Sign(bytes.NewReader(signBytes), crypto.SHA256) - if err != nil { - return err - } - - header := jsHeader{ - Chain: make([]string, len(chain)), - Algorithm: algorithm, - } - - for i, cert := range chain { - header.Chain[i] = base64.StdEncoding.EncodeToString(cert.Raw) - } - - js.signatures = append(js.signatures, jsSignature{ - Header: header, - Signature: joseBase64UrlEncode(sigBytes), - Protected: protected, - }) - - return nil -} - -// Verify verifies all the signatures and returns the list of -// public keys used to sign. Any x509 chains are not checked. -func (js *JSONSignature) Verify() ([]PublicKey, error) { - keys := make([]PublicKey, len(js.signatures)) - for i, signature := range js.signatures { - signBytes, err := js.signBytes(signature.Protected) - if err != nil { - return nil, err - } - var publicKey PublicKey - if len(signature.Header.Chain) > 0 { - certBytes, err := base64.StdEncoding.DecodeString(signature.Header.Chain[0]) - if err != nil { - return nil, err - } - cert, err := x509.ParseCertificate(certBytes) - if err != nil { - return nil, err - } - publicKey, err = FromCryptoPublicKey(cert.PublicKey) - if err != nil { - return nil, err - } - } else if signature.Header.JWK != nil { - publicKey = signature.Header.JWK - } else { - return nil, errors.New("missing public key") - } - - sigBytes, err := joseBase64UrlDecode(signature.Signature) - if err != nil { - return nil, err - } - - err = publicKey.Verify(bytes.NewReader(signBytes), signature.Header.Algorithm, sigBytes) - if err != nil { - return nil, err - } - - keys[i] = publicKey - } - return keys, nil -} - -// VerifyChains verifies all the signatures and the chains associated -// with each signature and returns the list of verified chains. -// Signatures without an x509 chain are not checked. -func (js *JSONSignature) VerifyChains(ca *x509.CertPool) ([][]*x509.Certificate, error) { - chains := make([][]*x509.Certificate, 0, len(js.signatures)) - for _, signature := range js.signatures { - signBytes, err := js.signBytes(signature.Protected) - if err != nil { - return nil, err - } - var publicKey PublicKey - if len(signature.Header.Chain) > 0 { - certBytes, err := base64.StdEncoding.DecodeString(signature.Header.Chain[0]) - if err != nil { - return nil, err - } - cert, err := x509.ParseCertificate(certBytes) - if err != nil { - return nil, err - } - publicKey, err = FromCryptoPublicKey(cert.PublicKey) - if err != nil { - return nil, err - } - intermediates := x509.NewCertPool() - if len(signature.Header.Chain) > 1 { - intermediateChain := signature.Header.Chain[1:] - for i := range intermediateChain { - certBytes, err := base64.StdEncoding.DecodeString(intermediateChain[i]) - if err != nil { - return nil, err - } - intermediate, err := x509.ParseCertificate(certBytes) - if err != nil { - return nil, err - } - intermediates.AddCert(intermediate) - } - } - - verifyOptions := x509.VerifyOptions{ - Intermediates: intermediates, - Roots: ca, - } - - verifiedChains, err := cert.Verify(verifyOptions) - if err != nil { - return nil, err - } - chains = append(chains, verifiedChains...) - - sigBytes, err := joseBase64UrlDecode(signature.Signature) - if err != nil { - return nil, err - } - - err = publicKey.Verify(bytes.NewReader(signBytes), signature.Header.Algorithm, sigBytes) - if err != nil { - return nil, err - } - } - - } - return chains, nil -} - -// JWS returns JSON serialized JWS according to -// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-7.2 -func (js *JSONSignature) JWS() ([]byte, error) { - if len(js.signatures) == 0 { - return nil, errors.New("missing signature") - } - - sort.Sort(jsSignaturesSorted(js.signatures)) - - jsonMap := map[string]interface{}{ - "payload": js.payload, - "signatures": js.signatures, - } - - return json.MarshalIndent(jsonMap, "", " ") -} - -func notSpace(r rune) bool { - return !unicode.IsSpace(r) -} - -func detectJSONIndent(jsonContent []byte) (indent string) { - if len(jsonContent) > 2 && jsonContent[0] == '{' && jsonContent[1] == '\n' { - quoteIndex := bytes.IndexRune(jsonContent[1:], '"') - if quoteIndex > 0 { - indent = string(jsonContent[2 : quoteIndex+1]) - } - } - return -} - -type jsParsedHeader struct { - JWK json.RawMessage `json:"jwk"` - Algorithm string `json:"alg"` - Chain []string `json:"x5c"` -} - -type jsParsedSignature struct { - Header jsParsedHeader `json:"header"` - Signature string `json:"signature"` - Protected string `json:"protected"` -} - -// ParseJWS parses a JWS serialized JSON object into a Json Signature. -func ParseJWS(content []byte) (*JSONSignature, error) { - type jsParsed struct { - Payload string `json:"payload"` - Signatures []jsParsedSignature `json:"signatures"` - } - parsed := &jsParsed{} - err := json.Unmarshal(content, parsed) - if err != nil { - return nil, err - } - if len(parsed.Signatures) == 0 { - return nil, errors.New("missing signatures") - } - payload, err := joseBase64UrlDecode(parsed.Payload) - if err != nil { - return nil, err - } - - js, err := NewJSONSignature(payload) - if err != nil { - return nil, err - } - js.signatures = make([]jsSignature, len(parsed.Signatures)) - for i, signature := range parsed.Signatures { - header := jsHeader{ - Algorithm: signature.Header.Algorithm, - } - if signature.Header.Chain != nil { - header.Chain = signature.Header.Chain - } - if signature.Header.JWK != nil { - publicKey, err := UnmarshalPublicKeyJWK([]byte(signature.Header.JWK)) - if err != nil { - return nil, err - } - header.JWK = publicKey - } - js.signatures[i] = jsSignature{ - Header: header, - Signature: signature.Signature, - Protected: signature.Protected, - } - } - - return js, nil -} - -// NewJSONSignature returns a new unsigned JWS from a json byte array. -// JSONSignature will need to be signed before serializing or storing. -// Optionally, one or more signatures can be provided as byte buffers, -// containing serialized JWS signatures, to assemble a fully signed JWS -// package. It is the callers responsibility to ensure uniqueness of the -// provided signatures. -func NewJSONSignature(content []byte, signatures ...[]byte) (*JSONSignature, error) { - var dataMap map[string]interface{} - err := json.Unmarshal(content, &dataMap) - if err != nil { - return nil, err - } - - js := newJSONSignature() - js.indent = detectJSONIndent(content) - - js.payload = joseBase64UrlEncode(content) - - // Find trailing } and whitespace, put in protected header - closeIndex := bytes.LastIndexFunc(content, notSpace) - if content[closeIndex] != '}' { - return nil, ErrInvalidJSONContent - } - lastRuneIndex := bytes.LastIndexFunc(content[:closeIndex], notSpace) - if content[lastRuneIndex] == ',' { - return nil, ErrInvalidJSONContent - } - js.formatLength = lastRuneIndex + 1 - js.formatTail = content[js.formatLength:] - - if len(signatures) > 0 { - for _, signature := range signatures { - var parsedJSig jsParsedSignature - - if err := json.Unmarshal(signature, &parsedJSig); err != nil { - return nil, err - } - - // TODO(stevvooe): A lot of the code below is repeated in - // ParseJWS. It will require more refactoring to fix that. - jsig := jsSignature{ - Header: jsHeader{ - Algorithm: parsedJSig.Header.Algorithm, - }, - Signature: parsedJSig.Signature, - Protected: parsedJSig.Protected, - } - - if parsedJSig.Header.Chain != nil { - jsig.Header.Chain = parsedJSig.Header.Chain - } - - if parsedJSig.Header.JWK != nil { - publicKey, err := UnmarshalPublicKeyJWK([]byte(parsedJSig.Header.JWK)) - if err != nil { - return nil, err - } - jsig.Header.JWK = publicKey - } - - js.signatures = append(js.signatures, jsig) - } - } - - return js, nil -} - -// NewJSONSignatureFromMap returns a new unsigned JSONSignature from a map or -// struct. JWS will need to be signed before serializing or storing. -func NewJSONSignatureFromMap(content interface{}) (*JSONSignature, error) { - switch content.(type) { - case map[string]interface{}: - case struct{}: - default: - return nil, errors.New("invalid data type") - } - - js := newJSONSignature() - js.indent = " " - - payload, err := json.MarshalIndent(content, "", js.indent) - if err != nil { - return nil, err - } - js.payload = joseBase64UrlEncode(payload) - - // Remove '\n}' from formatted section, put in protected header - js.formatLength = len(payload) - 2 - js.formatTail = payload[js.formatLength:] - - return js, nil -} - -func readIntFromMap(key string, m map[string]interface{}) (int, bool) { - value, ok := m[key] - if !ok { - return 0, false - } - switch v := value.(type) { - case int: - return v, true - case float64: - return int(v), true - default: - return 0, false - } -} - -func readStringFromMap(key string, m map[string]interface{}) (v string, ok bool) { - value, ok := m[key] - if !ok { - return "", false - } - v, ok = value.(string) - return -} - -// ParsePrettySignature parses a formatted signature into a -// JSON signature. If the signatures are missing the format information -// an error is thrown. The formatted signature must be created by -// the same method as format signature. -func ParsePrettySignature(content []byte, signatureKey string) (*JSONSignature, error) { - var contentMap map[string]json.RawMessage - err := json.Unmarshal(content, &contentMap) - if err != nil { - return nil, fmt.Errorf("error unmarshalling content: %s", err) - } - sigMessage, ok := contentMap[signatureKey] - if !ok { - return nil, ErrMissingSignatureKey - } - - var signatureBlocks []jsParsedSignature - err = json.Unmarshal([]byte(sigMessage), &signatureBlocks) - if err != nil { - return nil, fmt.Errorf("error unmarshalling signatures: %s", err) - } - - js := newJSONSignature() - js.signatures = make([]jsSignature, len(signatureBlocks)) - - for i, signatureBlock := range signatureBlocks { - protectedBytes, err := joseBase64UrlDecode(signatureBlock.Protected) - if err != nil { - return nil, fmt.Errorf("base64 decode error: %s", err) - } - var protectedHeader map[string]interface{} - err = json.Unmarshal(protectedBytes, &protectedHeader) - if err != nil { - return nil, fmt.Errorf("error unmarshalling protected header: %s", err) - } - - formatLength, ok := readIntFromMap("formatLength", protectedHeader) - if !ok { - return nil, errors.New("missing formatted length") - } - encodedTail, ok := readStringFromMap("formatTail", protectedHeader) - if !ok { - return nil, errors.New("missing formatted tail") - } - formatTail, err := joseBase64UrlDecode(encodedTail) - if err != nil { - return nil, fmt.Errorf("base64 decode error on tail: %s", err) - } - if js.formatLength == 0 { - js.formatLength = formatLength - } else if js.formatLength != formatLength { - return nil, errors.New("conflicting format length") - } - if len(js.formatTail) == 0 { - js.formatTail = formatTail - } else if bytes.Compare(js.formatTail, formatTail) != 0 { - return nil, errors.New("conflicting format tail") - } - - header := jsHeader{ - Algorithm: signatureBlock.Header.Algorithm, - Chain: signatureBlock.Header.Chain, - } - if signatureBlock.Header.JWK != nil { - publicKey, err := UnmarshalPublicKeyJWK([]byte(signatureBlock.Header.JWK)) - if err != nil { - return nil, fmt.Errorf("error unmarshalling public key: %s", err) - } - header.JWK = publicKey - } - js.signatures[i] = jsSignature{ - Header: header, - Signature: signatureBlock.Signature, - Protected: signatureBlock.Protected, - } - } - if js.formatLength > len(content) { - return nil, errors.New("invalid format length") - } - formatted := make([]byte, js.formatLength+len(js.formatTail)) - copy(formatted, content[:js.formatLength]) - copy(formatted[js.formatLength:], js.formatTail) - js.indent = detectJSONIndent(formatted) - js.payload = joseBase64UrlEncode(formatted) - - return js, nil -} - -// PrettySignature formats a json signature into an easy to read -// single json serialized object. -func (js *JSONSignature) PrettySignature(signatureKey string) ([]byte, error) { - if len(js.signatures) == 0 { - return nil, errors.New("no signatures") - } - payload, err := joseBase64UrlDecode(js.payload) - if err != nil { - return nil, err - } - payload = payload[:js.formatLength] - - sort.Sort(jsSignaturesSorted(js.signatures)) - - var marshalled []byte - var marshallErr error - if js.indent != "" { - marshalled, marshallErr = json.MarshalIndent(js.signatures, js.indent, js.indent) - } else { - marshalled, marshallErr = json.Marshal(js.signatures) - } - if marshallErr != nil { - return nil, marshallErr - } - - buf := bytes.NewBuffer(make([]byte, 0, len(payload)+len(marshalled)+34)) - buf.Write(payload) - buf.WriteByte(',') - if js.indent != "" { - buf.WriteByte('\n') - buf.WriteString(js.indent) - buf.WriteByte('"') - buf.WriteString(signatureKey) - buf.WriteString("\": ") - buf.Write(marshalled) - buf.WriteByte('\n') - } else { - buf.WriteByte('"') - buf.WriteString(signatureKey) - buf.WriteString("\":") - buf.Write(marshalled) - } - buf.WriteByte('}') - - return buf.Bytes(), nil -} - -// Signatures provides the signatures on this JWS as opaque blobs, sorted by -// keyID. These blobs can be stored and reassembled with payloads. Internally, -// they are simply marshaled json web signatures but implementations should -// not rely on this. -func (js *JSONSignature) Signatures() ([][]byte, error) { - sort.Sort(jsSignaturesSorted(js.signatures)) - - var sb [][]byte - for _, jsig := range js.signatures { - p, err := json.Marshal(jsig) - if err != nil { - return nil, err - } - - sb = append(sb, p) - } - - return sb, nil -} - -// Merge combines the signatures from one or more other signatures into the -// method receiver. If the payloads differ for any argument, an error will be -// returned and the receiver will not be modified. -func (js *JSONSignature) Merge(others ...*JSONSignature) error { - merged := js.signatures - for _, other := range others { - if js.payload != other.payload { - return fmt.Errorf("payloads differ from merge target") - } - merged = append(merged, other.signatures...) - } - - js.signatures = merged - return nil -} diff --git a/vendor/github.com/docker/libtrust/key.go b/vendor/github.com/docker/libtrust/key.go deleted file mode 100644 index 73642db2a..000000000 --- a/vendor/github.com/docker/libtrust/key.go +++ /dev/null @@ -1,253 +0,0 @@ -package libtrust - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "io" -) - -// PublicKey is a generic interface for a Public Key. -type PublicKey interface { - // KeyType returns the key type for this key. For elliptic curve keys, - // this value should be "EC". For RSA keys, this value should be "RSA". - KeyType() string - // KeyID returns a distinct identifier which is unique to this Public Key. - // The format generated by this library is a base32 encoding of a 240 bit - // hash of the public key data divided into 12 groups like so: - // ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP - KeyID() string - // Verify verifyies the signature of the data in the io.Reader using this - // Public Key. The alg parameter should identify the digital signature - // algorithm which was used to produce the signature and should be - // supported by this public key. Returns a nil error if the signature - // is valid. - Verify(data io.Reader, alg string, signature []byte) error - // CryptoPublicKey returns the internal object which can be used as a - // crypto.PublicKey for use with other standard library operations. The type - // is either *rsa.PublicKey or *ecdsa.PublicKey - CryptoPublicKey() crypto.PublicKey - // These public keys can be serialized to the standard JSON encoding for - // JSON Web Keys. See section 6 of the IETF draft RFC for JOSE JSON Web - // Algorithms. - MarshalJSON() ([]byte, error) - // These keys can also be serialized to the standard PEM encoding. - PEMBlock() (*pem.Block, error) - // The string representation of a key is its key type and ID. - String() string - AddExtendedField(string, interface{}) - GetExtendedField(string) interface{} -} - -// PrivateKey is a generic interface for a Private Key. -type PrivateKey interface { - // A PrivateKey contains all fields and methods of a PublicKey of the - // same type. The MarshalJSON method also outputs the private key as a - // JSON Web Key, and the PEMBlock method outputs the private key as a - // PEM block. - PublicKey - // PublicKey returns the PublicKey associated with this PrivateKey. - PublicKey() PublicKey - // Sign signs the data read from the io.Reader using a signature algorithm - // supported by the private key. If the specified hashing algorithm is - // supported by this key, that hash function is used to generate the - // signature otherwise the the default hashing algorithm for this key is - // used. Returns the signature and identifier of the algorithm used. - Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) - // CryptoPrivateKey returns the internal object which can be used as a - // crypto.PublicKey for use with other standard library operations. The - // type is either *rsa.PublicKey or *ecdsa.PublicKey - CryptoPrivateKey() crypto.PrivateKey -} - -// FromCryptoPublicKey returns a libtrust PublicKey representation of the given -// *ecdsa.PublicKey or *rsa.PublicKey. Returns a non-nil error when the given -// key is of an unsupported type. -func FromCryptoPublicKey(cryptoPublicKey crypto.PublicKey) (PublicKey, error) { - switch cryptoPublicKey := cryptoPublicKey.(type) { - case *ecdsa.PublicKey: - return fromECPublicKey(cryptoPublicKey) - case *rsa.PublicKey: - return fromRSAPublicKey(cryptoPublicKey), nil - default: - return nil, fmt.Errorf("public key type %T is not supported", cryptoPublicKey) - } -} - -// FromCryptoPrivateKey returns a libtrust PrivateKey representation of the given -// *ecdsa.PrivateKey or *rsa.PrivateKey. Returns a non-nil error when the given -// key is of an unsupported type. -func FromCryptoPrivateKey(cryptoPrivateKey crypto.PrivateKey) (PrivateKey, error) { - switch cryptoPrivateKey := cryptoPrivateKey.(type) { - case *ecdsa.PrivateKey: - return fromECPrivateKey(cryptoPrivateKey) - case *rsa.PrivateKey: - return fromRSAPrivateKey(cryptoPrivateKey), nil - default: - return nil, fmt.Errorf("private key type %T is not supported", cryptoPrivateKey) - } -} - -// UnmarshalPublicKeyPEM parses the PEM encoded data and returns a libtrust -// PublicKey or an error if there is a problem with the encoding. -func UnmarshalPublicKeyPEM(data []byte) (PublicKey, error) { - pemBlock, _ := pem.Decode(data) - if pemBlock == nil { - return nil, errors.New("unable to find PEM encoded data") - } else if pemBlock.Type != "PUBLIC KEY" { - return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type) - } - - return pubKeyFromPEMBlock(pemBlock) -} - -// UnmarshalPublicKeyPEMBundle parses the PEM encoded data as a bundle of -// PEM blocks appended one after the other and returns a slice of PublicKey -// objects that it finds. -func UnmarshalPublicKeyPEMBundle(data []byte) ([]PublicKey, error) { - pubKeys := []PublicKey{} - - for { - var pemBlock *pem.Block - pemBlock, data = pem.Decode(data) - if pemBlock == nil { - break - } else if pemBlock.Type != "PUBLIC KEY" { - return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type) - } - - pubKey, err := pubKeyFromPEMBlock(pemBlock) - if err != nil { - return nil, err - } - - pubKeys = append(pubKeys, pubKey) - } - - return pubKeys, nil -} - -// UnmarshalPrivateKeyPEM parses the PEM encoded data and returns a libtrust -// PrivateKey or an error if there is a problem with the encoding. -func UnmarshalPrivateKeyPEM(data []byte) (PrivateKey, error) { - pemBlock, _ := pem.Decode(data) - if pemBlock == nil { - return nil, errors.New("unable to find PEM encoded data") - } - - var key PrivateKey - - switch { - case pemBlock.Type == "RSA PRIVATE KEY": - rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) - if err != nil { - return nil, fmt.Errorf("unable to decode RSA Private Key PEM data: %s", err) - } - key = fromRSAPrivateKey(rsaPrivateKey) - case pemBlock.Type == "EC PRIVATE KEY": - ecPrivateKey, err := x509.ParseECPrivateKey(pemBlock.Bytes) - if err != nil { - return nil, fmt.Errorf("unable to decode EC Private Key PEM data: %s", err) - } - key, err = fromECPrivateKey(ecPrivateKey) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("unable to get PrivateKey from PEM type: %s", pemBlock.Type) - } - - addPEMHeadersToKey(pemBlock, key.PublicKey()) - - return key, nil -} - -// UnmarshalPublicKeyJWK unmarshals the given JSON Web Key into a generic -// Public Key to be used with libtrust. -func UnmarshalPublicKeyJWK(data []byte) (PublicKey, error) { - jwk := make(map[string]interface{}) - - err := json.Unmarshal(data, &jwk) - if err != nil { - return nil, fmt.Errorf( - "decoding JWK Public Key JSON data: %s\n", err, - ) - } - - // Get the Key Type value. - kty, err := stringFromMap(jwk, "kty") - if err != nil { - return nil, fmt.Errorf("JWK Public Key type: %s", err) - } - - switch { - case kty == "EC": - // Call out to unmarshal EC public key. - return ecPublicKeyFromMap(jwk) - case kty == "RSA": - // Call out to unmarshal RSA public key. - return rsaPublicKeyFromMap(jwk) - default: - return nil, fmt.Errorf( - "JWK Public Key type not supported: %q\n", kty, - ) - } -} - -// UnmarshalPublicKeyJWKSet parses the JSON encoded data as a JSON Web Key Set -// and returns a slice of Public Key objects. -func UnmarshalPublicKeyJWKSet(data []byte) ([]PublicKey, error) { - rawKeys, err := loadJSONKeySetRaw(data) - if err != nil { - return nil, err - } - - pubKeys := make([]PublicKey, 0, len(rawKeys)) - - for _, rawKey := range rawKeys { - pubKey, err := UnmarshalPublicKeyJWK(rawKey) - if err != nil { - return nil, err - } - pubKeys = append(pubKeys, pubKey) - } - - return pubKeys, nil -} - -// UnmarshalPrivateKeyJWK unmarshals the given JSON Web Key into a generic -// Private Key to be used with libtrust. -func UnmarshalPrivateKeyJWK(data []byte) (PrivateKey, error) { - jwk := make(map[string]interface{}) - - err := json.Unmarshal(data, &jwk) - if err != nil { - return nil, fmt.Errorf( - "decoding JWK Private Key JSON data: %s\n", err, - ) - } - - // Get the Key Type value. - kty, err := stringFromMap(jwk, "kty") - if err != nil { - return nil, fmt.Errorf("JWK Private Key type: %s", err) - } - - switch { - case kty == "EC": - // Call out to unmarshal EC private key. - return ecPrivateKeyFromMap(jwk) - case kty == "RSA": - // Call out to unmarshal RSA private key. - return rsaPrivateKeyFromMap(jwk) - default: - return nil, fmt.Errorf( - "JWK Private Key type not supported: %q\n", kty, - ) - } -} diff --git a/vendor/github.com/docker/libtrust/key_files.go b/vendor/github.com/docker/libtrust/key_files.go deleted file mode 100644 index c526de545..000000000 --- a/vendor/github.com/docker/libtrust/key_files.go +++ /dev/null @@ -1,255 +0,0 @@ -package libtrust - -import ( - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "io/ioutil" - "os" - "strings" -) - -var ( - // ErrKeyFileDoesNotExist indicates that the private key file does not exist. - ErrKeyFileDoesNotExist = errors.New("key file does not exist") -) - -func readKeyFileBytes(filename string) ([]byte, error) { - data, err := ioutil.ReadFile(filename) - if err != nil { - if os.IsNotExist(err) { - err = ErrKeyFileDoesNotExist - } else { - err = fmt.Errorf("unable to read key file %s: %s", filename, err) - } - - return nil, err - } - - return data, nil -} - -/* - Loading and Saving of Public and Private Keys in either PEM or JWK format. -*/ - -// LoadKeyFile opens the given filename and attempts to read a Private Key -// encoded in either PEM or JWK format (if .json or .jwk file extension). -func LoadKeyFile(filename string) (PrivateKey, error) { - contents, err := readKeyFileBytes(filename) - if err != nil { - return nil, err - } - - var key PrivateKey - - if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") { - key, err = UnmarshalPrivateKeyJWK(contents) - if err != nil { - return nil, fmt.Errorf("unable to decode private key JWK: %s", err) - } - } else { - key, err = UnmarshalPrivateKeyPEM(contents) - if err != nil { - return nil, fmt.Errorf("unable to decode private key PEM: %s", err) - } - } - - return key, nil -} - -// LoadPublicKeyFile opens the given filename and attempts to read a Public Key -// encoded in either PEM or JWK format (if .json or .jwk file extension). -func LoadPublicKeyFile(filename string) (PublicKey, error) { - contents, err := readKeyFileBytes(filename) - if err != nil { - return nil, err - } - - var key PublicKey - - if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") { - key, err = UnmarshalPublicKeyJWK(contents) - if err != nil { - return nil, fmt.Errorf("unable to decode public key JWK: %s", err) - } - } else { - key, err = UnmarshalPublicKeyPEM(contents) - if err != nil { - return nil, fmt.Errorf("unable to decode public key PEM: %s", err) - } - } - - return key, nil -} - -// SaveKey saves the given key to a file using the provided filename. -// This process will overwrite any existing file at the provided location. -func SaveKey(filename string, key PrivateKey) error { - var encodedKey []byte - var err error - - if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") { - // Encode in JSON Web Key format. - encodedKey, err = json.MarshalIndent(key, "", " ") - if err != nil { - return fmt.Errorf("unable to encode private key JWK: %s", err) - } - } else { - // Encode in PEM format. - pemBlock, err := key.PEMBlock() - if err != nil { - return fmt.Errorf("unable to encode private key PEM: %s", err) - } - encodedKey = pem.EncodeToMemory(pemBlock) - } - - err = ioutil.WriteFile(filename, encodedKey, os.FileMode(0600)) - if err != nil { - return fmt.Errorf("unable to write private key file %s: %s", filename, err) - } - - return nil -} - -// SavePublicKey saves the given public key to the file. -func SavePublicKey(filename string, key PublicKey) error { - var encodedKey []byte - var err error - - if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") { - // Encode in JSON Web Key format. - encodedKey, err = json.MarshalIndent(key, "", " ") - if err != nil { - return fmt.Errorf("unable to encode public key JWK: %s", err) - } - } else { - // Encode in PEM format. - pemBlock, err := key.PEMBlock() - if err != nil { - return fmt.Errorf("unable to encode public key PEM: %s", err) - } - encodedKey = pem.EncodeToMemory(pemBlock) - } - - err = ioutil.WriteFile(filename, encodedKey, os.FileMode(0644)) - if err != nil { - return fmt.Errorf("unable to write public key file %s: %s", filename, err) - } - - return nil -} - -// Public Key Set files - -type jwkSet struct { - Keys []json.RawMessage `json:"keys"` -} - -// LoadKeySetFile loads a key set -func LoadKeySetFile(filename string) ([]PublicKey, error) { - if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") { - return loadJSONKeySetFile(filename) - } - - // Must be a PEM format file - return loadPEMKeySetFile(filename) -} - -func loadJSONKeySetRaw(data []byte) ([]json.RawMessage, error) { - if len(data) == 0 { - // This is okay, just return an empty slice. - return []json.RawMessage{}, nil - } - - keySet := jwkSet{} - - err := json.Unmarshal(data, &keySet) - if err != nil { - return nil, fmt.Errorf("unable to decode JSON Web Key Set: %s", err) - } - - return keySet.Keys, nil -} - -func loadJSONKeySetFile(filename string) ([]PublicKey, error) { - contents, err := readKeyFileBytes(filename) - if err != nil && err != ErrKeyFileDoesNotExist { - return nil, err - } - - return UnmarshalPublicKeyJWKSet(contents) -} - -func loadPEMKeySetFile(filename string) ([]PublicKey, error) { - data, err := readKeyFileBytes(filename) - if err != nil && err != ErrKeyFileDoesNotExist { - return nil, err - } - - return UnmarshalPublicKeyPEMBundle(data) -} - -// AddKeySetFile adds a key to a key set -func AddKeySetFile(filename string, key PublicKey) error { - if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") { - return addKeySetJSONFile(filename, key) - } - - // Must be a PEM format file - return addKeySetPEMFile(filename, key) -} - -func addKeySetJSONFile(filename string, key PublicKey) error { - encodedKey, err := json.Marshal(key) - if err != nil { - return fmt.Errorf("unable to encode trusted client key: %s", err) - } - - contents, err := readKeyFileBytes(filename) - if err != nil && err != ErrKeyFileDoesNotExist { - return err - } - - rawEntries, err := loadJSONKeySetRaw(contents) - if err != nil { - return err - } - - rawEntries = append(rawEntries, json.RawMessage(encodedKey)) - entriesWrapper := jwkSet{Keys: rawEntries} - - encodedEntries, err := json.MarshalIndent(entriesWrapper, "", " ") - if err != nil { - return fmt.Errorf("unable to encode trusted client keys: %s", err) - } - - err = ioutil.WriteFile(filename, encodedEntries, os.FileMode(0644)) - if err != nil { - return fmt.Errorf("unable to write trusted client keys file %s: %s", filename, err) - } - - return nil -} - -func addKeySetPEMFile(filename string, key PublicKey) error { - // Encode to PEM, open file for appending, write PEM. - file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.FileMode(0644)) - if err != nil { - return fmt.Errorf("unable to open trusted client keys file %s: %s", filename, err) - } - defer file.Close() - - pemBlock, err := key.PEMBlock() - if err != nil { - return fmt.Errorf("unable to encoded trusted key: %s", err) - } - - _, err = file.Write(pem.EncodeToMemory(pemBlock)) - if err != nil { - return fmt.Errorf("unable to write trusted keys file: %s", err) - } - - return nil -} diff --git a/vendor/github.com/docker/libtrust/key_manager.go b/vendor/github.com/docker/libtrust/key_manager.go deleted file mode 100644 index 9a98ae357..000000000 --- a/vendor/github.com/docker/libtrust/key_manager.go +++ /dev/null @@ -1,175 +0,0 @@ -package libtrust - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "net" - "os" - "path" - "sync" -) - -// ClientKeyManager manages client keys on the filesystem -type ClientKeyManager struct { - key PrivateKey - clientFile string - clientDir string - - clientLock sync.RWMutex - clients []PublicKey - - configLock sync.Mutex - configs []*tls.Config -} - -// NewClientKeyManager loads a new manager from a set of key files -// and managed by the given private key. -func NewClientKeyManager(trustKey PrivateKey, clientFile, clientDir string) (*ClientKeyManager, error) { - m := &ClientKeyManager{ - key: trustKey, - clientFile: clientFile, - clientDir: clientDir, - } - if err := m.loadKeys(); err != nil { - return nil, err - } - // TODO Start watching file and directory - - return m, nil -} - -func (c *ClientKeyManager) loadKeys() (err error) { - // Load authorized keys file - var clients []PublicKey - if c.clientFile != "" { - clients, err = LoadKeySetFile(c.clientFile) - if err != nil { - return fmt.Errorf("unable to load authorized keys: %s", err) - } - } - - // Add clients from authorized keys directory - files, err := ioutil.ReadDir(c.clientDir) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("unable to open authorized keys directory: %s", err) - } - for _, f := range files { - if !f.IsDir() { - publicKey, err := LoadPublicKeyFile(path.Join(c.clientDir, f.Name())) - if err != nil { - return fmt.Errorf("unable to load authorized key file: %s", err) - } - clients = append(clients, publicKey) - } - } - - c.clientLock.Lock() - c.clients = clients - c.clientLock.Unlock() - - return nil -} - -// RegisterTLSConfig registers a tls configuration to manager -// such that any changes to the keys may be reflected in -// the tls client CA pool -func (c *ClientKeyManager) RegisterTLSConfig(tlsConfig *tls.Config) error { - c.clientLock.RLock() - certPool, err := GenerateCACertPool(c.key, c.clients) - if err != nil { - return fmt.Errorf("CA pool generation error: %s", err) - } - c.clientLock.RUnlock() - - tlsConfig.ClientCAs = certPool - - c.configLock.Lock() - c.configs = append(c.configs, tlsConfig) - c.configLock.Unlock() - - return nil -} - -// NewIdentityAuthTLSConfig creates a tls.Config for the server to use for -// libtrust identity authentication for the domain specified -func NewIdentityAuthTLSConfig(trustKey PrivateKey, clients *ClientKeyManager, addr string, domain string) (*tls.Config, error) { - tlsConfig := newTLSConfig() - - tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert - if err := clients.RegisterTLSConfig(tlsConfig); err != nil { - return nil, err - } - - // Generate cert - ips, domains, err := parseAddr(addr) - if err != nil { - return nil, err - } - // add domain that it expects clients to use - domains = append(domains, domain) - x509Cert, err := GenerateSelfSignedServerCert(trustKey, domains, ips) - if err != nil { - return nil, fmt.Errorf("certificate generation error: %s", err) - } - tlsConfig.Certificates = []tls.Certificate{{ - Certificate: [][]byte{x509Cert.Raw}, - PrivateKey: trustKey.CryptoPrivateKey(), - Leaf: x509Cert, - }} - - return tlsConfig, nil -} - -// NewCertAuthTLSConfig creates a tls.Config for the server to use for -// certificate authentication -func NewCertAuthTLSConfig(caPath, certPath, keyPath string) (*tls.Config, error) { - tlsConfig := newTLSConfig() - - cert, err := tls.LoadX509KeyPair(certPath, keyPath) - if err != nil { - return nil, fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?", certPath, keyPath, err) - } - tlsConfig.Certificates = []tls.Certificate{cert} - - // Verify client certificates against a CA? - if caPath != "" { - certPool := x509.NewCertPool() - file, err := ioutil.ReadFile(caPath) - if err != nil { - return nil, fmt.Errorf("Couldn't read CA certificate: %s", err) - } - certPool.AppendCertsFromPEM(file) - - tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert - tlsConfig.ClientCAs = certPool - } - - return tlsConfig, nil -} - -func newTLSConfig() *tls.Config { - return &tls.Config{ - NextProtos: []string{"http/1.1"}, - // Avoid fallback on insecure SSL protocols - MinVersion: tls.VersionTLS10, - } -} - -// parseAddr parses an address into an array of IPs and domains -func parseAddr(addr string) ([]net.IP, []string, error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, nil, err - } - var domains []string - var ips []net.IP - ip := net.ParseIP(host) - if ip != nil { - ips = []net.IP{ip} - } else { - domains = []string{host} - } - return ips, domains, nil -} diff --git a/vendor/github.com/docker/libtrust/rsa_key.go b/vendor/github.com/docker/libtrust/rsa_key.go deleted file mode 100644 index dac4cacf2..000000000 --- a/vendor/github.com/docker/libtrust/rsa_key.go +++ /dev/null @@ -1,427 +0,0 @@ -package libtrust - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "io" - "math/big" -) - -/* - * RSA DSA PUBLIC KEY - */ - -// rsaPublicKey implements a JWK Public Key using RSA digital signature algorithms. -type rsaPublicKey struct { - *rsa.PublicKey - extended map[string]interface{} -} - -func fromRSAPublicKey(cryptoPublicKey *rsa.PublicKey) *rsaPublicKey { - return &rsaPublicKey{cryptoPublicKey, map[string]interface{}{}} -} - -// KeyType returns the JWK key type for RSA keys, i.e., "RSA". -func (k *rsaPublicKey) KeyType() string { - return "RSA" -} - -// KeyID returns a distinct identifier which is unique to this Public Key. -func (k *rsaPublicKey) KeyID() string { - return keyIDFromCryptoKey(k) -} - -func (k *rsaPublicKey) String() string { - return fmt.Sprintf("RSA Public Key <%s>", k.KeyID()) -} - -// Verify verifyies the signature of the data in the io.Reader using this Public Key. -// The alg parameter should be the name of the JWA digital signature algorithm -// which was used to produce the signature and should be supported by this -// public key. Returns a nil error if the signature is valid. -func (k *rsaPublicKey) Verify(data io.Reader, alg string, signature []byte) error { - // Verify the signature of the given date, return non-nil error if valid. - sigAlg, err := rsaSignatureAlgorithmByName(alg) - if err != nil { - return fmt.Errorf("unable to verify Signature: %s", err) - } - - hasher := sigAlg.HashID().New() - _, err = io.Copy(hasher, data) - if err != nil { - return fmt.Errorf("error reading data to sign: %s", err) - } - hash := hasher.Sum(nil) - - err = rsa.VerifyPKCS1v15(k.PublicKey, sigAlg.HashID(), hash, signature) - if err != nil { - return fmt.Errorf("invalid %s signature: %s", sigAlg.HeaderParam(), err) - } - - return nil -} - -// CryptoPublicKey returns the internal object which can be used as a -// crypto.PublicKey for use with other standard library operations. The type -// is either *rsa.PublicKey or *ecdsa.PublicKey -func (k *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { - return k.PublicKey -} - -func (k *rsaPublicKey) toMap() map[string]interface{} { - jwk := make(map[string]interface{}) - for k, v := range k.extended { - jwk[k] = v - } - jwk["kty"] = k.KeyType() - jwk["kid"] = k.KeyID() - jwk["n"] = joseBase64UrlEncode(k.N.Bytes()) - jwk["e"] = joseBase64UrlEncode(serializeRSAPublicExponentParam(k.E)) - - return jwk -} - -// MarshalJSON serializes this Public Key using the JWK JSON serialization format for -// RSA keys. -func (k *rsaPublicKey) MarshalJSON() (data []byte, err error) { - return json.Marshal(k.toMap()) -} - -// PEMBlock serializes this Public Key to DER-encoded PKIX format. -func (k *rsaPublicKey) PEMBlock() (*pem.Block, error) { - derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey) - if err != nil { - return nil, fmt.Errorf("unable to serialize RSA PublicKey to DER-encoded PKIX format: %s", err) - } - k.extended["kid"] = k.KeyID() // For display purposes. - return createPemBlock("PUBLIC KEY", derBytes, k.extended) -} - -func (k *rsaPublicKey) AddExtendedField(field string, value interface{}) { - k.extended[field] = value -} - -func (k *rsaPublicKey) GetExtendedField(field string) interface{} { - v, ok := k.extended[field] - if !ok { - return nil - } - return v -} - -func rsaPublicKeyFromMap(jwk map[string]interface{}) (*rsaPublicKey, error) { - // JWK key type (kty) has already been determined to be "RSA". - // Need to extract 'n', 'e', and 'kid' and check for - // consistency. - - // Get the modulus parameter N. - nB64Url, err := stringFromMap(jwk, "n") - if err != nil { - return nil, fmt.Errorf("JWK RSA Public Key modulus: %s", err) - } - - n, err := parseRSAModulusParam(nB64Url) - if err != nil { - return nil, fmt.Errorf("JWK RSA Public Key modulus: %s", err) - } - - // Get the public exponent E. - eB64Url, err := stringFromMap(jwk, "e") - if err != nil { - return nil, fmt.Errorf("JWK RSA Public Key exponent: %s", err) - } - - e, err := parseRSAPublicExponentParam(eB64Url) - if err != nil { - return nil, fmt.Errorf("JWK RSA Public Key exponent: %s", err) - } - - key := &rsaPublicKey{ - PublicKey: &rsa.PublicKey{N: n, E: e}, - } - - // Key ID is optional, but if it exists, it should match the key. - _, ok := jwk["kid"] - if ok { - kid, err := stringFromMap(jwk, "kid") - if err != nil { - return nil, fmt.Errorf("JWK RSA Public Key ID: %s", err) - } - if kid != key.KeyID() { - return nil, fmt.Errorf("JWK RSA Public Key ID does not match: %s", kid) - } - } - - if _, ok := jwk["d"]; ok { - return nil, fmt.Errorf("JWK RSA Public Key cannot contain private exponent") - } - - key.extended = jwk - - return key, nil -} - -/* - * RSA DSA PRIVATE KEY - */ - -// rsaPrivateKey implements a JWK Private Key using RSA digital signature algorithms. -type rsaPrivateKey struct { - rsaPublicKey - *rsa.PrivateKey -} - -func fromRSAPrivateKey(cryptoPrivateKey *rsa.PrivateKey) *rsaPrivateKey { - return &rsaPrivateKey{ - *fromRSAPublicKey(&cryptoPrivateKey.PublicKey), - cryptoPrivateKey, - } -} - -// PublicKey returns the Public Key data associated with this Private Key. -func (k *rsaPrivateKey) PublicKey() PublicKey { - return &k.rsaPublicKey -} - -func (k *rsaPrivateKey) String() string { - return fmt.Sprintf("RSA Private Key <%s>", k.KeyID()) -} - -// Sign signs the data read from the io.Reader using a signature algorithm supported -// by the RSA private key. If the specified hashing algorithm is supported by -// this key, that hash function is used to generate the signature otherwise the -// the default hashing algorithm for this key is used. Returns the signature -// and the name of the JWK signature algorithm used, e.g., "RS256", "RS384", -// "RS512". -func (k *rsaPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) { - // Generate a signature of the data using the internal alg. - sigAlg := rsaPKCS1v15SignatureAlgorithmForHashID(hashID) - hasher := sigAlg.HashID().New() - - _, err = io.Copy(hasher, data) - if err != nil { - return nil, "", fmt.Errorf("error reading data to sign: %s", err) - } - hash := hasher.Sum(nil) - - signature, err = rsa.SignPKCS1v15(rand.Reader, k.PrivateKey, sigAlg.HashID(), hash) - if err != nil { - return nil, "", fmt.Errorf("error producing signature: %s", err) - } - - alg = sigAlg.HeaderParam() - - return -} - -// CryptoPrivateKey returns the internal object which can be used as a -// crypto.PublicKey for use with other standard library operations. The type -// is either *rsa.PublicKey or *ecdsa.PublicKey -func (k *rsaPrivateKey) CryptoPrivateKey() crypto.PrivateKey { - return k.PrivateKey -} - -func (k *rsaPrivateKey) toMap() map[string]interface{} { - k.Precompute() // Make sure the precomputed values are stored. - jwk := k.rsaPublicKey.toMap() - - jwk["d"] = joseBase64UrlEncode(k.D.Bytes()) - jwk["p"] = joseBase64UrlEncode(k.Primes[0].Bytes()) - jwk["q"] = joseBase64UrlEncode(k.Primes[1].Bytes()) - jwk["dp"] = joseBase64UrlEncode(k.Precomputed.Dp.Bytes()) - jwk["dq"] = joseBase64UrlEncode(k.Precomputed.Dq.Bytes()) - jwk["qi"] = joseBase64UrlEncode(k.Precomputed.Qinv.Bytes()) - - otherPrimes := k.Primes[2:] - - if len(otherPrimes) > 0 { - otherPrimesInfo := make([]interface{}, len(otherPrimes)) - for i, r := range otherPrimes { - otherPrimeInfo := make(map[string]string, 3) - otherPrimeInfo["r"] = joseBase64UrlEncode(r.Bytes()) - crtVal := k.Precomputed.CRTValues[i] - otherPrimeInfo["d"] = joseBase64UrlEncode(crtVal.Exp.Bytes()) - otherPrimeInfo["t"] = joseBase64UrlEncode(crtVal.Coeff.Bytes()) - otherPrimesInfo[i] = otherPrimeInfo - } - jwk["oth"] = otherPrimesInfo - } - - return jwk -} - -// MarshalJSON serializes this Private Key using the JWK JSON serialization format for -// RSA keys. -func (k *rsaPrivateKey) MarshalJSON() (data []byte, err error) { - return json.Marshal(k.toMap()) -} - -// PEMBlock serializes this Private Key to DER-encoded PKIX format. -func (k *rsaPrivateKey) PEMBlock() (*pem.Block, error) { - derBytes := x509.MarshalPKCS1PrivateKey(k.PrivateKey) - k.extended["keyID"] = k.KeyID() // For display purposes. - return createPemBlock("RSA PRIVATE KEY", derBytes, k.extended) -} - -func rsaPrivateKeyFromMap(jwk map[string]interface{}) (*rsaPrivateKey, error) { - // The JWA spec for RSA Private Keys (draft rfc section 5.3.2) states that - // only the private key exponent 'd' is REQUIRED, the others are just for - // signature/decryption optimizations and SHOULD be included when the JWK - // is produced. We MAY choose to accept a JWK which only includes 'd', but - // we're going to go ahead and not choose to accept it without the extra - // fields. Only the 'oth' field will be optional (for multi-prime keys). - privateExponent, err := parseRSAPrivateKeyParamFromMap(jwk, "d") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key exponent: %s", err) - } - firstPrimeFactor, err := parseRSAPrivateKeyParamFromMap(jwk, "p") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err) - } - secondPrimeFactor, err := parseRSAPrivateKeyParamFromMap(jwk, "q") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err) - } - firstFactorCRT, err := parseRSAPrivateKeyParamFromMap(jwk, "dp") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err) - } - secondFactorCRT, err := parseRSAPrivateKeyParamFromMap(jwk, "dq") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err) - } - crtCoeff, err := parseRSAPrivateKeyParamFromMap(jwk, "qi") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key CRT coefficient: %s", err) - } - - var oth interface{} - if _, ok := jwk["oth"]; ok { - oth = jwk["oth"] - delete(jwk, "oth") - } - - // JWK key type (kty) has already been determined to be "RSA". - // Need to extract the public key information, then extract the private - // key values. - publicKey, err := rsaPublicKeyFromMap(jwk) - if err != nil { - return nil, err - } - - privateKey := &rsa.PrivateKey{ - PublicKey: *publicKey.PublicKey, - D: privateExponent, - Primes: []*big.Int{firstPrimeFactor, secondPrimeFactor}, - Precomputed: rsa.PrecomputedValues{ - Dp: firstFactorCRT, - Dq: secondFactorCRT, - Qinv: crtCoeff, - }, - } - - if oth != nil { - // Should be an array of more JSON objects. - otherPrimesInfo, ok := oth.([]interface{}) - if !ok { - return nil, errors.New("JWK RSA Private Key: Invalid other primes info: must be an array") - } - numOtherPrimeFactors := len(otherPrimesInfo) - if numOtherPrimeFactors == 0 { - return nil, errors.New("JWK RSA Privake Key: Invalid other primes info: must be absent or non-empty") - } - otherPrimeFactors := make([]*big.Int, numOtherPrimeFactors) - productOfPrimes := new(big.Int).Mul(firstPrimeFactor, secondPrimeFactor) - crtValues := make([]rsa.CRTValue, numOtherPrimeFactors) - - for i, val := range otherPrimesInfo { - otherPrimeinfo, ok := val.(map[string]interface{}) - if !ok { - return nil, errors.New("JWK RSA Private Key: Invalid other prime info: must be a JSON object") - } - - otherPrimeFactor, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "r") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err) - } - otherFactorCRT, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "d") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err) - } - otherCrtCoeff, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "t") - if err != nil { - return nil, fmt.Errorf("JWK RSA Private Key CRT coefficient: %s", err) - } - - crtValue := crtValues[i] - crtValue.Exp = otherFactorCRT - crtValue.Coeff = otherCrtCoeff - crtValue.R = productOfPrimes - otherPrimeFactors[i] = otherPrimeFactor - productOfPrimes = new(big.Int).Mul(productOfPrimes, otherPrimeFactor) - } - - privateKey.Primes = append(privateKey.Primes, otherPrimeFactors...) - privateKey.Precomputed.CRTValues = crtValues - } - - key := &rsaPrivateKey{ - rsaPublicKey: *publicKey, - PrivateKey: privateKey, - } - - return key, nil -} - -/* - * Key Generation Functions. - */ - -func generateRSAPrivateKey(bits int) (k *rsaPrivateKey, err error) { - k = new(rsaPrivateKey) - k.PrivateKey, err = rsa.GenerateKey(rand.Reader, bits) - if err != nil { - return nil, err - } - - k.rsaPublicKey.PublicKey = &k.PrivateKey.PublicKey - k.extended = make(map[string]interface{}) - - return -} - -// GenerateRSA2048PrivateKey generates a key pair using 2048-bit RSA. -func GenerateRSA2048PrivateKey() (PrivateKey, error) { - k, err := generateRSAPrivateKey(2048) - if err != nil { - return nil, fmt.Errorf("error generating RSA 2048-bit key: %s", err) - } - - return k, nil -} - -// GenerateRSA3072PrivateKey generates a key pair using 3072-bit RSA. -func GenerateRSA3072PrivateKey() (PrivateKey, error) { - k, err := generateRSAPrivateKey(3072) - if err != nil { - return nil, fmt.Errorf("error generating RSA 3072-bit key: %s", err) - } - - return k, nil -} - -// GenerateRSA4096PrivateKey generates a key pair using 4096-bit RSA. -func GenerateRSA4096PrivateKey() (PrivateKey, error) { - k, err := generateRSAPrivateKey(4096) - if err != nil { - return nil, fmt.Errorf("error generating RSA 4096-bit key: %s", err) - } - - return k, nil -} diff --git a/vendor/github.com/docker/libtrust/util.go b/vendor/github.com/docker/libtrust/util.go deleted file mode 100644 index d88176cc3..000000000 --- a/vendor/github.com/docker/libtrust/util.go +++ /dev/null @@ -1,363 +0,0 @@ -package libtrust - -import ( - "bytes" - "crypto" - "crypto/elliptic" - "crypto/tls" - "crypto/x509" - "encoding/base32" - "encoding/base64" - "encoding/binary" - "encoding/pem" - "errors" - "fmt" - "math/big" - "net/url" - "os" - "path/filepath" - "strings" - "time" -) - -// LoadOrCreateTrustKey will load a PrivateKey from the specified path -func LoadOrCreateTrustKey(trustKeyPath string) (PrivateKey, error) { - if err := os.MkdirAll(filepath.Dir(trustKeyPath), 0700); err != nil { - return nil, err - } - - trustKey, err := LoadKeyFile(trustKeyPath) - if err == ErrKeyFileDoesNotExist { - trustKey, err = GenerateECP256PrivateKey() - if err != nil { - return nil, fmt.Errorf("error generating key: %s", err) - } - - if err := SaveKey(trustKeyPath, trustKey); err != nil { - return nil, fmt.Errorf("error saving key file: %s", err) - } - - dir, file := filepath.Split(trustKeyPath) - if err := SavePublicKey(filepath.Join(dir, "public-"+file), trustKey.PublicKey()); err != nil { - return nil, fmt.Errorf("error saving public key file: %s", err) - } - } else if err != nil { - return nil, fmt.Errorf("error loading key file: %s", err) - } - return trustKey, nil -} - -// NewIdentityAuthTLSClientConfig returns a tls.Config configured to use identity -// based authentication from the specified dockerUrl, the rootConfigPath and -// the server name to which it is connecting. -// If trustUnknownHosts is true it will automatically add the host to the -// known-hosts.json in rootConfigPath. -func NewIdentityAuthTLSClientConfig(dockerUrl string, trustUnknownHosts bool, rootConfigPath string, serverName string) (*tls.Config, error) { - tlsConfig := newTLSConfig() - - trustKeyPath := filepath.Join(rootConfigPath, "key.json") - knownHostsPath := filepath.Join(rootConfigPath, "known-hosts.json") - - u, err := url.Parse(dockerUrl) - if err != nil { - return nil, fmt.Errorf("unable to parse machine url") - } - - if u.Scheme == "unix" { - return nil, nil - } - - addr := u.Host - proto := "tcp" - - trustKey, err := LoadOrCreateTrustKey(trustKeyPath) - if err != nil { - return nil, fmt.Errorf("unable to load trust key: %s", err) - } - - knownHosts, err := LoadKeySetFile(knownHostsPath) - if err != nil { - return nil, fmt.Errorf("could not load trusted hosts file: %s", err) - } - - allowedHosts, err := FilterByHosts(knownHosts, addr, false) - if err != nil { - return nil, fmt.Errorf("error filtering hosts: %s", err) - } - - certPool, err := GenerateCACertPool(trustKey, allowedHosts) - if err != nil { - return nil, fmt.Errorf("Could not create CA pool: %s", err) - } - - tlsConfig.ServerName = serverName - tlsConfig.RootCAs = certPool - - x509Cert, err := GenerateSelfSignedClientCert(trustKey) - if err != nil { - return nil, fmt.Errorf("certificate generation error: %s", err) - } - - tlsConfig.Certificates = []tls.Certificate{{ - Certificate: [][]byte{x509Cert.Raw}, - PrivateKey: trustKey.CryptoPrivateKey(), - Leaf: x509Cert, - }} - - tlsConfig.InsecureSkipVerify = true - - testConn, err := tls.Dial(proto, addr, tlsConfig) - if err != nil { - return nil, fmt.Errorf("tls Handshake error: %s", err) - } - - opts := x509.VerifyOptions{ - Roots: tlsConfig.RootCAs, - CurrentTime: time.Now(), - DNSName: tlsConfig.ServerName, - Intermediates: x509.NewCertPool(), - } - - certs := testConn.ConnectionState().PeerCertificates - for i, cert := range certs { - if i == 0 { - continue - } - opts.Intermediates.AddCert(cert) - } - - if _, err := certs[0].Verify(opts); err != nil { - if _, ok := err.(x509.UnknownAuthorityError); ok { - if trustUnknownHosts { - pubKey, err := FromCryptoPublicKey(certs[0].PublicKey) - if err != nil { - return nil, fmt.Errorf("error extracting public key from cert: %s", err) - } - - pubKey.AddExtendedField("hosts", []string{addr}) - - if err := AddKeySetFile(knownHostsPath, pubKey); err != nil { - return nil, fmt.Errorf("error adding machine to known hosts: %s", err) - } - } else { - return nil, fmt.Errorf("unable to connect. unknown host: %s", addr) - } - } - } - - testConn.Close() - tlsConfig.InsecureSkipVerify = false - - return tlsConfig, nil -} - -// joseBase64UrlEncode encodes the given data using the standard base64 url -// encoding format but with all trailing '=' characters ommitted in accordance -// with the jose specification. -// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2 -func joseBase64UrlEncode(b []byte) string { - return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") -} - -// joseBase64UrlDecode decodes the given string using the standard base64 url -// decoder but first adds the appropriate number of trailing '=' characters in -// accordance with the jose specification. -// http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2 -func joseBase64UrlDecode(s string) ([]byte, error) { - s = strings.Replace(s, "\n", "", -1) - s = strings.Replace(s, " ", "", -1) - switch len(s) % 4 { - case 0: - case 2: - s += "==" - case 3: - s += "=" - default: - return nil, errors.New("illegal base64url string") - } - return base64.URLEncoding.DecodeString(s) -} - -func keyIDEncode(b []byte) string { - s := strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=") - var buf bytes.Buffer - var i int - for i = 0; i < len(s)/4-1; i++ { - start := i * 4 - end := start + 4 - buf.WriteString(s[start:end] + ":") - } - buf.WriteString(s[i*4:]) - return buf.String() -} - -func keyIDFromCryptoKey(pubKey PublicKey) string { - // Generate and return a 'libtrust' fingerprint of the public key. - // For an RSA key this should be: - // SHA256(DER encoded ASN1) - // Then truncated to 240 bits and encoded into 12 base32 groups like so: - // ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP - derBytes, err := x509.MarshalPKIXPublicKey(pubKey.CryptoPublicKey()) - if err != nil { - return "" - } - hasher := crypto.SHA256.New() - hasher.Write(derBytes) - return keyIDEncode(hasher.Sum(nil)[:30]) -} - -func stringFromMap(m map[string]interface{}, key string) (string, error) { - val, ok := m[key] - if !ok { - return "", fmt.Errorf("%q value not specified", key) - } - - str, ok := val.(string) - if !ok { - return "", fmt.Errorf("%q value must be a string", key) - } - delete(m, key) - - return str, nil -} - -func parseECCoordinate(cB64Url string, curve elliptic.Curve) (*big.Int, error) { - curveByteLen := (curve.Params().BitSize + 7) >> 3 - - cBytes, err := joseBase64UrlDecode(cB64Url) - if err != nil { - return nil, fmt.Errorf("invalid base64 URL encoding: %s", err) - } - cByteLength := len(cBytes) - if cByteLength != curveByteLen { - return nil, fmt.Errorf("invalid number of octets: got %d, should be %d", cByteLength, curveByteLen) - } - return new(big.Int).SetBytes(cBytes), nil -} - -func parseECPrivateParam(dB64Url string, curve elliptic.Curve) (*big.Int, error) { - dBytes, err := joseBase64UrlDecode(dB64Url) - if err != nil { - return nil, fmt.Errorf("invalid base64 URL encoding: %s", err) - } - - // The length of this octet string MUST be ceiling(log-base-2(n)/8) - // octets (where n is the order of the curve). This is because the private - // key d must be in the interval [1, n-1] so the bitlength of d should be - // no larger than the bitlength of n-1. The easiest way to find the octet - // length is to take bitlength(n-1), add 7 to force a carry, and shift this - // bit sequence right by 3, which is essentially dividing by 8 and adding - // 1 if there is any remainder. Thus, the private key value d should be - // output to (bitlength(n-1)+7)>>3 octets. - n := curve.Params().N - octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3 - dByteLength := len(dBytes) - - if dByteLength != octetLength { - return nil, fmt.Errorf("invalid number of octets: got %d, should be %d", dByteLength, octetLength) - } - - return new(big.Int).SetBytes(dBytes), nil -} - -func parseRSAModulusParam(nB64Url string) (*big.Int, error) { - nBytes, err := joseBase64UrlDecode(nB64Url) - if err != nil { - return nil, fmt.Errorf("invalid base64 URL encoding: %s", err) - } - - return new(big.Int).SetBytes(nBytes), nil -} - -func serializeRSAPublicExponentParam(e int) []byte { - // We MUST use the minimum number of octets to represent E. - // E is supposed to be 65537 for performance and security reasons - // and is what golang's rsa package generates, but it might be - // different if imported from some other generator. - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, uint32(e)) - var i int - for i = 0; i < 8; i++ { - if buf[i] != 0 { - break - } - } - return buf[i:] -} - -func parseRSAPublicExponentParam(eB64Url string) (int, error) { - eBytes, err := joseBase64UrlDecode(eB64Url) - if err != nil { - return 0, fmt.Errorf("invalid base64 URL encoding: %s", err) - } - // Only the minimum number of bytes were used to represent E, but - // binary.BigEndian.Uint32 expects at least 4 bytes, so we need - // to add zero padding if necassary. - byteLen := len(eBytes) - buf := make([]byte, 4-byteLen, 4) - eBytes = append(buf, eBytes...) - - return int(binary.BigEndian.Uint32(eBytes)), nil -} - -func parseRSAPrivateKeyParamFromMap(m map[string]interface{}, key string) (*big.Int, error) { - b64Url, err := stringFromMap(m, key) - if err != nil { - return nil, err - } - - paramBytes, err := joseBase64UrlDecode(b64Url) - if err != nil { - return nil, fmt.Errorf("invaled base64 URL encoding: %s", err) - } - - return new(big.Int).SetBytes(paramBytes), nil -} - -func createPemBlock(name string, derBytes []byte, headers map[string]interface{}) (*pem.Block, error) { - pemBlock := &pem.Block{Type: name, Bytes: derBytes, Headers: map[string]string{}} - for k, v := range headers { - switch val := v.(type) { - case string: - pemBlock.Headers[k] = val - case []string: - if k == "hosts" { - pemBlock.Headers[k] = strings.Join(val, ",") - } else { - // Return error, non-encodable type - } - default: - // Return error, non-encodable type - } - } - - return pemBlock, nil -} - -func pubKeyFromPEMBlock(pemBlock *pem.Block) (PublicKey, error) { - cryptoPublicKey, err := x509.ParsePKIXPublicKey(pemBlock.Bytes) - if err != nil { - return nil, fmt.Errorf("unable to decode Public Key PEM data: %s", err) - } - - pubKey, err := FromCryptoPublicKey(cryptoPublicKey) - if err != nil { - return nil, err - } - - addPEMHeadersToKey(pemBlock, pubKey) - - return pubKey, nil -} - -func addPEMHeadersToKey(pemBlock *pem.Block, pubKey PublicKey) { - for key, value := range pemBlock.Headers { - var safeVal interface{} - if key == "hosts" { - safeVal = strings.Split(value, ",") - } else { - safeVal = value - } - pubKey.AddExtendedField(key, safeVal) - } -} diff --git a/vendor/github.com/docker/notary/client/client.go b/vendor/github.com/docker/notary/client/client.go deleted file mode 100644 index 15070fbbf..000000000 --- a/vendor/github.com/docker/notary/client/client.go +++ /dev/null @@ -1,1014 +0,0 @@ -package client - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "os" - "path/filepath" - "strings" - "time" - - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - "github.com/docker/notary/client/changelist" - "github.com/docker/notary/cryptoservice" - store "github.com/docker/notary/storage" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/trustpinning" - "github.com/docker/notary/tuf" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" - "github.com/docker/notary/tuf/utils" -) - -func init() { - data.SetDefaultExpiryTimes(notary.NotaryDefaultExpiries) -} - -// ErrRepoNotInitialized is returned when trying to publish an uninitialized -// notary repository -type ErrRepoNotInitialized struct{} - -func (err ErrRepoNotInitialized) Error() string { - return "repository has not been initialized" -} - -// ErrInvalidRemoteRole is returned when the server is requested to manage -// a key type that is not permitted -type ErrInvalidRemoteRole struct { - Role string -} - -func (err ErrInvalidRemoteRole) Error() string { - return fmt.Sprintf( - "notary does not permit the server managing the %s key", err.Role) -} - -// ErrInvalidLocalRole is returned when the client wants to manage -// a key type that is not permitted -type ErrInvalidLocalRole struct { - Role string -} - -func (err ErrInvalidLocalRole) Error() string { - return fmt.Sprintf( - "notary does not permit the client managing the %s key", err.Role) -} - -// ErrRepositoryNotExist is returned when an action is taken on a remote -// repository that doesn't exist -type ErrRepositoryNotExist struct { - remote string - gun string -} - -func (err ErrRepositoryNotExist) Error() string { - return fmt.Sprintf("%s does not have trust data for %s", err.remote, err.gun) -} - -const ( - tufDir = "tuf" -) - -// NotaryRepository stores all the information needed to operate on a notary -// repository. -type NotaryRepository struct { - baseDir string - gun string - baseURL string - tufRepoPath string - fileStore store.MetadataStore - CryptoService signed.CryptoService - tufRepo *tuf.Repo - invalid *tuf.Repo // known data that was parsable but deemed invalid - roundTrip http.RoundTripper - trustPinning trustpinning.TrustPinConfig -} - -// repositoryFromKeystores is a helper function for NewNotaryRepository that -// takes some basic NotaryRepository parameters as well as keystores (in order -// of usage preference), and returns a NotaryRepository. -func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper, - keyStores []trustmanager.KeyStore, trustPin trustpinning.TrustPinConfig) (*NotaryRepository, error) { - - cryptoService := cryptoservice.NewCryptoService(keyStores...) - - nRepo := &NotaryRepository{ - gun: gun, - baseDir: baseDir, - baseURL: baseURL, - tufRepoPath: filepath.Join(baseDir, tufDir, filepath.FromSlash(gun)), - CryptoService: cryptoService, - roundTrip: rt, - trustPinning: trustPin, - } - - fileStore, err := store.NewFilesystemStore( - nRepo.tufRepoPath, - "metadata", - "json", - ) - if err != nil { - return nil, err - } - nRepo.fileStore = fileStore - - return nRepo, nil -} - -// Target represents a simplified version of the data TUF operates on, so external -// applications don't have to depend on TUF data types. -type Target struct { - Name string // the name of the target - Hashes data.Hashes // the hash of the target - Length int64 // the size in bytes of the target -} - -// TargetWithRole represents a Target that exists in a particular role - this is -// produced by ListTargets and GetTargetByName -type TargetWithRole struct { - Target - Role string -} - -// NewTarget is a helper method that returns a Target -func NewTarget(targetName string, targetPath string) (*Target, error) { - b, err := ioutil.ReadFile(targetPath) - if err != nil { - return nil, err - } - - meta, err := data.NewFileMeta(bytes.NewBuffer(b), data.NotaryDefaultHashes...) - if err != nil { - return nil, err - } - - return &Target{Name: targetName, Hashes: meta.Hashes, Length: meta.Length}, nil -} - -func rootCertKey(gun string, privKey data.PrivateKey) (data.PublicKey, error) { - // Hard-coded policy: the generated certificate expires in 10 years. - startTime := time.Now() - cert, err := cryptoservice.GenerateCertificate( - privKey, gun, startTime, startTime.Add(notary.Year*10)) - if err != nil { - return nil, err - } - - x509PublicKey := utils.CertToKey(cert) - if x509PublicKey == nil { - return nil, fmt.Errorf( - "cannot use regenerated certificate: format %s", cert.PublicKeyAlgorithm) - } - - return x509PublicKey, nil -} - -// Initialize creates a new repository by using rootKey as the root Key for the -// TUF repository. The server must be reachable (and is asked to generate a -// timestamp key and possibly other serverManagedRoles), but the created repository -// result is only stored on local disk, not published to the server. To do that, -// use r.Publish() eventually. -func (r *NotaryRepository) Initialize(rootKeyIDs []string, serverManagedRoles ...string) error { - privKeys := make([]data.PrivateKey, 0, len(rootKeyIDs)) - for _, keyID := range rootKeyIDs { - privKey, _, err := r.CryptoService.GetPrivateKey(keyID) - if err != nil { - return err - } - privKeys = append(privKeys, privKey) - } - - // currently we only support server managing timestamps and snapshots, and - // nothing else - timestamps are always managed by the server, and implicit - // (do not have to be passed in as part of `serverManagedRoles`, so that - // the API of Initialize doesn't change). - var serverManagesSnapshot bool - locallyManagedKeys := []string{ - data.CanonicalTargetsRole, - data.CanonicalSnapshotRole, - // root is also locally managed, but that should have been created - // already - } - remotelyManagedKeys := []string{data.CanonicalTimestampRole} - for _, role := range serverManagedRoles { - switch role { - case data.CanonicalTimestampRole: - continue // timestamp is already in the right place - case data.CanonicalSnapshotRole: - // because we put Snapshot last - locallyManagedKeys = []string{data.CanonicalTargetsRole} - remotelyManagedKeys = append( - remotelyManagedKeys, data.CanonicalSnapshotRole) - serverManagesSnapshot = true - default: - return ErrInvalidRemoteRole{Role: role} - } - } - - rootKeys := make([]data.PublicKey, 0, len(privKeys)) - for _, privKey := range privKeys { - rootKey, err := rootCertKey(r.gun, privKey) - if err != nil { - return err - } - rootKeys = append(rootKeys, rootKey) - } - - var ( - rootRole = data.NewBaseRole( - data.CanonicalRootRole, - notary.MinThreshold, - rootKeys..., - ) - timestampRole data.BaseRole - snapshotRole data.BaseRole - targetsRole data.BaseRole - ) - - // we want to create all the local keys first so we don't have to - // make unnecessary network calls - for _, role := range locallyManagedKeys { - // This is currently hardcoding the keys to ECDSA. - key, err := r.CryptoService.Create(role, r.gun, data.ECDSAKey) - if err != nil { - return err - } - switch role { - case data.CanonicalSnapshotRole: - snapshotRole = data.NewBaseRole( - role, - notary.MinThreshold, - key, - ) - case data.CanonicalTargetsRole: - targetsRole = data.NewBaseRole( - role, - notary.MinThreshold, - key, - ) - } - } - for _, role := range remotelyManagedKeys { - // This key is generated by the remote server. - key, err := getRemoteKey(r.baseURL, r.gun, role, r.roundTrip) - if err != nil { - return err - } - logrus.Debugf("got remote %s %s key with keyID: %s", - role, key.Algorithm(), key.ID()) - switch role { - case data.CanonicalSnapshotRole: - snapshotRole = data.NewBaseRole( - role, - notary.MinThreshold, - key, - ) - case data.CanonicalTimestampRole: - timestampRole = data.NewBaseRole( - role, - notary.MinThreshold, - key, - ) - } - } - - r.tufRepo = tuf.NewRepo(r.CryptoService) - - err := r.tufRepo.InitRoot( - rootRole, - timestampRole, - snapshotRole, - targetsRole, - false, - ) - if err != nil { - logrus.Debug("Error on InitRoot: ", err.Error()) - return err - } - _, err = r.tufRepo.InitTargets(data.CanonicalTargetsRole) - if err != nil { - logrus.Debug("Error on InitTargets: ", err.Error()) - return err - } - err = r.tufRepo.InitSnapshot() - if err != nil { - logrus.Debug("Error on InitSnapshot: ", err.Error()) - return err - } - - return r.saveMetadata(serverManagesSnapshot) -} - -// adds a TUF Change template to the given roles -func addChange(cl *changelist.FileChangelist, c changelist.Change, roles ...string) error { - - if len(roles) == 0 { - roles = []string{data.CanonicalTargetsRole} - } - - var changes []changelist.Change - for _, role := range roles { - // Ensure we can only add targets to the CanonicalTargetsRole, - // or a Delegation role (which is /something else) - if role != data.CanonicalTargetsRole && !data.IsDelegation(role) && !data.IsWildDelegation(role) { - return data.ErrInvalidRole{ - Role: role, - Reason: "cannot add targets to this role", - } - } - - changes = append(changes, changelist.NewTUFChange( - c.Action(), - role, - c.Type(), - c.Path(), - c.Content(), - )) - } - - for _, c := range changes { - if err := cl.Add(c); err != nil { - return err - } - } - return nil -} - -// AddTarget creates new changelist entries to add a target to the given roles -// in the repository when the changelist gets applied at publish time. -// If roles are unspecified, the default role is "targets" -func (r *NotaryRepository) AddTarget(target *Target, roles ...string) error { - - if len(target.Hashes) == 0 { - return fmt.Errorf("no hashes specified for target \"%s\"", target.Name) - } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf("Adding target \"%s\" with sha256 \"%x\" and size %d bytes.\n", target.Name, target.Hashes["sha256"], target.Length) - - meta := data.FileMeta{Length: target.Length, Hashes: target.Hashes} - metaJSON, err := json.Marshal(meta) - if err != nil { - return err - } - - template := changelist.NewTUFChange( - changelist.ActionCreate, "", changelist.TypeTargetsTarget, - target.Name, metaJSON) - return addChange(cl, template, roles...) -} - -// RemoveTarget creates new changelist entries to remove a target from the given -// roles in the repository when the changelist gets applied at publish time. -// If roles are unspecified, the default role is "target". -func (r *NotaryRepository) RemoveTarget(targetName string, roles ...string) error { - - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - logrus.Debugf("Removing target \"%s\"", targetName) - template := changelist.NewTUFChange(changelist.ActionDelete, "", - changelist.TypeTargetsTarget, targetName, nil) - return addChange(cl, template, roles...) -} - -// ListTargets lists all targets for the current repository. The list of -// roles should be passed in order from highest to lowest priority. -// -// IMPORTANT: if you pass a set of roles such as [ "targets/a", "targets/x" -// "targets/a/b" ], even though "targets/a/b" is part of the "targets/a" subtree -// its entries will be strictly shadowed by those in other parts of the "targets/a" -// subtree and also the "targets/x" subtree, as we will defer parsing it until -// we explicitly reach it in our iteration of the provided list of roles. -func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, error) { - if err := r.Update(false); err != nil { - return nil, err - } - - if len(roles) == 0 { - roles = []string{data.CanonicalTargetsRole} - } - targets := make(map[string]*TargetWithRole) - for _, role := range roles { - // Define an array of roles to skip for this walk (see IMPORTANT comment above) - skipRoles := utils.StrSliceRemove(roles, role) - - // Define a visitor function to populate the targets map in priority order - listVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { - // We found targets so we should try to add them to our targets map - for targetName, targetMeta := range tgt.Signed.Targets { - // Follow the priority by not overriding previously set targets - // and check that this path is valid with this role - if _, ok := targets[targetName]; ok || !validRole.CheckPaths(targetName) { - continue - } - targets[targetName] = &TargetWithRole{ - Target: Target{ - Name: targetName, - Hashes: targetMeta.Hashes, - Length: targetMeta.Length, - }, - Role: validRole.Name, - } - } - return nil - } - - r.tufRepo.WalkTargets("", role, listVisitorFunc, skipRoles...) - } - - var targetList []*TargetWithRole - for _, v := range targets { - targetList = append(targetList, v) - } - - return targetList, nil -} - -// GetTargetByName returns a target by the given name. If no roles are passed -// it uses the targets role and does a search of the entire delegation -// graph, finding the first entry in a breadth first search of the delegations. -// If roles are passed, they should be passed in descending priority and -// the target entry found in the subtree of the highest priority role -// will be returned. -// See the IMPORTANT section on ListTargets above. Those roles also apply here. -func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*TargetWithRole, error) { - if err := r.Update(false); err != nil { - return nil, err - } - - if len(roles) == 0 { - roles = append(roles, data.CanonicalTargetsRole) - } - var resultMeta data.FileMeta - var resultRoleName string - var foundTarget bool - for _, role := range roles { - // Define an array of roles to skip for this walk (see IMPORTANT comment above) - skipRoles := utils.StrSliceRemove(roles, role) - - // Define a visitor function to find the specified target - getTargetVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { - if tgt == nil { - return nil - } - // We found the target and validated path compatibility in our walk, - // so we should stop our walk and set the resultMeta and resultRoleName variables - if resultMeta, foundTarget = tgt.Signed.Targets[name]; foundTarget { - resultRoleName = validRole.Name - return tuf.StopWalk{} - } - return nil - } - // Check that we didn't error, and that we assigned to our target - if err := r.tufRepo.WalkTargets(name, role, getTargetVisitorFunc, skipRoles...); err == nil && foundTarget { - return &TargetWithRole{Target: Target{Name: name, Hashes: resultMeta.Hashes, Length: resultMeta.Length}, Role: resultRoleName}, nil - } - } - return nil, fmt.Errorf("No trust data for %s", name) - -} - -// TargetSignedStruct is a struct that contains a Target, the role it was found in, and the list of signatures for that role -type TargetSignedStruct struct { - Role data.DelegationRole - Target Target - Signatures []data.Signature -} - -// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all -// roles, and returns a list of TargetSignedStructs for each time it finds the specified target. -// If given an empty string for a target name, it will return back all targets signed into the repository in every role -func (r *NotaryRepository) GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error) { - if err := r.Update(false); err != nil { - return nil, err - } - - var targetInfoList []TargetSignedStruct - - // Define a visitor function to find the specified target - getAllTargetInfoByNameVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { - if tgt == nil { - return nil - } - // We found a target and validated path compatibility in our walk, - // so add it to our list if we have a match - // if we have an empty name, add all targets, else check if we have it - var targetMetaToAdd data.Files - if name == "" { - targetMetaToAdd = tgt.Signed.Targets - } else { - if meta, ok := tgt.Signed.Targets[name]; ok { - targetMetaToAdd = data.Files{name: meta} - } - } - - for targetName, resultMeta := range targetMetaToAdd { - targetInfo := TargetSignedStruct{ - Role: validRole, - Target: Target{Name: targetName, Hashes: resultMeta.Hashes, Length: resultMeta.Length}, - Signatures: tgt.Signatures, - } - targetInfoList = append(targetInfoList, targetInfo) - } - // continue walking to all child roles - return nil - } - - // Check that we didn't error, and that we found the target at least once - if err := r.tufRepo.WalkTargets(name, "", getAllTargetInfoByNameVisitorFunc); err != nil { - return nil, err - } - if len(targetInfoList) == 0 { - return nil, fmt.Errorf("No valid trust data for %s", name) - } - return targetInfoList, nil -} - -// GetChangelist returns the list of the repository's unpublished changes -func (r *NotaryRepository) GetChangelist() (changelist.Changelist, error) { - changelistDir := filepath.Join(r.tufRepoPath, "changelist") - cl, err := changelist.NewFileChangelist(changelistDir) - if err != nil { - logrus.Debug("Error initializing changelist") - return nil, err - } - return cl, nil -} - -// RoleWithSignatures is a Role with its associated signatures -type RoleWithSignatures struct { - Signatures []data.Signature - data.Role -} - -// ListRoles returns a list of RoleWithSignatures objects for this repo -// This represents the latest metadata for each role in this repo -func (r *NotaryRepository) ListRoles() ([]RoleWithSignatures, error) { - // Update to latest repo state - if err := r.Update(false); err != nil { - return nil, err - } - - // Get all role info from our updated keysDB, can be empty - roles := r.tufRepo.GetAllLoadedRoles() - - var roleWithSigs []RoleWithSignatures - - // Populate RoleWithSignatures with Role from keysDB and signatures from TUF metadata - for _, role := range roles { - roleWithSig := RoleWithSignatures{Role: *role, Signatures: nil} - switch role.Name { - case data.CanonicalRootRole: - roleWithSig.Signatures = r.tufRepo.Root.Signatures - case data.CanonicalTargetsRole: - roleWithSig.Signatures = r.tufRepo.Targets[data.CanonicalTargetsRole].Signatures - case data.CanonicalSnapshotRole: - roleWithSig.Signatures = r.tufRepo.Snapshot.Signatures - case data.CanonicalTimestampRole: - roleWithSig.Signatures = r.tufRepo.Timestamp.Signatures - default: - if !data.IsDelegation(role.Name) { - continue - } - if _, ok := r.tufRepo.Targets[role.Name]; ok { - // We'll only find a signature if we've published any targets with this delegation - roleWithSig.Signatures = r.tufRepo.Targets[role.Name].Signatures - } - } - roleWithSigs = append(roleWithSigs, roleWithSig) - } - return roleWithSigs, nil -} - -// Publish pushes the local changes in signed material to the remote notary-server -// Conceptually it performs an operation similar to a `git rebase` -func (r *NotaryRepository) Publish() error { - cl, err := r.GetChangelist() - if err != nil { - return err - } - if err = r.publish(cl); err != nil { - return err - } - if err = cl.Clear(""); err != nil { - // This is not a critical problem when only a single host is pushing - // but will cause weird behaviour if changelist cleanup is failing - // and there are multiple hosts writing to the repo. - logrus.Warn("Unable to clear changelist. You may want to manually delete the folder ", filepath.Join(r.tufRepoPath, "changelist")) - } - return nil -} - -// publish pushes the changes in the given changelist to the remote notary-server -// Conceptually it performs an operation similar to a `git rebase` -func (r *NotaryRepository) publish(cl changelist.Changelist) error { - var initialPublish bool - // update first before publishing - if err := r.Update(true); err != nil { - // If the remote is not aware of the repo, then this is being published - // for the first time. Try to load from disk instead for publishing. - if _, ok := err.(ErrRepositoryNotExist); ok { - err := r.bootstrapRepo() - if err != nil { - logrus.Debugf("Unable to load repository from local files: %s", - err.Error()) - if _, ok := err.(store.ErrMetaNotFound); ok { - return ErrRepoNotInitialized{} - } - return err - } - // Ensure we will push the initial root and targets file. Either or - // both of the root and targets may not be marked as Dirty, since - // there may not be any changes that update them, so use a - // different boolean. - initialPublish = true - } else { - // We could not update, so we cannot publish. - logrus.Error("Could not publish Repository since we could not update: ", err.Error()) - return err - } - } - // apply the changelist to the repo - if err := applyChangelist(r.tufRepo, r.invalid, cl); err != nil { - logrus.Debug("Error applying changelist") - return err - } - - // these are the TUF files we will need to update, serialized as JSON before - // we send anything to remote - updatedFiles := make(map[string][]byte) - - // check if our root file is nearing expiry or dirty. Resign if it is. If - // root is not dirty but we are publishing for the first time, then just - // publish the existing root we have. - if nearExpiry(r.tufRepo.Root.Signed.SignedCommon) || r.tufRepo.Root.Dirty { - rootJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalRootRole) - if err != nil { - return err - } - updatedFiles[data.CanonicalRootRole] = rootJSON - } else if initialPublish { - rootJSON, err := r.tufRepo.Root.MarshalJSON() - if err != nil { - return err - } - updatedFiles[data.CanonicalRootRole] = rootJSON - } - - // iterate through all the targets files - if they are dirty, sign and update - for roleName, roleObj := range r.tufRepo.Targets { - if roleObj.Dirty || (roleName == data.CanonicalTargetsRole && initialPublish) { - targetsJSON, err := serializeCanonicalRole(r.tufRepo, roleName) - if err != nil { - return err - } - updatedFiles[roleName] = targetsJSON - } - } - - // if we initialized the repo while designating the server as the snapshot - // signer, then there won't be a snapshots file. However, we might now - // have a local key (if there was a rotation), so initialize one. - if r.tufRepo.Snapshot == nil { - if err := r.tufRepo.InitSnapshot(); err != nil { - return err - } - } - - snapshotJSON, err := serializeCanonicalRole( - r.tufRepo, data.CanonicalSnapshotRole) - - if err == nil { - // Only update the snapshot if we've successfully signed it. - updatedFiles[data.CanonicalSnapshotRole] = snapshotJSON - } else if signErr, ok := err.(signed.ErrInsufficientSignatures); ok && signErr.FoundKeys == 0 { - // If signing fails due to us not having the snapshot key, then - // assume the server is going to sign, and do not include any snapshot - // data. - logrus.Debugf("Client does not have the key to sign snapshot. " + - "Assuming that server should sign the snapshot.") - } else { - logrus.Debugf("Client was unable to sign the snapshot: %s", err.Error()) - return err - } - - remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip) - if err != nil { - return err - } - - return remote.SetMulti(updatedFiles) -} - -// bootstrapRepo loads the repository from the local file system (i.e. -// a not yet published repo or a possibly obsolete local copy) into -// r.tufRepo. This attempts to load metadata for all roles. Since server -// snapshots are supported, if the snapshot metadata fails to load, that's ok. -// This assumes that bootstrapRepo is only used by Publish() or RotateKey() -func (r *NotaryRepository) bootstrapRepo() error { - b := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning) - - logrus.Debugf("Loading trusted collection.") - - for _, role := range data.BaseRoles { - jsonBytes, err := r.fileStore.GetSized(role, store.NoSizeLimit) - if err != nil { - if _, ok := err.(store.ErrMetaNotFound); ok && - // server snapshots are supported, and server timestamp management - // is required, so if either of these fail to load that's ok - especially - // if the repo is new - role == data.CanonicalSnapshotRole || role == data.CanonicalTimestampRole { - continue - } - return err - } - if err := b.Load(role, jsonBytes, 1, true); err != nil { - return err - } - } - - tufRepo, _, err := b.Finish() - if err == nil { - r.tufRepo = tufRepo - } - return nil -} - -// saveMetadata saves contents of r.tufRepo onto the local disk, creating -// signatures as necessary, possibly prompting for passphrases. -func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error { - logrus.Debugf("Saving changes to Trusted Collection.") - - rootJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalRootRole) - if err != nil { - return err - } - err = r.fileStore.Set(data.CanonicalRootRole, rootJSON) - if err != nil { - return err - } - - targetsToSave := make(map[string][]byte) - for t := range r.tufRepo.Targets { - signedTargets, err := r.tufRepo.SignTargets(t, data.DefaultExpires(data.CanonicalTargetsRole)) - if err != nil { - return err - } - targetsJSON, err := json.Marshal(signedTargets) - if err != nil { - return err - } - targetsToSave[t] = targetsJSON - } - - for role, blob := range targetsToSave { - parentDir := filepath.Dir(role) - os.MkdirAll(parentDir, 0755) - r.fileStore.Set(role, blob) - } - - if ignoreSnapshot { - return nil - } - - snapshotJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalSnapshotRole) - if err != nil { - return err - } - - return r.fileStore.Set(data.CanonicalSnapshotRole, snapshotJSON) -} - -// returns a properly constructed ErrRepositoryNotExist error based on this -// repo's information -func (r *NotaryRepository) errRepositoryNotExist() error { - host := r.baseURL - parsed, err := url.Parse(r.baseURL) - if err == nil { - host = parsed.Host // try to exclude the scheme and any paths - } - return ErrRepositoryNotExist{remote: host, gun: r.gun} -} - -// Update bootstraps a trust anchor (root.json) before updating all the -// metadata from the repo. -func (r *NotaryRepository) Update(forWrite bool) error { - c, err := r.bootstrapClient(forWrite) - if err != nil { - if _, ok := err.(store.ErrMetaNotFound); ok { - return r.errRepositoryNotExist() - } - return err - } - repo, invalid, err := c.Update() - if err != nil { - // notFound.Resource may include a checksum so when the role is root, - // it will be root or root.. Therefore best we can - // do it match a "root." prefix - if notFound, ok := err.(store.ErrMetaNotFound); ok && strings.HasPrefix(notFound.Resource, data.CanonicalRootRole+".") { - return r.errRepositoryNotExist() - } - return err - } - // we can be assured if we are at this stage that the repo we built is good - // no need to test the following function call for an error as it will always be fine should the repo be good- it is! - r.tufRepo = repo - r.invalid = invalid - warnRolesNearExpiry(repo) - return nil -} - -// bootstrapClient attempts to bootstrap a root.json to be used as the trust -// anchor for a repository. The checkInitialized argument indicates whether -// we should always attempt to contact the server to determine if the repository -// is initialized or not. If set to true, we will always attempt to download -// and return an error if the remote repository errors. -// -// Populates a tuf.RepoBuilder with this root metadata (only use -// TUFClient.Update to load the rest). -// -// Fails if the remote server is reachable and does not know the repo -// (i.e. before the first r.Publish()), in which case the error is -// store.ErrMetaNotFound, or if the root metadata (from whichever source is used) -// is not trusted. -// -// Returns a TUFClient for the remote server, which may not be actually -// operational (if the URL is invalid but a root.json is cached). -func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, error) { - minVersion := 1 - // the old root on disk should not be validated against any trust pinning configuration - // because if we have an old root, it itself is the thing that pins trust - oldBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, trustpinning.TrustPinConfig{}) - - // by default, we want to use the trust pinning configuration on any new root that we download - newBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning) - - // Try to read root from cache first. We will trust this root until we detect a problem - // during update which will cause us to download a new root and perform a rotation. - // If we have an old root, and it's valid, then we overwrite the newBuilder to be one - // preloaded with the old root or one which uses the old root for trust bootstrapping. - if rootJSON, err := r.fileStore.GetSized(data.CanonicalRootRole, store.NoSizeLimit); err == nil { - // if we can't load the cached root, fail hard because that is how we pin trust - if err := oldBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, true); err != nil { - return nil, err - } - - // again, the root on disk is the source of trust pinning, so use an empty trust - // pinning configuration - newBuilder = tuf.NewRepoBuilder(r.gun, r.CryptoService, trustpinning.TrustPinConfig{}) - - if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil { - // Ok, the old root is expired - we want to download a new one. But we want to use the - // old root to verify the new root, so bootstrap a new builder with the old builder - // but use the trustpinning to validate the new root - minVersion = oldBuilder.GetLoadedVersion(data.CanonicalRootRole) - newBuilder = oldBuilder.BootstrapNewBuilderWithNewTrustpin(r.trustPinning) - } - } - - remote, remoteErr := getRemoteStore(r.baseURL, r.gun, r.roundTrip) - if remoteErr != nil { - logrus.Error(remoteErr) - } else if !newBuilder.IsLoaded(data.CanonicalRootRole) || checkInitialized { - // remoteErr was nil and we were not able to load a root from cache or - // are specifically checking for initialization of the repo. - - // if remote store successfully set up, try and get root from remote - // We don't have any local data to determine the size of root, so try the maximum (though it is restricted at 100MB) - tmpJSON, err := remote.GetSized(data.CanonicalRootRole, store.NoSizeLimit) - if err != nil { - // we didn't have a root in cache and were unable to load one from - // the server. Nothing we can do but error. - return nil, err - } - - if !newBuilder.IsLoaded(data.CanonicalRootRole) { - // we always want to use the downloaded root if we couldn't load from cache - if err := newBuilder.Load(data.CanonicalRootRole, tmpJSON, minVersion, false); err != nil { - return nil, err - } - - err = r.fileStore.Set(data.CanonicalRootRole, tmpJSON) - if err != nil { - // if we can't write cache we should still continue, just log error - logrus.Errorf("could not save root to cache: %s", err.Error()) - } - } - } - - // We can only get here if remoteErr != nil (hence we don't download any new root), - // and there was no root on disk - if !newBuilder.IsLoaded(data.CanonicalRootRole) { - return nil, ErrRepoNotInitialized{} - } - - return NewTUFClient(oldBuilder, newBuilder, remote, r.fileStore), nil -} - -// RotateKey removes all existing keys associated with the role, and either -// creates and adds one new key or delegates managing the key to the server. -// These changes are staged in a changelist until publish is called. -func (r *NotaryRepository) RotateKey(role string, serverManagesKey bool) error { - // We currently support remotely managing timestamp and snapshot keys - canBeRemoteKey := role == data.CanonicalTimestampRole || role == data.CanonicalSnapshotRole - // And locally managing root, targets, and snapshot keys - canBeLocalKey := (role == data.CanonicalSnapshotRole || role == data.CanonicalTargetsRole || - role == data.CanonicalRootRole) - - switch { - case !data.ValidRole(role) || data.IsDelegation(role): - return fmt.Errorf("notary does not currently permit rotating the %s key", role) - case serverManagesKey && !canBeRemoteKey: - return ErrInvalidRemoteRole{Role: role} - case !serverManagesKey && !canBeLocalKey: - return ErrInvalidLocalRole{Role: role} - } - - var ( - pubKey data.PublicKey - err error - errFmtMsg string - ) - switch serverManagesKey { - case true: - pubKey, err = rotateRemoteKey(r.baseURL, r.gun, role, r.roundTrip) - errFmtMsg = "unable to rotate remote key: %s" - default: - pubKey, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey) - errFmtMsg = "unable to generate key: %s" - } - - if err != nil { - return fmt.Errorf(errFmtMsg, err) - } - - // if this is a root role, generate a root cert for the public key - if role == data.CanonicalRootRole { - privKey, _, err := r.CryptoService.GetPrivateKey(pubKey.ID()) - if err != nil { - return err - } - pubKey, err = rootCertKey(r.gun, privKey) - if err != nil { - return err - } - } - - cl := changelist.NewMemChangelist() - if err := r.rootFileKeyChange(cl, role, changelist.ActionCreate, pubKey); err != nil { - return err - } - return r.publish(cl) -} - -func (r *NotaryRepository) rootFileKeyChange(cl changelist.Changelist, role, action string, key data.PublicKey) error { - kl := make(data.KeyList, 0, 1) - kl = append(kl, key) - meta := changelist.TUFRootData{ - RoleName: role, - Keys: kl, - } - metaJSON, err := json.Marshal(meta) - if err != nil { - return err - } - - c := changelist.NewTUFChange( - action, - changelist.ScopeRoot, - changelist.TypeRootRole, - role, - metaJSON, - ) - return cl.Add(c) -} - -// DeleteTrustData removes the trust data stored for this repo in the TUF cache on the client side -// Note that we will not delete any private key material from local storage -func (r *NotaryRepository) DeleteTrustData(deleteRemote bool) error { - // Remove the tufRepoPath directory, which includes local TUF metadata files and changelist information - if err := os.RemoveAll(r.tufRepoPath); err != nil { - return fmt.Errorf("error clearing TUF repo data: %v", err) - } - // Note that this will require admin permission in this NotaryRepository's roundtripper - if deleteRemote { - remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip) - if err != nil { - return err - } - if err := remote.RemoveAll(); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/docker/notary/client/repo.go b/vendor/github.com/docker/notary/client/repo.go deleted file mode 100644 index 27f857616..000000000 --- a/vendor/github.com/docker/notary/client/repo.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build !pkcs11 - -package client - -import ( - "fmt" - "net/http" - - "github.com/docker/notary" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/trustpinning" -) - -// NewNotaryRepository is a helper method that returns a new notary repository. -// It takes the base directory under where all the trust files will be stored -// (This is normally defaults to "~/.notary" or "~/.docker/trust" when enabling -// docker content trust). -func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper, - retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) ( - *NotaryRepository, error) { - - fileKeyStore, err := trustmanager.NewKeyFileStore(baseDir, retriever) - if err != nil { - return nil, fmt.Errorf("failed to create private key store in directory: %s", baseDir) - } - - return repositoryFromKeystores(baseDir, gun, baseURL, rt, - []trustmanager.KeyStore{fileKeyStore}, trustPinning) -} diff --git a/vendor/github.com/docker/notary/client/repo_pkcs11.go b/vendor/github.com/docker/notary/client/repo_pkcs11.go deleted file mode 100644 index bbbe4762f..000000000 --- a/vendor/github.com/docker/notary/client/repo_pkcs11.go +++ /dev/null @@ -1,34 +0,0 @@ -// +build pkcs11 - -package client - -import ( - "fmt" - "net/http" - - "github.com/docker/notary" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/trustmanager/yubikey" - "github.com/docker/notary/trustpinning" -) - -// NewNotaryRepository is a helper method that returns a new notary repository. -// It takes the base directory under where all the trust files will be stored -// (usually ~/.docker/trust/). -func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper, - retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) ( - *NotaryRepository, error) { - - fileKeyStore, err := trustmanager.NewKeyFileStore(baseDir, retriever) - if err != nil { - return nil, fmt.Errorf("failed to create private key store in directory: %s", baseDir) - } - - keyStores := []trustmanager.KeyStore{fileKeyStore} - yubiKeyStore, _ := yubikey.NewYubiStore(fileKeyStore, retriever) - if yubiKeyStore != nil { - keyStores = []trustmanager.KeyStore{yubiKeyStore, fileKeyStore} - } - - return repositoryFromKeystores(baseDir, gun, baseURL, rt, keyStores, trustPinning) -} diff --git a/vendor/github.com/Sirupsen/logrus/LICENSE b/vendor/github.com/sirupsen/logrus/LICENSE similarity index 100% rename from vendor/github.com/Sirupsen/logrus/LICENSE rename to vendor/github.com/sirupsen/logrus/LICENSE diff --git a/vendor/github.com/Sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md similarity index 85% rename from vendor/github.com/Sirupsen/logrus/README.md rename to vendor/github.com/sirupsen/logrus/README.md index c32287611..4f5ce576d 100644 --- a/vendor/github.com/Sirupsen/logrus/README.md +++ b/vendor/github.com/sirupsen/logrus/README.md @@ -1,17 +1,24 @@ -# 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) - -**Seeing weird case-sensitive problems?** See [this -issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021). -This change has been reverted. I apologize for causing this. I greatly -underestimated the impact this would have. Logrus strives for stability and -backwards compatibility and failed to provide that. +# 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. [Godoc][godoc]. **Please note the Logrus API is not -yet stable (pre 1.0). Logrus itself is completely stable and has been used in -many large deployments. The core API is unlikely to change much but please -version control your Logrus to make sure you aren't fetching latest `master` on -every build.** +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): @@ -52,6 +59,12 @@ time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x20822 exit status 1 ``` +#### 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: @@ -60,7 +73,7 @@ The simplest way to use Logrus is simply the package-level exported logger: package main import ( - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) func main() { @@ -71,7 +84,7 @@ func main() { ``` 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"` +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: @@ -80,7 +93,7 @@ package main import ( "os" - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) func init() { @@ -131,7 +144,7 @@ package main import ( "os" - "github.com/Sirupsen/logrus" + "github.com/sirupsen/logrus" ) // Create a new instance of the logger. You can have any number of instances. @@ -159,7 +172,7 @@ func main() { #### Fields -Logrus encourages careful, structured logging though logging fields instead of +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: @@ -206,9 +219,9 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in ```go import ( - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" - logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" "log/syslog" ) @@ -238,14 +251,14 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | | [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) | | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| -| [Firehose](https://github.com/beaubrewer/firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/) +| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/) | [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | | [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) | | [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | | [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | | [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | | [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | -| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) | +| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) | | [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | | [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka | | [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | @@ -255,6 +268,7 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | | [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | | [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | +| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) | | [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | | [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) | | [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | @@ -269,10 +283,12 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v | [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | | [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) | | [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| -| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | +| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | +| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. | | [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) | | [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | | [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | +| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) | #### Level logging @@ -321,7 +337,7 @@ could do: ```go import ( - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) init() { @@ -356,6 +372,7 @@ The built-in logging formatters are: Third party logging formatters: +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can by parsed by Kubernetes and Google Container Engine. * [`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̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. @@ -434,15 +451,24 @@ Logrus has a built in facility for asserting the presence of log messages. This * a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): ```go -logger, hook := NewNullLogger() -logger.Error("Hello error") +import( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "testing" +) -assert.Equal(1, len(hook.Entries)) -assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) -assert.Equal("Hello error", hook.LastEntry().Message) +func TestSomething(t*testing.T){ + logger, hook := test.NewNullLogger() + logger.Error("Helloerror") -hook.Reset() -assert.Nil(hook.LastEntry()) + 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 diff --git a/vendor/github.com/Sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go similarity index 100% rename from vendor/github.com/Sirupsen/logrus/alt_exit.go rename to vendor/github.com/sirupsen/logrus/alt_exit.go diff --git a/vendor/github.com/Sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go similarity index 83% rename from vendor/github.com/Sirupsen/logrus/doc.go rename to vendor/github.com/sirupsen/logrus/doc.go index dddd5f877..da67aba06 100644 --- a/vendor/github.com/Sirupsen/logrus/doc.go +++ b/vendor/github.com/sirupsen/logrus/doc.go @@ -7,7 +7,7 @@ The simplest way to use Logrus is simply the package-level exported logger: package main import ( - log "github.com/Sirupsen/logrus" + log "github.com/sirupsen/logrus" ) func main() { @@ -21,6 +21,6 @@ The simplest way to use Logrus is simply the package-level exported logger: 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 +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 similarity index 87% rename from vendor/github.com/Sirupsen/logrus/entry.go rename to vendor/github.com/sirupsen/logrus/entry.go index 4edbe7a2d..5bf582ef2 100644 --- a/vendor/github.com/Sirupsen/logrus/entry.go +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -35,6 +35,7 @@ type Entry struct { Time time.Time // Level the log entry was logged at: 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 // Message passed to Debug, Info, Warn, Error, Fatal or Panic @@ -126,7 +127,7 @@ func (entry Entry) log(level Level, msg string) { } func (entry *Entry) Debug(args ...interface{}) { - if entry.Logger.Level >= DebugLevel { + if entry.Logger.level() >= DebugLevel { entry.log(DebugLevel, fmt.Sprint(args...)) } } @@ -136,13 +137,13 @@ func (entry *Entry) Print(args ...interface{}) { } func (entry *Entry) Info(args ...interface{}) { - if entry.Logger.Level >= InfoLevel { + if entry.Logger.level() >= InfoLevel { entry.log(InfoLevel, fmt.Sprint(args...)) } } func (entry *Entry) Warn(args ...interface{}) { - if entry.Logger.Level >= WarnLevel { + if entry.Logger.level() >= WarnLevel { entry.log(WarnLevel, fmt.Sprint(args...)) } } @@ -152,20 +153,20 @@ func (entry *Entry) Warning(args ...interface{}) { } func (entry *Entry) Error(args ...interface{}) { - if entry.Logger.Level >= ErrorLevel { + if entry.Logger.level() >= ErrorLevel { entry.log(ErrorLevel, fmt.Sprint(args...)) } } func (entry *Entry) Fatal(args ...interface{}) { - if entry.Logger.Level >= FatalLevel { + if entry.Logger.level() >= FatalLevel { entry.log(FatalLevel, fmt.Sprint(args...)) } Exit(1) } func (entry *Entry) Panic(args ...interface{}) { - if entry.Logger.Level >= PanicLevel { + if entry.Logger.level() >= PanicLevel { entry.log(PanicLevel, fmt.Sprint(args...)) } panic(fmt.Sprint(args...)) @@ -174,13 +175,13 @@ func (entry *Entry) Panic(args ...interface{}) { // Entry Printf family functions func (entry *Entry) Debugf(format string, args ...interface{}) { - if entry.Logger.Level >= DebugLevel { + if entry.Logger.level() >= DebugLevel { entry.Debug(fmt.Sprintf(format, args...)) } } func (entry *Entry) Infof(format string, args ...interface{}) { - if entry.Logger.Level >= InfoLevel { + if entry.Logger.level() >= InfoLevel { entry.Info(fmt.Sprintf(format, args...)) } } @@ -190,7 +191,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) { } func (entry *Entry) Warnf(format string, args ...interface{}) { - if entry.Logger.Level >= WarnLevel { + if entry.Logger.level() >= WarnLevel { entry.Warn(fmt.Sprintf(format, args...)) } } @@ -200,20 +201,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) { } func (entry *Entry) Errorf(format string, args ...interface{}) { - if entry.Logger.Level >= ErrorLevel { + if entry.Logger.level() >= ErrorLevel { entry.Error(fmt.Sprintf(format, args...)) } } func (entry *Entry) Fatalf(format string, args ...interface{}) { - if entry.Logger.Level >= FatalLevel { + if entry.Logger.level() >= FatalLevel { entry.Fatal(fmt.Sprintf(format, args...)) } Exit(1) } func (entry *Entry) Panicf(format string, args ...interface{}) { - if entry.Logger.Level >= PanicLevel { + if entry.Logger.level() >= PanicLevel { entry.Panic(fmt.Sprintf(format, args...)) } } @@ -221,13 +222,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) { // Entry Println family functions func (entry *Entry) Debugln(args ...interface{}) { - if entry.Logger.Level >= DebugLevel { + if entry.Logger.level() >= DebugLevel { entry.Debug(entry.sprintlnn(args...)) } } func (entry *Entry) Infoln(args ...interface{}) { - if entry.Logger.Level >= InfoLevel { + if entry.Logger.level() >= InfoLevel { entry.Info(entry.sprintlnn(args...)) } } @@ -237,7 +238,7 @@ func (entry *Entry) Println(args ...interface{}) { } func (entry *Entry) Warnln(args ...interface{}) { - if entry.Logger.Level >= WarnLevel { + if entry.Logger.level() >= WarnLevel { entry.Warn(entry.sprintlnn(args...)) } } @@ -247,20 +248,20 @@ func (entry *Entry) Warningln(args ...interface{}) { } func (entry *Entry) Errorln(args ...interface{}) { - if entry.Logger.Level >= ErrorLevel { + if entry.Logger.level() >= ErrorLevel { entry.Error(entry.sprintlnn(args...)) } } func (entry *Entry) Fatalln(args ...interface{}) { - if entry.Logger.Level >= FatalLevel { + if entry.Logger.level() >= FatalLevel { entry.Fatal(entry.sprintlnn(args...)) } Exit(1) } func (entry *Entry) Panicln(args ...interface{}) { - if entry.Logger.Level >= PanicLevel { + if entry.Logger.level() >= PanicLevel { entry.Panic(entry.sprintlnn(args...)) } } diff --git a/vendor/github.com/Sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go similarity index 99% rename from vendor/github.com/Sirupsen/logrus/exported.go rename to vendor/github.com/sirupsen/logrus/exported.go index 9a0120ac1..013183eda 100644 --- a/vendor/github.com/Sirupsen/logrus/exported.go +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -31,14 +31,14 @@ func SetFormatter(formatter Formatter) { func SetLevel(level Level) { std.mu.Lock() defer std.mu.Unlock() - std.Level = level + std.SetLevel(level) } // GetLevel returns the standard logger level. func GetLevel() Level { std.mu.Lock() defer std.mu.Unlock() - return std.Level + return std.level() } // AddHook adds a hook to the standard logger hooks. diff --git a/vendor/github.com/Sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go similarity index 96% rename from vendor/github.com/Sirupsen/logrus/formatter.go rename to vendor/github.com/sirupsen/logrus/formatter.go index b5fbe934d..b183ff5b1 100644 --- a/vendor/github.com/Sirupsen/logrus/formatter.go +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -2,7 +2,7 @@ package logrus import "time" -const DefaultTimestampFormat = time.RFC3339 +const defaultTimestampFormat = time.RFC3339 // The Formatter interface is used to implement a custom Formatter. It takes an // `Entry`. It exposes all the fields, including the default ones: diff --git a/vendor/github.com/Sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go similarity index 100% rename from vendor/github.com/Sirupsen/logrus/hooks.go rename to vendor/github.com/sirupsen/logrus/hooks.go diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go similarity index 78% rename from vendor/github.com/Sirupsen/logrus/json_formatter.go rename to vendor/github.com/sirupsen/logrus/json_formatter.go index 266554e9f..fb01c1b10 100644 --- a/vendor/github.com/Sirupsen/logrus/json_formatter.go +++ b/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -6,8 +6,11 @@ import ( ) type fieldKey string + +// FieldMap allows customization of the key names for default fields. type FieldMap map[fieldKey]string +// Default key names for the default fields const ( FieldKeyMsg = "msg" FieldKeyLevel = "level" @@ -22,6 +25,7 @@ func (f FieldMap) resolve(key fieldKey) string { return string(key) } +// JSONFormatter formats logs into parsable json type JSONFormatter struct { // TimestampFormat sets the format used for marshaling timestamps. TimestampFormat string @@ -29,25 +33,26 @@ type JSONFormatter struct { // DisableTimestamp allows disabling automatic timestamps in output DisableTimestamp bool - // FieldMap allows users to customize the names of keys for various fields. + // FieldMap allows users to customize the names of keys for default fields. // As an example: // formatter := &JSONFormatter{ // FieldMap: FieldMap{ // FieldKeyTime: "@timestamp", // FieldKeyLevel: "@level", - // FieldKeyLevel: "@message", + // FieldKeyMsg: "@message", // }, // } FieldMap FieldMap } +// Format renders a single log entry func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data := make(Fields, len(entry.Data)+3) 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 + // https://github.com/sirupsen/logrus/issues/137 data[k] = v.Error() default: data[k] = v @@ -57,7 +62,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat := f.TimestampFormat if timestampFormat == "" { - timestampFormat = DefaultTimestampFormat + timestampFormat = defaultTimestampFormat } if !f.DisableTimestamp { diff --git a/vendor/github.com/Sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go similarity index 87% rename from vendor/github.com/Sirupsen/logrus/logger.go rename to vendor/github.com/sirupsen/logrus/logger.go index b769f3d35..2acab0509 100644 --- a/vendor/github.com/Sirupsen/logrus/logger.go +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -4,6 +4,7 @@ import ( "io" "os" "sync" + "sync/atomic" ) type Logger struct { @@ -24,7 +25,7 @@ type Logger struct { Formatter Formatter // 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. `logrus.Debug` is useful in + // logged. Level Level // Used to sync writing to the log. Locking is enabled by Default mu MutexWrap @@ -112,7 +113,7 @@ func (logger *Logger) WithError(err error) *Entry { } func (logger *Logger) Debugf(format string, args ...interface{}) { - if logger.Level >= DebugLevel { + if logger.level() >= DebugLevel { entry := logger.newEntry() entry.Debugf(format, args...) logger.releaseEntry(entry) @@ -120,7 +121,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) { } func (logger *Logger) Infof(format string, args ...interface{}) { - if logger.Level >= InfoLevel { + if logger.level() >= InfoLevel { entry := logger.newEntry() entry.Infof(format, args...) logger.releaseEntry(entry) @@ -134,7 +135,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) { } func (logger *Logger) Warnf(format string, args ...interface{}) { - if logger.Level >= WarnLevel { + if logger.level() >= WarnLevel { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -142,7 +143,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) { } func (logger *Logger) Warningf(format string, args ...interface{}) { - if logger.Level >= WarnLevel { + if logger.level() >= WarnLevel { entry := logger.newEntry() entry.Warnf(format, args...) logger.releaseEntry(entry) @@ -150,7 +151,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) { } func (logger *Logger) Errorf(format string, args ...interface{}) { - if logger.Level >= ErrorLevel { + if logger.level() >= ErrorLevel { entry := logger.newEntry() entry.Errorf(format, args...) logger.releaseEntry(entry) @@ -158,7 +159,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) { } func (logger *Logger) Fatalf(format string, args ...interface{}) { - if logger.Level >= FatalLevel { + if logger.level() >= FatalLevel { entry := logger.newEntry() entry.Fatalf(format, args...) logger.releaseEntry(entry) @@ -167,7 +168,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) { } func (logger *Logger) Panicf(format string, args ...interface{}) { - if logger.Level >= PanicLevel { + if logger.level() >= PanicLevel { entry := logger.newEntry() entry.Panicf(format, args...) logger.releaseEntry(entry) @@ -175,7 +176,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) { } func (logger *Logger) Debug(args ...interface{}) { - if logger.Level >= DebugLevel { + if logger.level() >= DebugLevel { entry := logger.newEntry() entry.Debug(args...) logger.releaseEntry(entry) @@ -183,7 +184,7 @@ func (logger *Logger) Debug(args ...interface{}) { } func (logger *Logger) Info(args ...interface{}) { - if logger.Level >= InfoLevel { + if logger.level() >= InfoLevel { entry := logger.newEntry() entry.Info(args...) logger.releaseEntry(entry) @@ -197,7 +198,7 @@ func (logger *Logger) Print(args ...interface{}) { } func (logger *Logger) Warn(args ...interface{}) { - if logger.Level >= WarnLevel { + if logger.level() >= WarnLevel { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -205,7 +206,7 @@ func (logger *Logger) Warn(args ...interface{}) { } func (logger *Logger) Warning(args ...interface{}) { - if logger.Level >= WarnLevel { + if logger.level() >= WarnLevel { entry := logger.newEntry() entry.Warn(args...) logger.releaseEntry(entry) @@ -213,7 +214,7 @@ func (logger *Logger) Warning(args ...interface{}) { } func (logger *Logger) Error(args ...interface{}) { - if logger.Level >= ErrorLevel { + if logger.level() >= ErrorLevel { entry := logger.newEntry() entry.Error(args...) logger.releaseEntry(entry) @@ -221,7 +222,7 @@ func (logger *Logger) Error(args ...interface{}) { } func (logger *Logger) Fatal(args ...interface{}) { - if logger.Level >= FatalLevel { + if logger.level() >= FatalLevel { entry := logger.newEntry() entry.Fatal(args...) logger.releaseEntry(entry) @@ -230,7 +231,7 @@ func (logger *Logger) Fatal(args ...interface{}) { } func (logger *Logger) Panic(args ...interface{}) { - if logger.Level >= PanicLevel { + if logger.level() >= PanicLevel { entry := logger.newEntry() entry.Panic(args...) logger.releaseEntry(entry) @@ -238,7 +239,7 @@ func (logger *Logger) Panic(args ...interface{}) { } func (logger *Logger) Debugln(args ...interface{}) { - if logger.Level >= DebugLevel { + if logger.level() >= DebugLevel { entry := logger.newEntry() entry.Debugln(args...) logger.releaseEntry(entry) @@ -246,7 +247,7 @@ func (logger *Logger) Debugln(args ...interface{}) { } func (logger *Logger) Infoln(args ...interface{}) { - if logger.Level >= InfoLevel { + if logger.level() >= InfoLevel { entry := logger.newEntry() entry.Infoln(args...) logger.releaseEntry(entry) @@ -260,7 +261,7 @@ func (logger *Logger) Println(args ...interface{}) { } func (logger *Logger) Warnln(args ...interface{}) { - if logger.Level >= WarnLevel { + if logger.level() >= WarnLevel { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -268,7 +269,7 @@ func (logger *Logger) Warnln(args ...interface{}) { } func (logger *Logger) Warningln(args ...interface{}) { - if logger.Level >= WarnLevel { + if logger.level() >= WarnLevel { entry := logger.newEntry() entry.Warnln(args...) logger.releaseEntry(entry) @@ -276,7 +277,7 @@ func (logger *Logger) Warningln(args ...interface{}) { } func (logger *Logger) Errorln(args ...interface{}) { - if logger.Level >= ErrorLevel { + if logger.level() >= ErrorLevel { entry := logger.newEntry() entry.Errorln(args...) logger.releaseEntry(entry) @@ -284,7 +285,7 @@ func (logger *Logger) Errorln(args ...interface{}) { } func (logger *Logger) Fatalln(args ...interface{}) { - if logger.Level >= FatalLevel { + if logger.level() >= FatalLevel { entry := logger.newEntry() entry.Fatalln(args...) logger.releaseEntry(entry) @@ -293,7 +294,7 @@ func (logger *Logger) Fatalln(args ...interface{}) { } func (logger *Logger) Panicln(args ...interface{}) { - if logger.Level >= PanicLevel { + if logger.level() >= PanicLevel { entry := logger.newEntry() entry.Panicln(args...) logger.releaseEntry(entry) @@ -306,3 +307,11 @@ func (logger *Logger) Panicln(args ...interface{}) { func (logger *Logger) SetNoLock() { logger.mu.Disable() } + +func (logger *Logger) level() Level { + return Level(atomic.LoadUint32((*uint32)(&logger.Level))) +} + +func (logger *Logger) SetLevel(level Level) { + atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) +} diff --git a/vendor/github.com/Sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go similarity index 99% rename from vendor/github.com/Sirupsen/logrus/logrus.go rename to vendor/github.com/sirupsen/logrus/logrus.go index e59669111..dd3899974 100644 --- a/vendor/github.com/Sirupsen/logrus/logrus.go +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -10,7 +10,7 @@ import ( type Fields map[string]interface{} // Level type -type Level uint8 +type Level uint32 // Convert the Level to a string. E.g. PanicLevel becomes "panic". func (level Level) String() string { diff --git a/vendor/github.com/sirupsen/logrus/terminal_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_bsd.go new file mode 100644 index 000000000..d7b3893f3 --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_bsd.go @@ -0,0 +1,10 @@ +// +build darwin freebsd openbsd netbsd dragonfly +// +build !appengine + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TIOCGETA + +type Termios unix.Termios diff --git a/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/github.com/sirupsen/logrus/terminal_linux.go similarity index 70% rename from vendor/github.com/Sirupsen/logrus/terminal_linux.go rename to vendor/github.com/sirupsen/logrus/terminal_linux.go index 308160ca8..88d7298e2 100644 --- a/vendor/github.com/Sirupsen/logrus/terminal_linux.go +++ b/vendor/github.com/sirupsen/logrus/terminal_linux.go @@ -7,8 +7,8 @@ package logrus -import "syscall" +import "golang.org/x/sys/unix" -const ioctlReadTermios = syscall.TCGETS +const ioctlReadTermios = unix.TCGETS -type Termios syscall.Termios +type Termios unix.Termios diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go similarity index 82% rename from vendor/github.com/Sirupsen/logrus/text_formatter.go rename to vendor/github.com/sirupsen/logrus/text_formatter.go index ba8885406..be412aa94 100644 --- a/vendor/github.com/Sirupsen/logrus/text_formatter.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -3,10 +3,14 @@ package logrus import ( "bytes" "fmt" + "io" + "os" "sort" "strings" "sync" "time" + + "golang.org/x/crypto/ssh/terminal" ) const ( @@ -14,7 +18,7 @@ const ( red = 31 green = 32 yellow = 33 - blue = 34 + blue = 36 gray = 37 ) @@ -26,6 +30,7 @@ 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 @@ -52,10 +57,6 @@ type TextFormatter struct { // QuoteEmptyFields will wrap empty fields in quotes if true QuoteEmptyFields bool - // QuoteCharacter can be set to the override the default quoting character " - // with something else. For example: ', or `. - QuoteCharacter string - // Whether the logger's out is to a terminal isTerminal bool @@ -63,14 +64,21 @@ type TextFormatter struct { } func (f *TextFormatter) init(entry *Entry) { - if len(f.QuoteCharacter) == 0 { - f.QuoteCharacter = "\"" - } if entry.Logger != nil { - f.isTerminal = IsTerminal(entry.Logger.Out) + f.isTerminal = f.checkIfTerminal(entry.Logger.Out) } } +func (f *TextFormatter) checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return terminal.IsTerminal(int(v.Fd())) + default: + return false + } +} + +// Format renders a single log entry func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { var b *bytes.Buffer keys := make([]string, 0, len(entry.Data)) @@ -95,7 +103,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat := f.TimestampFormat if timestampFormat == "" { - timestampFormat = DefaultTimestampFormat + timestampFormat = defaultTimestampFormat } if isColored { f.printColored(b, entry, keys, timestampFormat) @@ -153,7 +161,7 @@ func (f *TextFormatter) needsQuoting(text string) bool { if !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || - ch == '-' || ch == '.') { + ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { return true } } @@ -161,29 +169,23 @@ func (f *TextFormatter) needsQuoting(text string) bool { } 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) - b.WriteByte(' ') } func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { - switch value := value.(type) { - case string: - if !f.needsQuoting(value) { - b.WriteString(value) - } else { - fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter) - } - case error: - errmsg := value.Error() - if !f.needsQuoting(errmsg) { - b.WriteString(errmsg) - } else { - fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter) - } - default: - fmt.Fprint(b, value) + 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 similarity index 100% rename from vendor/github.com/Sirupsen/logrus/writer.go rename to vendor/github.com/sirupsen/logrus/writer.go diff --git a/vendor/github.com/docker/notary/LICENSE b/vendor/github.com/theupdateframework/notary/LICENSE similarity index 99% rename from vendor/github.com/docker/notary/LICENSE rename to vendor/github.com/theupdateframework/notary/LICENSE index 6daf85e9d..ad9500955 100644 --- a/vendor/github.com/docker/notary/LICENSE +++ b/vendor/github.com/theupdateframework/notary/LICENSE @@ -1,4 +1,4 @@ -Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/vendor/github.com/docker/notary/README.md b/vendor/github.com/theupdateframework/notary/README.md similarity index 73% rename from vendor/github.com/docker/notary/README.md rename to vendor/github.com/theupdateframework/notary/README.md index e81a91c10..652305086 100644 --- a/vendor/github.com/docker/notary/README.md +++ b/vendor/github.com/theupdateframework/notary/README.md @@ -1,11 +1,23 @@ -# Notary -[![Circle CI](https://circleci.com/gh/docker/notary/tree/master.svg?style=shield)](https://circleci.com/gh/docker/notary/tree/master) [![CodeCov](https://codecov.io/github/docker/notary/coverage.svg?branch=master)](https://codecov.io/github/docker/notary) [![GoReportCard](https://goreportcard.com/badge/docker/notary)](https://goreportcard.com/report/github.com/docker/notary) +Notary + +[![Circle CI](https://circleci.com/gh/theupdateframework/notary/tree/master.svg?style=shield)](https://circleci.com/gh/theupdateframework/notary/tree/master) [![CodeCov](https://codecov.io/github/theupdateframework/notary/coverage.svg?branch=master)](https://codecov.io/github/theupdateframework/notary) [![GoReportCard](https://goreportcard.com/badge/theupdateframework/notary)](https://goreportcard.com/report/github.com/theupdateframework/notary) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Ftheupdateframework%2Fnotary.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Ftheupdateframework%2Fnotary?ref=badge_shield) + +# Notice + +The Notary project has officially been accepted in to the Cloud Native Computing Foundation (CNCF). +It has moved to https://github.com/theupdateframework/notary. Any downstream consumers should update +their Go imports to use this new location, which will be the canonical location going forward. + +We have moved the repo in GitHub, which will allow existing importers to continue using the old +location via GitHub's redirect. + +# Overview The Notary project comprises a [server](cmd/notary-server) and a [client](cmd/notary) for running and interacting with trusted collections. Please see the [service architecture](docs/service_architecture.md) documentation for more information. - Notary aims to make the internet more secure by making it easy for people to publish and verify content. We often rely on TLS to secure our communications with a web server which is inherently flawed, as any compromise of the server @@ -41,7 +53,7 @@ Any security vulnerabilities can be reported to security@docker.com. # Getting started with the Notary CLI -Please get the Notary Client CLI binary from [the official releases page](https://github.com/docker/notary/releases) or you can [build one yourself](#building-notary). +Please get the Notary Client CLI binary from [the official releases page](https://github.com/theupdateframework/notary/releases) or you can [build one yourself](#building-notary). The version of Notary server and signer should be greater than or equal to Notary CLI's version to ensure feature compatibility (ex: CLI version 0.2, server/signer version >= 0.2), and all official releases are associated with GitHub tags. To use the Notary CLI with Docker hub images, please have a look at our @@ -53,7 +65,7 @@ For more advanced usage, please see the To use the CLI against a local Notary server rather than against Docker Hub: 1. Please ensure that you have [docker and docker-compose](http://docs.docker.com/compose/install/) installed. -1. `git clone https://github.com/docker/notary.git` and from the cloned repository path, +1. `git clone https://github.com/theupdateframework/notary.git` and from the cloned repository path, start up a local Notary server and signer and copy the config file and testing certs to your local notary config directory: @@ -78,18 +90,21 @@ to use `notary` with Docker images. ## Building Notary +Note that our [latest stable release](https://github.com/theupdateframework/notary/releases) is at the head of the +[releases branch](https://github.com/theupdateframework/notary/tree/releases). The master branch is the development +branch and contains features for the next release. + Prerequisites: -- Go >= 1.7 - +- Go >= 1.7.1 - [godep](https://github.com/tools/godep) installed - libtool development headers installed - Ubuntu: `apt-get install libltdl-dev` - CentOS/RedHat: `yum install libtool-ltdl-devel` - Mac OS ([Homebrew](http://brew.sh/)): `brew install libtool` -Run `make binaries`, which creates the Notary Client CLI binary at `bin/notary`. -Note that `make binaries` assumes a standard Go directory structure, in which +Run `make client`, which creates the Notary Client CLI binary at `bin/notary`. +Note that `make client` assumes a standard Go directory structure, in which Notary is checked out to the `src` directory in your `GOPATH`. For example: ``` $GOPATH/ @@ -98,3 +113,9 @@ $GOPATH/ docker/ notary/ ``` + +To build the server and signer, please run `docker-compose build`. + + +## License +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Ftheupdateframework%2Fnotary.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Ftheupdateframework%2Fnotary?ref=badge_large) \ No newline at end of file diff --git a/vendor/github.com/docker/notary/client/changelist/change.go b/vendor/github.com/theupdateframework/notary/client/changelist/change.go similarity index 64% rename from vendor/github.com/docker/notary/client/changelist/change.go rename to vendor/github.com/theupdateframework/notary/client/changelist/change.go index 3e872e681..d445767a7 100644 --- a/vendor/github.com/docker/notary/client/changelist/change.go +++ b/vendor/github.com/theupdateframework/notary/client/changelist/change.go @@ -1,17 +1,15 @@ package changelist import ( - "github.com/docker/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/data" ) // Scopes for TUFChanges are simply the TUF roles. // Unfortunately because of targets delegations, we can only // cover the base roles. const ( - ScopeRoot = "root" - ScopeTargets = "targets" - ScopeSnapshot = "snapshot" - ScopeTimestamp = "timestamp" + ScopeRoot = "root" + ScopeTargets = "targets" ) // Types for TUFChanges are namespaced by the Role they @@ -20,7 +18,7 @@ const ( // all changes in Snapshot and Timestamp are programmatically // generated base on Root and Targets changes. const ( - TypeRootRole = "role" + TypeBaseRole = "role" TypeTargetsTarget = "target" TypeTargetsDelegation = "delegation" TypeWitness = "witness" @@ -29,22 +27,22 @@ const ( // TUFChange represents a change to a TUF repo type TUFChange struct { // Abbreviated because Go doesn't permit a field and method of the same name - Actn string `json:"action"` - Role string `json:"role"` - ChangeType string `json:"type"` - ChangePath string `json:"path"` - Data []byte `json:"data"` + Actn string `json:"action"` + Role data.RoleName `json:"role"` + ChangeType string `json:"type"` + ChangePath string `json:"path"` + Data []byte `json:"data"` } // TUFRootData represents a modification of the keys associated // with a role that appears in the root.json type TUFRootData struct { - Keys data.KeyList `json:"keys"` - RoleName string `json:"role"` + Keys data.KeyList `json:"keys"` + RoleName data.RoleName `json:"role"` } // NewTUFChange initializes a TUFChange object -func NewTUFChange(action string, role, changeType, changePath string, content []byte) *TUFChange { +func NewTUFChange(action string, role data.RoleName, changeType, changePath string, content []byte) *TUFChange { return &TUFChange{ Actn: action, Role: role, @@ -60,7 +58,7 @@ func (c TUFChange) Action() string { } // Scope returns c.Role -func (c TUFChange) Scope() string { +func (c TUFChange) Scope() data.RoleName { return c.Role } @@ -83,17 +81,17 @@ func (c TUFChange) Content() []byte { // this includes creating a delegations. This format is used to avoid // unexpected race conditions between humans modifying the same delegation type TUFDelegation struct { - NewName string `json:"new_name,omitempty"` - NewThreshold int `json:"threshold, omitempty"` - AddKeys data.KeyList `json:"add_keys, omitempty"` - RemoveKeys []string `json:"remove_keys,omitempty"` - AddPaths []string `json:"add_paths,omitempty"` - RemovePaths []string `json:"remove_paths,omitempty"` - ClearAllPaths bool `json:"clear_paths,omitempty"` + NewName data.RoleName `json:"new_name,omitempty"` + NewThreshold int `json:"threshold, omitempty"` + AddKeys data.KeyList `json:"add_keys, omitempty"` + RemoveKeys []string `json:"remove_keys,omitempty"` + AddPaths []string `json:"add_paths,omitempty"` + RemovePaths []string `json:"remove_paths,omitempty"` + ClearAllPaths bool `json:"clear_paths,omitempty"` } // ToNewRole creates a fresh role object from the TUFDelegation data -func (td TUFDelegation) ToNewRole(scope string) (*data.Role, error) { +func (td TUFDelegation) ToNewRole(scope data.RoleName) (*data.Role, error) { name := scope if td.NewName != "" { name = td.NewName diff --git a/vendor/github.com/docker/notary/client/changelist/changelist.go b/vendor/github.com/theupdateframework/notary/client/changelist/changelist.go similarity index 94% rename from vendor/github.com/docker/notary/client/changelist/changelist.go rename to vendor/github.com/theupdateframework/notary/client/changelist/changelist.go index 9b52981ad..30cf69459 100644 --- a/vendor/github.com/docker/notary/client/changelist/changelist.go +++ b/vendor/github.com/theupdateframework/notary/client/changelist/changelist.go @@ -21,6 +21,11 @@ func (cl *memChangelist) Add(c Change) error { return nil } +// Location returns the string "memory" +func (cl memChangelist) Location() string { + return "memory" +} + // Remove deletes the changes found at the given indices func (cl *memChangelist) Remove(idxs []int) error { remove := make(map[int]struct{}) diff --git a/vendor/github.com/docker/notary/client/changelist/file_changelist.go b/vendor/github.com/theupdateframework/notary/client/changelist/file_changelist.go similarity index 96% rename from vendor/github.com/docker/notary/client/changelist/file_changelist.go rename to vendor/github.com/theupdateframework/notary/client/changelist/file_changelist.go index a25215482..ab1b200e2 100644 --- a/vendor/github.com/docker/notary/client/changelist/file_changelist.go +++ b/vendor/github.com/theupdateframework/notary/client/changelist/file_changelist.go @@ -5,12 +5,12 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "sort" "time" - "github.com/Sirupsen/logrus" "github.com/docker/distribution/uuid" - "path/filepath" + "github.com/sirupsen/logrus" ) // FileChangelist stores all the changes as files @@ -137,6 +137,11 @@ func (cl FileChangelist) Close() error { return nil } +// Location returns the file path to the changelist +func (cl FileChangelist) Location() string { + return cl.dir +} + // NewIterator creates an iterator from FileChangelist func (cl FileChangelist) NewIterator() (ChangeIterator, error) { fileInfos, err := getFileNames(cl.dir) diff --git a/vendor/github.com/docker/notary/client/changelist/interface.go b/vendor/github.com/theupdateframework/notary/client/changelist/interface.go similarity index 93% rename from vendor/github.com/docker/notary/client/changelist/interface.go rename to vendor/github.com/theupdateframework/notary/client/changelist/interface.go index a319b7b89..e8fb82477 100644 --- a/vendor/github.com/docker/notary/client/changelist/interface.go +++ b/vendor/github.com/theupdateframework/notary/client/changelist/interface.go @@ -1,5 +1,7 @@ package changelist +import "github.com/theupdateframework/notary/tuf/data" + // Changelist is the interface for all TUF change lists type Changelist interface { // List returns the ordered list of changes @@ -25,6 +27,9 @@ type Changelist interface { // NewIterator returns an iterator for walking through the list // of changes currently stored NewIterator() (ChangeIterator, error) + + // Location returns the place the changelist is stores + Location() string } const ( @@ -43,7 +48,7 @@ type Change interface { // Where the change should be made. // For TUF this will be the role - Scope() string + Scope() data.RoleName // The content type being affected. // For TUF this will be "target", or "delegation". diff --git a/vendor/github.com/theupdateframework/notary/client/client.go b/vendor/github.com/theupdateframework/notary/client/client.go new file mode 100644 index 000000000..217e96235 --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/client/client.go @@ -0,0 +1,1374 @@ +/* +Package client implements everything required for interacting with a Notary repository. + +Usage + +Use this package by creating a new repository object and calling methods on it. + + package main + + import ( + "encoding/hex" + "fmt" + "net/http" + "os" + "time" + + "github.com/docker/distribution/registry/client/auth" + "github.com/docker/distribution/registry/client/auth/challenge" + "github.com/docker/distribution/registry/client/transport" + notary "github.com/theupdateframework/notary/client" + "github.com/theupdateframework/notary/trustpinning" + "github.com/theupdateframework/notary/tuf/data" + ) + + func main() { + rootDir := ".trust" + if err := os.MkdirAll(rootDir, 0700); err != nil { + panic(err) + } + + server := "https://notary.docker.io" + image := "docker.io/library/alpine" + repo, err := notary.NewFileCachedNotaryRepository( + rootDir, + data.GUN(image), + server, + makeHubTransport(server, image), + nil, + trustpinning.TrustPinConfig{}, + ) + + targets, err := repo.ListTargets() + if err != nil { + panic(err) + } + + for _, tgt := range targets { + fmt.Printf("%s\t%s\n", tgt.Name, hex.EncodeToString(tgt.Hashes["sha256"])) + } + } + + func makeHubTransport(server, image string) http.RoundTripper { + base := http.DefaultTransport + modifiers := []transport.RequestModifier{ + transport.NewHeaderRequestModifier(http.Header{ + "User-Agent": []string{"my-client"}, + }), + } + + authTransport := transport.NewTransport(base, modifiers...) + pingClient := &http.Client{ + Transport: authTransport, + Timeout: 5 * time.Second, + } + req, err := http.NewRequest("GET", server+"/v2/", nil) + if err != nil { + panic(err) + } + + challengeManager := challenge.NewSimpleManager() + resp, err := pingClient.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + if err := challengeManager.AddResponse(resp); err != nil { + panic(err) + } + tokenHandler := auth.NewTokenHandler(base, nil, image, "pull") + modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, auth.NewBasicHandler(nil))) + + return transport.NewTransport(base, modifiers...) + } + +*/ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "path/filepath" + "regexp" + "time" + + canonicaljson "github.com/docker/go/canonical/json" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/client/changelist" + "github.com/theupdateframework/notary/cryptoservice" + store "github.com/theupdateframework/notary/storage" + "github.com/theupdateframework/notary/trustpinning" + "github.com/theupdateframework/notary/tuf" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" + "github.com/theupdateframework/notary/tuf/utils" +) + +const ( + tufDir = "tuf" + + // SignWithAllOldVersions is a sentinel constant for LegacyVersions flag + SignWithAllOldVersions = -1 +) + +func init() { + data.SetDefaultExpiryTimes(data.NotaryDefaultExpiries) +} + +// repository stores all the information needed to operate on a notary repository. +type repository struct { + baseDir string + gun data.GUN + baseURL string + changelist changelist.Changelist + cache store.MetadataStore + remoteStore store.RemoteStore + cryptoService signed.CryptoService + tufRepo *tuf.Repo + invalid *tuf.Repo // known data that was parsable but deemed invalid + roundTrip http.RoundTripper + trustPinning trustpinning.TrustPinConfig + LegacyVersions int // number of versions back to fetch roots to sign with +} + +// NewFileCachedRepository is a wrapper for NewRepository that initializes +// a file cache from the provided repository, local config information and a crypto service. +// It also retrieves the remote store associated to the base directory under where all the +// trust files will be stored and the specified GUN. +// +// In case of a nil RoundTripper, a default offline store is used instead. +func NewFileCachedRepository(baseDir string, gun data.GUN, baseURL string, rt http.RoundTripper, + retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) (Repository, error) { + + cache, err := store.NewFileStore( + filepath.Join(baseDir, tufDir, filepath.FromSlash(gun.String()), "metadata"), + "json", + ) + if err != nil { + return nil, err + } + + keyStores, err := getKeyStores(baseDir, retriever) + if err != nil { + return nil, err + } + + cryptoService := cryptoservice.NewCryptoService(keyStores...) + + remoteStore, err := getRemoteStore(baseURL, gun, rt) + if err != nil { + // baseURL is syntactically invalid + return nil, err + } + + cl, err := changelist.NewFileChangelist(filepath.Join( + filepath.Join(baseDir, tufDir, filepath.FromSlash(gun.String()), "changelist"), + )) + if err != nil { + return nil, err + } + + return NewRepository(baseDir, gun, baseURL, remoteStore, cache, trustPinning, cryptoService, cl) +} + +// NewRepository is the base method that returns a new notary repository. +// It takes the base directory under where all the trust files will be stored +// (This is normally defaults to "~/.notary" or "~/.docker/trust" when enabling +// docker content trust). +// It expects an initialized cache. In case of a nil remote store, a default +// offline store is used. +func NewRepository(baseDir string, gun data.GUN, baseURL string, remoteStore store.RemoteStore, cache store.MetadataStore, + trustPinning trustpinning.TrustPinConfig, cryptoService signed.CryptoService, cl changelist.Changelist) (Repository, error) { + + // Repo's remote store is either a valid remote store or an OfflineStore + if remoteStore == nil { + remoteStore = store.OfflineStore{} + } + + if cache == nil { + return nil, fmt.Errorf("got an invalid cache (nil metadata store)") + } + + nRepo := &repository{ + gun: gun, + baseURL: baseURL, + baseDir: baseDir, + changelist: cl, + cache: cache, + remoteStore: remoteStore, + cryptoService: cryptoService, + trustPinning: trustPinning, + LegacyVersions: 0, // By default, don't sign with legacy roles + } + + return nRepo, nil +} + +// GetGUN is a getter for the GUN object from a Repository +func (r *repository) GetGUN() data.GUN { + return r.gun +} + +// Target represents a simplified version of the data TUF operates on, so external +// applications don't have to depend on TUF data types. +type Target struct { + Name string // the name of the target + Hashes data.Hashes // the hash of the target + Length int64 // the size in bytes of the target + Custom *canonicaljson.RawMessage // the custom data provided to describe the file at TARGETPATH +} + +// TargetWithRole represents a Target that exists in a particular role - this is +// produced by ListTargets and GetTargetByName +type TargetWithRole struct { + Target + Role data.RoleName +} + +// NewTarget is a helper method that returns a Target +func NewTarget(targetName, targetPath string, targetCustom *canonicaljson.RawMessage) (*Target, error) { + b, err := ioutil.ReadFile(targetPath) + if err != nil { + return nil, err + } + + meta, err := data.NewFileMeta(bytes.NewBuffer(b), data.NotaryDefaultHashes...) + if err != nil { + return nil, err + } + + return &Target{Name: targetName, Hashes: meta.Hashes, Length: meta.Length, Custom: targetCustom}, nil +} + +// rootCertKey generates the corresponding certificate for the private key given the privKey and repo's GUN +func rootCertKey(gun data.GUN, privKey data.PrivateKey) (data.PublicKey, error) { + // Hard-coded policy: the generated certificate expires in 10 years. + startTime := time.Now() + cert, err := cryptoservice.GenerateCertificate( + privKey, gun, startTime, startTime.Add(notary.Year*10)) + if err != nil { + return nil, err + } + + x509PublicKey := utils.CertToKey(cert) + if x509PublicKey == nil { + return nil, fmt.Errorf("cannot generate public key from private key with id: %v and algorithm: %v", privKey.ID(), privKey.Algorithm()) + } + + return x509PublicKey, nil +} + +// GetCryptoService is the getter for the repository's CryptoService +func (r *repository) GetCryptoService() signed.CryptoService { + return r.cryptoService +} + +// initialize initializes the notary repository with a set of rootkeys, root certificates and roles. +func (r *repository) initialize(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error { + + // currently we only support server managing timestamps and snapshots, and + // nothing else - timestamps are always managed by the server, and implicit + // (do not have to be passed in as part of `serverManagedRoles`, so that + // the API of Initialize doesn't change). + var serverManagesSnapshot bool + locallyManagedKeys := []data.RoleName{ + data.CanonicalTargetsRole, + data.CanonicalSnapshotRole, + // root is also locally managed, but that should have been created + // already + } + remotelyManagedKeys := []data.RoleName{data.CanonicalTimestampRole} + for _, role := range serverManagedRoles { + switch role { + case data.CanonicalTimestampRole: + continue // timestamp is already in the right place + case data.CanonicalSnapshotRole: + // because we put Snapshot last + locallyManagedKeys = []data.RoleName{data.CanonicalTargetsRole} + remotelyManagedKeys = append( + remotelyManagedKeys, data.CanonicalSnapshotRole) + serverManagesSnapshot = true + default: + return ErrInvalidRemoteRole{Role: role} + } + } + + // gets valid public keys corresponding to the rootKeyIDs or generate if necessary + var publicKeys []data.PublicKey + var err error + if len(rootCerts) == 0 { + publicKeys, err = r.createNewPublicKeyFromKeyIDs(rootKeyIDs) + } else { + publicKeys, err = r.publicKeysOfKeyIDs(rootKeyIDs, rootCerts) + } + if err != nil { + return err + } + + //initialize repo with public keys + rootRole, targetsRole, snapshotRole, timestampRole, err := r.initializeRoles( + publicKeys, + locallyManagedKeys, + remotelyManagedKeys, + ) + if err != nil { + return err + } + + r.tufRepo = tuf.NewRepo(r.GetCryptoService()) + + if err := r.tufRepo.InitRoot( + rootRole, + timestampRole, + snapshotRole, + targetsRole, + false, + ); err != nil { + logrus.Debug("Error on InitRoot: ", err.Error()) + return err + } + if _, err := r.tufRepo.InitTargets(data.CanonicalTargetsRole); err != nil { + logrus.Debug("Error on InitTargets: ", err.Error()) + return err + } + if err := r.tufRepo.InitSnapshot(); err != nil { + logrus.Debug("Error on InitSnapshot: ", err.Error()) + return err + } + + return r.saveMetadata(serverManagesSnapshot) +} + +// createNewPublicKeyFromKeyIDs generates a set of public keys corresponding to the given list of +// key IDs existing in the repository's CryptoService. +// the public keys returned are ordered to correspond to the keyIDs +func (r *repository) createNewPublicKeyFromKeyIDs(keyIDs []string) ([]data.PublicKey, error) { + publicKeys := []data.PublicKey{} + + privKeys, err := getAllPrivKeys(keyIDs, r.GetCryptoService()) + if err != nil { + return nil, err + } + + for _, privKey := range privKeys { + rootKey, err := rootCertKey(r.gun, privKey) + if err != nil { + return nil, err + } + publicKeys = append(publicKeys, rootKey) + } + return publicKeys, nil +} + +// publicKeysOfKeyIDs confirms that the public key and private keys (by Key IDs) forms valid, strictly ordered key pairs +// (eg. keyIDs[0] must match pubKeys[0] and keyIDs[1] must match certs[1] and so on). +// Or throw error when they mismatch. +func (r *repository) publicKeysOfKeyIDs(keyIDs []string, pubKeys []data.PublicKey) ([]data.PublicKey, error) { + if len(keyIDs) != len(pubKeys) { + err := fmt.Errorf("require matching number of keyIDs and public keys but got %d IDs and %d public keys", len(keyIDs), len(pubKeys)) + return nil, err + } + + if err := matchKeyIdsWithPubKeys(r, keyIDs, pubKeys); err != nil { + return nil, fmt.Errorf("could not obtain public key from IDs: %v", err) + } + return pubKeys, nil +} + +// matchKeyIdsWithPubKeys validates that the private keys (represented by their IDs) and the public keys +// forms matching key pairs +func matchKeyIdsWithPubKeys(r *repository, ids []string, pubKeys []data.PublicKey) error { + for i := 0; i < len(ids); i++ { + privKey, _, err := r.GetCryptoService().GetPrivateKey(ids[i]) + if err != nil { + return fmt.Errorf("could not get the private key matching id %v: %v", ids[i], err) + } + + pubKey := pubKeys[i] + err = signed.VerifyPublicKeyMatchesPrivateKey(privKey, pubKey) + if err != nil { + return err + } + } + return nil +} + +// Initialize creates a new repository by using rootKey as the root Key for the +// TUF repository. The server must be reachable (and is asked to generate a +// timestamp key and possibly other serverManagedRoles), but the created repository +// result is only stored on local disk, not published to the server. To do that, +// use r.Publish() eventually. +func (r *repository) Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error { + return r.initialize(rootKeyIDs, nil, serverManagedRoles...) +} + +type errKeyNotFound struct{} + +func (errKeyNotFound) Error() string { + return fmt.Sprintf("cannot find matching private key id") +} + +// keyExistsInList returns the id of the private key in ids that matches the public key +// otherwise return empty string +func keyExistsInList(cert data.PublicKey, ids map[string]bool) error { + pubKeyID, err := utils.CanonicalKeyID(cert) + if err != nil { + return fmt.Errorf("failed to obtain the public key id from the given certificate: %v", err) + } + if _, ok := ids[pubKeyID]; ok { + return nil + } + return errKeyNotFound{} +} + +// InitializeWithCertificate initializes the repository with root keys and their corresponding certificates +func (r *repository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, + serverManagedRoles ...data.RoleName) error { + + // If we explicitly pass in certificate(s) but not key, then look keys up using certificate + if len(rootKeyIDs) == 0 && len(rootCerts) != 0 { + rootKeyIDs = []string{} + availableRootKeyIDs := make(map[string]bool) + for _, k := range r.GetCryptoService().ListKeys(data.CanonicalRootRole) { + availableRootKeyIDs[k] = true + } + + for _, cert := range rootCerts { + if err := keyExistsInList(cert, availableRootKeyIDs); err != nil { + return fmt.Errorf("error initializing repository with certificate: %v", err) + } + keyID, _ := utils.CanonicalKeyID(cert) + rootKeyIDs = append(rootKeyIDs, keyID) + } + } + return r.initialize(rootKeyIDs, rootCerts, serverManagedRoles...) +} + +func (r *repository) initializeRoles(rootKeys []data.PublicKey, localRoles, remoteRoles []data.RoleName) ( + root, targets, snapshot, timestamp data.BaseRole, err error) { + root = data.NewBaseRole( + data.CanonicalRootRole, + notary.MinThreshold, + rootKeys..., + ) + + // we want to create all the local keys first so we don't have to + // make unnecessary network calls + for _, role := range localRoles { + // This is currently hardcoding the keys to ECDSA. + var key data.PublicKey + key, err = r.GetCryptoService().Create(role, r.gun, data.ECDSAKey) + if err != nil { + return + } + switch role { + case data.CanonicalSnapshotRole: + snapshot = data.NewBaseRole( + role, + notary.MinThreshold, + key, + ) + case data.CanonicalTargetsRole: + targets = data.NewBaseRole( + role, + notary.MinThreshold, + key, + ) + } + } + + remote := r.getRemoteStore() + + for _, role := range remoteRoles { + // This key is generated by the remote server. + var key data.PublicKey + key, err = getRemoteKey(role, remote) + if err != nil { + return + } + logrus.Debugf("got remote %s %s key with keyID: %s", + role, key.Algorithm(), key.ID()) + switch role { + case data.CanonicalSnapshotRole: + snapshot = data.NewBaseRole( + role, + notary.MinThreshold, + key, + ) + case data.CanonicalTimestampRole: + timestamp = data.NewBaseRole( + role, + notary.MinThreshold, + key, + ) + } + } + return root, targets, snapshot, timestamp, nil +} + +// adds a TUF Change template to the given roles +func addChange(cl changelist.Changelist, c changelist.Change, roles ...data.RoleName) error { + if len(roles) == 0 { + roles = []data.RoleName{data.CanonicalTargetsRole} + } + + var changes []changelist.Change + for _, role := range roles { + // Ensure we can only add targets to the CanonicalTargetsRole, + // or a Delegation role (which is /something else) + if role != data.CanonicalTargetsRole && !data.IsDelegation(role) && !data.IsWildDelegation(role) { + return data.ErrInvalidRole{ + Role: role, + Reason: "cannot add targets to this role", + } + } + + changes = append(changes, changelist.NewTUFChange( + c.Action(), + role, + c.Type(), + c.Path(), + c.Content(), + )) + } + + for _, c := range changes { + if err := cl.Add(c); err != nil { + return err + } + } + return nil +} + +// AddTarget creates new changelist entries to add a target to the given roles +// in the repository when the changelist gets applied at publish time. +// If roles are unspecified, the default role is "targets" +func (r *repository) AddTarget(target *Target, roles ...data.RoleName) error { + if len(target.Hashes) == 0 { + return fmt.Errorf("no hashes specified for target \"%s\"", target.Name) + } + logrus.Debugf("Adding target \"%s\" with sha256 \"%x\" and size %d bytes.\n", target.Name, target.Hashes["sha256"], target.Length) + + meta := data.FileMeta{Length: target.Length, Hashes: target.Hashes, Custom: target.Custom} + metaJSON, err := json.Marshal(meta) + if err != nil { + return err + } + + template := changelist.NewTUFChange( + changelist.ActionCreate, "", changelist.TypeTargetsTarget, + target.Name, metaJSON) + return addChange(r.changelist, template, roles...) +} + +// RemoveTarget creates new changelist entries to remove a target from the given +// roles in the repository when the changelist gets applied at publish time. +// If roles are unspecified, the default role is "target". +func (r *repository) RemoveTarget(targetName string, roles ...data.RoleName) error { + logrus.Debugf("Removing target \"%s\"", targetName) + template := changelist.NewTUFChange(changelist.ActionDelete, "", + changelist.TypeTargetsTarget, targetName, nil) + return addChange(r.changelist, template, roles...) +} + +// ListTargets lists all targets for the current repository. The list of +// roles should be passed in order from highest to lowest priority. +// +// IMPORTANT: if you pass a set of roles such as [ "targets/a", "targets/x" +// "targets/a/b" ], even though "targets/a/b" is part of the "targets/a" subtree +// its entries will be strictly shadowed by those in other parts of the "targets/a" +// subtree and also the "targets/x" subtree, as we will defer parsing it until +// we explicitly reach it in our iteration of the provided list of roles. +func (r *repository) ListTargets(roles ...data.RoleName) ([]*TargetWithRole, error) { + if err := r.Update(false); err != nil { + return nil, err + } + + if len(roles) == 0 { + roles = []data.RoleName{data.CanonicalTargetsRole} + } + targets := make(map[string]*TargetWithRole) + for _, role := range roles { + // Define an array of roles to skip for this walk (see IMPORTANT comment above) + skipRoles := utils.RoleNameSliceRemove(roles, role) + + // Define a visitor function to populate the targets map in priority order + listVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { + // We found targets so we should try to add them to our targets map + for targetName, targetMeta := range tgt.Signed.Targets { + // Follow the priority by not overriding previously set targets + // and check that this path is valid with this role + if _, ok := targets[targetName]; ok || !validRole.CheckPaths(targetName) { + continue + } + targets[targetName] = &TargetWithRole{ + Target: Target{ + Name: targetName, + Hashes: targetMeta.Hashes, + Length: targetMeta.Length, + Custom: targetMeta.Custom, + }, + Role: validRole.Name, + } + } + return nil + } + + r.tufRepo.WalkTargets("", role, listVisitorFunc, skipRoles...) + } + + var targetList []*TargetWithRole + for _, v := range targets { + targetList = append(targetList, v) + } + + return targetList, nil +} + +// GetTargetByName returns a target by the given name. If no roles are passed +// it uses the targets role and does a search of the entire delegation +// graph, finding the first entry in a breadth first search of the delegations. +// If roles are passed, they should be passed in descending priority and +// the target entry found in the subtree of the highest priority role +// will be returned. +// See the IMPORTANT section on ListTargets above. Those roles also apply here. +func (r *repository) GetTargetByName(name string, roles ...data.RoleName) (*TargetWithRole, error) { + if err := r.Update(false); err != nil { + return nil, err + } + + if len(roles) == 0 { + roles = append(roles, data.CanonicalTargetsRole) + } + var resultMeta data.FileMeta + var resultRoleName data.RoleName + var foundTarget bool + for _, role := range roles { + // Define an array of roles to skip for this walk (see IMPORTANT comment above) + skipRoles := utils.RoleNameSliceRemove(roles, role) + + // Define a visitor function to find the specified target + getTargetVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { + if tgt == nil { + return nil + } + // We found the target and validated path compatibility in our walk, + // so we should stop our walk and set the resultMeta and resultRoleName variables + if resultMeta, foundTarget = tgt.Signed.Targets[name]; foundTarget { + resultRoleName = validRole.Name + return tuf.StopWalk{} + } + return nil + } + // Check that we didn't error, and that we assigned to our target + if err := r.tufRepo.WalkTargets(name, role, getTargetVisitorFunc, skipRoles...); err == nil && foundTarget { + return &TargetWithRole{Target: Target{Name: name, Hashes: resultMeta.Hashes, Length: resultMeta.Length, Custom: resultMeta.Custom}, Role: resultRoleName}, nil + } + } + return nil, ErrNoSuchTarget(name) + +} + +// TargetSignedStruct is a struct that contains a Target, the role it was found in, and the list of signatures for that role +type TargetSignedStruct struct { + Role data.DelegationRole + Target Target + Signatures []data.Signature +} + +//ErrNoSuchTarget is returned when no valid trust data is found. +type ErrNoSuchTarget string + +func (f ErrNoSuchTarget) Error() string { + return fmt.Sprintf("No valid trust data for %s", string(f)) +} + +// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all +// roles, and returns a list of TargetSignedStructs for each time it finds the specified target. +// If given an empty string for a target name, it will return back all targets signed into the repository in every role +func (r *repository) GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error) { + if err := r.Update(false); err != nil { + return nil, err + } + + var targetInfoList []TargetSignedStruct + + // Define a visitor function to find the specified target + getAllTargetInfoByNameVisitorFunc := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { + if tgt == nil { + return nil + } + // We found a target and validated path compatibility in our walk, + // so add it to our list if we have a match + // if we have an empty name, add all targets, else check if we have it + var targetMetaToAdd data.Files + if name == "" { + targetMetaToAdd = tgt.Signed.Targets + } else { + if meta, ok := tgt.Signed.Targets[name]; ok { + targetMetaToAdd = data.Files{name: meta} + } + } + + for targetName, resultMeta := range targetMetaToAdd { + targetInfo := TargetSignedStruct{ + Role: validRole, + Target: Target{Name: targetName, Hashes: resultMeta.Hashes, Length: resultMeta.Length, Custom: resultMeta.Custom}, + Signatures: tgt.Signatures, + } + targetInfoList = append(targetInfoList, targetInfo) + } + // continue walking to all child roles + return nil + } + + // Check that we didn't error, and that we found the target at least once + if err := r.tufRepo.WalkTargets(name, "", getAllTargetInfoByNameVisitorFunc); err != nil { + return nil, err + } + if len(targetInfoList) == 0 { + return nil, ErrNoSuchTarget(name) + } + return targetInfoList, nil +} + +// GetChangelist returns the list of the repository's unpublished changes +func (r *repository) GetChangelist() (changelist.Changelist, error) { + return r.changelist, nil +} + +// getRemoteStore returns the remoteStore of a repository if valid or +// or an OfflineStore otherwise +func (r *repository) getRemoteStore() store.RemoteStore { + if r.remoteStore != nil { + return r.remoteStore + } + + r.remoteStore = &store.OfflineStore{} + + return r.remoteStore +} + +// RoleWithSignatures is a Role with its associated signatures +type RoleWithSignatures struct { + Signatures []data.Signature + data.Role +} + +// ListRoles returns a list of RoleWithSignatures objects for this repo +// This represents the latest metadata for each role in this repo +func (r *repository) ListRoles() ([]RoleWithSignatures, error) { + // Update to latest repo state + if err := r.Update(false); err != nil { + return nil, err + } + + // Get all role info from our updated keysDB, can be empty + roles := r.tufRepo.GetAllLoadedRoles() + + var roleWithSigs []RoleWithSignatures + + // Populate RoleWithSignatures with Role from keysDB and signatures from TUF metadata + for _, role := range roles { + roleWithSig := RoleWithSignatures{Role: *role, Signatures: nil} + switch role.Name { + case data.CanonicalRootRole: + roleWithSig.Signatures = r.tufRepo.Root.Signatures + case data.CanonicalTargetsRole: + roleWithSig.Signatures = r.tufRepo.Targets[data.CanonicalTargetsRole].Signatures + case data.CanonicalSnapshotRole: + roleWithSig.Signatures = r.tufRepo.Snapshot.Signatures + case data.CanonicalTimestampRole: + roleWithSig.Signatures = r.tufRepo.Timestamp.Signatures + default: + if !data.IsDelegation(role.Name) { + continue + } + if _, ok := r.tufRepo.Targets[role.Name]; ok { + // We'll only find a signature if we've published any targets with this delegation + roleWithSig.Signatures = r.tufRepo.Targets[role.Name].Signatures + } + } + roleWithSigs = append(roleWithSigs, roleWithSig) + } + return roleWithSigs, nil +} + +// Publish pushes the local changes in signed material to the remote notary-server +// Conceptually it performs an operation similar to a `git rebase` +func (r *repository) Publish() error { + if err := r.publish(r.changelist); err != nil { + return err + } + if err := r.changelist.Clear(""); err != nil { + // This is not a critical problem when only a single host is pushing + // but will cause weird behaviour if changelist cleanup is failing + // and there are multiple hosts writing to the repo. + logrus.Warn("Unable to clear changelist. You may want to manually delete the folder ", r.changelist.Location()) + } + return nil +} + +// publish pushes the changes in the given changelist to the remote notary-server +// Conceptually it performs an operation similar to a `git rebase` +func (r *repository) publish(cl changelist.Changelist) error { + var initialPublish bool + // update first before publishing + if err := r.Update(true); err != nil { + // If the remote is not aware of the repo, then this is being published + // for the first time. Try to initialize the repository before publishing. + if _, ok := err.(ErrRepositoryNotExist); ok { + err := r.bootstrapRepo() + if _, ok := err.(store.ErrMetaNotFound); ok { + logrus.Infof("No TUF data found locally or remotely - initializing repository %s for the first time", r.gun.String()) + err = r.Initialize(nil) + } + + if err != nil { + logrus.WithError(err).Debugf("Unable to load or initialize repository during first publish: %s", err.Error()) + return err + } + + // Ensure we will push the initial root and targets file. Either or + // both of the root and targets may not be marked as Dirty, since + // there may not be any changes that update them, so use a + // different boolean. + initialPublish = true + } else { + // We could not update, so we cannot publish. + logrus.Error("Could not publish Repository since we could not update: ", err.Error()) + return err + } + } + // apply the changelist to the repo + if err := applyChangelist(r.tufRepo, r.invalid, cl); err != nil { + logrus.Debug("Error applying changelist") + return err + } + + // these are the TUF files we will need to update, serialized as JSON before + // we send anything to remote + updatedFiles := make(map[data.RoleName][]byte) + + // Fetch old keys to support old clients + legacyKeys, err := r.oldKeysForLegacyClientSupport(r.LegacyVersions, initialPublish) + if err != nil { + return err + } + + // check if our root file is nearing expiry or dirty. Resign if it is. If + // root is not dirty but we are publishing for the first time, then just + // publish the existing root we have. + if err := signRootIfNecessary(updatedFiles, r.tufRepo, legacyKeys, initialPublish); err != nil { + return err + } + + if err := signTargets(updatedFiles, r.tufRepo, initialPublish); err != nil { + return err + } + + // if we initialized the repo while designating the server as the snapshot + // signer, then there won't be a snapshots file. However, we might now + // have a local key (if there was a rotation), so initialize one. + if r.tufRepo.Snapshot == nil { + if err := r.tufRepo.InitSnapshot(); err != nil { + return err + } + } + + if snapshotJSON, err := serializeCanonicalRole( + r.tufRepo, data.CanonicalSnapshotRole, nil); err == nil { + // Only update the snapshot if we've successfully signed it. + updatedFiles[data.CanonicalSnapshotRole] = snapshotJSON + } else if signErr, ok := err.(signed.ErrInsufficientSignatures); ok && signErr.FoundKeys == 0 { + // If signing fails due to us not having the snapshot key, then + // assume the server is going to sign, and do not include any snapshot + // data. + logrus.Debugf("Client does not have the key to sign snapshot. " + + "Assuming that server should sign the snapshot.") + } else { + logrus.Debugf("Client was unable to sign the snapshot: %s", err.Error()) + return err + } + + remote := r.getRemoteStore() + + return remote.SetMulti(data.MetadataRoleMapToStringMap(updatedFiles)) +} + +func signRootIfNecessary(updates map[data.RoleName][]byte, repo *tuf.Repo, extraSigningKeys data.KeyList, initialPublish bool) error { + if len(extraSigningKeys) > 0 { + repo.Root.Dirty = true + } + if nearExpiry(repo.Root.Signed.SignedCommon) || repo.Root.Dirty { + rootJSON, err := serializeCanonicalRole(repo, data.CanonicalRootRole, extraSigningKeys) + if err != nil { + return err + } + updates[data.CanonicalRootRole] = rootJSON + } else if initialPublish { + rootJSON, err := repo.Root.MarshalJSON() + if err != nil { + return err + } + updates[data.CanonicalRootRole] = rootJSON + } + return nil +} + +// Fetch back a `legacyVersions` number of roots files, collect the root public keys +// This includes old `root` roles as well as legacy versioned root roles, e.g. `1.root` +func (r *repository) oldKeysForLegacyClientSupport(legacyVersions int, initialPublish bool) (data.KeyList, error) { + if initialPublish { + return nil, nil + } + + var oldestVersion int + prevVersion := r.tufRepo.Root.Signed.Version + + if legacyVersions == SignWithAllOldVersions { + oldestVersion = 1 + } else { + oldestVersion = r.tufRepo.Root.Signed.Version - legacyVersions + } + + if oldestVersion < 1 { + oldestVersion = 1 + } + + if prevVersion <= 1 || oldestVersion == prevVersion { + return nil, nil + } + oldKeys := make(map[string]data.PublicKey) + + c, err := r.bootstrapClient(true) + // require a server connection to fetch old roots + if err != nil { + return nil, err + } + + for v := prevVersion; v >= oldestVersion; v-- { + logrus.Debugf("fetching old keys from version %d", v) + // fetch old root version + versionedRole := fmt.Sprintf("%d.%s", v, data.CanonicalRootRole.String()) + + raw, err := c.remote.GetSized(versionedRole, -1) + if err != nil { + logrus.Debugf("error downloading %s: %s", versionedRole, err) + continue + } + + signedOldRoot := &data.Signed{} + if err := json.Unmarshal(raw, signedOldRoot); err != nil { + return nil, err + } + oldRootVersion, err := data.RootFromSigned(signedOldRoot) + if err != nil { + return nil, err + } + + // extract legacy versioned root keys + oldRootVersionKeys := getOldRootPublicKeys(oldRootVersion) + for _, oldKey := range oldRootVersionKeys { + oldKeys[oldKey.ID()] = oldKey + } + } + oldKeyList := make(data.KeyList, 0, len(oldKeys)) + for _, key := range oldKeys { + oldKeyList = append(oldKeyList, key) + } + return oldKeyList, nil +} + +// get all the saved previous roles keys < the current root version +func getOldRootPublicKeys(root *data.SignedRoot) data.KeyList { + rootRole, err := root.BuildBaseRole(data.CanonicalRootRole) + if err != nil { + return nil + } + return rootRole.ListKeys() +} + +func signTargets(updates map[data.RoleName][]byte, repo *tuf.Repo, initialPublish bool) error { + // iterate through all the targets files - if they are dirty, sign and update + for roleName, roleObj := range repo.Targets { + if roleObj.Dirty || (roleName == data.CanonicalTargetsRole && initialPublish) { + targetsJSON, err := serializeCanonicalRole(repo, roleName, nil) + if err != nil { + return err + } + updates[roleName] = targetsJSON + } + } + return nil +} + +// bootstrapRepo loads the repository from the local file system (i.e. +// a not yet published repo or a possibly obsolete local copy) into +// r.tufRepo. This attempts to load metadata for all roles. Since server +// snapshots are supported, if the snapshot metadata fails to load, that's ok. +// This assumes that bootstrapRepo is only used by Publish() or RotateKey() +func (r *repository) bootstrapRepo() error { + b := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), r.trustPinning) + + logrus.Debugf("Loading trusted collection.") + + for _, role := range data.BaseRoles { + jsonBytes, err := r.cache.GetSized(role.String(), store.NoSizeLimit) + if err != nil { + if _, ok := err.(store.ErrMetaNotFound); ok && + // server snapshots are supported, and server timestamp management + // is required, so if either of these fail to load that's ok - especially + // if the repo is new + role == data.CanonicalSnapshotRole || role == data.CanonicalTimestampRole { + continue + } + return err + } + if err := b.Load(role, jsonBytes, 1, true); err != nil { + return err + } + } + + tufRepo, _, err := b.Finish() + if err == nil { + r.tufRepo = tufRepo + } + return nil +} + +// saveMetadata saves contents of r.tufRepo onto the local disk, creating +// signatures as necessary, possibly prompting for passphrases. +func (r *repository) saveMetadata(ignoreSnapshot bool) error { + logrus.Debugf("Saving changes to Trusted Collection.") + + rootJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalRootRole, nil) + if err != nil { + return err + } + err = r.cache.Set(data.CanonicalRootRole.String(), rootJSON) + if err != nil { + return err + } + + targetsToSave := make(map[data.RoleName][]byte) + for t := range r.tufRepo.Targets { + signedTargets, err := r.tufRepo.SignTargets(t, data.DefaultExpires(data.CanonicalTargetsRole)) + if err != nil { + return err + } + targetsJSON, err := json.Marshal(signedTargets) + if err != nil { + return err + } + targetsToSave[t] = targetsJSON + } + + for role, blob := range targetsToSave { + // If the parent directory does not exist, the cache.Set will create it + r.cache.Set(role.String(), blob) + } + + if ignoreSnapshot { + return nil + } + + snapshotJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalSnapshotRole, nil) + if err != nil { + return err + } + + return r.cache.Set(data.CanonicalSnapshotRole.String(), snapshotJSON) +} + +// returns a properly constructed ErrRepositoryNotExist error based on this +// repo's information +func (r *repository) errRepositoryNotExist() error { + host := r.baseURL + parsed, err := url.Parse(r.baseURL) + if err == nil { + host = parsed.Host // try to exclude the scheme and any paths + } + return ErrRepositoryNotExist{remote: host, gun: r.gun} +} + +// Update bootstraps a trust anchor (root.json) before updating all the +// metadata from the repo. +func (r *repository) Update(forWrite bool) error { + c, err := r.bootstrapClient(forWrite) + if err != nil { + if _, ok := err.(store.ErrMetaNotFound); ok { + return r.errRepositoryNotExist() + } + return err + } + repo, invalid, err := c.Update() + if err != nil { + // notFound.Resource may include a version or checksum so when the role is root, + // it will be root, .root or root.. + notFound, ok := err.(store.ErrMetaNotFound) + isRoot, _ := regexp.MatchString(`\.?`+data.CanonicalRootRole.String()+`\.?`, notFound.Resource) + if ok && isRoot { + return r.errRepositoryNotExist() + } + return err + } + // we can be assured if we are at this stage that the repo we built is good + // no need to test the following function call for an error as it will always be fine should the repo be good- it is! + r.tufRepo = repo + r.invalid = invalid + warnRolesNearExpiry(repo) + return nil +} + +// bootstrapClient attempts to bootstrap a root.json to be used as the trust +// anchor for a repository. The checkInitialized argument indicates whether +// we should always attempt to contact the server to determine if the repository +// is initialized or not. If set to true, we will always attempt to download +// and return an error if the remote repository errors. +// +// Populates a tuf.RepoBuilder with this root metadata. If the root metadata +// downloaded is a newer version than what is on disk, then intermediate +// versions will be downloaded and verified in order to rotate trusted keys +// properly. Newer root metadata must always be signed with the previous +// threshold and keys. +// +// Fails if the remote server is reachable and does not know the repo +// (i.e. before the first r.Publish()), in which case the error is +// store.ErrMetaNotFound, or if the root metadata (from whichever source is used) +// is not trusted. +// +// Returns a TUFClient for the remote server, which may not be actually +// operational (if the URL is invalid but a root.json is cached). +func (r *repository) bootstrapClient(checkInitialized bool) (*tufClient, error) { + minVersion := 1 + // the old root on disk should not be validated against any trust pinning configuration + // because if we have an old root, it itself is the thing that pins trust + oldBuilder := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), trustpinning.TrustPinConfig{}) + + // by default, we want to use the trust pinning configuration on any new root that we download + newBuilder := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), r.trustPinning) + + // Try to read root from cache first. We will trust this root until we detect a problem + // during update which will cause us to download a new root and perform a rotation. + // If we have an old root, and it's valid, then we overwrite the newBuilder to be one + // preloaded with the old root or one which uses the old root for trust bootstrapping. + if rootJSON, err := r.cache.GetSized(data.CanonicalRootRole.String(), store.NoSizeLimit); err == nil { + // if we can't load the cached root, fail hard because that is how we pin trust + if err := oldBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, true); err != nil { + return nil, err + } + + // again, the root on disk is the source of trust pinning, so use an empty trust + // pinning configuration + newBuilder = tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), trustpinning.TrustPinConfig{}) + + if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil { + // Ok, the old root is expired - we want to download a new one. But we want to use the + // old root to verify the new root, so bootstrap a new builder with the old builder + // but use the trustpinning to validate the new root + minVersion = oldBuilder.GetLoadedVersion(data.CanonicalRootRole) + newBuilder = oldBuilder.BootstrapNewBuilderWithNewTrustpin(r.trustPinning) + } + } + + remote := r.getRemoteStore() + + if !newBuilder.IsLoaded(data.CanonicalRootRole) || checkInitialized { + // remoteErr was nil and we were not able to load a root from cache or + // are specifically checking for initialization of the repo. + + // if remote store successfully set up, try and get root from remote + // We don't have any local data to determine the size of root, so try the maximum (though it is restricted at 100MB) + tmpJSON, err := remote.GetSized(data.CanonicalRootRole.String(), store.NoSizeLimit) + if err != nil { + // we didn't have a root in cache and were unable to load one from + // the server. Nothing we can do but error. + return nil, err + } + + if !newBuilder.IsLoaded(data.CanonicalRootRole) { + // we always want to use the downloaded root if we couldn't load from cache + if err := newBuilder.Load(data.CanonicalRootRole, tmpJSON, minVersion, false); err != nil { + return nil, err + } + + err = r.cache.Set(data.CanonicalRootRole.String(), tmpJSON) + if err != nil { + // if we can't write cache we should still continue, just log error + logrus.Errorf("could not save root to cache: %s", err.Error()) + } + } + } + + // We can only get here if remoteErr != nil (hence we don't download any new root), + // and there was no root on disk + if !newBuilder.IsLoaded(data.CanonicalRootRole) { + return nil, ErrRepoNotInitialized{} + } + + return newTufClient(oldBuilder, newBuilder, remote, r.cache), nil +} + +// RotateKey removes all existing keys associated with the role. If no keys are +// specified in keyList, then this creates and adds one new key or delegates +// managing the key to the server. If key(s) are specified by keyList, then they are +// used for signing the role. +// These changes are staged in a changelist until publish is called. +func (r *repository) RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error { + if err := checkRotationInput(role, serverManagesKey); err != nil { + return err + } + + pubKeyList, err := r.pubKeyListForRotation(role, serverManagesKey, keyList) + if err != nil { + return err + } + + cl := changelist.NewMemChangelist() + if err := r.rootFileKeyChange(cl, role, changelist.ActionCreate, pubKeyList); err != nil { + return err + } + return r.publish(cl) +} + +// Given a set of new keys to rotate to and a set of keys to drop, returns the list of current keys to use +func (r *repository) pubKeyListForRotation(role data.RoleName, serverManaged bool, newKeys []string) (pubKeyList data.KeyList, err error) { + var pubKey data.PublicKey + + // If server manages the key being rotated, request a rotation and return the new key + if serverManaged { + remote := r.getRemoteStore() + pubKey, err = rotateRemoteKey(role, remote) + pubKeyList = make(data.KeyList, 0, 1) + pubKeyList = append(pubKeyList, pubKey) + if err != nil { + return nil, fmt.Errorf("unable to rotate remote key: %s", err) + } + return pubKeyList, nil + } + + // If no new keys are passed in, we generate one + if len(newKeys) == 0 { + pubKeyList = make(data.KeyList, 0, 1) + pubKey, err = r.GetCryptoService().Create(role, r.gun, data.ECDSAKey) + pubKeyList = append(pubKeyList, pubKey) + } + if err != nil { + return nil, fmt.Errorf("unable to generate key: %s", err) + } + + // If a list of keys to rotate to are provided, we add those + if len(newKeys) > 0 { + pubKeyList = make(data.KeyList, 0, len(newKeys)) + for _, keyID := range newKeys { + pubKey = r.GetCryptoService().GetKey(keyID) + if pubKey == nil { + return nil, fmt.Errorf("unable to find key: %s", keyID) + } + pubKeyList = append(pubKeyList, pubKey) + } + } + + // Convert to certs (for root keys) + if pubKeyList, err = r.pubKeysToCerts(role, pubKeyList); err != nil { + return nil, err + } + + return pubKeyList, nil +} + +func (r *repository) pubKeysToCerts(role data.RoleName, pubKeyList data.KeyList) (data.KeyList, error) { + // only generate certs for root keys + if role != data.CanonicalRootRole { + return pubKeyList, nil + } + + for i, pubKey := range pubKeyList { + privKey, loadedRole, err := r.GetCryptoService().GetPrivateKey(pubKey.ID()) + if err != nil { + return nil, err + } + if loadedRole != role { + return nil, fmt.Errorf("attempted to load root key but given %s key instead", loadedRole) + } + pubKey, err = rootCertKey(r.gun, privKey) + if err != nil { + return nil, err + } + pubKeyList[i] = pubKey + } + return pubKeyList, nil +} + +func checkRotationInput(role data.RoleName, serverManaged bool) error { + // We currently support remotely managing timestamp and snapshot keys + canBeRemoteKey := role == data.CanonicalTimestampRole || role == data.CanonicalSnapshotRole + // And locally managing root, targets, and snapshot keys + canBeLocalKey := role == data.CanonicalSnapshotRole || role == data.CanonicalTargetsRole || + role == data.CanonicalRootRole + + switch { + case !data.ValidRole(role) || data.IsDelegation(role): + return fmt.Errorf("notary does not currently permit rotating the %s key", role) + case serverManaged && !canBeRemoteKey: + return ErrInvalidRemoteRole{Role: role} + case !serverManaged && !canBeLocalKey: + return ErrInvalidLocalRole{Role: role} + } + return nil +} + +func (r *repository) rootFileKeyChange(cl changelist.Changelist, role data.RoleName, action string, keyList []data.PublicKey) error { + meta := changelist.TUFRootData{ + RoleName: role, + Keys: keyList, + } + metaJSON, err := json.Marshal(meta) + if err != nil { + return err + } + + c := changelist.NewTUFChange( + action, + changelist.ScopeRoot, + changelist.TypeBaseRole, + role.String(), + metaJSON, + ) + return cl.Add(c) +} + +// DeleteTrustData removes the trust data stored for this repo in the TUF cache on the client side +// Note that we will not delete any private key material from local storage +func DeleteTrustData(baseDir string, gun data.GUN, URL string, rt http.RoundTripper, deleteRemote bool) error { + localRepo := filepath.Join(baseDir, tufDir, filepath.FromSlash(gun.String())) + // Remove the tufRepoPath directory, which includes local TUF metadata files and changelist information + if err := os.RemoveAll(localRepo); err != nil { + return fmt.Errorf("error clearing TUF repo data: %v", err) + } + // Note that this will require admin permission for the gun in the roundtripper + if deleteRemote { + remote, err := getRemoteStore(URL, gun, rt) + if err != nil { + logrus.Error("unable to instantiate a remote store: %v", err) + return err + } + if err := remote.RemoveAll(); err != nil { + return err + } + } + return nil +} + +// SetLegacyVersions allows the number of legacy versions of the root +// to be inspected for old signing keys to be configured. +func (r *repository) SetLegacyVersions(n int) { + r.LegacyVersions = n +} diff --git a/vendor/github.com/docker/notary/client/delegations.go b/vendor/github.com/theupdateframework/notary/client/delegations.go similarity index 75% rename from vendor/github.com/docker/notary/client/delegations.go rename to vendor/github.com/theupdateframework/notary/client/delegations.go index 9b5a40f5a..289654e22 100644 --- a/vendor/github.com/docker/notary/client/delegations.go +++ b/vendor/github.com/theupdateframework/notary/client/delegations.go @@ -3,19 +3,18 @@ package client import ( "encoding/json" "fmt" - "path/filepath" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - "github.com/docker/notary/client/changelist" - store "github.com/docker/notary/storage" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/client/changelist" + store "github.com/theupdateframework/notary/storage" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // AddDelegation creates changelist entries to add provided delegation public keys and paths. // This method composes AddDelegationRoleAndKeys and AddDelegationPaths (each creates one changelist if called). -func (r *NotaryRepository) AddDelegation(name string, delegationKeys []data.PublicKey, paths []string) error { +func (r *repository) AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error { if len(delegationKeys) > 0 { err := r.AddDelegationRoleAndKeys(name, delegationKeys) if err != nil { @@ -34,18 +33,12 @@ func (r *NotaryRepository) AddDelegation(name string, delegationKeys []data.Publ // AddDelegationRoleAndKeys creates a changelist entry to add provided delegation public keys. // This method is the simplest way to create a new delegation, because the delegation must have at least // one key upon creation to be valid since we will reject the changelist while validating the threshold. -func (r *NotaryRepository) AddDelegationRoleAndKeys(name string, delegationKeys []data.PublicKey) error { +func (r *repository) AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error { if !data.IsDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf(`Adding delegation "%s" with threshold %d, and %d keys\n`, name, notary.MinThreshold, len(delegationKeys)) @@ -59,23 +52,17 @@ func (r *NotaryRepository) AddDelegationRoleAndKeys(name string, delegationKeys } template := newCreateDelegationChange(name, tdJSON) - return addChange(cl, template, name) + return addChange(r.changelist, template, name) } // AddDelegationPaths creates a changelist entry to add provided paths to an existing delegation. // This method cannot create a new delegation itself because the role must meet the key threshold upon creation. -func (r *NotaryRepository) AddDelegationPaths(name string, paths []string) error { +func (r *repository) AddDelegationPaths(name data.RoleName, paths []string) error { if !data.IsDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf(`Adding %s paths to delegation %s\n`, paths, name) tdJSON, err := json.Marshal(&changelist.TUFDelegation{ @@ -86,12 +73,12 @@ func (r *NotaryRepository) AddDelegationPaths(name string, paths []string) error } template := newCreateDelegationChange(name, tdJSON) - return addChange(cl, template, name) + return addChange(r.changelist, template, name) } // RemoveDelegationKeysAndPaths creates changelist entries to remove provided delegation key IDs and paths. // This method composes RemoveDelegationPaths and RemoveDelegationKeys (each creates one changelist if called). -func (r *NotaryRepository) RemoveDelegationKeysAndPaths(name string, keyIDs, paths []string) error { +func (r *repository) RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error { if len(paths) > 0 { err := r.RemoveDelegationPaths(name, paths) if err != nil { @@ -108,37 +95,25 @@ func (r *NotaryRepository) RemoveDelegationKeysAndPaths(name string, keyIDs, pat } // RemoveDelegationRole creates a changelist to remove all paths and keys from a role, and delete the role in its entirety. -func (r *NotaryRepository) RemoveDelegationRole(name string) error { +func (r *repository) RemoveDelegationRole(name data.RoleName) error { if !data.IsDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf(`Removing delegation "%s"\n`, name) template := newDeleteDelegationChange(name, nil) - return addChange(cl, template, name) + return addChange(r.changelist, template, name) } // RemoveDelegationPaths creates a changelist entry to remove provided paths from an existing delegation. -func (r *NotaryRepository) RemoveDelegationPaths(name string, paths []string) error { +func (r *repository) RemoveDelegationPaths(name data.RoleName, paths []string) error { if !data.IsDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf(`Removing %s paths from delegation "%s"\n`, paths, name) tdJSON, err := json.Marshal(&changelist.TUFDelegation{ @@ -149,7 +124,7 @@ func (r *NotaryRepository) RemoveDelegationPaths(name string, paths []string) er } template := newUpdateDelegationChange(name, tdJSON) - return addChange(cl, template, name) + return addChange(r.changelist, template, name) } // RemoveDelegationKeys creates a changelist entry to remove provided keys from an existing delegation. @@ -157,18 +132,12 @@ func (r *NotaryRepository) RemoveDelegationPaths(name string, paths []string) er // the role itself will be deleted in its entirety. // It can also delete a key from all delegations under a parent using a name // with a wildcard at the end. -func (r *NotaryRepository) RemoveDelegationKeys(name string, keyIDs []string) error { +func (r *repository) RemoveDelegationKeys(name data.RoleName, keyIDs []string) error { if !data.IsDelegation(name) && !data.IsWildDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf(`Removing %s keys from delegation "%s"\n`, keyIDs, name) tdJSON, err := json.Marshal(&changelist.TUFDelegation{ @@ -179,22 +148,16 @@ func (r *NotaryRepository) RemoveDelegationKeys(name string, keyIDs []string) er } template := newUpdateDelegationChange(name, tdJSON) - return addChange(cl, template, name) + return addChange(r.changelist, template, name) } // ClearDelegationPaths creates a changelist entry to remove all paths from an existing delegation. -func (r *NotaryRepository) ClearDelegationPaths(name string) error { +func (r *repository) ClearDelegationPaths(name data.RoleName) error { if !data.IsDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} } - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return err - } - defer cl.Close() - logrus.Debugf(`Removing all paths from delegation "%s"\n`, name) tdJSON, err := json.Marshal(&changelist.TUFDelegation{ @@ -205,10 +168,10 @@ func (r *NotaryRepository) ClearDelegationPaths(name string) error { } template := newUpdateDelegationChange(name, tdJSON) - return addChange(cl, template, name) + return addChange(r.changelist, template, name) } -func newUpdateDelegationChange(name string, content []byte) *changelist.TUFChange { +func newUpdateDelegationChange(name data.RoleName, content []byte) *changelist.TUFChange { return changelist.NewTUFChange( changelist.ActionUpdate, name, @@ -218,7 +181,7 @@ func newUpdateDelegationChange(name string, content []byte) *changelist.TUFChang ) } -func newCreateDelegationChange(name string, content []byte) *changelist.TUFChange { +func newCreateDelegationChange(name data.RoleName, content []byte) *changelist.TUFChange { return changelist.NewTUFChange( changelist.ActionCreate, name, @@ -228,7 +191,7 @@ func newCreateDelegationChange(name string, content []byte) *changelist.TUFChang ) } -func newDeleteDelegationChange(name string, content []byte) *changelist.TUFChange { +func newDeleteDelegationChange(name data.RoleName, content []byte) *changelist.TUFChange { return changelist.NewTUFChange( changelist.ActionDelete, name, @@ -240,7 +203,7 @@ func newDeleteDelegationChange(name string, content []byte) *changelist.TUFChang // GetDelegationRoles returns the keys and roles of the repository's delegations // Also converts key IDs to canonical key IDs to keep consistent with signing prompts -func (r *NotaryRepository) GetDelegationRoles() ([]data.Role, error) { +func (r *repository) GetDelegationRoles() ([]data.Role, error) { // Update state of the repo to latest if err := r.Update(false); err != nil { return nil, err @@ -249,7 +212,7 @@ func (r *NotaryRepository) GetDelegationRoles() ([]data.Role, error) { // All top level delegations (ex: targets/level1) are stored exclusively in targets.json _, ok := r.tufRepo.Targets[data.CanonicalTargetsRole] if !ok { - return nil, store.ErrMetaNotFound{Resource: data.CanonicalTargetsRole} + return nil, store.ErrMetaNotFound{Resource: data.CanonicalTargetsRole.String()} } // make a copy for traversing nested delegations diff --git a/vendor/github.com/theupdateframework/notary/client/errors.go b/vendor/github.com/theupdateframework/notary/client/errors.go new file mode 100644 index 000000000..a2d4970ea --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/client/errors.go @@ -0,0 +1,48 @@ +package client + +import ( + "fmt" + + "github.com/theupdateframework/notary/tuf/data" +) + +// ErrRepoNotInitialized is returned when trying to publish an uninitialized +// notary repository +type ErrRepoNotInitialized struct{} + +func (err ErrRepoNotInitialized) Error() string { + return "repository has not been initialized" +} + +// ErrInvalidRemoteRole is returned when the server is requested to manage +// a key type that is not permitted +type ErrInvalidRemoteRole struct { + Role data.RoleName +} + +func (err ErrInvalidRemoteRole) Error() string { + return fmt.Sprintf( + "notary does not permit the server managing the %s key", err.Role.String()) +} + +// ErrInvalidLocalRole is returned when the client wants to manage +// a key type that is not permitted +type ErrInvalidLocalRole struct { + Role data.RoleName +} + +func (err ErrInvalidLocalRole) Error() string { + return fmt.Sprintf( + "notary does not permit the client managing the %s key", err.Role) +} + +// ErrRepositoryNotExist is returned when an action is taken on a remote +// repository that doesn't exist +type ErrRepositoryNotExist struct { + remote string + gun data.GUN +} + +func (err ErrRepositoryNotExist) Error() string { + return fmt.Sprintf("%s does not have trust data for %s", err.remote, err.gun.String()) +} diff --git a/vendor/github.com/docker/notary/client/helpers.go b/vendor/github.com/theupdateframework/notary/client/helpers.go similarity index 77% rename from vendor/github.com/docker/notary/client/helpers.go rename to vendor/github.com/theupdateframework/notary/client/helpers.go index 11691f63f..179d27ecb 100644 --- a/vendor/github.com/docker/notary/client/helpers.go +++ b/vendor/github.com/theupdateframework/notary/client/helpers.go @@ -6,18 +6,19 @@ import ( "net/http" "time" - "github.com/Sirupsen/logrus" - "github.com/docker/notary/client/changelist" - store "github.com/docker/notary/storage" - "github.com/docker/notary/tuf" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary/client/changelist" + store "github.com/theupdateframework/notary/storage" + "github.com/theupdateframework/notary/tuf" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" + "github.com/theupdateframework/notary/tuf/utils" ) // Use this to initialize remote HTTPStores from the config settings -func getRemoteStore(baseURL, gun string, rt http.RoundTripper) (store.RemoteStore, error) { +func getRemoteStore(baseURL string, gun data.GUN, rt http.RoundTripper) (store.RemoteStore, error) { s, err := store.NewHTTPStore( - baseURL+"/v2/"+gun+"/_trust/tuf/", + baseURL+"/v2/"+gun.String()+"/_trust/tuf/", "", "json", "key", @@ -26,7 +27,7 @@ func getRemoteStore(baseURL, gun string, rt http.RoundTripper) (store.RemoteStor if err != nil { return store.OfflineStore{}, err } - return s, err + return s, nil } func applyChangelist(repo *tuf.Repo, invalid *tuf.Repo, cl changelist.Changelist) error { @@ -47,7 +48,7 @@ func applyChangelist(repo *tuf.Repo, invalid *tuf.Repo, cl changelist.Changelist case c.Scope() == changelist.ScopeRoot: err = applyRootChange(repo, c) default: - return fmt.Errorf("scope not supported: %s", c.Scope()) + return fmt.Errorf("scope not supported: %s", c.Scope().String()) } if err != nil { logrus.Debugf("error attempting to apply change #%d: %s, on scope: %s path: %s type: %s", index, c.Action(), c.Scope(), c.Path(), c.Type()) @@ -165,7 +166,7 @@ func changeTargetMeta(repo *tuf.Repo, c changelist.Change) error { func applyRootChange(repo *tuf.Repo, c changelist.Change) error { var err error switch c.Type() { - case changelist.TypeRootRole: + case changelist.TypeBaseRole: err = applyRootRoleChange(repo, c) default: err = fmt.Errorf("type of root change not yet supported: %s", c.Type()) @@ -218,11 +219,7 @@ func warnRolesNearExpiry(r *tuf.Repo) { } // Fetches a public key from a remote store, given a gun and role -func getRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKey, error) { - remote, err := getRemoteStore(url, gun, rt) - if err != nil { - return nil, err - } +func getRemoteKey(role data.RoleName, remote store.RemoteStore) (data.PublicKey, error) { rawPubKey, err := remote.GetKey(role) if err != nil { return nil, err @@ -237,11 +234,7 @@ func getRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKey, } // Rotates a private key in a remote store and returns the public key component -func rotateRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKey, error) { - remote, err := getRemoteStore(url, gun, rt) - if err != nil { - return nil, err - } +func rotateRemoteKey(role data.RoleName, remote store.RemoteStore) (data.PublicKey, error) { rawPubKey, err := remote.RotateKey(role) if err != nil { return nil, err @@ -256,11 +249,11 @@ func rotateRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKe } // signs and serializes the metadata for a canonical role in a TUF repo to JSON -func serializeCanonicalRole(tufRepo *tuf.Repo, role string) (out []byte, err error) { +func serializeCanonicalRole(tufRepo *tuf.Repo, role data.RoleName, extraSigningKeys data.KeyList) (out []byte, err error) { var s *data.Signed switch { case role == data.CanonicalRootRole: - s, err = tufRepo.SignRoot(data.DefaultExpires(role)) + s, err = tufRepo.SignRoot(data.DefaultExpires(role), extraSigningKeys) case role == data.CanonicalSnapshotRole: s, err = tufRepo.SignSnapshot(data.DefaultExpires(role)) case tufRepo.Targets[role] != nil: @@ -276,3 +269,38 @@ func serializeCanonicalRole(tufRepo *tuf.Repo, role string) (out []byte, err err return json.Marshal(s) } + +func getAllPrivKeys(rootKeyIDs []string, cryptoService signed.CryptoService) ([]data.PrivateKey, error) { + if cryptoService == nil { + return nil, fmt.Errorf("no crypto service available to get private keys from") + } + + privKeys := make([]data.PrivateKey, 0, len(rootKeyIDs)) + for _, keyID := range rootKeyIDs { + privKey, _, err := cryptoService.GetPrivateKey(keyID) + if err != nil { + return nil, err + } + privKeys = append(privKeys, privKey) + } + if len(privKeys) == 0 { + var rootKeyID string + rootKeyList := cryptoService.ListKeys(data.CanonicalRootRole) + if len(rootKeyList) == 0 { + rootPublicKey, err := cryptoService.Create(data.CanonicalRootRole, "", data.ECDSAKey) + if err != nil { + return nil, err + } + rootKeyID = rootPublicKey.ID() + } else { + rootKeyID = rootKeyList[0] + } + privKey, _, err := cryptoService.GetPrivateKey(rootKeyID) + if err != nil { + return nil, err + } + privKeys = append(privKeys, privKey) + } + + return privKeys, nil +} diff --git a/vendor/github.com/theupdateframework/notary/client/interface.go b/vendor/github.com/theupdateframework/notary/client/interface.go new file mode 100644 index 000000000..4e6680dc0 --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/client/interface.go @@ -0,0 +1,47 @@ +package client + +import ( + "github.com/theupdateframework/notary/client/changelist" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" +) + +// Repository represents the set of options that must be supported over a TUF repo. +type Repository interface { + // General management operations + Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error + InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error + Publish() error + + // Target Operations + AddTarget(target *Target, roles ...data.RoleName) error + RemoveTarget(targetName string, roles ...data.RoleName) error + ListTargets(roles ...data.RoleName) ([]*TargetWithRole, error) + GetTargetByName(name string, roles ...data.RoleName) (*TargetWithRole, error) + GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error) + + // Changelist operations + GetChangelist() (changelist.Changelist, error) + + // Role operations + ListRoles() ([]RoleWithSignatures, error) + GetDelegationRoles() ([]data.Role, error) + AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error + AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error + AddDelegationPaths(name data.RoleName, paths []string) error + RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error + RemoveDelegationRole(name data.RoleName) error + RemoveDelegationPaths(name data.RoleName, paths []string) error + RemoveDelegationKeys(name data.RoleName, keyIDs []string) error + ClearDelegationPaths(name data.RoleName) error + + // Witness and other re-signing operations + Witness(roles ...data.RoleName) ([]data.RoleName, error) + + // Key Operations + RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error + + GetCryptoService() signed.CryptoService + SetLegacyVersions(int) + GetGUN() data.GUN +} diff --git a/vendor/github.com/theupdateframework/notary/client/repo.go b/vendor/github.com/theupdateframework/notary/client/repo.go new file mode 100644 index 000000000..cf2242b77 --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/client/repo.go @@ -0,0 +1,18 @@ +// +build !pkcs11 + +package client + +import ( + "fmt" + + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/trustmanager" +) + +func getKeyStores(baseDir string, retriever notary.PassRetriever) ([]trustmanager.KeyStore, error) { + fileKeyStore, err := trustmanager.NewKeyFileStore(baseDir, retriever) + if err != nil { + return nil, fmt.Errorf("failed to create private key store in directory: %s", baseDir) + } + return []trustmanager.KeyStore{fileKeyStore}, nil +} diff --git a/vendor/github.com/theupdateframework/notary/client/repo_pkcs11.go b/vendor/github.com/theupdateframework/notary/client/repo_pkcs11.go new file mode 100644 index 000000000..a24d3e604 --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/client/repo_pkcs11.go @@ -0,0 +1,25 @@ +// +build pkcs11 + +package client + +import ( + "fmt" + + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/trustmanager" + "github.com/theupdateframework/notary/trustmanager/yubikey" +) + +func getKeyStores(baseDir string, retriever notary.PassRetriever) ([]trustmanager.KeyStore, error) { + fileKeyStore, err := trustmanager.NewKeyFileStore(baseDir, retriever) + if err != nil { + return nil, fmt.Errorf("failed to create private key store in directory: %s", baseDir) + } + + keyStores := []trustmanager.KeyStore{fileKeyStore} + yubiKeyStore, _ := yubikey.NewYubiStore(fileKeyStore, retriever) + if yubiKeyStore != nil { + keyStores = []trustmanager.KeyStore{yubiKeyStore, fileKeyStore} + } + return keyStores, nil +} diff --git a/vendor/github.com/docker/notary/client/tufclient.go b/vendor/github.com/theupdateframework/notary/client/tufclient.go similarity index 59% rename from vendor/github.com/docker/notary/client/tufclient.go rename to vendor/github.com/theupdateframework/notary/client/tufclient.go index a6abdac7c..17be93056 100644 --- a/vendor/github.com/docker/notary/client/tufclient.go +++ b/vendor/github.com/theupdateframework/notary/client/tufclient.go @@ -2,26 +2,28 @@ package client import ( "encoding/json" + "fmt" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - store "github.com/docker/notary/storage" - "github.com/docker/notary/tuf" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + store "github.com/theupdateframework/notary/storage" + "github.com/theupdateframework/notary/trustpinning" + "github.com/theupdateframework/notary/tuf" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" ) -// TUFClient is a usability wrapper around a raw TUF repo -type TUFClient struct { +// tufClient is a usability wrapper around a raw TUF repo +type tufClient struct { remote store.RemoteStore cache store.MetadataStore oldBuilder tuf.RepoBuilder newBuilder tuf.RepoBuilder } -// NewTUFClient initialized a TUFClient with the given repo, remote source of content, and cache -func NewTUFClient(oldBuilder, newBuilder tuf.RepoBuilder, remote store.RemoteStore, cache store.MetadataStore) *TUFClient { - return &TUFClient{ +// newTufClient initialized a tufClient with the given repo, remote source of content, and cache +func newTufClient(oldBuilder, newBuilder tuf.RepoBuilder, remote store.RemoteStore, cache store.MetadataStore) *tufClient { + return &tufClient{ oldBuilder: oldBuilder, newBuilder: newBuilder, remote: remote, @@ -30,7 +32,7 @@ func NewTUFClient(oldBuilder, newBuilder tuf.RepoBuilder, remote store.RemoteSto } // Update performs an update to the TUF repo as defined by the TUF spec -func (c *TUFClient) Update() (*tuf.Repo, *tuf.Repo, error) { +func (c *tufClient) Update() (*tuf.Repo, *tuf.Repo, error) { // 1. Get timestamp // a. If timestamp error (verification, expired, etc...) download new root and return to 1. // 2. Check if local snapshot is up to date @@ -47,8 +49,8 @@ func (c *TUFClient) Update() (*tuf.Repo, *tuf.Repo, error) { c.newBuilder = c.newBuilder.BootstrapNewBuilder() - if err := c.downloadRoot(); err != nil { - logrus.Debug("Client Update (Root):", err) + if err := c.updateRoot(); err != nil { + logrus.Debug("Client Update (Root): ", err) return nil, nil, err } // If we error again, we now have the latest root and just want to fail @@ -61,7 +63,7 @@ func (c *TUFClient) Update() (*tuf.Repo, *tuf.Repo, error) { return c.newBuilder.Finish() } -func (c *TUFClient) update() error { +func (c *tufClient) update() error { if err := c.downloadTimestamp(); err != nil { logrus.Debugf("Client Update (Timestamp): %s", err.Error()) return err @@ -78,37 +80,103 @@ func (c *TUFClient) update() error { return nil } -// downloadRoot is responsible for downloading the root.json -func (c *TUFClient) downloadRoot() error { - role := data.CanonicalRootRole - consistentInfo := c.newBuilder.GetConsistentInfo(role) +// updateRoot checks if there is a newer version of the root available, and if so +// downloads all intermediate root files to allow proper key rotation. +func (c *tufClient) updateRoot() error { + // Get current root version + currentRootConsistentInfo := c.oldBuilder.GetConsistentInfo(data.CanonicalRootRole) + currentVersion := c.oldBuilder.GetLoadedVersion(currentRootConsistentInfo.RoleName) - // We can't read an exact size for the root metadata without risking getting stuck in the TUF update cycle - // since it's possible that downloading timestamp/snapshot metadata may fail due to a signature mismatch - if !consistentInfo.ChecksumKnown() { - logrus.Debugf("Loading root with no expected checksum") + // Get new root version + raw, err := c.downloadRoot() - // get the cached root, if it exists, just for version checking - cachedRoot, _ := c.cache.GetSized(role, -1) - // prefer to download a new root - _, remoteErr := c.tryLoadRemote(consistentInfo, cachedRoot) - return remoteErr + switch err.(type) { + case *trustpinning.ErrRootRotationFail: + // Rotation errors are okay since we haven't yet downloaded + // all intermediate root files + break + case nil: + // No error updating root - we were at most 1 version behind + return nil + default: + // Return any non-rotation error. + return err } - _, err := c.tryLoadCacheThenRemote(consistentInfo) - return err + // Load current version into newBuilder + currentRaw, err := c.cache.GetSized(data.CanonicalRootRole.String(), -1) + if err != nil { + logrus.Debugf("error loading %d.%s: %s", currentVersion, data.CanonicalRootRole, err) + return err + } + if err := c.newBuilder.LoadRootForUpdate(currentRaw, currentVersion, false); err != nil { + logrus.Debugf("%d.%s is invalid: %s", currentVersion, data.CanonicalRootRole, err) + return err + } + + // Extract newest version number + signedRoot := &data.Signed{} + if err := json.Unmarshal(raw, signedRoot); err != nil { + return err + } + newestRoot, err := data.RootFromSigned(signedRoot) + if err != nil { + return err + } + newestVersion := newestRoot.Signed.SignedCommon.Version + + // Update from current + 1 (current already loaded) to newest - 1 (newest loaded below) + if err := c.updateRootVersions(currentVersion+1, newestVersion-1); err != nil { + return err + } + + // Already downloaded newest, verify it against newest - 1 + if err := c.newBuilder.LoadRootForUpdate(raw, newestVersion, true); err != nil { + logrus.Debugf("downloaded %d.%s is invalid: %s", newestVersion, data.CanonicalRootRole, err) + return err + } + logrus.Debugf("successfully verified downloaded %d.%s", newestVersion, data.CanonicalRootRole) + + // Write newest to cache + if err := c.cache.Set(data.CanonicalRootRole.String(), raw); err != nil { + logrus.Debugf("unable to write %s to cache: %d.%s", newestVersion, data.CanonicalRootRole, err) + } + logrus.Debugf("finished updating root files") + return nil +} + +// updateRootVersions updates the root from it's current version to a target, rotating keys +// as they are found +func (c *tufClient) updateRootVersions(fromVersion, toVersion int) error { + for v := fromVersion; v <= toVersion; v++ { + logrus.Debugf("updating root from version %d to version %d, currently fetching %d", fromVersion, toVersion, v) + + versionedRole := fmt.Sprintf("%d.%s", v, data.CanonicalRootRole) + + raw, err := c.remote.GetSized(versionedRole, -1) + if err != nil { + logrus.Debugf("error downloading %s: %s", versionedRole, err) + return err + } + if err := c.newBuilder.LoadRootForUpdate(raw, v, false); err != nil { + logrus.Debugf("downloaded %s is invalid: %s", versionedRole, err) + return err + } + logrus.Debugf("successfully verified downloaded %s", versionedRole) + } + return nil } // downloadTimestamp is responsible for downloading the timestamp.json // Timestamps are special in that we ALWAYS attempt to download and only // use cache if the download fails (and the cache is still valid). -func (c *TUFClient) downloadTimestamp() error { +func (c *tufClient) downloadTimestamp() error { logrus.Debug("Loading timestamp...") role := data.CanonicalTimestampRole consistentInfo := c.newBuilder.GetConsistentInfo(role) // always get the remote timestamp, since it supersedes the local one - cachedTS, cachedErr := c.cache.GetSized(role, notary.MaxTimestampSize) + cachedTS, cachedErr := c.cache.GetSized(role.String(), notary.MaxTimestampSize) _, remoteErr := c.tryLoadRemote(consistentInfo, cachedTS) // check that there was no remote error, or if there was a network problem @@ -138,7 +206,7 @@ func (c *TUFClient) downloadTimestamp() error { } // downloadSnapshot is responsible for downloading the snapshot.json -func (c *TUFClient) downloadSnapshot() error { +func (c *tufClient) downloadSnapshot() error { logrus.Debug("Loading snapshot...") role := data.CanonicalSnapshotRole consistentInfo := c.newBuilder.GetConsistentInfo(role) @@ -150,7 +218,7 @@ func (c *TUFClient) downloadSnapshot() error { // downloadTargets downloads all targets and delegated targets for the repository. // It uses a pre-order tree traversal as it's necessary to download parents first // to obtain the keys to validate children. -func (c *TUFClient) downloadTargets() error { +func (c *tufClient) downloadTargets() error { toDownload := []data.DelegationRole{{ BaseRole: data.BaseRole{Name: data.CanonicalTargetsRole}, Paths: []string{""}, @@ -183,7 +251,7 @@ func (c *TUFClient) downloadTargets() error { return nil } -func (c TUFClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInfo) ([]data.DelegationRole, error) { +func (c tufClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInfo) ([]data.DelegationRole, error) { logrus.Debugf("Loading %s...", role.Name) tgs := &data.SignedTargets{} @@ -198,8 +266,26 @@ func (c TUFClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInf return tgs.GetValidDelegations(role), nil } -func (c *TUFClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([]byte, error) { - cachedTS, err := c.cache.GetSized(consistentInfo.RoleName, consistentInfo.Length()) +// downloadRoot is responsible for downloading the root.json +func (c *tufClient) downloadRoot() ([]byte, error) { + role := data.CanonicalRootRole + consistentInfo := c.newBuilder.GetConsistentInfo(role) + + // We can't read an exact size for the root metadata without risking getting stuck in the TUF update cycle + // since it's possible that downloading timestamp/snapshot metadata may fail due to a signature mismatch + if !consistentInfo.ChecksumKnown() { + logrus.Debugf("Loading root with no expected checksum") + + // get the cached root, if it exists, just for version checking + cachedRoot, _ := c.cache.GetSized(role.String(), -1) + // prefer to download a new root + return c.tryLoadRemote(consistentInfo, cachedRoot) + } + return c.tryLoadCacheThenRemote(consistentInfo) +} + +func (c *tufClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([]byte, error) { + cachedTS, err := c.cache.GetSized(consistentInfo.RoleName.String(), consistentInfo.Length()) if err != nil { logrus.Debugf("no %s in cache, must download", consistentInfo.RoleName) return c.tryLoadRemote(consistentInfo, nil) @@ -214,7 +300,7 @@ func (c *TUFClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([ return c.tryLoadRemote(consistentInfo, cachedTS) } -func (c *TUFClient) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) ([]byte, error) { +func (c *tufClient) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) ([]byte, error) { consistentName := consistentInfo.ConsistentName() raw, err := c.remote.GetSized(consistentName, consistentInfo.Length()) if err != nil { @@ -232,7 +318,7 @@ func (c *TUFClient) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) return raw, err } logrus.Debugf("successfully verified downloaded %s", consistentName) - if err := c.cache.Set(consistentInfo.RoleName, raw); err != nil { + if err := c.cache.Set(consistentInfo.RoleName.String(), raw); err != nil { logrus.Debugf("Unable to write %s to cache: %s", consistentInfo.RoleName, err) } return raw, nil diff --git a/vendor/github.com/docker/notary/client/witness.go b/vendor/github.com/theupdateframework/notary/client/witness.go similarity index 76% rename from vendor/github.com/docker/notary/client/witness.go rename to vendor/github.com/theupdateframework/notary/client/witness.go index 21a42aac4..ea6caa1b6 100644 --- a/vendor/github.com/docker/notary/client/witness.go +++ b/vendor/github.com/theupdateframework/notary/client/witness.go @@ -1,23 +1,16 @@ package client import ( - "path/filepath" - - "github.com/docker/notary/client/changelist" - "github.com/docker/notary/tuf" - "github.com/docker/notary/tuf/data" + "github.com/theupdateframework/notary/client/changelist" + "github.com/theupdateframework/notary/tuf" + "github.com/theupdateframework/notary/tuf/data" ) // Witness creates change objects to witness (i.e. re-sign) the given // roles on the next publish. One change is created per role -func (r *NotaryRepository) Witness(roles ...string) ([]string, error) { - cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) - if err != nil { - return nil, err - } - defer cl.Close() - - successful := make([]string, 0, len(roles)) +func (r *repository) Witness(roles ...data.RoleName) ([]data.RoleName, error) { + var err error + successful := make([]data.RoleName, 0, len(roles)) for _, role := range roles { // scope is role c := changelist.NewTUFChange( @@ -27,7 +20,7 @@ func (r *NotaryRepository) Witness(roles ...string) ([]string, error) { "", nil, ) - err = cl.Add(c) + err = r.changelist.Add(c) if err != nil { break } @@ -36,7 +29,7 @@ func (r *NotaryRepository) Witness(roles ...string) ([]string, error) { return successful, err } -func witnessTargets(repo *tuf.Repo, invalid *tuf.Repo, role string) error { +func witnessTargets(repo *tuf.Repo, invalid *tuf.Repo, role data.RoleName) error { if r, ok := repo.Targets[role]; ok { // role is already valid, mark for re-signing/updating r.Dirty = true diff --git a/vendor/github.com/docker/notary/const.go b/vendor/github.com/theupdateframework/notary/const.go similarity index 57% rename from vendor/github.com/docker/notary/const.go rename to vendor/github.com/theupdateframework/notary/const.go index 0c4d4037b..a1bf3588c 100644 --- a/vendor/github.com/docker/notary/const.go +++ b/vendor/github.com/theupdateframework/notary/const.go @@ -1,6 +1,8 @@ package notary -import "time" +import ( + "time" +) // application wide constants const ( @@ -12,14 +14,10 @@ const ( MinRSABitSize = 2048 // MinThreshold requires a minimum of one threshold for roles; currently we do not support a higher threshold MinThreshold = 1 - // PrivKeyPerms are the file permissions to use when writing private keys to disk - PrivKeyPerms = 0700 - // PubCertPerms are the file permissions to use when writing public certificates to disk - PubCertPerms = 0755 - // Sha256HexSize is how big a Sha256 hex is in number of characters - Sha256HexSize = 64 - // Sha512HexSize is how big a Sha512 hex is in number of characters - Sha512HexSize = 128 + // SHA256HexSize is how big a SHA256 hex is in number of characters + SHA256HexSize = 64 + // SHA512HexSize is how big a SHA512 hex is in number of characters + SHA512HexSize = 128 // SHA256 is the name of SHA256 hash algorithm SHA256 = "sha256" // SHA512 is the name of SHA512 hash algorithm @@ -29,8 +27,10 @@ const ( // PrivDir is the directory, under the notary repo base directory, where private keys are stored PrivDir = "private" // RootKeysSubdir is the subdirectory under PrivDir where root private keys are stored + // DEPRECATED: The only reason we need this constant is compatibility with older versions RootKeysSubdir = "root_keys" // NonRootKeysSubdir is the subdirectory under PrivDir where non-root private keys are stored + // DEPRECATED: The only reason we need this constant is compatibility with older versions NonRootKeysSubdir = "tuf_keys" // KeyExtension is the file extension to use for private key files KeyExtension = "key" @@ -54,17 +54,42 @@ const ( MySQLBackend = "mysql" MemoryBackend = "memory" + PostgresBackend = "postgres" SQLiteBackend = "sqlite3" RethinkDBBackend = "rethinkdb" + FileBackend = "file" DefaultImportRole = "delegation" + + // HealthCheckKeyManagement and HealthCheckSigner are the grpc service name + // for "KeyManagement" and "Signer" respectively which used for health check. + // The "Overall" indicates the querying for overall status of the server. + HealthCheckKeyManagement = "grpc.health.v1.Health.KeyManagement" + HealthCheckSigner = "grpc.health.v1.Health.Signer" + HealthCheckOverall = "grpc.health.v1.Health.Overall" + + // PrivExecPerms indicates the file permissions for directory + // and PrivNoExecPerms for file. + PrivExecPerms = 0700 + PrivNoExecPerms = 0600 + + // DefaultPageSize is the default number of records to return from the changefeed + DefaultPageSize = 100 ) -// NotaryDefaultExpiries is the construct used to configure the default expiry times of -// the various role files. -var NotaryDefaultExpiries = map[string]time.Duration{ - "root": NotaryRootExpiry, - "targets": NotaryTargetsExpiry, - "snapshot": NotarySnapshotExpiry, - "timestamp": NotaryTimestampExpiry, +// enum to use for setting and retrieving values from contexts +const ( + CtxKeyMetaStore CtxKey = iota + CtxKeyKeyAlgo + CtxKeyCryptoSvc + CtxKeyRepo +) + +// NotarySupportedBackends contains the backends we would like to support at present +var NotarySupportedBackends = []string{ + MemoryBackend, + MySQLBackend, + SQLiteBackend, + RethinkDBBackend, + PostgresBackend, } diff --git a/vendor/github.com/docker/notary/const_nowindows.go b/vendor/github.com/theupdateframework/notary/const_nowindows.go similarity index 100% rename from vendor/github.com/docker/notary/const_nowindows.go rename to vendor/github.com/theupdateframework/notary/const_nowindows.go diff --git a/vendor/github.com/docker/notary/const_windows.go b/vendor/github.com/theupdateframework/notary/const_windows.go similarity index 100% rename from vendor/github.com/docker/notary/const_windows.go rename to vendor/github.com/theupdateframework/notary/const_windows.go diff --git a/vendor/github.com/docker/notary/cryptoservice/certificate.go b/vendor/github.com/theupdateframework/notary/cryptoservice/certificate.go similarity index 65% rename from vendor/github.com/docker/notary/cryptoservice/certificate.go rename to vendor/github.com/theupdateframework/notary/cryptoservice/certificate.go index 805a169af..0270e89fb 100644 --- a/vendor/github.com/docker/notary/cryptoservice/certificate.go +++ b/vendor/github.com/theupdateframework/notary/cryptoservice/certificate.go @@ -7,22 +7,22 @@ import ( "fmt" "time" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // GenerateCertificate generates an X509 Certificate from a template, given a GUN and validity interval -func GenerateCertificate(rootKey data.PrivateKey, gun string, startTime, endTime time.Time) (*x509.Certificate, error) { +func GenerateCertificate(rootKey data.PrivateKey, gun data.GUN, startTime, endTime time.Time) (*x509.Certificate, error) { signer := rootKey.CryptoSigner() if signer == nil { - return nil, fmt.Errorf("key type not supported for Certificate generation: %s\n", rootKey.Algorithm()) + return nil, fmt.Errorf("key type not supported for Certificate generation: %s", rootKey.Algorithm()) } return generateCertificate(signer, gun, startTime, endTime) } -func generateCertificate(signer crypto.Signer, gun string, startTime, endTime time.Time) (*x509.Certificate, error) { - template, err := utils.NewCertificate(gun, startTime, endTime) +func generateCertificate(signer crypto.Signer, gun data.GUN, startTime, endTime time.Time) (*x509.Certificate, error) { + template, err := utils.NewCertificate(gun.String(), startTime, endTime) if err != nil { return nil, fmt.Errorf("failed to create the certificate template for: %s (%v)", gun, err) } diff --git a/vendor/github.com/docker/notary/cryptoservice/crypto_service.go b/vendor/github.com/theupdateframework/notary/cryptoservice/crypto_service.go similarity index 67% rename from vendor/github.com/docker/notary/cryptoservice/crypto_service.go rename to vendor/github.com/theupdateframework/notary/cryptoservice/crypto_service.go index 3f5002913..a558304f1 100644 --- a/vendor/github.com/docker/notary/cryptoservice/crypto_service.go +++ b/vendor/github.com/theupdateframework/notary/cryptoservice/crypto_service.go @@ -1,17 +1,16 @@ package cryptoservice import ( - "crypto/rand" - "fmt" - "crypto/x509" "encoding/pem" "errors" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "fmt" + + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/trustmanager" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) var ( @@ -36,47 +35,23 @@ func NewCryptoService(keyStores ...trustmanager.KeyStore) *CryptoService { } // Create is used to generate keys for targets, snapshots and timestamps -func (cs *CryptoService) Create(role, gun, algorithm string) (data.PublicKey, error) { - var privKey data.PrivateKey - var err error - - switch algorithm { - case data.RSAKey: - privKey, err = utils.GenerateRSAKey(rand.Reader, notary.MinRSABitSize) - if err != nil { - return nil, fmt.Errorf("failed to generate RSA key: %v", err) - } - case data.ECDSAKey: - privKey, err = utils.GenerateECDSAKey(rand.Reader) - if err != nil { - return nil, fmt.Errorf("failed to generate EC key: %v", err) - } - case data.ED25519Key: - privKey, err = utils.GenerateED25519Key(rand.Reader) - if err != nil { - return nil, fmt.Errorf("failed to generate ED25519 key: %v", err) - } - default: - return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm) +func (cs *CryptoService) Create(role data.RoleName, gun data.GUN, algorithm string) (data.PublicKey, error) { + if algorithm == data.RSAKey { + return nil, fmt.Errorf("%s keys can only be imported", data.RSAKey) } - logrus.Debugf("generated new %s key for role: %s and keyID: %s", algorithm, role, privKey.ID()) - // Store the private key into our keystore - for _, ks := range cs.keyStores { - err = ks.AddKey(trustmanager.KeyInfo{Role: role, Gun: gun}, privKey) - if err == nil { - return data.PublicKeyFromPrivate(privKey), nil - } - } + privKey, err := utils.GenerateKey(algorithm) if err != nil { - return nil, fmt.Errorf("failed to add key to filestore: %v", err) + return nil, fmt.Errorf("failed to generate %s key: %v", algorithm, err) } + logrus.Debugf("generated new %s key for role: %s and keyID: %s", algorithm, role.String(), privKey.ID()) + pubKey := data.PublicKeyFromPrivate(privKey) - return nil, fmt.Errorf("keystores would not accept new private keys for unknown reasons") + return pubKey, cs.AddKey(role, gun, privKey) } // GetPrivateKey returns a private key and role if present by ID. -func (cs *CryptoService) GetPrivateKey(keyID string) (k data.PrivateKey, role string, err error) { +func (cs *CryptoService) GetPrivateKey(keyID string) (k data.PrivateKey, role data.RoleName, err error) { for _, ks := range cs.keyStores { if k, role, err = ks.GetKey(keyID); err == nil { return @@ -120,14 +95,14 @@ func (cs *CryptoService) RemoveKey(keyID string) (err error) { // AddKey adds a private key to a specified role. // The GUN is inferred from the cryptoservice itself for non-root roles -func (cs *CryptoService) AddKey(role, gun string, key data.PrivateKey) (err error) { +func (cs *CryptoService) AddKey(role data.RoleName, gun data.GUN, key data.PrivateKey) (err error) { // First check if this key already exists in any of our keystores for _, ks := range cs.keyStores { if keyInfo, err := ks.GetKeyInfo(key.ID()); err == nil { if keyInfo.Role != role { - return fmt.Errorf("key with same ID already exists for role: %s", keyInfo.Role) + return fmt.Errorf("key with same ID already exists for role: %s", keyInfo.Role.String()) } - logrus.Debugf("key with same ID %s and role %s already exists", key.ID(), keyInfo.Role) + logrus.Debugf("key with same ID %s and role %s already exists", key.ID(), keyInfo.Role.String()) return nil } } @@ -142,7 +117,7 @@ func (cs *CryptoService) AddKey(role, gun string, key data.PrivateKey) (err erro } // ListKeys returns a list of key IDs valid for the given role -func (cs *CryptoService) ListKeys(role string) []string { +func (cs *CryptoService) ListKeys(role data.RoleName) []string { var res []string for _, ks := range cs.keyStores { for k, r := range ks.ListKeys() { @@ -155,8 +130,8 @@ func (cs *CryptoService) ListKeys(role string) []string { } // ListAllKeys returns a map of key IDs to role -func (cs *CryptoService) ListAllKeys() map[string]string { - res := make(map[string]string) +func (cs *CryptoService) ListAllKeys() map[string]data.RoleName { + res := make(map[string]data.RoleName) for _, ks := range cs.keyStores { for k, r := range ks.ListKeys() { res[k] = r.Role // keys are content addressed so don't care about overwrites @@ -173,9 +148,12 @@ func CheckRootKeyIsEncrypted(pemBytes []byte) error { return ErrNoValidPrivateKey } - if !x509.IsEncryptedPEMBlock(block) { - return ErrRootKeyNotEncrypted + if block.Type == "ENCRYPTED PRIVATE KEY" { + return nil + } + if !notary.FIPSEnabled() && x509.IsEncryptedPEMBlock(block) { + return nil } - return nil + return ErrRootKeyNotEncrypted } diff --git a/vendor/github.com/theupdateframework/notary/fips.go b/vendor/github.com/theupdateframework/notary/fips.go new file mode 100644 index 000000000..01ed2fb57 --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/fips.go @@ -0,0 +1,13 @@ +package notary + +import "os" + +// FIPSEnvVar is the name of the environment variable that is being used to switch +// between FIPS and non-FIPS mode +const FIPSEnvVar = "GOFIPS" + +// FIPSEnabled returns true if environment variable `GOFIPS` has been set to enable +// FIPS mode +func FIPSEnabled() bool { + return os.Getenv(FIPSEnvVar) != "" +} diff --git a/vendor/github.com/docker/notary/notary.go b/vendor/github.com/theupdateframework/notary/notary.go similarity index 70% rename from vendor/github.com/docker/notary/notary.go rename to vendor/github.com/theupdateframework/notary/notary.go index d6f070a47..7d6747f5d 100644 --- a/vendor/github.com/docker/notary/notary.go +++ b/vendor/github.com/theupdateframework/notary/notary.go @@ -5,3 +5,8 @@ package notary // confirmation), createNew will be true. Attempts is passed in so that implementers // decide how many chances to give to a human, for example. type PassRetriever func(keyName, alias string, createNew bool, attempts int) (passphrase string, giveup bool, err error) + +// CtxKey is a wrapper type for use in context.WithValue() to satisfy golint +// https://github.com/golang/go/issues/17293 +// https://github.com/golang/lint/pull/245 +type CtxKey int diff --git a/vendor/github.com/docker/notary/storage/errors.go b/vendor/github.com/theupdateframework/notary/storage/errors.go similarity index 100% rename from vendor/github.com/docker/notary/storage/errors.go rename to vendor/github.com/theupdateframework/notary/storage/errors.go diff --git a/vendor/github.com/docker/notary/storage/filestore.go b/vendor/github.com/theupdateframework/notary/storage/filestore.go similarity index 58% rename from vendor/github.com/docker/notary/storage/filestore.go rename to vendor/github.com/theupdateframework/notary/storage/filestore.go index 1d50a58be..c150d1ce5 100644 --- a/vendor/github.com/docker/notary/storage/filestore.go +++ b/vendor/github.com/theupdateframework/notary/storage/filestore.go @@ -1,6 +1,8 @@ package storage import ( + "bytes" + "encoding/pem" "fmt" "io" "io/ioutil" @@ -8,20 +10,14 @@ import ( "path/filepath" "strings" - "github.com/docker/notary" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" ) -// NewFilesystemStore creates a new store in a directory tree -func NewFilesystemStore(baseDir, subDir, extension string) (*FilesystemStore, error) { - baseDir = filepath.Join(baseDir, subDir) - - return NewFileStore(baseDir, extension, notary.PrivKeyPerms) -} - // NewFileStore creates a fully configurable file store -func NewFileStore(baseDir, fileExt string, perms os.FileMode) (*FilesystemStore, error) { +func NewFileStore(baseDir, fileExt string) (*FilesystemStore, error) { baseDir = filepath.Clean(baseDir) - if err := createDirectory(baseDir, perms); err != nil { + if err := createDirectory(baseDir, notary.PrivExecPerms); err != nil { return nil, err } if !strings.HasPrefix(fileExt, ".") { @@ -31,34 +27,95 @@ func NewFileStore(baseDir, fileExt string, perms os.FileMode) (*FilesystemStore, return &FilesystemStore{ baseDir: baseDir, ext: fileExt, - perms: perms, }, nil } -// NewSimpleFileStore is a convenience wrapper to create a world readable, -// owner writeable filestore -func NewSimpleFileStore(baseDir, fileExt string) (*FilesystemStore, error) { - return NewFileStore(baseDir, fileExt, notary.PubCertPerms) -} - // NewPrivateKeyFileStorage initializes a new filestore for private keys, appending // the notary.PrivDir to the baseDir. func NewPrivateKeyFileStorage(baseDir, fileExt string) (*FilesystemStore, error) { baseDir = filepath.Join(baseDir, notary.PrivDir) - return NewFileStore(baseDir, fileExt, notary.PrivKeyPerms) + myStore, err := NewFileStore(baseDir, fileExt) + myStore.migrateTo0Dot4() + return myStore, err } // NewPrivateSimpleFileStore is a wrapper to create an owner readable/writeable // _only_ filestore func NewPrivateSimpleFileStore(baseDir, fileExt string) (*FilesystemStore, error) { - return NewFileStore(baseDir, fileExt, notary.PrivKeyPerms) + return NewFileStore(baseDir, fileExt) } // FilesystemStore is a store in a locally accessible directory type FilesystemStore struct { baseDir string ext string - perms os.FileMode +} + +func (f *FilesystemStore) moveKeyTo0Dot4Location(file string) { + keyID := filepath.Base(file) + fileDir := filepath.Dir(file) + d, _ := f.Get(file) + block, _ := pem.Decode(d) + if block == nil { + logrus.Warn("Key data for", file, "could not be decoded as a valid PEM block. The key will not been migrated and may not be available") + return + } + fileDir = strings.TrimPrefix(fileDir, notary.RootKeysSubdir) + fileDir = strings.TrimPrefix(fileDir, notary.NonRootKeysSubdir) + if fileDir != "" { + block.Headers["gun"] = filepath.ToSlash(fileDir[1:]) + } + if strings.Contains(keyID, "_") { + role := strings.Split(keyID, "_")[1] + keyID = strings.TrimSuffix(keyID, "_"+role) + block.Headers["role"] = role + } + var keyPEM bytes.Buffer + // since block came from decoding the PEM bytes in the first place, and all we're doing is adding some headers we ignore the possibility of an error while encoding the block + pem.Encode(&keyPEM, block) + f.Set(keyID, keyPEM.Bytes()) +} + +func (f *FilesystemStore) migrateTo0Dot4() { + rootKeysSubDir := filepath.Clean(filepath.Join(f.Location(), notary.RootKeysSubdir)) + nonRootKeysSubDir := filepath.Clean(filepath.Join(f.Location(), notary.NonRootKeysSubdir)) + if _, err := os.Stat(rootKeysSubDir); !os.IsNotExist(err) && f.Location() != rootKeysSubDir { + if rootKeysSubDir == "" || rootKeysSubDir == "/" { + // making sure we don't remove a user's homedir + logrus.Warn("The directory for root keys is an unsafe value, we are not going to delete the directory. Please delete it manually") + } else { + // root_keys exists, migrate things from it + listOnlyRootKeysDirStore, _ := NewFileStore(rootKeysSubDir, f.ext) + for _, file := range listOnlyRootKeysDirStore.ListFiles() { + f.moveKeyTo0Dot4Location(filepath.Join(notary.RootKeysSubdir, file)) + } + // delete the old directory + os.RemoveAll(rootKeysSubDir) + } + } + + if _, err := os.Stat(nonRootKeysSubDir); !os.IsNotExist(err) && f.Location() != nonRootKeysSubDir { + if nonRootKeysSubDir == "" || nonRootKeysSubDir == "/" { + // making sure we don't remove a user's homedir + logrus.Warn("The directory for non root keys is an unsafe value, we are not going to delete the directory. Please delete it manually") + } else { + // tuf_keys exists, migrate things from it + listOnlyNonRootKeysDirStore, _ := NewFileStore(nonRootKeysSubDir, f.ext) + for _, file := range listOnlyNonRootKeysDirStore.ListFiles() { + f.moveKeyTo0Dot4Location(filepath.Join(notary.NonRootKeysSubdir, file)) + } + // delete the old directory + os.RemoveAll(nonRootKeysSubDir) + } + } + + // if we have a trusted_certificates folder, let's delete for a complete migration since it is unused by new clients + certsSubDir := filepath.Join(f.Location(), "trusted_certificates") + if certsSubDir == "" || certsSubDir == "/" { + logrus.Warn("The directory for trusted certificate is an unsafe value, we are not going to delete the directory. Please delete it manually") + } else { + os.RemoveAll(certsSubDir) + } } func (f *FilesystemStore) getPath(name string) (string, error) { @@ -80,7 +137,7 @@ func (f *FilesystemStore) GetSized(name string, size int64) ([]byte, error) { if err != nil { return nil, err } - file, err := os.OpenFile(p, os.O_RDONLY, f.perms) + file, err := os.OpenFile(p, os.O_RDONLY, notary.PrivNoExecPerms) if err != nil { if os.IsNotExist(err) { err = ErrMetaNotFound{Resource: name} @@ -140,7 +197,7 @@ func (f *FilesystemStore) Set(name string, meta []byte) error { } // Ensures the parent directories of the file we are about to write exist - err = os.MkdirAll(filepath.Dir(fp), f.perms) + err = os.MkdirAll(filepath.Dir(fp), notary.PrivExecPerms) if err != nil { return err } @@ -149,10 +206,7 @@ func (f *FilesystemStore) Set(name string, meta []byte) error { os.RemoveAll(fp) // Write the file to disk - if err = ioutil.WriteFile(fp, meta, f.perms); err != nil { - return err - } - return nil + return ioutil.WriteFile(fp, meta, notary.PrivNoExecPerms) } // RemoveAll clears the existing filestore by removing its base directory diff --git a/vendor/github.com/docker/notary/storage/httpstore.go b/vendor/github.com/theupdateframework/notary/storage/httpstore.go similarity index 83% rename from vendor/github.com/docker/notary/storage/httpstore.go rename to vendor/github.com/theupdateframework/notary/storage/httpstore.go index 994f94912..03392d4d1 100644 --- a/vendor/github.com/docker/notary/storage/httpstore.go +++ b/vendor/github.com/theupdateframework/notary/storage/httpstore.go @@ -3,7 +3,7 @@ // - Response bodies for error codes should be unmarshallable as: // {"errors": [{..., "detail": }]} // else validation error details, etc. will be unparsable. The errors -// should have a github.com/docker/notary/tuf/validation/SerializableError +// should have a github.com/theupdateframework/notary/tuf/validation/SerializableError // in the Details field. // If writing your own server, please have a look at // github.com/docker/distribution/registry/api/errcode @@ -22,9 +22,17 @@ import ( "net/url" "path" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - "github.com/docker/notary/tuf/validation" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/validation" +) + +const ( + // MaxErrorResponseSize is the maximum size for an error message - 1KiB + MaxErrorResponseSize int64 = 1 << 10 + // MaxKeySize is the maximum size for a stored TUF key - 256KiB + MaxKeySize = 256 << 10 ) // ErrServerUnavailable indicates an error from the server. code allows us to @@ -39,6 +47,21 @@ type NetworkError struct { } func (n NetworkError) Error() string { + if _, ok := n.Wrapped.(*url.Error); ok { + // QueryUnescape does the inverse transformation of QueryEscape, + // converting %AB into the byte 0xAB and '+' into ' ' (space). + // It returns an error if any % is not followed by two hexadecimal digits. + // + // If this happens, we log out the QueryUnescape error and return the + // original error to client. + res, err := url.QueryUnescape(n.Wrapped.Error()) + if err != nil { + logrus.Errorf("unescape network error message failed: %s", err) + return n.Wrapped.Error() + } + return res + } + return n.Wrapped.Error() } @@ -88,7 +111,9 @@ type HTTPStore struct { roundTrip http.RoundTripper } -// NewHTTPStore initializes a new store against a URL and a number of configuration options +// NewHTTPStore initializes a new store against a URL and a number of configuration options. +// +// In case of a nil `roundTrip`, a default offline store is used instead. func NewHTTPStore(baseURL, metaPrefix, metaExtension, keyExtension string, roundTrip http.RoundTripper) (RemoteStore, error) { base, err := url.Parse(baseURL) if err != nil { @@ -110,7 +135,8 @@ func NewHTTPStore(baseURL, metaPrefix, metaExtension, keyExtension string, round } func tryUnmarshalError(resp *http.Response, defaultError error) error { - bodyBytes, err := ioutil.ReadAll(resp.Body) + b := io.LimitReader(resp.Body, MaxErrorResponseSize) + bodyBytes, err := ioutil.ReadAll(b) if err != nil { return defaultError } @@ -269,8 +295,8 @@ func (s HTTPStore) buildMetaURL(name string) (*url.URL, error) { return s.buildURL(uri) } -func (s HTTPStore) buildKeyURL(name string) (*url.URL, error) { - filename := fmt.Sprintf("%s.%s", name, s.keyExtension) +func (s HTTPStore) buildKeyURL(name data.RoleName) (*url.URL, error) { + filename := fmt.Sprintf("%s.%s", name.String(), s.keyExtension) uri := path.Join(s.metaPrefix, filename) return s.buildURL(uri) } @@ -284,7 +310,7 @@ func (s HTTPStore) buildURL(uri string) (*url.URL, error) { } // GetKey retrieves a public key from the remote server -func (s HTTPStore) GetKey(role string) ([]byte, error) { +func (s HTTPStore) GetKey(role data.RoleName) ([]byte, error) { url, err := s.buildKeyURL(role) if err != nil { return nil, err @@ -298,10 +324,11 @@ func (s HTTPStore) GetKey(role string) ([]byte, error) { return nil, NetworkError{Wrapped: err} } defer resp.Body.Close() - if err := translateStatusToError(resp, role+" key"); err != nil { + if err := translateStatusToError(resp, role.String()+" key"); err != nil { return nil, err } - body, err := ioutil.ReadAll(resp.Body) + b := io.LimitReader(resp.Body, MaxKeySize) + body, err := ioutil.ReadAll(b) if err != nil { return nil, err } @@ -309,7 +336,7 @@ func (s HTTPStore) GetKey(role string) ([]byte, error) { } // RotateKey rotates a private key and returns the public component from the remote server -func (s HTTPStore) RotateKey(role string) ([]byte, error) { +func (s HTTPStore) RotateKey(role data.RoleName) ([]byte, error) { url, err := s.buildKeyURL(role) if err != nil { return nil, err @@ -323,10 +350,11 @@ func (s HTTPStore) RotateKey(role string) ([]byte, error) { return nil, NetworkError{Wrapped: err} } defer resp.Body.Close() - if err := translateStatusToError(resp, role+" key"); err != nil { + if err := translateStatusToError(resp, role.String()+" key"); err != nil { return nil, err } - body, err := ioutil.ReadAll(resp.Body) + b := io.LimitReader(resp.Body, MaxKeySize) + body, err := ioutil.ReadAll(b) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/notary/storage/interfaces.go b/vendor/github.com/theupdateframework/notary/storage/interfaces.go similarity index 85% rename from vendor/github.com/docker/notary/storage/interfaces.go rename to vendor/github.com/theupdateframework/notary/storage/interfaces.go index 867c9f181..c008f437a 100644 --- a/vendor/github.com/docker/notary/storage/interfaces.go +++ b/vendor/github.com/theupdateframework/notary/storage/interfaces.go @@ -1,5 +1,9 @@ package storage +import ( + "github.com/theupdateframework/notary/tuf/data" +) + // NoSizeLimit is represented as -1 for arguments to GetMeta const NoSizeLimit int64 = -1 @@ -15,8 +19,8 @@ type MetadataStore interface { // PublicKeyStore must be implemented by a key service type PublicKeyStore interface { - GetKey(role string) ([]byte, error) - RotateKey(role string) ([]byte, error) + GetKey(role data.RoleName) ([]byte, error) + RotateKey(role data.RoleName) ([]byte, error) } // RemoteStore is similar to LocalStore with the added expectation that it should diff --git a/vendor/github.com/docker/notary/storage/memorystore.go b/vendor/github.com/theupdateframework/notary/storage/memorystore.go similarity index 77% rename from vendor/github.com/docker/notary/storage/memorystore.go rename to vendor/github.com/theupdateframework/notary/storage/memorystore.go index 8a2ade54d..0c92c6994 100644 --- a/vendor/github.com/docker/notary/storage/memorystore.go +++ b/vendor/github.com/theupdateframework/notary/storage/memorystore.go @@ -2,25 +2,29 @@ package storage import ( "crypto/sha256" + "encoding/json" + "fmt" - "github.com/docker/notary" - "github.com/docker/notary/tuf/utils" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // NewMemoryStore returns a MetadataStore that operates entirely in memory. // Very useful for testing -func NewMemoryStore(initial map[string][]byte) *MemoryStore { - var consistent = make(map[string][]byte) - if initial == nil { - initial = make(map[string][]byte) - } else { - // add all seed meta to consistent - for name, data := range initial { - checksum := sha256.Sum256(data) - path := utils.ConsistentName(name, checksum[:]) - consistent[path] = data - } +func NewMemoryStore(seed map[data.RoleName][]byte) *MemoryStore { + var ( + consistent = make(map[string][]byte) + initial = make(map[string][]byte) + ) + // add all seed meta to consistent + for name, d := range seed { + checksum := sha256.Sum256(d) + path := utils.ConsistentName(name.String(), checksum[:]) + initial[name.String()] = d + consistent[path] = d } + return &MemoryStore{ data: initial, consistent: consistent, @@ -75,6 +79,15 @@ func (m MemoryStore) Get(name string) ([]byte, error) { func (m *MemoryStore) Set(name string, meta []byte) error { m.data[name] = meta + parsedMeta := &data.SignedMeta{} + err := json.Unmarshal(meta, parsedMeta) + if err == nil { + // no parse error means this is metadata and not a key, so store by version + version := parsedMeta.Signed.Version + versionedName := fmt.Sprintf("%d.%s", version, name) + m.data[versionedName] = meta + } + checksum := sha256.Sum256(meta) path := utils.ConsistentName(name, checksum[:]) m.consistent[path] = meta diff --git a/vendor/github.com/docker/notary/storage/offlinestore.go b/vendor/github.com/theupdateframework/notary/storage/offlinestore.go similarity index 84% rename from vendor/github.com/docker/notary/storage/offlinestore.go rename to vendor/github.com/theupdateframework/notary/storage/offlinestore.go index fd297601e..c5062ae6b 100644 --- a/vendor/github.com/docker/notary/storage/offlinestore.go +++ b/vendor/github.com/theupdateframework/notary/storage/offlinestore.go @@ -1,5 +1,9 @@ package storage +import ( + "github.com/theupdateframework/notary/tuf/data" +) + // ErrOffline is used to indicate we are operating offline type ErrOffline struct{} @@ -34,12 +38,12 @@ func (es OfflineStore) Remove(name string) error { } // GetKey returns ErrOffline -func (es OfflineStore) GetKey(role string) ([]byte, error) { +func (es OfflineStore) GetKey(role data.RoleName) ([]byte, error) { return nil, err } // RotateKey returns ErrOffline -func (es OfflineStore) RotateKey(role string) ([]byte, error) { +func (es OfflineStore) RotateKey(role data.RoleName) ([]byte, error) { return nil, err } diff --git a/vendor/github.com/theupdateframework/notary/trustmanager/errors.go b/vendor/github.com/theupdateframework/notary/trustmanager/errors.go new file mode 100644 index 000000000..adfcb31b0 --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/trustmanager/errors.go @@ -0,0 +1,31 @@ +package trustmanager + +import "fmt" + +// ErrAttemptsExceeded is returned when too many attempts have been made to decrypt a key +type ErrAttemptsExceeded struct{} + +// ErrAttemptsExceeded is returned when too many attempts have been made to decrypt a key +func (err ErrAttemptsExceeded) Error() string { + return "maximum number of passphrase attempts exceeded" +} + +// ErrPasswordInvalid is returned when signing fails. It could also mean the signing +// key file was corrupted, but we have no way to distinguish. +type ErrPasswordInvalid struct{} + +// ErrPasswordInvalid is returned when signing fails. It could also mean the signing +// key file was corrupted, but we have no way to distinguish. +func (err ErrPasswordInvalid) Error() string { + return "password invalid, operation has failed." +} + +// ErrKeyNotFound is returned when the keystore fails to retrieve a specific key. +type ErrKeyNotFound struct { + KeyID string +} + +// ErrKeyNotFound is returned when the keystore fails to retrieve a specific key. +func (err ErrKeyNotFound) Error() string { + return fmt.Sprintf("signing key not found: %s", err.KeyID) +} diff --git a/vendor/github.com/docker/notary/trustmanager/interfaces.go b/vendor/github.com/theupdateframework/notary/trustmanager/interfaces.go similarity index 59% rename from vendor/github.com/docker/notary/trustmanager/interfaces.go rename to vendor/github.com/theupdateframework/notary/trustmanager/interfaces.go index 34bc128d2..9925d0ff5 100644 --- a/vendor/github.com/docker/notary/trustmanager/interfaces.go +++ b/vendor/github.com/theupdateframework/notary/trustmanager/interfaces.go @@ -1,9 +1,7 @@ package trustmanager import ( - "fmt" - - "github.com/docker/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/data" ) // Storage implements the bare bones primitives (no hierarchy) @@ -34,32 +32,11 @@ type Storage interface { Location() string } -// ErrAttemptsExceeded is returned when too many attempts have been made to decrypt a key -type ErrAttemptsExceeded struct{} - -// ErrAttemptsExceeded is returned when too many attempts have been made to decrypt a key -func (err ErrAttemptsExceeded) Error() string { - return "maximum number of passphrase attempts exceeded" -} - -// ErrPasswordInvalid is returned when signing fails. It could also mean the signing -// key file was corrupted, but we have no way to distinguish. -type ErrPasswordInvalid struct{} - -// ErrPasswordInvalid is returned when signing fails. It could also mean the signing -// key file was corrupted, but we have no way to distinguish. -func (err ErrPasswordInvalid) Error() string { - return "password invalid, operation has failed." -} - -// ErrKeyNotFound is returned when the keystore fails to retrieve a specific key. -type ErrKeyNotFound struct { - KeyID string -} - -// ErrKeyNotFound is returned when the keystore fails to retrieve a specific key. -func (err ErrKeyNotFound) Error() string { - return fmt.Sprintf("signing key not found: %s", err.KeyID) +// KeyInfo stores the role and gun for a corresponding private key ID +// It is assumed that each private key ID is unique +type KeyInfo struct { + Gun data.GUN + Role data.RoleName } // KeyStore is a generic interface for private key storage @@ -69,14 +46,9 @@ type KeyStore interface { AddKey(keyInfo KeyInfo, privKey data.PrivateKey) error // Should fail with ErrKeyNotFound if the keystore is operating normally // and knows that it does not store the requested key. - GetKey(keyID string) (data.PrivateKey, string, error) + GetKey(keyID string) (data.PrivateKey, data.RoleName, error) GetKeyInfo(keyID string) (KeyInfo, error) ListKeys() map[string]KeyInfo RemoveKey(keyID string) error Name() string } - -type cachedKey struct { - alias string - key data.PrivateKey -} diff --git a/vendor/github.com/theupdateframework/notary/trustmanager/keys.go b/vendor/github.com/theupdateframework/notary/trustmanager/keys.go new file mode 100644 index 000000000..8ad77a2fe --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/trustmanager/keys.go @@ -0,0 +1,240 @@ +package trustmanager + +import ( + "encoding/pem" + "errors" + "io" + "io/ioutil" + "path/filepath" + "sort" + "strings" + + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + tufdata "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" +) + +// Exporter is a simple interface for the two functions we need from the Storage interface +type Exporter interface { + Get(string) ([]byte, error) + ListFiles() []string +} + +// Importer is a simple interface for the one function we need from the Storage interface +type Importer interface { + Set(string, []byte) error +} + +// ExportKeysByGUN exports all keys filtered to a GUN +func ExportKeysByGUN(to io.Writer, s Exporter, gun string) error { + keys := s.ListFiles() + sort.Strings(keys) // ensure consistency. ListFiles has no order guarantee + for _, loc := range keys { + keyFile, err := s.Get(loc) + if err != nil { + logrus.Warn("Could not parse key file at ", loc) + continue + } + block, _ := pem.Decode(keyFile) + keyGun := block.Headers["gun"] + if keyGun == gun { // must be full GUN match + if err := ExportKeys(to, s, loc); err != nil { + return err + } + } + } + return nil +} + +// ExportKeysByID exports all keys matching the given ID +func ExportKeysByID(to io.Writer, s Exporter, ids []string) error { + want := make(map[string]struct{}) + for _, id := range ids { + want[id] = struct{}{} + } + keys := s.ListFiles() + for _, k := range keys { + id := filepath.Base(k) + if _, ok := want[id]; ok { + if err := ExportKeys(to, s, k); err != nil { + return err + } + } + } + return nil +} + +// ExportKeys copies a key from the store to the io.Writer +func ExportKeys(to io.Writer, s Exporter, from string) error { + // get PEM block + k, err := s.Get(from) + if err != nil { + return err + } + + // parse PEM blocks if there are more than one + for block, rest := pem.Decode(k); block != nil; block, rest = pem.Decode(rest) { + // add from path in a header for later import + block.Headers["path"] = from + // write serialized PEM + err = pem.Encode(to, block) + if err != nil { + return err + } + } + return nil +} + +// ImportKeys expects an io.Reader containing one or more PEM blocks. +// It reads PEM blocks one at a time until pem.Decode returns a nil +// block. +// Each block is written to the subpath indicated in the "path" PEM +// header. If the file already exists, the file is truncated. Multiple +// adjacent PEMs with the same "path" header are appended together. +func ImportKeys(from io.Reader, to []Importer, fallbackRole string, fallbackGUN string, passRet notary.PassRetriever) error { + // importLogic.md contains a small flowchart I made to clear up my understand while writing the cases in this function + // it is very rough, but it may help while reading this piece of code + data, err := ioutil.ReadAll(from) + if err != nil { + return err + } + var ( + writeTo string + toWrite []byte + ) + for block, rest := pem.Decode(data); block != nil; block, rest = pem.Decode(rest) { + handleLegacyPath(block) + setFallbacks(block, fallbackGUN, fallbackRole) + + loc, err := checkValidity(block) + if err != nil { + // already logged in checkValidity + continue + } + + // the path header is not of any use once we've imported the key so strip it away + delete(block.Headers, "path") + + // we are now all set for import but let's first encrypt the key + blockBytes := pem.EncodeToMemory(block) + // check if key is encrypted, note: if it is encrypted at this point, it will have had a path header + if privKey, err := utils.ParsePEMPrivateKey(blockBytes, ""); err == nil { + // Key is not encrypted- ask for a passphrase and encrypt this key + var chosenPassphrase string + for attempts := 0; ; attempts++ { + var giveup bool + chosenPassphrase, giveup, err = passRet(loc, block.Headers["role"], true, attempts) + if err == nil { + break + } + if giveup || attempts > 10 { + return errors.New("maximum number of passphrase attempts exceeded") + } + } + blockBytes, err = utils.ConvertPrivateKeyToPKCS8(privKey, tufdata.RoleName(block.Headers["role"]), tufdata.GUN(block.Headers["gun"]), chosenPassphrase) + if err != nil { + return errors.New("failed to encrypt key with given passphrase") + } + } + + if loc != writeTo { + // next location is different from previous one. We've finished aggregating + // data for the previous file. If we have data, write the previous file, + // clear toWrite and set writeTo to the next path we're going to write + if toWrite != nil { + if err = importToStores(to, writeTo, toWrite); err != nil { + return err + } + } + // set up for aggregating next file's data + toWrite = nil + writeTo = loc + } + + toWrite = append(toWrite, blockBytes...) + } + if toWrite != nil { // close out final iteration if there's data left + return importToStores(to, writeTo, toWrite) + } + return nil +} + +func handleLegacyPath(block *pem.Block) { + // if there is a legacy path then we set the gun header from this path + // this is the case when a user attempts to import a key bundle generated by an older client + if rawPath := block.Headers["path"]; rawPath != "" && rawPath != filepath.Base(rawPath) { + // this is a legacy filepath and we should try to deduce the gun name from it + pathWOFileName := filepath.Dir(rawPath) + if strings.HasPrefix(pathWOFileName, notary.NonRootKeysSubdir) { + // remove the notary keystore-specific segment of the path, and any potential leading or trailing slashes + gunName := strings.Trim(strings.TrimPrefix(pathWOFileName, notary.NonRootKeysSubdir), "/") + if gunName != "" { + block.Headers["gun"] = gunName + } + } + block.Headers["path"] = filepath.Base(rawPath) + } +} + +func setFallbacks(block *pem.Block, fallbackGUN, fallbackRole string) { + if block.Headers["gun"] == "" { + if fallbackGUN != "" { + block.Headers["gun"] = fallbackGUN + } + } + + if block.Headers["role"] == "" { + if fallbackRole == "" { + block.Headers["role"] = notary.DefaultImportRole + } else { + block.Headers["role"] = fallbackRole + } + } +} + +// checkValidity ensures the fields in the pem headers are valid and parses out the location. +// While importing a collection of keys, errors from this function should result in only the +// current pem block being skipped. +func checkValidity(block *pem.Block) (string, error) { + // A root key or a delegations key should not have a gun + // Note that a key that is not any of the canonical roles (except root) is a delegations key and should not have a gun + switch block.Headers["role"] { + case tufdata.CanonicalSnapshotRole.String(), tufdata.CanonicalTargetsRole.String(), tufdata.CanonicalTimestampRole.String(): + // check if the key is missing a gun header or has an empty gun and error out since we don't know what gun it belongs to + if block.Headers["gun"] == "" { + logrus.Warnf("failed to import key (%s) to store: Cannot have canonical role key without a gun, don't know what gun it belongs to", block.Headers["path"]) + return "", errors.New("invalid key pem block") + } + default: + delete(block.Headers, "gun") + } + + loc, ok := block.Headers["path"] + // only if the path isn't specified do we get into this parsing path logic + if !ok || loc == "" { + // if the path isn't specified, we will try to infer the path rel to trust dir from the role (and then gun) + // parse key for the keyID which we will save it by. + // if the key is encrypted at this point, we will generate an error and continue since we don't know the ID to save it by + + decodedKey, err := utils.ParsePEMPrivateKey(pem.EncodeToMemory(block), "") + if err != nil { + logrus.Warn("failed to import key to store: Invalid key generated, key may be encrypted and does not contain path header") + return "", errors.New("invalid key pem block") + } + loc = decodedKey.ID() + } + return loc, nil +} + +func importToStores(to []Importer, path string, bytes []byte) error { + var err error + for _, i := range to { + if err = i.Set(path, bytes); err != nil { + logrus.Errorf("failed to import key to store: %s", err.Error()) + continue + } + break + } + return err +} diff --git a/vendor/github.com/docker/notary/trustmanager/keystore.go b/vendor/github.com/theupdateframework/notary/trustmanager/keystore.go similarity index 59% rename from vendor/github.com/docker/notary/trustmanager/keystore.go rename to vendor/github.com/theupdateframework/notary/trustmanager/keystore.go index 03d9d9687..4383f8ed7 100644 --- a/vendor/github.com/docker/notary/trustmanager/keystore.go +++ b/vendor/github.com/theupdateframework/notary/trustmanager/keystore.go @@ -1,26 +1,23 @@ package trustmanager import ( - "encoding/pem" "fmt" "path/filepath" "strings" "sync" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - store "github.com/docker/notary/storage" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + store "github.com/theupdateframework/notary/storage" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) type keyInfoMap map[string]KeyInfo -// KeyInfo stores the role, path, and gun for a corresponding private key ID -// It is assumed that each private key ID is unique -type KeyInfo struct { - Gun string - Role string +type cachedKey struct { + role data.RoleName + key data.PrivateKey } // GenericKeyStore is a wrapper for Storage instances that provides @@ -80,40 +77,6 @@ func generateKeyInfoMap(s Storage) map[string]KeyInfo { return keyInfoMap } -// Attempts to infer the keyID, role, and GUN from the specified key path. -// Note that non-root roles can only be inferred if this is a legacy style filename: KEYID_ROLE.key -func inferKeyInfoFromKeyPath(keyPath string) (string, string, string) { - var keyID, role, gun string - keyID = filepath.Base(keyPath) - underscoreIndex := strings.LastIndex(keyID, "_") - - // This is the legacy KEYID_ROLE filename - // The keyID is the first part of the keyname - // The keyRole is the second part of the keyname - // in a key named abcde_root, abcde is the keyID and root is the KeyAlias - if underscoreIndex != -1 { - role = keyID[underscoreIndex+1:] - keyID = keyID[:underscoreIndex] - } - - if filepath.HasPrefix(keyPath, notary.RootKeysSubdir+"/") { - return keyID, data.CanonicalRootRole, "" - } - - keyPath = strings.TrimPrefix(keyPath, notary.NonRootKeysSubdir+"/") - gun = getGunFromFullID(keyPath) - return keyID, role, gun -} - -func getGunFromFullID(fullKeyID string) string { - keyGun := filepath.Dir(fullKeyID) - // If the gun is empty, Dir will return . - if keyGun == "." { - keyGun = "" - } - return keyGun -} - func (s *GenericKeyStore) loadKeyInfo() { s.keyInfoMap = generateKeyInfoMap(s.store) } @@ -139,9 +102,9 @@ func (s *GenericKeyStore) AddKey(keyInfo KeyInfo, privKey data.PrivateKey) error if keyInfo.Role == data.CanonicalRootRole || data.IsDelegation(keyInfo.Role) || !data.ValidRole(keyInfo.Role) { keyInfo.Gun = "" } - name := filepath.Join(keyInfo.Gun, privKey.ID()) + keyID := privKey.ID() for attempts := 0; ; attempts++ { - chosenPassphrase, giveup, err = s.PassRetriever(name, keyInfo.Role, true, attempts) + chosenPassphrase, giveup, err = s.PassRetriever(keyID, keyInfo.Role.String(), true, attempts) if err == nil { break } @@ -150,18 +113,14 @@ func (s *GenericKeyStore) AddKey(keyInfo KeyInfo, privKey data.PrivateKey) error } } - if chosenPassphrase != "" { - pemPrivKey, err = utils.EncryptPrivateKey(privKey, keyInfo.Role, keyInfo.Gun, chosenPassphrase) - } else { - pemPrivKey, err = utils.KeyToPEM(privKey, keyInfo.Role) - } + pemPrivKey, err = utils.ConvertPrivateKeyToPKCS8(privKey, keyInfo.Role, keyInfo.Gun, chosenPassphrase) if err != nil { return err } - s.cachedKeys[name] = &cachedKey{alias: keyInfo.Role, key: privKey} - err = s.store.Set(filepath.Join(getSubdir(keyInfo.Role), name), pemPrivKey) + s.cachedKeys[keyID] = &cachedKey{role: keyInfo.Role, key: privKey} + err = s.store.Set(keyID, pemPrivKey) if err != nil { return err } @@ -170,15 +129,21 @@ func (s *GenericKeyStore) AddKey(keyInfo KeyInfo, privKey data.PrivateKey) error } // GetKey returns the PrivateKey given a KeyID -func (s *GenericKeyStore) GetKey(name string) (data.PrivateKey, string, error) { +func (s *GenericKeyStore) GetKey(keyID string) (data.PrivateKey, data.RoleName, error) { s.Lock() defer s.Unlock() - cachedKeyEntry, ok := s.cachedKeys[name] + + cachedKeyEntry, ok := s.cachedKeys[keyID] if ok { - return cachedKeyEntry.key, cachedKeyEntry.alias, nil + return cachedKeyEntry.key, cachedKeyEntry.role, nil } - keyBytes, _, keyAlias, err := getKey(s.store, name) + role, err := getKeyRole(s.store, keyID) + if err != nil { + return nil, "", err + } + + keyBytes, err := s.store.Get(keyID) if err != nil { return nil, "", err } @@ -186,13 +151,13 @@ func (s *GenericKeyStore) GetKey(name string) (data.PrivateKey, string, error) { // See if the key is encrypted. If its encrypted we'll fail to parse the private key privKey, err := utils.ParsePEMPrivateKey(keyBytes, "") if err != nil { - privKey, _, err = GetPasswdDecryptBytes(s.PassRetriever, keyBytes, name, string(keyAlias)) + privKey, _, err = GetPasswdDecryptBytes(s.PassRetriever, keyBytes, keyID, string(role)) if err != nil { return nil, "", err } } - s.cachedKeys[name] = &cachedKey{alias: keyAlias, key: privKey} - return privKey, keyAlias, nil + s.cachedKeys[keyID] = &cachedKey{role: role, key: privKey} + return privKey, role, nil } // ListKeys returns a list of unique PublicKeys present on the KeyFileStore, by returning a copy of the keyInfoMap @@ -204,24 +169,14 @@ func (s *GenericKeyStore) ListKeys() map[string]KeyInfo { func (s *GenericKeyStore) RemoveKey(keyID string) error { s.Lock() defer s.Unlock() - - _, filename, _, err := getKey(s.store, keyID) - switch err.(type) { - case ErrKeyNotFound, nil: - break - default: - return err - } - delete(s.cachedKeys, keyID) - err = s.store.Remove(filename) // removing a file that doesn't exist doesn't fail + err := s.store.Remove(keyID) if err != nil { return err } - // Remove this key from our keyInfo map if we removed from our filesystem - delete(s.keyInfoMap, filepath.Base(keyID)) + delete(s.keyInfoMap, keyID) return nil } @@ -242,55 +197,37 @@ func copyKeyInfoMap(keyInfoMap map[string]KeyInfo) map[string]KeyInfo { // KeyInfoFromPEM attempts to get a keyID and KeyInfo from the filename and PEM bytes of a key func KeyInfoFromPEM(pemBytes []byte, filename string) (string, KeyInfo, error) { - keyID, role, gun := inferKeyInfoFromKeyPath(filename) - if role == "" { - block, _ := pem.Decode(pemBytes) - if block == nil { - return "", KeyInfo{}, fmt.Errorf("could not decode PEM block for key %s", filename) - } - if keyRole, ok := block.Headers["role"]; ok { - role = keyRole - } + var keyID string + keyID = filepath.Base(filename) + role, gun, err := utils.ExtractPrivateKeyAttributes(pemBytes) + if err != nil { + return "", KeyInfo{}, err } return keyID, KeyInfo{Gun: gun, Role: role}, nil } -// getKey finds the key and role for the given keyID. It attempts to -// look both in the newer format PEM headers, and also in the legacy filename -// format. It returns: the key bytes, the filename it was found under, the role, -// and an error -func getKey(s Storage, keyID string) ([]byte, string, string, error) { +// getKeyRole finds the role for the given keyID. It attempts to look +// both in the newer format PEM headers, and also in the legacy filename +// format. It returns: the role, and an error +func getKeyRole(s Storage, keyID string) (data.RoleName, error) { name := strings.TrimSpace(strings.TrimSuffix(filepath.Base(keyID), filepath.Ext(keyID))) for _, file := range s.ListFiles() { filename := filepath.Base(file) - if strings.HasPrefix(filename, name) { d, err := s.Get(file) if err != nil { - return nil, "", "", err - } - block, _ := pem.Decode(d) - if block != nil { - if role, ok := block.Headers["role"]; ok { - return d, file, role, nil - } + return "", err } - role := strings.TrimPrefix(filename, name+"_") - return d, file, role, nil + role, _, err := utils.ExtractPrivateKeyAttributes(d) + if err != nil { + return "", err + } + return role, nil } } - - return nil, "", "", ErrKeyNotFound{KeyID: keyID} -} - -// Assumes 2 subdirectories, 1 containing root keys and 1 containing TUF keys -func getSubdir(alias string) string { - if alias == data.CanonicalRootRole { - return notary.RootKeysSubdir - } - return notary.NonRootKeysSubdir + return "", ErrKeyNotFound{KeyID: keyID} } // GetPasswdDecryptBytes gets the password to decrypt the given pem bytes. diff --git a/vendor/github.com/docker/notary/trustmanager/yubikey/import.go b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/import.go similarity index 83% rename from vendor/github.com/docker/notary/trustmanager/yubikey/import.go rename to vendor/github.com/theupdateframework/notary/trustmanager/yubikey/import.go index 08048ef52..680ded289 100644 --- a/vendor/github.com/docker/notary/trustmanager/yubikey/import.go +++ b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/import.go @@ -5,9 +5,11 @@ package yubikey import ( "encoding/pem" "errors" - "github.com/docker/notary" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/tuf/utils" + + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/trustmanager" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // YubiImport is a wrapper around the YubiStore that allows us to import private @@ -39,7 +41,7 @@ func (s *YubiImport) Set(name string, bytes []byte) error { } ki := trustmanager.KeyInfo{ // GUN is ignored by YubiStore - Role: role, + Role: data.RoleName(role), } privKey, err := utils.ParsePEMPrivateKey(bytes, "") if err != nil { @@ -47,7 +49,7 @@ func (s *YubiImport) Set(name string, bytes []byte) error { s.passRetriever, bytes, name, - ki.Role, + ki.Role.String(), ) if err != nil { return err diff --git a/vendor/github.com/docker/notary/trustmanager/yubikey/non_pkcs11.go b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/non_pkcs11.go similarity index 100% rename from vendor/github.com/docker/notary/trustmanager/yubikey/non_pkcs11.go rename to vendor/github.com/theupdateframework/notary/trustmanager/yubikey/non_pkcs11.go diff --git a/vendor/github.com/docker/notary/trustmanager/yubikey/pkcs11_darwin.go b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/pkcs11_darwin.go similarity index 100% rename from vendor/github.com/docker/notary/trustmanager/yubikey/pkcs11_darwin.go rename to vendor/github.com/theupdateframework/notary/trustmanager/yubikey/pkcs11_darwin.go diff --git a/vendor/github.com/docker/notary/trustmanager/yubikey/pkcs11_interface.go b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/pkcs11_interface.go similarity index 100% rename from vendor/github.com/docker/notary/trustmanager/yubikey/pkcs11_interface.go rename to vendor/github.com/theupdateframework/notary/trustmanager/yubikey/pkcs11_interface.go diff --git a/vendor/github.com/docker/notary/trustmanager/yubikey/pkcs11_linux.go b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/pkcs11_linux.go similarity index 100% rename from vendor/github.com/docker/notary/trustmanager/yubikey/pkcs11_linux.go rename to vendor/github.com/theupdateframework/notary/trustmanager/yubikey/pkcs11_linux.go diff --git a/vendor/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/yubikeystore.go similarity index 95% rename from vendor/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go rename to vendor/github.com/theupdateframework/notary/trustmanager/yubikey/yubikeystore.go index 94f9bd1db..1fd71eea9 100644 --- a/vendor/github.com/docker/notary/trustmanager/yubikey/yubikeystore.go +++ b/vendor/github.com/theupdateframework/notary/trustmanager/yubikey/yubikeystore.go @@ -16,13 +16,13 @@ import ( "os" "time" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" - "github.com/docker/notary/tuf/utils" "github.com/miekg/pkcs11" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/trustmanager" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" + "github.com/theupdateframework/notary/tuf/utils" ) const ( @@ -126,7 +126,7 @@ func (err errHSMNotPresent) Error() string { } type yubiSlot struct { - role string + role data.RoleName slotID []byte } @@ -208,7 +208,7 @@ func (y *YubiPrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts return sig, nil } } - return nil, errors.New("Failed to generate signature on Yubikey.") + return nil, errors.New("failed to generate signature on Yubikey") } // If a byte array is less than the number of bytes specified by @@ -230,7 +230,7 @@ func addECDSAKey( privKey data.PrivateKey, pkcs11KeyID []byte, passRetriever notary.PassRetriever, - role string, + role data.RoleName, ) error { logrus.Debugf("Attempting to add key to yubikey with ID: %s", privKey.ID()) @@ -250,7 +250,7 @@ func addECDSAKey( // Hard-coded policy: the generated certificate expires in 10 years. startTime := time.Now() - template, err := utils.NewCertificate(role, startTime, startTime.AddDate(10, 0, 0)) + template, err := utils.NewCertificate(role.String(), startTime, startTime.AddDate(10, 0, 0)) if err != nil { return fmt.Errorf("failed to create the certificate template: %v", err) } @@ -288,7 +288,7 @@ func addECDSAKey( return nil } -func getECDSAKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte) (*data.ECDSAPublicKey, string, error) { +func getECDSAKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte) (*data.ECDSAPublicKey, data.RoleName, error) { findTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), @@ -448,45 +448,19 @@ func yubiRemoveKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []b func yubiListKeys(ctx IPKCS11Ctx, session pkcs11.SessionHandle) (keys map[string]yubiSlot, err error) { keys = make(map[string]yubiSlot) - findTemplate := []*pkcs11.Attribute{ - pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), - //pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID), - pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE), - } attrTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ID, []byte{0}), pkcs11.NewAttribute(pkcs11.CKA_VALUE, []byte{0}), } - if err = ctx.FindObjectsInit(session, findTemplate); err != nil { - logrus.Debugf("Failed to init: %s", err.Error()) - return - } - objs, b, err := ctx.FindObjects(session, numSlots) - for err == nil { - var o []pkcs11.ObjectHandle - o, b, err = ctx.FindObjects(session, numSlots) - if err != nil { - continue - } - if len(o) == 0 { - break - } - objs = append(objs, o...) - } + objs, err := listObjects(ctx, session) if err != nil { - logrus.Debugf("Failed to find: %s %v", err.Error(), b) - if len(objs) == 0 { - return nil, err - } - } - if err = ctx.FindObjectsFinal(session); err != nil { - logrus.Debugf("Failed to finalize: %s", err.Error()) - return + return nil, err } + if len(objs) == 0 { - return nil, errors.New("No keys found in yubikey.") + return nil, errors.New("no keys found in yubikey") } logrus.Debugf("Found %d objects matching list filters", len(objs)) for _, obj := range objs { @@ -511,7 +485,7 @@ func yubiListKeys(ctx IPKCS11Ctx, session pkcs11.SessionHandle) (keys map[string if err != nil { continue } - if !data.ValidRole(cert.Subject.CommonName) { + if !data.ValidRole(data.RoleName(cert.Subject.CommonName)) { continue } } @@ -538,13 +512,49 @@ func yubiListKeys(ctx IPKCS11Ctx, session pkcs11.SessionHandle) (keys map[string } keys[data.NewECDSAPublicKey(pubBytes).ID()] = yubiSlot{ - role: cert.Subject.CommonName, + role: data.RoleName(cert.Subject.CommonName), slotID: slot, } } return } +func listObjects(ctx IPKCS11Ctx, session pkcs11.SessionHandle) ([]pkcs11.ObjectHandle, error) { + findTemplate := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), + pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE), + } + + if err := ctx.FindObjectsInit(session, findTemplate); err != nil { + logrus.Debugf("Failed to init: %s", err.Error()) + return nil, err + } + + objs, b, err := ctx.FindObjects(session, numSlots) + for err == nil { + var o []pkcs11.ObjectHandle + o, b, err = ctx.FindObjects(session, numSlots) + if err != nil { + continue + } + if len(o) == 0 { + break + } + objs = append(objs, o...) + } + if err != nil { + logrus.Debugf("Failed to find: %s %v", err.Error(), b) + if len(objs) == 0 { + return nil, err + } + } + if err := ctx.FindObjectsFinal(session); err != nil { + logrus.Debugf("Failed to finalize: %s", err.Error()) + return nil, err + } + return objs, nil +} + func getNextEmptySlot(ctx IPKCS11Ctx, session pkcs11.SessionHandle) ([]byte, error) { findTemplate := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), @@ -611,7 +621,7 @@ func getNextEmptySlot(ctx IPKCS11Ctx, session pkcs11.SessionHandle) ([]byte, err return []byte{byte(loc)}, nil } } - return nil, errors.New("Yubikey has no available slots.") + return nil, errors.New("yubikey has no available slots") } // YubiStore is a KeyStore for private keys inside a Yubikey @@ -687,7 +697,7 @@ func (s *YubiStore) AddKey(keyInfo trustmanager.KeyInfo, privKey data.PrivateKey // Only add if we haven't seen the key already. Return whether the key was // added. -func (s *YubiStore) addKey(keyID, role string, privKey data.PrivateKey) ( +func (s *YubiStore) addKey(keyID string, role data.RoleName, privKey data.PrivateKey) ( bool, error) { // We only allow adding root keys for now @@ -733,7 +743,7 @@ func (s *YubiStore) addKey(keyID, role string, privKey data.PrivateKey) ( // GetKey retrieves a key from the Yubikey only (it does not look inside the // backup store) -func (s *YubiStore) GetKey(keyID string) (data.PrivateKey, string, error) { +func (s *YubiStore) GetKey(keyID string) (data.PrivateKey, data.RoleName, error) { ctx, session, err := SetupHSMEnv(pkcs11Lib, s.libLoader) if err != nil { logrus.Debugf("No yubikey found, using alternative key storage: %s", err.Error()) diff --git a/vendor/github.com/docker/notary/trustpinning/certs.go b/vendor/github.com/theupdateframework/notary/trustpinning/certs.go similarity index 92% rename from vendor/github.com/docker/notary/trustpinning/certs.go rename to vendor/github.com/theupdateframework/notary/trustpinning/certs.go index 709df67d1..9be49ee10 100644 --- a/vendor/github.com/docker/notary/trustpinning/certs.go +++ b/vendor/github.com/theupdateframework/notary/trustpinning/certs.go @@ -6,12 +6,14 @@ import ( "fmt" "strings" - "github.com/Sirupsen/logrus" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" - "github.com/docker/notary/tuf/utils" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" + "github.com/theupdateframework/notary/tuf/utils" ) +const wildcard = "*" + // ErrValidationFail is returned when there is no valid trusted certificates // being served inside of the roots.json type ErrValidationFail struct { @@ -82,7 +84,7 @@ We shall call this: TOFUS. Validation failure at any step will result in an ErrValidationFailed error. */ -func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trustPinning TrustPinConfig) (*data.SignedRoot, error) { +func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun data.GUN, trustPinning TrustPinConfig) (*data.SignedRoot, error) { logrus.Debugf("entered ValidateRoot with dns: %s", gun) signedRoot, err := data.RootFromSigned(root) if err != nil { @@ -140,7 +142,7 @@ func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trus } // Regardless of having a previous root or not, confirm that the new root validates against the trust pinning - logrus.Debugf("checking root against trust_pinning config", gun) + logrus.Debugf("checking root against trust_pinning config for %s", gun) trustPinCheckFunc, err := NewTrustPinChecker(trustPinning, gun, !havePrevRoot) if err != nil { return nil, &ErrValidationFail{Reason: err.Error()} @@ -175,16 +177,27 @@ func ValidateRoot(prevRoot *data.SignedRoot, root *data.Signed, gun string, trus return data.RootFromSigned(root) } +// MatchCNToGun checks that the common name in a cert is valid for the given gun. +// This allows wildcards as suffixes, e.g. `namespace/*` +func MatchCNToGun(commonName string, gun data.GUN) bool { + if strings.HasSuffix(commonName, wildcard) { + prefix := strings.TrimRight(commonName, wildcard) + logrus.Debugf("checking gun %s against wildcard prefix %s", gun, prefix) + return strings.HasPrefix(gun.String(), prefix) + } + return commonName == gun.String() +} + // validRootLeafCerts returns a list of possibly (if checkExpiry is true) non-expired, non-sha1 certificates // found in root whose Common-Names match the provided GUN. Note that this // "validity" alone does not imply any measure of trust. -func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun string, checkExpiry bool) (map[string]*x509.Certificate, error) { +func validRootLeafCerts(allLeafCerts map[string]*x509.Certificate, gun data.GUN, checkExpiry bool) (map[string]*x509.Certificate, error) { validLeafCerts := make(map[string]*x509.Certificate) // Go through every leaf certificate and check that the CN matches the gun for id, cert := range allLeafCerts { - // Validate that this leaf certificate has a CN that matches the exact gun - if cert.Subject.CommonName != gun { + // Validate that this leaf certificate has a CN that matches the gun + if !MatchCNToGun(cert.Subject.CommonName, gun) { logrus.Debugf("error leaf certificate CN: %s doesn't match the given GUN: %s", cert.Subject.CommonName, gun) continue diff --git a/vendor/github.com/docker/notary/trustpinning/trustpin.go b/vendor/github.com/theupdateframework/notary/trustpinning/trustpin.go similarity index 63% rename from vendor/github.com/docker/notary/trustpinning/trustpin.go rename to vendor/github.com/theupdateframework/notary/trustpinning/trustpin.go index 252885676..67908f8b2 100644 --- a/vendor/github.com/docker/notary/trustpinning/trustpin.go +++ b/vendor/github.com/theupdateframework/notary/trustpinning/trustpin.go @@ -3,21 +3,38 @@ package trustpinning import ( "crypto/x509" "fmt" - "github.com/Sirupsen/logrus" - "github.com/docker/notary/tuf/utils" "strings" + + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // TrustPinConfig represents the configuration under the trust_pinning section of the config file // This struct represents the preferred way to bootstrap trust for this repository +// This is fully optional. If left at the default, uninitialized value Notary will use TOFU over +// HTTPS. +// You can use this to provide certificates or a CA to pin to as a root of trust for a GUN. +// These are used with the following precedence: +// +// 1. Certs +// 2. CA +// 3. TOFUS (TOFU over HTTPS) +// +// Only one trust pinning option will be used to validate a particular GUN. type TrustPinConfig struct { - CA map[string]string - Certs map[string][]string + // CA maps a GUN prefix to file paths containing the root CA. + // This file can contain multiple root certificates, bundled in separate PEM blocks. + CA map[string]string + // Certs maps a GUN to a list of certificate IDs + Certs map[string][]string + // DisableTOFU, when true, disables "Trust On First Use" of new key data + // This is false by default, which means new key data will always be trusted the first time it is seen. DisableTOFU bool } type trustPinChecker struct { - gun string + gun data.GUN config TrustPinConfig pinnedCAPool *x509.CertPool pinnedCertIDs []string @@ -27,14 +44,19 @@ type trustPinChecker struct { type CertChecker func(leafCert *x509.Certificate, intCerts []*x509.Certificate) bool // NewTrustPinChecker returns a new certChecker function from a TrustPinConfig for a GUN -func NewTrustPinChecker(trustPinConfig TrustPinConfig, gun string, firstBootstrap bool) (CertChecker, error) { +func NewTrustPinChecker(trustPinConfig TrustPinConfig, gun data.GUN, firstBootstrap bool) (CertChecker, error) { t := trustPinChecker{gun: gun, config: trustPinConfig} // Determine the mode, and if it's even valid - if pinnedCerts, ok := trustPinConfig.Certs[gun]; ok { + if pinnedCerts, ok := trustPinConfig.Certs[gun.String()]; ok { logrus.Debugf("trust-pinning using Cert IDs") t.pinnedCertIDs = pinnedCerts return t.certsCheck, nil } + var ok bool + t.pinnedCertIDs, ok = wildcardMatch(gun, trustPinConfig.Certs) + if ok { + return t.certsCheck, nil + } if caFilepath, err := getPinnedCAFilepathByPrefix(gun, trustPinConfig); err == nil { logrus.Debugf("trust-pinning using root CA bundle at: %s", caFilepath) @@ -103,19 +125,39 @@ func (t trustPinChecker) tofusCheck(leafCert *x509.Certificate, intCerts []*x509 // Will return the CA filepath corresponding to the most specific (longest) entry in the map that is still a prefix // of the provided gun. Returns an error if no entry matches this GUN as a prefix. -func getPinnedCAFilepathByPrefix(gun string, t TrustPinConfig) (string, error) { +func getPinnedCAFilepathByPrefix(gun data.GUN, t TrustPinConfig) (string, error) { specificGUN := "" specificCAFilepath := "" foundCA := false for gunPrefix, caFilepath := range t.CA { - if strings.HasPrefix(gun, gunPrefix) && len(gunPrefix) >= len(specificGUN) { + if strings.HasPrefix(gun.String(), gunPrefix) && len(gunPrefix) >= len(specificGUN) { specificGUN = gunPrefix specificCAFilepath = caFilepath foundCA = true } } if !foundCA { - return "", fmt.Errorf("could not find pinned CA for GUN: %s\n", gun) + return "", fmt.Errorf("could not find pinned CA for GUN: %s", gun) } return specificCAFilepath, nil } + +// wildcardMatch will attempt to match the most specific (longest prefix) wildcarded +// trustpinning option for key IDs. Given the simple globbing and the use of maps, +// it is impossible to have two different prefixes of equal length. +// This logic also solves the issue of Go's randomization of map iteration. +func wildcardMatch(gun data.GUN, certs map[string][]string) ([]string, bool) { + var ( + longest = "" + ids []string + ) + for gunPrefix, keyIDs := range certs { + if strings.HasSuffix(gunPrefix, "*") { + if strings.HasPrefix(gun.String(), gunPrefix[:len(gunPrefix)-1]) && len(gunPrefix) > len(longest) { + longest = gunPrefix + ids = keyIDs + } + } + } + return ids, ids != nil +} diff --git a/vendor/github.com/docker/notary/tuf/LICENSE b/vendor/github.com/theupdateframework/notary/tuf/LICENSE similarity index 100% rename from vendor/github.com/docker/notary/tuf/LICENSE rename to vendor/github.com/theupdateframework/notary/tuf/LICENSE diff --git a/vendor/github.com/docker/notary/tuf/README.md b/vendor/github.com/theupdateframework/notary/tuf/README.md similarity index 100% rename from vendor/github.com/docker/notary/tuf/README.md rename to vendor/github.com/theupdateframework/notary/tuf/README.md diff --git a/vendor/github.com/docker/notary/tuf/builder.go b/vendor/github.com/theupdateframework/notary/tuf/builder.go similarity index 80% rename from vendor/github.com/docker/notary/tuf/builder.go rename to vendor/github.com/theupdateframework/notary/tuf/builder.go index 1eaf0498c..db0a4d111 100644 --- a/vendor/github.com/docker/notary/tuf/builder.go +++ b/vendor/github.com/theupdateframework/notary/tuf/builder.go @@ -4,12 +4,12 @@ import ( "fmt" "github.com/docker/go/canonical/json" - "github.com/docker/notary" + "github.com/theupdateframework/notary" - "github.com/docker/notary/trustpinning" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" - "github.com/docker/notary/tuf/utils" + "github.com/theupdateframework/notary/trustpinning" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" + "github.com/theupdateframework/notary/tuf/utils" ) // ErrBuildDone is returned when any functions are called on RepoBuilder, and it @@ -28,7 +28,7 @@ func (e ErrInvalidBuilderInput) Error() string { // ConsistentInfo is the consistent name and size of a role, or just the name // of the role and a -1 if no file metadata for the role is known type ConsistentInfo struct { - RoleName string + RoleName data.RoleName fileMeta data.FileMeta } @@ -42,7 +42,7 @@ func (c ConsistentInfo) ChecksumKnown() bool { // ConsistentName returns the consistent name (rolename.sha256) for the role // given this consistent information func (c ConsistentInfo) ConsistentName() string { - return utils.ConsistentName(c.RoleName, c.fileMeta.Hashes[notary.SHA256]) + return utils.ConsistentName(c.RoleName.String(), c.fileMeta.Hashes[notary.SHA256]) } // Length returns the expected length of the role as per this consistent @@ -56,7 +56,8 @@ func (c ConsistentInfo) Length() int64 { // RepoBuilder is an interface for an object which builds a tuf.Repo type RepoBuilder interface { - Load(roleName string, content []byte, minVersion int, allowExpired bool) error + Load(roleName data.RoleName, content []byte, minVersion int, allowExpired bool) error + LoadRootForUpdate(content []byte, minVersion int, isFinal bool) error GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, error) GenerateTimestamp(prev *data.SignedTimestamp) ([]byte, int, error) Finish() (*Repo, *Repo, error) @@ -64,15 +65,18 @@ type RepoBuilder interface { BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning.TrustPinConfig) RepoBuilder // informative functions - IsLoaded(roleName string) bool - GetLoadedVersion(roleName string) int - GetConsistentInfo(roleName string) ConsistentInfo + IsLoaded(roleName data.RoleName) bool + GetLoadedVersion(roleName data.RoleName) int + GetConsistentInfo(roleName data.RoleName) ConsistentInfo } // finishedBuilder refuses any more input or output type finishedBuilder struct{} -func (f finishedBuilder) Load(roleName string, content []byte, minVersion int, allowExpired bool) error { +func (f finishedBuilder) Load(roleName data.RoleName, content []byte, minVersion int, allowExpired bool) error { + return ErrBuildDone +} +func (f finishedBuilder) LoadRootForUpdate(content []byte, minVersion int, isFinal bool) error { return ErrBuildDone } func (f finishedBuilder) GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, error) { @@ -86,27 +90,27 @@ func (f finishedBuilder) BootstrapNewBuilder() RepoBuilder { return f } func (f finishedBuilder) BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning.TrustPinConfig) RepoBuilder { return f } -func (f finishedBuilder) IsLoaded(roleName string) bool { return false } -func (f finishedBuilder) GetLoadedVersion(roleName string) int { return 0 } -func (f finishedBuilder) GetConsistentInfo(roleName string) ConsistentInfo { +func (f finishedBuilder) IsLoaded(roleName data.RoleName) bool { return false } +func (f finishedBuilder) GetLoadedVersion(roleName data.RoleName) int { return 0 } +func (f finishedBuilder) GetConsistentInfo(roleName data.RoleName) ConsistentInfo { return ConsistentInfo{RoleName: roleName} } // NewRepoBuilder is the only way to get a pre-built RepoBuilder -func NewRepoBuilder(gun string, cs signed.CryptoService, trustpin trustpinning.TrustPinConfig) RepoBuilder { +func NewRepoBuilder(gun data.GUN, cs signed.CryptoService, trustpin trustpinning.TrustPinConfig) RepoBuilder { return NewBuilderFromRepo(gun, NewRepo(cs), trustpin) } // NewBuilderFromRepo allows us to bootstrap a builder given existing repo data. // YOU PROBABLY SHOULDN'T BE USING THIS OUTSIDE OF TESTING CODE!!! -func NewBuilderFromRepo(gun string, repo *Repo, trustpin trustpinning.TrustPinConfig) RepoBuilder { +func NewBuilderFromRepo(gun data.GUN, repo *Repo, trustpin trustpinning.TrustPinConfig) RepoBuilder { return &repoBuilderWrapper{ RepoBuilder: &repoBuilder{ repo: repo, invalidRoles: NewRepo(nil), gun: gun, trustpin: trustpin, - loadedNotChecksummed: make(map[string][]byte), + loadedNotChecksummed: make(map[data.RoleName][]byte), }, } } @@ -134,13 +138,13 @@ type repoBuilder struct { invalidRoles *Repo // needed for root trust pininng verification - gun string + gun data.GUN trustpin trustpinning.TrustPinConfig // in case we load root and/or targets before snapshot and timestamp ( // or snapshot and not timestamp), so we know what to verify when the // data with checksums come in - loadedNotChecksummed map[string][]byte + loadedNotChecksummed map[data.RoleName][]byte // bootstrapped values to validate a new root prevRoot *data.SignedRoot @@ -159,7 +163,7 @@ func (rb *repoBuilder) BootstrapNewBuilder() RepoBuilder { repo: NewRepo(rb.repo.cryptoService), invalidRoles: NewRepo(nil), gun: rb.gun, - loadedNotChecksummed: make(map[string][]byte), + loadedNotChecksummed: make(map[data.RoleName][]byte), trustpin: rb.trustpin, prevRoot: rb.repo.Root, @@ -171,7 +175,7 @@ func (rb *repoBuilder) BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning. return &repoBuilderWrapper{RepoBuilder: &repoBuilder{ repo: NewRepo(rb.repo.cryptoService), gun: rb.gun, - loadedNotChecksummed: make(map[string][]byte), + loadedNotChecksummed: make(map[data.RoleName][]byte), trustpin: trustpin, prevRoot: rb.repo.Root, @@ -180,7 +184,7 @@ func (rb *repoBuilder) BootstrapNewBuilderWithNewTrustpin(trustpin trustpinning. } // IsLoaded returns whether a particular role has already been loaded -func (rb *repoBuilder) IsLoaded(roleName string) bool { +func (rb *repoBuilder) IsLoaded(roleName data.RoleName) bool { switch roleName { case data.CanonicalRootRole: return rb.repo.Root != nil @@ -195,7 +199,7 @@ func (rb *repoBuilder) IsLoaded(roleName string) bool { // GetLoadedVersion returns the metadata version, if it is loaded, or 1 (the // minimum valid version number) otherwise -func (rb *repoBuilder) GetLoadedVersion(roleName string) int { +func (rb *repoBuilder) GetLoadedVersion(roleName data.RoleName) int { switch { case roleName == data.CanonicalRootRole && rb.repo.Root != nil: return rb.repo.Root.Signed.Version @@ -215,7 +219,7 @@ func (rb *repoBuilder) GetLoadedVersion(roleName string) int { // GetConsistentInfo returns the consistent name and size of a role, if it is known, // otherwise just the rolename and a -1 for size (both of which are inside a // ConsistentInfo object) -func (rb *repoBuilder) GetConsistentInfo(roleName string) ConsistentInfo { +func (rb *repoBuilder) GetConsistentInfo(roleName data.RoleName) ConsistentInfo { info := ConsistentInfo{RoleName: roleName} // starts out with unknown filemeta switch roleName { case data.CanonicalTimestampRole: @@ -224,29 +228,45 @@ func (rb *repoBuilder) GetConsistentInfo(roleName string) ConsistentInfo { info.fileMeta.Length = notary.MaxTimestampSize case data.CanonicalSnapshotRole: if rb.repo.Timestamp != nil { - info.fileMeta = rb.repo.Timestamp.Signed.Meta[roleName] + info.fileMeta = rb.repo.Timestamp.Signed.Meta[roleName.String()] } case data.CanonicalRootRole: switch { case rb.bootstrappedRootChecksum != nil: info.fileMeta = *rb.bootstrappedRootChecksum case rb.repo.Snapshot != nil: - info.fileMeta = rb.repo.Snapshot.Signed.Meta[roleName] + info.fileMeta = rb.repo.Snapshot.Signed.Meta[roleName.String()] } default: if rb.repo.Snapshot != nil { - info.fileMeta = rb.repo.Snapshot.Signed.Meta[roleName] + info.fileMeta = rb.repo.Snapshot.Signed.Meta[roleName.String()] } } return info } -func (rb *repoBuilder) Load(roleName string, content []byte, minVersion int, allowExpired bool) error { +func (rb *repoBuilder) Load(roleName data.RoleName, content []byte, minVersion int, allowExpired bool) error { + return rb.loadOptions(roleName, content, minVersion, allowExpired, false, false) +} + +// LoadRootForUpdate adds additional flags for updating the root.json file +func (rb *repoBuilder) LoadRootForUpdate(content []byte, minVersion int, isFinal bool) error { + if err := rb.loadOptions(data.CanonicalRootRole, content, minVersion, !isFinal, !isFinal, true); err != nil { + return err + } + if !isFinal { + rb.prevRoot = rb.repo.Root + } + return nil +} + +// loadOptions adds additional flags that should only be used for updating the root.json +func (rb *repoBuilder) loadOptions(roleName data.RoleName, content []byte, minVersion int, allowExpired, skipChecksum, allowLoaded bool) error { if !data.ValidRole(roleName) { return ErrInvalidBuilderInput{msg: fmt.Sprintf("%s is an invalid role", roleName)} } - if rb.IsLoaded(roleName) { + if !allowLoaded && rb.IsLoaded(roleName) { return ErrInvalidBuilderInput{msg: fmt.Sprintf("%s has already been loaded", roleName)} } @@ -255,9 +275,9 @@ func (rb *repoBuilder) Load(roleName string, content []byte, minVersion int, all case data.CanonicalRootRole: break case data.CanonicalTimestampRole, data.CanonicalSnapshotRole, data.CanonicalTargetsRole: - err = rb.checkPrereqsLoaded([]string{data.CanonicalRootRole}) + err = rb.checkPrereqsLoaded([]data.RoleName{data.CanonicalRootRole}) default: // delegations - err = rb.checkPrereqsLoaded([]string{data.CanonicalRootRole, data.CanonicalTargetsRole}) + err = rb.checkPrereqsLoaded([]data.RoleName{data.CanonicalRootRole, data.CanonicalTargetsRole}) } if err != nil { return err @@ -265,7 +285,7 @@ func (rb *repoBuilder) Load(roleName string, content []byte, minVersion int, all switch roleName { case data.CanonicalRootRole: - return rb.loadRoot(content, minVersion, allowExpired) + return rb.loadRoot(content, minVersion, allowExpired, skipChecksum) case data.CanonicalSnapshotRole: return rb.loadSnapshot(content, minVersion, allowExpired) case data.CanonicalTimestampRole: @@ -277,7 +297,7 @@ func (rb *repoBuilder) Load(roleName string, content []byte, minVersion int, all } } -func (rb *repoBuilder) checkPrereqsLoaded(prereqRoles []string) error { +func (rb *repoBuilder) checkPrereqsLoaded(prereqRoles []data.RoleName) error { for _, req := range prereqRoles { if !rb.IsLoaded(req) { return ErrInvalidBuilderInput{msg: fmt.Sprintf("%s must be loaded first", req)} @@ -301,7 +321,7 @@ func (rb *repoBuilder) GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, return nil, 0, ErrInvalidBuilderInput{msg: "cannot generate snapshot if timestamp has already been loaded"} } - if err := rb.checkPrereqsLoaded([]string{data.CanonicalRootRole}); err != nil { + if err := rb.checkPrereqsLoaded([]data.RoleName{data.CanonicalRootRole}); err != nil { return nil, 0, err } @@ -310,7 +330,7 @@ func (rb *repoBuilder) GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, // valid (it has a targets meta), we're good. switch prev { case nil: - if err := rb.checkPrereqsLoaded([]string{data.CanonicalTargetsRole}); err != nil { + if err := rb.checkPrereqsLoaded([]data.RoleName{data.CanonicalTargetsRole}); err != nil { return nil, 0, err } @@ -342,7 +362,7 @@ func (rb *repoBuilder) GenerateSnapshot(prev *data.SignedSnapshot) ([]byte, int, // the root and targets data (there may not be any) that that have been loaded, // remove all of them from rb.loadedNotChecksummed for tgtName := range rb.repo.Targets { - delete(rb.loadedNotChecksummed, tgtName) + delete(rb.loadedNotChecksummed, data.RoleName(tgtName)) } delete(rb.loadedNotChecksummed, data.CanonicalRootRole) @@ -367,7 +387,7 @@ func (rb *repoBuilder) GenerateTimestamp(prev *data.SignedTimestamp) ([]byte, in // SignTimestamp always serializes the loaded snapshot and signs in the data, so we must always // have the snapshot loaded first - if err := rb.checkPrereqsLoaded([]string{data.CanonicalRootRole, data.CanonicalSnapshotRole}); err != nil { + if err := rb.checkPrereqsLoaded([]data.RoleName{data.CanonicalRootRole, data.CanonicalSnapshotRole}); err != nil { return nil, 0, err } @@ -408,10 +428,10 @@ func (rb *repoBuilder) GenerateTimestamp(prev *data.SignedTimestamp) ([]byte, in } // loadRoot loads a root if one has not been loaded -func (rb *repoBuilder) loadRoot(content []byte, minVersion int, allowExpired bool) error { +func (rb *repoBuilder) loadRoot(content []byte, minVersion int, allowExpired, skipChecksum bool) error { roleName := data.CanonicalRootRole - signedObj, err := rb.bytesToSigned(content, data.CanonicalRootRole) + signedObj, err := rb.bytesToSigned(content, data.CanonicalRootRole, skipChecksum) if err != nil { return err } @@ -511,7 +531,7 @@ func (rb *repoBuilder) loadSnapshot(content []byte, minVersion int, allowExpired // this snapshot to bootstrap the next builder if needed - and we don't need to do // the 2-value assignment since we've already validated the signedSnapshot, which MUST // have root metadata - rootMeta := signedSnapshot.Signed.Meta[data.CanonicalRootRole] + rootMeta := signedSnapshot.Signed.Meta[data.CanonicalRootRole.String()] rb.nextRootChecksum = &rootMeta if err := rb.validateChecksumsFromSnapshot(signedSnapshot); err != nil { @@ -555,14 +575,14 @@ func (rb *repoBuilder) loadTargets(content []byte, minVersion int, allowExpired return nil } -func (rb *repoBuilder) loadDelegation(roleName string, content []byte, minVersion int, allowExpired bool) error { +func (rb *repoBuilder) loadDelegation(roleName data.RoleName, content []byte, minVersion int, allowExpired bool) error { delegationRole, err := rb.repo.GetDelegationRole(roleName) if err != nil { return err } // bytesToSigned checks checksum - signedObj, err := rb.bytesToSigned(content, roleName) + signedObj, err := rb.bytesToSigned(content, roleName, false) if err != nil { return err } @@ -599,8 +619,8 @@ func (rb *repoBuilder) validateChecksumsFromTimestamp(ts *data.SignedTimestamp) sn, ok := rb.loadedNotChecksummed[data.CanonicalSnapshotRole] if ok { // by this point, the SignedTimestamp has been validated so it must have a snapshot hash - snMeta := ts.Signed.Meta[data.CanonicalSnapshotRole].Hashes - if err := data.CheckHashes(sn, data.CanonicalSnapshotRole, snMeta); err != nil { + snMeta := ts.Signed.Meta[data.CanonicalSnapshotRole.String()].Hashes + if err := data.CheckHashes(sn, data.CanonicalSnapshotRole.String(), snMeta); err != nil { return err } delete(rb.loadedNotChecksummed, data.CanonicalSnapshotRole) @@ -609,13 +629,13 @@ func (rb *repoBuilder) validateChecksumsFromTimestamp(ts *data.SignedTimestamp) } func (rb *repoBuilder) validateChecksumsFromSnapshot(sn *data.SignedSnapshot) error { - var goodRoles []string + var goodRoles []data.RoleName for roleName, loadedBytes := range rb.loadedNotChecksummed { switch roleName { case data.CanonicalSnapshotRole, data.CanonicalTimestampRole: break default: - if err := data.CheckHashes(loadedBytes, roleName, sn.Signed.Meta[roleName].Hashes); err != nil { + if err := data.CheckHashes(loadedBytes, roleName.String(), sn.Signed.Meta[roleName.String()].Hashes); err != nil { return err } goodRoles = append(goodRoles, roleName) @@ -627,10 +647,10 @@ func (rb *repoBuilder) validateChecksumsFromSnapshot(sn *data.SignedSnapshot) er return nil } -func (rb *repoBuilder) validateChecksumFor(content []byte, roleName string) error { +func (rb *repoBuilder) validateChecksumFor(content []byte, roleName data.RoleName) error { // validate the bootstrap checksum for root, if provided if roleName == data.CanonicalRootRole && rb.bootstrappedRootChecksum != nil { - if err := data.CheckHashes(content, roleName, rb.bootstrappedRootChecksum.Hashes); err != nil { + if err := data.CheckHashes(content, roleName.String(), rb.bootstrappedRootChecksum.Hashes); err != nil { return err } } @@ -639,7 +659,7 @@ func (rb *repoBuilder) validateChecksumFor(content []byte, roleName string) erro // loaded it is validated (to make sure everything in the repo is self-consistent) checksums := rb.getChecksumsFor(roleName) if checksums != nil { // as opposed to empty, in which case hash check should fail - if err := data.CheckHashes(content, roleName, *checksums); err != nil { + if err := data.CheckHashes(content, roleName.String(), *checksums); err != nil { return err } } else if roleName != data.CanonicalTimestampRole { @@ -655,9 +675,11 @@ func (rb *repoBuilder) validateChecksumFor(content []byte, roleName string) erro // Checksums the given bytes, and if they validate, convert to a data.Signed object. // If a checksums are nil (as opposed to empty), adds the bytes to the list of roles that // haven't been checksummed (unless it's a timestamp, which has no checksum reference). -func (rb *repoBuilder) bytesToSigned(content []byte, roleName string) (*data.Signed, error) { - if err := rb.validateChecksumFor(content, roleName); err != nil { - return nil, err +func (rb *repoBuilder) bytesToSigned(content []byte, roleName data.RoleName, skipChecksum bool) (*data.Signed, error) { + if !skipChecksum { + if err := rb.validateChecksumFor(content, roleName); err != nil { + return nil, err + } } // unmarshal to signed @@ -671,7 +693,7 @@ func (rb *repoBuilder) bytesToSigned(content []byte, roleName string) (*data.Sig func (rb *repoBuilder) bytesToSignedAndValidateSigs(role data.BaseRole, content []byte) (*data.Signed, error) { - signedObj, err := rb.bytesToSigned(content, role.Name) + signedObj, err := rb.bytesToSigned(content, role.Name, false) if err != nil { return nil, err } @@ -690,7 +712,7 @@ func (rb *repoBuilder) bytesToSignedAndValidateSigs(role data.BaseRole, content // available. If the checksum reference *is* loaded, then always returns the // Hashes object for the given role - if it doesn't exist, returns an empty Hash // object (against which any checksum validation would fail). -func (rb *repoBuilder) getChecksumsFor(role string) *data.Hashes { +func (rb *repoBuilder) getChecksumsFor(role data.RoleName) *data.Hashes { var hashes data.Hashes switch role { case data.CanonicalTimestampRole: @@ -699,12 +721,12 @@ func (rb *repoBuilder) getChecksumsFor(role string) *data.Hashes { if rb.repo.Timestamp == nil { return nil } - hashes = rb.repo.Timestamp.Signed.Meta[data.CanonicalSnapshotRole].Hashes + hashes = rb.repo.Timestamp.Signed.Meta[data.CanonicalSnapshotRole.String()].Hashes default: if rb.repo.Snapshot == nil { return nil } - hashes = rb.repo.Snapshot.Signed.Meta[role].Hashes + hashes = rb.repo.Snapshot.Signed.Meta[role.String()].Hashes } return &hashes } diff --git a/vendor/github.com/docker/notary/tuf/data/errors.go b/vendor/github.com/theupdateframework/notary/tuf/data/errors.go similarity index 93% rename from vendor/github.com/docker/notary/tuf/data/errors.go rename to vendor/github.com/theupdateframework/notary/tuf/data/errors.go index 5c1397d3e..32dd25066 100644 --- a/vendor/github.com/docker/notary/tuf/data/errors.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/errors.go @@ -4,12 +4,12 @@ import "fmt" // ErrInvalidMetadata is the error to be returned when metadata is invalid type ErrInvalidMetadata struct { - role string + role RoleName msg string } func (e ErrInvalidMetadata) Error() string { - return fmt.Sprintf("%s type metadata invalid: %s", e.role, e.msg) + return fmt.Sprintf("%s type metadata invalid: %s", e.role.String(), e.msg) } // ErrMissingMeta - couldn't find the FileMeta object for the given Role, or diff --git a/vendor/github.com/docker/notary/tuf/data/keys.go b/vendor/github.com/theupdateframework/notary/tuf/data/keys.go similarity index 97% rename from vendor/github.com/docker/notary/tuf/data/keys.go rename to vendor/github.com/theupdateframework/notary/tuf/data/keys.go index 25df598c1..c19ea8fa1 100644 --- a/vendor/github.com/docker/notary/tuf/data/keys.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/keys.go @@ -12,9 +12,9 @@ import ( "io" "math/big" - "github.com/Sirupsen/logrus" "github.com/agl/ed25519" "github.com/docker/go/canonical/json" + "github.com/sirupsen/logrus" ) // PublicKey is the necessary interface for public keys @@ -376,7 +376,7 @@ func NewECDSAPrivateKey(public PublicKey, private []byte) (*ECDSAPrivateKey, err switch public.(type) { case *ECDSAPublicKey, *ECDSAx509PublicKey: default: - return nil, errors.New("Invalid public key type provided to NewECDSAPrivateKey") + return nil, errors.New("invalid public key type provided to NewECDSAPrivateKey") } ecdsaPrivKey, err := x509.ParseECPrivateKey(private) if err != nil { @@ -394,7 +394,7 @@ func NewRSAPrivateKey(public PublicKey, private []byte) (*RSAPrivateKey, error) switch public.(type) { case *RSAPublicKey, *RSAx509PublicKey: default: - return nil, errors.New("Invalid public key type provided to NewRSAPrivateKey") + return nil, errors.New("invalid public key type provided to NewRSAPrivateKey") } rsaPrivKey, err := x509.ParsePKCS1PrivateKey(private) if err != nil { @@ -445,7 +445,7 @@ type ecdsaSig struct { func (k ECDSAPrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { ecdsaPrivKey, ok := k.CryptoSigner().(*ecdsa.PrivateKey) if !ok { - return nil, errors.New("Signer was based on the wrong key type") + return nil, errors.New("signer was based on the wrong key type") } hashed := sha256.Sum256(msg) sigASN1, err := ecdsaPrivKey.Sign(rand, hashed[:], opts) @@ -492,7 +492,7 @@ func (k ED25519PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOp // Sign on an UnknownPrivateKey raises an error because the client does not // know how to sign with this key type. func (k UnknownPrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { - return nil, errors.New("Unknown key type, cannot sign.") + return nil, errors.New("unknown key type, cannot sign") } // SignatureAlgorithm returns the SigAlgorithm for a ECDSAPrivateKey diff --git a/vendor/github.com/docker/notary/tuf/data/roles.go b/vendor/github.com/theupdateframework/notary/tuf/data/roles.go similarity index 89% rename from vendor/github.com/docker/notary/tuf/data/roles.go rename to vendor/github.com/theupdateframework/notary/tuf/data/roles.go index 282377827..1a6541ca3 100644 --- a/vendor/github.com/docker/notary/tuf/data/roles.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/roles.go @@ -6,20 +6,20 @@ import ( "regexp" "strings" - "github.com/Sirupsen/logrus" + "github.com/sirupsen/logrus" ) // Canonical base role names -const ( - CanonicalRootRole = "root" - CanonicalTargetsRole = "targets" - CanonicalSnapshotRole = "snapshot" - CanonicalTimestampRole = "timestamp" +var ( + CanonicalRootRole RoleName = "root" + CanonicalTargetsRole RoleName = "targets" + CanonicalSnapshotRole RoleName = "snapshot" + CanonicalTimestampRole RoleName = "timestamp" ) // BaseRoles is an easy to iterate list of the top level // roles. -var BaseRoles = []string{ +var BaseRoles = []RoleName{ CanonicalRootRole, CanonicalTargetsRole, CanonicalSnapshotRole, @@ -31,7 +31,7 @@ var delegationRegexp = regexp.MustCompile("^[-a-z0-9_/]+$") // ErrNoSuchRole indicates the roles doesn't exist type ErrNoSuchRole struct { - Role string + Role RoleName } func (e ErrNoSuchRole) Error() string { @@ -42,7 +42,7 @@ func (e ErrNoSuchRole) Error() string { // something like a role for which sone of the public keys were // not found in the TUF repo. type ErrInvalidRole struct { - Role string + Role RoleName Reason string } @@ -56,7 +56,7 @@ func (e ErrInvalidRole) Error() string { // ValidRole only determines the name is semantically // correct. For target delegated roles, it does NOT check // the the appropriate parent roles exist. -func ValidRole(name string) bool { +func ValidRole(name RoleName) bool { if IsDelegation(name) { return true } @@ -70,24 +70,25 @@ func ValidRole(name string) bool { } // IsDelegation checks if the role is a delegation or a root role -func IsDelegation(role string) bool { +func IsDelegation(role RoleName) bool { + strRole := role.String() targetsBase := CanonicalTargetsRole + "/" - whitelistedChars := delegationRegexp.MatchString(role) + whitelistedChars := delegationRegexp.MatchString(strRole) // Limit size of full role string to 255 chars for db column size limit correctLength := len(role) < 256 // Removes ., .., extra slashes, and trailing slash - isClean := path.Clean(role) == role - return strings.HasPrefix(role, targetsBase) && + isClean := path.Clean(strRole) == strRole + return strings.HasPrefix(strRole, targetsBase.String()) && whitelistedChars && correctLength && isClean } // IsBaseRole checks if the role is a base role -func IsBaseRole(role string) bool { +func IsBaseRole(role RoleName) bool { for _, baseRole := range BaseRoles { if role == baseRole { return true @@ -100,11 +101,11 @@ func IsBaseRole(role string) bool { // path, i.e. targets/*, targets/foo/*. // The wildcard may only appear as the final part of the delegation and must // be a whole segment, i.e. targets/foo* is not a valid wildcard delegation. -func IsWildDelegation(role string) bool { - if path.Clean(role) != role { +func IsWildDelegation(role RoleName) bool { + if path.Clean(role.String()) != role.String() { return false } - base := path.Dir(role) + base := role.Parent() if !(IsDelegation(base) || base == CanonicalTargetsRole) { return false } @@ -114,12 +115,12 @@ func IsWildDelegation(role string) bool { // BaseRole is an internal representation of a root/targets/snapshot/timestamp role, with its public keys included type BaseRole struct { Keys map[string]PublicKey - Name string + Name RoleName Threshold int } // NewBaseRole creates a new BaseRole object with the provided parameters -func NewBaseRole(name string, threshold int, keys ...PublicKey) BaseRole { +func NewBaseRole(name RoleName, threshold int, keys ...PublicKey) BaseRole { r := BaseRole{ Name: name, Threshold: threshold, @@ -199,7 +200,7 @@ func (d DelegationRole) Restrict(child DelegationRole) (DelegationRole, error) { // determined by delegation name. // Ex: targets/a is a direct parent of targets/a/b, but targets/a is not a direct parent of targets/a/b/c func (d DelegationRole) IsParentOf(child DelegationRole) bool { - return path.Dir(child.Name) == d.Name + return path.Dir(child.Name.String()) == d.Name.String() } // CheckPaths checks if a given path is valid for the role @@ -251,12 +252,12 @@ type RootRole struct { // Eventually should only be used for immediately before and after serialization/deserialization type Role struct { RootRole - Name string `json:"name"` + Name RoleName `json:"name"` Paths []string `json:"paths,omitempty"` } // NewRole creates a new Role object from the given parameters -func NewRole(name string, threshold int, keyIDs, paths []string) (*Role, error) { +func NewRole(name RoleName, threshold int, keyIDs, paths []string) (*Role, error) { if IsDelegation(name) { if len(paths) == 0 { logrus.Debugf("role %s with no Paths will never be able to publish content until one or more are added", name) diff --git a/vendor/github.com/docker/notary/tuf/data/root.go b/vendor/github.com/theupdateframework/notary/tuf/data/root.go similarity index 90% rename from vendor/github.com/docker/notary/tuf/data/root.go rename to vendor/github.com/theupdateframework/notary/tuf/data/root.go index cfadbdbfb..9420e87ce 100644 --- a/vendor/github.com/docker/notary/tuf/data/root.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/root.go @@ -16,9 +16,9 @@ type SignedRoot struct { // Root is the Signed component of a root.json type Root struct { SignedCommon - Keys Keys `json:"keys"` - Roles map[string]*RootRole `json:"roles"` - ConsistentSnapshot bool `json:"consistent_snapshot"` + Keys Keys `json:"keys"` + Roles map[RoleName]*RootRole `json:"roles"` + ConsistentSnapshot bool `json:"consistent_snapshot"` } // isValidRootStructure returns an error, or nil, depending on whether the content of the struct @@ -51,7 +51,7 @@ func isValidRootStructure(r Root) error { return nil } -func isValidRootRoleStructure(metaContainingRole, rootRoleName string, r RootRole, validKeys Keys) error { +func isValidRootRoleStructure(metaContainingRole, rootRoleName RoleName, r RootRole, validKeys Keys) error { if r.Threshold < 1 { return ErrInvalidMetadata{ role: metaContainingRole, @@ -70,7 +70,7 @@ func isValidRootRoleStructure(metaContainingRole, rootRoleName string, r RootRol } // NewRoot initializes a new SignedRoot with a set of keys, roles, and the consistent flag -func NewRoot(keys map[string]PublicKey, roles map[string]*RootRole, consistent bool) (*SignedRoot, error) { +func NewRoot(keys map[string]PublicKey, roles map[RoleName]*RootRole, consistent bool) (*SignedRoot, error) { signedRoot := &SignedRoot{ Signatures: make([]Signature, 0), Signed: Root{ @@ -91,7 +91,7 @@ func NewRoot(keys map[string]PublicKey, roles map[string]*RootRole, consistent b // BuildBaseRole returns a copy of a BaseRole using the information in this SignedRoot for the specified role name. // Will error for invalid role name or key metadata within this SignedRoot -func (r SignedRoot) BuildBaseRole(roleName string) (BaseRole, error) { +func (r SignedRoot) BuildBaseRole(roleName RoleName) (BaseRole, error) { roleData, ok := r.Signed.Roles[roleName] if !ok { return BaseRole{}, ErrInvalidRole{Role: roleName, Reason: "role not found in root file"} diff --git a/vendor/github.com/docker/notary/tuf/data/serializer.go b/vendor/github.com/theupdateframework/notary/tuf/data/serializer.go similarity index 100% rename from vendor/github.com/docker/notary/tuf/data/serializer.go rename to vendor/github.com/theupdateframework/notary/tuf/data/serializer.go diff --git a/vendor/github.com/docker/notary/tuf/data/snapshot.go b/vendor/github.com/theupdateframework/notary/tuf/data/snapshot.go similarity index 81% rename from vendor/github.com/docker/notary/tuf/data/snapshot.go rename to vendor/github.com/theupdateframework/notary/tuf/data/snapshot.go index 1d1178e4a..2a07105ba 100644 --- a/vendor/github.com/docker/notary/tuf/data/snapshot.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/snapshot.go @@ -4,9 +4,9 @@ import ( "bytes" "fmt" - "github.com/Sirupsen/logrus" "github.com/docker/go/canonical/json" - "github.com/docker/notary" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" ) // SignedSnapshot is a fully unpacked snapshot.json @@ -37,22 +37,22 @@ func IsValidSnapshotStructure(s Snapshot) error { role: CanonicalSnapshotRole, msg: "version cannot be less than one"} } - for _, role := range []string{CanonicalRootRole, CanonicalTargetsRole} { + for _, file := range []RoleName{CanonicalRootRole, CanonicalTargetsRole} { // Meta is a map of FileMeta, so if the role isn't in the map it returns // an empty FileMeta, which has an empty map, and you can check on keys // from an empty map. // // For now sha256 is required and sha512 is not. - if _, ok := s.Meta[role].Hashes[notary.SHA256]; !ok { + if _, ok := s.Meta[file.String()].Hashes[notary.SHA256]; !ok { return ErrInvalidMetadata{ role: CanonicalSnapshotRole, - msg: fmt.Sprintf("missing %s sha256 checksum information", role), + msg: fmt.Sprintf("missing %s sha256 checksum information", file.String()), } } - if err := CheckValidHashStructures(s.Meta[role].Hashes); err != nil { + if err := CheckValidHashStructures(s.Meta[file.String()].Hashes); err != nil { return ErrInvalidMetadata{ role: CanonicalSnapshotRole, - msg: fmt.Sprintf("invalid %s checksum information, %v", role, err), + msg: fmt.Sprintf("invalid %s checksum information, %v", file.String(), err), } } } @@ -90,8 +90,8 @@ func NewSnapshot(root *Signed, targets *Signed) (*SignedSnapshot, error) { Expires: DefaultExpires(CanonicalSnapshotRole), }, Meta: Files{ - CanonicalRootRole: rootMeta, - CanonicalTargetsRole: targetsMeta, + CanonicalRootRole.String(): rootMeta, + CanonicalTargetsRole.String(): targetsMeta, }, }, }, nil @@ -117,27 +117,27 @@ func (sp *SignedSnapshot) ToSigned() (*Signed, error) { } // AddMeta updates a role in the snapshot with new meta -func (sp *SignedSnapshot) AddMeta(role string, meta FileMeta) { - sp.Signed.Meta[role] = meta +func (sp *SignedSnapshot) AddMeta(role RoleName, meta FileMeta) { + sp.Signed.Meta[role.String()] = meta sp.Dirty = true } // GetMeta gets the metadata for a particular role, returning an error if it's // not found -func (sp *SignedSnapshot) GetMeta(role string) (*FileMeta, error) { - if meta, ok := sp.Signed.Meta[role]; ok { +func (sp *SignedSnapshot) GetMeta(role RoleName) (*FileMeta, error) { + if meta, ok := sp.Signed.Meta[role.String()]; ok { if _, ok := meta.Hashes["sha256"]; ok { return &meta, nil } } - return nil, ErrMissingMeta{Role: role} + return nil, ErrMissingMeta{Role: role.String()} } // DeleteMeta removes a role from the snapshot. If the role doesn't // exist in the snapshot, it's a noop. -func (sp *SignedSnapshot) DeleteMeta(role string) { - if _, ok := sp.Signed.Meta[role]; ok { - delete(sp.Signed.Meta, role) +func (sp *SignedSnapshot) DeleteMeta(role RoleName) { + if _, ok := sp.Signed.Meta[role.String()]; ok { + delete(sp.Signed.Meta, role.String()) sp.Dirty = true } } diff --git a/vendor/github.com/docker/notary/tuf/data/targets.go b/vendor/github.com/theupdateframework/notary/tuf/data/targets.go similarity index 94% rename from vendor/github.com/docker/notary/tuf/data/targets.go rename to vendor/github.com/theupdateframework/notary/tuf/data/targets.go index 04cca121f..f01eb5e6a 100644 --- a/vendor/github.com/docker/notary/tuf/data/targets.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/targets.go @@ -26,7 +26,7 @@ type Targets struct { // isValidTargetsStructure returns an error, or nil, depending on whether the content of the struct // is valid for targets metadata. This does not check signatures or expiry, just that // the metadata content is valid. -func isValidTargetsStructure(t Targets, roleName string) error { +func isValidTargetsStructure(t Targets, roleName RoleName) error { if roleName != CanonicalTargetsRole && !IsDelegation(roleName) { return ErrInvalidRole{Role: roleName} } @@ -43,7 +43,7 @@ func isValidTargetsStructure(t Targets, roleName string) error { } for _, roleObj := range t.Delegations.Roles { - if !IsDelegation(roleObj.Name) || path.Dir(roleObj.Name) != roleName { + if !IsDelegation(roleObj.Name) || path.Dir(roleObj.Name.String()) != roleName.String() { return ErrInvalidMetadata{ role: roleName, msg: fmt.Sprintf("delegation role %s invalid", roleObj.Name)} } @@ -99,7 +99,7 @@ func (t SignedTargets) GetValidDelegations(parent DelegationRole) []DelegationRo // BuildDelegationRole returns a copy of a DelegationRole using the information in this SignedTargets for the specified role name. // Will error for invalid role name or key metadata within this SignedTargets. Path data is not validated. -func (t *SignedTargets) BuildDelegationRole(roleName string) (DelegationRole, error) { +func (t *SignedTargets) BuildDelegationRole(roleName RoleName) (DelegationRole, error) { for _, role := range t.Signed.Delegations.Roles { if role.Name == roleName { pubKeys := make(map[string]PublicKey) @@ -184,7 +184,7 @@ func (t *SignedTargets) MarshalJSON() ([]byte, error) { // TargetsFromSigned fully unpacks a Signed object into a SignedTargets, given // a role name (so it can validate the SignedTargets object) -func TargetsFromSigned(s *Signed, roleName string) (*SignedTargets, error) { +func TargetsFromSigned(s *Signed, roleName RoleName) (*SignedTargets, error) { t := Targets{} if err := defaultSerializer.Unmarshal(*s.Signed, &t); err != nil { return nil, err diff --git a/vendor/github.com/docker/notary/tuf/data/timestamp.go b/vendor/github.com/theupdateframework/notary/tuf/data/timestamp.go similarity index 91% rename from vendor/github.com/docker/notary/tuf/data/timestamp.go rename to vendor/github.com/theupdateframework/notary/tuf/data/timestamp.go index 1a6424156..baf4016ee 100644 --- a/vendor/github.com/docker/notary/tuf/data/timestamp.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/timestamp.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/docker/go/canonical/json" - "github.com/docker/notary" + "github.com/theupdateframework/notary" ) // SignedTimestamp is a fully unpacked timestamp.json @@ -41,11 +41,11 @@ func IsValidTimestampStructure(t Timestamp) error { // from an empty map. // // For now sha256 is required and sha512 is not. - if _, ok := t.Meta[CanonicalSnapshotRole].Hashes[notary.SHA256]; !ok { + if _, ok := t.Meta[CanonicalSnapshotRole.String()].Hashes[notary.SHA256]; !ok { return ErrInvalidMetadata{ role: CanonicalTimestampRole, msg: "missing snapshot sha256 checksum information"} } - if err := CheckValidHashStructures(t.Meta[CanonicalSnapshotRole].Hashes); err != nil { + if err := CheckValidHashStructures(t.Meta[CanonicalSnapshotRole.String()].Hashes); err != nil { return ErrInvalidMetadata{ role: CanonicalTimestampRole, msg: fmt.Sprintf("invalid snapshot checksum information, %v", err)} } @@ -72,7 +72,7 @@ func NewTimestamp(snapshot *Signed) (*SignedTimestamp, error) { Expires: DefaultExpires(CanonicalTimestampRole), }, Meta: Files{ - CanonicalSnapshotRole: snapshotMeta, + CanonicalSnapshotRole.String(): snapshotMeta, }, }, }, nil @@ -101,9 +101,9 @@ func (ts *SignedTimestamp) ToSigned() (*Signed, error) { // GetSnapshot gets the expected snapshot metadata hashes in the timestamp metadata, // or nil if it doesn't exist func (ts *SignedTimestamp) GetSnapshot() (*FileMeta, error) { - snapshotExpected, ok := ts.Signed.Meta[CanonicalSnapshotRole] + snapshotExpected, ok := ts.Signed.Meta[CanonicalSnapshotRole.String()] if !ok { - return nil, ErrMissingMeta{Role: CanonicalSnapshotRole} + return nil, ErrMissingMeta{Role: CanonicalSnapshotRole.String()} } return &snapshotExpected, nil } diff --git a/vendor/github.com/docker/notary/tuf/data/types.go b/vendor/github.com/theupdateframework/notary/tuf/data/types.go similarity index 73% rename from vendor/github.com/docker/notary/tuf/data/types.go rename to vendor/github.com/theupdateframework/notary/tuf/data/types.go index 1f46a1023..6f9c11201 100644 --- a/vendor/github.com/docker/notary/tuf/data/types.go +++ b/vendor/github.com/theupdateframework/notary/tuf/data/types.go @@ -1,6 +1,7 @@ package data import ( + "bytes" "crypto/sha256" "crypto/sha512" "crypto/subtle" @@ -9,14 +10,63 @@ import ( "hash" "io" "io/ioutil" + "path" "strings" "time" - "github.com/Sirupsen/logrus" "github.com/docker/go/canonical/json" - "github.com/docker/notary" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" ) +// GUN is a Globally Unique Name. It is used to identify trust collections. +// An example usage of this is for container image repositories. +// For example: myregistry.io/myuser/myimage +type GUN string + +func (g GUN) String() string { + return string(g) +} + +// RoleName type for specifying role +type RoleName string + +func (r RoleName) String() string { + return string(r) +} + +// Parent provides the parent path role from the provided child role +func (r RoleName) Parent() RoleName { + return RoleName(path.Dir(r.String())) +} + +// MetadataRoleMapToStringMap generates a map string of bytes from a map RoleName of bytes +func MetadataRoleMapToStringMap(roles map[RoleName][]byte) map[string][]byte { + metadata := make(map[string][]byte) + for k, v := range roles { + metadata[k.String()] = v + } + return metadata +} + +// NewRoleList generates an array of RoleName objects from a slice of strings +func NewRoleList(roles []string) []RoleName { + var roleNames []RoleName + for _, role := range roles { + roleNames = append(roleNames, RoleName(role)) + } + return roleNames +} + +// RolesListToStringList generates an array of string objects from a slice of roles +func RolesListToStringList(roles []RoleName) []string { + var roleNames []string + for _, role := range roles { + roleNames = append(roleNames, role.String()) + } + return roleNames +} + // SigAlgorithm for types of signatures type SigAlgorithm string @@ -26,6 +76,15 @@ func (k SigAlgorithm) String() string { const defaultHashAlgorithm = "sha256" +// NotaryDefaultExpiries is the construct used to configure the default expiry times of +// the various role files. +var NotaryDefaultExpiries = map[RoleName]time.Duration{ + CanonicalRootRole: notary.NotaryRootExpiry, + CanonicalTargetsRole: notary.NotaryTargetsExpiry, + CanonicalSnapshotRole: notary.NotarySnapshotExpiry, + CanonicalTimestampRole: notary.NotaryTimestampExpiry, +} + // Signature types const ( EDDSASignature SigAlgorithm = "eddsa" @@ -45,23 +104,15 @@ const ( ) // TUFTypes is the set of metadata types -var TUFTypes = map[string]string{ +var TUFTypes = map[RoleName]string{ CanonicalRootRole: "Root", CanonicalTargetsRole: "Targets", CanonicalSnapshotRole: "Snapshot", CanonicalTimestampRole: "Timestamp", } -// SetTUFTypes allows one to override some or all of the default -// type names in TUF. -func SetTUFTypes(ts map[string]string) { - for k, v := range ts { - TUFTypes[k] = v - } -} - // ValidTUFType checks if the given type is valid for the role -func ValidTUFType(typ, role string) bool { +func ValidTUFType(typ string, role RoleName) bool { if ValidRole(role) { // All targets delegation roles must have // the valid type is for targets. @@ -70,7 +121,7 @@ func ValidTUFType(typ, role string) bool { // a type return false } - if strings.HasPrefix(role, CanonicalTargetsRole+"/") { + if strings.HasPrefix(role.String(), CanonicalTargetsRole.String()+"/") { role = CanonicalTargetsRole } } @@ -133,6 +184,34 @@ type FileMeta struct { Custom *json.RawMessage `json:"custom,omitempty"` } +// Equals returns true if the other FileMeta object is equivalent to this one +func (f FileMeta) Equals(o FileMeta) bool { + if o.Length != f.Length || len(f.Hashes) != len(f.Hashes) { + return false + } + if f.Custom == nil && o.Custom != nil || f.Custom != nil && o.Custom == nil { + return false + } + // we don't care if these are valid hashes, just that they are equal + for key, val := range f.Hashes { + if !bytes.Equal(val, o.Hashes[key]) { + return false + } + } + if f.Custom == nil && o.Custom == nil { + return true + } + fBytes, err := f.Custom.MarshalJSON() + if err != nil { + return false + } + oBytes, err := o.Custom.MarshalJSON() + if err != nil { + return false + } + return bytes.Equal(fBytes, oBytes) +} + // CheckHashes verifies all the checksums specified by the "hashes" of the payload. func CheckHashes(payload []byte, name string, hashes Hashes) error { cnt := 0 @@ -269,7 +348,7 @@ func NewDelegations() *Delegations { } // These values are recommended TUF expiry times. -var defaultExpiryTimes = map[string]time.Duration{ +var defaultExpiryTimes = map[RoleName]time.Duration{ CanonicalRootRole: notary.Year, CanonicalTargetsRole: 90 * notary.Day, CanonicalSnapshotRole: 7 * notary.Day, @@ -277,10 +356,10 @@ var defaultExpiryTimes = map[string]time.Duration{ } // SetDefaultExpiryTimes allows one to change the default expiries. -func SetDefaultExpiryTimes(times map[string]time.Duration) { +func SetDefaultExpiryTimes(times map[RoleName]time.Duration) { for key, value := range times { if _, ok := defaultExpiryTimes[key]; !ok { - logrus.Errorf("Attempted to set default expiry for an unknown role: %s", key) + logrus.Errorf("Attempted to set default expiry for an unknown role: %s", key.String()) continue } defaultExpiryTimes[key] = value @@ -288,7 +367,7 @@ func SetDefaultExpiryTimes(times map[string]time.Duration) { } // DefaultExpires gets the default expiry time for the given role -func DefaultExpires(role string) time.Time { +func DefaultExpires(role RoleName) time.Time { if d, ok := defaultExpiryTimes[role]; ok { return time.Now().Add(d) } diff --git a/vendor/github.com/docker/notary/tuf/signed/ed25519.go b/vendor/github.com/theupdateframework/notary/tuf/signed/ed25519.go similarity index 79% rename from vendor/github.com/docker/notary/tuf/signed/ed25519.go rename to vendor/github.com/theupdateframework/notary/tuf/signed/ed25519.go index 7a70739e4..b526085a4 100644 --- a/vendor/github.com/docker/notary/tuf/signed/ed25519.go +++ b/vendor/github.com/theupdateframework/notary/tuf/signed/ed25519.go @@ -4,13 +4,13 @@ import ( "crypto/rand" "errors" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "github.com/theupdateframework/notary/trustmanager" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) type edCryptoKey struct { - role string + role data.RoleName privKey data.PrivateKey } @@ -28,13 +28,13 @@ func NewEd25519() *Ed25519 { } // AddKey allows you to add a private key -func (e *Ed25519) AddKey(role, gun string, k data.PrivateKey) error { +func (e *Ed25519) AddKey(role data.RoleName, gun data.GUN, k data.PrivateKey) error { e.addKey(role, k) return nil } // addKey allows you to add a private key -func (e *Ed25519) addKey(role string, k data.PrivateKey) { +func (e *Ed25519) addKey(role data.RoleName, k data.PrivateKey) { e.keys[k.ID()] = edCryptoKey{ role: role, privKey: k, @@ -48,7 +48,7 @@ func (e *Ed25519) RemoveKey(keyID string) error { } // ListKeys returns the list of keys IDs for the role -func (e *Ed25519) ListKeys(role string) []string { +func (e *Ed25519) ListKeys(role data.RoleName) []string { keyIDs := make([]string, 0, len(e.keys)) for id, edCryptoKey := range e.keys { if edCryptoKey.role == role { @@ -59,8 +59,8 @@ func (e *Ed25519) ListKeys(role string) []string { } // ListAllKeys returns the map of keys IDs to role -func (e *Ed25519) ListAllKeys() map[string]string { - keys := make(map[string]string) +func (e *Ed25519) ListAllKeys() map[string]data.RoleName { + keys := make(map[string]data.RoleName) for id, edKey := range e.keys { keys[id] = edKey.role } @@ -68,7 +68,7 @@ func (e *Ed25519) ListAllKeys() map[string]string { } // Create generates a new key and returns the public part -func (e *Ed25519) Create(role, gun, algorithm string) (data.PublicKey, error) { +func (e *Ed25519) Create(role data.RoleName, gun data.GUN, algorithm string) (data.PublicKey, error) { if algorithm != data.ED25519Key { return nil, errors.New("only ED25519 supported by this cryptoservice") } @@ -103,7 +103,7 @@ func (e *Ed25519) GetKey(keyID string) data.PublicKey { } // GetPrivateKey returns a single private key and role if present, based on the ID -func (e *Ed25519) GetPrivateKey(keyID string) (data.PrivateKey, string, error) { +func (e *Ed25519) GetPrivateKey(keyID string) (data.PrivateKey, data.RoleName, error) { if k, ok := e.keys[keyID]; ok { return k.privKey, k.role, nil } diff --git a/vendor/github.com/docker/notary/tuf/signed/errors.go b/vendor/github.com/theupdateframework/notary/tuf/signed/errors.go similarity index 94% rename from vendor/github.com/docker/notary/tuf/signed/errors.go rename to vendor/github.com/theupdateframework/notary/tuf/signed/errors.go index 2a633c864..29ec40de2 100644 --- a/vendor/github.com/docker/notary/tuf/signed/errors.go +++ b/vendor/github.com/theupdateframework/notary/tuf/signed/errors.go @@ -3,6 +3,8 @@ package signed import ( "fmt" "strings" + + "github.com/theupdateframework/notary/tuf/data" ) // ErrInsufficientSignatures - can not create enough signatures on a piece of @@ -29,12 +31,12 @@ func (e ErrInsufficientSignatures) Error() string { // ErrExpired indicates a piece of metadata has expired type ErrExpired struct { - Role string + Role data.RoleName Expired string } func (e ErrExpired) Error() string { - return fmt.Sprintf("%s expired at %v", e.Role, e.Expired) + return fmt.Sprintf("%s expired at %v", e.Role.String(), e.Expired) } // ErrLowVersion indicates the piece of metadata has a version number lower than diff --git a/vendor/github.com/docker/notary/tuf/signed/interface.go b/vendor/github.com/theupdateframework/notary/tuf/signed/interface.go similarity index 80% rename from vendor/github.com/docker/notary/tuf/signed/interface.go rename to vendor/github.com/theupdateframework/notary/tuf/signed/interface.go index 862b23b8f..14f3a33fa 100644 --- a/vendor/github.com/docker/notary/tuf/signed/interface.go +++ b/vendor/github.com/theupdateframework/notary/tuf/signed/interface.go @@ -1,8 +1,6 @@ package signed -import ( - "github.com/docker/notary/tuf/data" -) +import "github.com/theupdateframework/notary/tuf/data" // KeyService provides management of keys locally. It will never // accept or provide private keys. Communication between the KeyService @@ -10,17 +8,17 @@ import ( type KeyService interface { // Create issues a new key pair and is responsible for loading // the private key into the appropriate signing service. - Create(role, gun, algorithm string) (data.PublicKey, error) + Create(role data.RoleName, gun data.GUN, algorithm string) (data.PublicKey, error) // AddKey adds a private key to the specified role and gun - AddKey(role, gun string, key data.PrivateKey) error + AddKey(role data.RoleName, gun data.GUN, key data.PrivateKey) error // GetKey retrieves the public key if present, otherwise it returns nil GetKey(keyID string) data.PublicKey // GetPrivateKey retrieves the private key and role if present and retrievable, // otherwise it returns nil and an error - GetPrivateKey(keyID string) (data.PrivateKey, string, error) + GetPrivateKey(keyID string) (data.PrivateKey, data.RoleName, error) // RemoveKey deletes the specified key, and returns an error only if the key // removal fails. If the key doesn't exist, no error should be returned. @@ -28,11 +26,11 @@ type KeyService interface { // ListKeys returns a list of key IDs for the role, or an empty list or // nil if there are no keys. - ListKeys(role string) []string + ListKeys(role data.RoleName) []string // ListAllKeys returns a map of all available signing key IDs to role, or // an empty map or nil if there are no keys. - ListAllKeys() map[string]string + ListAllKeys() map[string]data.RoleName } // CryptoService is deprecated and all instances of its use should be diff --git a/vendor/github.com/docker/notary/tuf/signed/sign.go b/vendor/github.com/theupdateframework/notary/tuf/signed/sign.go similarity index 95% rename from vendor/github.com/docker/notary/tuf/signed/sign.go rename to vendor/github.com/theupdateframework/notary/tuf/signed/sign.go index 31abb1204..b3e329ce4 100644 --- a/vendor/github.com/docker/notary/tuf/signed/sign.go +++ b/vendor/github.com/theupdateframework/notary/tuf/signed/sign.go @@ -14,10 +14,10 @@ package signed import ( "crypto/rand" - "github.com/Sirupsen/logrus" - "github.com/docker/notary/trustmanager" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/utils" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary/trustmanager" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // Sign takes a data.Signed and a cryptoservice containing private keys, diff --git a/vendor/github.com/docker/notary/tuf/signed/verifiers.go b/vendor/github.com/theupdateframework/notary/tuf/signed/verifiers.go similarity index 92% rename from vendor/github.com/docker/notary/tuf/signed/verifiers.go rename to vendor/github.com/theupdateframework/notary/tuf/signed/verifiers.go index 792186366..d5ce7f862 100644 --- a/vendor/github.com/docker/notary/tuf/signed/verifiers.go +++ b/vendor/github.com/theupdateframework/notary/tuf/signed/verifiers.go @@ -9,11 +9,10 @@ import ( "encoding/pem" "fmt" "math/big" - "reflect" - "github.com/Sirupsen/logrus" "github.com/agl/ed25519" - "github.com/docker/notary/tuf/data" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary/tuf/data" ) const ( @@ -32,24 +31,6 @@ var Verifiers = map[data.SigAlgorithm]Verifier{ data.EDDSASignature: Ed25519Verifier{}, } -// RegisterVerifier provides a convenience function for init() functions -// to register additional verifiers or replace existing ones. -func RegisterVerifier(algorithm data.SigAlgorithm, v Verifier) { - curr, ok := Verifiers[algorithm] - if ok { - typOld := reflect.TypeOf(curr) - typNew := reflect.TypeOf(v) - logrus.Debugf( - "replacing already loaded verifier %s:%s with %s:%s", - typOld.PkgPath(), typOld.Name(), - typNew.PkgPath(), typNew.Name(), - ) - } else { - logrus.Debug("adding verifier for: ", algorithm) - } - Verifiers[algorithm] = v -} - // Ed25519Verifier used to verify Ed25519 signatures type Ed25519Verifier struct{} diff --git a/vendor/github.com/docker/notary/tuf/signed/verify.go b/vendor/github.com/theupdateframework/notary/tuf/signed/verify.go similarity index 77% rename from vendor/github.com/docker/notary/tuf/signed/verify.go rename to vendor/github.com/theupdateframework/notary/tuf/signed/verify.go index 5858766a4..5ae2da485 100644 --- a/vendor/github.com/docker/notary/tuf/signed/verify.go +++ b/vendor/github.com/theupdateframework/notary/tuf/signed/verify.go @@ -6,18 +6,16 @@ import ( "strings" "time" - "github.com/Sirupsen/logrus" "github.com/docker/go/canonical/json" - "github.com/docker/notary/tuf/data" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/utils" ) // Various basic signing errors var ( - ErrMissingKey = errors.New("tuf: missing key") ErrNoSignatures = errors.New("tuf: data has no signatures") ErrInvalid = errors.New("tuf: signature verification failed") - ErrWrongMethod = errors.New("tuf: invalid signature type") - ErrUnknownRole = errors.New("tuf: unknown role") ErrWrongType = errors.New("tuf: meta file has wrong type") ) @@ -27,7 +25,7 @@ func IsExpired(t time.Time) bool { } // VerifyExpiry returns ErrExpired if the metadata is expired -func VerifyExpiry(s *data.SignedCommon, role string) error { +func VerifyExpiry(s *data.SignedCommon, role data.RoleName) error { if IsExpired(s.Expires) { logrus.Errorf("Metadata for %s expired", role) return ErrExpired{Role: role, Expired: s.Expires.Format("Mon Jan 2 15:04:05 MST 2006")} @@ -101,12 +99,25 @@ func VerifySignature(msg []byte, sig *data.Signature, pk data.PublicKey) error { method := sig.Method verifier, ok := Verifiers[method] if !ok { - return fmt.Errorf("signing method is not supported: %s\n", sig.Method) + return fmt.Errorf("signing method is not supported: %s", sig.Method) } if err := verifier.Verify(pk, sig.Signature, msg); err != nil { - return fmt.Errorf("signature was invalid\n") + return fmt.Errorf("signature was invalid") } sig.IsValid = true return nil } + +// VerifyPublicKeyMatchesPrivateKey checks if the private key and the public keys forms valid key pairs. +// Supports both x509 certificate PublicKeys and non-certificate PublicKeys +func VerifyPublicKeyMatchesPrivateKey(privKey data.PrivateKey, pubKey data.PublicKey) error { + pubKeyID, err := utils.CanonicalKeyID(pubKey) + if err != nil { + return fmt.Errorf("could not verify key pair: %v", err) + } + if privKey == nil || pubKeyID != privKey.ID() { + return fmt.Errorf("private key is nil or does not match public key") + } + return nil +} diff --git a/vendor/github.com/docker/notary/tuf/tuf.go b/vendor/github.com/theupdateframework/notary/tuf/tuf.go similarity index 82% rename from vendor/github.com/docker/notary/tuf/tuf.go rename to vendor/github.com/theupdateframework/notary/tuf/tuf.go index 91f3fa514..74f6ceb59 100644 --- a/vendor/github.com/docker/notary/tuf/tuf.go +++ b/vendor/github.com/theupdateframework/notary/tuf/tuf.go @@ -5,17 +5,14 @@ import ( "bytes" "encoding/json" "fmt" - "path" - "sort" - "strconv" "strings" "time" - "github.com/Sirupsen/logrus" - "github.com/docker/notary" - "github.com/docker/notary/tuf/data" - "github.com/docker/notary/tuf/signed" - "github.com/docker/notary/tuf/utils" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/signed" + "github.com/theupdateframework/notary/tuf/utils" ) // ErrSigVerifyFail - signature verification failed @@ -43,7 +40,7 @@ func (e ErrLocalRootExpired) Error() string { // the repo. This means specifically that the relevant JSON file has not // been loaded. type ErrNotLoaded struct { - Role string + Role data.RoleName } func (err ErrNotLoaded) Error() string { @@ -60,7 +57,7 @@ type StopWalk struct{} // the Repo instance. type Repo struct { Root *data.SignedRoot - Targets map[string]*data.SignedTargets + Targets map[data.RoleName]*data.SignedTargets Snapshot *data.SignedSnapshot Timestamp *data.SignedTimestamp cryptoService signed.CryptoService @@ -78,13 +75,13 @@ type Repo struct { // can be nil. func NewRepo(cryptoService signed.CryptoService) *Repo { return &Repo{ - Targets: make(map[string]*data.SignedTargets), + Targets: make(map[data.RoleName]*data.SignedTargets), cryptoService: cryptoService, } } // AddBaseKeys is used to add keys to the role in root.json -func (tr *Repo) AddBaseKeys(role string, keys ...data.PublicKey) error { +func (tr *Repo) AddBaseKeys(role data.RoleName, keys ...data.PublicKey) error { if tr.Root == nil { return ErrNotLoaded{Role: data.CanonicalRootRole} } @@ -117,7 +114,7 @@ func (tr *Repo) AddBaseKeys(role string, keys ...data.PublicKey) error { } // ReplaceBaseKeys is used to replace all keys for the given role with the new keys -func (tr *Repo) ReplaceBaseKeys(role string, keys ...data.PublicKey) error { +func (tr *Repo) ReplaceBaseKeys(role data.RoleName, keys ...data.PublicKey) error { r, err := tr.GetBaseRole(role) if err != nil { return err @@ -130,7 +127,7 @@ func (tr *Repo) ReplaceBaseKeys(role string, keys ...data.PublicKey) error { } // RemoveBaseKeys is used to remove keys from the roles in root.json -func (tr *Repo) RemoveBaseKeys(role string, keyIDs ...string) error { +func (tr *Repo) RemoveBaseKeys(role data.RoleName, keyIDs ...string) error { if tr.Root == nil { return ErrNotLoaded{Role: data.CanonicalRootRole} } @@ -153,20 +150,7 @@ func (tr *Repo) RemoveBaseKeys(role string, keyIDs ...string) error { // also, whichever role had keys removed needs to be re-signed // root has already been marked dirty. - switch role { - case data.CanonicalSnapshotRole: - if tr.Snapshot != nil { - tr.Snapshot.Dirty = true - } - case data.CanonicalTargetsRole: - if target, ok := tr.Targets[data.CanonicalTargetsRole]; ok { - target.Dirty = true - } - case data.CanonicalTimestampRole: - if tr.Timestamp != nil { - tr.Timestamp.Dirty = true - } - } + tr.markRoleDirty(role) // determine which keys are no longer in use by any roles for roleName, r := range tr.Root.Signed.Roles { @@ -193,12 +177,30 @@ func (tr *Repo) RemoveBaseKeys(role string, keyIDs ...string) error { tr.cryptoService.RemoveKey(k) } } + tr.Root.Dirty = true return nil } +func (tr *Repo) markRoleDirty(role data.RoleName) { + switch role { + case data.CanonicalSnapshotRole: + if tr.Snapshot != nil { + tr.Snapshot.Dirty = true + } + case data.CanonicalTargetsRole: + if target, ok := tr.Targets[data.CanonicalTargetsRole]; ok { + target.Dirty = true + } + case data.CanonicalTimestampRole: + if tr.Timestamp != nil { + tr.Timestamp.Dirty = true + } + } +} + // GetBaseRole gets a base role from this repo's metadata -func (tr *Repo) GetBaseRole(name string) (data.BaseRole, error) { +func (tr *Repo) GetBaseRole(name data.RoleName) (data.BaseRole, error) { if !data.ValidRole(name) { return data.BaseRole{}, data.ErrInvalidRole{Role: name, Reason: "invalid base role name"} } @@ -215,7 +217,7 @@ func (tr *Repo) GetBaseRole(name string) (data.BaseRole, error) { } // GetDelegationRole gets a delegation role from this repo's metadata, walking from the targets role down to the delegation itself -func (tr *Repo) GetDelegationRole(name string) (data.DelegationRole, error) { +func (tr *Repo) GetDelegationRole(name data.RoleName) (data.DelegationRole, error) { if !data.IsDelegation(name) { return data.DelegationRole{}, data.ErrInvalidRole{Role: name, Reason: "invalid delegation name"} } @@ -267,7 +269,7 @@ func (tr *Repo) GetDelegationRole(name string) (data.DelegationRole, error) { } // Walk to the parent of this delegation, since that is where its role metadata exists - err := tr.WalkTargets("", path.Dir(name), buildDelegationRoleVisitor) + err := tr.WalkTargets("", name.Parent(), buildDelegationRoleVisitor) if err != nil { return data.DelegationRole{}, err } @@ -306,7 +308,7 @@ func (tr *Repo) GetAllLoadedRoles() []*data.Role { // Walk to parent, and either create or update this delegation. We can only create a new delegation if we're given keys // Ensure all updates are valid, by checking against parent ancestor paths and ensuring the keys meet the role threshold. -func delegationUpdateVisitor(roleName string, addKeys data.KeyList, removeKeys, addPaths, removePaths []string, clearAllPaths bool, newThreshold int) walkVisitorFunc { +func delegationUpdateVisitor(roleName data.RoleName, addKeys data.KeyList, removeKeys, addPaths, removePaths []string, clearAllPaths bool, newThreshold int) walkVisitorFunc { return func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { var err error // Validate the changes underneath this restricted validRole for adding paths, reject invalid path additions @@ -382,11 +384,11 @@ func delegationUpdateVisitor(roleName string, addKeys data.KeyList, removeKeys, // a new delegation or updating an existing one. If keys are // provided, the IDs will be added to the role (if they do not exist // there already), and the keys will be added to the targets file. -func (tr *Repo) UpdateDelegationKeys(roleName string, addKeys data.KeyList, removeKeys []string, newThreshold int) error { +func (tr *Repo) UpdateDelegationKeys(roleName data.RoleName, addKeys data.KeyList, removeKeys []string, newThreshold int) error { if !data.IsDelegation(roleName) { return data.ErrInvalidRole{Role: roleName, Reason: "not a valid delegated role"} } - parent := path.Dir(roleName) + parent := roleName.Parent() if err := tr.VerifyCanSign(parent); err != nil { return err @@ -405,13 +407,13 @@ func (tr *Repo) UpdateDelegationKeys(roleName string, addKeys data.KeyList, remo // Walk to the parent of this delegation, since that is where its role metadata exists // We do not have to verify that the walker reached its desired role in this scenario // since we've already done another walk to the parent role in VerifyCanSign, and potentially made a targets file - return tr.WalkTargets("", parent, delegationUpdateVisitor(roleName, addKeys, removeKeys, []string{}, []string{}, false, newThreshold)) + return tr.WalkTargets("", roleName.Parent(), delegationUpdateVisitor(roleName, addKeys, removeKeys, []string{}, []string{}, false, newThreshold)) } // PurgeDelegationKeys removes the provided canonical key IDs from all delegations // present in the subtree rooted at role. The role argument must be provided in a wildcard // format, i.e. targets/* would remove the key from all delegations in the repo -func (tr *Repo) PurgeDelegationKeys(role string, removeKeys []string) error { +func (tr *Repo) PurgeDelegationKeys(role data.RoleName, removeKeys []string) error { if !data.IsWildDelegation(role) { return data.ErrInvalidRole{ Role: role, @@ -424,7 +426,7 @@ func (tr *Repo) PurgeDelegationKeys(role string, removeKeys []string) error { removeIDs[id] = struct{}{} } - start := path.Dir(role) + start := role.Parent() tufIDToCanon := make(map[string]string) purgeKeys := func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { @@ -480,11 +482,11 @@ func (tr *Repo) PurgeDelegationKeys(role string, removeKeys []string) error { // UpdateDelegationPaths updates the appropriate delegation's paths. // It is not allowed to create a new delegation. -func (tr *Repo) UpdateDelegationPaths(roleName string, addPaths, removePaths []string, clearPaths bool) error { +func (tr *Repo) UpdateDelegationPaths(roleName data.RoleName, addPaths, removePaths []string, clearPaths bool) error { if !data.IsDelegation(roleName) { return data.ErrInvalidRole{Role: roleName, Reason: "not a valid delegated role"} } - parent := path.Dir(roleName) + parent := roleName.Parent() if err := tr.VerifyCanSign(parent); err != nil { return err @@ -510,12 +512,12 @@ func (tr *Repo) UpdateDelegationPaths(roleName string, addPaths, removePaths []s // DeleteDelegation removes a delegated targets role from its parent // targets object. It also deletes the delegation from the snapshot. // DeleteDelegation will only make use of the role Name field. -func (tr *Repo) DeleteDelegation(roleName string) error { +func (tr *Repo) DeleteDelegation(roleName data.RoleName) error { if !data.IsDelegation(roleName) { return data.ErrInvalidRole{Role: roleName, Reason: "not a valid delegated role"} } - parent := path.Dir(roleName) + parent := roleName.Parent() if err := tr.VerifyCanSign(parent); err != nil { return err } @@ -554,7 +556,7 @@ func (tr *Repo) DeleteDelegation(roleName string) error { // InitRoot initializes an empty root file with the 4 core roles passed to the // method, and the consistent flag. func (tr *Repo) InitRoot(root, timestamp, snapshot, targets data.BaseRole, consistent bool) error { - rootRoles := make(map[string]*data.RootRole) + rootRoles := make(map[data.RoleName]*data.RootRole) rootKeys := make(map[string]data.PublicKey) for _, r := range []data.BaseRole{root, timestamp, snapshot, targets} { @@ -576,11 +578,11 @@ func (tr *Repo) InitRoot(root, timestamp, snapshot, targets data.BaseRole, consi } // InitTargets initializes an empty targets, and returns the new empty target -func (tr *Repo) InitTargets(role string) (*data.SignedTargets, error) { +func (tr *Repo) InitTargets(role data.RoleName) (*data.SignedTargets, error) { if !data.IsDelegation(role) && role != data.CanonicalTargetsRole { return nil, data.ErrInvalidRole{ Role: role, - Reason: fmt.Sprintf("role is not a valid targets role name: %s", role), + Reason: fmt.Sprintf("role is not a valid targets role name: %s", role.String()), } } targets := data.NewTargets() @@ -631,7 +633,7 @@ func (tr *Repo) InitTimestamp() error { // TargetMeta returns the FileMeta entry for the given path in the // targets file associated with the given role. This may be nil if // the target isn't found in the targets file. -func (tr Repo) TargetMeta(role, path string) *data.FileMeta { +func (tr Repo) TargetMeta(role data.RoleName, path string) *data.FileMeta { if t, ok := tr.Targets[role]; ok { if m, ok := t.Signed.Targets[path]; ok { return &m @@ -642,7 +644,7 @@ func (tr Repo) TargetMeta(role, path string) *data.FileMeta { // TargetDelegations returns a slice of Roles that are valid publishers // for the target path provided. -func (tr Repo) TargetDelegations(role, path string) []*data.Role { +func (tr Repo) TargetDelegations(role data.RoleName, path string) []*data.Role { var roles []*data.Role if t, ok := tr.Targets[role]; ok { for _, r := range t.Signed.Delegations.Roles { @@ -659,7 +661,7 @@ func (tr Repo) TargetDelegations(role, path string) []*data.Role { // enough signing keys to meet the threshold, since we want to support the use // case of multiple signers for a role. It returns an error if the role doesn't // exist or if there are no signing keys. -func (tr *Repo) VerifyCanSign(roleName string) error { +func (tr *Repo) VerifyCanSign(roleName data.RoleName) error { var ( role data.BaseRole err error @@ -702,7 +704,7 @@ type walkVisitorFunc func(*data.SignedTargets, data.DelegationRole) interface{} // WalkTargets will apply the specified visitor function to iteratively walk the targets/delegation metadata tree, // until receiving a StopWalk. The walk starts from the base "targets" role, and searches for the correct targetPath and/or rolePath // to call the visitor function on. Any roles passed into skipRoles will be excluded from the walk, as well as roles in those subtrees -func (tr *Repo) WalkTargets(targetPath, rolePath string, visitTargets walkVisitorFunc, skipRoles ...string) error { +func (tr *Repo) WalkTargets(targetPath string, rolePath data.RoleName, visitTargets walkVisitorFunc, skipRoles ...data.RoleName) error { // Start with the base targets role, which implicitly has the "" targets path targetsRole, err := tr.GetBaseRole(data.CanonicalTargetsRole) if err != nil { @@ -728,15 +730,15 @@ func (tr *Repo) WalkTargets(targetPath, rolePath string, visitTargets walkVisito } // We're at a prefix of the desired role subtree, so add its delegation role children and continue walking - if strings.HasPrefix(rolePath, role.Name+"/") { + if strings.HasPrefix(rolePath.String(), role.Name.String()+"/") { roles = append(roles, signedTgt.GetValidDelegations(role)...) continue } // Determine whether to visit this role or not: - // If the paths validate against the specified targetPath and the rolePath is empty or is in the subtree. + // If the paths validate against the specified targetPath and the role is empty or is a path in the subtree. // Also check if we are choosing to skip visiting this role on this walk (see ListTargets and GetTargetByName priority) - if isValidPath(targetPath, role) && isAncestorRole(role.Name, rolePath) && !utils.StrSliceContains(skipRoles, role.Name) { + if isValidPath(targetPath, role) && isAncestorRole(role.Name, rolePath) && !utils.RoleNameSliceContains(skipRoles, role.Name) { // If we had matching path or role name, visit this target and determine whether or not to keep walking res := visitTargets(signedTgt, role) switch typedRes := res.(type) { @@ -763,8 +765,8 @@ func (tr *Repo) WalkTargets(targetPath, rolePath string, visitTargets walkVisito // Will return true if given an empty candidateAncestor role name // The HasPrefix check is for determining whether the role name for candidateChild is a child (direct or further down the chain) // of candidateAncestor, for ex: candidateAncestor targets/a and candidateChild targets/a/b/c -func isAncestorRole(candidateChild, candidateAncestor string) bool { - return candidateAncestor == "" || candidateAncestor == candidateChild || strings.HasPrefix(candidateChild, candidateAncestor+"/") +func isAncestorRole(candidateChild data.RoleName, candidateAncestor data.RoleName) bool { + return candidateAncestor.String() == "" || candidateAncestor == candidateChild || strings.HasPrefix(candidateChild.String(), candidateAncestor.String()+"/") } // helper function that returns whether the delegation Role is valid against the given path @@ -776,11 +778,12 @@ func isValidPath(candidatePath string, delgRole data.DelegationRole) bool { // AddTargets will attempt to add the given targets specifically to // the directed role. If the metadata for the role doesn't exist yet, // AddTargets will create one. -func (tr *Repo) AddTargets(role string, targets data.Files) (data.Files, error) { - err := tr.VerifyCanSign(role) - if err != nil { - return nil, err +func (tr *Repo) AddTargets(role data.RoleName, targets data.Files) (data.Files, error) { + cantSignErr := tr.VerifyCanSign(role) + if _, ok := cantSignErr.(data.ErrInvalidRole); ok { + return nil, cantSignErr } + var needSign bool // check existence of the role's metadata _, ok := tr.Targets[role] @@ -796,10 +799,18 @@ func (tr *Repo) AddTargets(role string, targets data.Files) (data.Files, error) addTargetVisitor := func(targetPath string, targetMeta data.FileMeta) func(*data.SignedTargets, data.DelegationRole) interface{} { return func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { // We've already validated the role's target path in our walk, so just modify the metadata - tgt.Signed.Targets[targetPath] = targetMeta - tgt.Dirty = true - // Also add to our new addedTargets map to keep track of every target we've added successfully - addedTargets[targetPath] = targetMeta + if targetMeta.Equals(tgt.Signed.Targets[targetPath]) { + // Also add to our new addedTargets map because this target was "added" successfully + addedTargets[targetPath] = targetMeta + return StopWalk{} + } + needSign = true + if cantSignErr == nil { + tgt.Signed.Targets[targetPath] = targetMeta + tgt.Dirty = true + // Also add to our new addedTargets map to keep track of every target we've added successfully + addedTargets[targetPath] = targetMeta + } return StopWalk{} } } @@ -807,6 +818,9 @@ func (tr *Repo) AddTargets(role string, targets data.Files) (data.Files, error) // Walk the role tree while validating the target paths, and add all of our targets for path, target := range targets { tr.WalkTargets(path, role, addTargetVisitor(path, target)) + if needSign && cantSignErr != nil { + return nil, cantSignErr + } } if len(addedTargets) != len(targets) { return nil, fmt.Errorf("Could not add all targets") @@ -815,18 +829,21 @@ func (tr *Repo) AddTargets(role string, targets data.Files) (data.Files, error) } // RemoveTargets removes the given target (paths) from the given target role (delegation) -func (tr *Repo) RemoveTargets(role string, targets ...string) error { - if err := tr.VerifyCanSign(role); err != nil { - return err +func (tr *Repo) RemoveTargets(role data.RoleName, targets ...string) error { + cantSignErr := tr.VerifyCanSign(role) + if _, ok := cantSignErr.(data.ErrInvalidRole); ok { + return cantSignErr } - + var needSign bool removeTargetVisitor := func(targetPath string) func(*data.SignedTargets, data.DelegationRole) interface{} { return func(tgt *data.SignedTargets, validRole data.DelegationRole) interface{} { // We've already validated the role path in our walk, so just modify the metadata // We don't check against the target path against the valid role paths because it's // possible we got into an invalid state and are trying to fix it - delete(tgt.Signed.Targets, targetPath) - tgt.Dirty = true + if _, needSign = tgt.Signed.Targets[targetPath]; needSign && cantSignErr == nil { + delete(tgt.Signed.Targets, targetPath) + tgt.Dirty = true + } return StopWalk{} } } @@ -836,6 +853,9 @@ func (tr *Repo) RemoveTargets(role string, targets ...string) error { if ok { for _, path := range targets { tr.WalkTargets("", role, removeTargetVisitor(path)) + if needSign && cantSignErr != nil { + return cantSignErr + } } } @@ -843,7 +863,7 @@ func (tr *Repo) RemoveTargets(role string, targets ...string) error { } // UpdateSnapshot updates the FileMeta for the given role based on the Signed object -func (tr *Repo) UpdateSnapshot(role string, s *data.Signed) error { +func (tr *Repo) UpdateSnapshot(role data.RoleName, s *data.Signed) error { jsonData, err := json.Marshal(s) if err != nil { return err @@ -852,7 +872,7 @@ func (tr *Repo) UpdateSnapshot(role string, s *data.Signed) error { if err != nil { return err } - tr.Snapshot.Signed.Meta[role] = meta + tr.Snapshot.Signed.Meta[role.String()] = meta tr.Snapshot.Dirty = true return nil } @@ -867,28 +887,18 @@ func (tr *Repo) UpdateTimestamp(s *data.Signed) error { if err != nil { return err } - tr.Timestamp.Signed.Meta[data.CanonicalSnapshotRole] = meta + tr.Timestamp.Signed.Meta[data.CanonicalSnapshotRole.String()] = meta tr.Timestamp.Dirty = true return nil } -type versionedRootRole struct { - data.BaseRole - version int -} - -type versionedRootRoles []versionedRootRole - -func (v versionedRootRoles) Len() int { return len(v) } -func (v versionedRootRoles) Swap(i, j int) { v[i], v[j] = v[j], v[i] } -func (v versionedRootRoles) Less(i, j int) bool { return v[i].version < v[j].version } - // SignRoot signs the root, using all keys from the "root" role (i.e. currently trusted) // as well as available keys used to sign the previous version, if the public part is // carried in tr.Root.Keys and the private key is available (i.e. probably previously // trusted keys, to allow rollover). If there are any errors, attempt to put root // back to the way it was (so version won't be incremented, for instance). -func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) { +// Extra signing keys can be added to support older clients +func (tr *Repo) SignRoot(expires time.Time, extraSigningKeys data.KeyList) (*data.Signed, error) { logrus.Debug("signing root...") // duplicate root and attempt to modify it rather than the existing root @@ -906,40 +916,12 @@ func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) { return nil, err } - oldRootRoles := tr.getOldRootRoles() + var rolesToSignWith []data.BaseRole - var latestSavedRole data.BaseRole - rolesToSignWith := make([]data.BaseRole, 0, len(oldRootRoles)) - - if len(oldRootRoles) > 0 { - sort.Sort(oldRootRoles) - for _, vRole := range oldRootRoles { - rolesToSignWith = append(rolesToSignWith, vRole.BaseRole) - } - latest := rolesToSignWith[len(rolesToSignWith)-1] - latestSavedRole = data.BaseRole{ - Name: data.CanonicalRootRole, - Threshold: latest.Threshold, - Keys: latest.Keys, - } - } - - // If the root role (root keys or root threshold) has changed, save the - // previous role under the role name "root.", such that the "n" is the - // latest root.json version for which previous root role was valid. - // Also, guard against re-saving the previous role if the latest - // saved role is the same (which should not happen). - // n = root.json version of the originalRootRole (previous role) - // n+1 = root.json version of the currRoot (current role) - // n-m = root.json version of latestSavedRole (not necessarily n-1, because the - // last root rotation could have happened several root.json versions ago - if !tr.originalRootRole.Equals(currRoot) && !tr.originalRootRole.Equals(latestSavedRole) { + // If the root role (root keys or root threshold) has changed, sign with the + // previous root role keys + if !tr.originalRootRole.Equals(currRoot) { rolesToSignWith = append(rolesToSignWith, tr.originalRootRole) - latestSavedRole = tr.originalRootRole - - versionName := oldRootVersionName(tempRoot.Signed.Version) - tempRoot.Signed.Roles[versionName] = &data.RootRole{ - KeyIDs: latestSavedRole.ListKeyIDs(), Threshold: latestSavedRole.Threshold} } tempRoot.Signed.Expires = expires @@ -950,7 +932,8 @@ func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) { if err != nil { return nil, err } - signed, err = tr.sign(signed, rolesToSignWith, tr.getOptionalRootKeys(rolesToSignWith)) + + signed, err = tr.sign(signed, rolesToSignWith, extraSigningKeys) if err != nil { return nil, err } @@ -961,68 +944,12 @@ func (tr *Repo) SignRoot(expires time.Time) (*data.Signed, error) { return signed, nil } -// get all the saved previous roles < the current root version -func (tr *Repo) getOldRootRoles() versionedRootRoles { - oldRootRoles := make(versionedRootRoles, 0, len(tr.Root.Signed.Roles)) - - // now go through the old roles - for roleName := range tr.Root.Signed.Roles { - // ensure that the rolename matches our format and that the version is - // not too high - if data.ValidRole(roleName) { - continue - } - nameTokens := strings.Split(roleName, ".") - if len(nameTokens) != 2 || nameTokens[0] != data.CanonicalRootRole { - continue - } - version, err := strconv.Atoi(nameTokens[1]) - if err != nil || version >= tr.Root.Signed.Version { - continue - } - - // ignore invalid roles, which shouldn't happen - oldRole, err := tr.Root.BuildBaseRole(roleName) - if err != nil { - continue - } - - oldRootRoles = append(oldRootRoles, versionedRootRole{BaseRole: oldRole, version: version}) - } - - return oldRootRoles -} - -// gets any extra optional root keys from the existing root.json signatures -// (because older repositories that have already done root rotation may not -// necessarily have older root roles) -func (tr *Repo) getOptionalRootKeys(signingRoles []data.BaseRole) []data.PublicKey { - oldKeysMap := make(map[string]data.PublicKey) - for _, oldSig := range tr.Root.Signatures { - if k, ok := tr.Root.Signed.Keys[oldSig.KeyID]; ok { - oldKeysMap[k.ID()] = k - } - } - for _, role := range signingRoles { - for keyID := range role.Keys { - delete(oldKeysMap, keyID) - } - } - - oldKeys := make([]data.PublicKey, 0, len(oldKeysMap)) - for _, key := range oldKeysMap { - oldKeys = append(oldKeys, key) - } - - return oldKeys -} - func oldRootVersionName(version int) string { return fmt.Sprintf("%s.%v", data.CanonicalRootRole, version) } // SignTargets signs the targets file for the given top level or delegated targets role -func (tr *Repo) SignTargets(role string, expires time.Time) (*data.Signed, error) { +func (tr *Repo) SignTargets(role data.RoleName, expires time.Time) (*data.Signed, error) { logrus.Debugf("sign targets called for role %s", role) if _, ok := tr.Targets[role]; !ok { return nil, data.ErrInvalidRole{ diff --git a/vendor/github.com/theupdateframework/notary/tuf/utils/pkcs8.go b/vendor/github.com/theupdateframework/notary/tuf/utils/pkcs8.go new file mode 100644 index 000000000..edcaa77ff --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/tuf/utils/pkcs8.go @@ -0,0 +1,341 @@ +// Package utils contains tuf related utility functions however this file is hard +// forked from https://github.com/youmark/pkcs8 package. It has been further modified +// based on the requirements of Notary. For converting keys into PKCS#8 format, +// original package expected *crypto.PrivateKey interface, which then type inferred +// to either *rsa.PrivateKey or *ecdsa.PrivateKey depending on the need and later +// converted to ASN.1 DER encoded form, this whole process was superfluous here as +// keys are already being kept in ASN.1 DER format wrapped in data.PrivateKey +// structure. With these changes, package has became tightly coupled with notary as +// most of the method signatures have been updated. Moreover support for ED25519 +// keys has been added as well. License for original package is following: +// +// The MIT License (MIT) +// +// Copyright (c) 2014 youmark +// +// 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 utils + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" + + "golang.org/x/crypto/pbkdf2" + + "github.com/theupdateframework/notary/tuf/data" +) + +// Copy from crypto/x509 +var ( + oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} + oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} + oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} + // crypto/x509 doesn't have support for ED25519 + // http://www.oid-info.com/get/1.3.6.1.4.1.11591.15.1 + oidPublicKeyED25519 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11591, 15, 1} +) + +// Copy from crypto/x509 +var ( + oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} + oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} + oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} + oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +// Copy from crypto/x509 +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case elliptic.P224(): + return oidNamedCurveP224, true + case elliptic.P256(): + return oidNamedCurveP256, true + case elliptic.P384(): + return oidNamedCurveP384, true + case elliptic.P521(): + return oidNamedCurveP521, true + } + + return nil, false +} + +// Unecrypted PKCS8 +var ( + oidPKCS5PBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} + oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} + oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42} +) + +type ecPrivateKey struct { + Version int + PrivateKey []byte + NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` + PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` +} + +type privateKeyInfo struct { + Version int + PrivateKeyAlgorithm []asn1.ObjectIdentifier + PrivateKey []byte +} + +// Encrypted PKCS8 +type pbkdf2Params struct { + Salt []byte + IterationCount int +} + +type pbkdf2Algorithms struct { + IDPBKDF2 asn1.ObjectIdentifier + PBKDF2Params pbkdf2Params +} + +type pbkdf2Encs struct { + EncryAlgo asn1.ObjectIdentifier + IV []byte +} + +type pbes2Params struct { + KeyDerivationFunc pbkdf2Algorithms + EncryptionScheme pbkdf2Encs +} + +type pbes2Algorithms struct { + IDPBES2 asn1.ObjectIdentifier + PBES2Params pbes2Params +} + +type encryptedPrivateKeyInfo struct { + EncryptionAlgorithm pbes2Algorithms + EncryptedData []byte +} + +// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. +// copied from https://github.com/golang/go/blob/964639cc338db650ccadeafb7424bc8ebb2c0f6c/src/crypto/x509/pkcs8.go#L17 +type pkcs8 struct { + Version int + Algo pkix.AlgorithmIdentifier + PrivateKey []byte +} + +func parsePKCS8ToTufKey(der []byte) (data.PrivateKey, error) { + var key pkcs8 + + if _, err := asn1.Unmarshal(der, &key); err != nil { + if _, ok := err.(asn1.StructuralError); ok { + return nil, errors.New("could not decrypt private key") + } + return nil, err + } + + if key.Algo.Algorithm.Equal(oidPublicKeyED25519) { + tufED25519PrivateKey, err := ED25519ToPrivateKey(key.PrivateKey) + if err != nil { + return nil, fmt.Errorf("could not convert ed25519.PrivateKey to data.PrivateKey: %v", err) + } + + return tufED25519PrivateKey, nil + } + + privKey, err := x509.ParsePKCS8PrivateKey(der) + if err != nil { + return nil, err + } + + switch priv := privKey.(type) { + case *rsa.PrivateKey: + tufRSAPrivateKey, err := RSAToPrivateKey(priv) + if err != nil { + return nil, fmt.Errorf("could not convert rsa.PrivateKey to data.PrivateKey: %v", err) + } + + return tufRSAPrivateKey, nil + case *ecdsa.PrivateKey: + tufECDSAPrivateKey, err := ECDSAToPrivateKey(priv) + if err != nil { + return nil, fmt.Errorf("could not convert ecdsa.PrivateKey to data.PrivateKey: %v", err) + } + + return tufECDSAPrivateKey, nil + } + + return nil, errors.New("unsupported key type") +} + +// ParsePKCS8ToTufKey requires PKCS#8 key in DER format and returns data.PrivateKey +// Password should be provided in case of Encrypted PKCS#8 key, else it should be nil. +func ParsePKCS8ToTufKey(der []byte, password []byte) (data.PrivateKey, error) { + if password == nil { + return parsePKCS8ToTufKey(der) + } + + var privKey encryptedPrivateKeyInfo + if _, err := asn1.Unmarshal(der, &privKey); err != nil { + return nil, errors.New("pkcs8: only PKCS #5 v2.0 supported") + } + + if !privKey.EncryptionAlgorithm.IDPBES2.Equal(oidPBES2) { + return nil, errors.New("pkcs8: only PBES2 supported") + } + + if !privKey.EncryptionAlgorithm.PBES2Params.KeyDerivationFunc.IDPBKDF2.Equal(oidPKCS5PBKDF2) { + return nil, errors.New("pkcs8: only PBKDF2 supported") + } + + encParam := privKey.EncryptionAlgorithm.PBES2Params.EncryptionScheme + kdfParam := privKey.EncryptionAlgorithm.PBES2Params.KeyDerivationFunc.PBKDF2Params + + switch { + case encParam.EncryAlgo.Equal(oidAES256CBC): + iv := encParam.IV + salt := kdfParam.Salt + iter := kdfParam.IterationCount + + encryptedKey := privKey.EncryptedData + symkey := pbkdf2.Key(password, salt, iter, 32, sha1.New) + block, err := aes.NewCipher(symkey) + if err != nil { + return nil, err + } + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(encryptedKey, encryptedKey) + + // no need to explicitly remove padding, as ASN.1 unmarshalling will automatically discard it + key, err := parsePKCS8ToTufKey(encryptedKey) + if err != nil { + return nil, errors.New("pkcs8: incorrect password") + } + + return key, nil + default: + return nil, errors.New("pkcs8: only AES-256-CBC supported") + } + +} + +func convertTUFKeyToPKCS8(priv data.PrivateKey) ([]byte, error) { + var pkey privateKeyInfo + + switch priv.Algorithm() { + case data.RSAKey, data.RSAx509Key: + // Per RFC5958, if publicKey is present, then version is set to v2(1) else version is set to v1(0). + // But openssl set to v1 even publicKey is present + pkey.Version = 0 + pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1) + pkey.PrivateKeyAlgorithm[0] = oidPublicKeyRSA + pkey.PrivateKey = priv.Private() + case data.ECDSAKey, data.ECDSAx509Key: + // To extract Curve value, parsing ECDSA key to *ecdsa.PrivateKey + eckey, err := x509.ParseECPrivateKey(priv.Private()) + if err != nil { + return nil, err + } + + oidNamedCurve, ok := oidFromNamedCurve(eckey.Curve) + if !ok { + return nil, errors.New("pkcs8: unknown elliptic curve") + } + + // Per RFC5958, if publicKey is present, then version is set to v2(1) else version is set to v1(0). + // But openssl set to v1 even publicKey is present + pkey.Version = 1 + pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 2) + pkey.PrivateKeyAlgorithm[0] = oidPublicKeyECDSA + pkey.PrivateKeyAlgorithm[1] = oidNamedCurve + pkey.PrivateKey = priv.Private() + case data.ED25519Key: + pkey.Version = 0 + pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1) + pkey.PrivateKeyAlgorithm[0] = oidPublicKeyED25519 + pkey.PrivateKey = priv.Private() + default: + return nil, fmt.Errorf("algorithm %s not supported", priv.Algorithm()) + } + + return asn1.Marshal(pkey) +} + +func convertTUFKeyToPKCS8Encrypted(priv data.PrivateKey, password []byte) ([]byte, error) { + // Convert private key into PKCS8 format + pkey, err := convertTUFKeyToPKCS8(priv) + if err != nil { + return nil, err + } + + // Calculate key from password based on PKCS5 algorithm + // Use 8 byte salt, 16 byte IV, and 2048 iteration + iter := 2048 + salt := make([]byte, 8) + iv := make([]byte, 16) + _, err = rand.Reader.Read(salt) + if err != nil { + return nil, err + } + + _, err = rand.Reader.Read(iv) + if err != nil { + return nil, err + } + + key := pbkdf2.Key(password, salt, iter, 32, sha1.New) + + // Use AES256-CBC mode, pad plaintext with PKCS5 padding scheme + padding := aes.BlockSize - len(pkey)%aes.BlockSize + if padding > 0 { + n := len(pkey) + pkey = append(pkey, make([]byte, padding)...) + for i := 0; i < padding; i++ { + pkey[n+i] = byte(padding) + } + } + + encryptedKey := make([]byte, len(pkey)) + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(encryptedKey, pkey) + + pbkdf2algo := pbkdf2Algorithms{oidPKCS5PBKDF2, pbkdf2Params{salt, iter}} + pbkdf2encs := pbkdf2Encs{oidAES256CBC, iv} + pbes2algo := pbes2Algorithms{oidPBES2, pbes2Params{pbkdf2algo, pbkdf2encs}} + + encryptedPkey := encryptedPrivateKeyInfo{pbes2algo, encryptedKey} + return asn1.Marshal(encryptedPkey) +} + +// ConvertTUFKeyToPKCS8 converts a private key (data.Private) to PKCS#8 and returns in DER format +// if password is not nil, it would convert the Private Key to Encrypted PKCS#8. +func ConvertTUFKeyToPKCS8(priv data.PrivateKey, password []byte) ([]byte, error) { + if password == nil { + return convertTUFKeyToPKCS8(priv) + } + return convertTUFKeyToPKCS8Encrypted(priv, password) +} diff --git a/vendor/github.com/docker/notary/tuf/utils/role_sort.go b/vendor/github.com/theupdateframework/notary/tuf/utils/role_sort.go similarity index 100% rename from vendor/github.com/docker/notary/tuf/utils/role_sort.go rename to vendor/github.com/theupdateframework/notary/tuf/utils/role_sort.go diff --git a/vendor/github.com/docker/notary/tuf/utils/stack.go b/vendor/github.com/theupdateframework/notary/tuf/utils/stack.go similarity index 100% rename from vendor/github.com/docker/notary/tuf/utils/stack.go rename to vendor/github.com/theupdateframework/notary/tuf/utils/stack.go diff --git a/vendor/github.com/docker/notary/tuf/utils/utils.go b/vendor/github.com/theupdateframework/notary/tuf/utils/utils.go similarity index 62% rename from vendor/github.com/docker/notary/tuf/utils/utils.go rename to vendor/github.com/theupdateframework/notary/tuf/utils/utils.go index 8de72b679..ada7dc8cc 100644 --- a/vendor/github.com/docker/notary/tuf/utils/utils.go +++ b/vendor/github.com/theupdateframework/notary/tuf/utils/utils.go @@ -3,36 +3,13 @@ package utils import ( "crypto/sha256" "crypto/sha512" - "crypto/tls" "encoding/hex" "fmt" "io" - "net/http" - "net/url" - "os" - "strings" - "github.com/docker/notary/tuf/data" + "github.com/theupdateframework/notary/tuf/data" ) -// Download does a simple download from a URL -func Download(url url.URL) (*http.Response, error) { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - return client.Get(url.String()) -} - -// Upload does a simple JSON upload to a URL -func Upload(url string, body io.Reader) (*http.Response, error) { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client := &http.Client{Transport: tr} - return client.Post(url, "application/json", body) -} - // StrSliceContains checks if the given string appears in the slice func StrSliceContains(ss []string, s string) bool { for _, v := range ss { @@ -43,23 +20,9 @@ func StrSliceContains(ss []string, s string) bool { return false } -// StrSliceRemove removes the the given string from the slice, returning a new slice -func StrSliceRemove(ss []string, s string) []string { - res := []string{} +// RoleNameSliceContains checks if the given string appears in the slice +func RoleNameSliceContains(ss []data.RoleName, s data.RoleName) bool { for _, v := range ss { - if v != s { - res = append(res, v) - } - } - return res -} - -// StrSliceContainsI checks if the given string appears in the slice -// in a case insensitive manner -func StrSliceContainsI(ss []string, s string) bool { - s = strings.ToLower(s) - for _, v := range ss { - v = strings.ToLower(v) if v == s { return true } @@ -67,11 +30,15 @@ func StrSliceContainsI(ss []string, s string) bool { return false } -// FileExists returns true if a file (or dir) exists at the given path, -// false otherwise -func FileExists(path string) bool { - _, err := os.Stat(path) - return os.IsNotExist(err) +// RoleNameSliceRemove removes the the given RoleName from the slice, returning a new slice +func RoleNameSliceRemove(ss []data.RoleName, s data.RoleName) []data.RoleName { + res := []data.RoleName{} + for _, v := range ss { + if v != s { + res = append(res, v) + } + } + return res } // NoopCloser is a simple Reader wrapper that does nothing when Close is @@ -131,7 +98,7 @@ func RemoveUnusedKeys(t *data.SignedTargets) { // FindRoleIndex returns the index of the role named or -1 if no // matching role is found. -func FindRoleIndex(rs []*data.Role, name string) int { +func FindRoleIndex(rs []*data.Role, name data.RoleName) int { for i, r := range rs { if r.Name == name { return i @@ -143,9 +110,9 @@ func FindRoleIndex(rs []*data.Role, name string) int { // ConsistentName generates the appropriate HTTP URL path for the role, // based on whether the repo is marked as consistent. The RemoteStore // is responsible for adding file extensions. -func ConsistentName(role string, hashSha256 []byte) string { - if len(hashSha256) > 0 { - hash := hex.EncodeToString(hashSha256) +func ConsistentName(role string, hashSHA256 []byte) string { + if len(hashSHA256) > 0 { + hash := hex.EncodeToString(hashSHA256) return fmt.Sprintf("%s.%s", role, hash) } return role diff --git a/vendor/github.com/docker/notary/tuf/utils/x509.go b/vendor/github.com/theupdateframework/notary/tuf/utils/x509.go similarity index 80% rename from vendor/github.com/docker/notary/tuf/utils/x509.go rename to vendor/github.com/theupdateframework/notary/tuf/utils/x509.go index 57624f68e..7738418ac 100644 --- a/vendor/github.com/docker/notary/tuf/utils/x509.go +++ b/vendor/github.com/theupdateframework/notary/tuf/utils/x509.go @@ -16,16 +16,19 @@ import ( "math/big" "time" - "github.com/Sirupsen/logrus" "github.com/agl/ed25519" - "github.com/docker/notary" - "github.com/docker/notary/tuf/data" + "github.com/sirupsen/logrus" + "github.com/theupdateframework/notary" + "github.com/theupdateframework/notary/tuf/data" ) // CanonicalKeyID returns the ID of the public bytes version of a TUF key. // On regular RSA/ECDSA TUF keys, this is just the key ID. On X509 RSA/ECDSA // TUF keys, this is the key ID of the public key part of the key in the leaf cert func CanonicalKeyID(k data.PublicKey) (string, error) { + if k == nil { + return "", errors.New("public key is nil") + } switch k.Algorithm() { case data.ECDSAx509Key, data.RSAx509Key: return X509PublicKeyID(k) @@ -82,12 +85,9 @@ func X509PublicKeyID(certPubKey data.PublicKey) (string, error) { return key.ID(), nil } -// ParsePEMPrivateKey returns a data.PrivateKey from a PEM encoded private key. It -// only supports RSA (PKCS#1) and attempts to decrypt using the passphrase, if encrypted. -func ParsePEMPrivateKey(pemBytes []byte, passphrase string) (data.PrivateKey, error) { - block, _ := pem.Decode(pemBytes) - if block == nil { - return nil, errors.New("no valid private key found") +func parseLegacyPrivateKey(block *pem.Block, passphrase string) (data.PrivateKey, error) { + if notary.FIPSEnabled() { + return nil, fmt.Errorf("%s not supported in FIPS mode", block.Type) } var privKeyBytes []byte @@ -142,6 +142,28 @@ func ParsePEMPrivateKey(pemBytes []byte, passphrase string) (data.PrivateKey, er } } +// ParsePEMPrivateKey returns a data.PrivateKey from a PEM encoded private key. It +// supports PKCS#8 as well as RSA/ECDSA (PKCS#1) only in non-FIPS mode and +// attempts to decrypt using the passphrase, if encrypted. +func ParsePEMPrivateKey(pemBytes []byte, passphrase string) (data.PrivateKey, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("no valid private key found") + } + + switch block.Type { + case "RSA PRIVATE KEY", "EC PRIVATE KEY", "ED25519 PRIVATE KEY": + return parseLegacyPrivateKey(block, passphrase) + case "ENCRYPTED PRIVATE KEY", "PRIVATE KEY": + if passphrase == "" { + return ParsePKCS8ToTufKey(block.Bytes, nil) + } + return ParsePKCS8ToTufKey(block.Bytes, []byte(passphrase)) + default: + return nil, fmt.Errorf("unsupported key type %q", block.Type) + } +} + // CertToPEM is a utility function returns a PEM encoded x509 Certificate func CertToPEM(cert *x509.Certificate) []byte { pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) @@ -252,11 +274,31 @@ func ParsePEMPublicKey(pubKeyBytes []byte) (data.PublicKey, error) { return nil, fmt.Errorf("invalid certificate: %v", err) } return CertToKey(cert), nil + case "PUBLIC KEY": + keyType, err := keyTypeForPublicKey(pemBlock.Bytes) + if err != nil { + return nil, err + } + return data.NewPublicKey(keyType, pemBlock.Bytes), nil default: - return nil, fmt.Errorf("unsupported PEM block type %q, expected certificate", pemBlock.Type) + return nil, fmt.Errorf("unsupported PEM block type %q, expected CERTIFICATE or PUBLIC KEY", pemBlock.Type) } } +func keyTypeForPublicKey(pubKeyBytes []byte) (string, error) { + pub, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return "", fmt.Errorf("unable to parse pem encoded public key: %v", err) + } + switch pub.(type) { + case *ecdsa.PublicKey: + return data.ECDSAKey, nil + case *rsa.PublicKey: + return data.RSAKey, nil + } + return "", fmt.Errorf("unknown public key format") +} + // ValidateCertificate returns an error if the certificate is not valid for notary // Currently this is only ensuring the public key has a large enough modulus if RSA, // using a non SHA1 signature algorithm, and an optional time expiry check @@ -293,21 +335,16 @@ func ValidateCertificate(c *x509.Certificate, checkExpiry bool) error { return nil } -// GenerateRSAKey generates an RSA private key and returns a TUF PrivateKey -func GenerateRSAKey(random io.Reader, bits int) (data.PrivateKey, error) { - rsaPrivKey, err := rsa.GenerateKey(random, bits) - if err != nil { - return nil, fmt.Errorf("could not generate private key: %v", err) +// GenerateKey returns a new private key using the provided algorithm or an +// error detailing why the key could not be generated +func GenerateKey(algorithm string) (data.PrivateKey, error) { + switch algorithm { + case data.ECDSAKey: + return GenerateECDSAKey(rand.Reader) + case data.ED25519Key: + return GenerateED25519Key(rand.Reader) } - - tufPrivKey, err := RSAToPrivateKey(rsaPrivKey) - if err != nil { - return nil, err - } - - logrus.Debugf("generated RSA key with keyID: %s", tufPrivKey.ID()) - - return tufPrivKey, nil + return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm) } // RSAToPrivateKey converts an rsa.Private key to a TUF data.PrivateKey type @@ -394,85 +431,54 @@ func ED25519ToPrivateKey(privKeyBytes []byte) (data.PrivateKey, error) { return data.NewED25519PrivateKey(*pubKey, privKeyBytes) } -func blockType(k data.PrivateKey) (string, error) { - switch k.Algorithm() { - case data.RSAKey, data.RSAx509Key: - return "RSA PRIVATE KEY", nil - case data.ECDSAKey, data.ECDSAx509Key: - return "EC PRIVATE KEY", nil - case data.ED25519Key: - return "ED25519 PRIVATE KEY", nil - default: - return "", fmt.Errorf("algorithm %s not supported", k.Algorithm()) - } -} - -// KeyToPEM returns a PEM encoded key from a Private Key -func KeyToPEM(privKey data.PrivateKey, role string) ([]byte, error) { - bt, err := blockType(privKey) - if err != nil { - return nil, err +// ExtractPrivateKeyAttributes extracts role and gun values from private key bytes +func ExtractPrivateKeyAttributes(pemBytes []byte) (data.RoleName, data.GUN, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return "", "", errors.New("PEM block is empty") } - headers := map[string]string{} - if role != "" { - headers = map[string]string{ - "role": role, + switch block.Type { + case "RSA PRIVATE KEY", "EC PRIVATE KEY", "ED25519 PRIVATE KEY": + if notary.FIPSEnabled() { + return "", "", fmt.Errorf("%s not supported in FIPS mode", block.Type) } + case "PRIVATE KEY", "ENCRYPTED PRIVATE KEY": + // do nothing for PKCS#8 keys + default: + return "", "", errors.New("unknown key format") } - - block := &pem.Block{ - Type: bt, - Headers: headers, - Bytes: privKey.Private(), - } - - return pem.EncodeToMemory(block), nil + return data.RoleName(block.Headers["role"]), data.GUN(block.Headers["gun"]), nil } -// EncryptPrivateKey returns an encrypted PEM key given a Privatekey -// and a passphrase -func EncryptPrivateKey(key data.PrivateKey, role, gun, passphrase string) ([]byte, error) { - bt, err := blockType(key) +// ConvertPrivateKeyToPKCS8 converts a data.PrivateKey to PKCS#8 Format +func ConvertPrivateKeyToPKCS8(key data.PrivateKey, role data.RoleName, gun data.GUN, passphrase string) ([]byte, error) { + var ( + err error + der []byte + blockType = "PRIVATE KEY" + ) + + if passphrase == "" { + der, err = ConvertTUFKeyToPKCS8(key, nil) + } else { + blockType = "ENCRYPTED PRIVATE KEY" + der, err = ConvertTUFKeyToPKCS8(key, []byte(passphrase)) + } if err != nil { - return nil, err + return nil, fmt.Errorf("unable to convert to PKCS8 key") } - password := []byte(passphrase) - cipherType := x509.PEMCipherAES256 - - encryptedPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, - bt, - key.Private(), - password, - cipherType) - if err != nil { - return nil, err + headers := make(map[string]string) + if role != "" { + headers["role"] = role.String() } - if encryptedPEMBlock.Headers == nil { - return nil, fmt.Errorf("unable to encrypt key - invalid PEM file produced") - } - encryptedPEMBlock.Headers["role"] = role - if gun != "" { - encryptedPEMBlock.Headers["gun"] = gun + headers["gun"] = gun.String() } - return pem.EncodeToMemory(encryptedPEMBlock), nil -} - -// ReadRoleFromPEM returns the value from the role PEM header, if it exists -func ReadRoleFromPEM(pemBytes []byte) string { - pemBlock, _ := pem.Decode(pemBytes) - if pemBlock == nil || pemBlock.Headers == nil { - return "" - } - role, ok := pemBlock.Headers["role"] - if !ok { - return "" - } - return role + return pem.EncodeToMemory(&pem.Block{Bytes: der, Type: blockType, Headers: headers}), nil } // CertToKey transforms a single input certificate into its corresponding @@ -527,8 +533,8 @@ func CertBundleToKey(leafCert *x509.Certificate, intCerts []*x509.Certificate) ( return newKey, nil } -// NewCertificate returns an X509 Certificate following a template, given a GUN and validity interval. -func NewCertificate(gun string, startTime, endTime time.Time) (*x509.Certificate, error) { +// NewCertificate returns an X509 Certificate following a template, given a Common Name and validity interval. +func NewCertificate(commonName string, startTime, endTime time.Time) (*x509.Certificate, error) { serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) @@ -539,7 +545,7 @@ func NewCertificate(gun string, startTime, endTime time.Time) (*x509.Certificate return &x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ - CommonName: gun, + CommonName: commonName, }, NotBefore: startTime, NotAfter: endTime, diff --git a/vendor/github.com/docker/notary/tuf/validation/errors.go b/vendor/github.com/theupdateframework/notary/tuf/validation/errors.go similarity index 100% rename from vendor/github.com/docker/notary/tuf/validation/errors.go rename to vendor/github.com/theupdateframework/notary/tuf/validation/errors.go diff --git a/vendor/github.com/theupdateframework/notary/vendor.conf b/vendor/github.com/theupdateframework/notary/vendor.conf new file mode 100644 index 000000000..73e12db5d --- /dev/null +++ b/vendor/github.com/theupdateframework/notary/vendor.conf @@ -0,0 +1,59 @@ +github.com/Shopify/logrus-bugsnag 6dbc35f2c30d1e37549f9673dd07912452ab28a5 +github.com/sirupsen/logrus f006c2ac4710855cf0f916dd6b77acf6b048dc6e # v1.0.3 +github.com/agl/ed25519 278e1ec8e8a6e017cd07577924d6766039146ced +github.com/bugsnag/bugsnag-go 13fd6b8acda029830ef9904df6b63be0a83369d0 +github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782 +github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702 +github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c +github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb +github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d +github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06 +github.com/dvsekhvalnov/jose2go 6387d3c1f5abd8443b223577d5a7e0f4e0e5731f # v1.2 +github.com/go-sql-driver/mysql a0583e0143b1624142adab07e0e97fe106d99561 # v1.3 +github.com/gorilla/mux e444e69cbd2e2e3e0749a2f3c717cec491552bbf +github.com/jinzhu/gorm 5409931a1bb87e484d68d649af9367c207713ea2 +github.com/jinzhu/inflection 1c35d901db3da928c72a72d8458480cc9ade058f +github.com/lib/pq 0dad96c0b94f8dee039aa40467f767467392a0af +github.com/mattn/go-sqlite3 b4142c444a8941d0d92b0b7103a24df9cd815e42 # v1.0.0 +github.com/miekg/pkcs11 ba39b9c6300b7e0be41b115330145ef8afdff7d6 +github.com/mitchellh/go-homedir df55a15e5ce646808815381b3db47a8c66ea62f4 +github.com/prometheus/client_golang 449ccefff16c8e2b7229f6be1921ba22f62461fe +github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 # model-0.0.2-12-gfa8ad6f +github.com/prometheus/procfs b1afdc266f54247f5dc725544f5d351a8661f502 +github.com/prometheus/common 4fdc91a58c9d3696b982e8a680f4997403132d44 +github.com/golang/protobuf c3cefd437628a0b7d31b34fe44b3a7a540e98527 +github.com/spf13/cobra f368244301305f414206f889b1735a54cfc8bde8 +github.com/spf13/viper be5ff3e4840cf692388bde7a057595a474ef379e +golang.org/x/crypto 76eec36fa14229c4b25bb894c2d0e591527af429 +golang.org/x/net 6a513affb38dc9788b449d59ffed099b8de18fa0 +golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f +google.golang.org/grpc 708a7f9f3283aa2d4f6132d287d78683babe55c8 # v1.0.5 +github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 + +github.com/spf13/pflag cb88ea77998c3f024757528e3305022ab50b43be +github.com/spf13/cast 4d07383ffe94b5e5a6fa3af9211374a4507a0184 +gopkg.in/yaml.v2 bef53efd0c76e49e6de55ead051f886bea7e9420 +gopkg.in/fatih/pool.v2 cba550ebf9bce999a02e963296d4bc7a486cb715 +github.com/gorilla/context 14f550f51af52180c2eefed15e5fd18d63c0a64a +github.com/spf13/jwalterweatherman 3d60171a64319ef63c78bd45bd60e6eab1e75f8b +github.com/mitchellh/mapstructure 2caf8efc93669b6c43e0441cdc6aed17546c96f3 +github.com/magiconair/properties 624009598839a9432bd97bb75552389422357723 # v1.5.3 +github.com/kr/text 6807e777504f54ad073ecef66747de158294b639 +github.com/kr/pretty bc9499caa0f45ee5edb2f0209fbd61fbf3d9018f # go.weekly.2011-12-22-18-gbc9499c +github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478 +github.com/docker/libtrust aabc10ec26b754e797f9028f4589c5b7bd90dc20 +github.com/beorn7/perks b965b613227fddccbfffe13eae360ed3fa822f8d +github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 + +github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453 +github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 + +gopkg.in/dancannon/gorethink.v3 e324d6ad938205da6c1e8a0179dc97a5b1a92185 https://github.com/docker/gorethink # v3.0.0-logrus +# dependencies of gorethink.v3 +gopkg.in/gorethink/gorethink.v2 ac5be4ae8538d44ae8843b97fc9f90860cb48a85 https://github.com/docker/gorethink # v2.2.2-logrus +github.com/cenk/backoff 32cd0c5b3aef12c76ed64aaf678f6c79736be7dc # v1.0.0 + +# Testing requirements +github.com/stretchr/testify 089c7181b8c728499929ff09b62d3fdd8df8adff +github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a +github.com/google/certificate-transparency 0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341 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 000000000..593f65300 --- /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/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go new file mode 100644 index 000000000..18379a935 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go @@ -0,0 +1,951 @@ +// Copyright 2011 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 terminal + +import ( + "bytes" + "io" + "sync" + "unicode/utf8" +) + +// EscapeCodes contains escape sequences that can be written to the terminal in +// order to achieve different styles of text. +type EscapeCodes struct { + // Foreground colors + Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte + + // Reset all attributes + Reset []byte +} + +var vt100EscapeCodes = EscapeCodes{ + Black: []byte{keyEscape, '[', '3', '0', 'm'}, + Red: []byte{keyEscape, '[', '3', '1', 'm'}, + Green: []byte{keyEscape, '[', '3', '2', 'm'}, + Yellow: []byte{keyEscape, '[', '3', '3', 'm'}, + Blue: []byte{keyEscape, '[', '3', '4', 'm'}, + Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, + Cyan: []byte{keyEscape, '[', '3', '6', 'm'}, + White: []byte{keyEscape, '[', '3', '7', 'm'}, + + Reset: []byte{keyEscape, '[', '0', 'm'}, +} + +// Terminal contains the state for running a VT100 terminal that is capable of +// reading lines of input. +type Terminal struct { + // AutoCompleteCallback, if non-null, is called for each keypress with + // the full input line and the current position of the cursor (in + // bytes, as an index into |line|). If it returns ok=false, the key + // press is processed normally. Otherwise it returns a replacement line + // and the new cursor position. + AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) + + // Escape contains a pointer to the escape codes for this terminal. + // It's always a valid pointer, although the escape codes themselves + // may be empty if the terminal doesn't support them. + Escape *EscapeCodes + + // lock protects the terminal and the state in this object from + // concurrent processing of a key press and a Write() call. + lock sync.Mutex + + c io.ReadWriter + prompt []rune + + // line is the current line being entered. + line []rune + // pos is the logical position of the cursor in line + pos int + // echo is true if local echo is enabled + echo bool + // pasteActive is true iff there is a bracketed paste operation in + // progress. + pasteActive bool + + // cursorX contains the current X value of the cursor where the left + // edge is 0. cursorY contains the row number where the first row of + // the current line is 0. + cursorX, cursorY int + // maxLine is the greatest value of cursorY so far. + maxLine int + + termWidth, termHeight int + + // outBuf contains the terminal data to be sent. + outBuf []byte + // remainder contains the remainder of any partial key sequences after + // a read. It aliases into inBuf. + remainder []byte + inBuf [256]byte + + // history contains previously entered commands so that they can be + // accessed with the up and down keys. + history stRingBuffer + // historyIndex stores the currently accessed history entry, where zero + // means the immediately previous entry. + historyIndex int + // When navigating up and down the history it's possible to return to + // the incomplete, initial line. That value is stored in + // historyPending. + historyPending string +} + +// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is +// a local terminal, that terminal must first have been put into raw mode. +// prompt is a string that is written at the start of each input line (i.e. +// "> "). +func NewTerminal(c io.ReadWriter, prompt string) *Terminal { + return &Terminal{ + Escape: &vt100EscapeCodes, + c: c, + prompt: []rune(prompt), + termWidth: 80, + termHeight: 24, + echo: true, + historyIndex: -1, + } +} + +const ( + keyCtrlD = 4 + keyCtrlU = 21 + keyEnter = '\r' + keyEscape = 27 + keyBackspace = 127 + keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota + keyUp + keyDown + keyLeft + keyRight + keyAltLeft + keyAltRight + keyHome + keyEnd + keyDeleteWord + keyDeleteLine + keyClearScreen + keyPasteStart + keyPasteEnd +) + +var ( + crlf = []byte{'\r', '\n'} + pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'} + pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'} +) + +// bytesToKey tries to parse a key sequence from b. If successful, it returns +// the key and the remainder of the input. Otherwise it returns utf8.RuneError. +func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { + if len(b) == 0 { + return utf8.RuneError, nil + } + + if !pasteActive { + switch b[0] { + case 1: // ^A + return keyHome, b[1:] + case 5: // ^E + return keyEnd, b[1:] + case 8: // ^H + return keyBackspace, b[1:] + case 11: // ^K + return keyDeleteLine, b[1:] + case 12: // ^L + return keyClearScreen, b[1:] + case 23: // ^W + return keyDeleteWord, b[1:] + } + } + + if b[0] != keyEscape { + if !utf8.FullRune(b) { + return utf8.RuneError, b + } + r, l := utf8.DecodeRune(b) + return r, b[l:] + } + + if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' { + switch b[2] { + case 'A': + return keyUp, b[3:] + case 'B': + return keyDown, b[3:] + case 'C': + return keyRight, b[3:] + case 'D': + return keyLeft, b[3:] + case 'H': + return keyHome, b[3:] + case 'F': + return keyEnd, b[3:] + } + } + + if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' { + switch b[5] { + case 'C': + return keyAltRight, b[6:] + case 'D': + return keyAltLeft, b[6:] + } + } + + if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) { + return keyPasteStart, b[6:] + } + + if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) { + return keyPasteEnd, b[6:] + } + + // If we get here then we have a key that we don't recognise, or a + // partial sequence. It's not clear how one should find the end of a + // sequence without knowing them all, but it seems that [a-zA-Z~] only + // appears at the end of a sequence. + for i, c := range b[0:] { + if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' { + return keyUnknown, b[i+1:] + } + } + + return utf8.RuneError, b +} + +// queue appends data to the end of t.outBuf +func (t *Terminal) queue(data []rune) { + t.outBuf = append(t.outBuf, []byte(string(data))...) +} + +var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'} +var space = []rune{' '} + +func isPrintable(key rune) bool { + isInSurrogateArea := key >= 0xd800 && key <= 0xdbff + return key >= 32 && !isInSurrogateArea +} + +// moveCursorToPos appends data to t.outBuf which will move the cursor to the +// given, logical position in the text. +func (t *Terminal) moveCursorToPos(pos int) { + if !t.echo { + return + } + + x := visualLength(t.prompt) + pos + y := x / t.termWidth + x = x % t.termWidth + + up := 0 + if y < t.cursorY { + up = t.cursorY - y + } + + down := 0 + if y > t.cursorY { + down = y - t.cursorY + } + + left := 0 + if x < t.cursorX { + left = t.cursorX - x + } + + right := 0 + if x > t.cursorX { + right = x - t.cursorX + } + + t.cursorX = x + t.cursorY = y + t.move(up, down, left, right) +} + +func (t *Terminal) move(up, down, left, right int) { + movement := make([]rune, 3*(up+down+left+right)) + m := movement + for i := 0; i < up; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'A' + m = m[3:] + } + for i := 0; i < down; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'B' + m = m[3:] + } + for i := 0; i < left; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'D' + m = m[3:] + } + for i := 0; i < right; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'C' + m = m[3:] + } + + t.queue(movement) +} + +func (t *Terminal) clearLineToRight() { + op := []rune{keyEscape, '[', 'K'} + t.queue(op) +} + +const maxLineLength = 4096 + +func (t *Terminal) setLine(newLine []rune, newPos int) { + if t.echo { + t.moveCursorToPos(0) + t.writeLine(newLine) + for i := len(newLine); i < len(t.line); i++ { + t.writeLine(space) + } + t.moveCursorToPos(newPos) + } + t.line = newLine + t.pos = newPos +} + +func (t *Terminal) advanceCursor(places int) { + t.cursorX += places + t.cursorY += t.cursorX / t.termWidth + if t.cursorY > t.maxLine { + t.maxLine = t.cursorY + } + t.cursorX = t.cursorX % t.termWidth + + if places > 0 && t.cursorX == 0 { + // Normally terminals will advance the current position + // when writing a character. But that doesn't happen + // for the last character in a line. However, when + // writing a character (except a new line) that causes + // a line wrap, the position will be advanced two + // places. + // + // So, if we are stopping at the end of a line, we + // need to write a newline so that our cursor can be + // advanced to the next line. + t.outBuf = append(t.outBuf, '\r', '\n') + } +} + +func (t *Terminal) eraseNPreviousChars(n int) { + if n == 0 { + return + } + + if t.pos < n { + n = t.pos + } + t.pos -= n + t.moveCursorToPos(t.pos) + + copy(t.line[t.pos:], t.line[n+t.pos:]) + t.line = t.line[:len(t.line)-n] + if t.echo { + t.writeLine(t.line[t.pos:]) + for i := 0; i < n; i++ { + t.queue(space) + } + t.advanceCursor(n) + t.moveCursorToPos(t.pos) + } +} + +// countToLeftWord returns then number of characters from the cursor to the +// start of the previous word. +func (t *Terminal) countToLeftWord() int { + if t.pos == 0 { + return 0 + } + + pos := t.pos - 1 + for pos > 0 { + if t.line[pos] != ' ' { + break + } + pos-- + } + for pos > 0 { + if t.line[pos] == ' ' { + pos++ + break + } + pos-- + } + + return t.pos - pos +} + +// countToRightWord returns then number of characters from the cursor to the +// start of the next word. +func (t *Terminal) countToRightWord() int { + pos := t.pos + for pos < len(t.line) { + if t.line[pos] == ' ' { + break + } + pos++ + } + for pos < len(t.line) { + if t.line[pos] != ' ' { + break + } + pos++ + } + return pos - t.pos +} + +// visualLength returns the number of visible glyphs in s. +func visualLength(runes []rune) int { + inEscapeSeq := false + length := 0 + + for _, r := range runes { + switch { + case inEscapeSeq: + if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { + inEscapeSeq = false + } + case r == '\x1b': + inEscapeSeq = true + default: + length++ + } + } + + return length +} + +// handleKey processes the given key and, optionally, returns a line of text +// that the user has entered. +func (t *Terminal) handleKey(key rune) (line string, ok bool) { + if t.pasteActive && key != keyEnter { + t.addKeyToLine(key) + return + } + + switch key { + case keyBackspace: + if t.pos == 0 { + return + } + t.eraseNPreviousChars(1) + case keyAltLeft: + // move left by a word. + t.pos -= t.countToLeftWord() + t.moveCursorToPos(t.pos) + case keyAltRight: + // move right by a word. + t.pos += t.countToRightWord() + t.moveCursorToPos(t.pos) + case keyLeft: + if t.pos == 0 { + return + } + t.pos-- + t.moveCursorToPos(t.pos) + case keyRight: + if t.pos == len(t.line) { + return + } + t.pos++ + t.moveCursorToPos(t.pos) + case keyHome: + if t.pos == 0 { + return + } + t.pos = 0 + t.moveCursorToPos(t.pos) + case keyEnd: + if t.pos == len(t.line) { + return + } + t.pos = len(t.line) + t.moveCursorToPos(t.pos) + case keyUp: + entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1) + if !ok { + return "", false + } + if t.historyIndex == -1 { + t.historyPending = string(t.line) + } + t.historyIndex++ + runes := []rune(entry) + t.setLine(runes, len(runes)) + case keyDown: + switch t.historyIndex { + case -1: + return + case 0: + runes := []rune(t.historyPending) + t.setLine(runes, len(runes)) + t.historyIndex-- + default: + entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1) + if ok { + t.historyIndex-- + runes := []rune(entry) + t.setLine(runes, len(runes)) + } + } + case keyEnter: + t.moveCursorToPos(len(t.line)) + t.queue([]rune("\r\n")) + line = string(t.line) + ok = true + t.line = t.line[:0] + t.pos = 0 + t.cursorX = 0 + t.cursorY = 0 + t.maxLine = 0 + case keyDeleteWord: + // Delete zero or more spaces and then one or more characters. + t.eraseNPreviousChars(t.countToLeftWord()) + case keyDeleteLine: + // Delete everything from the current cursor position to the + // end of line. + for i := t.pos; i < len(t.line); i++ { + t.queue(space) + t.advanceCursor(1) + } + t.line = t.line[:t.pos] + t.moveCursorToPos(t.pos) + case keyCtrlD: + // Erase the character under the current position. + // The EOF case when the line is empty is handled in + // readLine(). + if t.pos < len(t.line) { + t.pos++ + t.eraseNPreviousChars(1) + } + case keyCtrlU: + t.eraseNPreviousChars(t.pos) + case keyClearScreen: + // Erases the screen and moves the cursor to the home position. + t.queue([]rune("\x1b[2J\x1b[H")) + t.queue(t.prompt) + t.cursorX, t.cursorY = 0, 0 + t.advanceCursor(visualLength(t.prompt)) + t.setLine(t.line, t.pos) + default: + if t.AutoCompleteCallback != nil { + prefix := string(t.line[:t.pos]) + suffix := string(t.line[t.pos:]) + + t.lock.Unlock() + newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key) + t.lock.Lock() + + if completeOk { + t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos])) + return + } + } + if !isPrintable(key) { + return + } + if len(t.line) == maxLineLength { + return + } + t.addKeyToLine(key) + } + return +} + +// addKeyToLine inserts the given key at the current position in the current +// line. +func (t *Terminal) addKeyToLine(key rune) { + if len(t.line) == cap(t.line) { + newLine := make([]rune, len(t.line), 2*(1+len(t.line))) + copy(newLine, t.line) + t.line = newLine + } + t.line = t.line[:len(t.line)+1] + copy(t.line[t.pos+1:], t.line[t.pos:]) + t.line[t.pos] = key + if t.echo { + t.writeLine(t.line[t.pos:]) + } + t.pos++ + t.moveCursorToPos(t.pos) +} + +func (t *Terminal) writeLine(line []rune) { + for len(line) != 0 { + remainingOnLine := t.termWidth - t.cursorX + todo := len(line) + if todo > remainingOnLine { + todo = remainingOnLine + } + t.queue(line[:todo]) + t.advanceCursor(visualLength(line[:todo])) + line = line[todo:] + } +} + +// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n. +func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { + for len(buf) > 0 { + i := bytes.IndexByte(buf, '\n') + todo := len(buf) + if i >= 0 { + todo = i + } + + var nn int + nn, err = w.Write(buf[:todo]) + n += nn + if err != nil { + return n, err + } + buf = buf[todo:] + + if i >= 0 { + if _, err = w.Write(crlf); err != nil { + return n, err + } + n += 1 + buf = buf[1:] + } + } + + return n, nil +} + +func (t *Terminal) Write(buf []byte) (n int, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + if t.cursorX == 0 && t.cursorY == 0 { + // This is the easy case: there's nothing on the screen that we + // have to move out of the way. + return writeWithCRLF(t.c, buf) + } + + // We have a prompt and possibly user input on the screen. We + // have to clear it first. + t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */) + t.cursorX = 0 + t.clearLineToRight() + + for t.cursorY > 0 { + t.move(1 /* up */, 0, 0, 0) + t.cursorY-- + t.clearLineToRight() + } + + if _, err = t.c.Write(t.outBuf); err != nil { + return + } + t.outBuf = t.outBuf[:0] + + if n, err = writeWithCRLF(t.c, buf); err != nil { + return + } + + t.writeLine(t.prompt) + if t.echo { + t.writeLine(t.line) + } + + t.moveCursorToPos(t.pos) + + if _, err = t.c.Write(t.outBuf); err != nil { + return + } + t.outBuf = t.outBuf[:0] + return +} + +// ReadPassword temporarily changes the prompt and reads a password, without +// echo, from the terminal. +func (t *Terminal) ReadPassword(prompt string) (line string, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + oldPrompt := t.prompt + t.prompt = []rune(prompt) + t.echo = false + + line, err = t.readLine() + + t.prompt = oldPrompt + t.echo = true + + return +} + +// ReadLine returns a line of input from the terminal. +func (t *Terminal) ReadLine() (line string, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + return t.readLine() +} + +func (t *Terminal) readLine() (line string, err error) { + // t.lock must be held at this point + + if t.cursorX == 0 && t.cursorY == 0 { + t.writeLine(t.prompt) + t.c.Write(t.outBuf) + t.outBuf = t.outBuf[:0] + } + + lineIsPasted := t.pasteActive + + for { + rest := t.remainder + lineOk := false + for !lineOk { + var key rune + key, rest = bytesToKey(rest, t.pasteActive) + if key == utf8.RuneError { + break + } + if !t.pasteActive { + if key == keyCtrlD { + if len(t.line) == 0 { + return "", io.EOF + } + } + if key == keyPasteStart { + t.pasteActive = true + if len(t.line) == 0 { + lineIsPasted = true + } + continue + } + } else if key == keyPasteEnd { + t.pasteActive = false + continue + } + if !t.pasteActive { + lineIsPasted = false + } + line, lineOk = t.handleKey(key) + } + if len(rest) > 0 { + n := copy(t.inBuf[:], rest) + t.remainder = t.inBuf[:n] + } else { + t.remainder = nil + } + t.c.Write(t.outBuf) + t.outBuf = t.outBuf[:0] + if lineOk { + if t.echo { + t.historyIndex = -1 + t.history.Add(line) + } + if lineIsPasted { + err = ErrPasteIndicator + } + return + } + + // t.remainder is a slice at the beginning of t.inBuf + // containing a partial key sequence + readBuf := t.inBuf[len(t.remainder):] + var n int + + t.lock.Unlock() + n, err = t.c.Read(readBuf) + t.lock.Lock() + + if err != nil { + return + } + + t.remainder = t.inBuf[:n+len(t.remainder)] + } +} + +// SetPrompt sets the prompt to be used when reading subsequent lines. +func (t *Terminal) SetPrompt(prompt string) { + t.lock.Lock() + defer t.lock.Unlock() + + t.prompt = []rune(prompt) +} + +func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) { + // Move cursor to column zero at the start of the line. + t.move(t.cursorY, 0, t.cursorX, 0) + t.cursorX, t.cursorY = 0, 0 + t.clearLineToRight() + for t.cursorY < numPrevLines { + // Move down a line + t.move(0, 1, 0, 0) + t.cursorY++ + t.clearLineToRight() + } + // Move back to beginning. + t.move(t.cursorY, 0, 0, 0) + t.cursorX, t.cursorY = 0, 0 + + t.queue(t.prompt) + t.advanceCursor(visualLength(t.prompt)) + t.writeLine(t.line) + t.moveCursorToPos(t.pos) +} + +func (t *Terminal) SetSize(width, height int) error { + t.lock.Lock() + defer t.lock.Unlock() + + if width == 0 { + width = 1 + } + + oldWidth := t.termWidth + t.termWidth, t.termHeight = width, height + + switch { + case width == oldWidth: + // If the width didn't change then nothing else needs to be + // done. + return nil + case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: + // If there is nothing on current line and no prompt printed, + // just do nothing + return nil + case width < oldWidth: + // Some terminals (e.g. xterm) will truncate lines that were + // too long when shinking. Others, (e.g. gnome-terminal) will + // attempt to wrap them. For the former, repainting t.maxLine + // works great, but that behaviour goes badly wrong in the case + // of the latter because they have doubled every full line. + + // We assume that we are working on a terminal that wraps lines + // and adjust the cursor position based on every previous line + // wrapping and turning into two. This causes the prompt on + // xterms to move upwards, which isn't great, but it avoids a + // huge mess with gnome-terminal. + if t.cursorX >= t.termWidth { + t.cursorX = t.termWidth - 1 + } + t.cursorY *= 2 + t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2) + case width > oldWidth: + // If the terminal expands then our position calculations will + // be wrong in the future because we think the cursor is + // |t.pos| chars into the string, but there will be a gap at + // the end of any wrapped line. + // + // But the position will actually be correct until we move, so + // we can move back to the beginning and repaint everything. + t.clearAndRepaintLinePlusNPrevious(t.maxLine) + } + + _, err := t.c.Write(t.outBuf) + t.outBuf = t.outBuf[:0] + return err +} + +type pasteIndicatorError struct{} + +func (pasteIndicatorError) Error() string { + return "terminal: ErrPasteIndicator not correctly handled" +} + +// ErrPasteIndicator may be returned from ReadLine as the error, in addition +// to valid line data. It indicates that bracketed paste mode is enabled and +// that the returned line consists only of pasted data. Programs may wish to +// interpret pasted data more literally than typed data. +var ErrPasteIndicator = pasteIndicatorError{} + +// SetBracketedPasteMode requests that the terminal bracket paste operations +// with markers. Not all terminals support this but, if it is supported, then +// enabling this mode will stop any autocomplete callback from running due to +// pastes. Additionally, any lines that are completely pasted will be returned +// from ReadLine with the error set to ErrPasteIndicator. +func (t *Terminal) SetBracketedPasteMode(on bool) { + if on { + io.WriteString(t.c, "\x1b[?2004h") + } else { + io.WriteString(t.c, "\x1b[?2004l") + } +} + +// stRingBuffer is a ring buffer of strings. +type stRingBuffer struct { + // entries contains max elements. + entries []string + max int + // head contains the index of the element most recently added to the ring. + head int + // size contains the number of elements in the ring. + size int +} + +func (s *stRingBuffer) Add(a string) { + if s.entries == nil { + const defaultNumEntries = 100 + s.entries = make([]string, defaultNumEntries) + s.max = defaultNumEntries + } + + s.head = (s.head + 1) % s.max + s.entries[s.head] = a + if s.size < s.max { + s.size++ + } +} + +// NthPreviousEntry returns the value passed to the nth previous call to Add. +// If n is zero then the immediately prior value is returned, if one, then the +// next most recent, and so on. If such an element doesn't exist then ok is +// false. +func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { + if n >= s.size { + return "", false + } + index := s.head - n + if index < 0 { + index += s.max + } + return s.entries[index], true +} + +// readPasswordLine reads from reader until it finds \n or io.EOF. +// The slice returned does not include the \n. +// readPasswordLine also ignores any \r it finds. +func readPasswordLine(reader io.Reader) ([]byte, error) { + var buf [1]byte + var ret []byte + + for { + n, err := reader.Read(buf[:]) + if n > 0 { + switch buf[0] { + case '\n': + return ret, nil + case '\r': + // remove \r from passwords on Windows + default: + ret = append(ret, buf[0]) + } + continue + } + if err != nil { + if err == io.EOF && len(ret) > 0 { + return ret, nil + } + return ret, err + } + } +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go new file mode 100644 index 000000000..d01919614 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go @@ -0,0 +1,119 @@ +// Copyright 2011 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 darwin dragonfly freebsd linux,!appengine netbsd openbsd + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal // import "golang.org/x/crypto/ssh/terminal" + +import ( + "syscall" + "unsafe" +) + +// State contains the state of a terminal. +type State struct { + termios syscall.Termios +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + + newState := oldState.termios + // This attempts to replicate the behaviour documented for cfmakeraw in + // the termios(3) manpage. + newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON + newState.Oflag &^= syscall.OPOST + newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN + newState.Cflag &^= syscall.CSIZE | syscall.PARENB + newState.Cflag |= syscall.CS8 + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { + return nil, err + } + + return &oldState, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + var oldState State + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 { + return nil, err + } + + return &oldState, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0); err != 0 { + return err + } + return nil +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + var dimensions [4]uint16 + + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 { + return -1, -1, err + } + return int(dimensions[1]), int(dimensions[0]), nil +} + +// passwordReader is an io.Reader that reads from a specific file descriptor. +type passwordReader int + +func (r passwordReader) Read(buf []byte) (int, error) { + return syscall.Read(int(r), buf) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + var oldState syscall.Termios + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 { + return nil, err + } + + newState := oldState + newState.Lflag &^= syscall.ECHO + newState.Lflag |= syscall.ICANON | syscall.ISIG + newState.Iflag |= syscall.ICRNL + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { + return nil, err + } + + defer func() { + syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0) + }() + + return readPasswordLine(passwordReader(fd)) +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go new file mode 100644 index 000000000..9c1ffd145 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go @@ -0,0 +1,12 @@ +// 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. + +// +build darwin dragonfly freebsd netbsd openbsd + +package terminal + +import "syscall" + +const ioctlReadTermios = syscall.TIOCGETA +const ioctlWriteTermios = syscall.TIOCSETA diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go new file mode 100644 index 000000000..5883b22d7 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go @@ -0,0 +1,11 @@ +// 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 terminal + +// These constants are declared here, rather than importing +// them from the syscall package as some syscall packages, even +// on linux, for example gccgo, do not declare them. +const ioctlReadTermios = 0x5401 // syscall.TCGETS +const ioctlWriteTermios = 0x5402 // syscall.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go new file mode 100644 index 000000000..799f049f0 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go @@ -0,0 +1,58 @@ +// 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 terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal + +import ( + "fmt" + "runtime" +) + +type State struct{} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + return false +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go new file mode 100644 index 000000000..07eb5edd7 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go @@ -0,0 +1,73 @@ +// Copyright 2015 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 solaris + +package terminal // import "golang.org/x/crypto/ssh/terminal" + +import ( + "golang.org/x/sys/unix" + "io" + "syscall" +) + +// State contains the state of a terminal. +type State struct { + termios syscall.Termios +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + // see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c + var termio unix.Termio + err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio) + return err == nil +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + // see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c + val, err := unix.IoctlGetTermios(fd, unix.TCGETS) + if err != nil { + return nil, err + } + oldState := *val + + newState := oldState + newState.Lflag &^= syscall.ECHO + newState.Lflag |= syscall.ICANON | syscall.ISIG + newState.Iflag |= syscall.ICRNL + err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState) + if err != nil { + return nil, err + } + + defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState) + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(fd, buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go new file mode 100644 index 000000000..e0a1f36ce --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -0,0 +1,155 @@ +// Copyright 2011 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 windows + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal + +import ( + "syscall" + "unsafe" +) + +const ( + enableLineInput = 2 + enableEchoInput = 4 + enableProcessedInput = 1 + enableWindowInput = 8 + enableMouseInput = 16 + enableInsertMode = 32 + enableQuickEditMode = 64 + enableExtendedFlags = 128 + enableAutoPosition = 256 + enableProcessedOutput = 1 + enableWrapAtEolOutput = 2 +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + +var ( + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") +) + +type ( + short int16 + word uint16 + + coord struct { + x short + y short + } + smallRect struct { + left short + top short + right short + bottom short + } + consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord + } +) + +type State struct { + mode uint32 +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) + _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0) + if e != 0 { + return nil, error(e) + } + return &State{st}, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + return &State{st}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0) + return err +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + var info consoleScreenBufferInfo + _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) + if e != 0 { + return 0, 0, error(e) + } + return int(info.size.x), int(info.size.y), nil +} + +// passwordReader is an io.Reader that reads from a specific Windows HANDLE. +type passwordReader int + +func (r passwordReader) Read(buf []byte) (int, error) { + return syscall.Read(syscall.Handle(r), buf) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + old := st + + st &^= (enableEchoInput) + st |= (enableProcessedInput | enableLineInput | enableProcessedOutput) + _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) + if e != 0 { + return nil, error(e) + } + + defer func() { + syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0) + }() + + return readPasswordLine(passwordReader(fd)) +}