From 301a08af9567e6468a2c4f96524c7011fa7757b9 Mon Sep 17 00:00:00 2001 From: Avdhesh Kumar Date: Tue, 8 Aug 2023 14:43:41 +0530 Subject: [PATCH 1/2] fix: git sensor processes spawn --- go.mod | 4 +- go.sum | 20 +- pkg/git/Bean.go | 2 +- pkg/git/GitCliUtil.go | 3 +- pkg/git/RepositoryManager.go | 7 +- pkg/git/Watcher.go | 2 +- .../devtron-labs/go-git}/LICENSE | 0 .../devtron-labs/go-git}/blame.go | 6 +- .../devtron-labs/go-git/blame_test.go | 551 ++++ .../devtron-labs/go-git}/common.go | 0 .../devtron-labs/go-git/common_test.go | 170 ++ .../devtron-labs/go-git}/config/branch.go | 4 +- .../devtron-labs/go-git}/config/config.go | 4 +- .../devtron-labs/go-git}/config/modules.go | 2 +- .../devtron-labs/go-git}/config/refspec.go | 2 +- .../devtron-labs/go-git}/doc.go | 2 +- .../devtron-labs/go-git/example_test.go | 166 + .../devtron-labs/go-git}/internal/url/url.go | 0 .../devtron-labs/go-git}/object_walker.go | 8 +- .../devtron-labs/go-git}/options.go | 10 +- .../devtron-labs/go-git/options_test.go | 35 + .../devtron-labs/go-git}/plumbing/error.go | 0 .../go-git}/plumbing/filemode/filemode.go | 0 .../go-git}/plumbing/format/config/common.go | 0 .../go-git}/plumbing/format/config/decoder.go | 0 .../go-git}/plumbing/format/config/doc.go | 0 .../go-git}/plumbing/format/config/encoder.go | 0 .../go-git}/plumbing/format/config/option.go | 0 .../go-git}/plumbing/format/config/section.go | 0 .../go-git}/plumbing/format/diff/patch.go | 4 +- .../plumbing/format/diff/unified_encoder.go | 6 +- .../go-git}/plumbing/format/index/decoder.go | 4 +- .../go-git}/plumbing/format/index/doc.go | 0 .../go-git}/plumbing/format/index/encoder.go | 2 +- .../go-git}/plumbing/format/index/index.go | 8 +- .../go-git}/plumbing/format/index/match.go | 0 .../plumbing/format/pktline/encoder.go | 0 .../plumbing/format/pktline/scanner.go | 0 .../devtron-labs/go-git}/plumbing/hash.go | 0 .../devtron-labs/go-git}/plumbing/memory.go | 0 .../devtron-labs/go-git}/plumbing/object.go | 0 .../go-git}/plumbing/object/blob.go | 6 +- .../go-git}/plumbing/object/change.go | 2 +- .../go-git}/plumbing/object/change_adaptor.go | 4 +- .../go-git}/plumbing/object/commit.go | 6 +- .../go-git}/plumbing/object/commit_walker.go | 6 +- .../plumbing/object/commit_walker_bfs.go | 4 +- .../object/commit_walker_bfs_filtered.go | 5 +- .../plumbing/object/commit_walker_ctime.go | 4 +- .../plumbing/object/commit_walker_file.go | 4 +- .../go-git}/plumbing/object/common.go | 0 .../go-git}/plumbing/object/difftree.go | 4 +- .../go-git}/plumbing/object/file.go | 8 +- .../go-git}/plumbing/object/merge_base.go | 4 +- .../go-git}/plumbing/object/object.go | 28 +- .../go-git}/plumbing/object/patch.go | 8 +- .../go-git}/plumbing/object/tag.go | 6 +- .../go-git}/plumbing/object/tree.go | 8 +- .../go-git}/plumbing/object/treenoder.go | 6 +- .../plumbing/protocol/packp/advrefs.go | 20 +- .../plumbing/protocol/packp/advrefs_decode.go | 4 +- .../plumbing/protocol/packp/advrefs_encode.go | 6 +- .../protocol/packp/capability/capability.go | 0 .../protocol/packp/capability/list.go | 0 .../go-git}/plumbing/protocol/packp/common.go | 0 .../go-git}/plumbing/protocol/packp/doc.go | 0 .../plumbing/protocol/packp/report_status.go | 4 +- .../plumbing/protocol/packp/shallowupd.go | 4 +- .../protocol/packp/sideband/common.go | 0 .../plumbing/protocol/packp/sideband/demux.go | 2 +- .../plumbing/protocol/packp/sideband/doc.go | 0 .../plumbing/protocol/packp/sideband/muxer.go | 2 +- .../plumbing/protocol/packp/srvresp.go | 4 +- .../go-git}/plumbing/protocol/packp/ulreq.go | 4 +- .../plumbing/protocol/packp/ulreq_decode.go | 4 +- .../plumbing/protocol/packp/ulreq_encode.go | 4 +- .../go-git}/plumbing/protocol/packp/updreq.go | 7 +- .../plumbing/protocol/packp/updreq_decode.go | 4 +- .../plumbing/protocol/packp/updreq_encode.go | 6 +- .../plumbing/protocol/packp/uppackreq.go | 6 +- .../plumbing/protocol/packp/uppackresp.go | 4 +- .../go-git}/plumbing/reference.go | 0 .../devtron-labs/go-git}/plumbing/revision.go | 0 .../go-git}/plumbing/storer/doc.go | 0 .../go-git}/plumbing/storer/index.go | 2 +- .../go-git}/plumbing/storer/object.go | 2 +- .../go-git}/plumbing/storer/reference.go | 2 +- .../go-git}/plumbing/storer/shallow.go | 2 +- .../go-git}/plumbing/storer/storer.go | 0 .../go-git}/plumbing/transport/common.go | 8 +- .../devtron-labs/go-git}/prune.go | 4 +- .../devtron-labs/go-git/prune_test.go | 75 + .../devtron-labs/go-git}/references.go | 6 +- .../devtron-labs/go-git/references_test.go | 401 +++ .../devtron-labs/go-git}/remote.go | 32 +- .../devtron-labs/go-git/remote_test.go | 889 ++++++ .../devtron-labs/go-git}/repository.go | 84 +- .../devtron-labs/go-git/repository_test.go | 2695 +++++++++++++++++ .../go-git/repository_unix_test.go | 11 + .../go-git/repository_windows_test.go | 9 + .../devtron-labs/go-git}/status.go | 0 .../go-git}/storage/memory/storage.go | 10 +- .../devtron-labs/go-git}/storage/storer.go | 6 +- .../devtron-labs/go-git}/submodule.go | 6 +- .../devtron-labs/go-git/submodule_test.go | 236 ++ .../devtron-labs/go-git}/utils/binary/read.go | 9 +- .../go-git}/utils/binary/write.go | 0 .../devtron-labs/go-git}/utils/diff/diff.go | 0 .../go-git}/utils/ioutil/common.go | 0 .../go-git}/utils/merkletrie/change.go | 2 +- .../go-git}/utils/merkletrie/difftree.go | 2 +- .../go-git}/utils/merkletrie/doc.go | 0 .../go-git}/utils/merkletrie/doubleiter.go | 2 +- .../utils/merkletrie/internal/frame/frame.go | 7 +- .../go-git}/utils/merkletrie/iter.go | 21 +- .../go-git}/utils/merkletrie/noder/noder.go | 0 .../go-git}/utils/merkletrie/noder/path.go | 0 .../devtron-labs/go-git}/worktree.go | 18 +- .../devtron-labs/go-git}/worktree_bsd.go | 3 +- .../devtron-labs/go-git}/worktree_commit.go | 10 +- .../go-git/worktree_commit_test.go | 369 +++ .../devtron-labs/go-git}/worktree_linux.go | 3 +- .../devtron-labs/go-git}/worktree_status.go | 20 +- .../devtron-labs/go-git/worktree_test.go | 2008 ++++++++++++ .../go-git}/worktree_unix_other.go | 3 +- .../devtron-labs/go-git}/worktree_windows.go | 3 +- .../kevinburke/ssh_config/.gitattributes | 1 - .../kevinburke/ssh_config/.gitignore | 0 .../github.com/kevinburke/ssh_config/.mailmap | 1 - .../kevinburke/ssh_config/.travis.yml | 14 - .../kevinburke/ssh_config/AUTHORS.txt | 5 - .../github.com/kevinburke/ssh_config/LICENSE | 49 - .../github.com/kevinburke/ssh_config/Makefile | 30 - .../kevinburke/ssh_config/README.md | 81 - .../kevinburke/ssh_config/config.go | 649 ---- .../github.com/kevinburke/ssh_config/lexer.go | 240 -- .../kevinburke/ssh_config/parser.go | 191 -- .../kevinburke/ssh_config/position.go | 25 - .../github.com/kevinburke/ssh_config/token.go | 49 - .../kevinburke/ssh_config/validators.go | 162 - .../github.com/mitchellh/go-homedir/LICENSE | 21 - .../github.com/mitchellh/go-homedir/README.md | 14 - .../mitchellh/go-homedir/homedir.go | 167 - .../sergi/go-diff/diffmatchpatch/diff.go | 135 +- .../sergi/go-diff/diffmatchpatch/patch.go | 2 +- .../go-diff/diffmatchpatch/stringutil.go | 18 + vendor/github.com/xanzy/ssh-agent/.gitignore | 24 - vendor/github.com/xanzy/ssh-agent/LICENSE | 202 -- vendor/github.com/xanzy/ssh-agent/README.md | 23 - .../xanzy/ssh-agent/pageant_windows.go | 146 - vendor/github.com/xanzy/ssh-agent/sshagent.go | 49 - .../xanzy/ssh-agent/sshagent_windows.go | 80 - vendor/golang.org/x/crypto/blowfish/block.go | 159 - vendor/golang.org/x/crypto/blowfish/cipher.go | 99 - vendor/golang.org/x/crypto/blowfish/const.go | 199 -- .../x/crypto/chacha20/chacha_arm64.go | 17 - .../x/crypto/chacha20/chacha_arm64.s | 308 -- .../x/crypto/chacha20/chacha_generic.go | 398 --- .../x/crypto/chacha20/chacha_noasm.go | 14 - .../x/crypto/chacha20/chacha_ppc64le.go | 17 - .../x/crypto/chacha20/chacha_ppc64le.s | 450 --- .../x/crypto/chacha20/chacha_s390x.go | 28 - .../x/crypto/chacha20/chacha_s390x.s | 225 -- vendor/golang.org/x/crypto/chacha20/xor.go | 42 - .../x/crypto/curve25519/curve25519.go | 146 - .../x/crypto/curve25519/internal/field/README | 7 - .../x/crypto/curve25519/internal/field/fe.go | 416 --- .../curve25519/internal/field/fe_amd64.go | 16 - .../curve25519/internal/field/fe_amd64.s | 379 --- .../internal/field/fe_amd64_noasm.go | 12 - .../curve25519/internal/field/fe_arm64.go | 16 - .../curve25519/internal/field/fe_arm64.s | 43 - .../internal/field/fe_arm64_noasm.go | 12 - .../curve25519/internal/field/fe_generic.go | 264 -- .../curve25519/internal/field/sync.checkpoint | 1 - .../crypto/curve25519/internal/field/sync.sh | 19 - .../x/crypto/internal/poly1305/bits_compat.go | 40 - .../x/crypto/internal/poly1305/bits_go1.13.go | 22 - .../x/crypto/internal/poly1305/mac_noasm.go | 10 - .../x/crypto/internal/poly1305/poly1305.go | 99 - .../x/crypto/internal/poly1305/sum_amd64.go | 48 - .../x/crypto/internal/poly1305/sum_amd64.s | 109 - .../x/crypto/internal/poly1305/sum_generic.go | 309 -- .../x/crypto/internal/poly1305/sum_ppc64le.go | 48 - .../x/crypto/internal/poly1305/sum_ppc64le.s | 182 -- .../x/crypto/internal/poly1305/sum_s390x.go | 77 - .../x/crypto/internal/poly1305/sum_s390x.s | 504 --- .../x/crypto/internal/subtle/aliasing.go | 33 - .../crypto/internal/subtle/aliasing_purego.go | 36 - .../golang.org/x/crypto/ssh/agent/client.go | 847 ------ .../golang.org/x/crypto/ssh/agent/forward.go | 103 - .../golang.org/x/crypto/ssh/agent/keyring.go | 241 -- .../golang.org/x/crypto/ssh/agent/server.go | 570 ---- vendor/golang.org/x/crypto/ssh/buffer.go | 97 - vendor/golang.org/x/crypto/ssh/certs.go | 589 ---- vendor/golang.org/x/crypto/ssh/channel.go | 633 ---- vendor/golang.org/x/crypto/ssh/cipher.go | 789 ----- vendor/golang.org/x/crypto/ssh/client.go | 282 -- vendor/golang.org/x/crypto/ssh/client_auth.go | 725 ----- vendor/golang.org/x/crypto/ssh/common.go | 430 --- vendor/golang.org/x/crypto/ssh/connection.go | 143 - vendor/golang.org/x/crypto/ssh/doc.go | 22 - vendor/golang.org/x/crypto/ssh/handshake.go | 704 ----- .../ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go | 93 - vendor/golang.org/x/crypto/ssh/kex.go | 774 ----- vendor/golang.org/x/crypto/ssh/keys.go | 1447 --------- .../x/crypto/ssh/knownhosts/knownhosts.go | 540 ---- vendor/golang.org/x/crypto/ssh/mac.go | 61 - vendor/golang.org/x/crypto/ssh/messages.go | 877 ------ vendor/golang.org/x/crypto/ssh/mux.go | 351 --- vendor/golang.org/x/crypto/ssh/server.go | 752 ----- vendor/golang.org/x/crypto/ssh/session.go | 648 ---- vendor/golang.org/x/crypto/ssh/ssh_gss.go | 139 - vendor/golang.org/x/crypto/ssh/streamlocal.go | 116 - vendor/golang.org/x/crypto/ssh/tcpip.go | 474 --- vendor/golang.org/x/crypto/ssh/transport.go | 357 --- .../golang.org/x/net/internal/socks/client.go | 168 - .../golang.org/x/net/internal/socks/socks.go | 317 -- vendor/golang.org/x/net/proxy/dial.go | 54 - vendor/golang.org/x/net/proxy/direct.go | 31 - vendor/golang.org/x/net/proxy/per_host.go | 155 - vendor/golang.org/x/net/proxy/proxy.go | 149 - vendor/golang.org/x/net/proxy/socks5.go | 42 - vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 18 - vendor/golang.org/x/sys/cpu/byteorder.go | 66 - vendor/golang.org/x/sys/cpu/cpu.go | 287 -- vendor/golang.org/x/sys/cpu/cpu_aix.go | 34 - vendor/golang.org/x/sys/cpu/cpu_arm.go | 73 - vendor/golang.org/x/sys/cpu/cpu_arm64.go | 172 -- vendor/golang.org/x/sys/cpu/cpu_arm64.s | 32 - vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 12 - vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 22 - vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 17 - .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 12 - .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 23 - vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c | 38 - vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 33 - vendor/golang.org/x/sys/cpu/cpu_linux.go | 16 - vendor/golang.org/x/sys/cpu/cpu_linux_arm.go | 39 - .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 71 - .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 24 - .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 10 - .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 32 - .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 40 - vendor/golang.org/x/sys/cpu/cpu_loong64.go | 13 - vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 16 - vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 12 - .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 -- vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 10 - .../golang.org/x/sys/cpu/cpu_other_arm64.go | 10 - .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 13 - .../golang.org/x/sys/cpu/cpu_other_riscv64.go | 12 - vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 17 - vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 12 - vendor/golang.org/x/sys/cpu/cpu_s390x.go | 172 -- vendor/golang.org/x/sys/cpu/cpu_s390x.s | 58 - vendor/golang.org/x/sys/cpu/cpu_wasm.go | 18 - vendor/golang.org/x/sys/cpu/cpu_x86.go | 145 - vendor/golang.org/x/sys/cpu/cpu_x86.s | 28 - vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 - vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 - vendor/golang.org/x/sys/cpu/hwcap_linux.go | 56 - .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 27 - .../x/sys/cpu/syscall_aix_ppc64_gc.go | 36 - vendor/gopkg.in/src-d/go-billy.v4/.gitignore | 4 - vendor/gopkg.in/src-d/go-billy.v4/.travis.yml | 17 - vendor/gopkg.in/src-d/go-billy.v4/DCO | 25 - vendor/gopkg.in/src-d/go-billy.v4/LICENSE | 201 -- vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS | 1 - vendor/gopkg.in/src-d/go-billy.v4/Makefile | 25 - vendor/gopkg.in/src-d/go-billy.v4/README.md | 72 - .../gopkg.in/src-d/go-billy.v4/appveyor.yml | 15 - vendor/gopkg.in/src-d/go-billy.v4/fs.go | 202 -- .../src-d/go-billy.v4/helper/chroot/chroot.go | 242 -- .../go-billy.v4/helper/polyfill/polyfill.go | 105 - vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go | 139 - .../src-d/go-billy.v4/osfs/os_posix.go | 21 - .../src-d/go-billy.v4/osfs/os_windows.go | 57 - .../gopkg.in/src-d/go-billy.v4/util/glob.go | 111 - .../gopkg.in/src-d/go-billy.v4/util/util.go | 224 -- vendor/gopkg.in/src-d/go-git.v4/.gitignore | 4 - vendor/gopkg.in/src-d/go-git.v4/.travis.yml | 37 - .../src-d/go-git.v4/CODE_OF_CONDUCT.md | 74 - .../gopkg.in/src-d/go-git.v4/COMPATIBILITY.md | 111 - .../gopkg.in/src-d/go-git.v4/CONTRIBUTING.md | 59 - vendor/gopkg.in/src-d/go-git.v4/DCO | 36 - vendor/gopkg.in/src-d/go-git.v4/MAINTAINERS | 3 - vendor/gopkg.in/src-d/go-git.v4/Makefile | 52 - vendor/gopkg.in/src-d/go-git.v4/README.md | 123 - vendor/gopkg.in/src-d/go-git.v4/appveyor.yml | 21 - .../go-git.v4/internal/revision/parser.go | 622 ---- .../go-git.v4/internal/revision/scanner.go | 117 - .../go-git.v4/internal/revision/token.go | 28 - .../go-git.v4/plumbing/cache/buffer_lru.go | 98 - .../src-d/go-git.v4/plumbing/cache/common.go | 39 - .../go-git.v4/plumbing/cache/object_lru.go | 101 - .../plumbing/format/gitignore/dir.go | 136 - .../plumbing/format/gitignore/doc.go | 70 - .../plumbing/format/gitignore/matcher.go | 30 - .../plumbing/format/gitignore/pattern.go | 153 - .../plumbing/format/idxfile/decoder.go | 177 -- .../go-git.v4/plumbing/format/idxfile/doc.go | 128 - .../plumbing/format/idxfile/encoder.go | 142 - .../plumbing/format/idxfile/idxfile.go | 346 --- .../plumbing/format/idxfile/writer.go | 186 -- .../go-git.v4/plumbing/format/objfile/doc.go | 2 - .../plumbing/format/objfile/reader.go | 114 - .../plumbing/format/objfile/writer.go | 109 - .../plumbing/format/packfile/common.go | 78 - .../plumbing/format/packfile/delta_index.go | 297 -- .../format/packfile/delta_selector.go | 369 --- .../plumbing/format/packfile/diff_delta.go | 200 -- .../go-git.v4/plumbing/format/packfile/doc.go | 39 - .../plumbing/format/packfile/encoder.go | 219 -- .../plumbing/format/packfile/error.go | 30 - .../plumbing/format/packfile/fsobject.go | 116 - .../plumbing/format/packfile/object_pack.go | 164 - .../plumbing/format/packfile/packfile.go | 562 ---- .../plumbing/format/packfile/parser.go | 483 --- .../plumbing/format/packfile/patch_delta.go | 229 -- .../plumbing/format/packfile/scanner.go | 466 --- .../go-git.v4/plumbing/revlist/revlist.go | 230 -- .../plumbing/transport/client/client.go | 48 - .../plumbing/transport/file/client.go | 156 - .../plumbing/transport/file/server.go | 53 - .../plumbing/transport/git/common.go | 109 - .../plumbing/transport/http/common.go | 281 -- .../plumbing/transport/http/receive_pack.go | 106 - .../plumbing/transport/http/upload_pack.go | 123 - .../transport/internal/common/common.go | 467 --- .../transport/internal/common/server.go | 73 - .../plumbing/transport/server/loader.go | 64 - .../plumbing/transport/server/server.go | 422 --- .../plumbing/transport/ssh/auth_method.go | 322 -- .../plumbing/transport/ssh/common.go | 228 -- .../go-git.v4/storage/filesystem/config.go | 61 - .../storage/filesystem/deltaobject.go | 37 - .../storage/filesystem/dotgit/dotgit.go | 1099 ------- .../dotgit/dotgit_rewrite_packed_refs.go | 81 - .../filesystem/dotgit/dotgit_setref.go | 90 - .../storage/filesystem/dotgit/writers.go | 284 -- .../go-git.v4/storage/filesystem/index.go | 54 - .../go-git.v4/storage/filesystem/module.go | 20 - .../go-git.v4/storage/filesystem/object.go | 815 ----- .../go-git.v4/storage/filesystem/reference.go | 44 - .../go-git.v4/storage/filesystem/shallow.go | 54 - .../go-git.v4/storage/filesystem/storage.go | 73 - .../utils/merkletrie/filesystem/node.go | 196 -- .../go-git.v4/utils/merkletrie/index/node.go | 90 - vendor/modules.txt | 90 +- 350 files changed, 8008 insertions(+), 36609 deletions(-) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/LICENSE (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/blame.go (98%) create mode 100644 vendor/github.com/devtron-labs/go-git/blame_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/common.go (100%) create mode 100644 vendor/github.com/devtron-labs/go-git/common_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/config/branch.go (94%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/config/config.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/config/modules.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/config/refspec.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/doc.go (89%) create mode 100644 vendor/github.com/devtron-labs/go-git/example_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/internal/url/url.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/object_walker.go (93%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/options.go (98%) create mode 100644 vendor/github.com/devtron-labs/go-git/options_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/error.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/filemode/filemode.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/config/common.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/config/decoder.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/config/doc.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/config/encoder.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/config/option.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/config/section.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/diff/patch.go (94%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/diff/unified_encoder.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/index/decoder.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/index/doc.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/index/encoder.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/index/index.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/index/match.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/pktline/encoder.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/format/pktline/scanner.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/hash.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/memory.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/blob.go (95%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/change.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/change_adaptor.go (91%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/commit.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/commit_walker.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/commit_walker_bfs.go (95%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/commit_walker_bfs_filtered.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/commit_walker_ctime.go (95%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/commit_walker_file.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/common.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/difftree.go (88%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/file.go (93%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/merge_base.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/object.go (94%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/patch.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/tag.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/tree.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/object/treenoder.go (95%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/advrefs.go (88%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/advrefs_decode.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/advrefs_encode.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/capability/capability.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/capability/list.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/common.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/doc.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/report_status.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/shallowupd.go (94%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/sideband/common.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/sideband/demux.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/sideband/doc.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/sideband/muxer.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/srvresp.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/ulreq.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/ulreq_decode.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/ulreq_encode.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/updreq.go (93%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/updreq_decode.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/updreq_encode.go (88%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/uppackreq.go (93%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/protocol/packp/uppackresp.go (95%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/reference.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/revision.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/storer/doc.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/storer/index.go (71%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/storer/object.go (99%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/storer/reference.go (99%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/storer/shallow.go (84%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/storer/storer.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/plumbing/transport/common.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/prune.go (94%) create mode 100644 vendor/github.com/devtron-labs/go-git/prune_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/references.go (98%) create mode 100644 vendor/github.com/devtron-labs/go-git/references_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/remote.go (96%) create mode 100644 vendor/github.com/devtron-labs/go-git/remote_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/repository.go (96%) create mode 100644 vendor/github.com/devtron-labs/go-git/repository_test.go create mode 100644 vendor/github.com/devtron-labs/go-git/repository_unix_test.go create mode 100644 vendor/github.com/devtron-labs/go-git/repository_windows_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/status.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/storage/memory/storage.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/storage/storer.go (79%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/submodule.go (98%) create mode 100644 vendor/github.com/devtron-labs/go-git/submodule_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/binary/read.go (96%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/binary/write.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/diff/diff.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/ioutil/common.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/change.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/difftree.go (99%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/doc.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/doubleiter.go (98%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/internal/frame/frame.go (95%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/iter.go (94%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/noder/noder.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/utils/merkletrie/noder/path.go (100%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree.go (97%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree_bsd.go (82%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree_commit.go (95%) create mode 100644 vendor/github.com/devtron-labs/go-git/worktree_commit_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree_linux.go (84%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree_status.go (96%) create mode 100644 vendor/github.com/devtron-labs/go-git/worktree_test.go rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree_unix_other.go (81%) rename vendor/{gopkg.in/src-d/go-git.v4 => github.com/devtron-labs/go-git}/worktree_windows.go (90%) delete mode 100644 vendor/github.com/kevinburke/ssh_config/.gitattributes delete mode 100644 vendor/github.com/kevinburke/ssh_config/.gitignore delete mode 100644 vendor/github.com/kevinburke/ssh_config/.mailmap delete mode 100644 vendor/github.com/kevinburke/ssh_config/.travis.yml delete mode 100644 vendor/github.com/kevinburke/ssh_config/AUTHORS.txt delete mode 100644 vendor/github.com/kevinburke/ssh_config/LICENSE delete mode 100644 vendor/github.com/kevinburke/ssh_config/Makefile delete mode 100644 vendor/github.com/kevinburke/ssh_config/README.md delete mode 100644 vendor/github.com/kevinburke/ssh_config/config.go delete mode 100644 vendor/github.com/kevinburke/ssh_config/lexer.go delete mode 100644 vendor/github.com/kevinburke/ssh_config/parser.go delete mode 100644 vendor/github.com/kevinburke/ssh_config/position.go delete mode 100644 vendor/github.com/kevinburke/ssh_config/token.go delete mode 100644 vendor/github.com/kevinburke/ssh_config/validators.go delete mode 100644 vendor/github.com/mitchellh/go-homedir/LICENSE delete mode 100644 vendor/github.com/mitchellh/go-homedir/README.md delete mode 100644 vendor/github.com/mitchellh/go-homedir/homedir.go delete mode 100644 vendor/github.com/xanzy/ssh-agent/.gitignore delete mode 100644 vendor/github.com/xanzy/ssh-agent/LICENSE delete mode 100644 vendor/github.com/xanzy/ssh-agent/README.md delete mode 100644 vendor/github.com/xanzy/ssh-agent/pageant_windows.go delete mode 100644 vendor/github.com/xanzy/ssh-agent/sshagent.go delete mode 100644 vendor/github.com/xanzy/ssh-agent/sshagent_windows.go delete mode 100644 vendor/golang.org/x/crypto/blowfish/block.go delete mode 100644 vendor/golang.org/x/crypto/blowfish/cipher.go delete mode 100644 vendor/golang.org/x/crypto/blowfish/const.go delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.go delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.s delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_generic.go delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_noasm.go delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.go delete mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.s delete mode 100644 vendor/golang.org/x/crypto/chacha20/xor.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/README delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/poly1305.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go delete mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s delete mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing.go delete mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go delete mode 100644 vendor/golang.org/x/crypto/ssh/agent/client.go delete mode 100644 vendor/golang.org/x/crypto/ssh/agent/forward.go delete mode 100644 vendor/golang.org/x/crypto/ssh/agent/keyring.go delete mode 100644 vendor/golang.org/x/crypto/ssh/agent/server.go delete mode 100644 vendor/golang.org/x/crypto/ssh/buffer.go delete mode 100644 vendor/golang.org/x/crypto/ssh/certs.go delete mode 100644 vendor/golang.org/x/crypto/ssh/channel.go delete mode 100644 vendor/golang.org/x/crypto/ssh/cipher.go delete mode 100644 vendor/golang.org/x/crypto/ssh/client.go delete mode 100644 vendor/golang.org/x/crypto/ssh/client_auth.go delete mode 100644 vendor/golang.org/x/crypto/ssh/common.go delete mode 100644 vendor/golang.org/x/crypto/ssh/connection.go delete mode 100644 vendor/golang.org/x/crypto/ssh/doc.go delete mode 100644 vendor/golang.org/x/crypto/ssh/handshake.go delete mode 100644 vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go delete mode 100644 vendor/golang.org/x/crypto/ssh/kex.go delete mode 100644 vendor/golang.org/x/crypto/ssh/keys.go delete mode 100644 vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go delete mode 100644 vendor/golang.org/x/crypto/ssh/mac.go delete mode 100644 vendor/golang.org/x/crypto/ssh/messages.go delete mode 100644 vendor/golang.org/x/crypto/ssh/mux.go delete mode 100644 vendor/golang.org/x/crypto/ssh/server.go delete mode 100644 vendor/golang.org/x/crypto/ssh/session.go delete mode 100644 vendor/golang.org/x/crypto/ssh/ssh_gss.go delete mode 100644 vendor/golang.org/x/crypto/ssh/streamlocal.go delete mode 100644 vendor/golang.org/x/crypto/ssh/tcpip.go delete mode 100644 vendor/golang.org/x/crypto/ssh/transport.go delete mode 100644 vendor/golang.org/x/net/internal/socks/client.go delete mode 100644 vendor/golang.org/x/net/internal/socks/socks.go delete mode 100644 vendor/golang.org/x/net/proxy/dial.go delete mode 100644 vendor/golang.org/x/net/proxy/direct.go delete mode 100644 vendor/golang.org/x/net/proxy/per_host.go delete mode 100644 vendor/golang.org/x/net/proxy/proxy.go delete mode 100644 vendor/golang.org/x/net/proxy/socks5.go delete mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s delete mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.s delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_riscv64.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go delete mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go delete mode 100644 vendor/golang.org/x/sys/cpu/hwcap_linux.go delete mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go delete mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/.gitignore delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/.travis.yml delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/DCO delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/LICENSE delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/Makefile delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/README.md delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/fs.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/util/glob.go delete mode 100644 vendor/gopkg.in/src-d/go-billy.v4/util/util.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/.gitignore delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/.travis.yml delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/CODE_OF_CONDUCT.md delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/COMPATIBILITY.md delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/CONTRIBUTING.md delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/DCO delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/MAINTAINERS delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/Makefile delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/README.md delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/appveyor.yml delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/internal/revision/parser.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/internal/revision/scanner.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/internal/revision/token.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/buffer_lru.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/common.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/dir.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/doc.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/matcher.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/pattern.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/decoder.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/doc.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/encoder.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/idxfile.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/writer.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/doc.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/reader.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/writer.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_index.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_selector.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/diff_delta.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/doc.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/encoder.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/error.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/object_pack.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/patch_delta.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/revlist/revlist.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/client/client.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/client.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/server.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/git/common.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/common.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/receive_pack.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/upload_pack.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/common.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/server.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/loader.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/server.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/auth_method.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/common.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/config.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/deltaobject.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/writers.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/index.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/module.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/reference.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/shallow.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem/node.go delete mode 100644 vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/index/node.go diff --git a/go.mod b/go.mod index 033f3489..d134f33b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.17 require ( github.com/caarlos0/env v3.5.0+incompatible github.com/devtron-labs/common-lib v0.0.0-20230109070754-ff4dca200a2c + github.com/devtron-labs/go-git v1.5.0 github.com/devtron-labs/protos v0.0.0-20230503113602-282404f70fd2 github.com/gammazero/workerpool v0.0.0-20200206003619-019d125201ab github.com/go-pg/pg v6.15.1+incompatible @@ -19,7 +20,6 @@ require ( go.uber.org/zap v1.21.0 google.golang.org/grpc v1.51.0 google.golang.org/protobuf v1.28.1 - gopkg.in/src-d/go-git.v4 v4.13.1 ) require ( @@ -47,7 +47,7 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.13.0 // indirect github.com/prometheus/procfs v0.1.3 // indirect - github.com/sergi/go-diff v1.1.0 // indirect + github.com/sergi/go-diff v1.3.0 // indirect github.com/src-d/gcfg v1.4.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/tidwall/match v1.0.3 // indirect diff --git a/go.sum b/go.sum index 9e18a4a5..23368068 100644 --- a/go.sum +++ b/go.sum @@ -82,7 +82,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -90,7 +89,6 @@ github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= @@ -139,6 +137,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/devtron-labs/common-lib v0.0.0-20230109070754-ff4dca200a2c h1:jz7yPUlIJXFg9AvJh2fb0QW7JT6+RKj8LOl1mWM/HQA= github.com/devtron-labs/common-lib v0.0.0-20230109070754-ff4dca200a2c/go.mod h1:R24nOqgk4buk9zv+BXzORfObZsOe3NE9P55KrZXGX9k= +github.com/devtron-labs/go-git v1.5.0 h1:7AX+lyFL4q2ZUQP7+D9QM/Tk2SInl9wV+nrkxzVcHUM= +github.com/devtron-labs/go-git v1.5.0/go.mod h1:FpAQlxsT69FB/iKtqI0FN9rvPnyU9as3viPPc3bBMq0= +github.com/devtron-labs/go-git-fixtures v0.1.5 h1:SGwaGpURP99quP3xmwGYYV7hVyYKCGdihsbPvE/kjMA= +github.com/devtron-labs/go-git-fixtures v0.1.5/go.mod h1:34narKKLDDS+SSsJ7Oo6Yc5mtfpjw5vyIpohCYhDzQk= github.com/devtron-labs/protos v0.0.0-20230503113602-282404f70fd2 h1:/IEIsJTxDZ3hv8uOoCaqdWCXqcv7nCAgX9AP/v84dUY= github.com/devtron-labs/protos v0.0.0-20230503113602-282404f70fd2/go.mod h1:l85jxWHlcSo910hdUfRycL40yGzC6glE93V1sVxVPto= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -171,7 +173,6 @@ github.com/gammazero/deque v0.0.0-20200124200322-7e84b94275b8/go.mod h1:D90+MBHV github.com/gammazero/workerpool v0.0.0-20200206003619-019d125201ab h1:BLCWHqLiTSzLZriw46b3HJLswyqY0E6B9y9tk4+7eFI= github.com/gammazero/workerpool v0.0.0-20200206003619-019d125201ab/go.mod h1:ZObaTlXZGgqKXhhlk+zNvSOXT+h6VGThA0ZQxLqn8x0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -426,7 +427,6 @@ github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -473,9 +473,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.0 h1:i3Oy7NmznCkiLOhlp9O92z4yadEJE2pWESZMJPBBBrk= +github.com/sergi/go-diff v1.3.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -494,7 +493,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -773,7 +771,6 @@ golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -808,7 +805,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1061,10 +1057,6 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= diff --git a/pkg/git/Bean.go b/pkg/git/Bean.go index fef898fe..8b9892ba 100644 --- a/pkg/git/Bean.go +++ b/pkg/git/Bean.go @@ -18,7 +18,7 @@ package git import ( "github.com/devtron-labs/git-sensor/internal/sql" - "gopkg.in/src-d/go-git.v4/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/object" "time" ) diff --git a/pkg/git/GitCliUtil.go b/pkg/git/GitCliUtil.go index 3dd3ca14..26389a23 100644 --- a/pkg/git/GitCliUtil.go +++ b/pkg/git/GitCliUtil.go @@ -2,9 +2,8 @@ package git import ( "fmt" + "github.com/devtron-labs/go-git/config" "go.uber.org/zap" - "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/config" "os" "os/exec" "strings" diff --git a/pkg/git/RepositoryManager.go b/pkg/git/RepositoryManager.go index 69f79d43..a50d5bb5 100644 --- a/pkg/git/RepositoryManager.go +++ b/pkg/git/RepositoryManager.go @@ -29,11 +29,10 @@ import ( "github.com/devtron-labs/git-sensor/internal/middleware" "github.com/devtron-labs/git-sensor/internal/sql" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/transport" "go.uber.org/zap" - "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/transport" ) type RepositoryManager interface { diff --git a/pkg/git/Watcher.go b/pkg/git/Watcher.go index d63cfe36..e4ad5dd1 100644 --- a/pkg/git/Watcher.go +++ b/pkg/git/Watcher.go @@ -25,10 +25,10 @@ import ( "github.com/devtron-labs/git-sensor/internal/middleware" "github.com/devtron-labs/git-sensor/internal/sql" "github.com/devtron-labs/git-sensor/util" + "github.com/devtron-labs/go-git/plumbing/object" "github.com/gammazero/workerpool" "github.com/robfig/cron/v3" "go.uber.org/zap" - "gopkg.in/src-d/go-git.v4/plumbing/object" "regexp" "strings" "time" diff --git a/vendor/gopkg.in/src-d/go-git.v4/LICENSE b/vendor/github.com/devtron-labs/go-git/LICENSE similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/LICENSE rename to vendor/github.com/devtron-labs/go-git/LICENSE diff --git a/vendor/gopkg.in/src-d/go-git.v4/blame.go b/vendor/github.com/devtron-labs/go-git/blame.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/blame.go rename to vendor/github.com/devtron-labs/go-git/blame.go index f6108519..3720d8c9 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/blame.go +++ b/vendor/github.com/devtron-labs/go-git/blame.go @@ -9,9 +9,9 @@ import ( "time" "unicode/utf8" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/utils/diff" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/utils/diff" ) // BlameResult represents the result of a Blame operation. diff --git a/vendor/github.com/devtron-labs/go-git/blame_test.go b/vendor/github.com/devtron-labs/go-git/blame_test.go new file mode 100644 index 00000000..797b7de1 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/blame_test.go @@ -0,0 +1,551 @@ +package git + +import ( + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/object" + + "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" +) + +type BlameSuite struct { + BaseSuite +} + +var _ = Suite(&BlameSuite{}) + +func (s *BlameSuite) TestNewLines(c *C) { + h := plumbing.NewHash("ce9f123d790717599aaeb76bc62510de437761be") + lines, err := newLines([]string{"foo"}, []*object.Commit{{ + Hash: h, + Message: "foo", + }}) + + c.Assert(err, IsNil) + c.Assert(lines, HasLen, 1) + c.Assert(lines[0].Text, Equals, "foo") + c.Assert(lines[0].Hash, Equals, h) +} + +func (s *BlameSuite) TestNewLinesWithNewLine(c *C) { + lines, err := newLines([]string{"foo"}, []*object.Commit{ + {Message: "foo"}, + {Message: "bar"}, + }) + + c.Assert(err, IsNil) + c.Assert(lines, HasLen, 2) + c.Assert(lines[0].Text, Equals, "foo") + c.Assert(lines[1].Text, Equals, "\n") +} + +type blameTest struct { + repo string + rev string + path string + blames []string // the commits blamed for each line +} + +// run a blame on all the suite's tests +func (s *BlameSuite) TestBlame(c *C) { + for _, t := range blameTests { + r := s.NewRepositoryFromPackfile(fixtures.ByURL(t.repo).One()) + + exp := s.mockBlame(c, t, r) + commit, err := r.CommitObject(plumbing.NewHash(t.rev)) + c.Assert(err, IsNil) + + obt, err := Blame(commit, t.path) + c.Assert(err, IsNil) + c.Assert(obt, DeepEquals, exp) + + for i, l := range obt.Lines { + c.Assert(l.Hash.String(), Equals, t.blames[i]) + } + } +} + +func (s *BlameSuite) mockBlame(c *C, t blameTest, r *Repository) (blame *BlameResult) { + commit, err := r.CommitObject(plumbing.NewHash(t.rev)) + c.Assert(err, IsNil, Commentf("%v: repo=%s, rev=%s", err, t.repo, t.rev)) + + f, err := commit.File(t.path) + c.Assert(err, IsNil) + lines, err := f.Lines() + c.Assert(err, IsNil) + c.Assert(len(t.blames), Equals, len(lines), Commentf( + "repo=%s, path=%s, rev=%s: the number of lines in the file and the number of expected blames differ (len(blames)=%d, len(lines)=%d)\nblames=%#q\nlines=%#q", t.repo, t.path, t.rev, len(t.blames), len(lines), t.blames, lines)) + + blamedLines := make([]*Line, 0, len(t.blames)) + for i := range t.blames { + commit, err := r.CommitObject(plumbing.NewHash(t.blames[i])) + c.Assert(err, IsNil) + l := &Line{ + Author: commit.Author.Email, + Text: lines[i], + Date: commit.Author.When, + Hash: commit.Hash, + } + blamedLines = append(blamedLines, l) + } + + return &BlameResult{ + Path: t.path, + Rev: plumbing.NewHash(t.rev), + Lines: blamedLines, + } +} + +// utility function to avoid writing so many repeated commits +func repeat(s string, n int) []string { + if n < 0 { + panic("repeat: n < 0") + } + r := make([]string, 0, n) + for i := 0; i < n; i++ { + r = append(r, s) + } + + return r +} + +// utility function to concat slices +func concat(vargs ...[]string) []string { + var r []string + for _, ss := range vargs { + r = append(r, ss...) + } + + return r +} + +var blameTests = [...]blameTest{ + // use the blame2humantest.bash script to easily add more tests. + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", concat( + repeat("35e85108805c84807bc66a02d91535e1e24b38b9", 285), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", concat( + repeat("b8e471f58bcbca63b07bda20e428190409c2db47", 1), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", concat( + repeat("918c48b83bd081e863dbe1b80f8998f058cd8294", 142), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", concat( + repeat("af2d6a6954d532f8ffb47615169c8fdf9d383a1a", 6492), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", concat( + repeat("af2d6a6954d532f8ffb47615169c8fdf9d383a1a", 22), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", concat( + repeat("b029517f6300c2da0f4b651b8642506cd6aaf45d", 22), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", concat( + repeat("918c48b83bd081e863dbe1b80f8998f058cd8294", 259), + )}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", concat( + repeat("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 7), + )}, + /* + // Failed + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "InstallSpinnaker.sh", concat( + repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), + repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 1), + repeat("23673af3ad70b50bba7fdafadc2323302f5ba520", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 29), + repeat("9a06d3f20eabb254d0a1e2ff7735ef007ccd595e", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 4), + repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), + repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 2), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 3), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 7), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 2), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 7), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 6), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 10), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 4), + repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 2), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 4), + repeat("23673af3ad70b50bba7fdafadc2323302f5ba520", 4), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 4), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 13), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 2), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 6), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 2), + repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 1), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 4), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 3), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 4), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 3), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 15), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 1), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 8), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 2), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 12), + repeat("505577dc87d300cf562dc4702a05a5615d90d855", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 5), + repeat("370d61cdbc1f3c90db6759f1599ccbabd40ad6c1", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 4), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 5), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 3), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 2), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 2), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 9), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 3), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 4), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 6), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 6), + repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), + repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 4), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("c9c2a0ec03968ab17e8b16fdec9661eb1dbea173", 1), + repeat("d2f6214b625db706384b378a29cc4c22237db97a", 2), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 12), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 5), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), + repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 5), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 2), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("b2c7142082d52b09ca20228606c31c7479c0833e", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("495c7118e7cf757aa04eab410b64bfb5b5149ad2", 1), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), + repeat("495c7118e7cf757aa04eab410b64bfb5b5149ad2", 3), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), + repeat("495c7118e7cf757aa04eab410b64bfb5b5149ad2", 1), + repeat("50d0556563599366f29cb286525780004fa5a317", 1), + repeat("dd2d03c19658ff96d371aef00e75e2e54702da0e", 1), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), + repeat("dd2d03c19658ff96d371aef00e75e2e54702da0e", 2), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("b5c6053a46993b20d1b91e7b7206bffa54669ad7", 1), + repeat("9e74d009894d73dd07773ea6b3bdd8323db980f7", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 4), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), + repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 3), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 2), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 4), + repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), + repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 5), + repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 2), + repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), + repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), + repeat("ba486de7c025457963701114c683dcd4708e1dee", 4), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 3), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 3), + repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 2), + repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 3), + repeat("3de4f77c105f700f50d9549d32b9a05a01b46c4b", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 2), + repeat("370d61cdbc1f3c90db6759f1599ccbabd40ad6c1", 6), + repeat("dd7e66c862209e8b912694a582a09c0db3227f0d", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 2), + repeat("dd7e66c862209e8b912694a582a09c0db3227f0d", 3), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("dd7e66c862209e8b912694a582a09c0db3227f0d", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 3), + )}, + */ + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/reconfigure_spinnaker.py", concat( + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 22), + repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 7), + )}, + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/validate_configuration.py", concat( + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 29), + repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 19), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 15), + repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 8), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 4), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 46), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 42), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), + repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 8), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 2), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), + repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 3), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 10), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 69), + repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 7), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + )}, + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/run.py", concat( + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 185), + )}, + /* + // Fail by 3 + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/configurator.py", concat( + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 53), + repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + repeat("e805183c72f0426fb073728c01901c2fd2db1da6", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 6), + repeat("023d4fb17b76e0fe0764971df8b8538b735a1d67", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 36), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 3), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 13), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 18), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), + repeat("023d4fb17b76e0fe0764971df8b8538b735a1d67", 17), + repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 43), + )}, + */ + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/__init__.py", []string{}}, + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "gradle/wrapper/gradle-wrapper.jar", concat( + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 7), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 2), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 10), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 11), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 29), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 7), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 58), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 13), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 4), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 13), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 9), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 17), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 6), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 6), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 5), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 4), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), + repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 6), + repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 55), + )}, + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/settings.js", concat( + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 17), + repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 43), + repeat("d2838db9f6ef9628645e7d04cd9658a83e8708ea", 1), + repeat("637ba49300f701cfbd859c1ccf13c4f39a9ba1c8", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 13), + )}, + /* + // fail a few lines + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/default-spinnaker-local.yml", concat( + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 9), + repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 2), + repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 2), + repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 5), + repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 2), + repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 5), + repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 1), + repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 25), + repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), + repeat("eaf7614cad81e8ab5c813dd4821129d0c04ea449", 1), + repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 24), + repeat("974b775a8978b120ff710cac93a21c7387b914c9", 2), + repeat("3ce7b902a51bac2f10994f7d1f251b616c975e54", 1), + repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 6), + repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 14), + repeat("7c8d9a6081d9cb7a56c479bfe64d70540ea32795", 5), + repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2), + )}, + */ + /* + // fail one line + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/spinnaker.yml", concat( + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 32), + repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 2), + repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 1), + repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 6), + repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2), + repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 2), + repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2), + repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 3), + repeat("7c8d9a6081d9cb7a56c479bfe64d70540ea32795", 3), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 50), + repeat("974b775a8978b120ff710cac93a21c7387b914c9", 2), + repeat("d4553dac205023fa77652308af1a2d1cf52138fb", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 9), + repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), + repeat("eaf7614cad81e8ab5c813dd4821129d0c04ea449", 1), + repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 39), + repeat("079e42e7c979541b6fab7343838f7b9fd4a360cd", 6), + repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 15), + )}, + */ + /* + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/install_development.sh", concat( + repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 71), + )}, + */ + /* + // FAIL two lines interchanged + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/bootstrap_dev.sh", concat( + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 95), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 10), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 7), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 3), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 2), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 6), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 4), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("376599177551c3f04ccc94d71bbb4d037dec0c3f", 2), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 17), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 2), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 2), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 8), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 4), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 6), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 4), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 10), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 2), + repeat("fc28a378558cdb5bbc08b6dcb96ee77c5b716760", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 8), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), + repeat("fc28a378558cdb5bbc08b6dcb96ee77c5b716760", 1), + repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), + repeat("24551a5d486969a2972ee05e87f16444890f9555", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), + repeat("24551a5d486969a2972ee05e87f16444890f9555", 1), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 8), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 13), + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5), + repeat("24551a5d486969a2972ee05e87f16444890f9555", 1), + repeat("838aed816872c52ed435e4876a7b64dba0bed500", 8), + )}, + */ + /* + // FAIL move? + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/create_google_dev_vm.sh", concat( + repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 20), + )}, + */ +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/common.go b/vendor/github.com/devtron-labs/go-git/common.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/common.go rename to vendor/github.com/devtron-labs/go-git/common.go diff --git a/vendor/github.com/devtron-labs/go-git/common_test.go b/vendor/github.com/devtron-labs/go-git/common_test.go new file mode 100644 index 00000000..fed07e23 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/common_test.go @@ -0,0 +1,170 @@ +package git + +import ( + "testing" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/format/packfile" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/storage/filesystem" + "github.com/devtron-labs/go-git/storage/memory" + + "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-billy.v4" + "gopkg.in/src-d/go-billy.v4/memfs" + "gopkg.in/src-d/go-billy.v4/util" +) + +func Test(t *testing.T) { TestingT(t) } + +type BaseSuite struct { + fixtures.Suite + Repository *Repository + + backupProtocol transport.Transport + cache map[string]*Repository +} + +func (s *BaseSuite) SetUpSuite(c *C) { + s.Suite.SetUpSuite(c) + s.buildBasicRepository(c) + + s.cache = make(map[string]*Repository) +} + +func (s *BaseSuite) TearDownSuite(c *C) { + s.Suite.TearDownSuite(c) +} + +func (s *BaseSuite) buildBasicRepository(c *C) { + f := fixtures.Basic().One() + s.Repository = s.NewRepository(f) +} + +// NewRepository returns a new repository using the .git folder, if the fixture +// is tagged as worktree the filesystem from fixture is used, otherwise a new +// memfs filesystem is used as worktree. +func (s *BaseSuite) NewRepository(f *fixtures.Fixture) *Repository { + var worktree, dotgit billy.Filesystem + if f.Is("worktree") { + r, err := PlainOpen(f.Worktree().Root()) + if err != nil { + panic(err) + } + + return r + } + + dotgit = f.DotGit() + worktree = memfs.New() + + st := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()) + + r, err := Open(st, worktree) + if err != nil { + panic(err) + } + + return r +} + +// NewRepositoryWithEmptyWorktree returns a new repository using the .git folder +// from the fixture but without a empty memfs worktree, the index and the +// modules are deleted from the .git folder. +func (s *BaseSuite) NewRepositoryWithEmptyWorktree(f *fixtures.Fixture) *Repository { + dotgit := f.DotGit() + err := dotgit.Remove("index") + if err != nil { + panic(err) + } + + err = util.RemoveAll(dotgit, "modules") + if err != nil { + panic(err) + } + + worktree := memfs.New() + + st := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()) + + r, err := Open(st, worktree) + if err != nil { + panic(err) + } + + return r + +} + +func (s *BaseSuite) NewRepositoryFromPackfile(f *fixtures.Fixture) *Repository { + h := f.PackfileHash.String() + if r, ok := s.cache[h]; ok { + return r + } + + storer := memory.NewStorage() + p := f.Packfile() + defer p.Close() + + if err := packfile.UpdateObjectStorage(storer, p); err != nil { + panic(err) + } + + storer.SetReference(plumbing.NewHashReference(plumbing.HEAD, f.Head)) + + r, err := Open(storer, memfs.New()) + if err != nil { + panic(err) + } + + s.cache[h] = r + return r +} + +func (s *BaseSuite) GetBasicLocalRepositoryURL() string { + fixture := fixtures.Basic().One() + return s.GetLocalRepositoryURL(fixture) +} + +func (s *BaseSuite) GetLocalRepositoryURL(f *fixtures.Fixture) string { + return f.DotGit().Root() +} + +type SuiteCommon struct{} + +var _ = Suite(&SuiteCommon{}) + +var countLinesTests = [...]struct { + i string // the string we want to count lines from + e int // the expected number of lines in i +}{ + {"", 0}, + {"a", 1}, + {"a\n", 1}, + {"a\nb", 2}, + {"a\nb\n", 2}, + {"a\nb\nc", 3}, + {"a\nb\nc\n", 3}, + {"a\n\n\nb\n", 4}, + {"first line\n\tsecond line\nthird line\n", 3}, +} + +func (s *SuiteCommon) TestCountLines(c *C) { + for i, t := range countLinesTests { + o := countLines(t.i) + c.Assert(o, Equals, t.e, Commentf("subtest %d, input=%q", i, t.i)) + } +} + +func AssertReferences(c *C, r *Repository, expected map[string]string) { + for name, target := range expected { + expected := plumbing.NewReferenceFromStrings(name, target) + + obtained, err := r.Reference(expected.Name(), true) + c.Assert(err, IsNil) + + c.Assert(obtained, DeepEquals, expected) + } +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/config/branch.go b/vendor/github.com/devtron-labs/go-git/config/branch.go similarity index 94% rename from vendor/gopkg.in/src-d/go-git.v4/config/branch.go rename to vendor/github.com/devtron-labs/go-git/config/branch.go index 20dde6e0..83abf3fc 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/config/branch.go +++ b/vendor/github.com/devtron-labs/go-git/config/branch.go @@ -3,8 +3,8 @@ package config import ( "errors" - "gopkg.in/src-d/go-git.v4/plumbing" - format "gopkg.in/src-d/go-git.v4/plumbing/format/config" + "github.com/devtron-labs/go-git/plumbing" + format "github.com/devtron-labs/go-git/plumbing/format/config" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/config/config.go b/vendor/github.com/devtron-labs/go-git/config/config.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/config/config.go rename to vendor/github.com/devtron-labs/go-git/config/config.go index ea614e96..2813aead 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/config/config.go +++ b/vendor/github.com/devtron-labs/go-git/config/config.go @@ -8,8 +8,8 @@ import ( "sort" "strconv" - "gopkg.in/src-d/go-git.v4/internal/url" - format "gopkg.in/src-d/go-git.v4/plumbing/format/config" + "github.com/devtron-labs/go-git/internal/url" + format "github.com/devtron-labs/go-git/plumbing/format/config" ) const ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/config/modules.go b/vendor/github.com/devtron-labs/go-git/config/modules.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/config/modules.go rename to vendor/github.com/devtron-labs/go-git/config/modules.go index 90758d93..289f79e2 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/config/modules.go +++ b/vendor/github.com/devtron-labs/go-git/config/modules.go @@ -5,7 +5,7 @@ import ( "errors" "regexp" - format "gopkg.in/src-d/go-git.v4/plumbing/format/config" + format "github.com/devtron-labs/go-git/plumbing/format/config" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/config/refspec.go b/vendor/github.com/devtron-labs/go-git/config/refspec.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/config/refspec.go rename to vendor/github.com/devtron-labs/go-git/config/refspec.go index 14bb4006..1fe4963e 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/config/refspec.go +++ b/vendor/github.com/devtron-labs/go-git/config/refspec.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "gopkg.in/src-d/go-git.v4/plumbing" + "github.com/devtron-labs/go-git/plumbing" ) const ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/doc.go b/vendor/github.com/devtron-labs/go-git/doc.go similarity index 89% rename from vendor/gopkg.in/src-d/go-git.v4/doc.go rename to vendor/github.com/devtron-labs/go-git/doc.go index 60f2261e..a97b293e 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/doc.go +++ b/vendor/github.com/devtron-labs/go-git/doc.go @@ -7,4 +7,4 @@ // It is highly extensible, we have been following the open/close principle in // its design to facilitate extensions, mainly focusing the efforts on the // persistence of the objects. -package git // import "gopkg.in/src-d/go-git.v4" +package git // import "github.com/devtron-labs/go-git" diff --git a/vendor/github.com/devtron-labs/go-git/example_test.go b/vendor/github.com/devtron-labs/go-git/example_test.go new file mode 100644 index 00000000..cef709e8 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/example_test.go @@ -0,0 +1,166 @@ +package git_test + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" + + "github.com/devtron-labs/go-git" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/transport/http" + "github.com/devtron-labs/go-git/storage/memory" + + "gopkg.in/src-d/go-billy.v4/memfs" +) + +func ExampleClone() { + // Filesystem abstraction based on memory + fs := memfs.New() + // Git objects storer based on memory + storer := memory.NewStorage() + + // Clones the repository into the worktree (fs) and storer all the .git + // content into the storer + _, err := git.Clone(storer, fs, &git.CloneOptions{ + URL: "https://github.com/git-fixtures/basic.git", + }) + if err != nil { + log.Fatal(err) + } + + // Prints the content of the CHANGELOG file from the cloned repository + changelog, err := fs.Open("CHANGELOG") + if err != nil { + log.Fatal(err) + } + + io.Copy(os.Stdout, changelog) + // Output: Initial changelog +} + +func ExamplePlainClone() { + // Tempdir to clone the repository + dir, err := ioutil.TempDir("", "clone-example") + if err != nil { + log.Fatal(err) + } + + defer os.RemoveAll(dir) // clean up + + // Clones the repository into the given dir, just as a normal git clone does + _, err = git.PlainClone(dir, false, &git.CloneOptions{ + URL: "https://github.com/git-fixtures/basic.git", + }) + + if err != nil { + log.Fatal(err) + } + + // Prints the content of the CHANGELOG file from the cloned repository + changelog, err := os.Open(filepath.Join(dir, "CHANGELOG")) + if err != nil { + log.Fatal(err) + } + + io.Copy(os.Stdout, changelog) + // Output: Initial changelog +} + +func ExamplePlainClone_usernamePassword() { + // Tempdir to clone the repository + dir, err := ioutil.TempDir("", "clone-example") + if err != nil { + log.Fatal(err) + } + + defer os.RemoveAll(dir) // clean up + + // Clones the repository into the given dir, just as a normal git clone does + _, err = git.PlainClone(dir, false, &git.CloneOptions{ + URL: "https://github.com/git-fixtures/basic.git", + Auth: &http.BasicAuth{ + Username: "username", + Password: "password", + }, + }) + + if err != nil { + log.Fatal(err) + } +} + +func ExamplePlainClone_accessToken() { + // Tempdir to clone the repository + dir, err := ioutil.TempDir("", "clone-example") + if err != nil { + log.Fatal(err) + } + + defer os.RemoveAll(dir) // clean up + + // Clones the repository into the given dir, just as a normal git clone does + _, err = git.PlainClone(dir, false, &git.CloneOptions{ + URL: "https://github.com/git-fixtures/basic.git", + Auth: &http.BasicAuth{ + Username: "abc123", // anything except an empty string + Password: "github_access_token", + }, + }) + + if err != nil { + log.Fatal(err) + } +} + +func ExampleRepository_References() { + r, _ := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{ + URL: "https://github.com/git-fixtures/basic.git", + }) + + // simulating a git show-ref + refs, _ := r.References() + refs.ForEach(func(ref *plumbing.Reference) error { + if ref.Type() == plumbing.HashReference { + fmt.Println(ref) + } + + return nil + }) + + // Example Output: + // 6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/remotes/origin/master + // e8d3ffab552895c19b9fcf7aa264d277cde33881 refs/remotes/origin/branch + // 6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/heads/master + +} + +func ExampleRepository_CreateRemote() { + r, _ := git.Init(memory.NewStorage(), nil) + + // Add a new remote, with the default fetch refspec + _, err := r.CreateRemote(&config.RemoteConfig{ + Name: "example", + URLs: []string{"https://github.com/git-fixtures/basic.git"}, + }) + + if err != nil { + log.Fatal(err) + } + + list, err := r.Remotes() + if err != nil { + log.Fatal(err) + } + + for _, r := range list { + fmt.Println(r) + } + + // Example Output: + // example https://github.com/git-fixtures/basic.git (fetch) + // example https://github.com/git-fixtures/basic.git (push) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/internal/url/url.go b/vendor/github.com/devtron-labs/go-git/internal/url/url.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/internal/url/url.go rename to vendor/github.com/devtron-labs/go-git/internal/url/url.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/object_walker.go b/vendor/github.com/devtron-labs/go-git/object_walker.go similarity index 93% rename from vendor/gopkg.in/src-d/go-git.v4/object_walker.go rename to vendor/github.com/devtron-labs/go-git/object_walker.go index f8b19cdb..5098bc72 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/object_walker.go +++ b/vendor/github.com/devtron-labs/go-git/object_walker.go @@ -3,10 +3,10 @@ package git import ( "fmt" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/storage" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/storage" ) type objectWalker struct { diff --git a/vendor/gopkg.in/src-d/go-git.v4/options.go b/vendor/github.com/devtron-labs/go-git/options.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/options.go rename to vendor/github.com/devtron-labs/go-git/options.go index 0f728e7c..a3fdd2c0 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/options.go +++ b/vendor/github.com/devtron-labs/go-git/options.go @@ -5,12 +5,12 @@ import ( "regexp" "strings" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband" + "github.com/devtron-labs/go-git/plumbing/transport" "golang.org/x/crypto/openpgp" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" - "gopkg.in/src-d/go-git.v4/plumbing/transport" ) // SubmoduleRescursivity defines how depth will affect any submodule recursive diff --git a/vendor/github.com/devtron-labs/go-git/options_test.go b/vendor/github.com/devtron-labs/go-git/options_test.go new file mode 100644 index 00000000..eb0a0df0 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/options_test.go @@ -0,0 +1,35 @@ +package git + +import ( + "github.com/devtron-labs/go-git/plumbing/object" + . "gopkg.in/check.v1" +) + +type OptionsSuite struct { + BaseSuite +} + +var _ = Suite(&OptionsSuite{}) + +func (s *OptionsSuite) TestCommitOptionsParentsFromHEAD(c *C) { + o := CommitOptions{Author: &object.Signature{}} + err := o.Validate(s.Repository) + c.Assert(err, IsNil) + c.Assert(o.Parents, HasLen, 1) +} + +func (s *OptionsSuite) TestCommitOptionsMissingAuthor(c *C) { + o := CommitOptions{} + err := o.Validate(s.Repository) + c.Assert(err, Equals, ErrMissingAuthor) +} + +func (s *OptionsSuite) TestCommitOptionsCommitter(c *C) { + sig := &object.Signature{} + + o := CommitOptions{Author: sig} + err := o.Validate(s.Repository) + c.Assert(err, IsNil) + + c.Assert(o.Committer, Equals, o.Author) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/error.go b/vendor/github.com/devtron-labs/go-git/plumbing/error.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/error.go rename to vendor/github.com/devtron-labs/go-git/plumbing/error.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/filemode/filemode.go b/vendor/github.com/devtron-labs/go-git/plumbing/filemode/filemode.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/filemode/filemode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/filemode/filemode.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/config/common.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/common.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/config/common.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/decoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/config/decoder.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/decoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/config/decoder.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/config/doc.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/doc.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/config/doc.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/encoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/config/encoder.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/encoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/config/encoder.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/option.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/config/option.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/option.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/config/option.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/section.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/config/section.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/config/section.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/config/section.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/diff/patch.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/diff/patch.go similarity index 94% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/diff/patch.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/diff/patch.go index 7c6cf4ae..057a7c4f 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/diff/patch.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/diff/patch.go @@ -1,8 +1,8 @@ package diff import ( - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" ) // Operation defines the operation of a diff item. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/diff/unified_encoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/diff/unified_encoder.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/diff/unified_encoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/diff/unified_encoder.go index 169242dc..499484ee 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/diff/unified_encoder.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/diff/unified_encoder.go @@ -6,7 +6,7 @@ import ( "io" "strings" - "gopkg.in/src-d/go-git.v4/plumbing" + "github.com/devtron-labs/go-git/plumbing" ) const ( @@ -46,8 +46,8 @@ const ( // UnifiedEncoder encodes an unified diff into the provided Writer. // There are some unsupported features: -// - Similarity index for renames -// - Sort hash representation +// - Similarity index for renames +// - Sort hash representation type UnifiedEncoder struct { io.Writer diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/decoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/decoder.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/decoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/index/decoder.go index 98f92fda..8f8d2e11 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/decoder.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/decoder.go @@ -11,8 +11,8 @@ import ( "strconv" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/utils/binary" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/utils/binary" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/doc.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/doc.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/index/doc.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/encoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/encoder.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/encoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/index/encoder.go index 7111314c..ca4ca4d6 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/encoder.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/encoder.go @@ -9,7 +9,7 @@ import ( "sort" "time" - "gopkg.in/src-d/go-git.v4/utils/binary" + "github.com/devtron-labs/go-git/utils/binary" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/index.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/index.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/index.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/index/index.go index 6653c91d..60f97fab 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/index.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/index.go @@ -7,8 +7,8 @@ import ( "path/filepath" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" ) var ( @@ -202,8 +202,8 @@ type ResolveUndoEntry struct { // can take advantage of this to quickly locate the index extensions without // having to parse through all of the index entries. // -// Because it must be able to be loaded before the variable length cache -// entries and other index extensions, this extension must be written last. +// Because it must be able to be loaded before the variable length cache +// entries and other index extensions, this extension must be written last. type EndOfIndexEntry struct { // Offset to the end of the index entries Offset uint32 diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/match.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/index/match.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/index/match.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/index/match.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/pktline/encoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/pktline/encoder.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/pktline/encoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/pktline/encoder.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/pktline/scanner.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/pktline/scanner.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/format/pktline/scanner.go rename to vendor/github.com/devtron-labs/go-git/plumbing/format/pktline/scanner.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/hash.go b/vendor/github.com/devtron-labs/go-git/plumbing/hash.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/hash.go rename to vendor/github.com/devtron-labs/go-git/plumbing/hash.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/memory.go b/vendor/github.com/devtron-labs/go-git/plumbing/memory.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/memory.go rename to vendor/github.com/devtron-labs/go-git/plumbing/memory.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object.go b/vendor/github.com/devtron-labs/go-git/plumbing/object.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/blob.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/blob.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/blob.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/blob.go index f376baa6..c6ea0100 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/blob.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/blob.go @@ -3,9 +3,9 @@ package object import ( "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/ioutil" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/ioutil" ) // Blob is used to store arbitrary data - it is generally a file. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/change.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/change.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/change.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/change.go index a1b4c274..dd338362 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/change.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/change.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - "gopkg.in/src-d/go-git.v4/utils/merkletrie" + "github.com/devtron-labs/go-git/utils/merkletrie" ) // Change values represent a detected change between two git trees. For diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/change_adaptor.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/change_adaptor.go similarity index 91% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/change_adaptor.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/change_adaptor.go index 491c3990..782822e7 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/change_adaptor.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/change_adaptor.go @@ -4,8 +4,8 @@ import ( "errors" "fmt" - "gopkg.in/src-d/go-git.v4/utils/merkletrie" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // The following functions transform changes types form the merkletrie diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/commit.go index 6b509340..e951c153 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit.go @@ -11,9 +11,9 @@ import ( "golang.org/x/crypto/openpgp" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/ioutil" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/ioutil" ) const ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker.go index 0eff0591..e8311a2c 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker.go @@ -4,9 +4,9 @@ import ( "container/list" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/storage" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage" ) type commitPreIterator struct { diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_bfs.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_bfs.go index dabfe75c..0844d803 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_bfs.go @@ -3,8 +3,8 @@ package object import ( "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" ) type bfsCommitIterator struct { diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs_filtered.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_bfs_filtered.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs_filtered.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_bfs_filtered.go index b12523d4..2c9f718c 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_bfs_filtered.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_bfs_filtered.go @@ -3,8 +3,8 @@ package object import ( "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" ) // NewFilterCommitIter returns a CommitIter that walks the commit history, @@ -173,4 +173,3 @@ func (w *filterCommitIter) addToQueue( return nil } - diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_ctime.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_ctime.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_ctime.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_ctime.go index 01916149..83b135ef 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_ctime.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_ctime.go @@ -5,8 +5,8 @@ import ( "github.com/emirpasic/gods/trees/binaryheap" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" ) type commitIteratorByCTime struct { diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_file.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_file.go index 6f16e611..51232bcd 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit_walker_file.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/commit_walker_file.go @@ -3,9 +3,9 @@ package object import ( "io" - "gopkg.in/src-d/go-git.v4/plumbing" + "github.com/devtron-labs/go-git/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing/storer" ) type commitFileIter struct { diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/common.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/common.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/common.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/difftree.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/difftree.go similarity index 88% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/difftree.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/difftree.go index a30a29e3..e73d7553 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/difftree.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/difftree.go @@ -4,8 +4,8 @@ import ( "bytes" "context" - "gopkg.in/src-d/go-git.v4/utils/merkletrie" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // DiffTree compares the content and mode of the blobs found via two diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/file.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/file.go similarity index 93% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/file.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/file.go index 1c5fdbb3..2ced9bfa 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/file.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/file.go @@ -5,10 +5,10 @@ import ( "io" "strings" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/binary" - "gopkg.in/src-d/go-git.v4/utils/ioutil" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/binary" + "github.com/devtron-labs/go-git/utils/ioutil" ) // File represents git file objects. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/merge_base.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/merge_base.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/merge_base.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/merge_base.go index 6f2568db..6ace8126 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/merge_base.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/merge_base.go @@ -4,8 +4,8 @@ import ( "fmt" "sort" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" ) // errIsReachable is thrown when first commit is an ancestor of the second diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/object.go similarity index 94% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/object.go index e960e50c..a6be749a 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/object.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/object.go @@ -10,8 +10,8 @@ import ( "strconv" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" ) // ErrUnsupportedObject trigger when a non-supported object is being decoded. @@ -24,18 +24,18 @@ var ErrUnsupportedObject = errors.New("unsupported object type") // Object is returned when an object can be of any type. It is frequently used // with a type cast to acquire the specific type of object: // -// func process(obj Object) { -// switch o := obj.(type) { -// case *Commit: -// // o is a Commit -// case *Tree: -// // o is a Tree -// case *Blob: -// // o is a Blob -// case *Tag: -// // o is a Tag -// } -// } +// func process(obj Object) { +// switch o := obj.(type) { +// case *Commit: +// // o is a Commit +// case *Tree: +// // o is a Tree +// case *Blob: +// // o is a Blob +// case *Tag: +// // o is a Tag +// } +// } // // This interface is intentionally different from plumbing.EncodedObject, which // is a lower level interface used by storage implementations to read and write diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/patch.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/patch.go index 32454ac4..3f728535 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/patch.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/patch.go @@ -9,10 +9,10 @@ import ( "math" "strings" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - fdiff "gopkg.in/src-d/go-git.v4/plumbing/format/diff" - "gopkg.in/src-d/go-git.v4/utils/diff" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + fdiff "github.com/devtron-labs/go-git/plumbing/format/diff" + "github.com/devtron-labs/go-git/utils/diff" dmp "github.com/sergi/go-diff/diffmatchpatch" ) diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tag.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/tag.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tag.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/tag.go index 9ee55092..4014ea6a 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tag.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/tag.go @@ -10,9 +10,9 @@ import ( "golang.org/x/crypto/openpgp" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/ioutil" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/ioutil" ) // Tag represents an annotated tag object. It points to a single git object of diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/tree.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/tree.go index d0b4fff1..c8214bcd 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/tree.go @@ -10,10 +10,10 @@ import ( "path/filepath" "strings" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/ioutil" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/ioutil" ) const ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/treenoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/object/treenoder.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/object/treenoder.go rename to vendor/github.com/devtron-labs/go-git/plumbing/object/treenoder.go index 52f0e612..628af6dc 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/object/treenoder.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/object/treenoder.go @@ -3,9 +3,9 @@ package object import ( "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // A treenoder is a helper type that wraps git trees into merkletrie diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs.go similarity index 88% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs.go index 487ee19b..a2d3a715 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs.go @@ -5,10 +5,10 @@ import ( "sort" "strings" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/storage/memory" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage/memory" ) // AdvRefs values represent the information transmitted on an @@ -96,12 +96,12 @@ func (a *AdvRefs) addRefs(s storer.ReferenceStorer) error { // // Git versions prior to 1.8.4.3 has an special procedure to get // the reference where is pointing to HEAD: -// - Check if a reference called master exists. If exists and it -// has the same hash as HEAD hash, we can say that HEAD is pointing to master -// - If master does not exists or does not have the same hash as HEAD, -// order references and check in that order if that reference has the same -// hash than HEAD. If yes, set HEAD pointing to that branch hash -// - If no reference is found, throw an error +// - Check if a reference called master exists. If exists and it +// has the same hash as HEAD hash, we can say that HEAD is pointing to master +// - If master does not exists or does not have the same hash as HEAD, +// order references and check in that order if that reference has the same +// hash than HEAD. If yes, set HEAD pointing to that branch hash +// - If no reference is found, throw an error func (a *AdvRefs) resolveHead(s storer.ReferenceStorer) error { if a.Head == nil { return nil diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs_decode.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs_decode.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs_decode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs_decode.go index 1b4c62c8..3939027b 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs_decode.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs_decode.go @@ -7,8 +7,8 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) // Decode reads the next advertised-refs message form its input and diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs_encode.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs_encode.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs_encode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs_encode.go index c23e3feb..a64f9a0a 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/advrefs_encode.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/advrefs_encode.go @@ -6,9 +6,9 @@ import ( "io" "sort" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" ) // Encode writes the AdvRefs encoding to a writer. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability/capability.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/capability/capability.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability/capability.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/capability/capability.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability/list.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/capability/list.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability/list.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/capability/list.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/common.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/common.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/common.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/doc.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/doc.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/doc.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/report_status.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/report_status.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/report_status.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/report_status.go index 29c1a4cd..14cc6443 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/report_status.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/report_status.go @@ -6,8 +6,8 @@ import ( "io" "strings" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) const ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/shallowupd.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/shallowupd.go similarity index 94% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/shallowupd.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/shallowupd.go index fce4e3be..50485674 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/shallowupd.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/shallowupd.go @@ -5,8 +5,8 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) const ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/common.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/common.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/common.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/demux.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/demux.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/demux.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/demux.go index 352336dc..94c8feb2 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/demux.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/demux.go @@ -5,7 +5,7 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) // ErrMaxPackedExceeded returned by Read, if the maximum packed size is exceeded diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/doc.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/doc.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/doc.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/muxer.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/muxer.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/muxer.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/muxer.go index 45fecc2c..76e6e23f 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband/muxer.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband/muxer.go @@ -3,7 +3,7 @@ package sideband import ( "io" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) // Muxer multiplex the packfile along with the progress messages and the error diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/srvresp.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/srvresp.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/srvresp.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/srvresp.go index 6a919918..fbd98f57 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/srvresp.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/srvresp.go @@ -7,8 +7,8 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) const ackLineLen = 44 diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq.go index 74109d88..2545b641 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq.go @@ -4,8 +4,8 @@ import ( "fmt" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" ) // UploadRequest values represent the information transmitted on a diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq_decode.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq_decode.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq_decode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq_decode.go index bcd642db..f5411053 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq_decode.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq_decode.go @@ -8,8 +8,8 @@ import ( "strconv" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) // Decode reads the next upload-request form its input and diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq_encode.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq_encode.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq_encode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq_encode.go index 89a59868..54b66f51 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/ulreq_encode.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/ulreq_encode.go @@ -6,8 +6,8 @@ import ( "io" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) // Encode writes the UlReq encoding of u to the stream. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq.go similarity index 93% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq.go index 73be1171..8f756b98 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq.go @@ -4,9 +4,9 @@ import ( "errors" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband" ) var ( @@ -47,6 +47,7 @@ func NewReferenceUpdateRequest() *ReferenceUpdateRequest { // - ofs-delta // - ref-delta // - delete-refs +// // It leaves up to the user to add the following capabilities later: // - atomic // - ofs-delta diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq_decode.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq_decode.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq_decode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq_decode.go index 51e8183d..d889fa18 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq_decode.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq_decode.go @@ -8,8 +8,8 @@ import ( "io" "io/ioutil" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq_encode.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq_encode.go similarity index 88% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq_encode.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq_encode.go index 44c05739..c1817015 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/updreq_encode.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/updreq_encode.go @@ -4,9 +4,9 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/uppackreq.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/uppackreq.go similarity index 93% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/uppackreq.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/uppackreq.go index 11441395..ceab96a5 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/uppackreq.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/uppackreq.go @@ -5,9 +5,9 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" ) // UploadPackRequest represents a upload-pack request. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/uppackresp.go b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/uppackresp.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/uppackresp.go rename to vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/uppackresp.go index c18e159e..fb033499 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/uppackresp.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/protocol/packp/uppackresp.go @@ -6,8 +6,8 @@ import ( "bufio" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/utils/ioutil" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/utils/ioutil" ) // ErrUploadPackResponseNotDecoded is returned if Read is called without diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/reference.go b/vendor/github.com/devtron-labs/go-git/plumbing/reference.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/reference.go rename to vendor/github.com/devtron-labs/go-git/plumbing/reference.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/revision.go b/vendor/github.com/devtron-labs/go-git/plumbing/revision.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/revision.go rename to vendor/github.com/devtron-labs/go-git/plumbing/revision.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/storer/doc.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/doc.go rename to vendor/github.com/devtron-labs/go-git/plumbing/storer/doc.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/index.go b/vendor/github.com/devtron-labs/go-git/plumbing/storer/index.go similarity index 71% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/index.go rename to vendor/github.com/devtron-labs/go-git/plumbing/storer/index.go index e087296e..186aaf3d 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/index.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/storer/index.go @@ -1,6 +1,6 @@ package storer -import "gopkg.in/src-d/go-git.v4/plumbing/format/index" +import "github.com/devtron-labs/go-git/plumbing/format/index" // IndexStorer generic storage of index.Index type IndexStorer interface { diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/object.go b/vendor/github.com/devtron-labs/go-git/plumbing/storer/object.go similarity index 99% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/object.go rename to vendor/github.com/devtron-labs/go-git/plumbing/storer/object.go index 98d1ec3f..8df24481 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/object.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/storer/object.go @@ -5,7 +5,7 @@ import ( "io" "time" - "gopkg.in/src-d/go-git.v4/plumbing" + "github.com/devtron-labs/go-git/plumbing" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/reference.go b/vendor/github.com/devtron-labs/go-git/plumbing/storer/reference.go similarity index 99% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/reference.go rename to vendor/github.com/devtron-labs/go-git/plumbing/storer/reference.go index cce72b4a..7fbbcba0 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/reference.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/storer/reference.go @@ -4,7 +4,7 @@ import ( "errors" "io" - "gopkg.in/src-d/go-git.v4/plumbing" + "github.com/devtron-labs/go-git/plumbing" ) const MaxResolveRecursion = 1024 diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/shallow.go b/vendor/github.com/devtron-labs/go-git/plumbing/storer/shallow.go similarity index 84% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/shallow.go rename to vendor/github.com/devtron-labs/go-git/plumbing/storer/shallow.go index 39aaaa54..ed1d964d 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/shallow.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/storer/shallow.go @@ -1,6 +1,6 @@ package storer -import "gopkg.in/src-d/go-git.v4/plumbing" +import "github.com/devtron-labs/go-git/plumbing" // ShallowStorer is a storage of references to shallow commits by hash, // meaning that these commits have missing parents because of a shallow fetch. diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/storer.go b/vendor/github.com/devtron-labs/go-git/plumbing/storer/storer.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/storer/storer.go rename to vendor/github.com/devtron-labs/go-git/plumbing/storer/storer.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/common.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/common.go rename to vendor/github.com/devtron-labs/go-git/plumbing/transport/common.go index dcf9391d..a01facf3 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/common.go +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/common.go @@ -22,10 +22,10 @@ import ( "strconv" "strings" - giturl "gopkg.in/src-d/go-git.v4/internal/url" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" + giturl "github.com/devtron-labs/go-git/internal/url" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/prune.go b/vendor/github.com/devtron-labs/go-git/prune.go similarity index 94% rename from vendor/gopkg.in/src-d/go-git.v4/prune.go rename to vendor/github.com/devtron-labs/go-git/prune.go index c840325f..0eee0ad8 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/prune.go +++ b/vendor/github.com/devtron-labs/go-git/prune.go @@ -4,8 +4,8 @@ import ( "errors" "time" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" ) type PruneHandler func(unreferencedObjectHash plumbing.Hash) error diff --git a/vendor/github.com/devtron-labs/go-git/prune_test.go b/vendor/github.com/devtron-labs/go-git/prune_test.go new file mode 100644 index 00000000..ea655c32 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/prune_test.go @@ -0,0 +1,75 @@ +package git + +import ( + "time" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/storage/filesystem" + + "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" +) + +type PruneSuite struct { + BaseSuite +} + +var _ = Suite(&PruneSuite{}) + +func (s *PruneSuite) testPrune(c *C, deleteTime time.Time) { + srcFs := fixtures.ByTag("unpacked").One().DotGit() + var sto storage.Storer + var err error + sto = filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) + + los := sto.(storer.LooseObjectStorer) + c.Assert(los, NotNil) + + count := 0 + err = los.ForEachObjectHash(func(_ plumbing.Hash) error { + count++ + return nil + }) + c.Assert(err, IsNil) + + r, err := Open(sto, srcFs) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + // Remove a branch so we can prune some objects. + err = sto.RemoveReference(plumbing.ReferenceName("refs/heads/v4")) + c.Assert(err, IsNil) + err = sto.RemoveReference(plumbing.ReferenceName("refs/remotes/origin/v4")) + c.Assert(err, IsNil) + + err = r.Prune(PruneOptions{ + OnlyObjectsOlderThan: deleteTime, + Handler: r.DeleteObject, + }) + c.Assert(err, IsNil) + + newCount := 0 + err = los.ForEachObjectHash(func(_ plumbing.Hash) error { + newCount++ + return nil + }) + c.Assert(err, IsNil) + + if deleteTime.IsZero() { + c.Assert(newCount < count, Equals, true) + } else { + // Assume a delete time older than any of the objects was passed in. + c.Assert(newCount, Equals, count) + } +} + +func (s *PruneSuite) TestPrune(c *C) { + s.testPrune(c, time.Time{}) +} + +func (s *PruneSuite) TestPruneWithNoDelete(c *C) { + s.testPrune(c, time.Unix(0, 1)) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/references.go b/vendor/github.com/devtron-labs/go-git/references.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/references.go rename to vendor/github.com/devtron-labs/go-git/references.go index 5673ac13..a4921f77 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/references.go +++ b/vendor/github.com/devtron-labs/go-git/references.go @@ -4,9 +4,9 @@ import ( "io" "sort" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/utils/diff" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/utils/diff" "github.com/sergi/go-diff/diffmatchpatch" ) diff --git a/vendor/github.com/devtron-labs/go-git/references_test.go b/vendor/github.com/devtron-labs/go-git/references_test.go new file mode 100644 index 00000000..4d9d3dc7 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/references_test.go @@ -0,0 +1,401 @@ +package git + +import ( + "bytes" + "fmt" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/storage/memory" + + "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" +) + +type ReferencesSuite struct { + BaseSuite +} + +var _ = Suite(&ReferencesSuite{}) + +var referencesTests = [...]struct { + // input data to revlist + repo string + commit string + path string + // expected output data form the revlist + revs []string +}{ + // Tyba git-fixture + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", []string{ + "35e85108805c84807bc66a02d91535e1e24b38b9", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", []string{ + "b8e471f58bcbca63b07bda20e428190409c2db47", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", []string{ + "918c48b83bd081e863dbe1b80f8998f058cd8294", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", []string{ + "af2d6a6954d532f8ffb47615169c8fdf9d383a1a", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", []string{ + "af2d6a6954d532f8ffb47615169c8fdf9d383a1a", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", []string{ + "b029517f6300c2da0f4b651b8642506cd6aaf45d", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", []string{ + "918c48b83bd081e863dbe1b80f8998f058cd8294", + }}, + {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", []string{ + "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "LICENSE", []string{ + "ffcda27c2de6768ee83f3f4a027fa4ab57d50f09", + }}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "README.md", []string{ + "ffcda27c2de6768ee83f3f4a027fa4ab57d50f09", + "2e87a2dcc63a115f9a61bd969d1e85fb132a431b", + "215b0ac06225b0671bc3460d10da88c3406f796f", + "0260eb7a2623dd2309ab439f74e8681fccdc4285", + "d46b48933e94f30992486374fa9a6becfd28ea17", + "9cb4df2a88efee8836f9b8ad27ca2717f624164e", + "8c49acdec2ed441706d8799f8b17878aae4c1ffe", + "ebaca0c6f54c23193ee8175c3530e370cb2dabe3", + "77675f82039551a19de4fbccbe69366fe63680df", + "b9741594fb8ab7374f9be07d6a09a3bf96719816", + "04db6acd94de714ca48128c606b17ee1149a630e", + "ff737bd8a962a714a446d7592fae423a56e61e12", + "eadd03f7a1cc54810bd10eef6747ad9562ad246d", + "b5072ab5c1cf89191d71f1244eecc5d1f369ef7e", + "bfa6ebc9948f1939402b063c0a2a24bf2b1c1cc3", + "d9aef39828c670dfdb172502021a2ebcda8cf2fb", + "1a6b6e45c91e1831494eb139ee3f8e21649c7fb0", + "09fdbe4612066cf63ea46aee43c7cfaaff02ecfb", + "236f6526b1150cc1f1723566b4738f443fc70777", + "7862953f470b62397d22f6782a884f5bea6d760d", + "b0b0152d08c2333680266977a5bc9c4e50e1e968", + "13ce6c1c77c831f381974aa1c62008a414bd2b37", + "d3f3c8faca048d11709969fbfc0cdf2901b87578", + "8777dde1abe18c805d021366643218d3f3356dd9", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/reconfigure_spinnaker.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/validate_configuration.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", + "1e3d328a2cabda5d0aaddc5dec65271343e0dc37", + "b5d999e2986e190d81767cd3cfeda0260f9f6fb8", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/fetch.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/yaml_util.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", + "b5d999e2986e190d81767cd3cfeda0260f9f6fb8", + "023d4fb17b76e0fe0764971df8b8538b735a1d67", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "dev/build_release.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", + "f42771ba298b93a7c4f5b16c5b30ab96c15305a8", + "dd52703a50e71891f63fcf05df1f69836f4e7056", + "0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", + "d375f1994ff4d0bdc32d614e698f1b50e1093f14", + "abad497f11a366548aa95303c8c2f165fe7ae918", + "6986d885626792dee4ef6b7474dfc9230c5bda54", + "5422a86a10a8c5a1ef6728f5fc8894d9a4c54cb9", + "09a4ea729b25714b6368959eea5113c99938f7b6", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pkg_scripts/postUninstall.sh", []string{ + "ce9f123d790717599aaeb76bc62510de437761be", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/first_google_boot.sh", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + "de25f576b888569192e6442b0202d30ca7b2d8ec", + "a596972a661d9a7deca8abd18b52ce1a39516e89", + "9467ec579708b3c71dd9e5b3906772841c144a30", + "c4a9091e4076cb740fa46e790dd5b658e19012ad", + "6eb5d9c5225224bfe59c401182a2939d6c27fc00", + "495c7118e7cf757aa04eab410b64bfb5b5149ad2", + "dd2d03c19658ff96d371aef00e75e2e54702da0e", + "2a3b1d3b134e937c7bafdab6cc2950e264bf5dee", + "a57b08a9072f6a865f760551be2a4944f72f804a", + "0777fadf4ca6f458d7071de414f9bd5417911037", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.sh", []string{ + "0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_fake_openjdk8.sh", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + "37f94770d81232b1895fca447878f68d65aac652", + "46c9dcbb55ca3f4735e82ad006e8cae2fdd050d9", + "124a88cfda413cb7182ca9c739a284a9e50042a1", + "eb4faf67a8b775d7985d07a708e3ffeac4273580", + "0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", + "01171a8a2e843bef3a574ba73b258ac29e5d5405", + "739d8c6fe16edcb6ef9185dc74197de561b84315", + "d33c2d1e350b03fb989eefc612e8c9d5fa7cadc2", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/__init__.py", []string{ + "a24001f6938d425d0e7504bdf5d27fc866a85c3d", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "experimental/docker-compose/docker-compose.yml", []string{ + "fda357835d889595dc39dfebc6181d863cce7d4f", + "57c59e7144354a76e1beba69ae2f85db6b1727af", + "7682dff881029c722d893a112a64fea6849a0428", + "66f1c938c380a4096674b27540086656076a597f", + "56dc238f6f397e93f1d1aad702976889c830e8bf", + "b95e442c064935709e789fa02126f17ddceef10b", + "f98965a8f42037bd038b86c3401da7e6dfbf4f2e", + "5344429749e8b68b168d2707b7903692436cc2ea", + "6a31f5d219766b0cec4ea4fbbbfe47bdcdb0ab8e", + "ddaae195b628150233b0a48f50a1674fd9d1a924", + "7119ad9cf7d4e4d8b059e5337374baae4adc7458", + }}, + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/validate_configuration_test.py", []string{ + "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", + "1e3d328a2cabda5d0aaddc5dec65271343e0dc37", + }}, + {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "README.adoc", []string{ + "638f61b3331695f46f1a88095e26dea0f09f176b", + "bd42370d3fe8d410e78acb96f81cb3d838ad1c21", + "d6905eab6fec1841c7cf8e4484499f5c8d7d423e", + "c0a70a0f5aa494f0ae01c55ba191f2325556489a", + "811795c8a185e88f5d269195cb68b29c8d0fe170", + "d6e6fe0194447cc280f942d6a2e0521b68ea7796", + "174bdbf9edfb0ca88415dd4a673852d5b22e7036", + "9944d6cf72b8f82d622d85dad7434472bc8f397d", + "e805183c72f0426fb073728c01901c2fd2db1da6", + "8ef83dd443a05e9122681950399edaa58a38d466", + "d73f9cee49a5ad27a42a6e18af7c49a8f28ad8a8", + }}, + // FAILS + /* + // this contains an empty move + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "google/dev/build_google_tarball.py", []string{ + "88e60ac93f832efc2616b3c165e99a8f2ffc3e0c", + "9e49443da49b8c862cc140b660744f84eebcfa51", + }}, + */ + /* + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/yaml_util_test.py", []string{ + "edf909edb9319c5e615e4ce73da47bbdca388ebe", + "023d4fb17b76e0fe0764971df8b8538b735a1d67", + }}, + */ + /* + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/configurator_test.py", []string{ + "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", + "edf909edb9319c5e615e4ce73da47bbdca388ebe", + "d14f793a6cd7169ef708a4fc276ad876bd3edd4e", + "023d4fb17b76e0fe0764971df8b8538b735a1d67", + }}, + */ + /* + // this contains a cherry-pick at 094d0e7d5d691 (with 3f34438d) + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "desk", []string{ + "ffcda27c2de6768ee83f3f4a027fa4ab57d50f09", + "a0c1e853158ccbaf95574220bbf3b54509034a9f", + "decfc524570c407d6bba0f217e534c8b47dbdbee", + "1413872d5b3af7cd674bbe0e1f23387cd5d940e6", + "40cd5a91d916e7b2f331e4e85fdc52636fd7cff7", + "8e07d73aa0e3780f8c7cf8ad1a6b263df26a0a52", + "19c56f95720ac3630efe9f29b1a252581d6cbc0c", + "9ea46ccc6d253cffb4b7b66e936987d87de136e4", + "094d0e7d5d69141c98a606910ba64786c5565da0", + "801e62706a9e4fef75fcaca9c78744de0bc36e6a", + "eddf335f31c73624ed3f40dc5fcad50136074b2b", + "c659093f06eb2bd68c6252caeab605e5cd8aa49e", + "d94b3fe8ce0e3a474874d742992d432cd040582f", + "93cddf036df2d8509f910063696acd556ca7600f", + "b3d4cb0c826b16b301f088581d681654d8de6c07", + "52d90f9b513dd3c5330663cba39396e6b8a3ba4e", + "15919e99ded03c6ceea9ff98558e77a322a4dadb", + "803bf37847633e2f685a46a27b11facf22efebec", + "c07ad524ee1e616c70bf2ea7a0ee4f4a01195d78", + "b91aff30f318fda461d009c308490613b394f3e2", + "67cec1e8a3f21c6eb11678e3f31ffd228b55b783", + "bbe404c78af7525fabc57b9e7aa7c100b0d39f7a", + "5dd078848786c2babc2511e9502fa98518cf3535", + "7970ae7cc165c5205945dfb704d67d53031f550a", + "33091ac904747747ff30f107d4d0f22fa872eccf", + "069f81cab12d185ba1b509be946c47897cd4fb1f", + "13ce6c1c77c831f381974aa1c62008a414bd2b37", + }}, + */ + /* + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "InstallSpinnaker.sh", []string{ + "ce9f123d790717599aaeb76bc62510de437761be", + "23673af3ad70b50bba7fdafadc2323302f5ba520", + "b7015a5d36990d69a054482556127b9c7404a24a", + "582da9622e3a72a19cd261a017276d72b5b0051a", + "0c5bb1e4392e751f884f3c57de5d4aee72c40031", + "c9c2a0ec03968ab17e8b16fdec9661eb1dbea173", + "a3cdf880826b4d9af42b93f4a2df29a91ab31d35", + "18526c447f5174d33c96aac6d6433318b0e2021c", + "2a6288be1c8ea160c443ca3cd0fe826ff2387d37", + "9e74d009894d73dd07773ea6b3bdd8323db980f7", + "d2f6214b625db706384b378a29cc4c22237db97a", + "202a9c720b3ba8106e022a0ad027ebe279040c78", + "791bcd1592828d9d5d16e83f3a825fb08b0ba22d", + "01e65d67eed8afcb67a6bdf1c962541f62b299c9", + "6328ee836affafc1b52127147b5ca07300ac78e6", + "3de4f77c105f700f50d9549d32b9a05a01b46c4b", + "8980daf661408a3faa1f22c225702a5c1d11d5c9", + "8eb116de9128c314ac8a6f5310ca500b8c74f5db", + "88e841aad37b71b78a8fb88bc75fe69499d527c7", + "370d61cdbc1f3c90db6759f1599ccbabd40ad6c1", + "505577dc87d300cf562dc4702a05a5615d90d855", + "b5c6053a46993b20d1b91e7b7206bffa54669ad7", + "ba486de7c025457963701114c683dcd4708e1dee", + "b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", + "a47d0aaeda421f06df248ad65bd58230766bf118", + "495c7118e7cf757aa04eab410b64bfb5b5149ad2", + "46670eb6477c353d837dbaba3cf36c5f8b86f037", + "dd2d03c19658ff96d371aef00e75e2e54702da0e", + "4bbcad219ec55a465fb48ce236cb10ca52d43b1f", + "50d0556563599366f29cb286525780004fa5a317", + "9a06d3f20eabb254d0a1e2ff7735ef007ccd595e", + "d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", + }}, + */ + /* + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/default-spinnaker-local.yml", []string{ + "ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", + "99534ecc895fe17a1d562bb3049d4168a04d0865", + "caf6d62e8285d4681514dd8027356fb019bc97ff", + "eaf7614cad81e8ab5c813dd4821129d0c04ea449", + "5a2a845bc08974a36d599a4a4b7e25be833823b0", + "41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", + "974b775a8978b120ff710cac93a21c7387b914c9", + "87e459a9a044b3109dfeb943cc82c627b61d84a6", + "5e09821cbd7d710405b61cab0a795c2982a71b9c", + "8cc2d4bdb0a15aafc7fe02cdcb03ab90c974cafa", + "3ce7b902a51bac2f10994f7d1f251b616c975e54", + "a596972a661d9a7deca8abd18b52ce1a39516e89", + "8980daf661408a3faa1f22c225702a5c1d11d5c9", + }}, + */ + /* + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/spinnaker.yml", []string{ + "ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", + "caf6d62e8285d4681514dd8027356fb019bc97ff", + "eaf7614cad81e8ab5c813dd4821129d0c04ea449", + "5a2a845bc08974a36d599a4a4b7e25be833823b0", + "41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", + "974b775a8978b120ff710cac93a21c7387b914c9", + "ed887f6547d7cd2b2d741184a06f97a0a704152b", + "d4553dac205023fa77652308af1a2d1cf52138fb", + "a596972a661d9a7deca8abd18b52ce1a39516e89", + "66ac94f0b4442707fb6f695fbed91d62b3bd9d4a", + "079e42e7c979541b6fab7343838f7b9fd4a360cd", + }}, + */ +} + +func (s *ReferencesSuite) TestObjectNotFoundError(c *C) { + h1 := plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a") + hParent := plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea") + + url := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One().DotGit().Root() + storer := memory.NewStorage() + r, err := Clone(storer, nil, &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + delete(storer.Objects, hParent) + + commit, err := r.CommitObject(h1) + c.Assert(err, IsNil) + + _, err = references(commit, "LICENSE") + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *ReferencesSuite) TestRevList(c *C) { + for _, t := range referencesTests { + r := s.NewRepositoryFromPackfile(fixtures.ByURL(t.repo).One()) + + commit, err := r.CommitObject(plumbing.NewHash(t.commit)) + c.Assert(err, IsNil) + + revs, err := references(commit, t.path) + c.Assert(err, IsNil) + c.Assert(len(revs), Equals, len(t.revs)) + + for i := range revs { + if revs[i].Hash.String() != t.revs[i] { + commit, err := s.Repository.CommitObject(plumbing.NewHash(t.revs[i])) + c.Assert(err, IsNil) + equiv, err := equivalent(t.path, revs[i], commit) + c.Assert(err, IsNil) + if equiv { + fmt.Printf("cherry-pick detected: %s %s\n", revs[i].Hash.String(), t.revs[i]) + } else { + c.Fatalf("\nrepo=%s, commit=%s, path=%s, \n%s", + t.repo, t.commit, t.path, compareSideBySide(t.revs, revs)) + } + } + } + } +} + +// same length is assumed +func compareSideBySide(a []string, b []*object.Commit) string { + var buf bytes.Buffer + buf.WriteString("\t EXPECTED OBTAINED ") + var sep string + var obt string + for i := range a { + obt = b[i].Hash.String() + if a[i] != obt { + sep = "------" + } else { + sep = " " + } + buf.WriteString(fmt.Sprintf("\n%d", i+1)) + buf.WriteString(sep) + buf.WriteString(a[i]) + buf.WriteString(sep) + buf.WriteString(obt) + } + return buf.String() +} + +var cherryPicks = [...][]string{ + // repo, path, commit a, commit b + {"https://github.com/jamesob/desk.git", "desk", "094d0e7d5d69141c98a606910ba64786c5565da0", "3f34438d54f4a1ca86db8c0f03ed8eb38f20e22c"}, +} + +// should detect cherry picks +func (s *ReferencesSuite) TestEquivalent(c *C) { + for _, t := range cherryPicks { + cs := s.commits(c, t[0], t[2], t[3]) + equiv, err := equivalent(t[1], cs[0], cs[1]) + c.Assert(err, IsNil) + c.Assert(equiv, Equals, true, Commentf("repo=%s, file=%s, a=%s b=%s", t[0], t[1], t[2], t[3])) + } +} + +// returns the commits from a slice of hashes +func (s *ReferencesSuite) commits(c *C, repo string, hs ...string) []*object.Commit { + r := s.NewRepositoryFromPackfile(fixtures.ByURL(repo).One()) + + result := make([]*object.Commit, 0, len(hs)) + for _, h := range hs { + commit, err := r.CommitObject(plumbing.NewHash(h)) + c.Assert(err, IsNil) + + result = append(result, commit) + } + + return result +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/remote.go b/vendor/github.com/devtron-labs/go-git/remote.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/remote.go rename to vendor/github.com/devtron-labs/go-git/remote.go index baee7a08..32a50c73 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/remote.go +++ b/vendor/github.com/devtron-labs/go-git/remote.go @@ -6,23 +6,23 @@ import ( "fmt" "io" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/format/packfile" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband" + "github.com/devtron-labs/go-git/plumbing/revlist" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/client" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/storage/filesystem" + "github.com/devtron-labs/go-git/storage/memory" + "github.com/devtron-labs/go-git/utils/ioutil" "gopkg.in/src-d/go-billy.v4/osfs" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" - "gopkg.in/src-d/go-git.v4/plumbing/revlist" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/client" - "gopkg.in/src-d/go-git.v4/storage" - "gopkg.in/src-d/go-git.v4/storage/filesystem" - "gopkg.in/src-d/go-git.v4/storage/memory" - "gopkg.in/src-d/go-git.v4/utils/ioutil" ) var ( diff --git a/vendor/github.com/devtron-labs/go-git/remote_test.go b/vendor/github.com/devtron-labs/go-git/remote_test.go new file mode 100644 index 00000000..df632701 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/remote_test.go @@ -0,0 +1,889 @@ +package git + +import ( + "bytes" + "context" + "io" + "io/ioutil" + "os" + "runtime" + "time" + + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/storage/filesystem" + "github.com/devtron-labs/go-git/storage/memory" + + fixtures "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-billy.v4/osfs" +) + +type RemoteSuite struct { + BaseSuite +} + +var _ = Suite(&RemoteSuite{}) + +func (s *RemoteSuite) TestFetchInvalidEndpoint(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}}) + err := r.Fetch(&FetchOptions{RemoteName: "foo"}) + c.Assert(err, ErrorMatches, ".*invalid character.*") +} + +func (s *RemoteSuite) TestFetchNonExistentEndpoint(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}}) + err := r.Fetch(&FetchOptions{}) + c.Assert(err, NotNil) +} + +func (s *RemoteSuite) TestFetchInvalidSchemaEndpoint(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) + err := r.Fetch(&FetchOptions{}) + c.Assert(err, ErrorMatches, ".*unsupported scheme.*") +} + +func (s *RemoteSuite) TestFetchInvalidFetchOptions(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) + invalid := config.RefSpec("^*$ñ") + err := r.Fetch(&FetchOptions{RefSpecs: []config.RefSpec{invalid}}) + c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) +} + +func (s *RemoteSuite) TestFetchWildcard(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + s.testFetch(c, r, &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + }) +} + +func (s *RemoteSuite) TestFetchWildcardTags(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, + }) + + s.testFetch(c, r, &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), + plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"), + plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"), + plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"), + plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"), + plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), + }) +} + +func (s *RemoteSuite) TestFetch(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, + }) + + s.testFetch(c, r, &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), + }) +} + +func (s *RemoteSuite) TestFetchNonExistantReference(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, + }) + + err := r.Fetch(&FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/foo:refs/remotes/origin/foo"), + }, + }) + + c.Assert(err, ErrorMatches, "couldn't find remote ref.*") +} + +func (s *RemoteSuite) TestFetchContext(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, + }) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err := r.FetchContext(ctx, &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), + }, + }) + c.Assert(err, NotNil) +} + +func (s *RemoteSuite) TestFetchWithAllTags(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, + }) + + s.testFetch(c, r, &FetchOptions{ + Tags: AllTags, + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), + plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"), + plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"), + plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"), + plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"), + plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), + }) +} + +func (s *RemoteSuite) TestFetchWithNoTags(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, + }) + + s.testFetch(c, r, &FetchOptions{ + Tags: NoTags, + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), + }) + +} + +func (s *RemoteSuite) TestFetchWithDepth(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + s.testFetch(c, r, &FetchOptions{ + Depth: 1, + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + }) + + c.Assert(r.s.(*memory.Storage).Objects, HasLen, 18) +} + +func (s *RemoteSuite) testFetch(c *C, r *Remote, o *FetchOptions, expected []*plumbing.Reference) { + err := r.Fetch(o) + c.Assert(err, IsNil) + + var refs int + l, err := r.s.IterReferences() + c.Assert(err, IsNil) + l.ForEach(func(r *plumbing.Reference) error { refs++; return nil }) + + c.Assert(refs, Equals, len(expected)) + + for _, exp := range expected { + r, err := r.s.Reference(exp.Name()) + c.Assert(err, IsNil) + c.Assert(exp.String(), Equals, r.String()) + } +} + +func (s *RemoteSuite) TestFetchWithProgress(c *C) { + url := s.GetBasicLocalRepositoryURL() + sto := memory.NewStorage() + buf := bytes.NewBuffer(nil) + + r := NewRemote(sto, &config.RemoteConfig{Name: "foo", URLs: []string{url}}) + + refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") + err := r.Fetch(&FetchOptions{ + RefSpecs: []config.RefSpec{refspec}, + Progress: buf, + }) + + c.Assert(err, IsNil) + c.Assert(sto.Objects, HasLen, 31) + + c.Assert(buf.Len(), Not(Equals), 0) +} + +type mockPackfileWriter struct { + storage.Storer + PackfileWriterCalled bool +} + +func (m *mockPackfileWriter) PackfileWriter() (io.WriteCloser, error) { + m.PackfileWriterCalled = true + return m.Storer.(storer.PackfileWriter).PackfileWriter() +} + +func (s *RemoteSuite) TestFetchWithPackfileWriter(c *C) { + dir, err := ioutil.TempDir("", "fetch") + c.Assert(err, IsNil) + + defer os.RemoveAll(dir) // clean up + + fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) + c.Assert(err, IsNil) + + mock := &mockPackfileWriter{Storer: fss} + + url := s.GetBasicLocalRepositoryURL() + r := NewRemote(mock, &config.RemoteConfig{Name: "foo", URLs: []string{url}}) + + refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") + err = r.Fetch(&FetchOptions{ + RefSpecs: []config.RefSpec{refspec}, + }) + + c.Assert(err, IsNil) + + var count int + iter, err := mock.IterEncodedObjects(plumbing.AnyObject) + c.Assert(err, IsNil) + + iter.ForEach(func(plumbing.EncodedObject) error { + count++ + return nil + }) + + c.Assert(count, Equals, 31) + c.Assert(mock.PackfileWriterCalled, Equals, true) +} + +func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) { + url := s.GetBasicLocalRepositoryURL() + s.doTestFetchNoErrAlreadyUpToDate(c, url) +} + +func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateButStillUpdateLocalRemoteRefs(c *C) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + o := &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), + }, + } + + err := r.Fetch(o) + c.Assert(err, IsNil) + + // Simulate an out of date remote ref even though we have the new commit locally + r.s.SetReference(plumbing.NewReferenceFromStrings( + "refs/remotes/origin/master", "918c48b83bd081e863dbe1b80f8998f058cd8294", + )) + + err = r.Fetch(o) + c.Assert(err, IsNil) + + exp := plumbing.NewReferenceFromStrings( + "refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + ) + + ref, err := r.s.Reference("refs/remotes/origin/master") + c.Assert(err, IsNil) + c.Assert(exp.String(), Equals, ref.String()) +} + +func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateWithNonCommitObjects(c *C) { + fixture := fixtures.ByTag("tags").One() + url := s.GetLocalRepositoryURL(fixture) + s.doTestFetchNoErrAlreadyUpToDate(c, url) +} + +func (s *RemoteSuite) doTestFetchNoErrAlreadyUpToDate(c *C, url string) { + r := NewRemote(memory.NewStorage(), &config.RemoteConfig{URLs: []string{url}}) + + o := &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), + }, + } + + err := r.Fetch(o) + c.Assert(err, IsNil) + err = r.Fetch(o) + c.Assert(err, Equals, NoErrAlreadyUpToDate) +} + +func (s *RemoteSuite) testFetchFastForward(c *C, sto storage.Storer) { + r := NewRemote(sto, &config.RemoteConfig{ + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + s.testFetch(c, r, &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/master:refs/heads/master"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + }) + + // First make sure that we error correctly when a force is required. + err := r.Fetch(&FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("refs/heads/branch:refs/heads/master"), + }, + }) + c.Assert(err, Equals, ErrForceNeeded) + + // And that forcing it fixes the problem. + err = r.Fetch(&FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/branch:refs/heads/master"), + }, + }) + c.Assert(err, IsNil) + + // Now test that a fast-forward, non-force fetch works. + r.s.SetReference(plumbing.NewReferenceFromStrings( + "refs/heads/master", "918c48b83bd081e863dbe1b80f8998f058cd8294", + )) + s.testFetch(c, r, &FetchOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("refs/heads/master:refs/heads/master"), + }, + }, []*plumbing.Reference{ + plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + }) +} + +func (s *RemoteSuite) TestFetchFastForwardMem(c *C) { + s.testFetchFastForward(c, memory.NewStorage()) +} + +func (s *RemoteSuite) TestFetchFastForwardFS(c *C) { + dir, err := ioutil.TempDir("", "fetch") + c.Assert(err, IsNil) + + defer os.RemoveAll(dir) // clean up + + fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) + + // This exercises `storage.filesystem.Storage.CheckAndSetReference()`. + s.testFetchFastForward(c, fss) +} + +func (s *RemoteSuite) TestString(c *C) { + r := NewRemote(nil, &config.RemoteConfig{ + Name: "foo", + URLs: []string{"https://github.com/git-fixtures/basic.git"}, + }) + + c.Assert(r.String(), Equals, ""+ + "foo\thttps://github.com/git-fixtures/basic.git (fetch)\n"+ + "foo\thttps://github.com/git-fixtures/basic.git (push)", + ) +} + +func (s *RemoteSuite) TestPushToEmptyRepository(c *C) { + url := c.MkDir() + server, err := PlainInit(url, true) + c.Assert(err, IsNil) + + srcFs := fixtures.Basic().One().DotGit() + sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) + + r := NewRemote(sto, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{url}, + }) + + rs := config.RefSpec("refs/heads/*:refs/heads/*") + err = r.Push(&PushOptions{ + RefSpecs: []config.RefSpec{rs}, + }) + c.Assert(err, IsNil) + + iter, err := r.s.IterReferences() + c.Assert(err, IsNil) + + expected := make(map[string]string) + iter.ForEach(func(ref *plumbing.Reference) error { + if !ref.Name().IsBranch() { + return nil + } + + expected[ref.Name().String()] = ref.Hash().String() + return nil + }) + c.Assert(err, IsNil) + + AssertReferences(c, server, expected) + +} + +func (s *RemoteSuite) TestPushContext(c *C) { + url := c.MkDir() + _, err := PlainInit(url, true) + c.Assert(err, IsNil) + + fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() + sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + r := NewRemote(sto, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{url}, + }) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + numGoroutines := runtime.NumGoroutine() + + err = r.PushContext(ctx, &PushOptions{ + RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}, + }) + c.Assert(err, NotNil) + + // let the goroutine from pushHashes finish and check that the number of + // goroutines is the same as before + time.Sleep(100 * time.Millisecond) + c.Assert(runtime.NumGoroutine(), Equals, numGoroutines) +} + +func (s *RemoteSuite) TestPushTags(c *C) { + url := c.MkDir() + server, err := PlainInit(url, true) + c.Assert(err, IsNil) + + fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() + sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + r := NewRemote(sto, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{url}, + }) + + err = r.Push(&PushOptions{ + RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}, + }) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/tags/lightweight-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", + "refs/tags/annotated-tag": "b742a2a9fa0afcfa9a6fad080980fbc26b007c69", + "refs/tags/commit-tag": "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc", + "refs/tags/blob-tag": "fe6cb94756faa81e5ed9240f9191b833db5f40ae", + "refs/tags/tree-tag": "152175bf7e5580299fa1f0ba41ef6474cc043b70", + }) +} + +func (s *RemoteSuite) TestPushNoErrAlreadyUpToDate(c *C) { + fs := fixtures.Basic().One().DotGit() + sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + r := NewRemote(sto, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{fs.Root()}, + }) + + err := r.Push(&PushOptions{ + RefSpecs: []config.RefSpec{"refs/heads/*:refs/heads/*"}, + }) + c.Assert(err, Equals, NoErrAlreadyUpToDate) +} + +func (s *RemoteSuite) TestPushDeleteReference(c *C) { + fs := fixtures.Basic().One().DotGit() + sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + r, err := PlainClone(c.MkDir(), true, &CloneOptions{ + URL: fs.Root(), + }) + c.Assert(err, IsNil) + + remote, err := r.Remote(DefaultRemoteName) + c.Assert(err, IsNil) + + err = remote.Push(&PushOptions{ + RefSpecs: []config.RefSpec{":refs/heads/branch"}, + }) + c.Assert(err, IsNil) + + _, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch")) + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) + + _, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) +} + +func (s *RemoteSuite) TestPushRejectNonFastForward(c *C) { + fs := fixtures.Basic().One().DotGit() + server := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + r, err := PlainClone(c.MkDir(), true, &CloneOptions{ + URL: fs.Root(), + }) + c.Assert(err, IsNil) + + remote, err := r.Remote(DefaultRemoteName) + c.Assert(err, IsNil) + + branch := plumbing.ReferenceName("refs/heads/branch") + oldRef, err := server.Reference(branch) + c.Assert(err, IsNil) + c.Assert(oldRef, NotNil) + + err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ + "refs/heads/master:refs/heads/branch", + }}) + c.Assert(err, ErrorMatches, "non-fast-forward update: refs/heads/branch") + + newRef, err := server.Reference(branch) + c.Assert(err, IsNil) + c.Assert(newRef, DeepEquals, oldRef) +} + +func (s *RemoteSuite) TestPushForce(c *C) { + f := fixtures.Basic().One() + sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) + + dstFs := f.DotGit() + dstSto := filesystem.NewStorage(dstFs, cache.NewObjectLRUDefault()) + + url := dstFs.Root() + r := NewRemote(sto, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{url}, + }) + + oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) + c.Assert(err, IsNil) + c.Assert(oldRef, NotNil) + + err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{ + config.RefSpec("+refs/heads/master:refs/heads/branch"), + }}) + c.Assert(err, IsNil) + + newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) + c.Assert(err, IsNil) + c.Assert(newRef, Not(DeepEquals), oldRef) +} + +func (s *RemoteSuite) TestPushPrune(c *C) { + fs := fixtures.Basic().One().DotGit() + url := c.MkDir() + server, err := PlainClone(url, true, &CloneOptions{ + URL: fs.Root(), + }) + c.Assert(err, IsNil) + + r, err := PlainClone(c.MkDir(), true, &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + tag, err := r.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true) + c.Assert(err, IsNil) + + err = r.DeleteTag("v1.0.0") + c.Assert(err, IsNil) + + remote, err := r.Remote(DefaultRemoteName) + c.Assert(err, IsNil) + + ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) + c.Assert(err, IsNil) + + err = remote.Push(&PushOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("refs/heads/*:refs/heads/*"), + }, + Prune: true, + }) + c.Assert(err, Equals, NoErrAlreadyUpToDate) + + AssertReferences(c, server, map[string]string{ + "refs/tags/v1.0.0": tag.Hash().String(), + }) + + err = remote.Push(&PushOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec("*:*"), + }, + Prune: true, + }) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/remotes/origin/master": ref.Hash().String(), + }) + + AssertReferences(c, server, map[string]string{ + "refs/remotes/origin/master": ref.Hash().String(), + }) + + ref, err = server.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true) + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) +} + +func (s *RemoteSuite) TestPushNewReference(c *C) { + fs := fixtures.Basic().One().DotGit() + url := c.MkDir() + server, err := PlainClone(url, true, &CloneOptions{ + URL: fs.Root(), + }) + c.Assert(err, IsNil) + + r, err := PlainClone(c.MkDir(), true, &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + remote, err := r.Remote(DefaultRemoteName) + c.Assert(err, IsNil) + + ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) + c.Assert(err, IsNil) + + err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ + "refs/heads/master:refs/heads/branch2", + }}) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/heads/branch2": ref.Hash().String(), + }) + + AssertReferences(c, r, map[string]string{ + "refs/remotes/origin/branch2": ref.Hash().String(), + }) +} + +func (s *RemoteSuite) TestPushNewReferenceAndDeleteInBatch(c *C) { + fs := fixtures.Basic().One().DotGit() + url := c.MkDir() + server, err := PlainClone(url, true, &CloneOptions{ + URL: fs.Root(), + }) + c.Assert(err, IsNil) + + r, err := PlainClone(c.MkDir(), true, &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + remote, err := r.Remote(DefaultRemoteName) + c.Assert(err, IsNil) + + ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) + c.Assert(err, IsNil) + + err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ + "refs/heads/master:refs/heads/branch2", + ":refs/heads/branch", + }}) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/heads/branch2": ref.Hash().String(), + }) + + AssertReferences(c, r, map[string]string{ + "refs/remotes/origin/branch2": ref.Hash().String(), + }) + + _, err = server.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) +} + +func (s *RemoteSuite) TestPushInvalidEndpoint(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}}) + err := r.Push(&PushOptions{RemoteName: "foo"}) + c.Assert(err, ErrorMatches, ".*invalid character.*") +} + +func (s *RemoteSuite) TestPushNonExistentEndpoint(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}}) + err := r.Push(&PushOptions{}) + c.Assert(err, NotNil) +} + +func (s *RemoteSuite) TestPushInvalidSchemaEndpoint(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "origin", URLs: []string{"qux://foo"}}) + err := r.Push(&PushOptions{}) + c.Assert(err, ErrorMatches, ".*unsupported scheme.*") +} + +func (s *RemoteSuite) TestPushInvalidFetchOptions(c *C) { + r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) + invalid := config.RefSpec("^*$ñ") + err := r.Push(&PushOptions{RefSpecs: []config.RefSpec{invalid}}) + c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) +} + +func (s *RemoteSuite) TestPushInvalidRefSpec(c *C) { + r := NewRemote(nil, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{"some-url"}, + }) + + rs := config.RefSpec("^*$**") + err := r.Push(&PushOptions{ + RefSpecs: []config.RefSpec{rs}, + }) + c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) +} + +func (s *RemoteSuite) TestPushWrongRemoteName(c *C) { + r := NewRemote(nil, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{"some-url"}, + }) + + err := r.Push(&PushOptions{ + RemoteName: "other-remote", + }) + c.Assert(err, ErrorMatches, ".*remote names don't match.*") +} + +func (s *RemoteSuite) TestGetHaves(c *C) { + f := fixtures.Basic().One() + sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) + + var localRefs = []*plumbing.Reference{ + plumbing.NewReferenceFromStrings( + "foo", + "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", + ), + plumbing.NewReferenceFromStrings( + "bar", + "fe6cb94756faa81e5ed9240f9191b833db5f40ae", + ), + plumbing.NewReferenceFromStrings( + "qux", + "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", + ), + } + + l, err := getHaves(localRefs, memory.NewStorage(), sto) + c.Assert(err, IsNil) + c.Assert(l, HasLen, 2) +} + +func (s *RemoteSuite) TestList(c *C) { + repo := fixtures.Basic().One() + remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{repo.URL}, + }) + + refs, err := remote.List(&ListOptions{}) + c.Assert(err, IsNil) + + expected := []*plumbing.Reference{ + plumbing.NewSymbolicReference("HEAD", "refs/heads/master"), + plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewReferenceFromStrings("refs/heads/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewReferenceFromStrings("refs/pull/1/head", "b8e471f58bcbca63b07bda20e428190409c2db47"), + plumbing.NewReferenceFromStrings("refs/pull/2/head", "9632f02833b2f9613afb5e75682132b0b22e4a31"), + plumbing.NewReferenceFromStrings("refs/pull/2/merge", "c37f58a130ca555e42ff96a071cb9ccb3f437504"), + } + c.Assert(len(refs), Equals, len(expected)) + for _, e := range expected { + found := false + for _, r := range refs { + if r.Name() == e.Name() { + found = true + c.Assert(r, DeepEquals, e) + } + } + c.Assert(found, Equals, true) + } +} + +func (s *RemoteSuite) TestUpdateShallows(c *C) { + hashes := []plumbing.Hash{ + plumbing.NewHash("0000000000000000000000000000000000000001"), + plumbing.NewHash("0000000000000000000000000000000000000002"), + plumbing.NewHash("0000000000000000000000000000000000000003"), + plumbing.NewHash("0000000000000000000000000000000000000004"), + plumbing.NewHash("0000000000000000000000000000000000000005"), + plumbing.NewHash("0000000000000000000000000000000000000006"), + } + + tests := []struct { + hashes []plumbing.Hash + result []plumbing.Hash + }{ + // add to empty shallows + {hashes[0:2], hashes[0:2]}, + // add new hashes + {hashes[2:4], hashes[0:4]}, + // add some hashes already in shallow list + {hashes[2:6], hashes[0:6]}, + // add all hashes + {hashes[0:6], hashes[0:6]}, + // add empty list + {nil, hashes[0:6]}, + } + + remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{ + Name: DefaultRemoteName, + }) + + shallows, err := remote.s.Shallow() + c.Assert(err, IsNil) + c.Assert(len(shallows), Equals, 0) + + resp := new(packp.UploadPackResponse) + o := &FetchOptions{ + Depth: 1, + } + + for _, t := range tests { + resp.Shallows = t.hashes + err = remote.updateShallow(o, resp) + c.Assert(err, IsNil) + + shallow, err := remote.s.Shallow() + c.Assert(err, IsNil) + c.Assert(len(shallow), Equals, len(t.result)) + c.Assert(shallow, DeepEquals, t.result) + } +} + +func (s *RemoteSuite) TestUseRefDeltas(c *C) { + url := c.MkDir() + _, err := PlainInit(url, true) + c.Assert(err, IsNil) + + fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() + sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + r := NewRemote(sto, &config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{url}, + }) + + ar := packp.NewAdvRefs() + + ar.Capabilities.Add(capability.OFSDelta) + c.Assert(r.useRefDeltas(ar), Equals, false) + + ar.Capabilities.Delete(capability.OFSDelta) + c.Assert(r.useRefDeltas(ar), Equals, true) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/repository.go b/vendor/github.com/devtron-labs/go-git/repository.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/repository.go rename to vendor/github.com/devtron-labs/go-git/repository.go index 2251d6cf..12795e42 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/repository.go +++ b/vendor/github.com/devtron-labs/go-git/repository.go @@ -13,17 +13,17 @@ import ( "strings" "time" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/internal/revision" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/format/packfile" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/storage/filesystem" + "github.com/devtron-labs/go-git/utils/ioutil" "golang.org/x/crypto/openpgp" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/internal/revision" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/storage" - "gopkg.in/src-d/go-git.v4/storage/filesystem" - "gopkg.in/src-d/go-git.v4/utils/ioutil" "gopkg.in/src-d/go-billy.v4" "gopkg.in/src-d/go-billy.v4/osfs" @@ -667,21 +667,20 @@ func (r *Repository) buildTagSignature(tag *object.Tag, signKey *openpgp.Entity) // If you want to check to see if the tag is an annotated tag, you can call // TagObject on the hash of the reference in ForEach: // -// ref, err := r.Tag("v0.1.0") -// if err != nil { -// // Handle error -// } -// -// obj, err := r.TagObject(ref.Hash()) -// switch err { -// case nil: -// // Tag object present -// case plumbing.ErrObjectNotFound: -// // Not a tag object -// default: -// // Some other error -// } +// ref, err := r.Tag("v0.1.0") +// if err != nil { +// // Handle error +// } // +// obj, err := r.TagObject(ref.Hash()) +// switch err { +// case nil: +// // Tag object present +// case plumbing.ErrObjectNotFound: +// // Not a tag object +// default: +// // Some other error +// } func (r *Repository) Tag(name string) (*plumbing.Reference, error) { ref, err := r.Reference(plumbing.ReferenceName(path.Join("refs", "tags", name)), false) if err != nil { @@ -1128,26 +1127,25 @@ func commitIterFunc(order LogOrder) func(c *object.Commit) object.CommitIter { // If you want to check to see if the tag is an annotated tag, you can call // TagObject on the hash Reference passed in through ForEach: // -// iter, err := r.Tags() -// if err != nil { -// // Handle error -// } -// -// if err := iter.ForEach(func (ref *plumbing.Reference) error { -// obj, err := r.TagObject(ref.Hash()) -// switch err { -// case nil: -// // Tag object present -// case plumbing.ErrObjectNotFound: -// // Not a tag object -// default: -// // Some other error -// return err -// } -// }); err != nil { -// // Handle outer iterator error -// } +// iter, err := r.Tags() +// if err != nil { +// // Handle error +// } // +// if err := iter.ForEach(func (ref *plumbing.Reference) error { +// obj, err := r.TagObject(ref.Hash()) +// switch err { +// case nil: +// // Tag object present +// case plumbing.ErrObjectNotFound: +// // Not a tag object +// default: +// // Some other error +// return err +// } +// }); err != nil { +// // Handle outer iterator error +// } func (r *Repository) Tags() (storer.ReferenceIter, error) { refIter, err := r.Storer.IterReferences() if err != nil { diff --git a/vendor/github.com/devtron-labs/go-git/repository_test.go b/vendor/github.com/devtron-labs/go-git/repository_test.go new file mode 100644 index 00000000..4c3f7c43 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/repository_test.go @@ -0,0 +1,2695 @@ +package git + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/armor" + openpgperr "golang.org/x/crypto/openpgp/errors" + + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/storage/filesystem" + "github.com/devtron-labs/go-git/storage/memory" + + "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-billy.v4/memfs" + "gopkg.in/src-d/go-billy.v4/osfs" + "gopkg.in/src-d/go-billy.v4/util" +) + +type RepositorySuite struct { + BaseSuite +} + +var _ = Suite(&RepositorySuite{}) + +func (s *RepositorySuite) TestInit(c *C) { + r, err := Init(memory.NewStorage(), memfs.New()) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Core.IsBare, Equals, false) +} + +func (s *RepositorySuite) TestInitNonStandardDotGit(c *C) { + dir, err := ioutil.TempDir("", "init-non-standard") + c.Assert(err, IsNil) + c.Assert(os.RemoveAll(dir), IsNil) + + fs := osfs.New(dir) + dot, _ := fs.Chroot("storage") + storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) + + wt, _ := fs.Chroot("worktree") + r, err := Init(storage, wt) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + f, err := fs.Open(fs.Join("worktree", ".git")) + c.Assert(err, IsNil) + + all, err := ioutil.ReadAll(f) + c.Assert(err, IsNil) + c.Assert(string(all), Equals, fmt.Sprintf("gitdir: %s\n", filepath.Join("..", "storage"))) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Core.Worktree, Equals, filepath.Join("..", "worktree")) +} + +func (s *RepositorySuite) TestInitStandardDotGit(c *C) { + dir, err := ioutil.TempDir("", "init-standard") + c.Assert(err, IsNil) + c.Assert(os.RemoveAll(dir), IsNil) + + fs := osfs.New(dir) + dot, _ := fs.Chroot(".git") + storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) + + r, err := Init(storage, fs) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + l, err := fs.ReadDir(".git") + c.Assert(err, IsNil) + c.Assert(len(l) > 0, Equals, true) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Core.Worktree, Equals, "") +} + +func (s *RepositorySuite) TestInitBare(c *C) { + r, err := Init(memory.NewStorage(), nil) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Core.IsBare, Equals, true) + +} + +func (s *RepositorySuite) TestInitAlreadyExists(c *C) { + st := memory.NewStorage() + + r, err := Init(st, nil) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = Init(st, nil) + c.Assert(err, Equals, ErrRepositoryAlreadyExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestOpen(c *C) { + st := memory.NewStorage() + + r, err := Init(st, memfs.New()) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = Open(st, memfs.New()) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestOpenBare(c *C) { + st := memory.NewStorage() + + r, err := Init(st, nil) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = Open(st, nil) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestOpenBareMissingWorktree(c *C) { + st := memory.NewStorage() + + r, err := Init(st, memfs.New()) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = Open(st, nil) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestOpenNotExists(c *C) { + r, err := Open(memory.NewStorage(), nil) + c.Assert(err, Equals, ErrRepositoryNotExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestClone(c *C) { + r, err := Clone(memory.NewStorage(), nil, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) +} + +func (s *RepositorySuite) TestCloneContext(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + r, err := CloneContext(ctx, memory.NewStorage(), nil, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(r, NotNil) + c.Assert(err, ErrorMatches, ".* context canceled") +} + +func (s *RepositorySuite) TestCloneWithTags(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, err := Clone(memory.NewStorage(), nil, &CloneOptions{URL: url, Tags: NoTags}) + c.Assert(err, IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) + + i, err := r.References() + c.Assert(err, IsNil) + + var count int + i.ForEach(func(r *plumbing.Reference) error { count++; return nil }) + + c.Assert(count, Equals, 3) +} + +func (s *RepositorySuite) TestCreateRemoteAndRemote(c *C) { + r, _ := Init(memory.NewStorage(), nil) + remote, err := r.CreateRemote(&config.RemoteConfig{ + Name: "foo", + URLs: []string{"http://foo/foo.git"}, + }) + + c.Assert(err, IsNil) + c.Assert(remote.Config().Name, Equals, "foo") + + alt, err := r.Remote("foo") + c.Assert(err, IsNil) + c.Assert(alt, Not(Equals), remote) + c.Assert(alt.Config().Name, Equals, "foo") +} + +func (s *RepositorySuite) TestCreateRemoteInvalid(c *C) { + r, _ := Init(memory.NewStorage(), nil) + remote, err := r.CreateRemote(&config.RemoteConfig{}) + + c.Assert(err, Equals, config.ErrRemoteConfigEmptyName) + c.Assert(remote, IsNil) +} + +func (s *RepositorySuite) TestCreateRemoteAnonymous(c *C) { + r, _ := Init(memory.NewStorage(), nil) + remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{ + Name: "anonymous", + URLs: []string{"http://foo/foo.git"}, + }) + + c.Assert(err, IsNil) + c.Assert(remote.Config().Name, Equals, "anonymous") +} + +func (s *RepositorySuite) TestCreateRemoteAnonymousInvalidName(c *C) { + r, _ := Init(memory.NewStorage(), nil) + remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{ + Name: "not_anonymous", + URLs: []string{"http://foo/foo.git"}, + }) + + c.Assert(err, Equals, ErrAnonymousRemoteName) + c.Assert(remote, IsNil) +} + +func (s *RepositorySuite) TestCreateRemoteAnonymousInvalid(c *C) { + r, _ := Init(memory.NewStorage(), nil) + remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{}) + + c.Assert(err, Equals, config.ErrRemoteConfigEmptyName) + c.Assert(remote, IsNil) +} + +func (s *RepositorySuite) TestDeleteRemote(c *C) { + r, _ := Init(memory.NewStorage(), nil) + _, err := r.CreateRemote(&config.RemoteConfig{ + Name: "foo", + URLs: []string{"http://foo/foo.git"}, + }) + + c.Assert(err, IsNil) + + err = r.DeleteRemote("foo") + c.Assert(err, IsNil) + + alt, err := r.Remote("foo") + c.Assert(err, Equals, ErrRemoteNotFound) + c.Assert(alt, IsNil) +} + +func (s *RepositorySuite) TestCreateBranchAndBranch(c *C) { + r, _ := Init(memory.NewStorage(), nil) + testBranch := &config.Branch{ + Name: "foo", + Remote: "origin", + Merge: "refs/heads/foo", + } + err := r.CreateBranch(testBranch) + + c.Assert(err, IsNil) + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(len(cfg.Branches), Equals, 1) + branch := cfg.Branches["foo"] + c.Assert(branch.Name, Equals, testBranch.Name) + c.Assert(branch.Remote, Equals, testBranch.Remote) + c.Assert(branch.Merge, Equals, testBranch.Merge) + + branch, err = r.Branch("foo") + c.Assert(err, IsNil) + c.Assert(branch.Name, Equals, testBranch.Name) + c.Assert(branch.Remote, Equals, testBranch.Remote) + c.Assert(branch.Merge, Equals, testBranch.Merge) +} + +func (s *RepositorySuite) TestCreateBranchUnmarshal(c *C) { + r, _ := Init(memory.NewStorage(), nil) + + expected := []byte(`[core] + bare = true +[remote "foo"] + url = http://foo/foo.git + fetch = +refs/heads/*:refs/remotes/foo/* +[branch "foo"] + remote = origin + merge = refs/heads/foo +[branch "master"] + remote = origin + merge = refs/heads/master +`) + + _, err := r.CreateRemote(&config.RemoteConfig{ + Name: "foo", + URLs: []string{"http://foo/foo.git"}, + }) + c.Assert(err, IsNil) + testBranch1 := &config.Branch{ + Name: "master", + Remote: "origin", + Merge: "refs/heads/master", + } + testBranch2 := &config.Branch{ + Name: "foo", + Remote: "origin", + Merge: "refs/heads/foo", + } + err = r.CreateBranch(testBranch1) + c.Assert(err, IsNil) + err = r.CreateBranch(testBranch2) + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + marshaled, err := cfg.Marshal() + c.Assert(err, IsNil) + c.Assert(string(expected), Equals, string(marshaled)) +} + +func (s *RepositorySuite) TestBranchInvalid(c *C) { + r, _ := Init(memory.NewStorage(), nil) + branch, err := r.Branch("foo") + + c.Assert(err, NotNil) + c.Assert(branch, IsNil) +} + +func (s *RepositorySuite) TestCreateBranchInvalid(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.CreateBranch(&config.Branch{}) + + c.Assert(err, NotNil) + + testBranch := &config.Branch{ + Name: "foo", + Remote: "origin", + Merge: "refs/heads/foo", + } + err = r.CreateBranch(testBranch) + c.Assert(err, IsNil) + err = r.CreateBranch(testBranch) + c.Assert(err, NotNil) +} + +func (s *RepositorySuite) TestDeleteBranch(c *C) { + r, _ := Init(memory.NewStorage(), nil) + testBranch := &config.Branch{ + Name: "foo", + Remote: "origin", + Merge: "refs/heads/foo", + } + err := r.CreateBranch(testBranch) + + c.Assert(err, IsNil) + + err = r.DeleteBranch("foo") + c.Assert(err, IsNil) + + b, err := r.Branch("foo") + c.Assert(err, Equals, ErrBranchNotFound) + c.Assert(b, IsNil) + + err = r.DeleteBranch("foo") + c.Assert(err, Equals, ErrBranchNotFound) +} + +func (s *RepositorySuite) TestPlainInit(c *C) { + dir, err := ioutil.TempDir("", "plain-init") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Core.IsBare, Equals, true) +} + +func (s *RepositorySuite) TestPlainInitAlreadyExists(c *C) { + dir, err := ioutil.TempDir("", "plain-init") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = PlainInit(dir, true) + c.Assert(err, Equals, ErrRepositoryAlreadyExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestPlainOpen(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, false) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = PlainOpen(dir) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestPlainOpenBare(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = PlainOpen(dir) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestPlainOpenNotBare(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, false) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + r, err = PlainOpen(filepath.Join(dir, ".git")) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) testPlainOpenGitFile(c *C, f func(string, string) string) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + altDir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(altDir) + + err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(f(dir, altDir)), 0644) + c.Assert(err, IsNil) + + r, err = PlainOpen(altDir) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFile(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + return fmt.Sprintf("gitdir: %s\n", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFileNoEOL(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + return fmt.Sprintf("gitdir: %s", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFile(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + dir, err := filepath.Rel(altDir, dir) + c.Assert(err, IsNil) + return fmt.Sprintf("gitdir: %s\n", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileNoEOL(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + dir, err := filepath.Rel(altDir, dir) + c.Assert(err, IsNil) + return fmt.Sprintf("gitdir: %s\n", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileTrailingGarbage(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + altDir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("gitdir: %s\nTRAILING", altDir)), 0644) + c.Assert(err, IsNil) + + r, err = PlainOpen(altDir) + c.Assert(err, Equals, ErrRepositoryNotExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileBadPrefix(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + altDir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("xgitdir: %s\n", dir)), 0644) + c.Assert(err, IsNil) + + r, err = PlainOpen(altDir) + c.Assert(err, ErrorMatches, ".*gitdir.*") + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestPlainOpenNotExists(c *C) { + r, err := PlainOpen("/not-exists/") + c.Assert(err, Equals, ErrRepositoryNotExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestPlainOpenDetectDotGit(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + subdir := filepath.Join(dir, "a", "b") + err = os.MkdirAll(subdir, 0755) + c.Assert(err, IsNil) + + r, err := PlainInit(dir, false) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + opt := &PlainOpenOptions{DetectDotGit: true} + r, err = PlainOpenWithOptions(subdir, opt) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestPlainOpenNotExistsDetectDotGit(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + opt := &PlainOpenOptions{DetectDotGit: true} + r, err := PlainOpenWithOptions(dir, opt) + c.Assert(err, Equals, ErrRepositoryNotExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestPlainClone(c *C) { + r, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 1) + c.Assert(cfg.Branches["master"].Name, Equals, "master") +} + +func (s *RepositorySuite) TestPlainCloneWithRemoteName(c *C) { + r, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + RemoteName: "test", + }) + + c.Assert(err, IsNil) + + remote, err := r.Remote("test") + c.Assert(err, IsNil) + c.Assert(remote, NotNil) +} + +func (s *RepositorySuite) TestPlainCloneOverExistingGitDirectory(c *C) { + tmpDir := c.MkDir() + r, err := PlainInit(tmpDir, false) + c.Assert(r, NotNil) + c.Assert(err, IsNil) + + r, err = PlainClone(tmpDir, false, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(r, IsNil) + c.Assert(err, Equals, ErrRepositoryAlreadyExists) +} + +func (s *RepositorySuite) TestPlainCloneContextCancel(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + r, err := PlainCloneContext(ctx, c.MkDir(), false, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(r, NotNil) + c.Assert(err, ErrorMatches, ".* context canceled") +} + +func (s *RepositorySuite) TestPlainCloneContextNonExistentWithExistentDir(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + tmpDir := c.MkDir() + repoDir := tmpDir + + r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ + URL: "incorrectOnPurpose", + }) + c.Assert(r, NotNil) + c.Assert(err, Equals, transport.ErrRepositoryNotFound) + + _, err = os.Stat(repoDir) + c.Assert(os.IsNotExist(err), Equals, false) + + names, err := ioutil.ReadDir(repoDir) + c.Assert(err, IsNil) + c.Assert(names, HasLen, 0) +} + +func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNonExistentDir(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + tmpDir := c.MkDir() + repoDir := filepath.Join(tmpDir, "repoDir") + + r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ + URL: "incorrectOnPurpose", + }) + c.Assert(r, NotNil) + c.Assert(err, Equals, transport.ErrRepositoryNotFound) + + _, err = os.Stat(repoDir) + c.Assert(os.IsNotExist(err), Equals, true) +} + +func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotDir(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + tmpDir := c.MkDir() + repoDir := filepath.Join(tmpDir, "repoDir") + f, err := os.Create(repoDir) + c.Assert(err, IsNil) + c.Assert(f.Close(), IsNil) + + r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ + URL: "incorrectOnPurpose", + }) + c.Assert(r, IsNil) + c.Assert(err, ErrorMatches, ".*not a directory.*") + + fi, err := os.Stat(repoDir) + c.Assert(err, IsNil) + c.Assert(fi.IsDir(), Equals, false) +} + +func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotEmptyDir(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + tmpDir := c.MkDir() + repoDirPath := filepath.Join(tmpDir, "repoDir") + err := os.Mkdir(repoDirPath, 0777) + c.Assert(err, IsNil) + + dummyFile := filepath.Join(repoDirPath, "dummyFile") + err = ioutil.WriteFile(dummyFile, []byte(fmt.Sprint("dummyContent")), 0644) + c.Assert(err, IsNil) + + r, err := PlainCloneContext(ctx, repoDirPath, false, &CloneOptions{ + URL: "incorrectOnPurpose", + }) + c.Assert(r, NotNil) + c.Assert(err, Equals, transport.ErrRepositoryNotFound) + + _, err = os.Stat(dummyFile) + c.Assert(err, IsNil) + +} + +func (s *RepositorySuite) TestPlainCloneContextNonExistingOverExistingGitDirectory(c *C) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + tmpDir := c.MkDir() + r, err := PlainInit(tmpDir, false) + c.Assert(r, NotNil) + c.Assert(err, IsNil) + + r, err = PlainCloneContext(ctx, tmpDir, false, &CloneOptions{ + URL: "incorrectOnPurpose", + }) + c.Assert(r, IsNil) + c.Assert(err, Equals, ErrRepositoryAlreadyExists) +} + +func (s *RepositorySuite) TestPlainCloneWithRecurseSubmodules(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + dir, err := ioutil.TempDir("", "plain-clone-submodule") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + path := fixtures.ByTag("submodule").One().Worktree().Root() + r, err := PlainClone(dir, false, &CloneOptions{ + URL: path, + RecurseSubmodules: DefaultSubmoduleRecursionDepth, + }) + + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Remotes, HasLen, 1) + c.Assert(cfg.Branches, HasLen, 1) + c.Assert(cfg.Submodules, HasLen, 2) +} + +func (s *RepositorySuite) TestPlainCloneNoCheckout(c *C) { + dir, err := ioutil.TempDir("", "plain-clone-no-checkout") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + path := fixtures.ByTag("submodule").One().Worktree().Root() + r, err := PlainClone(dir, false, &CloneOptions{ + URL: path, + NoCheckout: true, + RecurseSubmodules: DefaultSubmoduleRecursionDepth, + }) + c.Assert(err, IsNil) + + h, err := r.Head() + c.Assert(err, IsNil) + c.Assert(h.Hash().String(), Equals, "b685400c1f9316f350965a5993d350bc746b0bf4") + + fi, err := osfs.New(dir).ReadDir("") + c.Assert(err, IsNil) + c.Assert(fi, HasLen, 1) // .git +} + +func (s *RepositorySuite) TestFetch(c *C) { + r, _ := Init(memory.NewStorage(), nil) + _, err := r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + c.Assert(err, IsNil) + c.Assert(r.Fetch(&FetchOptions{}), IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) + + _, err = r.Head() + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) + + branch, err := r.Reference("refs/remotes/origin/master", false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Type(), Equals, plumbing.HashReference) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") +} + +func (s *RepositorySuite) TestFetchContext(c *C) { + r, _ := Init(memory.NewStorage(), nil) + _, err := r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + c.Assert(err, IsNil) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + c.Assert(r.FetchContext(ctx, &FetchOptions{}), NotNil) +} + +func (s *RepositorySuite) TestCloneWithProgress(c *C) { + fs := memfs.New() + + buf := bytes.NewBuffer(nil) + _, err := Clone(memory.NewStorage(), fs, &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + Progress: buf, + }) + + c.Assert(err, IsNil) + c.Assert(buf.Len(), Not(Equals), 0) +} + +func (s *RepositorySuite) TestCloneDeep(c *C) { + fs := memfs.New() + r, _ := Init(memory.NewStorage(), fs) + + head, err := r.Head() + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) + c.Assert(head, IsNil) + + err = r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) + + head, err = r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.SymbolicReference) + c.Assert(head.Target().String(), Equals, "refs/heads/master") + + branch, err := r.Reference(head.Target(), false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + branch, err = r.Reference("refs/remotes/origin/master", false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Type(), Equals, plumbing.HashReference) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + fi, err := fs.ReadDir("") + c.Assert(err, IsNil) + c.Assert(fi, HasLen, 8) +} + +func (s *RepositorySuite) TestCloneConfig(c *C) { + r, _ := Init(memory.NewStorage(), nil) + + head, err := r.Head() + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) + c.Assert(head, IsNil) + + err = r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + + c.Assert(cfg.Core.IsBare, Equals, true) + c.Assert(cfg.Remotes, HasLen, 1) + c.Assert(cfg.Remotes["origin"].Name, Equals, "origin") + c.Assert(cfg.Remotes["origin"].URLs, HasLen, 1) + c.Assert(cfg.Branches, HasLen, 1) + c.Assert(cfg.Branches["master"].Name, Equals, "master") +} + +func (s *RepositorySuite) TestCloneSingleBranchAndNonHEAD(c *C) { + r, _ := Init(memory.NewStorage(), nil) + + head, err := r.Head() + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) + c.Assert(head, IsNil) + + err = r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + ReferenceName: plumbing.ReferenceName("refs/heads/branch"), + SingleBranch: true, + }) + + c.Assert(err, IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 1) + c.Assert(cfg.Branches["branch"].Name, Equals, "branch") + c.Assert(cfg.Branches["branch"].Remote, Equals, "origin") + c.Assert(cfg.Branches["branch"].Merge, Equals, plumbing.ReferenceName("refs/heads/branch")) + + head, err = r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.SymbolicReference) + c.Assert(head.Target().String(), Equals, "refs/heads/branch") + + branch, err := r.Reference(head.Target(), false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881") + + branch, err = r.Reference("refs/remotes/origin/branch", false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Type(), Equals, plumbing.HashReference) + c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881") +} + +func (s *RepositorySuite) TestCloneSingleBranch(c *C) { + r, _ := Init(memory.NewStorage(), nil) + + head, err := r.Head() + c.Assert(err, Equals, plumbing.ErrReferenceNotFound) + c.Assert(head, IsNil) + + err = r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + SingleBranch: true, + }) + + c.Assert(err, IsNil) + + remotes, err := r.Remotes() + c.Assert(err, IsNil) + c.Assert(remotes, HasLen, 1) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 1) + c.Assert(cfg.Branches["master"].Name, Equals, "master") + c.Assert(cfg.Branches["master"].Remote, Equals, "origin") + c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master")) + + head, err = r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.SymbolicReference) + c.Assert(head.Target().String(), Equals, "refs/heads/master") + + branch, err := r.Reference(head.Target(), false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + branch, err = r.Reference("refs/remotes/origin/master", false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + c.Assert(branch.Type(), Equals, plumbing.HashReference) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") +} + +func (s *RepositorySuite) TestCloneSingleTag(c *C) { + r, _ := Init(memory.NewStorage(), nil) + + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + err := r.clone(context.Background(), &CloneOptions{ + URL: url, + SingleBranch: true, + ReferenceName: plumbing.ReferenceName("refs/tags/commit-tag"), + }) + c.Assert(err, IsNil) + + branch, err := r.Reference("refs/tags/commit-tag", false) + c.Assert(err, IsNil) + c.Assert(branch, NotNil) + + conf, err := r.Config() + c.Assert(err, IsNil) + originRemote := conf.Remotes["origin"] + c.Assert(originRemote, NotNil) + c.Assert(originRemote.Fetch, HasLen, 1) + c.Assert(originRemote.Fetch[0].String(), Equals, "+refs/tags/commit-tag:refs/tags/commit-tag") +} + +func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), + }) + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 0) + + head, err := r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.HashReference) + c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + count := 0 + objects, err := r.Objects() + c.Assert(err, IsNil) + objects.ForEach(func(object.Object) error { count++; return nil }) + c.Assert(count, Equals, 28) +} + +func (s *RepositorySuite) TestCloneDetachedHEADAndSingle(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), + SingleBranch: true, + }) + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 0) + + head, err := r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.HashReference) + c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + count := 0 + objects, err := r.Objects() + c.Assert(err, IsNil) + objects.ForEach(func(object.Object) error { count++; return nil }) + c.Assert(count, Equals, 28) +} + +func (s *RepositorySuite) TestCloneDetachedHEADAndShallow(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), + Depth: 1, + }) + + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 0) + + head, err := r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.HashReference) + c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + count := 0 + objects, err := r.Objects() + c.Assert(err, IsNil) + objects.ForEach(func(object.Object) error { count++; return nil }) + c.Assert(count, Equals, 15) +} + +func (s *RepositorySuite) TestCloneDetachedHEADAnnotatedTag(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()), + ReferenceName: plumbing.ReferenceName("refs/tags/annotated-tag"), + }) + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Branches, HasLen, 0) + + head, err := r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(head, NotNil) + c.Assert(head.Type(), Equals, plumbing.HashReference) + c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") + + count := 0 + objects, err := r.Objects() + c.Assert(err, IsNil) + objects.ForEach(func(object.Object) error { count++; return nil }) + c.Assert(count, Equals, 7) +} + +func (s *RepositorySuite) TestPush(c *C) { + url := c.MkDir() + server, err := PlainInit(url, true) + c.Assert(err, IsNil) + + _, err = s.Repository.CreateRemote(&config.RemoteConfig{ + Name: "test", + URLs: []string{url}, + }) + c.Assert(err, IsNil) + + err = s.Repository.Push(&PushOptions{ + RemoteName: "test", + }) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", + }) + + AssertReferences(c, s.Repository, map[string]string{ + "refs/remotes/test/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "refs/remotes/test/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", + }) +} + +func (s *RepositorySuite) TestPushContext(c *C) { + url := c.MkDir() + _, err := PlainInit(url, true) + c.Assert(err, IsNil) + + _, err = s.Repository.CreateRemote(&config.RemoteConfig{ + Name: "foo", + URLs: []string{url}, + }) + c.Assert(err, IsNil) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err = s.Repository.PushContext(ctx, &PushOptions{ + RemoteName: "foo", + }) + c.Assert(err, NotNil) +} + +// installPreReceiveHook installs a pre-receive hook in the .git +// directory at path which prints message m before exiting +// successfully. +func installPreReceiveHook(c *C, path, m string) { + hooks := filepath.Join(path, "hooks") + err := os.MkdirAll(hooks, 0777) + c.Assert(err, IsNil) + + err = ioutil.WriteFile(filepath.Join(hooks, "pre-receive"), preReceiveHook(m), 0777) + c.Assert(err, IsNil) +} + +func (s *RepositorySuite) TestPushWithProgress(c *C) { + url := c.MkDir() + server, err := PlainInit(url, true) + c.Assert(err, IsNil) + + m := "Receiving..." + installPreReceiveHook(c, url, m) + + _, err = s.Repository.CreateRemote(&config.RemoteConfig{ + Name: "bar", + URLs: []string{url}, + }) + c.Assert(err, IsNil) + + var p bytes.Buffer + err = s.Repository.Push(&PushOptions{ + RemoteName: "bar", + Progress: &p, + }) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", + }) + + c.Assert((&p).Bytes(), DeepEquals, []byte(m)) +} + +func (s *RepositorySuite) TestPushDepth(c *C) { + url := c.MkDir() + server, err := PlainClone(url, true, &CloneOptions{ + URL: fixtures.Basic().One().DotGit().Root(), + }) + + c.Assert(err, IsNil) + + r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ + URL: url, + Depth: 1, + }) + c.Assert(err, IsNil) + + err = util.WriteFile(r.wt, "foo", nil, 0755) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + _, err = w.Add("foo") + c.Assert(err, IsNil) + + hash, err := w.Commit("foo", &CommitOptions{ + Author: defaultSignature(), + Committer: defaultSignature(), + }) + c.Assert(err, IsNil) + + err = r.Push(&PushOptions{}) + c.Assert(err, IsNil) + + AssertReferences(c, server, map[string]string{ + "refs/heads/master": hash.String(), + }) + + AssertReferences(c, r, map[string]string{ + "refs/remotes/origin/master": hash.String(), + }) +} + +func (s *RepositorySuite) TestPushNonExistentRemote(c *C) { + srcFs := fixtures.Basic().One().DotGit() + sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) + + r, err := Open(sto, srcFs) + c.Assert(err, IsNil) + + err = r.Push(&PushOptions{RemoteName: "myremote"}) + c.Assert(err, ErrorMatches, ".*remote not found.*") +} + +func (s *RepositorySuite) TestLog(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + cIter, err := r.Log(&LogOptions{ + From: plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + }) + + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogAll(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + rIter, err := r.Storer.IterReferences() + c.Assert(err, IsNil) + + refCount := 0 + err = rIter.ForEach(func(ref *plumbing.Reference) error { + refCount++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(refCount, Equals, 5) + + cIter, err := r.Log(&LogOptions{ + All: true, + }) + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), + plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), + plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), + plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) + cIter.Close() +} + +func (s *RepositorySuite) TestLogAllMissingReferences(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + err = r.Storer.RemoveReference(plumbing.HEAD) + c.Assert(err, IsNil) + + rIter, err := r.Storer.IterReferences() + c.Assert(err, IsNil) + + refCount := 0 + err = rIter.ForEach(func(ref *plumbing.Reference) error { + refCount++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(refCount, Equals, 4) + + err = r.Storer.SetReference(plumbing.NewHashReference(plumbing.ReferenceName("DUMMY"), plumbing.NewHash("DUMMY"))) + c.Assert(err, IsNil) + + rIter, err = r.Storer.IterReferences() + c.Assert(err, IsNil) + + refCount = 0 + err = rIter.ForEach(func(ref *plumbing.Reference) error { + refCount++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(refCount, Equals, 5) + + cIter, err := r.Log(&LogOptions{ + All: true, + }) + c.Assert(cIter, NotNil) + c.Assert(err, IsNil) + + cCount := 0 + cIter.ForEach(func(c *object.Commit) error { + cCount++ + return nil + }) + c.Assert(cCount, Equals, 9) + + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) + cIter.Close() +} + +func (s *RepositorySuite) TestLogAllOrderByTime(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + All: true, + }) + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), + plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), + plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), + plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) + cIter.Close() +} + +func (s *RepositorySuite) TestLogHead(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + cIter, err := r.Log(&LogOptions{}) + + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), + plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), + plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), + plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogError(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + _, err = r.Log(&LogOptions{ + From: plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + }) + c.Assert(err, NotNil) +} + +func (s *RepositorySuite) TestLogFileNext(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + fileName := "vendor/foo.go" + cIter, err := r.Log(&LogOptions{FileName: &fileName}) + + c.Assert(err, IsNil) + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), + } + + for _, o := range commitOrder { + commit, err := cIter.Next() + c.Assert(err, IsNil) + c.Assert(commit.Hash, Equals, o) + } + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogFileForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + fileName := "php/crappy.php" + cIter, err := r.Log(&LogOptions{FileName: &fileName}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), + } + + expectedIndex := 0 + cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(expectedIndex, Equals, 1) +} + +func (s *RepositorySuite) TestLogNonHeadFile(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + fileName := "README" + cIter, err := r.Log(&LogOptions{FileName: &fileName}) + c.Assert(err, IsNil) + defer cIter.Close() + + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogAllFileForEach(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + fileName := "README" + cIter, err := r.Log(&LogOptions{FileName: &fileName, All: true}) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), + } + + expectedIndex := 0 + cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(expectedIndex, Equals, 1) +} + +func (s *RepositorySuite) TestLogInvalidFile(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + // Throwing in a file that does not exist + fileName := "vendor/foo12.go" + cIter, err := r.Log(&LogOptions{FileName: &fileName}) + // Not raising an error since `git log -- vendor/foo12.go` responds silently + c.Assert(err, IsNil) + defer cIter.Close() + + _, err = cIter.Next() + c.Assert(err, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogFileInitialCommit(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + fileName := "LICENSE" + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + FileName: &fileName, + }) + c.Assert(err, IsNil) + defer cIter.Close() + + commitOrder := []plumbing.Hash{ + plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + } + + expectedIndex := 0 + cIter.ForEach(func(commit *object.Commit) error { + expectedCommitHash := commitOrder[expectedIndex] + c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) + expectedIndex++ + return nil + }) + c.Assert(expectedIndex, Equals, 1) +} + +func (s *RepositorySuite) TestLogFileWithOtherParamsFail(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + fileName := "vendor/foo.go" + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + FileName: &fileName, + From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + defer cIter.Close() + + _, iterErr := cIter.Next() + c.Assert(iterErr, Equals, io.EOF) +} + +func (s *RepositorySuite) TestLogFileWithOtherParamsPass(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + fileName := "LICENSE" + cIter, err := r.Log(&LogOptions{ + Order: LogOrderCommitterTime, + FileName: &fileName, + From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + commitVal, iterErr := cIter.Next() + c.Assert(iterErr, Equals, nil) + c.Assert(commitVal.Hash.String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") + + _, iterErr = cIter.Next() + c.Assert(iterErr, Equals, io.EOF) +} + +func (s *RepositorySuite) TestCommit(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + hash := plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47") + commit, err := r.CommitObject(hash) + c.Assert(err, IsNil) + + c.Assert(commit.Hash.IsZero(), Equals, false) + c.Assert(commit.Hash, Equals, commit.ID()) + c.Assert(commit.Hash, Equals, hash) + c.Assert(commit.Type(), Equals, plumbing.CommitObject) + + tree, err := commit.Tree() + c.Assert(err, IsNil) + c.Assert(tree.Hash.IsZero(), Equals, false) + + c.Assert(commit.Author.Email, Equals, "daniel@lordran.local") +} + +func (s *RepositorySuite) TestCommits(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + count := 0 + commits, err := r.CommitObjects() + c.Assert(err, IsNil) + for { + commit, err := commits.Next() + if err != nil { + break + } + + count++ + c.Assert(commit.Hash.IsZero(), Equals, false) + c.Assert(commit.Hash, Equals, commit.ID()) + c.Assert(commit.Type(), Equals, plumbing.CommitObject) + } + + c.Assert(count, Equals, 9) +} + +func (s *RepositorySuite) TestBlob(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + + c.Assert(err, IsNil) + + blob, err := r.BlobObject(plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47")) + c.Assert(err, NotNil) + c.Assert(blob, IsNil) + + blobHash := plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492") + blob, err = r.BlobObject(blobHash) + c.Assert(err, IsNil) + + c.Assert(blob.Hash.IsZero(), Equals, false) + c.Assert(blob.Hash, Equals, blob.ID()) + c.Assert(blob.Hash, Equals, blobHash) + c.Assert(blob.Type(), Equals, plumbing.BlobObject) +} + +func (s *RepositorySuite) TestBlobs(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + count := 0 + blobs, err := r.BlobObjects() + c.Assert(err, IsNil) + for { + blob, err := blobs.Next() + if err != nil { + break + } + + count++ + c.Assert(blob.Hash.IsZero(), Equals, false) + c.Assert(blob.Hash, Equals, blob.ID()) + c.Assert(blob.Type(), Equals, plumbing.BlobObject) + } + + c.Assert(count, Equals, 10) +} + +func (s *RepositorySuite) TestTagObject(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + hash := plumbing.NewHash("ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc") + tag, err := r.TagObject(hash) + c.Assert(err, IsNil) + + c.Assert(tag.Hash.IsZero(), Equals, false) + c.Assert(tag.Hash, Equals, hash) + c.Assert(tag.Type(), Equals, plumbing.TagObject) +} + +func (s *RepositorySuite) TestTags(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + count := 0 + tags, err := r.Tags() + c.Assert(err, IsNil) + + tags.ForEach(func(tag *plumbing.Reference) error { + count++ + c.Assert(tag.Hash().IsZero(), Equals, false) + c.Assert(tag.Name().IsTag(), Equals, true) + return nil + }) + + c.Assert(count, Equals, 5) +} + +func (s *RepositorySuite) TestCreateTagLightweight(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + expected, err := r.Head() + c.Assert(err, IsNil) + + ref, err := r.CreateTag("foobar", expected.Hash(), nil) + c.Assert(err, IsNil) + c.Assert(ref, NotNil) + + actual, err := r.Tag("foobar") + c.Assert(err, IsNil) + + c.Assert(expected.Hash(), Equals, actual.Hash()) +} + +func (s *RepositorySuite) TestCreateTagLightweightExists(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + expected, err := r.Head() + c.Assert(err, IsNil) + + ref, err := r.CreateTag("lightweight-tag", expected.Hash(), nil) + c.Assert(ref, IsNil) + c.Assert(err, Equals, ErrTagExists) +} + +func (s *RepositorySuite) TestCreateTagAnnotated(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + h, err := r.Head() + c.Assert(err, IsNil) + + expectedHash := h.Hash() + + ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ + Tagger: defaultSignature(), + Message: "foo bar baz qux", + }) + c.Assert(err, IsNil) + + tag, err := r.Tag("foobar") + c.Assert(err, IsNil) + + obj, err := r.TagObject(tag.Hash()) + c.Assert(err, IsNil) + + c.Assert(ref, DeepEquals, tag) + c.Assert(obj.Hash, Equals, ref.Hash()) + c.Assert(obj.Type(), Equals, plumbing.TagObject) + c.Assert(obj.Target, Equals, expectedHash) +} + +func (s *RepositorySuite) TestCreateTagAnnotatedBadOpts(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + h, err := r.Head() + c.Assert(err, IsNil) + + expectedHash := h.Hash() + + ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ + Message: "foo bar baz qux", + }) + c.Assert(ref, IsNil) + c.Assert(err, Equals, ErrMissingTagger) + + ref, err = r.CreateTag("foobar", expectedHash, &CreateTagOptions{ + Tagger: defaultSignature(), + }) + c.Assert(ref, IsNil) + c.Assert(err, Equals, ErrMissingMessage) +} + +func (s *RepositorySuite) TestCreateTagAnnotatedBadHash(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + ref, err := r.CreateTag("foobar", plumbing.ZeroHash, &CreateTagOptions{ + Tagger: defaultSignature(), + Message: "foo bar baz qux", + }) + c.Assert(ref, IsNil) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *RepositorySuite) TestCreateTagSigned(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + h, err := r.Head() + c.Assert(err, IsNil) + + key := commitSignKey(c, true) + _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ + Tagger: defaultSignature(), + Message: "foo bar baz qux", + SignKey: key, + }) + c.Assert(err, IsNil) + + tag, err := r.Tag("foobar") + c.Assert(err, IsNil) + + obj, err := r.TagObject(tag.Hash()) + c.Assert(err, IsNil) + + // Verify the tag. + pks := new(bytes.Buffer) + pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) + c.Assert(err, IsNil) + + err = key.Serialize(pkw) + c.Assert(err, IsNil) + err = pkw.Close() + c.Assert(err, IsNil) + + actual, err := obj.Verify(pks.String()) + c.Assert(err, IsNil) + c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) +} + +func (s *RepositorySuite) TestCreateTagSignedBadKey(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + h, err := r.Head() + c.Assert(err, IsNil) + + key := commitSignKey(c, false) + _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ + Tagger: defaultSignature(), + Message: "foo bar baz qux", + SignKey: key, + }) + c.Assert(err, Equals, openpgperr.InvalidArgumentError("signing key is encrypted")) +} + +func (s *RepositorySuite) TestCreateTagCanonicalize(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + h, err := r.Head() + c.Assert(err, IsNil) + + key := commitSignKey(c, true) + _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ + Tagger: defaultSignature(), + Message: "\n\nfoo bar baz qux\n\nsome message here", + SignKey: key, + }) + c.Assert(err, IsNil) + + tag, err := r.Tag("foobar") + c.Assert(err, IsNil) + + obj, err := r.TagObject(tag.Hash()) + c.Assert(err, IsNil) + + // Assert the new canonicalized message. + c.Assert(obj.Message, Equals, "foo bar baz qux\n\nsome message here\n") + + // Verify the tag. + pks := new(bytes.Buffer) + pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) + c.Assert(err, IsNil) + + err = key.Serialize(pkw) + c.Assert(err, IsNil) + err = pkw.Close() + c.Assert(err, IsNil) + + actual, err := obj.Verify(pks.String()) + c.Assert(err, IsNil) + c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) +} + +func (s *RepositorySuite) TestTagLightweight(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + expected := plumbing.NewHash("f7b877701fbf855b44c0a9e86f3fdce2c298b07f") + + tag, err := r.Tag("lightweight-tag") + c.Assert(err, IsNil) + + actual := tag.Hash() + c.Assert(expected, Equals, actual) +} + +func (s *RepositorySuite) TestTagLightweightMissingTag(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + tag, err := r.Tag("lightweight-tag-tag") + c.Assert(tag, IsNil) + c.Assert(err, Equals, ErrTagNotFound) +} + +func (s *RepositorySuite) TestDeleteTag(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + err = r.DeleteTag("lightweight-tag") + c.Assert(err, IsNil) + + _, err = r.Tag("lightweight-tag") + c.Assert(err, Equals, ErrTagNotFound) +} + +func (s *RepositorySuite) TestDeleteTagMissingTag(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + err = r.DeleteTag("lightweight-tag-tag") + c.Assert(err, Equals, ErrTagNotFound) +} + +func (s *RepositorySuite) TestDeleteTagAnnotated(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + dir, err := ioutil.TempDir("", "go-git-test-deletetag-annotated") + c.Assert(err, IsNil) + + defer os.RemoveAll(dir) // clean up + + fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) + + r, _ := Init(fss, nil) + err = r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + ref, err := r.Tag("annotated-tag") + c.Assert(ref, NotNil) + c.Assert(err, IsNil) + + obj, err := r.TagObject(ref.Hash()) + c.Assert(obj, NotNil) + c.Assert(err, IsNil) + + err = r.DeleteTag("annotated-tag") + c.Assert(err, IsNil) + + _, err = r.Tag("annotated-tag") + c.Assert(err, Equals, ErrTagNotFound) + + // Run a prune (and repack, to ensure that we are GCing everything regardless + // of the fixture in use) and try to get the tag object again. + // + // The repo needs to be re-opened after the repack. + err = r.Prune(PruneOptions{Handler: r.DeleteObject}) + c.Assert(err, IsNil) + + err = r.RepackObjects(&RepackConfig{}) + c.Assert(err, IsNil) + + r, err = PlainOpen(dir) + c.Assert(r, NotNil) + c.Assert(err, IsNil) + + // Now check to see if the GC was effective in removing the tag object. + obj, err = r.TagObject(ref.Hash()) + c.Assert(obj, IsNil) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *RepositorySuite) TestDeleteTagAnnotatedUnpacked(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + dir, err := ioutil.TempDir("", "go-git-test-deletetag-annotated-unpacked") + c.Assert(err, IsNil) + + defer os.RemoveAll(dir) // clean up + + fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) + + r, _ := Init(fss, nil) + err = r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + // Create a tag for the deletion test. This ensures that the ultimate loose + // object will be unpacked (as we aren't doing anything that should pack it), + // so that we can effectively test that a prune deletes it, without having to + // resort to a repack. + h, err := r.Head() + c.Assert(err, IsNil) + + expectedHash := h.Hash() + + ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ + Tagger: defaultSignature(), + Message: "foo bar baz qux", + }) + c.Assert(err, IsNil) + + tag, err := r.Tag("foobar") + c.Assert(err, IsNil) + + obj, err := r.TagObject(tag.Hash()) + c.Assert(obj, NotNil) + c.Assert(err, IsNil) + + err = r.DeleteTag("foobar") + c.Assert(err, IsNil) + + _, err = r.Tag("foobar") + c.Assert(err, Equals, ErrTagNotFound) + + // As mentioned, only run a prune. We are not testing for packed objects + // here. + err = r.Prune(PruneOptions{Handler: r.DeleteObject}) + c.Assert(err, IsNil) + + // Now check to see if the GC was effective in removing the tag object. + obj, err = r.TagObject(ref.Hash()) + c.Assert(obj, IsNil) + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *RepositorySuite) TestBranches(c *C) { + f := fixtures.ByURL("https://github.com/git-fixtures/root-references.git").One() + sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) + r, err := Open(sto, f.DotGit()) + c.Assert(err, IsNil) + + count := 0 + branches, err := r.Branches() + c.Assert(err, IsNil) + + branches.ForEach(func(branch *plumbing.Reference) error { + count++ + c.Assert(branch.Hash().IsZero(), Equals, false) + c.Assert(branch.Name().IsBranch(), Equals, true) + return nil + }) + + c.Assert(count, Equals, 8) +} + +func (s *RepositorySuite) TestNotes(c *C) { + // TODO add fixture with Notes + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + count := 0 + notes, err := r.Notes() + c.Assert(err, IsNil) + + notes.ForEach(func(note *plumbing.Reference) error { + count++ + c.Assert(note.Hash().IsZero(), Equals, false) + c.Assert(note.Name().IsNote(), Equals, true) + return nil + }) + + c.Assert(count, Equals, 0) +} + +func (s *RepositorySuite) TestTree(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + + invalidHash := plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + tree, err := r.TreeObject(invalidHash) + c.Assert(tree, IsNil) + c.Assert(err, NotNil) + + hash := plumbing.NewHash("dbd3641b371024f44d0e469a9c8f5457b0660de1") + tree, err = r.TreeObject(hash) + c.Assert(err, IsNil) + + c.Assert(tree.Hash.IsZero(), Equals, false) + c.Assert(tree.Hash, Equals, tree.ID()) + c.Assert(tree.Hash, Equals, hash) + c.Assert(tree.Type(), Equals, plumbing.TreeObject) + c.Assert(len(tree.Entries), Not(Equals), 0) +} + +func (s *RepositorySuite) TestTrees(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + count := 0 + trees, err := r.TreeObjects() + c.Assert(err, IsNil) + for { + tree, err := trees.Next() + if err != nil { + break + } + + count++ + c.Assert(tree.Hash.IsZero(), Equals, false) + c.Assert(tree.Hash, Equals, tree.ID()) + c.Assert(tree.Type(), Equals, plumbing.TreeObject) + c.Assert(len(tree.Entries), Not(Equals), 0) + } + + c.Assert(count, Equals, 12) +} + +func (s *RepositorySuite) TestTagObjects(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + count := 0 + tags, err := r.TagObjects() + c.Assert(err, IsNil) + + tags.ForEach(func(tag *object.Tag) error { + count++ + + c.Assert(tag.Hash.IsZero(), Equals, false) + c.Assert(tag.Type(), Equals, plumbing.TagObject) + return nil + }) + + refs, _ := r.References() + refs.ForEach(func(ref *plumbing.Reference) error { + return nil + }) + + c.Assert(count, Equals, 4) +} + +func (s *RepositorySuite) TestCommitIterClosePanic(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + commits, err := r.CommitObjects() + c.Assert(err, IsNil) + commits.Close() +} + +func (s *RepositorySuite) TestRef(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + ref, err := r.Reference(plumbing.HEAD, false) + c.Assert(err, IsNil) + c.Assert(ref.Name(), Equals, plumbing.HEAD) + + ref, err = r.Reference(plumbing.HEAD, true) + c.Assert(err, IsNil) + c.Assert(ref.Name(), Equals, plumbing.ReferenceName("refs/heads/master")) +} + +func (s *RepositorySuite) TestRefs(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + c.Assert(err, IsNil) + + iter, err := r.References() + c.Assert(err, IsNil) + c.Assert(iter, NotNil) +} + +func (s *RepositorySuite) TestObject(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + hash := plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + o, err := r.Object(plumbing.CommitObject, hash) + c.Assert(err, IsNil) + + c.Assert(o.ID().IsZero(), Equals, false) + c.Assert(o.Type(), Equals, plumbing.CommitObject) +} + +func (s *RepositorySuite) TestObjects(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + count := 0 + objects, err := r.Objects() + c.Assert(err, IsNil) + for { + o, err := objects.Next() + if err != nil { + break + } + + count++ + c.Assert(o.ID().IsZero(), Equals, false) + c.Assert(o.Type(), Not(Equals), plumbing.AnyObject) + } + + c.Assert(count, Equals, 31) +} + +func (s *RepositorySuite) TestObjectNotFound(c *C) { + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) + c.Assert(err, IsNil) + + hash := plumbing.NewHash("0a3fb06ff80156fb153bcdcc58b5e16c2d27625c") + tag, err := r.Object(plumbing.TagObject, hash) + c.Assert(err, DeepEquals, plumbing.ErrObjectNotFound) + c.Assert(tag, IsNil) +} + +func (s *RepositorySuite) TestWorktree(c *C) { + def := memfs.New() + r, _ := Init(memory.NewStorage(), def) + w, err := r.Worktree() + c.Assert(err, IsNil) + c.Assert(w.Filesystem, Equals, def) +} + +func (s *RepositorySuite) TestWorktreeBare(c *C) { + r, _ := Init(memory.NewStorage(), nil) + w, err := r.Worktree() + c.Assert(err, Equals, ErrIsBareRepository) + c.Assert(w, IsNil) +} + +func (s *RepositorySuite) TestResolveRevision(c *C) { + f := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One() + sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) + r, err := Open(sto, f.DotGit()) + c.Assert(err, IsNil) + + datas := map[string]string{ + "HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "heads/master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", + "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d", + "refs/tags/v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "refs/remotes/origin/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "refs/remotes/origin/HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d", + "HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", + "HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", + "HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9", + "HEAD~^{/!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea", + "master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", + "v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + "branch~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", + "v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", + "master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", + "918c48b83bd081e863dbe1b80f8998f058cd8294": "918c48b83bd081e863dbe1b80f8998f058cd8294", + } + + for rev, hash := range datas { + h, err := r.ResolveRevision(plumbing.Revision(rev)) + + c.Assert(err, IsNil, Commentf("while checking %s", rev)) + c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev)) + } +} + +func (s *RepositorySuite) TestResolveRevisionAnnotated(c *C) { + f := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One() + sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) + r, err := Open(sto, f.DotGit()) + c.Assert(err, IsNil) + + datas := map[string]string{ + "refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", + "b742a2a9fa0afcfa9a6fad080980fbc26b007c69": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", + } + + for rev, hash := range datas { + h, err := r.ResolveRevision(plumbing.Revision(rev)) + + c.Assert(err, IsNil, Commentf("while checking %s", rev)) + c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev)) + } +} + +func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) { + url := s.GetLocalRepositoryURL( + fixtures.ByURL("https://github.com/git-fixtures/basic.git").One(), + ) + + r, _ := Init(memory.NewStorage(), nil) + err := r.clone(context.Background(), &CloneOptions{URL: url}) + c.Assert(err, IsNil) + + headRef, err := r.Head() + c.Assert(err, IsNil) + + ref := plumbing.NewHashReference("refs/heads/918c48b83bd081e863dbe1b80f8998f058cd8294", headRef.Hash()) + err = r.Storer.SetReference(ref) + c.Assert(err, IsNil) + + datas := map[string]string{ + "efs/heads/master~": "reference not found", + "HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`, + "HEAD^{/whatever}": `No commit message match regexp : "whatever"`, + "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83": "reference not found", + } + + for rev, rerr := range datas { + _, err := r.ResolveRevision(plumbing.Revision(rev)) + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, rerr) + } +} + +func (s *RepositorySuite) testRepackObjects( + c *C, deleteTime time.Time, expectedPacks int) { + srcFs := fixtures.ByTag("unpacked").One().DotGit() + var sto storage.Storer + var err error + sto = filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) + + los := sto.(storer.LooseObjectStorer) + c.Assert(los, NotNil) + + numLooseStart := 0 + err = los.ForEachObjectHash(func(_ plumbing.Hash) error { + numLooseStart++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(numLooseStart > 0, Equals, true) + + pos := sto.(storer.PackedObjectStorer) + c.Assert(los, NotNil) + + packs, err := pos.ObjectPacks() + c.Assert(err, IsNil) + numPacksStart := len(packs) + c.Assert(numPacksStart > 1, Equals, true) + + r, err := Open(sto, srcFs) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + err = r.RepackObjects(&RepackConfig{ + OnlyDeletePacksOlderThan: deleteTime, + }) + c.Assert(err, IsNil) + + numLooseEnd := 0 + err = los.ForEachObjectHash(func(_ plumbing.Hash) error { + numLooseEnd++ + return nil + }) + c.Assert(err, IsNil) + c.Assert(numLooseEnd, Equals, 0) + + packs, err = pos.ObjectPacks() + c.Assert(err, IsNil) + numPacksEnd := len(packs) + c.Assert(numPacksEnd, Equals, expectedPacks) +} + +func (s *RepositorySuite) TestRepackObjects(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + s.testRepackObjects(c, time.Time{}, 1) +} + +func (s *RepositorySuite) TestRepackObjectsWithNoDelete(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + s.testRepackObjects(c, time.Unix(0, 1), 3) +} + +func ExecuteOnPath(c *C, path string, cmds ...string) error { + for _, cmd := range cmds { + err := executeOnPath(path, cmd) + c.Assert(err, IsNil) + } + + return nil +} + +func executeOnPath(path, cmd string) error { + args := strings.Split(cmd, " ") + c := exec.Command(args[0], args[1:]...) + c.Dir = path + c.Env = os.Environ() + + buf := bytes.NewBuffer(nil) + c.Stderr = buf + c.Stdout = buf + + return c.Run() +} + +func (s *RepositorySuite) TestBrokenMultipleShallowFetch(c *C) { + r, _ := Init(memory.NewStorage(), nil) + _, err := r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + c.Assert(err, IsNil) + + c.Assert(r.Fetch(&FetchOptions{ + Depth: 2, + RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/master:refs/heads/master")}, + }), IsNil) + + shallows, err := r.Storer.Shallow() + c.Assert(err, IsNil) + c.Assert(len(shallows), Equals, 1) + + ref, err := r.Reference("refs/heads/master", true) + c.Assert(err, IsNil) + cobj, err := r.CommitObject(ref.Hash()) + c.Assert(err, IsNil) + c.Assert(cobj, NotNil) + err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error { + for _, ph := range c.ParentHashes { + for _, h := range shallows { + if ph == h { + return storer.ErrStop + } + } + } + + return nil + }) + c.Assert(err, IsNil) + + c.Assert(r.Fetch(&FetchOptions{ + Depth: 5, + RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/*:refs/heads/*")}, + }), IsNil) + + shallows, err = r.Storer.Shallow() + c.Assert(err, IsNil) + c.Assert(len(shallows), Equals, 3) + + ref, err = r.Reference("refs/heads/master", true) + c.Assert(err, IsNil) + cobj, err = r.CommitObject(ref.Hash()) + c.Assert(err, IsNil) + c.Assert(cobj, NotNil) + err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error { + for _, ph := range c.ParentHashes { + for _, h := range shallows { + if ph == h { + return storer.ErrStop + } + } + } + + return nil + }) + c.Assert(err, IsNil) +} + +func BenchmarkObjects(b *testing.B) { + if err := fixtures.Init(); err != nil { + b.Fatal(err) + } + + defer func() { + if err := fixtures.Clean(); err != nil { + b.Fatal(err) + } + }() + + for _, f := range fixtures.ByTag("packfile") { + if f.DotGitHash == plumbing.ZeroHash { + continue + } + + b.Run(f.URL, func(b *testing.B) { + fs := f.DotGit() + storer := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + + worktree, err := fs.Chroot(filepath.Dir(fs.Root())) + if err != nil { + b.Fatal(err) + } + + repo, err := Open(storer, worktree) + if err != nil { + b.Fatal(err) + } + + for i := 0; i < b.N; i++ { + iter, err := repo.Objects() + if err != nil { + b.Fatal(err) + } + + for { + _, err := iter.Next() + if err == io.EOF { + break + } + + if err != nil { + b.Fatal(err) + } + } + + iter.Close() + } + }) + } +} + +func BenchmarkPlainClone(b *testing.B) { + for i := 0; i < b.N; i++ { + t, err := ioutil.TempDir("", "") + if err != nil { + b.Fatal(err) + } + _, err = PlainClone(t, false, &CloneOptions{ + URL: "https://github.com/knqyf263/vuln-list", + Depth: 1, + }) + if err != nil { + b.Error(err) + } + b.StopTimer() + os.RemoveAll(t) + b.StartTimer() + } +} diff --git a/vendor/github.com/devtron-labs/go-git/repository_unix_test.go b/vendor/github.com/devtron-labs/go-git/repository_unix_test.go new file mode 100644 index 00000000..75682ae7 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/repository_unix_test.go @@ -0,0 +1,11 @@ +// +build !plan9,!windows + +package git + +import "fmt" + +// preReceiveHook returns the bytes of a pre-receive hook script +// that prints m before exiting successfully +func preReceiveHook(m string) []byte { + return []byte(fmt.Sprintf("#!/bin/sh\nprintf '%s'\n", m)) +} diff --git a/vendor/github.com/devtron-labs/go-git/repository_windows_test.go b/vendor/github.com/devtron-labs/go-git/repository_windows_test.go new file mode 100644 index 00000000..bec0acdd --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/repository_windows_test.go @@ -0,0 +1,9 @@ +package git + +import "fmt" + +// preReceiveHook returns the bytes of a pre-receive hook script +// that prints m before exiting successfully +func preReceiveHook(m string) []byte { + return []byte(fmt.Sprintf("#!C:/Program\\ Files/Git/usr/bin/sh.exe\nprintf '%s'\n", m)) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/status.go b/vendor/github.com/devtron-labs/go-git/status.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/status.go rename to vendor/github.com/devtron-labs/go-git/status.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/memory/storage.go b/vendor/github.com/devtron-labs/go-git/storage/memory/storage.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/storage/memory/storage.go rename to vendor/github.com/devtron-labs/go-git/storage/memory/storage.go index f240f2a1..ef406b37 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/memory/storage.go +++ b/vendor/github.com/devtron-labs/go-git/storage/memory/storage.go @@ -5,11 +5,11 @@ import ( "fmt" "time" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/storage" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage" ) var ErrUnsupportedObjectType = fmt.Errorf("unsupported object type") diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/storer.go b/vendor/github.com/devtron-labs/go-git/storage/storer.go similarity index 79% rename from vendor/gopkg.in/src-d/go-git.v4/storage/storer.go rename to vendor/github.com/devtron-labs/go-git/storage/storer.go index 5de0cfb9..34af101c 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/storer.go +++ b/vendor/github.com/devtron-labs/go-git/storage/storer.go @@ -3,14 +3,14 @@ package storage import ( "errors" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing/storer" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing/storer" ) var ErrReferenceHasChanged = errors.New("reference has changed concurrently") // Storer is a generic storage of objects, references and any information -// related to a particular repository. The package gopkg.in/src-d/go-git.v4/storage +// related to a particular repository. The package github.com/devtron-labs/go-git/storage // contains two implementation a filesystem base implementation (such as `.git`) // and a memory implementations being ephemeral type Storer interface { diff --git a/vendor/gopkg.in/src-d/go-git.v4/submodule.go b/vendor/github.com/devtron-labs/go-git/submodule.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/submodule.go rename to vendor/github.com/devtron-labs/go-git/submodule.go index a4eb7ded..8076191b 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/submodule.go +++ b/vendor/github.com/devtron-labs/go-git/submodule.go @@ -6,10 +6,10 @@ import ( "errors" "fmt" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/index" "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" ) var ( diff --git a/vendor/github.com/devtron-labs/go-git/submodule_test.go b/vendor/github.com/devtron-labs/go-git/submodule_test.go new file mode 100644 index 00000000..c73ae6ee --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/submodule_test.go @@ -0,0 +1,236 @@ +package git + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/devtron-labs/go-git/plumbing" + + "github.com/devtron-labs/go-git-fixtures" + . "gopkg.in/check.v1" +) + +type SubmoduleSuite struct { + BaseSuite + Worktree *Worktree + path string +} + +var _ = Suite(&SubmoduleSuite{}) + +func (s *SubmoduleSuite) SetUpTest(c *C) { + path := fixtures.ByTag("submodule").One().Worktree().Root() + + dir, err := ioutil.TempDir("", "submodule") + c.Assert(err, IsNil) + + r, err := PlainClone(filepath.Join(dir, "worktree"), false, &CloneOptions{ + URL: path, + }) + + c.Assert(err, IsNil) + + s.Repository = r + s.Worktree, err = r.Worktree() + c.Assert(err, IsNil) + + s.path = dir +} + +func (s *SubmoduleSuite) TearDownTest(c *C) { + err := os.RemoveAll(s.path) + c.Assert(err, IsNil) +} + +func (s *SubmoduleSuite) TestInit(c *C) { + sm, err := s.Worktree.Submodule("basic") + c.Assert(err, IsNil) + + c.Assert(sm.initialized, Equals, false) + err = sm.Init() + c.Assert(err, IsNil) + + c.Assert(sm.initialized, Equals, true) + + cfg, err := s.Repository.Config() + c.Assert(err, IsNil) + + c.Assert(cfg.Submodules, HasLen, 1) + c.Assert(cfg.Submodules["basic"], NotNil) + + status, err := sm.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, false) +} + +func (s *SubmoduleSuite) TestUpdate(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + sm, err := s.Worktree.Submodule("basic") + c.Assert(err, IsNil) + + err = sm.Update(&SubmoduleUpdateOptions{ + Init: true, + }) + + c.Assert(err, IsNil) + + r, err := sm.Repository() + c.Assert(err, IsNil) + + ref, err := r.Reference(plumbing.HEAD, true) + c.Assert(err, IsNil) + c.Assert(ref.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + status, err := sm.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *SubmoduleSuite) TestRepositoryWithoutInit(c *C) { + sm, err := s.Worktree.Submodule("basic") + c.Assert(err, IsNil) + + r, err := sm.Repository() + c.Assert(err, Equals, ErrSubmoduleNotInitialized) + c.Assert(r, IsNil) +} + +func (s *SubmoduleSuite) TestUpdateWithoutInit(c *C) { + sm, err := s.Worktree.Submodule("basic") + c.Assert(err, IsNil) + + err = sm.Update(&SubmoduleUpdateOptions{}) + c.Assert(err, Equals, ErrSubmoduleNotInitialized) +} + +func (s *SubmoduleSuite) TestUpdateWithNotFetch(c *C) { + sm, err := s.Worktree.Submodule("basic") + c.Assert(err, IsNil) + + err = sm.Update(&SubmoduleUpdateOptions{ + Init: true, + NoFetch: true, + }) + + // Since we are not fetching, the object is not there + c.Assert(err, Equals, plumbing.ErrObjectNotFound) +} + +func (s *SubmoduleSuite) TestUpdateWithRecursion(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + sm, err := s.Worktree.Submodule("itself") + c.Assert(err, IsNil) + + err = sm.Update(&SubmoduleUpdateOptions{ + Init: true, + RecurseSubmodules: 2, + }) + + c.Assert(err, IsNil) + + fs := s.Worktree.Filesystem + _, err = fs.Stat(fs.Join("itself", "basic", "LICENSE")) + c.Assert(err, IsNil) +} + +func (s *SubmoduleSuite) TestUpdateWithInitAndUpdate(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + sm, err := s.Worktree.Submodule("basic") + c.Assert(err, IsNil) + + err = sm.Update(&SubmoduleUpdateOptions{ + Init: true, + }) + c.Assert(err, IsNil) + + idx, err := s.Repository.Storer.Index() + c.Assert(err, IsNil) + + for i, e := range idx.Entries { + if e.Name == "basic" { + e.Hash = plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d") + } + + idx.Entries[i] = e + } + + err = s.Repository.Storer.SetIndex(idx) + c.Assert(err, IsNil) + + err = sm.Update(&SubmoduleUpdateOptions{}) + c.Assert(err, IsNil) + + r, err := sm.Repository() + c.Assert(err, IsNil) + + ref, err := r.Reference(plumbing.HEAD, true) + c.Assert(err, IsNil) + c.Assert(ref.Hash().String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") + +} + +func (s *SubmoduleSuite) TestSubmodulesInit(c *C) { + sm, err := s.Worktree.Submodules() + c.Assert(err, IsNil) + + err = sm.Init() + c.Assert(err, IsNil) + + sm, err = s.Worktree.Submodules() + c.Assert(err, IsNil) + + for _, m := range sm { + c.Assert(m.initialized, Equals, true) + } +} + +func (s *SubmoduleSuite) TestGitSubmodulesSymlink(c *C) { + f, err := s.Worktree.Filesystem.Create("badfile") + c.Assert(err, IsNil) + defer f.Close() + + err = s.Worktree.Filesystem.Remove(gitmodulesFile) + c.Assert(err, IsNil) + + err = s.Worktree.Filesystem.Symlink("badfile", gitmodulesFile) + c.Assert(err, IsNil) + + _, err = s.Worktree.Submodules() + c.Assert(err, Equals, ErrGitModulesSymlink) +} + +func (s *SubmoduleSuite) TestSubmodulesStatus(c *C) { + sm, err := s.Worktree.Submodules() + c.Assert(err, IsNil) + + status, err := sm.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 2) +} + +func (s *SubmoduleSuite) TestSubmodulesUpdateContext(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + sm, err := s.Worktree.Submodules() + c.Assert(err, IsNil) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err = sm.UpdateContext(ctx, &SubmoduleUpdateOptions{Init: true}) + c.Assert(err, NotNil) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/binary/read.go b/vendor/github.com/devtron-labs/go-git/utils/binary/read.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/utils/binary/read.go rename to vendor/github.com/devtron-labs/go-git/utils/binary/read.go index 12e57c30..88affae6 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/binary/read.go +++ b/vendor/github.com/devtron-labs/go-git/utils/binary/read.go @@ -7,7 +7,7 @@ import ( "encoding/binary" "io" - "gopkg.in/src-d/go-git.v4/plumbing" + "github.com/devtron-labs/go-git/plumbing" ) // Read reads structured binary data from r into data. Bytes are read and @@ -80,10 +80,9 @@ func ReadUntilFromBufioReader(r *bufio.Reader, delim byte) ([]byte, error) { // // This is how the offset is saved in C: // -// dheader[pos] = ofs & 127; -// while (ofs >>= 7) -// dheader[--pos] = 128 | (--ofs & 127); -// +// dheader[pos] = ofs & 127; +// while (ofs >>= 7) +// dheader[--pos] = 128 | (--ofs & 127); func ReadVariableWidthInt(r io.Reader) (int64, error) { var c byte if err := Read(r, &c); err != nil { diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/binary/write.go b/vendor/github.com/devtron-labs/go-git/utils/binary/write.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/utils/binary/write.go rename to vendor/github.com/devtron-labs/go-git/utils/binary/write.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/diff/diff.go b/vendor/github.com/devtron-labs/go-git/utils/diff/diff.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/utils/diff/diff.go rename to vendor/github.com/devtron-labs/go-git/utils/diff/diff.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go b/vendor/github.com/devtron-labs/go-git/utils/ioutil/common.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go rename to vendor/github.com/devtron-labs/go-git/utils/ioutil/common.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/change.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/change.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/change.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/change.go index 0b50ca71..e18197c0 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/change.go +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/change.go @@ -4,7 +4,7 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // Action values represent the kind of things a Change can represent: diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/difftree.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/difftree.go similarity index 99% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/difftree.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/difftree.go index d57ed133..03f9b96d 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/difftree.go +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/difftree.go @@ -252,7 +252,7 @@ import ( "errors" "fmt" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) var ( diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/doc.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/doc.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/doc.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/doc.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/doubleiter.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/doubleiter.go similarity index 98% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/doubleiter.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/doubleiter.go index e56dee70..985aae37 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/doubleiter.go +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/doubleiter.go @@ -4,7 +4,7 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // A doubleIter is a convenience type to keep track of the current diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/internal/frame/frame.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/internal/frame/frame.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/internal/frame/frame.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/internal/frame/frame.go index a0b042ee..c63dcccc 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/internal/frame/frame.go +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/internal/frame/frame.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // A Frame is a collection of siblings in a trie, sorted alphabetically @@ -42,8 +42,9 @@ func New(n noder.Noder) (*Frame, error) { // separated by comas. // // Examples: -// [] -// ["a", "b"] +// +// [] +// ["a", "b"] func (f *Frame) String() string { var buf bytes.Buffer _ = buf.WriteByte('[') diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/iter.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/iter.go similarity index 94% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/iter.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/iter.go index b4d4c99a..24ef01ab 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/iter.go +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/iter.go @@ -4,8 +4,8 @@ import ( "fmt" "io" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/internal/frame" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" + "github.com/devtron-labs/go-git/utils/merkletrie/internal/frame" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" ) // Iter is an iterator for merkletries (only the trie part of the @@ -17,15 +17,14 @@ import ( // This is the kind of traversal you will expect when listing ordinary // files and directories recursively, for example: // -// Trie Traversal order -// ---- --------------- -// . -// / | \ c -// / | \ d/ -// d c z ===> d/a -// / \ d/b -// b a z -// +// Trie Traversal order +// ---- --------------- +// . +// / | \ c +// / | \ d/ +// d c z ===> d/a +// / \ d/b +// b a z // // This iterator is somewhat especial as you can chose to skip whole // "directories" when iterating: diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/noder/noder.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/noder/noder.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/noder/noder.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/noder/noder.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/noder/path.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/noder/path.go similarity index 100% rename from vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/noder/path.go rename to vendor/github.com/devtron-labs/go-git/utils/merkletrie/noder/path.go diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree.go b/vendor/github.com/devtron-labs/go-git/worktree.go similarity index 97% rename from vendor/gopkg.in/src-d/go-git.v4/worktree.go rename to vendor/github.com/devtron-labs/go-git/worktree.go index 4a609e9e..ec4c082e 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree.go +++ b/vendor/github.com/devtron-labs/go-git/worktree.go @@ -11,15 +11,15 @@ import ( "strings" "sync" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/format/gitignore" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/ioutil" - "gopkg.in/src-d/go-git.v4/utils/merkletrie" + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/format/gitignore" + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/ioutil" + "github.com/devtron-labs/go-git/utils/merkletrie" "gopkg.in/src-d/go-billy.v4" "gopkg.in/src-d/go-billy.v4/util" diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_bsd.go b/vendor/github.com/devtron-labs/go-git/worktree_bsd.go similarity index 82% rename from vendor/gopkg.in/src-d/go-git.v4/worktree_bsd.go rename to vendor/github.com/devtron-labs/go-git/worktree_bsd.go index 9ff670e0..e738a982 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_bsd.go +++ b/vendor/github.com/devtron-labs/go-git/worktree_bsd.go @@ -1,3 +1,4 @@ +//go:build darwin || freebsd || netbsd // +build darwin freebsd netbsd package git @@ -6,7 +7,7 @@ import ( "syscall" "time" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/format/index" ) func init() { diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_commit.go b/vendor/github.com/devtron-labs/go-git/worktree_commit.go similarity index 95% rename from vendor/gopkg.in/src-d/go-git.v4/worktree_commit.go rename to vendor/github.com/devtron-labs/go-git/worktree_commit.go index 673eb167..e98687f5 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_commit.go +++ b/vendor/github.com/devtron-labs/go-git/worktree_commit.go @@ -6,12 +6,12 @@ import ( "sort" "strings" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/storage" "golang.org/x/crypto/openpgp" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/storage" "gopkg.in/src-d/go-billy.v4" ) diff --git a/vendor/github.com/devtron-labs/go-git/worktree_commit_test.go b/vendor/github.com/devtron-labs/go-git/worktree_commit_test.go new file mode 100644 index 00000000..5be5c649 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/worktree_commit_test.go @@ -0,0 +1,369 @@ +package git + +import ( + "bytes" + "io/ioutil" + "os" + "os/exec" + "strings" + "time" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage/filesystem" + "github.com/devtron-labs/go-git/storage/memory" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/armor" + "golang.org/x/crypto/openpgp/errors" + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-billy.v4/memfs" + "gopkg.in/src-d/go-billy.v4/osfs" + "gopkg.in/src-d/go-billy.v4/util" +) + +func (s *WorktreeSuite) TestCommitInvalidOptions(c *C) { + r, err := Init(memory.NewStorage(), memfs.New()) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + hash, err := w.Commit("", &CommitOptions{}) + c.Assert(err, Equals, ErrMissingAuthor) + c.Assert(hash.IsZero(), Equals, true) +} + +func (s *WorktreeSuite) TestCommitInitial(c *C) { + expected := plumbing.NewHash("98c4ac7c29c913f7461eae06e024dc18e80d23a4") + + fs := memfs.New() + storage := memory.NewStorage() + + r, err := Init(storage, fs) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + util.WriteFile(fs, "foo", []byte("foo"), 0644) + + _, err = w.Add("foo") + c.Assert(err, IsNil) + + hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) + c.Assert(hash, Equals, expected) + c.Assert(err, IsNil) + + assertStorageStatus(c, r, 1, 1, 1, expected) +} + +func (s *WorktreeSuite) TestCommitParent(c *C) { + expected := plumbing.NewHash("ef3ca05477530b37f48564be33ddd48063fc7a22") + + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + util.WriteFile(fs, "foo", []byte("foo"), 0644) + + _, err = w.Add("foo") + c.Assert(err, IsNil) + + hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) + c.Assert(hash, Equals, expected) + c.Assert(err, IsNil) + + assertStorageStatus(c, s.Repository, 13, 11, 10, expected) +} + +func (s *WorktreeSuite) TestCommitAll(c *C) { + expected := plumbing.NewHash("aede6f8c9c1c7ec9ca8d287c64b8ed151276fa28") + + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + util.WriteFile(fs, "LICENSE", []byte("foo"), 0644) + util.WriteFile(fs, "foo", []byte("foo"), 0644) + + hash, err := w.Commit("foo\n", &CommitOptions{ + All: true, + Author: defaultSignature(), + }) + + c.Assert(hash, Equals, expected) + c.Assert(err, IsNil) + + assertStorageStatus(c, s.Repository, 13, 11, 10, expected) +} + +func (s *WorktreeSuite) TestRemoveAndCommitAll(c *C) { + expected := plumbing.NewHash("907cd576c6ced2ecd3dab34a72bf9cf65944b9a9") + + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + util.WriteFile(fs, "foo", []byte("foo"), 0644) + _, err = w.Add("foo") + c.Assert(err, IsNil) + + _, errFirst := w.Commit("Add in Repo\n", &CommitOptions{ + Author: defaultSignature(), + }) + c.Assert(errFirst, IsNil) + + errRemove := fs.Remove("foo") + c.Assert(errRemove, IsNil) + + hash, errSecond := w.Commit("Remove foo\n", &CommitOptions{ + All: true, + Author: defaultSignature(), + }) + c.Assert(errSecond, IsNil) + + c.Assert(hash, Equals, expected) + c.Assert(err, IsNil) + + assertStorageStatus(c, s.Repository, 13, 11, 11, expected) +} + +func (s *WorktreeSuite) TestCommitSign(c *C) { + fs := memfs.New() + storage := memory.NewStorage() + + r, err := Init(storage, fs) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + util.WriteFile(fs, "foo", []byte("foo"), 0644) + + _, err = w.Add("foo") + c.Assert(err, IsNil) + + key := commitSignKey(c, true) + hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) + c.Assert(err, IsNil) + + // Verify the commit. + pks := new(bytes.Buffer) + pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) + c.Assert(err, IsNil) + + err = key.Serialize(pkw) + c.Assert(err, IsNil) + err = pkw.Close() + c.Assert(err, IsNil) + + expectedCommit, err := r.CommitObject(hash) + c.Assert(err, IsNil) + actual, err := expectedCommit.Verify(pks.String()) + c.Assert(err, IsNil) + c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) +} + +func (s *WorktreeSuite) TestCommitSignBadKey(c *C) { + fs := memfs.New() + storage := memory.NewStorage() + + r, err := Init(storage, fs) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + util.WriteFile(fs, "foo", []byte("foo"), 0644) + + _, err = w.Add("foo") + c.Assert(err, IsNil) + + key := commitSignKey(c, false) + _, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) + c.Assert(err, Equals, errors.InvalidArgumentError("signing key is encrypted")) +} + +func (s *WorktreeSuite) TestCommitTreeSort(c *C) { + path, err := ioutil.TempDir(os.TempDir(), "test-commit-tree-sort") + c.Assert(err, IsNil) + fs := osfs.New(path) + st := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) + r, err := Init(st, nil) + c.Assert(err, IsNil) + + r, _ = Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ + URL: path, + }) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + mfs := w.Filesystem + + err = mfs.MkdirAll("delta", 0755) + c.Assert(err, IsNil) + + for _, p := range []string{"delta_last", "Gamma", "delta/middle", "Beta", "delta-first", "alpha"} { + util.WriteFile(mfs, p, []byte("foo"), 0644) + _, err = w.Add(p) + c.Assert(err, IsNil) + } + + _, err = w.Commit("foo\n", &CommitOptions{ + All: true, + Author: defaultSignature(), + }) + c.Assert(err, IsNil) + + err = r.Push(&PushOptions{}) + c.Assert(err, IsNil) + + cmd := exec.Command("git", "fsck") + cmd.Dir = path + cmd.Env = os.Environ() + buf := &bytes.Buffer{} + cmd.Stderr = buf + cmd.Stdout = buf + + err = cmd.Run() + + c.Assert(err, IsNil, Commentf("%s", buf.Bytes())) +} + +func assertStorageStatus( + c *C, r *Repository, + treesCount, blobCount, commitCount int, head plumbing.Hash, +) { + trees, err := r.Storer.IterEncodedObjects(plumbing.TreeObject) + c.Assert(err, IsNil) + blobs, err := r.Storer.IterEncodedObjects(plumbing.BlobObject) + c.Assert(err, IsNil) + commits, err := r.Storer.IterEncodedObjects(plumbing.CommitObject) + c.Assert(err, IsNil) + + c.Assert(lenIterEncodedObjects(trees), Equals, treesCount) + c.Assert(lenIterEncodedObjects(blobs), Equals, blobCount) + c.Assert(lenIterEncodedObjects(commits), Equals, commitCount) + + ref, err := r.Head() + c.Assert(err, IsNil) + c.Assert(ref.Hash(), Equals, head) +} + +func lenIterEncodedObjects(iter storer.EncodedObjectIter) int { + count := 0 + iter.ForEach(func(plumbing.EncodedObject) error { + count++ + return nil + }) + + return count +} + +func defaultSignature() *object.Signature { + when, _ := time.Parse(object.DateFormat, "Thu May 04 00:03:43 2017 +0200") + return &object.Signature{ + Name: "foo", + Email: "foo@foo.foo", + When: when, + } +} + +func commitSignKey(c *C, decrypt bool) *openpgp.Entity { + s := strings.NewReader(armoredKeyRing) + es, err := openpgp.ReadArmoredKeyRing(s) + c.Assert(err, IsNil) + + c.Assert(es, HasLen, 1) + c.Assert(es[0].Identities, HasLen, 1) + _, ok := es[0].Identities["foo bar "] + c.Assert(ok, Equals, true) + + key := es[0] + if decrypt { + err = key.PrivateKey.Decrypt([]byte(keyPassphrase)) + c.Assert(err, IsNil) + } + + return key +} + +const armoredKeyRing = ` +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lQdGBFt89QIBEAC8du0Purt9yeFuLlBYHcexnZvcbaci2pY+Ejn1VnxM7caFxRX/ +b2weZi9E6+I0F+K/hKIaidPdcbK92UCL0Vp6F3izjqategZ7o44vlK/HfWFME4wv +sou6lnig9ovA73HRyzngi3CmqWxSdg8lL0kIJLNzlvCFEd4Z34BnEkagklQJRymo +0WnmLJjSnZFT5Nk7q5jrcR7ApbD98cakvgivDlUBPJCk2JFPWheCkouWPHMvLXQz +bZXW5RFz4lJsMUWa/S3ofvIOnjG5Etnil3IA4uksS8fSDkGus998mBvUwzqX7xBh +dK17ZEbxDdO4PuVJDkjvq618rMu8FVk5yVd59rUketSnGrehd/+vdh6qtgQC4tu1 +RldbUVAuKZGg79H61nWnvrDZmbw4eoqCEuv1+aZsM9ElSC5Ps2J0rtpHRyBndKn+ +8Jlc/KTH04/O+FAhEv0IgMTFEm3iAq8udBhRBgu6Y4gJyn4tqy6+6ZjPUNos8GOG ++ZJPdrgHHHfQged1ygeceN6W2AwQRet/B3/rieHf2V93uHJy/DjYUEuBhPm9nxqi +R6ILUr97Sj2EsvLyfQO9pFpIctoNKEJmDx/C9tkFMNNlQhpsBitSdR2/wancw9ND +iWV/J9roUdC0qns7eNSbiFe3Len8Xir7srnjAFgbGvOu9jDBUuiKGT5F3wARAQAB +/gcDAl+0SktmjrUW8uwpvru6GeIeo5kc4rXuD7iIxH6nDl3nmjZMX7qWvp+pRTHH +0hEDH44899PDvzclBN3ouehfFUbJ+DBy8umBiLqF8Mu2PrKjdmyv3BvnbTkqPM3m +2Su7WmUDBhG00X07lfl8fTpZJG80onEGzGynryP/xVm4ymzoHyYGksntXLYr2HJ5 +aV6L7sL2/STsaaOVHoa/oEmVBo1+NRsTxRRUcFVLs3g0OIi6ZCeSevBdavMwf9Iv +b5Bs/e0+GLpP71XzFpdrGcL6oGjZH/dgdeypzbGA+FHtQJqynN3qEE9eCc9cfTGL +2zN2OtnMA28NtPVN4SnSxQIDvycWx68NZjfwLOK+gswfKpimp+6xMWSnNIRDyU9M +w0hdNPMK9JAxm/MlnkR7x6ysX/8vrVVFl9gWOmxzJ5L4kvfMsHcV5ZFRP8OnVA6a +NFBWIBGXF1uQC4qrXup/xKyWJOoH++cMo2cjPT3+3oifZgdBydVfHXjS9aQ/S3Sa +A6henWyx/qeBGPVRuXWdXIOKDboOPK8JwQaGd6yazKkH9c5tDohmQHzZ6ho0gyAt +dh+g9ZyiZVpjc6excfK/DP/RdUOYKw3Ur9652hKephvYZzHvPjTbqVkhS7JjZkVY +rukQ64d5T0pE1B4y+If4hLFXMNQtfo0TIsATNA69jop+KFnJpLzAB+Ee33EA/HUl +YC5EJCJaXt6kdtYFac0HvVWiz5ZuMhdtzpJfvOe+Olp/xR9nIPW3XZojQoHIZKwu +gXeZeVMvfeoq+ymKAKNH5Np4WaUDF7Wh9VLl045jGyF5viyy61ivC0eyAzp5W1uy +gJBZwafVma5MhmZUS2dFs0hBwBrKRzZZhN65VvfSYw6CnXp83ryUjReDvrLmqZDM +FNpSMDKRk1+k9Wwi3m+fzLAvlxoHscJ5Any7ApsvBRbyehP8MAAG7UV3jImugTLi +yN6FKVwziQXiC4/97oKbA1YYNjTT7Qw9gWTXvLRspn4f9997brcA9dm0M0seTjLa +lc5hTJwJQdvPPI2klf+YgPvsD6nrP1moeWBb8irICqG1/BoE0JHPS+bqJ1J+m1iV +kRV/+4pV2bLlXKqg1LEvqANW+1P1eM2nbbVB7EQn8ZOPIKMoCLoC1QWUPNfnemsW +U5ynAbhsbm16PDJql0ApEgUCEDfsXTu1ui6SIO3bs/gWyD9HEmnfaYMYDKF+j+0r +jXd4GnCxb+Yu3wV5WyewOHouzC+++h/3WcDLkOYZ9pcIbA86qT+v6b9MuTAU0D3c +wlDv8r5J59zOcXl4HpMb2BY5F9dZn8hjgeVJRhJdij9x1TQ8qlVasSi4Eq8SiPmZ +PZz33Pk6yn2caQ6wd47A79LXCbFQqJqA5aA6oS4DOpENGS5fh7WUZq/MTcmm9GsG +w2gHxocASK9RCUYgZFWVYgLDuviMMWvc/2TJcTMxdF0Amu3erYAD90smFs0g/6fZ +4pRLnKFuifwAMGMOx7jbW5tmOaSPx6XkuYvkDJeLMHoN3z/8bZEG5VpayypwFGyV +bk/YIUWg/KM/43juDPdTvab9tZzYIjxC6on7dtYIAGjZis97XZou3KYKTaMe1VY6 +IhrnVzJ0JAHpd1prf9NUz96e1vjGdn3I61JgjNp5sWklIJEZzvaD28Eovf/LH1BO +gYFFCvsWXaRoPHNQ5a9m7CROkLeHUFgRu5uriqHxxQHgogDznc8/3fnvDAHNpNb6 +Jnk4zaeVR3tTyIjiNM+wxUFPDNFpJWmQbSDCcPVYTbpznzVRnhqrw7q0FWZvbyBi +YXIgPGZvb0Bmb28uZm9vPokCVAQTAQgAPgIbAwULCQgHAgYVCAkKCwIEFgIDAQIe +AQIXgBYhBJOhf/AeVDKFRgh8jgKTlUAu/M1TBQJbfPU4BQkSzAM2AAoJEAKTlUAu +/M1TVTIQALA6ocNc2fXz1loLykMxlfnX/XxiyNDOUPDZkrZtscqqWPYaWvJK3OiD +32bdVEbftnAiFvJYkinrCXLEmwwf5wyOxKFmCHwwKhH0UYt60yF4WwlOVNstGSAy +RkPMEEmVfMXS9K1nzKv/9A5YsqMQob7sN5CMN66Vrm0RKSvOF/NhhM9v8fC0QSU2 +GZNO0tnRfaS4wMnFr5L4FuDST+14F5sJT7ZEJz7HfbxXKLvvWbvqLlCYHJOdz56s +X/eKde8eT9/LSzcmgsd7rGS2np5901kubww5jllUl1CFnk3Mdg9FTJl5u9Epuhnn +823Jpdy1ZNbyLqZ266Z/q2HepDA7P/GqIXgWdHjwG2y1YAC4JIkA4RBbesQwqAXs +6cX5gqRFRl5iDGEP5zclS0y5mWi/J8bLYxMYfqxs9EZtHd9DumWISi87804TEzYa +WDijMlW7PR8QRW0vdmtYOhJZOlTnomLQx2v27iqpVXRh12J1aYVBFC+IvG1vhCf9 +FL3LzAHHEGlIoDaKJMd+Wg/Lm/f1PqqQx3lWIh9hhKh5Qx6hcuJH669JOWuEdxfo +1so50aItG+tdDKqXflmOi7grrUURchYYKteaW2fC2SQgzDClprALI7aj9s/lDrEN +CgLH6twOqdSFWqB/4ASDMsNeLeKX3WOYKYYMlE01cj3T1m6dpRUO +=gIM9 +-----END PGP PRIVATE KEY BLOCK----- +` + +const keyPassphrase = "abcdef0123456789" diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_linux.go b/vendor/github.com/devtron-labs/go-git/worktree_linux.go similarity index 84% rename from vendor/gopkg.in/src-d/go-git.v4/worktree_linux.go rename to vendor/github.com/devtron-labs/go-git/worktree_linux.go index 891cb1cf..5420dbcb 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_linux.go +++ b/vendor/github.com/devtron-labs/go-git/worktree_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package git @@ -6,7 +7,7 @@ import ( "syscall" "time" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/format/index" ) func init() { diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_status.go b/vendor/github.com/devtron-labs/go-git/worktree_status.go similarity index 96% rename from vendor/gopkg.in/src-d/go-git.v4/worktree_status.go rename to vendor/github.com/devtron-labs/go-git/worktree_status.go index 16ce9370..41286120 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_status.go +++ b/vendor/github.com/devtron-labs/go-git/worktree_status.go @@ -8,17 +8,17 @@ import ( "path" "path/filepath" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/format/gitignore" + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/utils/ioutil" + "github.com/devtron-labs/go-git/utils/merkletrie" + "github.com/devtron-labs/go-git/utils/merkletrie/filesystem" + mindex "github.com/devtron-labs/go-git/utils/merkletrie/index" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" "gopkg.in/src-d/go-billy.v4/util" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/format/gitignore" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/utils/ioutil" - "gopkg.in/src-d/go-git.v4/utils/merkletrie" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem" - mindex "gopkg.in/src-d/go-git.v4/utils/merkletrie/index" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" ) var ( diff --git a/vendor/github.com/devtron-labs/go-git/worktree_test.go b/vendor/github.com/devtron-labs/go-git/worktree_test.go new file mode 100644 index 00000000..b4da7b75 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/worktree_test.go @@ -0,0 +1,2008 @@ +package git + +import ( + "bytes" + "context" + "errors" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "runtime" + "testing" + "time" + + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/format/gitignore" + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/storage/memory" + + "github.com/devtron-labs/go-git-fixtures" + "golang.org/x/text/unicode/norm" + . "gopkg.in/check.v1" + "gopkg.in/src-d/go-billy.v4/memfs" + "gopkg.in/src-d/go-billy.v4/osfs" + "gopkg.in/src-d/go-billy.v4/util" +) + +type WorktreeSuite struct { + BaseSuite +} + +var _ = Suite(&WorktreeSuite{}) + +func (s *WorktreeSuite) SetUpTest(c *C) { + f := fixtures.Basic().One() + s.Repository = s.NewRepositoryWithEmptyWorktree(f) +} + +func (s *WorktreeSuite) TestPullCheckout(c *C) { + fs := memfs.New() + r, _ := Init(memory.NewStorage(), fs) + r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, IsNil) + + fi, err := fs.ReadDir("") + c.Assert(err, IsNil) + c.Assert(fi, HasLen, 8) +} + +func (s *WorktreeSuite) TestPullFastForward(c *C) { + url := c.MkDir() + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + + server, err := PlainClone(url, false, &CloneOptions{ + URL: path, + }) + c.Assert(err, IsNil) + + r, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + w, err := server.Worktree() + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) + c.Assert(err, IsNil) + hash, err := w.Commit("foo", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + w, err = r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, IsNil) + + head, err := r.Head() + c.Assert(err, IsNil) + c.Assert(head.Hash(), Equals, hash) +} + +func (s *WorktreeSuite) TestPullNonFastForward(c *C) { + url := c.MkDir() + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + + server, err := PlainClone(url, false, &CloneOptions{ + URL: path, + }) + c.Assert(err, IsNil) + + r, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + w, err := server.Worktree() + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) + c.Assert(err, IsNil) + _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + w, err = r.Worktree() + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755) + c.Assert(err, IsNil) + _, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, Equals, ErrNonFastForwardUpdate) +} + +func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + err := r.Fetch(&FetchOptions{}) + c.Assert(err, IsNil) + + _, err = r.Reference("refs/heads/master", false) + c.Assert(err, NotNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, IsNil) + + head, err := r.Reference(plumbing.HEAD, true) + c.Assert(err, IsNil) + c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + branch, err := r.Reference("refs/heads/master", false) + c.Assert(err, IsNil) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + err = w.Pull(&PullOptions{}) + c.Assert(err, Equals, NoErrAlreadyUpToDate) +} + +func (s *WorktreeSuite) TestPullInSingleBranch(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + SingleBranch: true, + }) + + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, Equals, NoErrAlreadyUpToDate) + + branch, err := r.Reference("refs/heads/master", false) + c.Assert(err, IsNil) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + branch, err = r.Reference("refs/remotes/foo/branch", false) + c.Assert(err, NotNil) + + storage := r.Storer.(*memory.Storage) + c.Assert(storage.Objects, HasLen, 28) +} + +func (s *WorktreeSuite) TestPullProgress(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + + r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{s.GetBasicLocalRepositoryURL()}, + }) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + buf := bytes.NewBuffer(nil) + err = w.Pull(&PullOptions{ + Progress: buf, + }) + + c.Assert(err, IsNil) + c.Assert(buf.Len(), Not(Equals), 0) +} + +func (s *WorktreeSuite) TestPullProgressWithRecursion(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + path := fixtures.ByTag("submodule").One().Worktree().Root() + + dir, err := ioutil.TempDir("", "plain-clone-submodule") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, _ := PlainInit(dir, false) + r.CreateRemote(&config.RemoteConfig{ + Name: DefaultRemoteName, + URLs: []string{path}, + }) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{ + RecurseSubmodules: DefaultSubmoduleRecursionDepth, + }) + c.Assert(err, IsNil) + + cfg, err := r.Config() + c.Assert(err, IsNil) + c.Assert(cfg.Submodules, HasLen, 2) +} + +func (s *RepositorySuite) TestPullAdd(c *C) { + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + + r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ + URL: filepath.Join(path, ".git"), + }) + + c.Assert(err, IsNil) + + storage := r.Storer.(*memory.Storage) + c.Assert(storage.Objects, HasLen, 28) + + branch, err := r.Reference("refs/heads/master", false) + c.Assert(err, IsNil) + c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") + + ExecuteOnPath(c, path, + "touch foo", + "git add foo", + "git commit -m foo foo", + ) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{RemoteName: "origin"}) + c.Assert(err, IsNil) + + // the commit command has introduced a new commit, tree and blob + c.Assert(storage.Objects, HasLen, 31) + + branch, err = r.Reference("refs/heads/master", false) + c.Assert(err, IsNil) + c.Assert(branch.Hash().String(), Not(Equals), "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") +} + +func (s *WorktreeSuite) TestCheckout(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{ + Force: true, + }) + c.Assert(err, IsNil) + + entries, err := fs.ReadDir("/") + c.Assert(err, IsNil) + + c.Assert(entries, HasLen, 8) + ch, err := fs.Open("CHANGELOG") + c.Assert(err, IsNil) + + content, err := ioutil.ReadAll(ch) + c.Assert(err, IsNil) + c.Assert(string(content), Equals, "Initial changelog\n") + + idx, err := s.Repository.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) +} + +func (s *WorktreeSuite) TestCheckoutForce(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + w.Filesystem = memfs.New() + + err = w.Checkout(&CheckoutOptions{ + Force: true, + }) + c.Assert(err, IsNil) + + entries, err := w.Filesystem.ReadDir("/") + c.Assert(err, IsNil) + c.Assert(entries, HasLen, 8) +} + +func (s *WorktreeSuite) TestCheckoutKeep(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{ + Force: true, + }) + c.Assert(err, IsNil) + + // Create a new branch and create a new file. + err = w.Checkout(&CheckoutOptions{ + Branch: plumbing.NewBranchReferenceName("new-branch"), + Create: true, + }) + c.Assert(err, IsNil) + + w.Filesystem = memfs.New() + f, err := w.Filesystem.Create("new-file.txt") + c.Assert(err, IsNil) + _, err = f.Write([]byte("DUMMY")) + c.Assert(err, IsNil) + c.Assert(f.Close(), IsNil) + + // Add the file to staging. + _, err = w.Add("new-file.txt") + c.Assert(err, IsNil) + + // Switch branch to master, and verify that the new file was kept in staging. + err = w.Checkout(&CheckoutOptions{ + Keep: true, + }) + c.Assert(err, IsNil) + + fi, err := w.Filesystem.Stat("new-file.txt") + c.Assert(err, IsNil) + c.Assert(fi.Size(), Equals, int64(5)) +} + +func (s *WorktreeSuite) TestCheckoutSymlink(c *C) { + if runtime.GOOS == "windows" { + c.Skip("git doesn't support symlinks by default in windows") + } + + dir, err := ioutil.TempDir("", "checkout") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, false) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + w.Filesystem.Symlink("not-exists", "bar") + w.Add("bar") + w.Commit("foo", &CommitOptions{Author: defaultSignature()}) + + r.Storer.SetIndex(&index.Index{Version: 2}) + w.Filesystem = osfs.New(filepath.Join(dir, "worktree-empty")) + + err = w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) + + target, err := w.Filesystem.Readlink("bar") + c.Assert(target, Equals, "not-exists") + c.Assert(err, IsNil) +} + +func (s *WorktreeSuite) TestFilenameNormalization(c *C) { + if runtime.GOOS == "windows" { + c.Skip("windows paths may contain non utf-8 sequences") + } + + url := c.MkDir() + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + + server, err := PlainClone(url, false, &CloneOptions{ + URL: path, + }) + c.Assert(err, IsNil) + + filename := "페" + + w, err := server.Worktree() + c.Assert(err, IsNil) + + writeFile := func(path string) { + err := util.WriteFile(w.Filesystem, path, []byte("foo"), 0755) + c.Assert(err, IsNil) + } + + writeFile(filename) + origHash, err := w.Add(filename) + c.Assert(err, IsNil) + _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ + URL: url, + }) + c.Assert(err, IsNil) + + w, err = r.Worktree() + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) + + err = w.Filesystem.Remove(filename) + c.Assert(err, IsNil) + + modFilename := norm.NFKD.String(filename) + writeFile(modFilename) + + _, err = w.Add(filename) + c.Assert(err, IsNil) + modHash, err := w.Add(modFilename) + c.Assert(err, IsNil) + // At this point we've got two files with the same content. + // Hence their hashes must be the same. + c.Assert(origHash == modHash, Equals, true) + + status, err = w.Status() + c.Assert(err, IsNil) + // However, their names are different and the work tree is still dirty. + c.Assert(status.IsClean(), Equals, false) + + // Revert back the deletion of the first file. + writeFile(filename) + _, err = w.Add(filename) + c.Assert(err, IsNil) + + status, err = w.Status() + c.Assert(err, IsNil) + // Still dirty - the second file is added. + c.Assert(status.IsClean(), Equals, false) + + _, err = w.Remove(modFilename) + c.Assert(err, IsNil) + + status, err = w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestCheckoutSubmodule(c *C) { + url := "https://github.com/git-fixtures/submodule.git" + r := s.NewRepositoryWithEmptyWorktree(fixtures.ByURL(url).One()) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestCheckoutSubmoduleInitialized(c *C) { + url := "https://github.com/git-fixtures/submodule.git" + r := s.NewRepository(fixtures.ByURL(url).One()) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + sub, err := w.Submodules() + c.Assert(err, IsNil) + + err = sub.Update(&SubmoduleUpdateOptions{Init: true}) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestCheckoutIndexMem(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + idx, err := s.Repository.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88") + c.Assert(idx.Entries[0].Name, Equals, ".gitignore") + c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular) + c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false) + c.Assert(idx.Entries[0].Size, Equals, uint32(189)) + + // ctime, dev, inode, uid and gid are not supported on memfs fs + c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, true) + c.Assert(idx.Entries[0].Dev, Equals, uint32(0)) + c.Assert(idx.Entries[0].Inode, Equals, uint32(0)) + c.Assert(idx.Entries[0].UID, Equals, uint32(0)) + c.Assert(idx.Entries[0].GID, Equals, uint32(0)) +} + +func (s *WorktreeSuite) TestCheckoutIndexOS(c *C) { + dir, err := ioutil.TempDir("", "checkout") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + fs := osfs.New(filepath.Join(dir, "worktree")) + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err = w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + idx, err := s.Repository.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88") + c.Assert(idx.Entries[0].Name, Equals, ".gitignore") + c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular) + c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false) + c.Assert(idx.Entries[0].Size, Equals, uint32(189)) + + c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, false) + if runtime.GOOS != "windows" { + c.Assert(idx.Entries[0].Dev, Not(Equals), uint32(0)) + c.Assert(idx.Entries[0].Inode, Not(Equals), uint32(0)) + c.Assert(idx.Entries[0].UID, Not(Equals), uint32(0)) + c.Assert(idx.Entries[0].GID, Not(Equals), uint32(0)) + } +} + +func (s *WorktreeSuite) TestCheckoutBranch(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{ + Branch: "refs/heads/branch", + }) + c.Assert(err, IsNil) + + head, err := w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "refs/heads/branch") + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestCheckoutCreateWithHash(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{ + Create: true, + Branch: "refs/heads/foo", + Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + c.Assert(err, IsNil) + + head, err := w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "refs/heads/foo") + c.Assert(head.Hash(), Equals, plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestCheckoutCreate(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{ + Create: true, + Branch: "refs/heads/foo", + }) + c.Assert(err, IsNil) + + head, err := w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "refs/heads/foo") + c.Assert(head.Hash(), Equals, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5")) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestCheckoutBranchAndHash(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{ + Branch: "refs/heads/foo", + Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), + }) + + c.Assert(err, Equals, ErrBranchHashExclusive) +} + +func (s *WorktreeSuite) TestCheckoutCreateMissingBranch(c *C) { + w := &Worktree{ + r: s.Repository, + Filesystem: memfs.New(), + } + + err := w.Checkout(&CheckoutOptions{ + Create: true, + }) + + c.Assert(err, Equals, ErrCreateRequiresBranch) +} + +func (s *WorktreeSuite) TestCheckoutTag(c *C) { + f := fixtures.ByTag("tags").One() + r := s.NewRepositoryWithEmptyWorktree(f) + w, err := r.Worktree() + c.Assert(err, IsNil) + + err = w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + head, err := w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "refs/heads/master") + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) + + err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/lightweight-tag"}) + c.Assert(err, IsNil) + head, err = w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "HEAD") + c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") + + err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/commit-tag"}) + c.Assert(err, IsNil) + head, err = w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "HEAD") + c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") + + err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/tree-tag"}) + c.Assert(err, NotNil) + head, err = w.r.Head() + c.Assert(err, IsNil) + c.Assert(head.Name().String(), Equals, "HEAD") +} + +func (s *WorktreeSuite) TestCheckoutBisect(c *C) { + if testing.Short() { + c.Skip("skipping test in short mode.") + } + + s.testCheckoutBisect(c, "https://github.com/src-d/go-git.git") +} + +func (s *WorktreeSuite) TestCheckoutBisectSubmodules(c *C) { + s.testCheckoutBisect(c, "https://github.com/git-fixtures/submodule.git") +} + +// TestCheckoutBisect simulates a git bisect going through the git history and +// checking every commit over the previous commit +func (s *WorktreeSuite) testCheckoutBisect(c *C, url string) { + f := fixtures.ByURL(url).One() + r := s.NewRepositoryWithEmptyWorktree(f) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + iter, err := w.r.Log(&LogOptions{}) + c.Assert(err, IsNil) + + iter.ForEach(func(commit *object.Commit) error { + err := w.Checkout(&CheckoutOptions{Hash: commit.Hash}) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) + + return nil + }) +} + +func (s *WorktreeSuite) TestStatus(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + status, err := w.Status() + c.Assert(err, IsNil) + + c.Assert(status.IsClean(), Equals, false) + c.Assert(status, HasLen, 9) +} + +func (s *WorktreeSuite) TestStatusEmpty(c *C) { + fs := memfs.New() + storage := memory.NewStorage() + + r, err := Init(storage, fs) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) + c.Assert(status, NotNil) +} + +func (s *WorktreeSuite) TestStatusEmptyDirty(c *C) { + fs := memfs.New() + err := util.WriteFile(fs, "foo", []byte("foo"), 0755) + c.Assert(err, IsNil) + + storage := memory.NewStorage() + + r, err := Init(storage, fs) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, false) + c.Assert(status, HasLen, 1) +} + +func (s *WorktreeSuite) TestReset(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + branch, err := w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Not(Equals), commit) + + err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit}) + c.Assert(err, IsNil) + + branch, err = w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Equals, commit) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestResetWithUntracked(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + err = util.WriteFile(fs, "foo", nil, 0755) + c.Assert(err, IsNil) + + err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit}) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) +} + +func (s *WorktreeSuite) TestResetSoft(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + err = w.Reset(&ResetOptions{Mode: SoftReset, Commit: commit}) + c.Assert(err, IsNil) + + branch, err := w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Equals, commit) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, false) + c.Assert(status.File("CHANGELOG").Staging, Equals, Added) +} + +func (s *WorktreeSuite) TestResetMixed(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + err = w.Reset(&ResetOptions{Mode: MixedReset, Commit: commit}) + c.Assert(err, IsNil) + + branch, err := w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Equals, commit) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, false) + c.Assert(status.File("CHANGELOG").Staging, Equals, Untracked) +} + +func (s *WorktreeSuite) TestResetMerge(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + commitA := plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294") + commitB := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitA}) + c.Assert(err, IsNil) + + branch, err := w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Equals, commitA) + + f, err := fs.Create(".gitignore") + c.Assert(err, IsNil) + _, err = f.Write([]byte("foo")) + c.Assert(err, IsNil) + err = f.Close() + c.Assert(err, IsNil) + + err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitB}) + c.Assert(err, Equals, ErrUnstagedChanges) + + branch, err = w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Equals, commitA) +} + +func (s *WorktreeSuite) TestResetHard(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") + + err := w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + f, err := fs.Create(".gitignore") + c.Assert(err, IsNil) + _, err = f.Write([]byte("foo")) + c.Assert(err, IsNil) + err = f.Close() + c.Assert(err, IsNil) + + err = w.Reset(&ResetOptions{Mode: HardReset, Commit: commit}) + c.Assert(err, IsNil) + + branch, err := w.r.Reference(plumbing.Master, false) + c.Assert(err, IsNil) + c.Assert(branch.Hash(), Equals, commit) +} + +func (s *WorktreeSuite) TestStatusAfterCheckout(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, true) + +} + +func (s *WorktreeSuite) TestStatusModified(c *C) { + dir, err := ioutil.TempDir("", "status") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + fs := osfs.New(filepath.Join(dir, "worktree")) + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err = w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + f, err := fs.Create(".gitignore") + c.Assert(err, IsNil) + _, err = f.Write([]byte("foo")) + c.Assert(err, IsNil) + err = f.Close() + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, false) + c.Assert(status.File(".gitignore").Worktree, Equals, Modified) +} + +func (s *WorktreeSuite) TestStatusIgnored(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + w.Checkout(&CheckoutOptions{}) + + fs.MkdirAll("another", os.ModePerm) + f, _ := fs.Create("another/file") + f.Close() + fs.MkdirAll("vendor/github.com", os.ModePerm) + f, _ = fs.Create("vendor/github.com/file") + f.Close() + fs.MkdirAll("vendor/gopkg.in", os.ModePerm) + f, _ = fs.Create("vendor/gopkg.in/file") + f.Close() + + status, _ := w.Status() + c.Assert(len(status), Equals, 3) + _, ok := status["another/file"] + c.Assert(ok, Equals, true) + _, ok = status["vendor/github.com/file"] + c.Assert(ok, Equals, true) + _, ok = status["vendor/gopkg.in/file"] + c.Assert(ok, Equals, true) + + f, _ = fs.Create(".gitignore") + f.Write([]byte("vendor/g*/")) + f.Close() + f, _ = fs.Create("vendor/.gitignore") + f.Write([]byte("!github.com/\n")) + f.Close() + + status, _ = w.Status() + c.Assert(len(status), Equals, 4) + _, ok = status[".gitignore"] + c.Assert(ok, Equals, true) + _, ok = status["another/file"] + c.Assert(ok, Equals, true) + _, ok = status["vendor/.gitignore"] + c.Assert(ok, Equals, true) + _, ok = status["vendor/github.com/file"] + c.Assert(ok, Equals, true) +} + +func (s *WorktreeSuite) TestStatusUntracked(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + f, err := w.Filesystem.Create("foo") + c.Assert(err, IsNil) + c.Assert(f.Close(), IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.File("foo").Staging, Equals, Untracked) + c.Assert(status.File("foo").Worktree, Equals, Untracked) +} + +func (s *WorktreeSuite) TestStatusDeleted(c *C) { + dir, err := ioutil.TempDir("", "status") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + fs := osfs.New(filepath.Join(dir, "worktree")) + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err = w.Checkout(&CheckoutOptions{}) + c.Assert(err, IsNil) + + err = fs.Remove(".gitignore") + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status.IsClean(), Equals, false) + c.Assert(status.File(".gitignore").Worktree, Equals, Deleted) +} + +func (s *WorktreeSuite) TestSubmodule(c *C) { + path := fixtures.ByTag("submodule").One().Worktree().Root() + r, err := PlainOpen(path) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + m, err := w.Submodule("basic") + c.Assert(err, IsNil) + + c.Assert(m.Config().Name, Equals, "basic") +} + +func (s *WorktreeSuite) TestSubmodules(c *C) { + path := fixtures.ByTag("submodule").One().Worktree().Root() + r, err := PlainOpen(path) + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + + l, err := w.Submodules() + c.Assert(err, IsNil) + + c.Assert(l, HasLen, 2) +} + +func (s *WorktreeSuite) TestAddUntracked(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + idx, err := w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) + c.Assert(err, IsNil) + + hash, err := w.Add("foo") + c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5") + c.Assert(err, IsNil) + + idx, err = w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 10) + + e, err := idx.Entry("foo") + c.Assert(err, IsNil) + c.Assert(e.Hash, Equals, hash) + c.Assert(e.Mode, Equals, filemode.Executable) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 1) + + file := status.File("foo") + c.Assert(file.Staging, Equals, Added) + c.Assert(file.Worktree, Equals, Unmodified) + + obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, hash) + c.Assert(err, IsNil) + c.Assert(obj, NotNil) + c.Assert(obj.Size(), Equals, int64(3)) +} + +func (s *WorktreeSuite) TestIgnored(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + w.Excludes = make([]gitignore.Pattern, 0) + w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil)) + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + idx, err := w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 0) + + file := status.File("foo") + c.Assert(file.Staging, Equals, Untracked) + c.Assert(file.Worktree, Equals, Untracked) +} + +func (s *WorktreeSuite) TestExcludedNoGitignore(c *C) { + f := fixtures.ByTag("empty").One() + r := s.NewRepository(f) + + fs := memfs.New() + w := &Worktree{ + r: r, + Filesystem: fs, + } + + _, err := fs.Open(".gitignore") + c.Assert(err, Equals, os.ErrNotExist) + + w.Excludes = make([]gitignore.Pattern, 0) + w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil)) + + err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 0) + + file := status.File("foo") + c.Assert(file.Staging, Equals, Untracked) + c.Assert(file.Worktree, Equals, Untracked) +} + +func (s *WorktreeSuite) TestAddModified(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + idx, err := w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + err = util.WriteFile(w.Filesystem, "LICENSE", []byte("FOO"), 0644) + c.Assert(err, IsNil) + + hash, err := w.Add("LICENSE") + c.Assert(err, IsNil) + c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5") + + idx, err = w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + e, err := idx.Entry("LICENSE") + c.Assert(err, IsNil) + c.Assert(e.Hash, Equals, hash) + c.Assert(e.Mode, Equals, filemode.Regular) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 1) + + file := status.File("LICENSE") + c.Assert(file.Staging, Equals, Modified) + c.Assert(file.Worktree, Equals, Unmodified) +} + +func (s *WorktreeSuite) TestAddUnmodified(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Add("LICENSE") + c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") + c.Assert(err, IsNil) +} + +func (s *WorktreeSuite) TestAddRemoved(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + idx, err := w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + err = w.Filesystem.Remove("LICENSE") + c.Assert(err, IsNil) + + hash, err := w.Add("LICENSE") + c.Assert(err, IsNil) + c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") + + e, err := idx.Entry("LICENSE") + c.Assert(err, IsNil) + c.Assert(e.Hash, Equals, hash) + c.Assert(e.Mode, Equals, filemode.Regular) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 1) + + file := status.File("LICENSE") + c.Assert(file.Staging, Equals, Deleted) +} + +func (s *WorktreeSuite) TestAddSymlink(c *C) { + dir, err := ioutil.TempDir("", "checkout") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, false) + c.Assert(err, IsNil) + err = util.WriteFile(r.wt, "foo", []byte("qux"), 0644) + c.Assert(err, IsNil) + err = r.wt.Symlink("foo", "bar") + c.Assert(err, IsNil) + + w, err := r.Worktree() + c.Assert(err, IsNil) + h, err := w.Add("foo") + c.Assert(err, IsNil) + c.Assert(h, Not(Equals), plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c")) + + h, err = w.Add("bar") + c.Assert(err, IsNil) + c.Assert(h, Equals, plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c")) + + obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, h) + c.Assert(err, IsNil) + c.Assert(obj, NotNil) + c.Assert(obj.Size(), Equals, int64(3)) +} + +func (s *WorktreeSuite) TestAddDirectory(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + idx, err := w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + err = util.WriteFile(w.Filesystem, "qux/foo", []byte("FOO"), 0755) + c.Assert(err, IsNil) + err = util.WriteFile(w.Filesystem, "qux/baz/bar", []byte("BAR"), 0755) + c.Assert(err, IsNil) + + h, err := w.Add("qux") + c.Assert(err, IsNil) + c.Assert(h.IsZero(), Equals, true) + + idx, err = w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 11) + + e, err := idx.Entry("qux/foo") + c.Assert(err, IsNil) + c.Assert(e.Mode, Equals, filemode.Executable) + + e, err = idx.Entry("qux/baz/bar") + c.Assert(err, IsNil) + c.Assert(e.Mode, Equals, filemode.Executable) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 2) + + file := status.File("qux/foo") + c.Assert(file.Staging, Equals, Added) + c.Assert(file.Worktree, Equals, Unmodified) + + file = status.File("qux/baz/bar") + c.Assert(file.Staging, Equals, Added) + c.Assert(file.Worktree, Equals, Unmodified) +} + +func (s *WorktreeSuite) TestAddDirectoryErrorNotFound(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + w, _ := r.Worktree() + + h, err := w.Add("foo") + c.Assert(err, NotNil) + c.Assert(h.IsZero(), Equals, true) +} + +func (s *WorktreeSuite) TestAddGlob(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + idx, err := w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 9) + + err = util.WriteFile(w.Filesystem, "qux/qux", []byte("QUX"), 0755) + c.Assert(err, IsNil) + err = util.WriteFile(w.Filesystem, "qux/baz", []byte("BAZ"), 0755) + c.Assert(err, IsNil) + err = util.WriteFile(w.Filesystem, "qux/bar/baz", []byte("BAZ"), 0755) + c.Assert(err, IsNil) + + err = w.AddGlob(w.Filesystem.Join("qux", "b*")) + c.Assert(err, IsNil) + + idx, err = w.r.Storer.Index() + c.Assert(err, IsNil) + c.Assert(idx.Entries, HasLen, 11) + + e, err := idx.Entry("qux/baz") + c.Assert(err, IsNil) + c.Assert(e.Mode, Equals, filemode.Executable) + + e, err = idx.Entry("qux/bar/baz") + c.Assert(err, IsNil) + c.Assert(e.Mode, Equals, filemode.Executable) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 3) + + file := status.File("qux/qux") + c.Assert(file.Staging, Equals, Untracked) + c.Assert(file.Worktree, Equals, Untracked) + + file = status.File("qux/baz") + c.Assert(file.Staging, Equals, Added) + c.Assert(file.Worktree, Equals, Unmodified) + + file = status.File("qux/bar/baz") + c.Assert(file.Staging, Equals, Added) + c.Assert(file.Worktree, Equals, Unmodified) +} + +func (s *WorktreeSuite) TestAddGlobErrorNoMatches(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + w, _ := r.Worktree() + + err := w.AddGlob("foo") + c.Assert(err, Equals, ErrGlobNoMatches) +} + +func (s *WorktreeSuite) TestRemove(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Remove("LICENSE") + c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 1) + c.Assert(status.File("LICENSE").Staging, Equals, Deleted) +} + +func (s *WorktreeSuite) TestRemoveNotExistentEntry(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Remove("not-exists") + c.Assert(hash.IsZero(), Equals, true) + c.Assert(err, NotNil) +} + +func (s *WorktreeSuite) TestRemoveDirectory(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Remove("json") + c.Assert(hash.IsZero(), Equals, true) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 2) + c.Assert(status.File("json/long.json").Staging, Equals, Deleted) + c.Assert(status.File("json/short.json").Staging, Equals, Deleted) + + _, err = w.Filesystem.Stat("json") + c.Assert(os.IsNotExist(err), Equals, true) +} + +func (s *WorktreeSuite) TestRemoveDirectoryUntracked(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755) + c.Assert(err, IsNil) + + hash, err := w.Remove("json") + c.Assert(hash.IsZero(), Equals, true) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 3) + c.Assert(status.File("json/long.json").Staging, Equals, Deleted) + c.Assert(status.File("json/short.json").Staging, Equals, Deleted) + c.Assert(status.File("json/foo").Staging, Equals, Untracked) + + _, err = w.Filesystem.Stat("json") + c.Assert(err, IsNil) +} + +func (s *WorktreeSuite) TestRemoveDeletedFromWorktree(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + err = fs.Remove("LICENSE") + c.Assert(err, IsNil) + + hash, err := w.Remove("LICENSE") + c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 1) + c.Assert(status.File("LICENSE").Staging, Equals, Deleted) +} + +func (s *WorktreeSuite) TestRemoveGlob(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + err = w.RemoveGlob(w.Filesystem.Join("json", "l*")) + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 1) + c.Assert(status.File("json/long.json").Staging, Equals, Deleted) +} + +func (s *WorktreeSuite) TestRemoveGlobDirectory(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + err = w.RemoveGlob("js*") + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 2) + c.Assert(status.File("json/short.json").Staging, Equals, Deleted) + c.Assert(status.File("json/long.json").Staging, Equals, Deleted) + + _, err = w.Filesystem.Stat("json") + c.Assert(os.IsNotExist(err), Equals, true) +} + +func (s *WorktreeSuite) TestRemoveGlobDirectoryDeleted(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + err = fs.Remove("json/short.json") + c.Assert(err, IsNil) + + err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755) + c.Assert(err, IsNil) + + err = w.RemoveGlob("js*") + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 3) + c.Assert(status.File("json/short.json").Staging, Equals, Deleted) + c.Assert(status.File("json/long.json").Staging, Equals, Deleted) +} + +func (s *WorktreeSuite) TestMove(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Move("LICENSE", "foo") + c.Check(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") + c.Assert(err, IsNil) + + status, err := w.Status() + c.Assert(err, IsNil) + c.Assert(status, HasLen, 2) + c.Assert(status.File("LICENSE").Staging, Equals, Deleted) + c.Assert(status.File("foo").Staging, Equals, Added) + +} + +func (s *WorktreeSuite) TestMoveNotExistentEntry(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Move("not-exists", "foo") + c.Assert(hash.IsZero(), Equals, true) + c.Assert(err, NotNil) +} + +func (s *WorktreeSuite) TestMoveToExistent(c *C) { + fs := memfs.New() + w := &Worktree{ + r: s.Repository, + Filesystem: fs, + } + + err := w.Checkout(&CheckoutOptions{Force: true}) + c.Assert(err, IsNil) + + hash, err := w.Move(".gitignore", "LICENSE") + c.Assert(hash.IsZero(), Equals, true) + c.Assert(err, Equals, ErrDestinationExists) +} + +func (s *WorktreeSuite) TestClean(c *C) { + fs := fixtures.ByTag("dirty").One().Worktree() + + // Open the repo. + fs, err := fs.Chroot("repo") + c.Assert(err, IsNil) + r, err := PlainOpen(fs.Root()) + c.Assert(err, IsNil) + + wt, err := r.Worktree() + c.Assert(err, IsNil) + + // Status before cleaning. + status, err := wt.Status() + c.Assert(err, IsNil) + c.Assert(len(status), Equals, 2) + + err = wt.Clean(&CleanOptions{}) + c.Assert(err, IsNil) + + // Status after cleaning. + status, err = wt.Status() + c.Assert(err, IsNil) + + c.Assert(len(status), Equals, 1) + + fi, err := fs.Lstat("pkgA") + c.Assert(err, IsNil) + c.Assert(fi.IsDir(), Equals, true) + + // Clean with Dir: true. + err = wt.Clean(&CleanOptions{Dir: true}) + c.Assert(err, IsNil) + + status, err = wt.Status() + c.Assert(err, IsNil) + + c.Assert(len(status), Equals, 0) + + // An empty dir should be deleted, as well. + _, err = fs.Lstat("pkgA") + c.Assert(err, ErrorMatches, ".*(no such file or directory.*|.*file does not exist)*.") + +} + +func (s *WorktreeSuite) TestAlternatesRepo(c *C) { + fs := fixtures.ByTag("alternates").One().Worktree() + + // Open 1st repo. + rep1fs, err := fs.Chroot("rep1") + c.Assert(err, IsNil) + rep1, err := PlainOpen(rep1fs.Root()) + c.Assert(err, IsNil) + + // Open 2nd repo. + rep2fs, err := fs.Chroot("rep2") + c.Assert(err, IsNil) + rep2, err := PlainOpen(rep2fs.Root()) + c.Assert(err, IsNil) + + // Get the HEAD commit from the main repo. + h, err := rep1.Head() + c.Assert(err, IsNil) + commit1, err := rep1.CommitObject(h.Hash()) + c.Assert(err, IsNil) + + // Get the HEAD commit from the shared repo. + h, err = rep2.Head() + c.Assert(err, IsNil) + commit2, err := rep2.CommitObject(h.Hash()) + c.Assert(err, IsNil) + + c.Assert(commit1.String(), Equals, commit2.String()) +} + +func (s *WorktreeSuite) TestGrep(c *C) { + cases := []struct { + name string + options GrepOptions + wantResult []GrepResult + dontWantResult []GrepResult + wantError error + }{ + { + name: "basic word match", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, + }, + wantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + { + FileName: "vendor/foo.go", + LineNumber: 3, + Content: "import \"fmt\"", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, { + name: "case insensitive match", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile(`(?i)IMport`)}, + }, + wantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + { + FileName: "vendor/foo.go", + LineNumber: 3, + Content: "import \"fmt\"", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, { + name: "invert match", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, + InvertMatch: true, + }, + dontWantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + { + FileName: "vendor/foo.go", + LineNumber: 3, + Content: "import \"fmt\"", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, { + name: "match at a given commit hash", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("The MIT License")}, + CommitHash: plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), + }, + wantResult: []GrepResult{ + { + FileName: "LICENSE", + LineNumber: 1, + Content: "The MIT License (MIT)", + TreeName: "b029517f6300c2da0f4b651b8642506cd6aaf45d", + }, + }, + dontWantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, { + name: "match for a given pathspec", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, + PathSpecs: []*regexp.Regexp{regexp.MustCompile("go/")}, + }, + wantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + dontWantResult: []GrepResult{ + { + FileName: "vendor/foo.go", + LineNumber: 3, + Content: "import \"fmt\"", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, { + name: "match at a given reference name", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, + ReferenceName: "refs/heads/master", + }, + wantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "refs/heads/master", + }, + }, + }, { + name: "ambiguous options", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, + CommitHash: plumbing.NewHash("2d55a722f3c3ecc36da919dfd8b6de38352f3507"), + ReferenceName: "somereferencename", + }, + wantError: ErrHashOrReference, + }, { + name: "multiple patterns", + options: GrepOptions{ + Patterns: []*regexp.Regexp{ + regexp.MustCompile("import"), + regexp.MustCompile("License"), + }, + }, + wantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + { + FileName: "vendor/foo.go", + LineNumber: 3, + Content: "import \"fmt\"", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + { + FileName: "LICENSE", + LineNumber: 1, + Content: "The MIT License (MIT)", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, { + name: "multiple pathspecs", + options: GrepOptions{ + Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, + PathSpecs: []*regexp.Regexp{ + regexp.MustCompile("go/"), + regexp.MustCompile("vendor/"), + }, + }, + wantResult: []GrepResult{ + { + FileName: "go/example.go", + LineNumber: 3, + Content: "import (", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + { + FileName: "vendor/foo.go", + LineNumber: 3, + Content: "import \"fmt\"", + TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", + }, + }, + }, + } + + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + server, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: path, + }) + c.Assert(err, IsNil) + + w, err := server.Worktree() + c.Assert(err, IsNil) + + for _, tc := range cases { + gr, err := w.Grep(&tc.options) + if tc.wantError != nil { + c.Assert(err, Equals, tc.wantError) + } else { + c.Assert(err, IsNil) + } + + // Iterate through the results and check if the wanted result is present + // in the got result. + for _, wantResult := range tc.wantResult { + found := false + for _, gotResult := range gr { + if wantResult == gotResult { + found = true + break + } + } + if !found { + c.Errorf("unexpected grep results for %q, expected result to contain: %v", tc.name, wantResult) + } + } + + // Iterate through the results and check if the not wanted result is + // present in the got result. + for _, dontWantResult := range tc.dontWantResult { + found := false + for _, gotResult := range gr { + if dontWantResult == gotResult { + found = true + break + } + } + if found { + c.Errorf("unexpected grep results for %q, expected result to NOT contain: %v", tc.name, dontWantResult) + } + } + } +} + +func (s *WorktreeSuite) TestAddAndCommit(c *C) { + dir, err := ioutil.TempDir("", "plain-repo") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + repo, err := PlainInit(dir, false) + c.Assert(err, IsNil) + + w, err := repo.Worktree() + c.Assert(err, IsNil) + + _, err = w.Add(".") + c.Assert(err, IsNil) + + w.Commit("Test Add And Commit", &CommitOptions{Author: &object.Signature{ + Name: "foo", + Email: "foo@foo.foo", + When: time.Now(), + }}) + + iter, err := w.r.Log(&LogOptions{}) + c.Assert(err, IsNil) + err = iter.ForEach(func(c *object.Commit) error { + files, err := c.Files() + if err != nil { + return err + } + + err = files.ForEach(func(f *object.File) error { + return errors.New("Expected no files, got at least 1") + }) + return err + }) + c.Assert(err, IsNil) +} diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_unix_other.go b/vendor/github.com/devtron-labs/go-git/worktree_unix_other.go similarity index 81% rename from vendor/gopkg.in/src-d/go-git.v4/worktree_unix_other.go rename to vendor/github.com/devtron-labs/go-git/worktree_unix_other.go index d6327676..e91aefe6 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_unix_other.go +++ b/vendor/github.com/devtron-labs/go-git/worktree_unix_other.go @@ -1,3 +1,4 @@ +//go:build openbsd || dragonfly || solaris // +build openbsd dragonfly solaris package git @@ -6,7 +7,7 @@ import ( "syscall" "time" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/format/index" ) func init() { diff --git a/vendor/gopkg.in/src-d/go-git.v4/worktree_windows.go b/vendor/github.com/devtron-labs/go-git/worktree_windows.go similarity index 90% rename from vendor/gopkg.in/src-d/go-git.v4/worktree_windows.go rename to vendor/github.com/devtron-labs/go-git/worktree_windows.go index 1bef6f75..91f64025 100644 --- a/vendor/gopkg.in/src-d/go-git.v4/worktree_windows.go +++ b/vendor/github.com/devtron-labs/go-git/worktree_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package git @@ -7,7 +8,7 @@ import ( "syscall" "time" - "gopkg.in/src-d/go-git.v4/plumbing/format/index" + "github.com/devtron-labs/go-git/plumbing/format/index" ) func init() { diff --git a/vendor/github.com/kevinburke/ssh_config/.gitattributes b/vendor/github.com/kevinburke/ssh_config/.gitattributes deleted file mode 100644 index 44db5818..00000000 --- a/vendor/github.com/kevinburke/ssh_config/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -testdata/dos-lines eol=crlf diff --git a/vendor/github.com/kevinburke/ssh_config/.gitignore b/vendor/github.com/kevinburke/ssh_config/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/github.com/kevinburke/ssh_config/.mailmap b/vendor/github.com/kevinburke/ssh_config/.mailmap deleted file mode 100644 index 253406b1..00000000 --- a/vendor/github.com/kevinburke/ssh_config/.mailmap +++ /dev/null @@ -1 +0,0 @@ -Kevin Burke Kevin Burke diff --git a/vendor/github.com/kevinburke/ssh_config/.travis.yml b/vendor/github.com/kevinburke/ssh_config/.travis.yml deleted file mode 100644 index 4306f30f..00000000 --- a/vendor/github.com/kevinburke/ssh_config/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -go_import_path: github.com/kevinburke/ssh_config - -language: go - -go: - - 1.11.x - - 1.12.x - - master - -before_script: - - go get -u ./... - -script: - - make race-test diff --git a/vendor/github.com/kevinburke/ssh_config/AUTHORS.txt b/vendor/github.com/kevinburke/ssh_config/AUTHORS.txt deleted file mode 100644 index cd337940..00000000 --- a/vendor/github.com/kevinburke/ssh_config/AUTHORS.txt +++ /dev/null @@ -1,5 +0,0 @@ -Eugene Terentev -Kevin Burke -Mark Nevill -Sergey Lukjanov -Wayne Ashley Berry diff --git a/vendor/github.com/kevinburke/ssh_config/LICENSE b/vendor/github.com/kevinburke/ssh_config/LICENSE deleted file mode 100644 index b9a770ac..00000000 --- a/vendor/github.com/kevinburke/ssh_config/LICENSE +++ /dev/null @@ -1,49 +0,0 @@ -Copyright (c) 2017 Kevin Burke. - -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. - -=================== - -The lexer and parser borrow heavily from github.com/pelletier/go-toml. The -license for that project is copied below. - -The MIT License (MIT) - -Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/kevinburke/ssh_config/Makefile b/vendor/github.com/kevinburke/ssh_config/Makefile deleted file mode 100644 index a1880d18..00000000 --- a/vendor/github.com/kevinburke/ssh_config/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -BUMP_VERSION := $(GOPATH)/bin/bump_version -STATICCHECK := $(GOPATH)/bin/staticcheck -WRITE_MAILMAP := $(GOPATH)/bin/write_mailmap - -$(STATICCHECK): - go get honnef.co/go/tools/cmd/staticcheck - -lint: $(STATICCHECK) - go vet ./... - $(STATICCHECK) - -test: lint - @# the timeout helps guard against infinite recursion - go test -timeout=250ms ./... - -race-test: lint - go test -timeout=500ms -race ./... - -$(BUMP_VERSION): - go get -u github.com/kevinburke/bump_version - -release: test | $(BUMP_VERSION) - $(BUMP_VERSION) minor config.go - -force: ; - -AUTHORS.txt: force | $(WRITE_MAILMAP) - $(WRITE_MAILMAP) > AUTHORS.txt - -authors: AUTHORS.txt diff --git a/vendor/github.com/kevinburke/ssh_config/README.md b/vendor/github.com/kevinburke/ssh_config/README.md deleted file mode 100644 index 52cc1eac..00000000 --- a/vendor/github.com/kevinburke/ssh_config/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# ssh_config - -This is a Go parser for `ssh_config` files. Importantly, this parser attempts -to preserve comments in a given file, so you can manipulate a `ssh_config` file -from a program, if your heart desires. - -It's designed to be used with the excellent -[x/crypto/ssh](https://golang.org/x/crypto/ssh) package, which handles SSH -negotiation but isn't very easy to configure. - -The `ssh_config` `Get()` and `GetStrict()` functions will attempt to read values -from `$HOME/.ssh/config` and fall back to `/etc/ssh/ssh_config`. The first -argument is the host name to match on, and the second argument is the key you -want to retrieve. - -```go -port := ssh_config.Get("myhost", "Port") -``` - -You can also load a config file and read values from it. - -```go -var config = ` -Host *.test - Compression yes -` - -cfg, err := ssh_config.Decode(strings.NewReader(config)) -fmt.Println(cfg.Get("example.test", "Port")) -``` - -Some SSH arguments have default values - for example, the default value for -`KeyboardAuthentication` is `"yes"`. If you call Get(), and no value for the -given Host/keyword pair exists in the config, we'll return a default for the -keyword if one exists. - -### Manipulating SSH config files - -Here's how you can manipulate an SSH config file, and then write it back to -disk. - -```go -f, _ := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config")) -cfg, _ := ssh_config.Decode(f) -for _, host := range cfg.Hosts { - fmt.Println("patterns:", host.Patterns) - for _, node := range host.Nodes { - // Manipulate the nodes as you see fit, or use a type switch to - // distinguish between Empty, KV, and Include nodes. - fmt.Println(node.String()) - } -} - -// Print the config to stdout: -fmt.Println(cfg.String()) -``` - -## Spec compliance - -Wherever possible we try to implement the specification as documented in -the `ssh_config` manpage. Unimplemented features should be present in the -[issues][issues] list. - -Notably, the `Match` directive is currently unsupported. - -[issues]: https://github.com/kevinburke/ssh_config/issues - -## Errata - -This is the second [comment-preserving configuration parser][blog] I've written, after -[an /etc/hosts parser][hostsfile]. Eventually, I will write one for every Linux -file format. - -[blog]: https://kev.inburke.com/kevin/more-comment-preserving-configuration-parsers/ -[hostsfile]: https://github.com/kevinburke/hostsfile - -## Donating - -Donations free up time to make improvements to the library, and respond to -bug reports. You can send donations via Paypal's "Send Money" feature to -kev@inburke.com. Donations are not tax deductible in the USA. diff --git a/vendor/github.com/kevinburke/ssh_config/config.go b/vendor/github.com/kevinburke/ssh_config/config.go deleted file mode 100644 index 136f0c35..00000000 --- a/vendor/github.com/kevinburke/ssh_config/config.go +++ /dev/null @@ -1,649 +0,0 @@ -// Package ssh_config provides tools for manipulating SSH config files. -// -// Importantly, this parser attempts to preserve comments in a given file, so -// you can manipulate a `ssh_config` file from a program, if your heart desires. -// -// The Get() and GetStrict() functions will attempt to read values from -// $HOME/.ssh/config, falling back to /etc/ssh/ssh_config. The first argument is -// the host name to match on ("example.com"), and the second argument is the key -// you want to retrieve ("Port"). The keywords are case insensitive. -// -// port := ssh_config.Get("myhost", "Port") -// -// You can also manipulate an SSH config file and then print it or write it back -// to disk. -// -// f, _ := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config")) -// cfg, _ := ssh_config.Decode(f) -// for _, host := range cfg.Hosts { -// fmt.Println("patterns:", host.Patterns) -// for _, node := range host.Nodes { -// fmt.Println(node.String()) -// } -// } -// -// // Write the cfg back to disk: -// fmt.Println(cfg.String()) -// -// BUG: the Match directive is currently unsupported; parsing a config with -// a Match directive will trigger an error. -package ssh_config - -import ( - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - osuser "os/user" - "path/filepath" - "regexp" - "runtime" - "strings" - "sync" -) - -const version = "1.0" - -var _ = version - -type configFinder func() string - -// UserSettings checks ~/.ssh and /etc/ssh for configuration files. The config -// files are parsed and cached the first time Get() or GetStrict() is called. -type UserSettings struct { - IgnoreErrors bool - systemConfig *Config - systemConfigFinder configFinder - userConfig *Config - userConfigFinder configFinder - loadConfigs sync.Once - onceErr error -} - -func homedir() string { - user, err := osuser.Current() - if err == nil { - return user.HomeDir - } else { - return os.Getenv("HOME") - } -} - -func userConfigFinder() string { - return filepath.Join(homedir(), ".ssh", "config") -} - -// DefaultUserSettings is the default UserSettings and is used by Get and -// GetStrict. It checks both $HOME/.ssh/config and /etc/ssh/ssh_config for keys, -// and it will return parse errors (if any) instead of swallowing them. -var DefaultUserSettings = &UserSettings{ - IgnoreErrors: false, - systemConfigFinder: systemConfigFinder, - userConfigFinder: userConfigFinder, -} - -func systemConfigFinder() string { - return filepath.Join("/", "etc", "ssh", "ssh_config") -} - -func findVal(c *Config, alias, key string) (string, error) { - if c == nil { - return "", nil - } - val, err := c.Get(alias, key) - if err != nil || val == "" { - return "", err - } - if err := validate(key, val); err != nil { - return "", err - } - return val, nil -} - -// Get finds the first value for key within a declaration that matches the -// alias. Get returns the empty string if no value was found, or if IgnoreErrors -// is false and we could not parse the configuration file. Use GetStrict to -// disambiguate the latter cases. -// -// The match for key is case insensitive. -// -// Get is a wrapper around DefaultUserSettings.Get. -func Get(alias, key string) string { - return DefaultUserSettings.Get(alias, key) -} - -// GetStrict finds the first value for key within a declaration that matches the -// alias. If key has a default value and no matching configuration is found, the -// default will be returned. For more information on default values and the way -// patterns are matched, see the manpage for ssh_config. -// -// error will be non-nil if and only if a user's configuration file or the -// system configuration file could not be parsed, and u.IgnoreErrors is false. -// -// GetStrict is a wrapper around DefaultUserSettings.GetStrict. -func GetStrict(alias, key string) (string, error) { - return DefaultUserSettings.GetStrict(alias, key) -} - -// Get finds the first value for key within a declaration that matches the -// alias. Get returns the empty string if no value was found, or if IgnoreErrors -// is false and we could not parse the configuration file. Use GetStrict to -// disambiguate the latter cases. -// -// The match for key is case insensitive. -func (u *UserSettings) Get(alias, key string) string { - val, err := u.GetStrict(alias, key) - if err != nil { - return "" - } - return val -} - -// GetStrict finds the first value for key within a declaration that matches the -// alias. If key has a default value and no matching configuration is found, the -// default will be returned. For more information on default values and the way -// patterns are matched, see the manpage for ssh_config. -// -// error will be non-nil if and only if a user's configuration file or the -// system configuration file could not be parsed, and u.IgnoreErrors is false. -func (u *UserSettings) GetStrict(alias, key string) (string, error) { - u.loadConfigs.Do(func() { - // can't parse user file, that's ok. - var filename string - if u.userConfigFinder == nil { - filename = userConfigFinder() - } else { - filename = u.userConfigFinder() - } - var err error - u.userConfig, err = parseFile(filename) - //lint:ignore S1002 I prefer it this way - if err != nil && os.IsNotExist(err) == false { - u.onceErr = err - return - } - if u.systemConfigFinder == nil { - filename = systemConfigFinder() - } else { - filename = u.systemConfigFinder() - } - u.systemConfig, err = parseFile(filename) - //lint:ignore S1002 I prefer it this way - if err != nil && os.IsNotExist(err) == false { - u.onceErr = err - return - } - }) - //lint:ignore S1002 I prefer it this way - if u.onceErr != nil && u.IgnoreErrors == false { - return "", u.onceErr - } - val, err := findVal(u.userConfig, alias, key) - if err != nil || val != "" { - return val, err - } - val2, err2 := findVal(u.systemConfig, alias, key) - if err2 != nil || val2 != "" { - return val2, err2 - } - return Default(key), nil -} - -func parseFile(filename string) (*Config, error) { - return parseWithDepth(filename, 0) -} - -func parseWithDepth(filename string, depth uint8) (*Config, error) { - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return decodeBytes(b, isSystem(filename), depth) -} - -func isSystem(filename string) bool { - // TODO: not sure this is the best way to detect a system repo - return strings.HasPrefix(filepath.Clean(filename), "/etc/ssh") -} - -// Decode reads r into a Config, or returns an error if r could not be parsed as -// an SSH config file. -func Decode(r io.Reader) (*Config, error) { - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - return decodeBytes(b, false, 0) -} - -func decodeBytes(b []byte, system bool, depth uint8) (c *Config, err error) { - defer func() { - if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } - if e, ok := r.(error); ok && e == ErrDepthExceeded { - err = e - return - } - err = errors.New(r.(string)) - } - }() - - c = parseSSH(lexSSH(b), system, depth) - return c, err -} - -// Config represents an SSH config file. -type Config struct { - // A list of hosts to match against. The file begins with an implicit - // "Host *" declaration matching all hosts. - Hosts []*Host - depth uint8 - position Position -} - -// Get finds the first value in the configuration that matches the alias and -// contains key. Get returns the empty string if no value was found, or if the -// Config contains an invalid conditional Include value. -// -// The match for key is case insensitive. -func (c *Config) Get(alias, key string) (string, error) { - lowerKey := strings.ToLower(key) - for _, host := range c.Hosts { - if !host.Matches(alias) { - continue - } - for _, node := range host.Nodes { - switch t := node.(type) { - case *Empty: - continue - case *KV: - // "keys are case insensitive" per the spec - lkey := strings.ToLower(t.Key) - if lkey == "match" { - panic("can't handle Match directives") - } - if lkey == lowerKey { - return t.Value, nil - } - case *Include: - val := t.Get(alias, key) - if val != "" { - return val, nil - } - default: - return "", fmt.Errorf("unknown Node type %v", t) - } - } - } - return "", nil -} - -// String returns a string representation of the Config file. -func (c Config) String() string { - return marshal(c).String() -} - -func (c Config) MarshalText() ([]byte, error) { - return marshal(c).Bytes(), nil -} - -func marshal(c Config) *bytes.Buffer { - var buf bytes.Buffer - for i := range c.Hosts { - buf.WriteString(c.Hosts[i].String()) - } - return &buf -} - -// Pattern is a pattern in a Host declaration. Patterns are read-only values; -// create a new one with NewPattern(). -type Pattern struct { - str string // Its appearance in the file, not the value that gets compiled. - regex *regexp.Regexp - not bool // True if this is a negated match -} - -// String prints the string representation of the pattern. -func (p Pattern) String() string { - return p.str -} - -// Copied from regexp.go with * and ? removed. -var specialBytes = []byte(`\.+()|[]{}^$`) - -func special(b byte) bool { - return bytes.IndexByte(specialBytes, b) >= 0 -} - -// NewPattern creates a new Pattern for matching hosts. NewPattern("*") creates -// a Pattern that matches all hosts. -// -// From the manpage, a pattern consists of zero or more non-whitespace -// characters, `*' (a wildcard that matches zero or more characters), or `?' (a -// wildcard that matches exactly one character). For example, to specify a set -// of declarations for any host in the ".co.uk" set of domains, the following -// pattern could be used: -// -// Host *.co.uk -// -// The following pattern would match any host in the 192.168.0.[0-9] network range: -// -// Host 192.168.0.? -func NewPattern(s string) (*Pattern, error) { - if s == "" { - return nil, errors.New("ssh_config: empty pattern") - } - negated := false - if s[0] == '!' { - negated = true - s = s[1:] - } - var buf bytes.Buffer - buf.WriteByte('^') - for i := 0; i < len(s); i++ { - // A byte loop is correct because all metacharacters are ASCII. - switch b := s[i]; b { - case '*': - buf.WriteString(".*") - case '?': - buf.WriteString(".?") - default: - // borrowing from QuoteMeta here. - if special(b) { - buf.WriteByte('\\') - } - buf.WriteByte(b) - } - } - buf.WriteByte('$') - r, err := regexp.Compile(buf.String()) - if err != nil { - return nil, err - } - return &Pattern{str: s, regex: r, not: negated}, nil -} - -// Host describes a Host directive and the keywords that follow it. -type Host struct { - // A list of host patterns that should match this host. - Patterns []*Pattern - // A Node is either a key/value pair or a comment line. - Nodes []Node - // EOLComment is the comment (if any) terminating the Host line. - EOLComment string - hasEquals bool - leadingSpace int // TODO: handle spaces vs tabs here. - // The file starts with an implicit "Host *" declaration. - implicit bool -} - -// Matches returns true if the Host matches for the given alias. For -// a description of the rules that provide a match, see the manpage for -// ssh_config. -func (h *Host) Matches(alias string) bool { - found := false - for i := range h.Patterns { - if h.Patterns[i].regex.MatchString(alias) { - if h.Patterns[i].not { - // Negated match. "A pattern entry may be negated by prefixing - // it with an exclamation mark (`!'). If a negated entry is - // matched, then the Host entry is ignored, regardless of - // whether any other patterns on the line match. Negated matches - // are therefore useful to provide exceptions for wildcard - // matches." - return false - } - found = true - } - } - return found -} - -// String prints h as it would appear in a config file. Minor tweaks may be -// present in the whitespace in the printed file. -func (h *Host) String() string { - var buf bytes.Buffer - //lint:ignore S1002 I prefer to write it this way - if h.implicit == false { - buf.WriteString(strings.Repeat(" ", int(h.leadingSpace))) - buf.WriteString("Host") - if h.hasEquals { - buf.WriteString(" = ") - } else { - buf.WriteString(" ") - } - for i, pat := range h.Patterns { - buf.WriteString(pat.String()) - if i < len(h.Patterns)-1 { - buf.WriteString(" ") - } - } - if h.EOLComment != "" { - buf.WriteString(" #") - buf.WriteString(h.EOLComment) - } - buf.WriteByte('\n') - } - for i := range h.Nodes { - buf.WriteString(h.Nodes[i].String()) - buf.WriteByte('\n') - } - return buf.String() -} - -// Node represents a line in a Config. -type Node interface { - Pos() Position - String() string -} - -// KV is a line in the config file that contains a key, a value, and possibly -// a comment. -type KV struct { - Key string - Value string - Comment string - hasEquals bool - leadingSpace int // Space before the key. TODO handle spaces vs tabs. - position Position -} - -// Pos returns k's Position. -func (k *KV) Pos() Position { - return k.position -} - -// String prints k as it was parsed in the config file. There may be slight -// changes to the whitespace between values. -func (k *KV) String() string { - if k == nil { - return "" - } - equals := " " - if k.hasEquals { - equals = " = " - } - line := fmt.Sprintf("%s%s%s%s", strings.Repeat(" ", int(k.leadingSpace)), k.Key, equals, k.Value) - if k.Comment != "" { - line += " #" + k.Comment - } - return line -} - -// Empty is a line in the config file that contains only whitespace or comments. -type Empty struct { - Comment string - leadingSpace int // TODO handle spaces vs tabs. - position Position -} - -// Pos returns e's Position. -func (e *Empty) Pos() Position { - return e.position -} - -// String prints e as it was parsed in the config file. -func (e *Empty) String() string { - if e == nil { - return "" - } - if e.Comment == "" { - return "" - } - return fmt.Sprintf("%s#%s", strings.Repeat(" ", int(e.leadingSpace)), e.Comment) -} - -// Include holds the result of an Include directive, including the config files -// that have been parsed as part of that directive. At most 5 levels of Include -// statements will be parsed. -type Include struct { - // Comment is the contents of any comment at the end of the Include - // statement. - Comment string - // an include directive can include several different files, and wildcards - directives []string - - mu sync.Mutex - // 1:1 mapping between matches and keys in files array; matches preserves - // ordering - matches []string - // actual filenames are listed here - files map[string]*Config - leadingSpace int - position Position - depth uint8 - hasEquals bool -} - -const maxRecurseDepth = 5 - -// ErrDepthExceeded is returned if too many Include directives are parsed. -// Usually this indicates a recursive loop (an Include directive pointing to the -// file it contains). -var ErrDepthExceeded = errors.New("ssh_config: max recurse depth exceeded") - -func removeDups(arr []string) []string { - // Use map to record duplicates as we find them. - encountered := make(map[string]bool, len(arr)) - result := make([]string, 0) - - for v := range arr { - //lint:ignore S1002 I prefer it this way - if encountered[arr[v]] == false { - encountered[arr[v]] = true - result = append(result, arr[v]) - } - } - return result -} - -// NewInclude creates a new Include with a list of file globs to include. -// Configuration files are parsed greedily (e.g. as soon as this function runs). -// Any error encountered while parsing nested configuration files will be -// returned. -func NewInclude(directives []string, hasEquals bool, pos Position, comment string, system bool, depth uint8) (*Include, error) { - if depth > maxRecurseDepth { - return nil, ErrDepthExceeded - } - inc := &Include{ - Comment: comment, - directives: directives, - files: make(map[string]*Config), - position: pos, - leadingSpace: pos.Col - 1, - depth: depth, - hasEquals: hasEquals, - } - // no need for inc.mu.Lock() since nothing else can access this inc - matches := make([]string, 0) - for i := range directives { - var path string - if filepath.IsAbs(directives[i]) { - path = directives[i] - } else if system { - path = filepath.Join("/etc/ssh", directives[i]) - } else { - path = filepath.Join(homedir(), ".ssh", directives[i]) - } - theseMatches, err := filepath.Glob(path) - if err != nil { - return nil, err - } - matches = append(matches, theseMatches...) - } - matches = removeDups(matches) - inc.matches = matches - for i := range matches { - config, err := parseWithDepth(matches[i], depth) - if err != nil { - return nil, err - } - inc.files[matches[i]] = config - } - return inc, nil -} - -// Pos returns the position of the Include directive in the larger file. -func (i *Include) Pos() Position { - return i.position -} - -// Get finds the first value in the Include statement matching the alias and the -// given key. -func (inc *Include) Get(alias, key string) string { - inc.mu.Lock() - defer inc.mu.Unlock() - // TODO: we search files in any order which is not correct - for i := range inc.matches { - cfg := inc.files[inc.matches[i]] - if cfg == nil { - panic("nil cfg") - } - val, err := cfg.Get(alias, key) - if err == nil && val != "" { - return val - } - } - return "" -} - -// String prints out a string representation of this Include directive. Note -// included Config files are not printed as part of this representation. -func (inc *Include) String() string { - equals := " " - if inc.hasEquals { - equals = " = " - } - line := fmt.Sprintf("%sInclude%s%s", strings.Repeat(" ", int(inc.leadingSpace)), equals, strings.Join(inc.directives, " ")) - if inc.Comment != "" { - line += " #" + inc.Comment - } - return line -} - -var matchAll *Pattern - -func init() { - var err error - matchAll, err = NewPattern("*") - if err != nil { - panic(err) - } -} - -func newConfig() *Config { - return &Config{ - Hosts: []*Host{ - &Host{ - implicit: true, - Patterns: []*Pattern{matchAll}, - Nodes: make([]Node, 0), - }, - }, - depth: 0, - } -} diff --git a/vendor/github.com/kevinburke/ssh_config/lexer.go b/vendor/github.com/kevinburke/ssh_config/lexer.go deleted file mode 100644 index 11680b4c..00000000 --- a/vendor/github.com/kevinburke/ssh_config/lexer.go +++ /dev/null @@ -1,240 +0,0 @@ -package ssh_config - -import ( - "bytes" -) - -// Define state functions -type sshLexStateFn func() sshLexStateFn - -type sshLexer struct { - inputIdx int - input []rune // Textual source - - buffer []rune // Runes composing the current token - tokens chan token - line int - col int - endbufferLine int - endbufferCol int -} - -func (s *sshLexer) lexComment(previousState sshLexStateFn) sshLexStateFn { - return func() sshLexStateFn { - growingString := "" - for next := s.peek(); next != '\n' && next != eof; next = s.peek() { - if next == '\r' && s.follow("\r\n") { - break - } - growingString += string(next) - s.next() - } - s.emitWithValue(tokenComment, growingString) - s.skip() - return previousState - } -} - -// lex the space after an equals sign in a function -func (s *sshLexer) lexRspace() sshLexStateFn { - for { - next := s.peek() - if !isSpace(next) { - break - } - s.skip() - } - return s.lexRvalue -} - -func (s *sshLexer) lexEquals() sshLexStateFn { - for { - next := s.peek() - if next == '=' { - s.emit(tokenEquals) - s.skip() - return s.lexRspace - } - // TODO error handling here; newline eof etc. - if !isSpace(next) { - break - } - s.skip() - } - return s.lexRvalue -} - -func (s *sshLexer) lexKey() sshLexStateFn { - growingString := "" - - for r := s.peek(); isKeyChar(r); r = s.peek() { - // simplified a lot here - if isSpace(r) || r == '=' { - s.emitWithValue(tokenKey, growingString) - s.skip() - return s.lexEquals - } - growingString += string(r) - s.next() - } - s.emitWithValue(tokenKey, growingString) - return s.lexEquals -} - -func (s *sshLexer) lexRvalue() sshLexStateFn { - growingString := "" - for { - next := s.peek() - switch next { - case '\r': - if s.follow("\r\n") { - s.emitWithValue(tokenString, growingString) - s.skip() - return s.lexVoid - } - case '\n': - s.emitWithValue(tokenString, growingString) - s.skip() - return s.lexVoid - case '#': - s.emitWithValue(tokenString, growingString) - s.skip() - return s.lexComment(s.lexVoid) - case eof: - s.next() - } - if next == eof { - break - } - growingString += string(next) - s.next() - } - s.emit(tokenEOF) - return nil -} - -func (s *sshLexer) read() rune { - r := s.peek() - if r == '\n' { - s.endbufferLine++ - s.endbufferCol = 1 - } else { - s.endbufferCol++ - } - s.inputIdx++ - return r -} - -func (s *sshLexer) next() rune { - r := s.read() - - if r != eof { - s.buffer = append(s.buffer, r) - } - return r -} - -func (s *sshLexer) lexVoid() sshLexStateFn { - for { - next := s.peek() - switch next { - case '#': - s.skip() - return s.lexComment(s.lexVoid) - case '\r': - fallthrough - case '\n': - s.emit(tokenEmptyLine) - s.skip() - continue - } - - if isSpace(next) { - s.skip() - } - - if isKeyStartChar(next) { - return s.lexKey - } - - // removed IsKeyStartChar and lexKey. probably will need to readd - - if next == eof { - s.next() - break - } - } - - s.emit(tokenEOF) - return nil -} - -func (s *sshLexer) ignore() { - s.buffer = make([]rune, 0) - s.line = s.endbufferLine - s.col = s.endbufferCol -} - -func (s *sshLexer) skip() { - s.next() - s.ignore() -} - -func (s *sshLexer) emit(t tokenType) { - s.emitWithValue(t, string(s.buffer)) -} - -func (s *sshLexer) emitWithValue(t tokenType, value string) { - tok := token{ - Position: Position{s.line, s.col}, - typ: t, - val: value, - } - s.tokens <- tok - s.ignore() -} - -func (s *sshLexer) peek() rune { - if s.inputIdx >= len(s.input) { - return eof - } - - r := s.input[s.inputIdx] - return r -} - -func (s *sshLexer) follow(next string) bool { - inputIdx := s.inputIdx - for _, expectedRune := range next { - if inputIdx >= len(s.input) { - return false - } - r := s.input[inputIdx] - inputIdx++ - if expectedRune != r { - return false - } - } - return true -} - -func (s *sshLexer) run() { - for state := s.lexVoid; state != nil; { - state = state() - } - close(s.tokens) -} - -func lexSSH(input []byte) chan token { - runes := bytes.Runes(input) - l := &sshLexer{ - input: runes, - tokens: make(chan token), - line: 1, - col: 1, - endbufferLine: 1, - endbufferCol: 1, - } - go l.run() - return l.tokens -} diff --git a/vendor/github.com/kevinburke/ssh_config/parser.go b/vendor/github.com/kevinburke/ssh_config/parser.go deleted file mode 100644 index 36c42055..00000000 --- a/vendor/github.com/kevinburke/ssh_config/parser.go +++ /dev/null @@ -1,191 +0,0 @@ -package ssh_config - -import ( - "fmt" - "strings" -) - -type sshParser struct { - flow chan token - config *Config - tokensBuffer []token - currentTable []string - seenTableKeys []string - // /etc/ssh parser or local parser - used to find the default for relative - // filepaths in the Include directive - system bool - depth uint8 -} - -type sshParserStateFn func() sshParserStateFn - -// Formats and panics an error message based on a token -func (p *sshParser) raiseErrorf(tok *token, msg string, args ...interface{}) { - // TODO this format is ugly - panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...)) -} - -func (p *sshParser) raiseError(tok *token, err error) { - if err == ErrDepthExceeded { - panic(err) - } - // TODO this format is ugly - panic(tok.Position.String() + ": " + err.Error()) -} - -func (p *sshParser) run() { - for state := p.parseStart; state != nil; { - state = state() - } -} - -func (p *sshParser) peek() *token { - if len(p.tokensBuffer) != 0 { - return &(p.tokensBuffer[0]) - } - - tok, ok := <-p.flow - if !ok { - return nil - } - p.tokensBuffer = append(p.tokensBuffer, tok) - return &tok -} - -func (p *sshParser) getToken() *token { - if len(p.tokensBuffer) != 0 { - tok := p.tokensBuffer[0] - p.tokensBuffer = p.tokensBuffer[1:] - return &tok - } - tok, ok := <-p.flow - if !ok { - return nil - } - return &tok -} - -func (p *sshParser) parseStart() sshParserStateFn { - tok := p.peek() - - // end of stream, parsing is finished - if tok == nil { - return nil - } - - switch tok.typ { - case tokenComment, tokenEmptyLine: - return p.parseComment - case tokenKey: - return p.parseKV - case tokenEOF: - return nil - default: - p.raiseErrorf(tok, fmt.Sprintf("unexpected token %q\n", tok)) - } - return nil -} - -func (p *sshParser) parseKV() sshParserStateFn { - key := p.getToken() - hasEquals := false - val := p.getToken() - if val.typ == tokenEquals { - hasEquals = true - val = p.getToken() - } - comment := "" - tok := p.peek() - if tok == nil { - tok = &token{typ: tokenEOF} - } - if tok.typ == tokenComment && tok.Position.Line == val.Position.Line { - tok = p.getToken() - comment = tok.val - } - if strings.ToLower(key.val) == "match" { - // https://github.com/kevinburke/ssh_config/issues/6 - p.raiseErrorf(val, "ssh_config: Match directive parsing is unsupported") - return nil - } - if strings.ToLower(key.val) == "host" { - strPatterns := strings.Split(val.val, " ") - patterns := make([]*Pattern, 0) - for i := range strPatterns { - if strPatterns[i] == "" { - continue - } - pat, err := NewPattern(strPatterns[i]) - if err != nil { - p.raiseErrorf(val, "Invalid host pattern: %v", err) - return nil - } - patterns = append(patterns, pat) - } - p.config.Hosts = append(p.config.Hosts, &Host{ - Patterns: patterns, - Nodes: make([]Node, 0), - EOLComment: comment, - hasEquals: hasEquals, - }) - return p.parseStart - } - lastHost := p.config.Hosts[len(p.config.Hosts)-1] - if strings.ToLower(key.val) == "include" { - inc, err := NewInclude(strings.Split(val.val, " "), hasEquals, key.Position, comment, p.system, p.depth+1) - if err == ErrDepthExceeded { - p.raiseError(val, err) - return nil - } - if err != nil { - p.raiseErrorf(val, "Error parsing Include directive: %v", err) - return nil - } - lastHost.Nodes = append(lastHost.Nodes, inc) - return p.parseStart - } - kv := &KV{ - Key: key.val, - Value: val.val, - Comment: comment, - hasEquals: hasEquals, - leadingSpace: key.Position.Col - 1, - position: key.Position, - } - lastHost.Nodes = append(lastHost.Nodes, kv) - return p.parseStart -} - -func (p *sshParser) parseComment() sshParserStateFn { - comment := p.getToken() - lastHost := p.config.Hosts[len(p.config.Hosts)-1] - lastHost.Nodes = append(lastHost.Nodes, &Empty{ - Comment: comment.val, - // account for the "#" as well - leadingSpace: comment.Position.Col - 2, - position: comment.Position, - }) - return p.parseStart -} - -func parseSSH(flow chan token, system bool, depth uint8) *Config { - // Ensure we consume tokens to completion even if parser exits early - defer func() { - for range flow { - } - }() - - result := newConfig() - result.position = Position{1, 1} - parser := &sshParser{ - flow: flow, - config: result, - tokensBuffer: make([]token, 0), - currentTable: make([]string, 0), - seenTableKeys: make([]string, 0), - system: system, - depth: depth, - } - parser.run() - return result -} diff --git a/vendor/github.com/kevinburke/ssh_config/position.go b/vendor/github.com/kevinburke/ssh_config/position.go deleted file mode 100644 index e0b5e3fb..00000000 --- a/vendor/github.com/kevinburke/ssh_config/position.go +++ /dev/null @@ -1,25 +0,0 @@ -package ssh_config - -import "fmt" - -// Position of a document element within a SSH document. -// -// Line and Col are both 1-indexed positions for the element's line number and -// column number, respectively. Values of zero or less will cause Invalid(), -// to return true. -type Position struct { - Line int // line within the document - Col int // column within the line -} - -// String representation of the position. -// Displays 1-indexed line and column numbers. -func (p Position) String() string { - return fmt.Sprintf("(%d, %d)", p.Line, p.Col) -} - -// Invalid returns whether or not the position is valid (i.e. with negative or -// null values) -func (p Position) Invalid() bool { - return p.Line <= 0 || p.Col <= 0 -} diff --git a/vendor/github.com/kevinburke/ssh_config/token.go b/vendor/github.com/kevinburke/ssh_config/token.go deleted file mode 100644 index a0ecbb2b..00000000 --- a/vendor/github.com/kevinburke/ssh_config/token.go +++ /dev/null @@ -1,49 +0,0 @@ -package ssh_config - -import "fmt" - -type token struct { - Position - typ tokenType - val string -} - -func (t token) String() string { - switch t.typ { - case tokenEOF: - return "EOF" - } - return fmt.Sprintf("%q", t.val) -} - -type tokenType int - -const ( - eof = -(iota + 1) -) - -const ( - tokenError tokenType = iota - tokenEOF - tokenEmptyLine - tokenComment - tokenKey - tokenEquals - tokenString -) - -func isSpace(r rune) bool { - return r == ' ' || r == '\t' -} - -func isKeyStartChar(r rune) bool { - return !(isSpace(r) || r == '\r' || r == '\n' || r == eof) -} - -// I'm not sure that this is correct -func isKeyChar(r rune) bool { - // Keys start with the first character that isn't whitespace or [ and end - // with the last non-whitespace character before the equals sign. Keys - // cannot contain a # character." - return !(r == '\r' || r == '\n' || r == eof || r == '=') -} diff --git a/vendor/github.com/kevinburke/ssh_config/validators.go b/vendor/github.com/kevinburke/ssh_config/validators.go deleted file mode 100644 index 29fab6a9..00000000 --- a/vendor/github.com/kevinburke/ssh_config/validators.go +++ /dev/null @@ -1,162 +0,0 @@ -package ssh_config - -import ( - "fmt" - "strconv" - "strings" -) - -// Default returns the default value for the given keyword, for example "22" if -// the keyword is "Port". Default returns the empty string if the keyword has no -// default, or if the keyword is unknown. Keyword matching is case-insensitive. -// -// Default values are provided by OpenSSH_7.4p1 on a Mac. -func Default(keyword string) string { - return defaults[strings.ToLower(keyword)] -} - -// Arguments where the value must be "yes" or "no" and *only* yes or no. -var yesnos = map[string]bool{ - strings.ToLower("BatchMode"): true, - strings.ToLower("CanonicalizeFallbackLocal"): true, - strings.ToLower("ChallengeResponseAuthentication"): true, - strings.ToLower("CheckHostIP"): true, - strings.ToLower("ClearAllForwardings"): true, - strings.ToLower("Compression"): true, - strings.ToLower("EnableSSHKeysign"): true, - strings.ToLower("ExitOnForwardFailure"): true, - strings.ToLower("ForwardAgent"): true, - strings.ToLower("ForwardX11"): true, - strings.ToLower("ForwardX11Trusted"): true, - strings.ToLower("GatewayPorts"): true, - strings.ToLower("GSSAPIAuthentication"): true, - strings.ToLower("GSSAPIDelegateCredentials"): true, - strings.ToLower("HostbasedAuthentication"): true, - strings.ToLower("IdentitiesOnly"): true, - strings.ToLower("KbdInteractiveAuthentication"): true, - strings.ToLower("NoHostAuthenticationForLocalhost"): true, - strings.ToLower("PasswordAuthentication"): true, - strings.ToLower("PermitLocalCommand"): true, - strings.ToLower("PubkeyAuthentication"): true, - strings.ToLower("RhostsRSAAuthentication"): true, - strings.ToLower("RSAAuthentication"): true, - strings.ToLower("StreamLocalBindUnlink"): true, - strings.ToLower("TCPKeepAlive"): true, - strings.ToLower("UseKeychain"): true, - strings.ToLower("UsePrivilegedPort"): true, - strings.ToLower("VisualHostKey"): true, -} - -var uints = map[string]bool{ - strings.ToLower("CanonicalizeMaxDots"): true, - strings.ToLower("CompressionLevel"): true, // 1 to 9 - strings.ToLower("ConnectionAttempts"): true, - strings.ToLower("ConnectTimeout"): true, - strings.ToLower("NumberOfPasswordPrompts"): true, - strings.ToLower("Port"): true, - strings.ToLower("ServerAliveCountMax"): true, - strings.ToLower("ServerAliveInterval"): true, -} - -func mustBeYesOrNo(lkey string) bool { - return yesnos[lkey] -} - -func mustBeUint(lkey string) bool { - return uints[lkey] -} - -func validate(key, val string) error { - lkey := strings.ToLower(key) - if mustBeYesOrNo(lkey) && (val != "yes" && val != "no") { - return fmt.Errorf("ssh_config: value for key %q must be 'yes' or 'no', got %q", key, val) - } - if mustBeUint(lkey) { - _, err := strconv.ParseUint(val, 10, 64) - if err != nil { - return fmt.Errorf("ssh_config: %v", err) - } - } - return nil -} - -var defaults = map[string]string{ - strings.ToLower("AddKeysToAgent"): "no", - strings.ToLower("AddressFamily"): "any", - strings.ToLower("BatchMode"): "no", - strings.ToLower("CanonicalizeFallbackLocal"): "yes", - strings.ToLower("CanonicalizeHostname"): "no", - strings.ToLower("CanonicalizeMaxDots"): "1", - strings.ToLower("ChallengeResponseAuthentication"): "yes", - strings.ToLower("CheckHostIP"): "yes", - // TODO is this still the correct cipher - strings.ToLower("Cipher"): "3des", - strings.ToLower("Ciphers"): "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc", - strings.ToLower("ClearAllForwardings"): "no", - strings.ToLower("Compression"): "no", - strings.ToLower("CompressionLevel"): "6", - strings.ToLower("ConnectionAttempts"): "1", - strings.ToLower("ControlMaster"): "no", - strings.ToLower("EnableSSHKeysign"): "no", - strings.ToLower("EscapeChar"): "~", - strings.ToLower("ExitOnForwardFailure"): "no", - strings.ToLower("FingerprintHash"): "sha256", - strings.ToLower("ForwardAgent"): "no", - strings.ToLower("ForwardX11"): "no", - strings.ToLower("ForwardX11Timeout"): "20m", - strings.ToLower("ForwardX11Trusted"): "no", - strings.ToLower("GatewayPorts"): "no", - strings.ToLower("GlobalKnownHostsFile"): "/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2", - strings.ToLower("GSSAPIAuthentication"): "no", - strings.ToLower("GSSAPIDelegateCredentials"): "no", - strings.ToLower("HashKnownHosts"): "no", - strings.ToLower("HostbasedAuthentication"): "no", - - strings.ToLower("HostbasedKeyTypes"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa", - strings.ToLower("HostKeyAlgorithms"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa", - // HostName has a dynamic default (the value passed at the command line). - - strings.ToLower("IdentitiesOnly"): "no", - strings.ToLower("IdentityFile"): "~/.ssh/identity", - - // IPQoS has a dynamic default based on interactive or non-interactive - // sessions. - - strings.ToLower("KbdInteractiveAuthentication"): "yes", - - strings.ToLower("KexAlgorithms"): "curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1", - strings.ToLower("LogLevel"): "INFO", - strings.ToLower("MACs"): "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1", - - strings.ToLower("NoHostAuthenticationForLocalhost"): "no", - strings.ToLower("NumberOfPasswordPrompts"): "3", - strings.ToLower("PasswordAuthentication"): "yes", - strings.ToLower("PermitLocalCommand"): "no", - strings.ToLower("Port"): "22", - - strings.ToLower("PreferredAuthentications"): "gssapi-with-mic,hostbased,publickey,keyboard-interactive,password", - strings.ToLower("Protocol"): "2", - strings.ToLower("ProxyUseFdpass"): "no", - strings.ToLower("PubkeyAcceptedKeyTypes"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa", - strings.ToLower("PubkeyAuthentication"): "yes", - strings.ToLower("RekeyLimit"): "default none", - strings.ToLower("RhostsRSAAuthentication"): "no", - strings.ToLower("RSAAuthentication"): "yes", - - strings.ToLower("ServerAliveCountMax"): "3", - strings.ToLower("ServerAliveInterval"): "0", - strings.ToLower("StreamLocalBindMask"): "0177", - strings.ToLower("StreamLocalBindUnlink"): "no", - strings.ToLower("StrictHostKeyChecking"): "ask", - strings.ToLower("TCPKeepAlive"): "yes", - strings.ToLower("Tunnel"): "no", - strings.ToLower("TunnelDevice"): "any:any", - strings.ToLower("UpdateHostKeys"): "no", - strings.ToLower("UseKeychain"): "no", - strings.ToLower("UsePrivilegedPort"): "no", - - strings.ToLower("UserKnownHostsFile"): "~/.ssh/known_hosts ~/.ssh/known_hosts2", - strings.ToLower("VerifyHostKeyDNS"): "no", - strings.ToLower("VisualHostKey"): "no", - strings.ToLower("XAuthLocation"): "/usr/X11R6/bin/xauth", -} diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE deleted file mode 100644 index f9c841a5..00000000 --- a/vendor/github.com/mitchellh/go-homedir/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-homedir/README.md b/vendor/github.com/mitchellh/go-homedir/README.md deleted file mode 100644 index d70706d5..00000000 --- a/vendor/github.com/mitchellh/go-homedir/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# go-homedir - -This is a Go library for detecting the user's home directory without -the use of cgo, so the library can be used in cross-compilation environments. - -Usage is incredibly simple, just call `homedir.Dir()` to get the home directory -for a user, and `homedir.Expand()` to expand the `~` in a path to the home -directory. - -**Why not just use `os/user`?** The built-in `os/user` package requires -cgo on Darwin systems. This means that any Go code that uses that package -cannot cross compile. But 99% of the time the use for `os/user` is just to -retrieve the home directory, which we can do for the current user without -cgo. This library does that, enabling cross-compilation. diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go deleted file mode 100644 index 25378537..00000000 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ /dev/null @@ -1,167 +0,0 @@ -package homedir - -import ( - "bytes" - "errors" - "os" - "os/exec" - "path/filepath" - "runtime" - "strconv" - "strings" - "sync" -) - -// DisableCache will disable caching of the home directory. Caching is enabled -// by default. -var DisableCache bool - -var homedirCache string -var cacheLock sync.RWMutex - -// Dir returns the home directory for the executing user. -// -// This uses an OS-specific method for discovering the home directory. -// An error is returned if a home directory cannot be detected. -func Dir() (string, error) { - if !DisableCache { - cacheLock.RLock() - cached := homedirCache - cacheLock.RUnlock() - if cached != "" { - return cached, nil - } - } - - cacheLock.Lock() - defer cacheLock.Unlock() - - var result string - var err error - if runtime.GOOS == "windows" { - result, err = dirWindows() - } else { - // Unix-like system, so just assume Unix - result, err = dirUnix() - } - - if err != nil { - return "", err - } - homedirCache = result - return result, nil -} - -// Expand expands the path to include the home directory if the path -// is prefixed with `~`. If it isn't prefixed with `~`, the path is -// returned as-is. -func Expand(path string) (string, error) { - if len(path) == 0 { - return path, nil - } - - if path[0] != '~' { - return path, nil - } - - if len(path) > 1 && path[1] != '/' && path[1] != '\\' { - return "", errors.New("cannot expand user-specific home dir") - } - - dir, err := Dir() - if err != nil { - return "", err - } - - return filepath.Join(dir, path[1:]), nil -} - -// Reset clears the cache, forcing the next call to Dir to re-detect -// the home directory. This generally never has to be called, but can be -// useful in tests if you're modifying the home directory via the HOME -// env var or something. -func Reset() { - cacheLock.Lock() - defer cacheLock.Unlock() - homedirCache = "" -} - -func dirUnix() (string, error) { - homeEnv := "HOME" - if runtime.GOOS == "plan9" { - // On plan9, env vars are lowercase. - homeEnv = "home" - } - - // First prefer the HOME environmental variable - if home := os.Getenv(homeEnv); home != "" { - return home, nil - } - - var stdout bytes.Buffer - - // If that fails, try OS specific commands - if runtime.GOOS == "darwin" { - cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) - cmd.Stdout = &stdout - if err := cmd.Run(); err == nil { - result := strings.TrimSpace(stdout.String()) - if result != "" { - return result, nil - } - } - } else { - cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - // If the error is ErrNotFound, we ignore it. Otherwise, return it. - if err != exec.ErrNotFound { - return "", err - } - } else { - if passwd := strings.TrimSpace(stdout.String()); passwd != "" { - // username:password:uid:gid:gecos:home:shell - passwdParts := strings.SplitN(passwd, ":", 7) - if len(passwdParts) > 5 { - return passwdParts[5], nil - } - } - } - } - - // If all else fails, try the shell - stdout.Reset() - cmd := exec.Command("sh", "-c", "cd && pwd") - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - return "", err - } - - result := strings.TrimSpace(stdout.String()) - if result == "" { - return "", errors.New("blank output when reading home directory") - } - - return result, nil -} - -func dirWindows() (string, error) { - // First prefer the HOME environmental variable - if home := os.Getenv("HOME"); home != "" { - return home, nil - } - - // Prefer standard environment variable USERPROFILE - if home := os.Getenv("USERPROFILE"); home != "" { - return home, nil - } - - drive := os.Getenv("HOMEDRIVE") - path := os.Getenv("HOMEPATH") - home := drive + path - if drive == "" || path == "" { - return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") - } - - return home, nil -} diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go index cb25b437..4f7b4248 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/diff.go @@ -34,6 +34,8 @@ const ( DiffInsert Operation = 1 // DiffEqual item represents an equal diff. DiffEqual Operation = 0 + //IndexSeparator is used to seperate the array indexes in an index string + IndexSeparator = "," ) // Diff represents one diff operation @@ -120,7 +122,7 @@ func (dmp *DiffMatchPatch) diffMainRunes(text1, text2 []rune, checklines bool, d // Restore the prefix and suffix. if len(commonprefix) != 0 { - diffs = append([]Diff{Diff{DiffEqual, string(commonprefix)}}, diffs...) + diffs = append([]Diff{{DiffEqual, string(commonprefix)}}, diffs...) } if len(commonsuffix) != 0 { diffs = append(diffs, Diff{DiffEqual, string(commonsuffix)}) @@ -165,8 +167,8 @@ func (dmp *DiffMatchPatch) diffCompute(text1, text2 []rune, checklines bool, dea // Single character string. // After the previous speedup, the character can't be an equality. return []Diff{ - Diff{DiffDelete, string(text1)}, - Diff{DiffInsert, string(text2)}, + {DiffDelete, string(text1)}, + {DiffInsert, string(text2)}, } // Check to see if the problem can be split in two. } else if hm := dmp.diffHalfMatch(text1, text2); hm != nil { @@ -193,7 +195,7 @@ func (dmp *DiffMatchPatch) diffCompute(text1, text2 []rune, checklines bool, dea // diffLineMode does a quick line-level diff on both []runes, then rediff the parts for greater accuracy. This speedup can produce non-minimal diffs. func (dmp *DiffMatchPatch) diffLineMode(text1, text2 []rune, deadline time.Time) []Diff { // Scan the text on a line-by-line basis first. - text1, text2, linearray := dmp.diffLinesToRunes(text1, text2) + text1, text2, linearray := dmp.DiffLinesToRunes(string(text1), string(text2)) diffs := dmp.diffMainRunes(text1, text2, false, deadline) @@ -368,8 +370,8 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time) } // Diff took too long and hit the deadline or number of diffs equals number of characters, no commonality at all. return []Diff{ - Diff{DiffDelete, string(runes1)}, - Diff{DiffInsert, string(runes2)}, + {DiffDelete, string(runes1)}, + {DiffInsert, string(runes2)}, } } @@ -390,66 +392,28 @@ func (dmp *DiffMatchPatch) diffBisectSplit(runes1, runes2 []rune, x, y int, // DiffLinesToChars splits two texts into a list of strings, and educes the texts to a string of hashes where each Unicode character represents one line. // It's slightly faster to call DiffLinesToRunes first, followed by DiffMainRunes. func (dmp *DiffMatchPatch) DiffLinesToChars(text1, text2 string) (string, string, []string) { - chars1, chars2, lineArray := dmp.DiffLinesToRunes(text1, text2) - return string(chars1), string(chars2), lineArray -} - -// DiffLinesToRunes splits two texts into a list of runes. Each rune represents one line. -func (dmp *DiffMatchPatch) DiffLinesToRunes(text1, text2 string) ([]rune, []rune, []string) { - // '\x00' is a valid character, but various debuggers don't like it. So we'll insert a junk entry to avoid generating a null character. - lineArray := []string{""} // e.g. lineArray[4] == 'Hello\n' - lineHash := map[string]int{} // e.g. lineHash['Hello\n'] == 4 - - chars1 := dmp.diffLinesToRunesMunge(text1, &lineArray, lineHash) - chars2 := dmp.diffLinesToRunesMunge(text2, &lineArray, lineHash) - + chars1, chars2, lineArray := dmp.diffLinesToStrings(text1, text2) return chars1, chars2, lineArray } -func (dmp *DiffMatchPatch) diffLinesToRunes(text1, text2 []rune) ([]rune, []rune, []string) { - return dmp.DiffLinesToRunes(string(text1), string(text2)) -} - -// diffLinesToRunesMunge splits a text into an array of strings, and reduces the texts to a []rune where each Unicode character represents one line. -// We use strings instead of []runes as input mainly because you can't use []rune as a map key. -func (dmp *DiffMatchPatch) diffLinesToRunesMunge(text string, lineArray *[]string, lineHash map[string]int) []rune { - // Walk the text, pulling out a substring for each line. text.split('\n') would would temporarily double our memory footprint. Modifying text would create many large strings to garbage collect. - lineStart := 0 - lineEnd := -1 - runes := []rune{} - - for lineEnd < len(text)-1 { - lineEnd = indexOf(text, "\n", lineStart) - - if lineEnd == -1 { - lineEnd = len(text) - 1 - } - - line := text[lineStart : lineEnd+1] - lineStart = lineEnd + 1 - lineValue, ok := lineHash[line] - - if ok { - runes = append(runes, rune(lineValue)) - } else { - *lineArray = append(*lineArray, line) - lineHash[line] = len(*lineArray) - 1 - runes = append(runes, rune(len(*lineArray)-1)) - } - } - - return runes +// DiffLinesToRunes splits two texts into a list of runes. +func (dmp *DiffMatchPatch) DiffLinesToRunes(text1, text2 string) ([]rune, []rune, []string) { + chars1, chars2, lineArray := dmp.diffLinesToStrings(text1, text2) + return []rune(chars1), []rune(chars2), lineArray } // DiffCharsToLines rehydrates the text in a diff from a string of line hashes to real lines of text. func (dmp *DiffMatchPatch) DiffCharsToLines(diffs []Diff, lineArray []string) []Diff { hydrated := make([]Diff, 0, len(diffs)) for _, aDiff := range diffs { - chars := aDiff.Text + chars := strings.Split(aDiff.Text, IndexSeparator) text := make([]string, len(chars)) for i, r := range chars { - text[i] = lineArray[r] + i1, err := strconv.Atoi(r) + if err == nil { + text[i] = lineArray[i1] + } } aDiff.Text = strings.Join(text, "") @@ -670,16 +634,16 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff { // An insertion or deletion. if diffs[pointer].Type == DiffInsert { - lengthInsertions2 += len(diffs[pointer].Text) + lengthInsertions2 += utf8.RuneCountInString(diffs[pointer].Text) } else { - lengthDeletions2 += len(diffs[pointer].Text) + lengthDeletions2 += utf8.RuneCountInString(diffs[pointer].Text) } // Eliminate an equality that is smaller or equal to the edits on both sides of it. difference1 := int(math.Max(float64(lengthInsertions1), float64(lengthDeletions1))) difference2 := int(math.Max(float64(lengthInsertions2), float64(lengthDeletions2))) - if len(lastequality) > 0 && - (len(lastequality) <= difference1) && - (len(lastequality) <= difference2) { + if utf8.RuneCountInString(lastequality) > 0 && + (utf8.RuneCountInString(lastequality) <= difference1) && + (utf8.RuneCountInString(lastequality) <= difference2) { // Duplicate record. insPoint := equalities[len(equalities)-1] diffs = splice(diffs, insPoint, 0, Diff{DiffDelete, lastequality}) @@ -728,8 +692,8 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff { overlapLength1 := dmp.DiffCommonOverlap(deletion, insertion) overlapLength2 := dmp.DiffCommonOverlap(insertion, deletion) if overlapLength1 >= overlapLength2 { - if float64(overlapLength1) >= float64(len(deletion))/2 || - float64(overlapLength1) >= float64(len(insertion))/2 { + if float64(overlapLength1) >= float64(utf8.RuneCountInString(deletion))/2 || + float64(overlapLength1) >= float64(utf8.RuneCountInString(insertion))/2 { // Overlap found. Insert an equality and trim the surrounding edits. diffs = splice(diffs, pointer, 0, Diff{DiffEqual, insertion[:overlapLength1]}) @@ -739,8 +703,8 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff { pointer++ } } else { - if float64(overlapLength2) >= float64(len(deletion))/2 || - float64(overlapLength2) >= float64(len(insertion))/2 { + if float64(overlapLength2) >= float64(utf8.RuneCountInString(deletion))/2 || + float64(overlapLength2) >= float64(utf8.RuneCountInString(insertion))/2 { // Reverse overlap found. Insert an equality and swap and trim the surrounding edits. overlap := Diff{DiffEqual, deletion[:overlapLength2]} diffs = splice(diffs, pointer, 0, overlap) @@ -1029,7 +993,7 @@ func (dmp *DiffMatchPatch) DiffCleanupMerge(diffs []Diff) []Diff { if x > 0 && diffs[x-1].Type == DiffEqual { diffs[x-1].Text += string(textInsert[:commonlength]) } else { - diffs = append([]Diff{Diff{DiffEqual, string(textInsert[:commonlength])}}, diffs...) + diffs = append([]Diff{{DiffEqual, string(textInsert[:commonlength])}}, diffs...) pointer++ } textInsert = textInsert[commonlength:] @@ -1343,3 +1307,46 @@ func (dmp *DiffMatchPatch) DiffFromDelta(text1 string, delta string) (diffs []Di return diffs, nil } + +// diffLinesToStrings splits two texts into a list of strings. Each string represents one line. +func (dmp *DiffMatchPatch) diffLinesToStrings(text1, text2 string) (string, string, []string) { + // '\x00' is a valid character, but various debuggers don't like it. So we'll insert a junk entry to avoid generating a null character. + lineArray := []string{""} // e.g. lineArray[4] == 'Hello\n' + + lineHash := make(map[string]int) + //Each string has the index of lineArray which it points to + strIndexArray1 := dmp.diffLinesToStringsMunge(text1, &lineArray, lineHash) + strIndexArray2 := dmp.diffLinesToStringsMunge(text2, &lineArray, lineHash) + + return intArrayToString(strIndexArray1), intArrayToString(strIndexArray2), lineArray +} + +// diffLinesToStringsMunge splits a text into an array of strings, and reduces the texts to a []string. +func (dmp *DiffMatchPatch) diffLinesToStringsMunge(text string, lineArray *[]string, lineHash map[string]int) []uint32 { + // Walk the text, pulling out a substring for each line. text.split('\n') would would temporarily double our memory footprint. Modifying text would create many large strings to garbage collect. + lineStart := 0 + lineEnd := -1 + strs := []uint32{} + + for lineEnd < len(text)-1 { + lineEnd = indexOf(text, "\n", lineStart) + + if lineEnd == -1 { + lineEnd = len(text) - 1 + } + + line := text[lineStart : lineEnd+1] + lineStart = lineEnd + 1 + lineValue, ok := lineHash[line] + + if ok { + strs = append(strs, uint32(lineValue)) + } else { + *lineArray = append(*lineArray, line) + lineHash[line] = len(*lineArray) - 1 + strs = append(strs, uint32(len(*lineArray)-1)) + } + } + + return strs +} diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go index 223c43c4..0dbe3bdd 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/patch.go @@ -324,7 +324,7 @@ func (dmp *DiffMatchPatch) PatchAddPadding(patches []Patch) string { paddingLength := dmp.PatchMargin nullPadding := "" for x := 1; x <= paddingLength; x++ { - nullPadding += string(x) + nullPadding += string(rune(x)) } // Bump all the patches forward. diff --git a/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go b/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go index 265f29cc..44c43595 100644 --- a/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go +++ b/vendor/github.com/sergi/go-diff/diffmatchpatch/stringutil.go @@ -9,6 +9,7 @@ package diffmatchpatch import ( + "strconv" "strings" "unicode/utf8" ) @@ -86,3 +87,20 @@ func runesIndex(r1, r2 []rune) int { } return -1 } + +func intArrayToString(ns []uint32) string { + if len(ns) == 0 { + return "" + } + + indexSeparator := IndexSeparator[0] + + // Appr. 3 chars per num plus the comma. + b := []byte{} + for _, n := range ns { + b = strconv.AppendInt(b, int64(n), 10) + b = append(b, indexSeparator) + } + b = b[:len(b)-1] + return string(b) +} diff --git a/vendor/github.com/xanzy/ssh-agent/.gitignore b/vendor/github.com/xanzy/ssh-agent/.gitignore deleted file mode 100644 index daf913b1..00000000 --- a/vendor/github.com/xanzy/ssh-agent/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof diff --git a/vendor/github.com/xanzy/ssh-agent/LICENSE b/vendor/github.com/xanzy/ssh-agent/LICENSE deleted file mode 100644 index 8f71f43f..00000000 --- a/vendor/github.com/xanzy/ssh-agent/LICENSE +++ /dev/null @@ -1,202 +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 - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/vendor/github.com/xanzy/ssh-agent/README.md b/vendor/github.com/xanzy/ssh-agent/README.md deleted file mode 100644 index d93af40a..00000000 --- a/vendor/github.com/xanzy/ssh-agent/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# ssh-agent - -Create a new [agent.Agent](https://godoc.org/golang.org/x/crypto/ssh/agent#Agent) on any type of OS (so including Windows) from any [Go](https://golang.org) application. - -## Limitations - -When compiled for Windows, it will only support [Pageant](http://the.earth.li/~sgtatham/putty/0.66/htmldoc/Chapter9.html#pageant) as the SSH authentication agent. - -## Credits - -Big thanks to [Давид Мзареулян (David Mzareulyan)](https://github.com/davidmz) for creating the [go-pageant](https://github.com/davidmz/go-pageant) package! - -## Issues - -If you have an issue: report it on the [issue tracker](https://github.com/xanzy/ssh-agent/issues) - -## Author - -Sander van Harmelen () - -## License - -The files `pageant_windows.go` and `sshagent_windows.go` have their own license (see file headers). The rest of this package is 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 diff --git a/vendor/github.com/xanzy/ssh-agent/pageant_windows.go b/vendor/github.com/xanzy/ssh-agent/pageant_windows.go deleted file mode 100644 index 62956079..00000000 --- a/vendor/github.com/xanzy/ssh-agent/pageant_windows.go +++ /dev/null @@ -1,146 +0,0 @@ -// -// Copyright (c) 2014 David Mzareulyan -// -// 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. -// - -// +build windows - -package sshagent - -// see https://github.com/Yasushi/putty/blob/master/windows/winpgntc.c#L155 -// see https://github.com/paramiko/paramiko/blob/master/paramiko/win_pageant.py - -import ( - "encoding/binary" - "errors" - "fmt" - "sync" - "syscall" - "unsafe" -) - -// Maximum size of message can be sent to pageant -const MaxMessageLen = 8192 - -var ( - ErrPageantNotFound = errors.New("pageant process not found") - ErrSendMessage = errors.New("error sending message") - - ErrMessageTooLong = errors.New("message too long") - ErrInvalidMessageFormat = errors.New("invalid message format") - ErrResponseTooLong = errors.New("response too long") -) - -const ( - agentCopydataID = 0x804e50ba - wmCopydata = 74 -) - -type copyData struct { - dwData uintptr - cbData uint32 - lpData unsafe.Pointer -} - -var ( - lock sync.Mutex - - winFindWindow = winAPI("user32.dll", "FindWindowW") - winGetCurrentThreadID = winAPI("kernel32.dll", "GetCurrentThreadId") - winSendMessage = winAPI("user32.dll", "SendMessageW") -) - -func winAPI(dllName, funcName string) func(...uintptr) (uintptr, uintptr, error) { - proc := syscall.MustLoadDLL(dllName).MustFindProc(funcName) - return func(a ...uintptr) (uintptr, uintptr, error) { return proc.Call(a...) } -} - -// Available returns true if Pageant is running -func Available() bool { return pageantWindow() != 0 } - -// Query sends message msg to Pageant and returns response or error. -// 'msg' is raw agent request with length prefix -// Response is raw agent response with length prefix -func query(msg []byte) ([]byte, error) { - if len(msg) > MaxMessageLen { - return nil, ErrMessageTooLong - } - - msgLen := binary.BigEndian.Uint32(msg[:4]) - if len(msg) != int(msgLen)+4 { - return nil, ErrInvalidMessageFormat - } - - lock.Lock() - defer lock.Unlock() - - paWin := pageantWindow() - - if paWin == 0 { - return nil, ErrPageantNotFound - } - - thID, _, _ := winGetCurrentThreadID() - mapName := fmt.Sprintf("PageantRequest%08x", thID) - pMapName, _ := syscall.UTF16PtrFromString(mapName) - - mmap, err := syscall.CreateFileMapping(syscall.InvalidHandle, nil, syscall.PAGE_READWRITE, 0, MaxMessageLen+4, pMapName) - if err != nil { - return nil, err - } - defer syscall.CloseHandle(mmap) - - ptr, err := syscall.MapViewOfFile(mmap, syscall.FILE_MAP_WRITE, 0, 0, 0) - if err != nil { - return nil, err - } - defer syscall.UnmapViewOfFile(ptr) - - mmSlice := (*(*[MaxMessageLen]byte)(unsafe.Pointer(ptr)))[:] - - copy(mmSlice, msg) - - mapNameBytesZ := append([]byte(mapName), 0) - - cds := copyData{ - dwData: agentCopydataID, - cbData: uint32(len(mapNameBytesZ)), - lpData: unsafe.Pointer(&(mapNameBytesZ[0])), - } - - resp, _, _ := winSendMessage(paWin, wmCopydata, 0, uintptr(unsafe.Pointer(&cds))) - - if resp == 0 { - return nil, ErrSendMessage - } - - respLen := binary.BigEndian.Uint32(mmSlice[:4]) - if respLen > MaxMessageLen-4 { - return nil, ErrResponseTooLong - } - - respData := make([]byte, respLen+4) - copy(respData, mmSlice) - - return respData, nil -} - -func pageantWindow() uintptr { - nameP, _ := syscall.UTF16PtrFromString("Pageant") - h, _, _ := winFindWindow(uintptr(unsafe.Pointer(nameP)), uintptr(unsafe.Pointer(nameP))) - return h -} diff --git a/vendor/github.com/xanzy/ssh-agent/sshagent.go b/vendor/github.com/xanzy/ssh-agent/sshagent.go deleted file mode 100644 index 259fea2b..00000000 --- a/vendor/github.com/xanzy/ssh-agent/sshagent.go +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2015, Sander van Harmelen -// -// 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. -// - -// +build !windows - -package sshagent - -import ( - "errors" - "fmt" - "net" - "os" - - "golang.org/x/crypto/ssh/agent" -) - -// New returns a new agent.Agent that uses a unix socket -func New() (agent.Agent, net.Conn, error) { - if !Available() { - return nil, nil, errors.New("SSH agent requested but SSH_AUTH_SOCK not-specified") - } - - sshAuthSock := os.Getenv("SSH_AUTH_SOCK") - - conn, err := net.Dial("unix", sshAuthSock) - if err != nil { - return nil, nil, fmt.Errorf("Error connecting to SSH_AUTH_SOCK: %v", err) - } - - return agent.NewClient(conn), conn, nil -} - -// Available returns true is a auth socket is defined -func Available() bool { - return os.Getenv("SSH_AUTH_SOCK") != "" -} diff --git a/vendor/github.com/xanzy/ssh-agent/sshagent_windows.go b/vendor/github.com/xanzy/ssh-agent/sshagent_windows.go deleted file mode 100644 index c46710e8..00000000 --- a/vendor/github.com/xanzy/ssh-agent/sshagent_windows.go +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) 2014 David Mzareulyan -// -// 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. -// - -// +build windows - -package sshagent - -import ( - "errors" - "io" - "net" - "sync" - - "golang.org/x/crypto/ssh/agent" -) - -// New returns a new agent.Agent and the (custom) connection it uses -// to communicate with a running pagent.exe instance (see README.md) -func New() (agent.Agent, net.Conn, error) { - if !Available() { - return nil, nil, errors.New("SSH agent requested but Pageant not running") - } - - return agent.NewClient(&conn{}), nil, nil -} - -type conn struct { - sync.Mutex - buf []byte -} - -func (c *conn) Close() { - c.Lock() - defer c.Unlock() - c.buf = nil -} - -func (c *conn) Write(p []byte) (int, error) { - c.Lock() - defer c.Unlock() - - resp, err := query(p) - if err != nil { - return 0, err - } - - c.buf = append(c.buf, resp...) - - return len(p), nil -} - -func (c *conn) Read(p []byte) (int, error) { - c.Lock() - defer c.Unlock() - - if len(c.buf) == 0 { - return 0, io.EOF - } - - n := copy(p, c.buf) - c.buf = c.buf[n:] - - return n, nil -} diff --git a/vendor/golang.org/x/crypto/blowfish/block.go b/vendor/golang.org/x/crypto/blowfish/block.go deleted file mode 100644 index 9d80f195..00000000 --- a/vendor/golang.org/x/crypto/blowfish/block.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package blowfish - -// getNextWord returns the next big-endian uint32 value from the byte slice -// at the given position in a circular manner, updating the position. -func getNextWord(b []byte, pos *int) uint32 { - var w uint32 - j := *pos - for i := 0; i < 4; i++ { - w = w<<8 | uint32(b[j]) - j++ - if j >= len(b) { - j = 0 - } - } - *pos = j - return w -} - -// ExpandKey performs a key expansion on the given *Cipher. Specifically, it -// performs the Blowfish algorithm's key schedule which sets up the *Cipher's -// pi and substitution tables for calls to Encrypt. This is used, primarily, -// by the bcrypt package to reuse the Blowfish key schedule during its -// set up. It's unlikely that you need to use this directly. -func ExpandKey(key []byte, c *Cipher) { - j := 0 - for i := 0; i < 18; i++ { - // Using inlined getNextWord for performance. - var d uint32 - for k := 0; k < 4; k++ { - d = d<<8 | uint32(key[j]) - j++ - if j >= len(key) { - j = 0 - } - } - c.p[i] ^= d - } - - var l, r uint32 - for i := 0; i < 18; i += 2 { - l, r = encryptBlock(l, r, c) - c.p[i], c.p[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s0[i], c.s0[i+1] = l, r - } - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s1[i], c.s1[i+1] = l, r - } - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s2[i], c.s2[i+1] = l, r - } - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s3[i], c.s3[i+1] = l, r - } -} - -// This is similar to ExpandKey, but folds the salt during the key -// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero -// salt passed in, reusing ExpandKey turns out to be a place of inefficiency -// and specializing it here is useful. -func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) { - j := 0 - for i := 0; i < 18; i++ { - c.p[i] ^= getNextWord(key, &j) - } - - j = 0 - var l, r uint32 - for i := 0; i < 18; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.p[i], c.p[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s0[i], c.s0[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s1[i], c.s1[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s2[i], c.s2[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s3[i], c.s3[i+1] = l, r - } -} - -func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { - xl, xr := l, r - xl ^= c.p[0] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16] - xr ^= c.p[17] - return xr, xl -} - -func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { - xl, xr := l, r - xl ^= c.p[17] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1] - xr ^= c.p[0] - return xr, xl -} diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go deleted file mode 100644 index 213bf204..00000000 --- a/vendor/golang.org/x/crypto/blowfish/cipher.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. -// -// Blowfish is a legacy cipher and its short block size makes it vulnerable to -// birthday bound attacks (see https://sweet32.info). It should only be used -// where compatibility with legacy systems, not security, is the goal. -// -// Deprecated: any new system should use AES (from crypto/aes, if necessary in -// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from -// golang.org/x/crypto/chacha20poly1305). -package blowfish // import "golang.org/x/crypto/blowfish" - -// The code is a port of Bruce Schneier's C implementation. -// See https://www.schneier.com/blowfish.html. - -import "strconv" - -// The Blowfish block size in bytes. -const BlockSize = 8 - -// A Cipher is an instance of Blowfish encryption using a particular key. -type Cipher struct { - p [18]uint32 - s0, s1, s2, s3 [256]uint32 -} - -type KeySizeError int - -func (k KeySizeError) Error() string { - return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k)) -} - -// NewCipher creates and returns a Cipher. -// The key argument should be the Blowfish key, from 1 to 56 bytes. -func NewCipher(key []byte) (*Cipher, error) { - var result Cipher - if k := len(key); k < 1 || k > 56 { - return nil, KeySizeError(k) - } - initCipher(&result) - ExpandKey(key, &result) - return &result, nil -} - -// NewSaltedCipher creates a returns a Cipher that folds a salt into its key -// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is -// sufficient and desirable. For bcrypt compatibility, the key can be over 56 -// bytes. -func NewSaltedCipher(key, salt []byte) (*Cipher, error) { - if len(salt) == 0 { - return NewCipher(key) - } - var result Cipher - if k := len(key); k < 1 { - return nil, KeySizeError(k) - } - initCipher(&result) - expandKeyWithSalt(key, salt, &result) - return &result, nil -} - -// BlockSize returns the Blowfish block size, 8 bytes. -// It is necessary to satisfy the Block interface in the -// package "crypto/cipher". -func (c *Cipher) BlockSize() int { return BlockSize } - -// Encrypt encrypts the 8-byte buffer src using the key k -// and stores the result in dst. -// Note that for amounts of data larger than a block, -// it is not safe to just call Encrypt on successive blocks; -// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). -func (c *Cipher) Encrypt(dst, src []byte) { - l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - l, r = encryptBlock(l, r, c) - dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) - dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) -} - -// Decrypt decrypts the 8-byte buffer src using the key k -// and stores the result in dst. -func (c *Cipher) Decrypt(dst, src []byte) { - l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - l, r = decryptBlock(l, r, c) - dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) - dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) -} - -func initCipher(c *Cipher) { - copy(c.p[0:], p[0:]) - copy(c.s0[0:], s0[0:]) - copy(c.s1[0:], s1[0:]) - copy(c.s2[0:], s2[0:]) - copy(c.s3[0:], s3[0:]) -} diff --git a/vendor/golang.org/x/crypto/blowfish/const.go b/vendor/golang.org/x/crypto/blowfish/const.go deleted file mode 100644 index d0407759..00000000 --- a/vendor/golang.org/x/crypto/blowfish/const.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The startup permutation array and substitution boxes. -// They are the hexadecimal digits of PI; see: -// https://www.schneier.com/code/constants.txt. - -package blowfish - -var s0 = [256]uint32{ - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, - 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, - 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, - 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, - 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, - 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, - 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, - 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, - 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, - 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, - 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, - 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, - 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, - 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, - 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, - 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, - 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, - 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, - 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, - 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, - 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, - 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, -} - -var s1 = [256]uint32{ - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, - 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, - 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, - 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, - 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, - 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, - 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, - 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, - 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, - 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, - 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, - 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, - 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, - 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, - 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, - 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, - 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, - 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, - 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, - 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, - 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, - 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, -} - -var s2 = [256]uint32{ - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, - 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, - 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, - 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, - 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, - 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, - 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, - 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, - 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, - 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, - 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, - 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, - 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, - 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, - 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, - 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, - 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, - 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, - 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, - 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, - 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, - 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, -} - -var s3 = [256]uint32{ - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, - 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, - 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, - 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, - 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, - 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, - 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, - 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, - 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, - 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, - 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, - 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, - 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, - 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, - 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, - 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, - 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, - 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, - 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, - 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, - 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, - 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, -} - -var p = [18]uint32{ - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, - 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b, -} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go deleted file mode 100644 index 94c71ac1..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 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. - -//go:build go1.11 && gc && !purego -// +build go1.11,gc,!purego - -package chacha20 - -const bufSize = 256 - -//go:noescape -func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) - -func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { - xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) -} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s deleted file mode 100644 index 63cae9e6..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2018 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. - -//go:build go1.11 && gc && !purego -// +build go1.11,gc,!purego - -#include "textflag.h" - -#define NUM_ROUNDS 10 - -// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) -TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 - MOVD dst+0(FP), R1 - MOVD src+24(FP), R2 - MOVD src_len+32(FP), R3 - MOVD key+48(FP), R4 - MOVD nonce+56(FP), R6 - MOVD counter+64(FP), R7 - - MOVD $·constants(SB), R10 - MOVD $·incRotMatrix(SB), R11 - - MOVW (R7), R20 - - AND $~255, R3, R13 - ADD R2, R13, R12 // R12 for block end - AND $255, R3, R13 -loop: - MOVD $NUM_ROUNDS, R21 - VLD1 (R11), [V30.S4, V31.S4] - - // load contants - // VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4] - WORD $0x4D60E940 - - // load keys - // VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4] - WORD $0x4DFFE884 - // VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4] - WORD $0x4DFFE888 - SUB $32, R4 - - // load counter + nonce - // VLD1R (R7), [V12.S4] - WORD $0x4D40C8EC - - // VLD3R (R6), [V13.S4, V14.S4, V15.S4] - WORD $0x4D40E8CD - - // update counter - VADD V30.S4, V12.S4, V12.S4 - -chacha: - // V0..V3 += V4..V7 - // V12..V15 <<<= ((V12..V15 XOR V0..V3), 16) - VADD V0.S4, V4.S4, V0.S4 - VADD V1.S4, V5.S4, V1.S4 - VADD V2.S4, V6.S4, V2.S4 - VADD V3.S4, V7.S4, V3.S4 - VEOR V12.B16, V0.B16, V12.B16 - VEOR V13.B16, V1.B16, V13.B16 - VEOR V14.B16, V2.B16, V14.B16 - VEOR V15.B16, V3.B16, V15.B16 - VREV32 V12.H8, V12.H8 - VREV32 V13.H8, V13.H8 - VREV32 V14.H8, V14.H8 - VREV32 V15.H8, V15.H8 - // V8..V11 += V12..V15 - // V4..V7 <<<= ((V4..V7 XOR V8..V11), 12) - VADD V8.S4, V12.S4, V8.S4 - VADD V9.S4, V13.S4, V9.S4 - VADD V10.S4, V14.S4, V10.S4 - VADD V11.S4, V15.S4, V11.S4 - VEOR V8.B16, V4.B16, V16.B16 - VEOR V9.B16, V5.B16, V17.B16 - VEOR V10.B16, V6.B16, V18.B16 - VEOR V11.B16, V7.B16, V19.B16 - VSHL $12, V16.S4, V4.S4 - VSHL $12, V17.S4, V5.S4 - VSHL $12, V18.S4, V6.S4 - VSHL $12, V19.S4, V7.S4 - VSRI $20, V16.S4, V4.S4 - VSRI $20, V17.S4, V5.S4 - VSRI $20, V18.S4, V6.S4 - VSRI $20, V19.S4, V7.S4 - - // V0..V3 += V4..V7 - // V12..V15 <<<= ((V12..V15 XOR V0..V3), 8) - VADD V0.S4, V4.S4, V0.S4 - VADD V1.S4, V5.S4, V1.S4 - VADD V2.S4, V6.S4, V2.S4 - VADD V3.S4, V7.S4, V3.S4 - VEOR V12.B16, V0.B16, V12.B16 - VEOR V13.B16, V1.B16, V13.B16 - VEOR V14.B16, V2.B16, V14.B16 - VEOR V15.B16, V3.B16, V15.B16 - VTBL V31.B16, [V12.B16], V12.B16 - VTBL V31.B16, [V13.B16], V13.B16 - VTBL V31.B16, [V14.B16], V14.B16 - VTBL V31.B16, [V15.B16], V15.B16 - - // V8..V11 += V12..V15 - // V4..V7 <<<= ((V4..V7 XOR V8..V11), 7) - VADD V12.S4, V8.S4, V8.S4 - VADD V13.S4, V9.S4, V9.S4 - VADD V14.S4, V10.S4, V10.S4 - VADD V15.S4, V11.S4, V11.S4 - VEOR V8.B16, V4.B16, V16.B16 - VEOR V9.B16, V5.B16, V17.B16 - VEOR V10.B16, V6.B16, V18.B16 - VEOR V11.B16, V7.B16, V19.B16 - VSHL $7, V16.S4, V4.S4 - VSHL $7, V17.S4, V5.S4 - VSHL $7, V18.S4, V6.S4 - VSHL $7, V19.S4, V7.S4 - VSRI $25, V16.S4, V4.S4 - VSRI $25, V17.S4, V5.S4 - VSRI $25, V18.S4, V6.S4 - VSRI $25, V19.S4, V7.S4 - - // V0..V3 += V5..V7, V4 - // V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16) - VADD V0.S4, V5.S4, V0.S4 - VADD V1.S4, V6.S4, V1.S4 - VADD V2.S4, V7.S4, V2.S4 - VADD V3.S4, V4.S4, V3.S4 - VEOR V15.B16, V0.B16, V15.B16 - VEOR V12.B16, V1.B16, V12.B16 - VEOR V13.B16, V2.B16, V13.B16 - VEOR V14.B16, V3.B16, V14.B16 - VREV32 V12.H8, V12.H8 - VREV32 V13.H8, V13.H8 - VREV32 V14.H8, V14.H8 - VREV32 V15.H8, V15.H8 - - // V10 += V15; V5 <<<= ((V10 XOR V5), 12) - // ... - VADD V15.S4, V10.S4, V10.S4 - VADD V12.S4, V11.S4, V11.S4 - VADD V13.S4, V8.S4, V8.S4 - VADD V14.S4, V9.S4, V9.S4 - VEOR V10.B16, V5.B16, V16.B16 - VEOR V11.B16, V6.B16, V17.B16 - VEOR V8.B16, V7.B16, V18.B16 - VEOR V9.B16, V4.B16, V19.B16 - VSHL $12, V16.S4, V5.S4 - VSHL $12, V17.S4, V6.S4 - VSHL $12, V18.S4, V7.S4 - VSHL $12, V19.S4, V4.S4 - VSRI $20, V16.S4, V5.S4 - VSRI $20, V17.S4, V6.S4 - VSRI $20, V18.S4, V7.S4 - VSRI $20, V19.S4, V4.S4 - - // V0 += V5; V15 <<<= ((V0 XOR V15), 8) - // ... - VADD V5.S4, V0.S4, V0.S4 - VADD V6.S4, V1.S4, V1.S4 - VADD V7.S4, V2.S4, V2.S4 - VADD V4.S4, V3.S4, V3.S4 - VEOR V0.B16, V15.B16, V15.B16 - VEOR V1.B16, V12.B16, V12.B16 - VEOR V2.B16, V13.B16, V13.B16 - VEOR V3.B16, V14.B16, V14.B16 - VTBL V31.B16, [V12.B16], V12.B16 - VTBL V31.B16, [V13.B16], V13.B16 - VTBL V31.B16, [V14.B16], V14.B16 - VTBL V31.B16, [V15.B16], V15.B16 - - // V10 += V15; V5 <<<= ((V10 XOR V5), 7) - // ... - VADD V15.S4, V10.S4, V10.S4 - VADD V12.S4, V11.S4, V11.S4 - VADD V13.S4, V8.S4, V8.S4 - VADD V14.S4, V9.S4, V9.S4 - VEOR V10.B16, V5.B16, V16.B16 - VEOR V11.B16, V6.B16, V17.B16 - VEOR V8.B16, V7.B16, V18.B16 - VEOR V9.B16, V4.B16, V19.B16 - VSHL $7, V16.S4, V5.S4 - VSHL $7, V17.S4, V6.S4 - VSHL $7, V18.S4, V7.S4 - VSHL $7, V19.S4, V4.S4 - VSRI $25, V16.S4, V5.S4 - VSRI $25, V17.S4, V6.S4 - VSRI $25, V18.S4, V7.S4 - VSRI $25, V19.S4, V4.S4 - - SUB $1, R21 - CBNZ R21, chacha - - // VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4] - WORD $0x4D60E950 - - // VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4] - WORD $0x4DFFE894 - VADD V30.S4, V12.S4, V12.S4 - VADD V16.S4, V0.S4, V0.S4 - VADD V17.S4, V1.S4, V1.S4 - VADD V18.S4, V2.S4, V2.S4 - VADD V19.S4, V3.S4, V3.S4 - // VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4] - WORD $0x4DFFE898 - // restore R4 - SUB $32, R4 - - // load counter + nonce - // VLD1R (R7), [V28.S4] - WORD $0x4D40C8FC - // VLD3R (R6), [V29.S4, V30.S4, V31.S4] - WORD $0x4D40E8DD - - VADD V20.S4, V4.S4, V4.S4 - VADD V21.S4, V5.S4, V5.S4 - VADD V22.S4, V6.S4, V6.S4 - VADD V23.S4, V7.S4, V7.S4 - VADD V24.S4, V8.S4, V8.S4 - VADD V25.S4, V9.S4, V9.S4 - VADD V26.S4, V10.S4, V10.S4 - VADD V27.S4, V11.S4, V11.S4 - VADD V28.S4, V12.S4, V12.S4 - VADD V29.S4, V13.S4, V13.S4 - VADD V30.S4, V14.S4, V14.S4 - VADD V31.S4, V15.S4, V15.S4 - - VZIP1 V1.S4, V0.S4, V16.S4 - VZIP2 V1.S4, V0.S4, V17.S4 - VZIP1 V3.S4, V2.S4, V18.S4 - VZIP2 V3.S4, V2.S4, V19.S4 - VZIP1 V5.S4, V4.S4, V20.S4 - VZIP2 V5.S4, V4.S4, V21.S4 - VZIP1 V7.S4, V6.S4, V22.S4 - VZIP2 V7.S4, V6.S4, V23.S4 - VZIP1 V9.S4, V8.S4, V24.S4 - VZIP2 V9.S4, V8.S4, V25.S4 - VZIP1 V11.S4, V10.S4, V26.S4 - VZIP2 V11.S4, V10.S4, V27.S4 - VZIP1 V13.S4, V12.S4, V28.S4 - VZIP2 V13.S4, V12.S4, V29.S4 - VZIP1 V15.S4, V14.S4, V30.S4 - VZIP2 V15.S4, V14.S4, V31.S4 - VZIP1 V18.D2, V16.D2, V0.D2 - VZIP2 V18.D2, V16.D2, V4.D2 - VZIP1 V19.D2, V17.D2, V8.D2 - VZIP2 V19.D2, V17.D2, V12.D2 - VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16] - - VZIP1 V22.D2, V20.D2, V1.D2 - VZIP2 V22.D2, V20.D2, V5.D2 - VZIP1 V23.D2, V21.D2, V9.D2 - VZIP2 V23.D2, V21.D2, V13.D2 - VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16] - VZIP1 V26.D2, V24.D2, V2.D2 - VZIP2 V26.D2, V24.D2, V6.D2 - VZIP1 V27.D2, V25.D2, V10.D2 - VZIP2 V27.D2, V25.D2, V14.D2 - VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16] - VZIP1 V30.D2, V28.D2, V3.D2 - VZIP2 V30.D2, V28.D2, V7.D2 - VZIP1 V31.D2, V29.D2, V11.D2 - VZIP2 V31.D2, V29.D2, V15.D2 - VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16] - VEOR V0.B16, V16.B16, V16.B16 - VEOR V1.B16, V17.B16, V17.B16 - VEOR V2.B16, V18.B16, V18.B16 - VEOR V3.B16, V19.B16, V19.B16 - VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1) - VEOR V4.B16, V20.B16, V20.B16 - VEOR V5.B16, V21.B16, V21.B16 - VEOR V6.B16, V22.B16, V22.B16 - VEOR V7.B16, V23.B16, V23.B16 - VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1) - VEOR V8.B16, V24.B16, V24.B16 - VEOR V9.B16, V25.B16, V25.B16 - VEOR V10.B16, V26.B16, V26.B16 - VEOR V11.B16, V27.B16, V27.B16 - VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1) - VEOR V12.B16, V28.B16, V28.B16 - VEOR V13.B16, V29.B16, V29.B16 - VEOR V14.B16, V30.B16, V30.B16 - VEOR V15.B16, V31.B16, V31.B16 - VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1) - - ADD $4, R20 - MOVW R20, (R7) // update counter - - CMP R2, R12 - BGT loop - - RET - - -DATA ·constants+0x00(SB)/4, $0x61707865 -DATA ·constants+0x04(SB)/4, $0x3320646e -DATA ·constants+0x08(SB)/4, $0x79622d32 -DATA ·constants+0x0c(SB)/4, $0x6b206574 -GLOBL ·constants(SB), NOPTR|RODATA, $32 - -DATA ·incRotMatrix+0x00(SB)/4, $0x00000000 -DATA ·incRotMatrix+0x04(SB)/4, $0x00000001 -DATA ·incRotMatrix+0x08(SB)/4, $0x00000002 -DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003 -DATA ·incRotMatrix+0x10(SB)/4, $0x02010003 -DATA ·incRotMatrix+0x14(SB)/4, $0x06050407 -DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B -DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F -GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/chacha20/chacha_generic.go deleted file mode 100644 index a2ecf5c3..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_generic.go +++ /dev/null @@ -1,398 +0,0 @@ -// 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 chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms -// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01. -package chacha20 - -import ( - "crypto/cipher" - "encoding/binary" - "errors" - "math/bits" - - "golang.org/x/crypto/internal/subtle" -) - -const ( - // KeySize is the size of the key used by this cipher, in bytes. - KeySize = 32 - - // NonceSize is the size of the nonce used with the standard variant of this - // cipher, in bytes. - // - // Note that this is too short to be safely generated at random if the same - // key is reused more than 2³² times. - NonceSize = 12 - - // NonceSizeX is the size of the nonce used with the XChaCha20 variant of - // this cipher, in bytes. - NonceSizeX = 24 -) - -// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key -// and nonce. A *Cipher implements the cipher.Stream interface. -type Cipher struct { - // The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter - // (incremented after each block), and 3 of nonce. - key [8]uint32 - counter uint32 - nonce [3]uint32 - - // The last len bytes of buf are leftover key stream bytes from the previous - // XORKeyStream invocation. The size of buf depends on how many blocks are - // computed at a time by xorKeyStreamBlocks. - buf [bufSize]byte - len int - - // overflow is set when the counter overflowed, no more blocks can be - // generated, and the next XORKeyStream call should panic. - overflow bool - - // The counter-independent results of the first round are cached after they - // are computed the first time. - precompDone bool - p1, p5, p9, p13 uint32 - p2, p6, p10, p14 uint32 - p3, p7, p11, p15 uint32 -} - -var _ cipher.Stream = (*Cipher)(nil) - -// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given -// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided, -// the XChaCha20 construction will be used. It returns an error if key or nonce -// have any other length. -// -// Note that ChaCha20, like all stream ciphers, is not authenticated and allows -// attackers to silently tamper with the plaintext. For this reason, it is more -// appropriate as a building block than as a standalone encryption mechanism. -// Instead, consider using package golang.org/x/crypto/chacha20poly1305. -func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) { - // This function is split into a wrapper so that the Cipher allocation will - // be inlined, and depending on how the caller uses the return value, won't - // escape to the heap. - c := &Cipher{} - return newUnauthenticatedCipher(c, key, nonce) -} - -func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) { - if len(key) != KeySize { - return nil, errors.New("chacha20: wrong key size") - } - if len(nonce) == NonceSizeX { - // XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a - // derived key, allowing it to operate on a nonce of 24 bytes. See - // draft-irtf-cfrg-xchacha-01, Section 2.3. - key, _ = HChaCha20(key, nonce[0:16]) - cNonce := make([]byte, NonceSize) - copy(cNonce[4:12], nonce[16:24]) - nonce = cNonce - } else if len(nonce) != NonceSize { - return nil, errors.New("chacha20: wrong nonce size") - } - - key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint - c.key = [8]uint32{ - binary.LittleEndian.Uint32(key[0:4]), - binary.LittleEndian.Uint32(key[4:8]), - binary.LittleEndian.Uint32(key[8:12]), - binary.LittleEndian.Uint32(key[12:16]), - binary.LittleEndian.Uint32(key[16:20]), - binary.LittleEndian.Uint32(key[20:24]), - binary.LittleEndian.Uint32(key[24:28]), - binary.LittleEndian.Uint32(key[28:32]), - } - c.nonce = [3]uint32{ - binary.LittleEndian.Uint32(nonce[0:4]), - binary.LittleEndian.Uint32(nonce[4:8]), - binary.LittleEndian.Uint32(nonce[8:12]), - } - return c, nil -} - -// The constant first 4 words of the ChaCha20 state. -const ( - j0 uint32 = 0x61707865 // expa - j1 uint32 = 0x3320646e // nd 3 - j2 uint32 = 0x79622d32 // 2-by - j3 uint32 = 0x6b206574 // te k -) - -const blockSize = 64 - -// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words. -// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16 -// words each round, in columnar or diagonal groups of 4 at a time. -func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { - a += b - d ^= a - d = bits.RotateLeft32(d, 16) - c += d - b ^= c - b = bits.RotateLeft32(b, 12) - a += b - d ^= a - d = bits.RotateLeft32(d, 8) - c += d - b ^= c - b = bits.RotateLeft32(b, 7) - return a, b, c, d -} - -// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will -// behave as if (64 * counter) bytes had been encrypted so far. -// -// To prevent accidental counter reuse, SetCounter panics if counter is less -// than the current value. -// -// Note that the execution time of XORKeyStream is not independent of the -// counter value. -func (s *Cipher) SetCounter(counter uint32) { - // Internally, s may buffer multiple blocks, which complicates this - // implementation slightly. When checking whether the counter has rolled - // back, we must use both s.counter and s.len to determine how many blocks - // we have already output. - outputCounter := s.counter - uint32(s.len)/blockSize - if s.overflow || counter < outputCounter { - panic("chacha20: SetCounter attempted to rollback counter") - } - - // In the general case, we set the new counter value and reset s.len to 0, - // causing the next call to XORKeyStream to refill the buffer. However, if - // we're advancing within the existing buffer, we can save work by simply - // setting s.len. - if counter < s.counter { - s.len = int(s.counter-counter) * blockSize - } else { - s.counter = counter - s.len = 0 - } -} - -// XORKeyStream XORs each byte in the given slice with a byte from the -// cipher's key stream. Dst and src must overlap entirely or not at all. -// -// If len(dst) < len(src), XORKeyStream will panic. It is acceptable -// to pass a dst bigger than src, and in that case, XORKeyStream will -// only update dst[:len(src)] and will not touch the rest of dst. -// -// Multiple calls to XORKeyStream behave as if the concatenation of -// the src buffers was passed in a single run. That is, Cipher -// maintains state and does not reset at each XORKeyStream call. -func (s *Cipher) XORKeyStream(dst, src []byte) { - if len(src) == 0 { - return - } - if len(dst) < len(src) { - panic("chacha20: output smaller than input") - } - dst = dst[:len(src)] - if subtle.InexactOverlap(dst, src) { - panic("chacha20: invalid buffer overlap") - } - - // First, drain any remaining key stream from a previous XORKeyStream. - if s.len != 0 { - keyStream := s.buf[bufSize-s.len:] - if len(src) < len(keyStream) { - keyStream = keyStream[:len(src)] - } - _ = src[len(keyStream)-1] // bounds check elimination hint - for i, b := range keyStream { - dst[i] = src[i] ^ b - } - s.len -= len(keyStream) - dst, src = dst[len(keyStream):], src[len(keyStream):] - } - if len(src) == 0 { - return - } - - // If we'd need to let the counter overflow and keep generating output, - // panic immediately. If instead we'd only reach the last block, remember - // not to generate any more output after the buffer is drained. - numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize - if s.overflow || uint64(s.counter)+numBlocks > 1<<32 { - panic("chacha20: counter overflow") - } else if uint64(s.counter)+numBlocks == 1<<32 { - s.overflow = true - } - - // xorKeyStreamBlocks implementations expect input lengths that are a - // multiple of bufSize. Platform-specific ones process multiple blocks at a - // time, so have bufSizes that are a multiple of blockSize. - - full := len(src) - len(src)%bufSize - if full > 0 { - s.xorKeyStreamBlocks(dst[:full], src[:full]) - } - dst, src = dst[full:], src[full:] - - // If using a multi-block xorKeyStreamBlocks would overflow, use the generic - // one that does one block at a time. - const blocksPerBuf = bufSize / blockSize - if uint64(s.counter)+blocksPerBuf > 1<<32 { - s.buf = [bufSize]byte{} - numBlocks := (len(src) + blockSize - 1) / blockSize - buf := s.buf[bufSize-numBlocks*blockSize:] - copy(buf, src) - s.xorKeyStreamBlocksGeneric(buf, buf) - s.len = len(buf) - copy(dst, buf) - return - } - - // If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and - // keep the leftover keystream for the next XORKeyStream invocation. - if len(src) > 0 { - s.buf = [bufSize]byte{} - copy(s.buf[:], src) - s.xorKeyStreamBlocks(s.buf[:], s.buf[:]) - s.len = bufSize - copy(dst, s.buf[:]) - } -} - -func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) { - if len(dst) != len(src) || len(dst)%blockSize != 0 { - panic("chacha20: internal error: wrong dst and/or src length") - } - - // To generate each block of key stream, the initial cipher state - // (represented below) is passed through 20 rounds of shuffling, - // alternatively applying quarterRounds by columns (like 1, 5, 9, 13) - // or by diagonals (like 1, 6, 11, 12). - // - // 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc - // 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk - // 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk - // 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn - // - // c=constant k=key b=blockcount n=nonce - var ( - c0, c1, c2, c3 = j0, j1, j2, j3 - c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3] - c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7] - _, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2] - ) - - // Three quarters of the first round don't depend on the counter, so we can - // calculate them here, and reuse them for multiple blocks in the loop, and - // for future XORKeyStream invocations. - if !s.precompDone { - s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13) - s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14) - s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15) - s.precompDone = true - } - - // A condition of len(src) > 0 would be sufficient, but this also - // acts as a bounds check elimination hint. - for len(src) >= 64 && len(dst) >= 64 { - // The remainder of the first column round. - fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter) - - // The second diagonal round. - x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15) - x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12) - x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13) - x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14) - - // The remaining 18 rounds. - for i := 0; i < 9; i++ { - // Column round. - x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) - x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) - x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) - x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) - - // Diagonal round. - x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) - x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) - x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) - x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) - } - - // Add back the initial state to generate the key stream, then - // XOR the key stream with the source and write out the result. - addXor(dst[0:4], src[0:4], x0, c0) - addXor(dst[4:8], src[4:8], x1, c1) - addXor(dst[8:12], src[8:12], x2, c2) - addXor(dst[12:16], src[12:16], x3, c3) - addXor(dst[16:20], src[16:20], x4, c4) - addXor(dst[20:24], src[20:24], x5, c5) - addXor(dst[24:28], src[24:28], x6, c6) - addXor(dst[28:32], src[28:32], x7, c7) - addXor(dst[32:36], src[32:36], x8, c8) - addXor(dst[36:40], src[36:40], x9, c9) - addXor(dst[40:44], src[40:44], x10, c10) - addXor(dst[44:48], src[44:48], x11, c11) - addXor(dst[48:52], src[48:52], x12, s.counter) - addXor(dst[52:56], src[52:56], x13, c13) - addXor(dst[56:60], src[56:60], x14, c14) - addXor(dst[60:64], src[60:64], x15, c15) - - s.counter += 1 - - src, dst = src[blockSize:], dst[blockSize:] - } -} - -// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes -// key and a 16 bytes nonce. It returns an error if key or nonce have any other -// length. It is used as part of the XChaCha20 construction. -func HChaCha20(key, nonce []byte) ([]byte, error) { - // This function is split into a wrapper so that the slice allocation will - // be inlined, and depending on how the caller uses the return value, won't - // escape to the heap. - out := make([]byte, 32) - return hChaCha20(out, key, nonce) -} - -func hChaCha20(out, key, nonce []byte) ([]byte, error) { - if len(key) != KeySize { - return nil, errors.New("chacha20: wrong HChaCha20 key size") - } - if len(nonce) != 16 { - return nil, errors.New("chacha20: wrong HChaCha20 nonce size") - } - - x0, x1, x2, x3 := j0, j1, j2, j3 - x4 := binary.LittleEndian.Uint32(key[0:4]) - x5 := binary.LittleEndian.Uint32(key[4:8]) - x6 := binary.LittleEndian.Uint32(key[8:12]) - x7 := binary.LittleEndian.Uint32(key[12:16]) - x8 := binary.LittleEndian.Uint32(key[16:20]) - x9 := binary.LittleEndian.Uint32(key[20:24]) - x10 := binary.LittleEndian.Uint32(key[24:28]) - x11 := binary.LittleEndian.Uint32(key[28:32]) - x12 := binary.LittleEndian.Uint32(nonce[0:4]) - x13 := binary.LittleEndian.Uint32(nonce[4:8]) - x14 := binary.LittleEndian.Uint32(nonce[8:12]) - x15 := binary.LittleEndian.Uint32(nonce[12:16]) - - for i := 0; i < 10; i++ { - // Diagonal round. - x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) - x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) - x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) - x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) - - // Column round. - x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) - x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) - x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) - x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) - } - - _ = out[31] // bounds check elimination hint - binary.LittleEndian.PutUint32(out[0:4], x0) - binary.LittleEndian.PutUint32(out[4:8], x1) - binary.LittleEndian.PutUint32(out[8:12], x2) - binary.LittleEndian.PutUint32(out[12:16], x3) - binary.LittleEndian.PutUint32(out[16:20], x12) - binary.LittleEndian.PutUint32(out[20:24], x13) - binary.LittleEndian.PutUint32(out[24:28], x14) - binary.LittleEndian.PutUint32(out[28:32], x15) - return out, nil -} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go deleted file mode 100644 index 025b4989..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 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. - -//go:build (!arm64 && !s390x && !ppc64le) || (arm64 && !go1.11) || !gc || purego -// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego - -package chacha20 - -const bufSize = blockSize - -func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) { - s.xorKeyStreamBlocksGeneric(dst, src) -} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go deleted file mode 100644 index da420b2e..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego -// +build gc,!purego - -package chacha20 - -const bufSize = 256 - -//go:noescape -func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) - -func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { - chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter) -} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s deleted file mode 100644 index 5c0fed26..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Based on CRYPTOGAMS code with the following comment: -// # ==================================================================== -// # Written by Andy Polyakov for the OpenSSL -// # project. The module is, however, dual licensed under OpenSSL and -// # CRYPTOGAMS licenses depending on where you obtain it. For further -// # details see http://www.openssl.org/~appro/cryptogams/. -// # ==================================================================== - -// Code for the perl script that generates the ppc64 assembler -// can be found in the cryptogams repository at the link below. It is based on -// the original from openssl. - -// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91 - -// The differences in this and the original implementation are -// due to the calling conventions and initialization of constants. - -//go:build gc && !purego -// +build gc,!purego - -#include "textflag.h" - -#define OUT R3 -#define INP R4 -#define LEN R5 -#define KEY R6 -#define CNT R7 -#define TMP R15 - -#define CONSTBASE R16 -#define BLOCKS R17 - -DATA consts<>+0x00(SB)/8, $0x3320646e61707865 -DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 -DATA consts<>+0x10(SB)/8, $0x0000000000000001 -DATA consts<>+0x18(SB)/8, $0x0000000000000000 -DATA consts<>+0x20(SB)/8, $0x0000000000000004 -DATA consts<>+0x28(SB)/8, $0x0000000000000000 -DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d -DATA consts<>+0x38(SB)/8, $0x0203000106070405 -DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c -DATA consts<>+0x48(SB)/8, $0x0102030005060704 -DATA consts<>+0x50(SB)/8, $0x6170786561707865 -DATA consts<>+0x58(SB)/8, $0x6170786561707865 -DATA consts<>+0x60(SB)/8, $0x3320646e3320646e -DATA consts<>+0x68(SB)/8, $0x3320646e3320646e -DATA consts<>+0x70(SB)/8, $0x79622d3279622d32 -DATA consts<>+0x78(SB)/8, $0x79622d3279622d32 -DATA consts<>+0x80(SB)/8, $0x6b2065746b206574 -DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 -DATA consts<>+0x90(SB)/8, $0x0000000100000000 -DATA consts<>+0x98(SB)/8, $0x0000000300000002 -GLOBL consts<>(SB), RODATA, $0xa0 - -//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) -TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 - MOVD out+0(FP), OUT - MOVD inp+8(FP), INP - MOVD len+16(FP), LEN - MOVD key+24(FP), KEY - MOVD counter+32(FP), CNT - - // Addressing for constants - MOVD $consts<>+0x00(SB), CONSTBASE - MOVD $16, R8 - MOVD $32, R9 - MOVD $48, R10 - MOVD $64, R11 - SRD $6, LEN, BLOCKS - // V16 - LXVW4X (CONSTBASE)(R0), VS48 - ADD $80,CONSTBASE - - // Load key into V17,V18 - LXVW4X (KEY)(R0), VS49 - LXVW4X (KEY)(R8), VS50 - - // Load CNT, NONCE into V19 - LXVW4X (CNT)(R0), VS51 - - // Clear V27 - VXOR V27, V27, V27 - - // V28 - LXVW4X (CONSTBASE)(R11), VS60 - - // splat slot from V19 -> V26 - VSPLTW $0, V19, V26 - - VSLDOI $4, V19, V27, V19 - VSLDOI $12, V27, V19, V19 - - VADDUWM V26, V28, V26 - - MOVD $10, R14 - MOVD R14, CTR - -loop_outer_vsx: - // V0, V1, V2, V3 - LXVW4X (R0)(CONSTBASE), VS32 - LXVW4X (R8)(CONSTBASE), VS33 - LXVW4X (R9)(CONSTBASE), VS34 - LXVW4X (R10)(CONSTBASE), VS35 - - // splat values from V17, V18 into V4-V11 - VSPLTW $0, V17, V4 - VSPLTW $1, V17, V5 - VSPLTW $2, V17, V6 - VSPLTW $3, V17, V7 - VSPLTW $0, V18, V8 - VSPLTW $1, V18, V9 - VSPLTW $2, V18, V10 - VSPLTW $3, V18, V11 - - // VOR - VOR V26, V26, V12 - - // splat values from V19 -> V13, V14, V15 - VSPLTW $1, V19, V13 - VSPLTW $2, V19, V14 - VSPLTW $3, V19, V15 - - // splat const values - VSPLTISW $-16, V27 - VSPLTISW $12, V28 - VSPLTISW $8, V29 - VSPLTISW $7, V30 - -loop_vsx: - VADDUWM V0, V4, V0 - VADDUWM V1, V5, V1 - VADDUWM V2, V6, V2 - VADDUWM V3, V7, V3 - - VXOR V12, V0, V12 - VXOR V13, V1, V13 - VXOR V14, V2, V14 - VXOR V15, V3, V15 - - VRLW V12, V27, V12 - VRLW V13, V27, V13 - VRLW V14, V27, V14 - VRLW V15, V27, V15 - - VADDUWM V8, V12, V8 - VADDUWM V9, V13, V9 - VADDUWM V10, V14, V10 - VADDUWM V11, V15, V11 - - VXOR V4, V8, V4 - VXOR V5, V9, V5 - VXOR V6, V10, V6 - VXOR V7, V11, V7 - - VRLW V4, V28, V4 - VRLW V5, V28, V5 - VRLW V6, V28, V6 - VRLW V7, V28, V7 - - VADDUWM V0, V4, V0 - VADDUWM V1, V5, V1 - VADDUWM V2, V6, V2 - VADDUWM V3, V7, V3 - - VXOR V12, V0, V12 - VXOR V13, V1, V13 - VXOR V14, V2, V14 - VXOR V15, V3, V15 - - VRLW V12, V29, V12 - VRLW V13, V29, V13 - VRLW V14, V29, V14 - VRLW V15, V29, V15 - - VADDUWM V8, V12, V8 - VADDUWM V9, V13, V9 - VADDUWM V10, V14, V10 - VADDUWM V11, V15, V11 - - VXOR V4, V8, V4 - VXOR V5, V9, V5 - VXOR V6, V10, V6 - VXOR V7, V11, V7 - - VRLW V4, V30, V4 - VRLW V5, V30, V5 - VRLW V6, V30, V6 - VRLW V7, V30, V7 - - VADDUWM V0, V5, V0 - VADDUWM V1, V6, V1 - VADDUWM V2, V7, V2 - VADDUWM V3, V4, V3 - - VXOR V15, V0, V15 - VXOR V12, V1, V12 - VXOR V13, V2, V13 - VXOR V14, V3, V14 - - VRLW V15, V27, V15 - VRLW V12, V27, V12 - VRLW V13, V27, V13 - VRLW V14, V27, V14 - - VADDUWM V10, V15, V10 - VADDUWM V11, V12, V11 - VADDUWM V8, V13, V8 - VADDUWM V9, V14, V9 - - VXOR V5, V10, V5 - VXOR V6, V11, V6 - VXOR V7, V8, V7 - VXOR V4, V9, V4 - - VRLW V5, V28, V5 - VRLW V6, V28, V6 - VRLW V7, V28, V7 - VRLW V4, V28, V4 - - VADDUWM V0, V5, V0 - VADDUWM V1, V6, V1 - VADDUWM V2, V7, V2 - VADDUWM V3, V4, V3 - - VXOR V15, V0, V15 - VXOR V12, V1, V12 - VXOR V13, V2, V13 - VXOR V14, V3, V14 - - VRLW V15, V29, V15 - VRLW V12, V29, V12 - VRLW V13, V29, V13 - VRLW V14, V29, V14 - - VADDUWM V10, V15, V10 - VADDUWM V11, V12, V11 - VADDUWM V8, V13, V8 - VADDUWM V9, V14, V9 - - VXOR V5, V10, V5 - VXOR V6, V11, V6 - VXOR V7, V8, V7 - VXOR V4, V9, V4 - - VRLW V5, V30, V5 - VRLW V6, V30, V6 - VRLW V7, V30, V7 - VRLW V4, V30, V4 - BC 16, LT, loop_vsx - - VADDUWM V12, V26, V12 - - WORD $0x13600F8C // VMRGEW V0, V1, V27 - WORD $0x13821F8C // VMRGEW V2, V3, V28 - - WORD $0x10000E8C // VMRGOW V0, V1, V0 - WORD $0x10421E8C // VMRGOW V2, V3, V2 - - WORD $0x13A42F8C // VMRGEW V4, V5, V29 - WORD $0x13C63F8C // VMRGEW V6, V7, V30 - - XXPERMDI VS32, VS34, $0, VS33 - XXPERMDI VS32, VS34, $3, VS35 - XXPERMDI VS59, VS60, $0, VS32 - XXPERMDI VS59, VS60, $3, VS34 - - WORD $0x10842E8C // VMRGOW V4, V5, V4 - WORD $0x10C63E8C // VMRGOW V6, V7, V6 - - WORD $0x13684F8C // VMRGEW V8, V9, V27 - WORD $0x138A5F8C // VMRGEW V10, V11, V28 - - XXPERMDI VS36, VS38, $0, VS37 - XXPERMDI VS36, VS38, $3, VS39 - XXPERMDI VS61, VS62, $0, VS36 - XXPERMDI VS61, VS62, $3, VS38 - - WORD $0x11084E8C // VMRGOW V8, V9, V8 - WORD $0x114A5E8C // VMRGOW V10, V11, V10 - - WORD $0x13AC6F8C // VMRGEW V12, V13, V29 - WORD $0x13CE7F8C // VMRGEW V14, V15, V30 - - XXPERMDI VS40, VS42, $0, VS41 - XXPERMDI VS40, VS42, $3, VS43 - XXPERMDI VS59, VS60, $0, VS40 - XXPERMDI VS59, VS60, $3, VS42 - - WORD $0x118C6E8C // VMRGOW V12, V13, V12 - WORD $0x11CE7E8C // VMRGOW V14, V15, V14 - - VSPLTISW $4, V27 - VADDUWM V26, V27, V26 - - XXPERMDI VS44, VS46, $0, VS45 - XXPERMDI VS44, VS46, $3, VS47 - XXPERMDI VS61, VS62, $0, VS44 - XXPERMDI VS61, VS62, $3, VS46 - - VADDUWM V0, V16, V0 - VADDUWM V4, V17, V4 - VADDUWM V8, V18, V8 - VADDUWM V12, V19, V12 - - CMPU LEN, $64 - BLT tail_vsx - - // Bottom of loop - LXVW4X (INP)(R0), VS59 - LXVW4X (INP)(R8), VS60 - LXVW4X (INP)(R9), VS61 - LXVW4X (INP)(R10), VS62 - - VXOR V27, V0, V27 - VXOR V28, V4, V28 - VXOR V29, V8, V29 - VXOR V30, V12, V30 - - STXVW4X VS59, (OUT)(R0) - STXVW4X VS60, (OUT)(R8) - ADD $64, INP - STXVW4X VS61, (OUT)(R9) - ADD $-64, LEN - STXVW4X VS62, (OUT)(R10) - ADD $64, OUT - BEQ done_vsx - - VADDUWM V1, V16, V0 - VADDUWM V5, V17, V4 - VADDUWM V9, V18, V8 - VADDUWM V13, V19, V12 - - CMPU LEN, $64 - BLT tail_vsx - - LXVW4X (INP)(R0), VS59 - LXVW4X (INP)(R8), VS60 - LXVW4X (INP)(R9), VS61 - LXVW4X (INP)(R10), VS62 - VXOR V27, V0, V27 - - VXOR V28, V4, V28 - VXOR V29, V8, V29 - VXOR V30, V12, V30 - - STXVW4X VS59, (OUT)(R0) - STXVW4X VS60, (OUT)(R8) - ADD $64, INP - STXVW4X VS61, (OUT)(R9) - ADD $-64, LEN - STXVW4X VS62, (OUT)(V10) - ADD $64, OUT - BEQ done_vsx - - VADDUWM V2, V16, V0 - VADDUWM V6, V17, V4 - VADDUWM V10, V18, V8 - VADDUWM V14, V19, V12 - - CMPU LEN, $64 - BLT tail_vsx - - LXVW4X (INP)(R0), VS59 - LXVW4X (INP)(R8), VS60 - LXVW4X (INP)(R9), VS61 - LXVW4X (INP)(R10), VS62 - - VXOR V27, V0, V27 - VXOR V28, V4, V28 - VXOR V29, V8, V29 - VXOR V30, V12, V30 - - STXVW4X VS59, (OUT)(R0) - STXVW4X VS60, (OUT)(R8) - ADD $64, INP - STXVW4X VS61, (OUT)(R9) - ADD $-64, LEN - STXVW4X VS62, (OUT)(R10) - ADD $64, OUT - BEQ done_vsx - - VADDUWM V3, V16, V0 - VADDUWM V7, V17, V4 - VADDUWM V11, V18, V8 - VADDUWM V15, V19, V12 - - CMPU LEN, $64 - BLT tail_vsx - - LXVW4X (INP)(R0), VS59 - LXVW4X (INP)(R8), VS60 - LXVW4X (INP)(R9), VS61 - LXVW4X (INP)(R10), VS62 - - VXOR V27, V0, V27 - VXOR V28, V4, V28 - VXOR V29, V8, V29 - VXOR V30, V12, V30 - - STXVW4X VS59, (OUT)(R0) - STXVW4X VS60, (OUT)(R8) - ADD $64, INP - STXVW4X VS61, (OUT)(R9) - ADD $-64, LEN - STXVW4X VS62, (OUT)(R10) - ADD $64, OUT - - MOVD $10, R14 - MOVD R14, CTR - BNE loop_outer_vsx - -done_vsx: - // Increment counter by number of 64 byte blocks - MOVD (CNT), R14 - ADD BLOCKS, R14 - MOVD R14, (CNT) - RET - -tail_vsx: - ADD $32, R1, R11 - MOVD LEN, CTR - - // Save values on stack to copy from - STXVW4X VS32, (R11)(R0) - STXVW4X VS36, (R11)(R8) - STXVW4X VS40, (R11)(R9) - STXVW4X VS44, (R11)(R10) - ADD $-1, R11, R12 - ADD $-1, INP - ADD $-1, OUT - -looptail_vsx: - // Copying the result to OUT - // in bytes. - MOVBZU 1(R12), KEY - MOVBZU 1(INP), TMP - XOR KEY, TMP, KEY - MOVBU KEY, 1(OUT) - BC 16, LT, looptail_vsx - - // Clear the stack values - STXVW4X VS48, (R11)(R0) - STXVW4X VS48, (R11)(R8) - STXVW4X VS48, (R11)(R9) - STXVW4X VS48, (R11)(R10) - BR done_vsx diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go deleted file mode 100644 index 4652247b..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 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. - -//go:build gc && !purego -// +build gc,!purego - -package chacha20 - -import "golang.org/x/sys/cpu" - -var haveAsm = cpu.S390X.HasVX - -const bufSize = 256 - -// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only -// be called when the vector facility is available. Implementation in asm_s390x.s. -// -//go:noescape -func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) - -func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { - if cpu.S390X.HasVX { - xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) - } else { - c.xorKeyStreamBlocksGeneric(dst, src) - } -} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s deleted file mode 100644 index f3ef5a01..00000000 --- a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2018 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. - -//go:build gc && !purego -// +build gc,!purego - -#include "go_asm.h" -#include "textflag.h" - -// This is an implementation of the ChaCha20 encryption algorithm as -// specified in RFC 7539. It uses vector instructions to compute -// 4 keystream blocks in parallel (256 bytes) which are then XORed -// with the bytes in the input slice. - -GLOBL ·constants<>(SB), RODATA|NOPTR, $32 -// BSWAP: swap bytes in each 4-byte element -DATA ·constants<>+0x00(SB)/4, $0x03020100 -DATA ·constants<>+0x04(SB)/4, $0x07060504 -DATA ·constants<>+0x08(SB)/4, $0x0b0a0908 -DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c -// J0: [j0, j1, j2, j3] -DATA ·constants<>+0x10(SB)/4, $0x61707865 -DATA ·constants<>+0x14(SB)/4, $0x3320646e -DATA ·constants<>+0x18(SB)/4, $0x79622d32 -DATA ·constants<>+0x1c(SB)/4, $0x6b206574 - -#define BSWAP V5 -#define J0 V6 -#define KEY0 V7 -#define KEY1 V8 -#define NONCE V9 -#define CTR V10 -#define M0 V11 -#define M1 V12 -#define M2 V13 -#define M3 V14 -#define INC V15 -#define X0 V16 -#define X1 V17 -#define X2 V18 -#define X3 V19 -#define X4 V20 -#define X5 V21 -#define X6 V22 -#define X7 V23 -#define X8 V24 -#define X9 V25 -#define X10 V26 -#define X11 V27 -#define X12 V28 -#define X13 V29 -#define X14 V30 -#define X15 V31 - -#define NUM_ROUNDS 20 - -#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \ - VAF a1, a0, a0 \ - VAF b1, b0, b0 \ - VAF c1, c0, c0 \ - VAF d1, d0, d0 \ - VX a0, a2, a2 \ - VX b0, b2, b2 \ - VX c0, c2, c2 \ - VX d0, d2, d2 \ - VERLLF $16, a2, a2 \ - VERLLF $16, b2, b2 \ - VERLLF $16, c2, c2 \ - VERLLF $16, d2, d2 \ - VAF a2, a3, a3 \ - VAF b2, b3, b3 \ - VAF c2, c3, c3 \ - VAF d2, d3, d3 \ - VX a3, a1, a1 \ - VX b3, b1, b1 \ - VX c3, c1, c1 \ - VX d3, d1, d1 \ - VERLLF $12, a1, a1 \ - VERLLF $12, b1, b1 \ - VERLLF $12, c1, c1 \ - VERLLF $12, d1, d1 \ - VAF a1, a0, a0 \ - VAF b1, b0, b0 \ - VAF c1, c0, c0 \ - VAF d1, d0, d0 \ - VX a0, a2, a2 \ - VX b0, b2, b2 \ - VX c0, c2, c2 \ - VX d0, d2, d2 \ - VERLLF $8, a2, a2 \ - VERLLF $8, b2, b2 \ - VERLLF $8, c2, c2 \ - VERLLF $8, d2, d2 \ - VAF a2, a3, a3 \ - VAF b2, b3, b3 \ - VAF c2, c3, c3 \ - VAF d2, d3, d3 \ - VX a3, a1, a1 \ - VX b3, b1, b1 \ - VX c3, c1, c1 \ - VX d3, d1, d1 \ - VERLLF $7, a1, a1 \ - VERLLF $7, b1, b1 \ - VERLLF $7, c1, c1 \ - VERLLF $7, d1, d1 - -#define PERMUTE(mask, v0, v1, v2, v3) \ - VPERM v0, v0, mask, v0 \ - VPERM v1, v1, mask, v1 \ - VPERM v2, v2, mask, v2 \ - VPERM v3, v3, mask, v3 - -#define ADDV(x, v0, v1, v2, v3) \ - VAF x, v0, v0 \ - VAF x, v1, v1 \ - VAF x, v2, v2 \ - VAF x, v3, v3 - -#define XORV(off, dst, src, v0, v1, v2, v3) \ - VLM off(src), M0, M3 \ - PERMUTE(BSWAP, v0, v1, v2, v3) \ - VX v0, M0, M0 \ - VX v1, M1, M1 \ - VX v2, M2, M2 \ - VX v3, M3, M3 \ - VSTM M0, M3, off(dst) - -#define SHUFFLE(a, b, c, d, t, u, v, w) \ - VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]} - VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]} - VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]} - VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]} - VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]} - VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]} - VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]} - VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]} - -// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) -TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 - MOVD $·constants<>(SB), R1 - MOVD dst+0(FP), R2 // R2=&dst[0] - LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src) - MOVD key+48(FP), R5 // R5=key - MOVD nonce+56(FP), R6 // R6=nonce - MOVD counter+64(FP), R7 // R7=counter - - // load BSWAP and J0 - VLM (R1), BSWAP, J0 - - // setup - MOVD $95, R0 - VLM (R5), KEY0, KEY1 - VLL R0, (R6), NONCE - VZERO M0 - VLEIB $7, $32, M0 - VSRLB M0, NONCE, NONCE - - // initialize counter values - VLREPF (R7), CTR - VZERO INC - VLEIF $1, $1, INC - VLEIF $2, $2, INC - VLEIF $3, $3, INC - VAF INC, CTR, CTR - VREPIF $4, INC - -chacha: - VREPF $0, J0, X0 - VREPF $1, J0, X1 - VREPF $2, J0, X2 - VREPF $3, J0, X3 - VREPF $0, KEY0, X4 - VREPF $1, KEY0, X5 - VREPF $2, KEY0, X6 - VREPF $3, KEY0, X7 - VREPF $0, KEY1, X8 - VREPF $1, KEY1, X9 - VREPF $2, KEY1, X10 - VREPF $3, KEY1, X11 - VLR CTR, X12 - VREPF $1, NONCE, X13 - VREPF $2, NONCE, X14 - VREPF $3, NONCE, X15 - - MOVD $(NUM_ROUNDS/2), R1 - -loop: - ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11) - ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9) - - ADD $-1, R1 - BNE loop - - // decrement length - ADD $-256, R4 - - // rearrange vectors - SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3) - ADDV(J0, X0, X1, X2, X3) - SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3) - ADDV(KEY0, X4, X5, X6, X7) - SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3) - ADDV(KEY1, X8, X9, X10, X11) - VAF CTR, X12, X12 - SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3) - ADDV(NONCE, X12, X13, X14, X15) - - // increment counters - VAF INC, CTR, CTR - - // xor keystream with plaintext - XORV(0*64, R2, R3, X0, X4, X8, X12) - XORV(1*64, R2, R3, X1, X5, X9, X13) - XORV(2*64, R2, R3, X2, X6, X10, X14) - XORV(3*64, R2, R3, X3, X7, X11, X15) - - // increment pointers - MOVD $256(R2), R2 - MOVD $256(R3), R3 - - CMPBNE R4, $0, chacha - - VSTEF $0, CTR, (R7) - RET diff --git a/vendor/golang.org/x/crypto/chacha20/xor.go b/vendor/golang.org/x/crypto/chacha20/xor.go deleted file mode 100644 index c2d04851..00000000 --- a/vendor/golang.org/x/crypto/chacha20/xor.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found src the LICENSE file. - -package chacha20 - -import "runtime" - -// Platforms that have fast unaligned 32-bit little endian accesses. -const unaligned = runtime.GOARCH == "386" || - runtime.GOARCH == "amd64" || - runtime.GOARCH == "arm64" || - runtime.GOARCH == "ppc64le" || - runtime.GOARCH == "s390x" - -// addXor reads a little endian uint32 from src, XORs it with (a + b) and -// places the result in little endian byte order in dst. -func addXor(dst, src []byte, a, b uint32) { - _, _ = src[3], dst[3] // bounds check elimination hint - if unaligned { - // The compiler should optimize this code into - // 32-bit unaligned little endian loads and stores. - // TODO: delete once the compiler does a reliably - // good job with the generic code below. - // See issue #25111 for more details. - v := uint32(src[0]) - v |= uint32(src[1]) << 8 - v |= uint32(src[2]) << 16 - v |= uint32(src[3]) << 24 - v ^= a + b - dst[0] = byte(v) - dst[1] = byte(v >> 8) - dst[2] = byte(v >> 16) - dst[3] = byte(v >> 24) - } else { - a += b - dst[0] = src[0] ^ byte(a) - dst[1] = src[1] ^ byte(a>>8) - dst[2] = src[2] ^ byte(a>>16) - dst[3] = src[3] ^ byte(a>>24) - } -} diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go deleted file mode 100644 index bc62161d..00000000 --- a/vendor/golang.org/x/crypto/curve25519/curve25519.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package curve25519 provides an implementation of the X25519 function, which -// performs scalar multiplication on the elliptic curve known as Curve25519. -// See RFC 7748. -package curve25519 // import "golang.org/x/crypto/curve25519" - -import ( - "crypto/subtle" - "errors" - "strconv" - - "golang.org/x/crypto/curve25519/internal/field" -) - -// ScalarMult sets dst to the product scalar * point. -// -// Deprecated: when provided a low-order point, ScalarMult will set dst to all -// zeroes, irrespective of the scalar. Instead, use the X25519 function, which -// will return an error. -func ScalarMult(dst, scalar, point *[32]byte) { - var e [32]byte - - copy(e[:], scalar[:]) - e[0] &= 248 - e[31] &= 127 - e[31] |= 64 - - var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element - x1.SetBytes(point[:]) - x2.One() - x3.Set(&x1) - z3.One() - - swap := 0 - for pos := 254; pos >= 0; pos-- { - b := e[pos/8] >> uint(pos&7) - b &= 1 - swap ^= int(b) - x2.Swap(&x3, swap) - z2.Swap(&z3, swap) - swap = int(b) - - tmp0.Subtract(&x3, &z3) - tmp1.Subtract(&x2, &z2) - x2.Add(&x2, &z2) - z2.Add(&x3, &z3) - z3.Multiply(&tmp0, &x2) - z2.Multiply(&z2, &tmp1) - tmp0.Square(&tmp1) - tmp1.Square(&x2) - x3.Add(&z3, &z2) - z2.Subtract(&z3, &z2) - x2.Multiply(&tmp1, &tmp0) - tmp1.Subtract(&tmp1, &tmp0) - z2.Square(&z2) - - z3.Mult32(&tmp1, 121666) - x3.Square(&x3) - tmp0.Add(&tmp0, &z3) - z3.Multiply(&x1, &z2) - z2.Multiply(&tmp1, &tmp0) - } - - x2.Swap(&x3, swap) - z2.Swap(&z3, swap) - - z2.Invert(&z2) - x2.Multiply(&x2, &z2) - copy(dst[:], x2.Bytes()) -} - -// ScalarBaseMult sets dst to the product scalar * base where base is the -// standard generator. -// -// It is recommended to use the X25519 function with Basepoint instead, as -// copying into fixed size arrays can lead to unexpected bugs. -func ScalarBaseMult(dst, scalar *[32]byte) { - ScalarMult(dst, scalar, &basePoint) -} - -const ( - // ScalarSize is the size of the scalar input to X25519. - ScalarSize = 32 - // PointSize is the size of the point input to X25519. - PointSize = 32 -) - -// Basepoint is the canonical Curve25519 generator. -var Basepoint []byte - -var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - -func init() { Basepoint = basePoint[:] } - -func checkBasepoint() { - if subtle.ConstantTimeCompare(Basepoint, []byte{ - 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }) != 1 { - panic("curve25519: global Basepoint value was modified") - } -} - -// X25519 returns the result of the scalar multiplication (scalar * point), -// according to RFC 7748, Section 5. scalar, point and the return value are -// slices of 32 bytes. -// -// scalar can be generated at random, for example with crypto/rand. point should -// be either Basepoint or the output of another X25519 call. -// -// If point is Basepoint (but not if it's a different slice with the same -// contents) a precomputed implementation might be used for performance. -func X25519(scalar, point []byte) ([]byte, error) { - // Outline the body of function, to let the allocation be inlined in the - // caller, and possibly avoid escaping to the heap. - var dst [32]byte - return x25519(&dst, scalar, point) -} - -func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) { - var in [32]byte - if l := len(scalar); l != 32 { - return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32") - } - if l := len(point); l != 32 { - return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32") - } - copy(in[:], scalar) - if &point[0] == &Basepoint[0] { - checkBasepoint() - ScalarBaseMult(dst, &in) - } else { - var base, zero [32]byte - copy(base[:], point) - ScalarMult(dst, &in, &base) - if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 { - return nil, errors.New("bad input point: low order point") - } - } - return dst[:], nil -} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/README b/vendor/golang.org/x/crypto/curve25519/internal/field/README deleted file mode 100644 index e25bca7d..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/README +++ /dev/null @@ -1,7 +0,0 @@ -This package is kept in sync with crypto/ed25519/internal/edwards25519/field in -the standard library. - -If there are any changes in the standard library that need to be synced to this -package, run sync.sh. It will not overwrite any local changes made since the -previous sync, so it's ok to land changes in this package first, and then sync -to the standard library later. diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go deleted file mode 100644 index ca841ad9..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright (c) 2017 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 field implements fast arithmetic modulo 2^255-19. -package field - -import ( - "crypto/subtle" - "encoding/binary" - "math/bits" -) - -// Element represents an element of the field GF(2^255-19). Note that this -// is not a cryptographically secure group, and should only be used to interact -// with edwards25519.Point coordinates. -// -// This type works similarly to math/big.Int, and all arguments and receivers -// are allowed to alias. -// -// The zero value is a valid zero element. -type Element struct { - // An element t represents the integer - // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204 - // - // Between operations, all limbs are expected to be lower than 2^52. - l0 uint64 - l1 uint64 - l2 uint64 - l3 uint64 - l4 uint64 -} - -const maskLow51Bits uint64 = (1 << 51) - 1 - -var feZero = &Element{0, 0, 0, 0, 0} - -// Zero sets v = 0, and returns v. -func (v *Element) Zero() *Element { - *v = *feZero - return v -} - -var feOne = &Element{1, 0, 0, 0, 0} - -// One sets v = 1, and returns v. -func (v *Element) One() *Element { - *v = *feOne - return v -} - -// reduce reduces v modulo 2^255 - 19 and returns it. -func (v *Element) reduce() *Element { - v.carryPropagate() - - // After the light reduction we now have a field element representation - // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19. - - // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1, - // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise. - c := (v.l0 + 19) >> 51 - c = (v.l1 + c) >> 51 - c = (v.l2 + c) >> 51 - c = (v.l3 + c) >> 51 - c = (v.l4 + c) >> 51 - - // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's - // effectively applying the reduction identity to the carry. - v.l0 += 19 * c - - v.l1 += v.l0 >> 51 - v.l0 = v.l0 & maskLow51Bits - v.l2 += v.l1 >> 51 - v.l1 = v.l1 & maskLow51Bits - v.l3 += v.l2 >> 51 - v.l2 = v.l2 & maskLow51Bits - v.l4 += v.l3 >> 51 - v.l3 = v.l3 & maskLow51Bits - // no additional carry - v.l4 = v.l4 & maskLow51Bits - - return v -} - -// Add sets v = a + b, and returns v. -func (v *Element) Add(a, b *Element) *Element { - v.l0 = a.l0 + b.l0 - v.l1 = a.l1 + b.l1 - v.l2 = a.l2 + b.l2 - v.l3 = a.l3 + b.l3 - v.l4 = a.l4 + b.l4 - // Using the generic implementation here is actually faster than the - // assembly. Probably because the body of this function is so simple that - // the compiler can figure out better optimizations by inlining the carry - // propagation. TODO - return v.carryPropagateGeneric() -} - -// Subtract sets v = a - b, and returns v. -func (v *Element) Subtract(a, b *Element) *Element { - // We first add 2 * p, to guarantee the subtraction won't underflow, and - // then subtract b (which can be up to 2^255 + 2^13 * 19). - v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0 - v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1 - v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2 - v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3 - v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4 - return v.carryPropagate() -} - -// Negate sets v = -a, and returns v. -func (v *Element) Negate(a *Element) *Element { - return v.Subtract(feZero, a) -} - -// Invert sets v = 1/z mod p, and returns v. -// -// If z == 0, Invert returns v = 0. -func (v *Element) Invert(z *Element) *Element { - // Inversion is implemented as exponentiation with exponent p − 2. It uses the - // same sequence of 255 squarings and 11 multiplications as [Curve25519]. - var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element - - z2.Square(z) // 2 - t.Square(&z2) // 4 - t.Square(&t) // 8 - z9.Multiply(&t, z) // 9 - z11.Multiply(&z9, &z2) // 11 - t.Square(&z11) // 22 - z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 - - t.Square(&z2_5_0) // 2^6 - 2^1 - for i := 0; i < 4; i++ { - t.Square(&t) // 2^10 - 2^5 - } - z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 - - t.Square(&z2_10_0) // 2^11 - 2^1 - for i := 0; i < 9; i++ { - t.Square(&t) // 2^20 - 2^10 - } - z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 - - t.Square(&z2_20_0) // 2^21 - 2^1 - for i := 0; i < 19; i++ { - t.Square(&t) // 2^40 - 2^20 - } - t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 - - t.Square(&t) // 2^41 - 2^1 - for i := 0; i < 9; i++ { - t.Square(&t) // 2^50 - 2^10 - } - z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 - - t.Square(&z2_50_0) // 2^51 - 2^1 - for i := 0; i < 49; i++ { - t.Square(&t) // 2^100 - 2^50 - } - z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 - - t.Square(&z2_100_0) // 2^101 - 2^1 - for i := 0; i < 99; i++ { - t.Square(&t) // 2^200 - 2^100 - } - t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 - - t.Square(&t) // 2^201 - 2^1 - for i := 0; i < 49; i++ { - t.Square(&t) // 2^250 - 2^50 - } - t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 - - t.Square(&t) // 2^251 - 2^1 - t.Square(&t) // 2^252 - 2^2 - t.Square(&t) // 2^253 - 2^3 - t.Square(&t) // 2^254 - 2^4 - t.Square(&t) // 2^255 - 2^5 - - return v.Multiply(&t, &z11) // 2^255 - 21 -} - -// Set sets v = a, and returns v. -func (v *Element) Set(a *Element) *Element { - *v = *a - return v -} - -// SetBytes sets v to x, which must be a 32-byte little-endian encoding. -// -// Consistent with RFC 7748, the most significant bit (the high bit of the -// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1) -// are accepted. Note that this is laxer than specified by RFC 8032. -func (v *Element) SetBytes(x []byte) *Element { - if len(x) != 32 { - panic("edwards25519: invalid field element input size") - } - - // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). - v.l0 = binary.LittleEndian.Uint64(x[0:8]) - v.l0 &= maskLow51Bits - // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). - v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 - v.l1 &= maskLow51Bits - // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). - v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 - v.l2 &= maskLow51Bits - // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). - v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 - v.l3 &= maskLow51Bits - // Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51). - // Note: not bytes 25:33, shift 4, to avoid overread. - v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 - v.l4 &= maskLow51Bits - - return v -} - -// Bytes returns the canonical 32-byte little-endian encoding of v. -func (v *Element) Bytes() []byte { - // This function is outlined to make the allocations inline in the caller - // rather than happen on the heap. - var out [32]byte - return v.bytes(&out) -} - -func (v *Element) bytes(out *[32]byte) []byte { - t := *v - t.reduce() - - var buf [8]byte - for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { - bitsOffset := i * 51 - binary.LittleEndian.PutUint64(buf[:], l<= len(out) { - break - } - out[off] |= bb - } - } - - return out[:] -} - -// Equal returns 1 if v and u are equal, and 0 otherwise. -func (v *Element) Equal(u *Element) int { - sa, sv := u.Bytes(), v.Bytes() - return subtle.ConstantTimeCompare(sa, sv) -} - -// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise. -func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) } - -// Select sets v to a if cond == 1, and to b if cond == 0. -func (v *Element) Select(a, b *Element, cond int) *Element { - m := mask64Bits(cond) - v.l0 = (m & a.l0) | (^m & b.l0) - v.l1 = (m & a.l1) | (^m & b.l1) - v.l2 = (m & a.l2) | (^m & b.l2) - v.l3 = (m & a.l3) | (^m & b.l3) - v.l4 = (m & a.l4) | (^m & b.l4) - return v -} - -// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v. -func (v *Element) Swap(u *Element, cond int) { - m := mask64Bits(cond) - t := m & (v.l0 ^ u.l0) - v.l0 ^= t - u.l0 ^= t - t = m & (v.l1 ^ u.l1) - v.l1 ^= t - u.l1 ^= t - t = m & (v.l2 ^ u.l2) - v.l2 ^= t - u.l2 ^= t - t = m & (v.l3 ^ u.l3) - v.l3 ^= t - u.l3 ^= t - t = m & (v.l4 ^ u.l4) - v.l4 ^= t - u.l4 ^= t -} - -// IsNegative returns 1 if v is negative, and 0 otherwise. -func (v *Element) IsNegative() int { - return int(v.Bytes()[0] & 1) -} - -// Absolute sets v to |u|, and returns v. -func (v *Element) Absolute(u *Element) *Element { - return v.Select(new(Element).Negate(u), u, u.IsNegative()) -} - -// Multiply sets v = x * y, and returns v. -func (v *Element) Multiply(x, y *Element) *Element { - feMul(v, x, y) - return v -} - -// Square sets v = x * x, and returns v. -func (v *Element) Square(x *Element) *Element { - feSquare(v, x) - return v -} - -// Mult32 sets v = x * y, and returns v. -func (v *Element) Mult32(x *Element, y uint32) *Element { - x0lo, x0hi := mul51(x.l0, y) - x1lo, x1hi := mul51(x.l1, y) - x2lo, x2hi := mul51(x.l2, y) - x3lo, x3hi := mul51(x.l3, y) - x4lo, x4hi := mul51(x.l4, y) - v.l0 = x0lo + 19*x4hi // carried over per the reduction identity - v.l1 = x1lo + x0hi - v.l2 = x2lo + x1hi - v.l3 = x3lo + x2hi - v.l4 = x4lo + x3hi - // The hi portions are going to be only 32 bits, plus any previous excess, - // so we can skip the carry propagation. - return v -} - -// mul51 returns lo + hi * 2⁵¹ = a * b. -func mul51(a uint64, b uint32) (lo uint64, hi uint64) { - mh, ml := bits.Mul64(a, uint64(b)) - lo = ml & maskLow51Bits - hi = (mh << 13) | (ml >> 51) - return -} - -// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3. -func (v *Element) Pow22523(x *Element) *Element { - var t0, t1, t2 Element - - t0.Square(x) // x^2 - t1.Square(&t0) // x^4 - t1.Square(&t1) // x^8 - t1.Multiply(x, &t1) // x^9 - t0.Multiply(&t0, &t1) // x^11 - t0.Square(&t0) // x^22 - t0.Multiply(&t1, &t0) // x^31 - t1.Square(&t0) // x^62 - for i := 1; i < 5; i++ { // x^992 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 - t1.Square(&t0) // 2^11 - 2 - for i := 1; i < 10; i++ { // 2^20 - 2^10 - t1.Square(&t1) - } - t1.Multiply(&t1, &t0) // 2^20 - 1 - t2.Square(&t1) // 2^21 - 2 - for i := 1; i < 20; i++ { // 2^40 - 2^20 - t2.Square(&t2) - } - t1.Multiply(&t2, &t1) // 2^40 - 1 - t1.Square(&t1) // 2^41 - 2 - for i := 1; i < 10; i++ { // 2^50 - 2^10 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // 2^50 - 1 - t1.Square(&t0) // 2^51 - 2 - for i := 1; i < 50; i++ { // 2^100 - 2^50 - t1.Square(&t1) - } - t1.Multiply(&t1, &t0) // 2^100 - 1 - t2.Square(&t1) // 2^101 - 2 - for i := 1; i < 100; i++ { // 2^200 - 2^100 - t2.Square(&t2) - } - t1.Multiply(&t2, &t1) // 2^200 - 1 - t1.Square(&t1) // 2^201 - 2 - for i := 1; i < 50; i++ { // 2^250 - 2^50 - t1.Square(&t1) - } - t0.Multiply(&t1, &t0) // 2^250 - 1 - t0.Square(&t0) // 2^251 - 2 - t0.Square(&t0) // 2^252 - 4 - return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) -} - -// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. -var sqrtM1 = &Element{1718705420411056, 234908883556509, - 2233514472574048, 2117202627021982, 765476049583133} - -// SqrtRatio sets r to the non-negative square root of the ratio of u and v. -// -// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio -// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, -// and returns r and 0. -func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) { - var a, b Element - - // r = (u * v3) * (u * v7)^((p-5)/8) - v2 := a.Square(v) - uv3 := b.Multiply(u, b.Multiply(v2, v)) - uv7 := a.Multiply(uv3, a.Square(v2)) - r.Multiply(uv3, r.Pow22523(uv7)) - - check := a.Multiply(v, a.Square(r)) // check = v * r^2 - - uNeg := b.Negate(u) - correctSignSqrt := check.Equal(u) - flippedSignSqrt := check.Equal(uNeg) - flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1)) - - rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r - // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) - r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI) - - r.Absolute(r) // Choose the nonnegative square root. - return r, correctSignSqrt | flippedSignSqrt -} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go deleted file mode 100644 index edcf163c..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. - -//go:build amd64 && gc && !purego -// +build amd64,gc,!purego - -package field - -// feMul sets out = a * b. It works like feMulGeneric. -// -//go:noescape -func feMul(out *Element, a *Element, b *Element) - -// feSquare sets out = a * a. It works like feSquareGeneric. -// -//go:noescape -func feSquare(out *Element, a *Element) diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s deleted file mode 100644 index 293f013c..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s +++ /dev/null @@ -1,379 +0,0 @@ -// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. - -//go:build amd64 && gc && !purego -// +build amd64,gc,!purego - -#include "textflag.h" - -// func feMul(out *Element, a *Element, b *Element) -TEXT ·feMul(SB), NOSPLIT, $0-24 - MOVQ a+8(FP), CX - MOVQ b+16(FP), BX - - // r0 = a0×b0 - MOVQ (CX), AX - MULQ (BX) - MOVQ AX, DI - MOVQ DX, SI - - // r0 += 19×a1×b4 - MOVQ 8(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r0 += 19×a2×b3 - MOVQ 16(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r0 += 19×a3×b2 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 16(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r0 += 19×a4×b1 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 8(BX) - ADDQ AX, DI - ADCQ DX, SI - - // r1 = a0×b1 - MOVQ (CX), AX - MULQ 8(BX) - MOVQ AX, R9 - MOVQ DX, R8 - - // r1 += a1×b0 - MOVQ 8(CX), AX - MULQ (BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r1 += 19×a2×b4 - MOVQ 16(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r1 += 19×a3×b3 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r1 += 19×a4×b2 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 16(BX) - ADDQ AX, R9 - ADCQ DX, R8 - - // r2 = a0×b2 - MOVQ (CX), AX - MULQ 16(BX) - MOVQ AX, R11 - MOVQ DX, R10 - - // r2 += a1×b1 - MOVQ 8(CX), AX - MULQ 8(BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r2 += a2×b0 - MOVQ 16(CX), AX - MULQ (BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r2 += 19×a3×b4 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r2 += 19×a4×b3 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, R11 - ADCQ DX, R10 - - // r3 = a0×b3 - MOVQ (CX), AX - MULQ 24(BX) - MOVQ AX, R13 - MOVQ DX, R12 - - // r3 += a1×b2 - MOVQ 8(CX), AX - MULQ 16(BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r3 += a2×b1 - MOVQ 16(CX), AX - MULQ 8(BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r3 += a3×b0 - MOVQ 24(CX), AX - MULQ (BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r3 += 19×a4×b4 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R13 - ADCQ DX, R12 - - // r4 = a0×b4 - MOVQ (CX), AX - MULQ 32(BX) - MOVQ AX, R15 - MOVQ DX, R14 - - // r4 += a1×b3 - MOVQ 8(CX), AX - MULQ 24(BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // r4 += a2×b2 - MOVQ 16(CX), AX - MULQ 16(BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // r4 += a3×b1 - MOVQ 24(CX), AX - MULQ 8(BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // r4 += a4×b0 - MOVQ 32(CX), AX - MULQ (BX) - ADDQ AX, R15 - ADCQ DX, R14 - - // First reduction chain - MOVQ $0x0007ffffffffffff, AX - SHLQ $0x0d, DI, SI - SHLQ $0x0d, R9, R8 - SHLQ $0x0d, R11, R10 - SHLQ $0x0d, R13, R12 - SHLQ $0x0d, R15, R14 - ANDQ AX, DI - IMUL3Q $0x13, R14, R14 - ADDQ R14, DI - ANDQ AX, R9 - ADDQ SI, R9 - ANDQ AX, R11 - ADDQ R8, R11 - ANDQ AX, R13 - ADDQ R10, R13 - ANDQ AX, R15 - ADDQ R12, R15 - - // Second reduction chain (carryPropagate) - MOVQ DI, SI - SHRQ $0x33, SI - MOVQ R9, R8 - SHRQ $0x33, R8 - MOVQ R11, R10 - SHRQ $0x33, R10 - MOVQ R13, R12 - SHRQ $0x33, R12 - MOVQ R15, R14 - SHRQ $0x33, R14 - ANDQ AX, DI - IMUL3Q $0x13, R14, R14 - ADDQ R14, DI - ANDQ AX, R9 - ADDQ SI, R9 - ANDQ AX, R11 - ADDQ R8, R11 - ANDQ AX, R13 - ADDQ R10, R13 - ANDQ AX, R15 - ADDQ R12, R15 - - // Store output - MOVQ out+0(FP), AX - MOVQ DI, (AX) - MOVQ R9, 8(AX) - MOVQ R11, 16(AX) - MOVQ R13, 24(AX) - MOVQ R15, 32(AX) - RET - -// func feSquare(out *Element, a *Element) -TEXT ·feSquare(SB), NOSPLIT, $0-16 - MOVQ a+8(FP), CX - - // r0 = l0×l0 - MOVQ (CX), AX - MULQ (CX) - MOVQ AX, SI - MOVQ DX, BX - - // r0 += 38×l1×l4 - MOVQ 8(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, SI - ADCQ DX, BX - - // r0 += 38×l2×l3 - MOVQ 16(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 24(CX) - ADDQ AX, SI - ADCQ DX, BX - - // r1 = 2×l0×l1 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 8(CX) - MOVQ AX, R8 - MOVQ DX, DI - - // r1 += 38×l2×l4 - MOVQ 16(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, R8 - ADCQ DX, DI - - // r1 += 19×l3×l3 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(CX) - ADDQ AX, R8 - ADCQ DX, DI - - // r2 = 2×l0×l2 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 16(CX) - MOVQ AX, R10 - MOVQ DX, R9 - - // r2 += l1×l1 - MOVQ 8(CX), AX - MULQ 8(CX) - ADDQ AX, R10 - ADCQ DX, R9 - - // r2 += 38×l3×l4 - MOVQ 24(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, R10 - ADCQ DX, R9 - - // r3 = 2×l0×l3 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 24(CX) - MOVQ AX, R12 - MOVQ DX, R11 - - // r3 += 2×l1×l2 - MOVQ 8(CX), AX - IMUL3Q $0x02, AX, AX - MULQ 16(CX) - ADDQ AX, R12 - ADCQ DX, R11 - - // r3 += 19×l4×l4 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(CX) - ADDQ AX, R12 - ADCQ DX, R11 - - // r4 = 2×l0×l4 - MOVQ (CX), AX - SHLQ $0x01, AX - MULQ 32(CX) - MOVQ AX, R14 - MOVQ DX, R13 - - // r4 += 2×l1×l3 - MOVQ 8(CX), AX - IMUL3Q $0x02, AX, AX - MULQ 24(CX) - ADDQ AX, R14 - ADCQ DX, R13 - - // r4 += l2×l2 - MOVQ 16(CX), AX - MULQ 16(CX) - ADDQ AX, R14 - ADCQ DX, R13 - - // First reduction chain - MOVQ $0x0007ffffffffffff, AX - SHLQ $0x0d, SI, BX - SHLQ $0x0d, R8, DI - SHLQ $0x0d, R10, R9 - SHLQ $0x0d, R12, R11 - SHLQ $0x0d, R14, R13 - ANDQ AX, SI - IMUL3Q $0x13, R13, R13 - ADDQ R13, SI - ANDQ AX, R8 - ADDQ BX, R8 - ANDQ AX, R10 - ADDQ DI, R10 - ANDQ AX, R12 - ADDQ R9, R12 - ANDQ AX, R14 - ADDQ R11, R14 - - // Second reduction chain (carryPropagate) - MOVQ SI, BX - SHRQ $0x33, BX - MOVQ R8, DI - SHRQ $0x33, DI - MOVQ R10, R9 - SHRQ $0x33, R9 - MOVQ R12, R11 - SHRQ $0x33, R11 - MOVQ R14, R13 - SHRQ $0x33, R13 - ANDQ AX, SI - IMUL3Q $0x13, R13, R13 - ADDQ R13, SI - ANDQ AX, R8 - ADDQ BX, R8 - ANDQ AX, R10 - ADDQ DI, R10 - ANDQ AX, R12 - ADDQ R9, R12 - ANDQ AX, R14 - ADDQ R11, R14 - - // Store output - MOVQ out+0(FP), AX - MOVQ SI, (AX) - MOVQ R8, 8(AX) - MOVQ R10, 16(AX) - MOVQ R12, 24(AX) - MOVQ R14, 32(AX) - RET diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go deleted file mode 100644 index ddb6c9b8..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !amd64 || !gc || purego -// +build !amd64 !gc purego - -package field - -func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } - -func feSquare(v, x *Element) { feSquareGeneric(v, x) } diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go deleted file mode 100644 index af459ef5..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2020 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. - -//go:build arm64 && gc && !purego -// +build arm64,gc,!purego - -package field - -//go:noescape -func carryPropagate(v *Element) - -func (v *Element) carryPropagate() *Element { - carryPropagate(v) - return v -} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s deleted file mode 100644 index 5c91e458..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2020 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. - -//go:build arm64 && gc && !purego -// +build arm64,gc,!purego - -#include "textflag.h" - -// carryPropagate works exactly like carryPropagateGeneric and uses the -// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but -// avoids loading R0-R4 twice and uses LDP and STP. -// -// See https://golang.org/issues/43145 for the main compiler issue. -// -// func carryPropagate(v *Element) -TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8 - MOVD v+0(FP), R20 - - LDP 0(R20), (R0, R1) - LDP 16(R20), (R2, R3) - MOVD 32(R20), R4 - - AND $0x7ffffffffffff, R0, R10 - AND $0x7ffffffffffff, R1, R11 - AND $0x7ffffffffffff, R2, R12 - AND $0x7ffffffffffff, R3, R13 - AND $0x7ffffffffffff, R4, R14 - - ADD R0>>51, R11, R11 - ADD R1>>51, R12, R12 - ADD R2>>51, R13, R13 - ADD R3>>51, R14, R14 - // R4>>51 * 19 + R10 -> R10 - LSR $51, R4, R21 - MOVD $19, R22 - MADD R22, R10, R21, R10 - - STP (R10, R11), 0(R20) - STP (R12, R13), 16(R20) - MOVD R14, 32(R20) - - RET diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go deleted file mode 100644 index 234a5b2e..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2021 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. - -//go:build !arm64 || !gc || purego -// +build !arm64 !gc purego - -package field - -func (v *Element) carryPropagate() *Element { - return v.carryPropagateGeneric() -} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go deleted file mode 100644 index 7b5b78cb..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2017 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 field - -import "math/bits" - -// uint128 holds a 128-bit number as two 64-bit limbs, for use with the -// bits.Mul64 and bits.Add64 intrinsics. -type uint128 struct { - lo, hi uint64 -} - -// mul64 returns a * b. -func mul64(a, b uint64) uint128 { - hi, lo := bits.Mul64(a, b) - return uint128{lo, hi} -} - -// addMul64 returns v + a * b. -func addMul64(v uint128, a, b uint64) uint128 { - hi, lo := bits.Mul64(a, b) - lo, c := bits.Add64(lo, v.lo, 0) - hi, _ = bits.Add64(hi, v.hi, c) - return uint128{lo, hi} -} - -// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. -func shiftRightBy51(a uint128) uint64 { - return (a.hi << (64 - 51)) | (a.lo >> 51) -} - -func feMulGeneric(v, a, b *Element) { - a0 := a.l0 - a1 := a.l1 - a2 := a.l2 - a3 := a.l3 - a4 := a.l4 - - b0 := b.l0 - b1 := b.l1 - b2 := b.l2 - b3 := b.l3 - b4 := b.l4 - - // Limb multiplication works like pen-and-paper columnar multiplication, but - // with 51-bit limbs instead of digits. - // - // a4 a3 a2 a1 a0 x - // b4 b3 b2 b1 b0 = - // ------------------------ - // a4b0 a3b0 a2b0 a1b0 a0b0 + - // a4b1 a3b1 a2b1 a1b1 a0b1 + - // a4b2 a3b2 a2b2 a1b2 a0b2 + - // a4b3 a3b3 a2b3 a1b3 a0b3 + - // a4b4 a3b4 a2b4 a1b4 a0b4 = - // ---------------------------------------------- - // r8 r7 r6 r5 r4 r3 r2 r1 r0 - // - // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to - // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5, - // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc. - // - // Reduction can be carried out simultaneously to multiplication. For - // example, we do not compute r5: whenever the result of a multiplication - // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0. - // - // a4b0 a3b0 a2b0 a1b0 a0b0 + - // a3b1 a2b1 a1b1 a0b1 19×a4b1 + - // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 + - // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 + - // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 = - // -------------------------------------- - // r4 r3 r2 r1 r0 - // - // Finally we add up the columns into wide, overlapping limbs. - - a1_19 := a1 * 19 - a2_19 := a2 * 19 - a3_19 := a3 * 19 - a4_19 := a4 * 19 - - // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) - r0 := mul64(a0, b0) - r0 = addMul64(r0, a1_19, b4) - r0 = addMul64(r0, a2_19, b3) - r0 = addMul64(r0, a3_19, b2) - r0 = addMul64(r0, a4_19, b1) - - // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2) - r1 := mul64(a0, b1) - r1 = addMul64(r1, a1, b0) - r1 = addMul64(r1, a2_19, b4) - r1 = addMul64(r1, a3_19, b3) - r1 = addMul64(r1, a4_19, b2) - - // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3) - r2 := mul64(a0, b2) - r2 = addMul64(r2, a1, b1) - r2 = addMul64(r2, a2, b0) - r2 = addMul64(r2, a3_19, b4) - r2 = addMul64(r2, a4_19, b3) - - // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4 - r3 := mul64(a0, b3) - r3 = addMul64(r3, a1, b2) - r3 = addMul64(r3, a2, b1) - r3 = addMul64(r3, a3, b0) - r3 = addMul64(r3, a4_19, b4) - - // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 - r4 := mul64(a0, b4) - r4 = addMul64(r4, a1, b3) - r4 = addMul64(r4, a2, b2) - r4 = addMul64(r4, a3, b1) - r4 = addMul64(r4, a4, b0) - - // After the multiplication, we need to reduce (carry) the five coefficients - // to obtain a result with limbs that are at most slightly larger than 2⁵¹, - // to respect the Element invariant. - // - // Overall, the reduction works the same as carryPropagate, except with - // wider inputs: we take the carry for each coefficient by shifting it right - // by 51, and add it to the limb above it. The top carry is multiplied by 19 - // according to the reduction identity and added to the lowest limb. - // - // The largest coefficient (r0) will be at most 111 bits, which guarantees - // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64. - // - // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) - // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²) - // r0 < (1 + 19 × 4) × 2⁵² × 2⁵² - // r0 < 2⁷ × 2⁵² × 2⁵² - // r0 < 2¹¹¹ - // - // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most - // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and - // allows us to easily apply the reduction identity. - // - // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 - // r4 < 5 × 2⁵² × 2⁵² - // r4 < 2¹⁰⁷ - // - - c0 := shiftRightBy51(r0) - c1 := shiftRightBy51(r1) - c2 := shiftRightBy51(r2) - c3 := shiftRightBy51(r3) - c4 := shiftRightBy51(r4) - - rr0 := r0.lo&maskLow51Bits + c4*19 - rr1 := r1.lo&maskLow51Bits + c0 - rr2 := r2.lo&maskLow51Bits + c1 - rr3 := r3.lo&maskLow51Bits + c2 - rr4 := r4.lo&maskLow51Bits + c3 - - // Now all coefficients fit into 64-bit registers but are still too large to - // be passed around as a Element. We therefore do one last carry chain, - // where the carries will be small enough to fit in the wiggle room above 2⁵¹. - *v = Element{rr0, rr1, rr2, rr3, rr4} - v.carryPropagate() -} - -func feSquareGeneric(v, a *Element) { - l0 := a.l0 - l1 := a.l1 - l2 := a.l2 - l3 := a.l3 - l4 := a.l4 - - // Squaring works precisely like multiplication above, but thanks to its - // symmetry we get to group a few terms together. - // - // l4 l3 l2 l1 l0 x - // l4 l3 l2 l1 l0 = - // ------------------------ - // l4l0 l3l0 l2l0 l1l0 l0l0 + - // l4l1 l3l1 l2l1 l1l1 l0l1 + - // l4l2 l3l2 l2l2 l1l2 l0l2 + - // l4l3 l3l3 l2l3 l1l3 l0l3 + - // l4l4 l3l4 l2l4 l1l4 l0l4 = - // ---------------------------------------------- - // r8 r7 r6 r5 r4 r3 r2 r1 r0 - // - // l4l0 l3l0 l2l0 l1l0 l0l0 + - // l3l1 l2l1 l1l1 l0l1 19×l4l1 + - // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 + - // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 + - // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 = - // -------------------------------------- - // r4 r3 r2 r1 r0 - // - // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with - // only three Mul64 and four Add64, instead of five and eight. - - l0_2 := l0 * 2 - l1_2 := l1 * 2 - - l1_38 := l1 * 38 - l2_38 := l2 * 38 - l3_38 := l3 * 38 - - l3_19 := l3 * 19 - l4_19 := l4 * 19 - - // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3) - r0 := mul64(l0, l0) - r0 = addMul64(r0, l1_38, l4) - r0 = addMul64(r0, l2_38, l3) - - // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 - r1 := mul64(l0_2, l1) - r1 = addMul64(r1, l2_38, l4) - r1 = addMul64(r1, l3_19, l3) - - // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4 - r2 := mul64(l0_2, l2) - r2 = addMul64(r2, l1, l1) - r2 = addMul64(r2, l3_38, l4) - - // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 - r3 := mul64(l0_2, l3) - r3 = addMul64(r3, l1_2, l2) - r3 = addMul64(r3, l4_19, l4) - - // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2 - r4 := mul64(l0_2, l4) - r4 = addMul64(r4, l1_2, l3) - r4 = addMul64(r4, l2, l2) - - c0 := shiftRightBy51(r0) - c1 := shiftRightBy51(r1) - c2 := shiftRightBy51(r2) - c3 := shiftRightBy51(r3) - c4 := shiftRightBy51(r4) - - rr0 := r0.lo&maskLow51Bits + c4*19 - rr1 := r1.lo&maskLow51Bits + c0 - rr2 := r2.lo&maskLow51Bits + c1 - rr3 := r3.lo&maskLow51Bits + c2 - rr4 := r4.lo&maskLow51Bits + c3 - - *v = Element{rr0, rr1, rr2, rr3, rr4} - v.carryPropagate() -} - -// carryPropagate brings the limbs below 52 bits by applying the reduction -// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. TODO inline -func (v *Element) carryPropagateGeneric() *Element { - c0 := v.l0 >> 51 - c1 := v.l1 >> 51 - c2 := v.l2 >> 51 - c3 := v.l3 >> 51 - c4 := v.l4 >> 51 - - v.l0 = v.l0&maskLow51Bits + c4*19 - v.l1 = v.l1&maskLow51Bits + c0 - v.l2 = v.l2&maskLow51Bits + c1 - v.l3 = v.l3&maskLow51Bits + c2 - v.l4 = v.l4&maskLow51Bits + c3 - - return v -} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint b/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint deleted file mode 100644 index e3685f95..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint +++ /dev/null @@ -1 +0,0 @@ -b0c49ae9f59d233526f8934262c5bbbe14d4358d diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh b/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh deleted file mode 100644 index 1ba22a8b..00000000 --- a/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/bash -set -euo pipefail - -cd "$(git rev-parse --show-toplevel)" - -STD_PATH=src/crypto/ed25519/internal/edwards25519/field -LOCAL_PATH=curve25519/internal/field -LAST_SYNC_REF=$(cat $LOCAL_PATH/sync.checkpoint) - -git fetch https://go.googlesource.com/go master - -if git diff --quiet $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH; then - echo "No changes." -else - NEW_REF=$(git rev-parse FETCH_HEAD | tee $LOCAL_PATH/sync.checkpoint) - echo "Applying changes from $LAST_SYNC_REF to $NEW_REF..." - git diff $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH | \ - git apply -3 --directory=$LOCAL_PATH -fi diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go deleted file mode 100644 index 45b5c966..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.13 -// +build !go1.13 - -package poly1305 - -// Generic fallbacks for the math/bits intrinsics, copied from -// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had -// variable time fallbacks until Go 1.13. - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - sum = x + y + carry - carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 - return -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - diff = x - y - borrow - borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 - return -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - const mask32 = 1<<32 - 1 - x0 := x & mask32 - x1 := x >> 32 - y0 := y & mask32 - y1 := y >> 32 - w0 := x0 * y0 - t := x1*y0 + w0>>32 - w1 := t & mask32 - w2 := t >> 32 - w1 += x0 * y1 - hi = x1*y1 + w2 + w1>>32 - lo = x * y - return -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go deleted file mode 100644 index ed52b341..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.13 -// +build go1.13 - -package poly1305 - -import "math/bits" - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - return bits.Add64(x, y, carry) -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - return bits.Sub64(x, y, borrow) -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - return bits.Mul64(x, y) -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go deleted file mode 100644 index f184b67d..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018 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. - -//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego -// +build !amd64,!ppc64le,!s390x !gc purego - -package poly1305 - -type mac struct{ macGeneric } diff --git a/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go b/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go deleted file mode 100644 index 4aaea810..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go +++ /dev/null @@ -1,99 +0,0 @@ -// 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 poly1305 implements Poly1305 one-time message authentication code as -// specified in https://cr.yp.to/mac/poly1305-20050329.pdf. -// -// Poly1305 is a fast, one-time authentication function. It is infeasible for an -// attacker to generate an authenticator for a message without the key. However, a -// key must only be used for a single message. Authenticating two different -// messages with the same key allows an attacker to forge authenticators for other -// messages with the same key. -// -// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was -// used with a fixed key in order to generate one-time keys from an nonce. -// However, in this package AES isn't used and the one-time key is specified -// directly. -package poly1305 - -import "crypto/subtle" - -// TagSize is the size, in bytes, of a poly1305 authenticator. -const TagSize = 16 - -// Sum generates an authenticator for msg using a one-time key and puts the -// 16-byte result into out. Authenticating two different messages with the same -// key allows an attacker to forge messages at will. -func Sum(out *[16]byte, m []byte, key *[32]byte) { - h := New(key) - h.Write(m) - h.Sum(out[:0]) -} - -// Verify returns true if mac is a valid authenticator for m with the given key. -func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { - var tmp [16]byte - Sum(&tmp, m, key) - return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 -} - -// New returns a new MAC computing an authentication -// tag of all data written to it with the given key. -// This allows writing the message progressively instead -// of passing it as a single slice. Common users should use -// the Sum function instead. -// -// The key must be unique for each message, as authenticating -// two different messages with the same key allows an attacker -// to forge messages at will. -func New(key *[32]byte) *MAC { - m := &MAC{} - initialize(key, &m.macState) - return m -} - -// MAC is an io.Writer computing an authentication tag -// of the data written to it. -// -// MAC cannot be used like common hash.Hash implementations, -// because using a poly1305 key twice breaks its security. -// Therefore writing data to a running MAC after calling -// Sum or Verify causes it to panic. -type MAC struct { - mac // platform-dependent implementation - - finalized bool -} - -// Size returns the number of bytes Sum will return. -func (h *MAC) Size() int { return TagSize } - -// Write adds more data to the running message authentication code. -// It never returns an error. -// -// It must not be called after the first call of Sum or Verify. -func (h *MAC) Write(p []byte) (n int, err error) { - if h.finalized { - panic("poly1305: write to MAC after Sum or Verify") - } - return h.mac.Write(p) -} - -// Sum computes the authenticator of all data written to the -// message authentication code. -func (h *MAC) Sum(b []byte) []byte { - var mac [TagSize]byte - h.mac.Sum(&mac) - h.finalized = true - return append(b, mac[:]...) -} - -// Verify returns whether the authenticator of all data written to -// the message authentication code matches the expected value. -func (h *MAC) Verify(expected []byte) bool { - var mac [TagSize]byte - h.mac.Sum(&mac) - h.finalized = true - return subtle.ConstantTimeCompare(expected, mac[:]) == 1 -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go deleted file mode 100644 index 6d522333..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - -//go:build gc && !purego -// +build gc,!purego - -package poly1305 - -//go:noescape -func update(state *macState, msg []byte) - -// mac is a wrapper for macGeneric that redirects calls that would have gone to -// updateGeneric to update. -// -// Its Write and Sum methods are otherwise identical to the macGeneric ones, but -// using function pointers would carry a major performance cost. -type mac struct{ macGeneric } - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - update(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - update(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -func (h *mac) Sum(out *[16]byte) { - state := h.macState - if h.offset > 0 { - update(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s deleted file mode 100644 index 1d74f0f8..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s +++ /dev/null @@ -1,109 +0,0 @@ -// 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. - -//go:build gc && !purego -// +build gc,!purego - -#include "textflag.h" - -#define POLY1305_ADD(msg, h0, h1, h2) \ - ADDQ 0(msg), h0; \ - ADCQ 8(msg), h1; \ - ADCQ $1, h2; \ - LEAQ 16(msg), msg - -#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \ - MOVQ r0, AX; \ - MULQ h0; \ - MOVQ AX, t0; \ - MOVQ DX, t1; \ - MOVQ r0, AX; \ - MULQ h1; \ - ADDQ AX, t1; \ - ADCQ $0, DX; \ - MOVQ r0, t2; \ - IMULQ h2, t2; \ - ADDQ DX, t2; \ - \ - MOVQ r1, AX; \ - MULQ h0; \ - ADDQ AX, t1; \ - ADCQ $0, DX; \ - MOVQ DX, h0; \ - MOVQ r1, t3; \ - IMULQ h2, t3; \ - MOVQ r1, AX; \ - MULQ h1; \ - ADDQ AX, t2; \ - ADCQ DX, t3; \ - ADDQ h0, t2; \ - ADCQ $0, t3; \ - \ - MOVQ t0, h0; \ - MOVQ t1, h1; \ - MOVQ t2, h2; \ - ANDQ $3, h2; \ - MOVQ t2, t0; \ - ANDQ $0xFFFFFFFFFFFFFFFC, t0; \ - ADDQ t0, h0; \ - ADCQ t3, h1; \ - ADCQ $0, h2; \ - SHRQ $2, t3, t2; \ - SHRQ $2, t3; \ - ADDQ t2, h0; \ - ADCQ t3, h1; \ - ADCQ $0, h2 - -// func update(state *[7]uint64, msg []byte) -TEXT ·update(SB), $0-32 - MOVQ state+0(FP), DI - MOVQ msg_base+8(FP), SI - MOVQ msg_len+16(FP), R15 - - MOVQ 0(DI), R8 // h0 - MOVQ 8(DI), R9 // h1 - MOVQ 16(DI), R10 // h2 - MOVQ 24(DI), R11 // r0 - MOVQ 32(DI), R12 // r1 - - CMPQ R15, $16 - JB bytes_between_0_and_15 - -loop: - POLY1305_ADD(SI, R8, R9, R10) - -multiply: - POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) - SUBQ $16, R15 - CMPQ R15, $16 - JAE loop - -bytes_between_0_and_15: - TESTQ R15, R15 - JZ done - MOVQ $1, BX - XORQ CX, CX - XORQ R13, R13 - ADDQ R15, SI - -flush_buffer: - SHLQ $8, BX, CX - SHLQ $8, BX - MOVB -1(SI), R13 - XORQ R13, BX - DECQ SI - DECQ R15 - JNZ flush_buffer - - ADDQ BX, R8 - ADCQ CX, R9 - ADCQ $0, R10 - MOVQ $16, R15 - JMP multiply - -done: - MOVQ R8, 0(DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - RET diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go deleted file mode 100644 index e041da5e..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2018 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. - -// This file provides the generic implementation of Sum and MAC. Other files -// might provide optimized assembly implementations of some of this code. - -package poly1305 - -import "encoding/binary" - -// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag -// for a 64 bytes message is approximately -// -// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5 -// -// for some secret r and s. It can be computed sequentially like -// -// for len(msg) > 0: -// h += read(msg, 16) -// h *= r -// h %= 2¹³⁰ - 5 -// return h + s -// -// All the complexity is about doing performant constant-time math on numbers -// larger than any available numeric type. - -func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { - h := newMACGeneric(key) - h.Write(msg) - h.Sum(out) -} - -func newMACGeneric(key *[32]byte) macGeneric { - m := macGeneric{} - initialize(key, &m.macState) - return m -} - -// macState holds numbers in saturated 64-bit little-endian limbs. That is, -// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸. -type macState struct { - // h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but - // can grow larger during and after rounds. It must, however, remain below - // 2 * (2¹³⁰ - 5). - h [3]uint64 - // r and s are the private key components. - r [2]uint64 - s [2]uint64 -} - -type macGeneric struct { - macState - - buffer [TagSize]byte - offset int -} - -// Write splits the incoming message into TagSize chunks, and passes them to -// update. It buffers incomplete chunks. -func (h *macGeneric) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - updateGeneric(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - updateGeneric(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -// Sum flushes the last incomplete chunk from the buffer, if any, and generates -// the MAC output. It does not modify its state, in order to allow for multiple -// calls to Sum, even if no Write is allowed after Sum. -func (h *macGeneric) Sum(out *[TagSize]byte) { - state := h.macState - if h.offset > 0 { - updateGeneric(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} - -// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It -// clears some bits of the secret coefficient to make it possible to implement -// multiplication more efficiently. -const ( - rMask0 = 0x0FFFFFFC0FFFFFFF - rMask1 = 0x0FFFFFFC0FFFFFFC -) - -// initialize loads the 256-bit key into the two 128-bit secret values r and s. -func initialize(key *[32]byte, m *macState) { - m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 - m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 - m.s[0] = binary.LittleEndian.Uint64(key[16:24]) - m.s[1] = binary.LittleEndian.Uint64(key[24:32]) -} - -// uint128 holds a 128-bit number as two 64-bit limbs, for use with the -// bits.Mul64 and bits.Add64 intrinsics. -type uint128 struct { - lo, hi uint64 -} - -func mul64(a, b uint64) uint128 { - hi, lo := bitsMul64(a, b) - return uint128{lo, hi} -} - -func add128(a, b uint128) uint128 { - lo, c := bitsAdd64(a.lo, b.lo, 0) - hi, c := bitsAdd64(a.hi, b.hi, c) - if c != 0 { - panic("poly1305: unexpected overflow") - } - return uint128{lo, hi} -} - -func shiftRightBy2(a uint128) uint128 { - a.lo = a.lo>>2 | (a.hi&3)<<62 - a.hi = a.hi >> 2 - return a -} - -// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of -// 128 bits of message, it computes -// -// h₊ = (h + m) * r mod 2¹³⁰ - 5 -// -// If the msg length is not a multiple of TagSize, it assumes the last -// incomplete chunk is the final one. -func updateGeneric(state *macState, msg []byte) { - h0, h1, h2 := state.h[0], state.h[1], state.h[2] - r0, r1 := state.r[0], state.r[1] - - for len(msg) > 0 { - var c uint64 - - // For the first step, h + m, we use a chain of bits.Add64 intrinsics. - // The resulting value of h might exceed 2¹³⁰ - 5, but will be partially - // reduced at the end of the multiplication below. - // - // The spec requires us to set a bit just above the message size, not to - // hide leading zeroes. For full chunks, that's 1 << 128, so we can just - // add 1 to the most significant (2¹²⁸) limb, h2. - if len(msg) >= TagSize { - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) - h2 += c + 1 - - msg = msg[TagSize:] - } else { - var buf [TagSize]byte - copy(buf[:], msg) - buf[len(msg)] = 1 - - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) - h2 += c - - msg = nil - } - - // Multiplication of big number limbs is similar to elementary school - // columnar multiplication. Instead of digits, there are 64-bit limbs. - // - // We are multiplying a 3 limbs number, h, by a 2 limbs number, r. - // - // h2 h1 h0 x - // r1 r0 = - // ---------------- - // h2r0 h1r0 h0r0 <-- individual 128-bit products - // + h2r1 h1r1 h0r1 - // ------------------------ - // m3 m2 m1 m0 <-- result in 128-bit overlapping limbs - // ------------------------ - // m3.hi m2.hi m1.hi m0.hi <-- carry propagation - // + m3.lo m2.lo m1.lo m0.lo - // ------------------------------- - // t4 t3 t2 t1 t0 <-- final result in 64-bit limbs - // - // The main difference from pen-and-paper multiplication is that we do - // carry propagation in a separate step, as if we wrote two digit sums - // at first (the 128-bit limbs), and then carried the tens all at once. - - h0r0 := mul64(h0, r0) - h1r0 := mul64(h1, r0) - h2r0 := mul64(h2, r0) - h0r1 := mul64(h0, r1) - h1r1 := mul64(h1, r1) - h2r1 := mul64(h2, r1) - - // Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their - // top 4 bits cleared by rMask{0,1}, we know that their product is not going - // to overflow 64 bits, so we can ignore the high part of the products. - // - // This also means that the product doesn't have a fifth limb (t4). - if h2r0.hi != 0 { - panic("poly1305: unexpected overflow") - } - if h2r1.hi != 0 { - panic("poly1305: unexpected overflow") - } - - m0 := h0r0 - m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again - m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1. - m3 := h2r1 - - t0 := m0.lo - t1, c := bitsAdd64(m1.lo, m0.hi, 0) - t2, c := bitsAdd64(m2.lo, m1.hi, c) - t3, _ := bitsAdd64(m3.lo, m2.hi, c) - - // Now we have the result as 4 64-bit limbs, and we need to reduce it - // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do - // a cheap partial reduction according to the reduction identity - // - // c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5 - // - // because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is - // likely to be larger than 2¹³⁰ - 5, but still small enough to fit the - // assumptions we make about h in the rest of the code. - // - // See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23 - - // We split the final result at the 2¹³⁰ mark into h and cc, the carry. - // Note that the carry bits are effectively shifted left by 2, in other - // words, cc = c * 4 for the c in the reduction identity. - h0, h1, h2 = t0, t1, t2&maskLow2Bits - cc := uint128{t2 & maskNotLow2Bits, t3} - - // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. - - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) - h2 += c - - cc = shiftRightBy2(cc) - - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) - h2 += c - - // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most - // - // 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1 - } - - state.h[0], state.h[1], state.h[2] = h0, h1, h2 -} - -const ( - maskLow2Bits uint64 = 0x0000000000000003 - maskNotLow2Bits uint64 = ^maskLow2Bits -) - -// select64 returns x if v == 1 and y if v == 0, in constant time. -func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y } - -// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order. -const ( - p0 = 0xFFFFFFFFFFFFFFFB - p1 = 0xFFFFFFFFFFFFFFFF - p2 = 0x0000000000000003 -) - -// finalize completes the modular reduction of h and computes -// -// out = h + s mod 2¹²⁸ -func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { - h0, h1, h2 := h[0], h[1], h[2] - - // After the partial reduction in updateGeneric, h might be more than - // 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction - // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the - // result if the subtraction underflows, and t otherwise. - - hMinusP0, b := bitsSub64(h0, p0, 0) - hMinusP1, b := bitsSub64(h1, p1, b) - _, b = bitsSub64(h2, p2, b) - - // h = h if h < p else h - p - h0 = select64(b, h0, hMinusP0) - h1 = select64(b, h1, hMinusP1) - - // Finally, we compute the last Poly1305 step - // - // tag = h + s mod 2¹²⁸ - // - // by just doing a wide addition with the 128 low bits of h and discarding - // the overflow. - h0, c := bitsAdd64(h0, s[0], 0) - h1, _ = bitsAdd64(h1, s[1], c) - - binary.LittleEndian.PutUint64(out[0:8], h0) - binary.LittleEndian.PutUint64(out[8:16], h1) -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go deleted file mode 100644 index 4a069941..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego -// +build gc,!purego - -package poly1305 - -//go:noescape -func update(state *macState, msg []byte) - -// mac is a wrapper for macGeneric that redirects calls that would have gone to -// updateGeneric to update. -// -// Its Write and Sum methods are otherwise identical to the macGeneric ones, but -// using function pointers would carry a major performance cost. -type mac struct{ macGeneric } - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - update(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - update(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -func (h *mac) Sum(out *[16]byte) { - state := h.macState - if h.offset > 0 { - update(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s deleted file mode 100644 index 58422aad..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego -// +build gc,!purego - -#include "textflag.h" - -// This was ported from the amd64 implementation. - -#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \ - MOVD (msg), t0; \ - MOVD 8(msg), t1; \ - MOVD $1, t2; \ - ADDC t0, h0, h0; \ - ADDE t1, h1, h1; \ - ADDE t2, h2; \ - ADD $16, msg - -#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ - MULLD r0, h0, t0; \ - MULLD r0, h1, t4; \ - MULHDU r0, h0, t1; \ - MULHDU r0, h1, t5; \ - ADDC t4, t1, t1; \ - MULLD r0, h2, t2; \ - ADDZE t5; \ - MULHDU r1, h0, t4; \ - MULLD r1, h0, h0; \ - ADD t5, t2, t2; \ - ADDC h0, t1, t1; \ - MULLD h2, r1, t3; \ - ADDZE t4, h0; \ - MULHDU r1, h1, t5; \ - MULLD r1, h1, t4; \ - ADDC t4, t2, t2; \ - ADDE t5, t3, t3; \ - ADDC h0, t2, t2; \ - MOVD $-4, t4; \ - MOVD t0, h0; \ - MOVD t1, h1; \ - ADDZE t3; \ - ANDCC $3, t2, h2; \ - AND t2, t4, t0; \ - ADDC t0, h0, h0; \ - ADDE t3, h1, h1; \ - SLD $62, t3, t4; \ - SRD $2, t2; \ - ADDZE h2; \ - OR t4, t2, t2; \ - SRD $2, t3; \ - ADDC t2, h0, h0; \ - ADDE t3, h1, h1; \ - ADDZE h2 - -DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF -DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC -GLOBL ·poly1305Mask<>(SB), RODATA, $16 - -// func update(state *[7]uint64, msg []byte) -TEXT ·update(SB), $0-32 - MOVD state+0(FP), R3 - MOVD msg_base+8(FP), R4 - MOVD msg_len+16(FP), R5 - - MOVD 0(R3), R8 // h0 - MOVD 8(R3), R9 // h1 - MOVD 16(R3), R10 // h2 - MOVD 24(R3), R11 // r0 - MOVD 32(R3), R12 // r1 - - CMP R5, $16 - BLT bytes_between_0_and_15 - -loop: - POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) - -multiply: - POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) - ADD $-16, R5 - CMP R5, $16 - BGE loop - -bytes_between_0_and_15: - CMP R5, $0 - BEQ done - MOVD $0, R16 // h0 - MOVD $0, R17 // h1 - -flush_buffer: - CMP R5, $8 - BLE just1 - - MOVD $8, R21 - SUB R21, R5, R21 - - // Greater than 8 -- load the rightmost remaining bytes in msg - // and put into R17 (h1) - MOVD (R4)(R21), R17 - MOVD $16, R22 - - // Find the offset to those bytes - SUB R5, R22, R22 - SLD $3, R22 - - // Shift to get only the bytes in msg - SRD R22, R17, R17 - - // Put 1 at high end - MOVD $1, R23 - SLD $3, R21 - SLD R21, R23, R23 - OR R23, R17, R17 - - // Remainder is 8 - MOVD $8, R5 - -just1: - CMP R5, $8 - BLT less8 - - // Exactly 8 - MOVD (R4), R16 - - CMP R17, $0 - - // Check if we've already set R17; if not - // set 1 to indicate end of msg. - BNE carry - MOVD $1, R17 - BR carry - -less8: - MOVD $0, R16 // h0 - MOVD $0, R22 // shift count - CMP R5, $4 - BLT less4 - MOVWZ (R4), R16 - ADD $4, R4 - ADD $-4, R5 - MOVD $32, R22 - -less4: - CMP R5, $2 - BLT less2 - MOVHZ (R4), R21 - SLD R22, R21, R21 - OR R16, R21, R16 - ADD $16, R22 - ADD $-2, R5 - ADD $2, R4 - -less2: - CMP R5, $0 - BEQ insert1 - MOVBZ (R4), R21 - SLD R22, R21, R21 - OR R16, R21, R16 - ADD $8, R22 - -insert1: - // Insert 1 at end of msg - MOVD $1, R21 - SLD R22, R21, R21 - OR R16, R21, R16 - -carry: - // Add new values to h0, h1, h2 - ADDC R16, R8 - ADDE R17, R9 - ADDZE R10, R10 - MOVD $16, R5 - ADD R5, R4 - BR multiply - -done: - // Save h0, h1, h2 in state - MOVD R8, 0(R3) - MOVD R9, 8(R3) - MOVD R10, 16(R3) - RET diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go deleted file mode 100644 index ec959668..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 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. - -//go:build gc && !purego -// +build gc,!purego - -package poly1305 - -import ( - "golang.org/x/sys/cpu" -) - -// updateVX is an assembly implementation of Poly1305 that uses vector -// instructions. It must only be called if the vector facility (vx) is -// available. -// -//go:noescape -func updateVX(state *macState, msg []byte) - -// mac is a replacement for macGeneric that uses a larger buffer and redirects -// calls that would have gone to updateGeneric to updateVX if the vector -// facility is installed. -// -// A larger buffer is required for good performance because the vector -// implementation has a higher fixed cost per call than the generic -// implementation. -type mac struct { - macState - - buffer [16 * TagSize]byte // size must be a multiple of block size (16) - offset int -} - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < len(h.buffer) { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - if cpu.S390X.HasVX { - updateVX(&h.macState, h.buffer[:]) - } else { - updateGeneric(&h.macState, h.buffer[:]) - } - } - - tail := len(p) % len(h.buffer) // number of bytes to copy into buffer - body := len(p) - tail // number of bytes to process now - if body > 0 { - if cpu.S390X.HasVX { - updateVX(&h.macState, p[:body]) - } else { - updateGeneric(&h.macState, p[:body]) - } - } - h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0 - return nn, nil -} - -func (h *mac) Sum(out *[TagSize]byte) { - state := h.macState - remainder := h.buffer[:h.offset] - - // Use the generic implementation if we have 2 or fewer blocks left - // to sum. The vector implementation has a higher startup time. - if cpu.S390X.HasVX && len(remainder) > 2*TagSize { - updateVX(&state, remainder) - } else if len(remainder) > 0 { - updateGeneric(&state, remainder) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s deleted file mode 100644 index aa9e0494..00000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2018 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. - -//go:build gc && !purego -// +build gc,!purego - -#include "textflag.h" - -// This implementation of Poly1305 uses the vector facility (vx) -// to process up to 2 blocks (32 bytes) per iteration using an -// algorithm based on the one described in: -// -// NEON crypto, Daniel J. Bernstein & Peter Schwabe -// https://cryptojedi.org/papers/neoncrypto-20120320.pdf -// -// This algorithm uses 5 26-bit limbs to represent a 130-bit -// value. These limbs are, for the most part, zero extended and -// placed into 64-bit vector register elements. Each vector -// register is 128-bits wide and so holds 2 of these elements. -// Using 26-bit limbs allows us plenty of headroom to accommodate -// accumulations before and after multiplication without -// overflowing either 32-bits (before multiplication) or 64-bits -// (after multiplication). -// -// In order to parallelise the operations required to calculate -// the sum we use two separate accumulators and then sum those -// in an extra final step. For compatibility with the generic -// implementation we perform this summation at the end of every -// updateVX call. -// -// To use two accumulators we must multiply the message blocks -// by r² rather than r. Only the final message block should be -// multiplied by r. -// -// Example: -// -// We want to calculate the sum (h) for a 64 byte message (m): -// -// h = m[0:16]r⁴ + m[16:32]r³ + m[32:48]r² + m[48:64]r -// -// To do this we split the calculation into the even indices -// and odd indices of the message. These form our SIMD 'lanes': -// -// h = m[ 0:16]r⁴ + m[32:48]r² + <- lane 0 -// m[16:32]r³ + m[48:64]r <- lane 1 -// -// To calculate this iteratively we refactor so that both lanes -// are written in terms of r² and r: -// -// h = (m[ 0:16]r² + m[32:48])r² + <- lane 0 -// (m[16:32]r² + m[48:64])r <- lane 1 -// ^ ^ -// | coefficients for second iteration -// coefficients for first iteration -// -// So in this case we would have two iterations. In the first -// both lanes are multiplied by r². In the second only the -// first lane is multiplied by r² and the second lane is -// instead multiplied by r. This gives use the odd and even -// powers of r that we need from the original equation. -// -// Notation: -// -// h - accumulator -// r - key -// m - message -// -// [a, b] - SIMD register holding two 64-bit values -// [a, b, c, d] - SIMD register holding four 32-bit values -// xᵢ[n] - limb n of variable x with bit width i -// -// Limbs are expressed in little endian order, so for 26-bit -// limbs x₂₆[4] will be the most significant limb and x₂₆[0] -// will be the least significant limb. - -// masking constants -#define MOD24 V0 // [0x0000000000ffffff, 0x0000000000ffffff] - mask low 24-bits -#define MOD26 V1 // [0x0000000003ffffff, 0x0000000003ffffff] - mask low 26-bits - -// expansion constants (see EXPAND macro) -#define EX0 V2 -#define EX1 V3 -#define EX2 V4 - -// key (r², r or 1 depending on context) -#define R_0 V5 -#define R_1 V6 -#define R_2 V7 -#define R_3 V8 -#define R_4 V9 - -// precalculated coefficients (5r², 5r or 0 depending on context) -#define R5_1 V10 -#define R5_2 V11 -#define R5_3 V12 -#define R5_4 V13 - -// message block (m) -#define M_0 V14 -#define M_1 V15 -#define M_2 V16 -#define M_3 V17 -#define M_4 V18 - -// accumulator (h) -#define H_0 V19 -#define H_1 V20 -#define H_2 V21 -#define H_3 V22 -#define H_4 V23 - -// temporary registers (for short-lived values) -#define T_0 V24 -#define T_1 V25 -#define T_2 V26 -#define T_3 V27 -#define T_4 V28 - -GLOBL ·constants<>(SB), RODATA, $0x30 -// EX0 -DATA ·constants<>+0x00(SB)/8, $0x0006050403020100 -DATA ·constants<>+0x08(SB)/8, $0x1016151413121110 -// EX1 -DATA ·constants<>+0x10(SB)/8, $0x060c0b0a09080706 -DATA ·constants<>+0x18(SB)/8, $0x161c1b1a19181716 -// EX2 -DATA ·constants<>+0x20(SB)/8, $0x0d0d0d0d0d0f0e0d -DATA ·constants<>+0x28(SB)/8, $0x1d1d1d1d1d1f1e1d - -// MULTIPLY multiplies each lane of f and g, partially reduced -// modulo 2¹³⁰ - 5. The result, h, consists of partial products -// in each lane that need to be reduced further to produce the -// final result. -// -// h₁₃₀ = (f₁₃₀g₁₃₀) % 2¹³⁰ + (5f₁₃₀g₁₃₀) / 2¹³⁰ -// -// Note that the multiplication by 5 of the high bits is -// achieved by precalculating the multiplication of four of the -// g coefficients by 5. These are g51-g54. -#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ - VMLOF f0, g0, h0 \ - VMLOF f0, g3, h3 \ - VMLOF f0, g1, h1 \ - VMLOF f0, g4, h4 \ - VMLOF f0, g2, h2 \ - VMLOF f1, g54, T_0 \ - VMLOF f1, g2, T_3 \ - VMLOF f1, g0, T_1 \ - VMLOF f1, g3, T_4 \ - VMLOF f1, g1, T_2 \ - VMALOF f2, g53, h0, h0 \ - VMALOF f2, g1, h3, h3 \ - VMALOF f2, g54, h1, h1 \ - VMALOF f2, g2, h4, h4 \ - VMALOF f2, g0, h2, h2 \ - VMALOF f3, g52, T_0, T_0 \ - VMALOF f3, g0, T_3, T_3 \ - VMALOF f3, g53, T_1, T_1 \ - VMALOF f3, g1, T_4, T_4 \ - VMALOF f3, g54, T_2, T_2 \ - VMALOF f4, g51, h0, h0 \ - VMALOF f4, g54, h3, h3 \ - VMALOF f4, g52, h1, h1 \ - VMALOF f4, g0, h4, h4 \ - VMALOF f4, g53, h2, h2 \ - VAG T_0, h0, h0 \ - VAG T_3, h3, h3 \ - VAG T_1, h1, h1 \ - VAG T_4, h4, h4 \ - VAG T_2, h2, h2 - -// REDUCE performs the following carry operations in four -// stages, as specified in Bernstein & Schwabe: -// -// 1: h₂₆[0]->h₂₆[1] h₂₆[3]->h₂₆[4] -// 2: h₂₆[1]->h₂₆[2] h₂₆[4]->h₂₆[0] -// 3: h₂₆[0]->h₂₆[1] h₂₆[2]->h₂₆[3] -// 4: h₂₆[3]->h₂₆[4] -// -// The result is that all of the limbs are limited to 26-bits -// except for h₂₆[1] and h₂₆[4] which are limited to 27-bits. -// -// Note that although each limb is aligned at 26-bit intervals -// they may contain values that exceed 2²⁶ - 1, hence the need -// to carry the excess bits in each limb. -#define REDUCE(h0, h1, h2, h3, h4) \ - VESRLG $26, h0, T_0 \ - VESRLG $26, h3, T_1 \ - VN MOD26, h0, h0 \ - VN MOD26, h3, h3 \ - VAG T_0, h1, h1 \ - VAG T_1, h4, h4 \ - VESRLG $26, h1, T_2 \ - VESRLG $26, h4, T_3 \ - VN MOD26, h1, h1 \ - VN MOD26, h4, h4 \ - VESLG $2, T_3, T_4 \ - VAG T_3, T_4, T_4 \ - VAG T_2, h2, h2 \ - VAG T_4, h0, h0 \ - VESRLG $26, h2, T_0 \ - VESRLG $26, h0, T_1 \ - VN MOD26, h2, h2 \ - VN MOD26, h0, h0 \ - VAG T_0, h3, h3 \ - VAG T_1, h1, h1 \ - VESRLG $26, h3, T_2 \ - VN MOD26, h3, h3 \ - VAG T_2, h4, h4 - -// EXPAND splits the 128-bit little-endian values in0 and in1 -// into 26-bit big-endian limbs and places the results into -// the first and second lane of d₂₆[0:4] respectively. -// -// The EX0, EX1 and EX2 constants are arrays of byte indices -// for permutation. The permutation both reverses the bytes -// in the input and ensures the bytes are copied into the -// destination limb ready to be shifted into their final -// position. -#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ - VPERM in0, in1, EX0, d0 \ - VPERM in0, in1, EX1, d2 \ - VPERM in0, in1, EX2, d4 \ - VESRLG $26, d0, d1 \ - VESRLG $30, d2, d3 \ - VESRLG $4, d2, d2 \ - VN MOD26, d0, d0 \ // [in0₂₆[0], in1₂₆[0]] - VN MOD26, d3, d3 \ // [in0₂₆[3], in1₂₆[3]] - VN MOD26, d1, d1 \ // [in0₂₆[1], in1₂₆[1]] - VN MOD24, d4, d4 \ // [in0₂₆[4], in1₂₆[4]] - VN MOD26, d2, d2 // [in0₂₆[2], in1₂₆[2]] - -// func updateVX(state *macState, msg []byte) -TEXT ·updateVX(SB), NOSPLIT, $0 - MOVD state+0(FP), R1 - LMG msg+8(FP), R2, R3 // R2=msg_base, R3=msg_len - - // load EX0, EX1 and EX2 - MOVD $·constants<>(SB), R5 - VLM (R5), EX0, EX2 - - // generate masks - VGMG $(64-24), $63, MOD24 // [0x00ffffff, 0x00ffffff] - VGMG $(64-26), $63, MOD26 // [0x03ffffff, 0x03ffffff] - - // load h (accumulator) and r (key) from state - VZERO T_1 // [0, 0] - VL 0(R1), T_0 // [h₆₄[0], h₆₄[1]] - VLEG $0, 16(R1), T_1 // [h₆₄[2], 0] - VL 24(R1), T_2 // [r₆₄[0], r₆₄[1]] - VPDI $0, T_0, T_2, T_3 // [h₆₄[0], r₆₄[0]] - VPDI $5, T_0, T_2, T_4 // [h₆₄[1], r₆₄[1]] - - // unpack h and r into 26-bit limbs - // note: h₆₄[2] may have the low 3 bits set, so h₂₆[4] is a 27-bit value - VN MOD26, T_3, H_0 // [h₂₆[0], r₂₆[0]] - VZERO H_1 // [0, 0] - VZERO H_3 // [0, 0] - VGMG $(64-12-14), $(63-12), T_0 // [0x03fff000, 0x03fff000] - 26-bit mask with low 12 bits masked out - VESLG $24, T_1, T_1 // [h₆₄[2]<<24, 0] - VERIMG $-26&63, T_3, MOD26, H_1 // [h₂₆[1], r₂₆[1]] - VESRLG $+52&63, T_3, H_2 // [h₂₆[2], r₂₆[2]] - low 12 bits only - VERIMG $-14&63, T_4, MOD26, H_3 // [h₂₆[1], r₂₆[1]] - VESRLG $40, T_4, H_4 // [h₂₆[4], r₂₆[4]] - low 24 bits only - VERIMG $+12&63, T_4, T_0, H_2 // [h₂₆[2], r₂₆[2]] - complete - VO T_1, H_4, H_4 // [h₂₆[4], r₂₆[4]] - complete - - // replicate r across all 4 vector elements - VREPF $3, H_0, R_0 // [r₂₆[0], r₂₆[0], r₂₆[0], r₂₆[0]] - VREPF $3, H_1, R_1 // [r₂₆[1], r₂₆[1], r₂₆[1], r₂₆[1]] - VREPF $3, H_2, R_2 // [r₂₆[2], r₂₆[2], r₂₆[2], r₂₆[2]] - VREPF $3, H_3, R_3 // [r₂₆[3], r₂₆[3], r₂₆[3], r₂₆[3]] - VREPF $3, H_4, R_4 // [r₂₆[4], r₂₆[4], r₂₆[4], r₂₆[4]] - - // zero out lane 1 of h - VLEIG $1, $0, H_0 // [h₂₆[0], 0] - VLEIG $1, $0, H_1 // [h₂₆[1], 0] - VLEIG $1, $0, H_2 // [h₂₆[2], 0] - VLEIG $1, $0, H_3 // [h₂₆[3], 0] - VLEIG $1, $0, H_4 // [h₂₆[4], 0] - - // calculate 5r (ignore least significant limb) - VREPIF $5, T_0 - VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r₂₆[1], 5r₂₆[1], 5r₂₆[1]] - VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r₂₆[2], 5r₂₆[2], 5r₂₆[2]] - VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r₂₆[3], 5r₂₆[3], 5r₂₆[3]] - VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r₂₆[4], 5r₂₆[4], 5r₂₆[4]] - - // skip r² calculation if we are only calculating one block - CMPBLE R3, $16, skip - - // calculate r² - MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, M_0, M_1, M_2, M_3, M_4) - REDUCE(M_0, M_1, M_2, M_3, M_4) - VGBM $0x0f0f, T_0 - VERIMG $0, M_0, T_0, R_0 // [r₂₆[0], r²₂₆[0], r₂₆[0], r²₂₆[0]] - VERIMG $0, M_1, T_0, R_1 // [r₂₆[1], r²₂₆[1], r₂₆[1], r²₂₆[1]] - VERIMG $0, M_2, T_0, R_2 // [r₂₆[2], r²₂₆[2], r₂₆[2], r²₂₆[2]] - VERIMG $0, M_3, T_0, R_3 // [r₂₆[3], r²₂₆[3], r₂₆[3], r²₂₆[3]] - VERIMG $0, M_4, T_0, R_4 // [r₂₆[4], r²₂₆[4], r₂₆[4], r²₂₆[4]] - - // calculate 5r² (ignore least significant limb) - VREPIF $5, T_0 - VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r²₂₆[1], 5r₂₆[1], 5r²₂₆[1]] - VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r²₂₆[2], 5r₂₆[2], 5r²₂₆[2]] - VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r²₂₆[3], 5r₂₆[3], 5r²₂₆[3]] - VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r²₂₆[4], 5r₂₆[4], 5r²₂₆[4]] - -loop: - CMPBLE R3, $32, b2 // 2 or fewer blocks remaining, need to change key coefficients - - // load next 2 blocks from message - VLM (R2), T_0, T_1 - - // update message slice - SUB $32, R3 - MOVD $32(R2), R2 - - // unpack message blocks into 26-bit big-endian limbs - EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) - - // add 2¹²⁸ to each message block value - VLEIB $4, $1, M_4 - VLEIB $12, $1, M_4 - -multiply: - // accumulate the incoming message - VAG H_0, M_0, M_0 - VAG H_3, M_3, M_3 - VAG H_1, M_1, M_1 - VAG H_4, M_4, M_4 - VAG H_2, M_2, M_2 - - // multiply the accumulator by the key coefficient - MULTIPLY(M_0, M_1, M_2, M_3, M_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) - - // carry and partially reduce the partial products - REDUCE(H_0, H_1, H_2, H_3, H_4) - - CMPBNE R3, $0, loop - -finish: - // sum lane 0 and lane 1 and put the result in lane 1 - VZERO T_0 - VSUMQG H_0, T_0, H_0 - VSUMQG H_3, T_0, H_3 - VSUMQG H_1, T_0, H_1 - VSUMQG H_4, T_0, H_4 - VSUMQG H_2, T_0, H_2 - - // reduce again after summation - // TODO(mundaym): there might be a more efficient way to do this - // now that we only have 1 active lane. For example, we could - // simultaneously pack the values as we reduce them. - REDUCE(H_0, H_1, H_2, H_3, H_4) - - // carry h[1] through to h[4] so that only h[4] can exceed 2²⁶ - 1 - // TODO(mundaym): in testing this final carry was unnecessary. - // Needs a proof before it can be removed though. - VESRLG $26, H_1, T_1 - VN MOD26, H_1, H_1 - VAQ T_1, H_2, H_2 - VESRLG $26, H_2, T_2 - VN MOD26, H_2, H_2 - VAQ T_2, H_3, H_3 - VESRLG $26, H_3, T_3 - VN MOD26, H_3, H_3 - VAQ T_3, H_4, H_4 - - // h is now < 2(2¹³⁰ - 5) - // Pack each lane in h₂₆[0:4] into h₁₂₈[0:1]. - VESLG $26, H_1, H_1 - VESLG $26, H_3, H_3 - VO H_0, H_1, H_0 - VO H_2, H_3, H_2 - VESLG $4, H_2, H_2 - VLEIB $7, $48, H_1 - VSLB H_1, H_2, H_2 - VO H_0, H_2, H_0 - VLEIB $7, $104, H_1 - VSLB H_1, H_4, H_3 - VO H_3, H_0, H_0 - VLEIB $7, $24, H_1 - VSRLB H_1, H_4, H_1 - - // update state - VSTEG $1, H_0, 0(R1) - VSTEG $0, H_0, 8(R1) - VSTEG $1, H_1, 16(R1) - RET - -b2: // 2 or fewer blocks remaining - CMPBLE R3, $16, b1 - - // Load the 2 remaining blocks (17-32 bytes remaining). - MOVD $-17(R3), R0 // index of final byte to load modulo 16 - VL (R2), T_0 // load full 16 byte block - VLL R0, 16(R2), T_1 // load final (possibly partial) block and pad with zeros to 16 bytes - - // The Poly1305 algorithm requires that a 1 bit be appended to - // each message block. If the final block is less than 16 bytes - // long then it is easiest to insert the 1 before the message - // block is split into 26-bit limbs. If, on the other hand, the - // final message block is 16 bytes long then we append the 1 bit - // after expansion as normal. - MOVBZ $1, R0 - MOVD $-16(R3), R3 // index of byte in last block to insert 1 at (could be 16) - CMPBEQ R3, $16, 2(PC) // skip the insertion if the final block is 16 bytes long - VLVGB R3, R0, T_1 // insert 1 into the byte at index R3 - - // Split both blocks into 26-bit limbs in the appropriate lanes. - EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) - - // Append a 1 byte to the end of the second to last block. - VLEIB $4, $1, M_4 - - // Append a 1 byte to the end of the last block only if it is a - // full 16 byte block. - CMPBNE R3, $16, 2(PC) - VLEIB $12, $1, M_4 - - // Finally, set up the coefficients for the final multiplication. - // We have previously saved r and 5r in the 32-bit even indexes - // of the R_[0-4] and R5_[1-4] coefficient registers. - // - // We want lane 0 to be multiplied by r² so that can be kept the - // same. We want lane 1 to be multiplied by r so we need to move - // the saved r value into the 32-bit odd index in lane 1 by - // rotating the 64-bit lane by 32. - VGBM $0x00ff, T_0 // [0, 0xffffffffffffffff] - mask lane 1 only - VERIMG $32, R_0, T_0, R_0 // [_, r²₂₆[0], _, r₂₆[0]] - VERIMG $32, R_1, T_0, R_1 // [_, r²₂₆[1], _, r₂₆[1]] - VERIMG $32, R_2, T_0, R_2 // [_, r²₂₆[2], _, r₂₆[2]] - VERIMG $32, R_3, T_0, R_3 // [_, r²₂₆[3], _, r₂₆[3]] - VERIMG $32, R_4, T_0, R_4 // [_, r²₂₆[4], _, r₂₆[4]] - VERIMG $32, R5_1, T_0, R5_1 // [_, 5r²₂₆[1], _, 5r₂₆[1]] - VERIMG $32, R5_2, T_0, R5_2 // [_, 5r²₂₆[2], _, 5r₂₆[2]] - VERIMG $32, R5_3, T_0, R5_3 // [_, 5r²₂₆[3], _, 5r₂₆[3]] - VERIMG $32, R5_4, T_0, R5_4 // [_, 5r²₂₆[4], _, 5r₂₆[4]] - - MOVD $0, R3 - BR multiply - -skip: - CMPBEQ R3, $0, finish - -b1: // 1 block remaining - - // Load the final block (1-16 bytes). This will be placed into - // lane 0. - MOVD $-1(R3), R0 - VLL R0, (R2), T_0 // pad to 16 bytes with zeros - - // The Poly1305 algorithm requires that a 1 bit be appended to - // each message block. If the final block is less than 16 bytes - // long then it is easiest to insert the 1 before the message - // block is split into 26-bit limbs. If, on the other hand, the - // final message block is 16 bytes long then we append the 1 bit - // after expansion as normal. - MOVBZ $1, R0 - CMPBEQ R3, $16, 2(PC) - VLVGB R3, R0, T_0 - - // Set the message block in lane 1 to the value 0 so that it - // can be accumulated without affecting the final result. - VZERO T_1 - - // Split the final message block into 26-bit limbs in lane 0. - // Lane 1 will be contain 0. - EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) - - // Append a 1 byte to the end of the last block only if it is a - // full 16 byte block. - CMPBNE R3, $16, 2(PC) - VLEIB $4, $1, M_4 - - // We have previously saved r and 5r in the 32-bit even indexes - // of the R_[0-4] and R5_[1-4] coefficient registers. - // - // We want lane 0 to be multiplied by r so we need to move the - // saved r value into the 32-bit odd index in lane 0. We want - // lane 1 to be set to the value 1. This makes multiplication - // a no-op. We do this by setting lane 1 in every register to 0 - // and then just setting the 32-bit index 3 in R_0 to 1. - VZERO T_0 - MOVD $0, R0 - MOVD $0x10111213, R12 - VLVGP R12, R0, T_1 // [_, 0x10111213, _, 0x00000000] - VPERM T_0, R_0, T_1, R_0 // [_, r₂₆[0], _, 0] - VPERM T_0, R_1, T_1, R_1 // [_, r₂₆[1], _, 0] - VPERM T_0, R_2, T_1, R_2 // [_, r₂₆[2], _, 0] - VPERM T_0, R_3, T_1, R_3 // [_, r₂₆[3], _, 0] - VPERM T_0, R_4, T_1, R_4 // [_, r₂₆[4], _, 0] - VPERM T_0, R5_1, T_1, R5_1 // [_, 5r₂₆[1], _, 0] - VPERM T_0, R5_2, T_1, R5_2 // [_, 5r₂₆[2], _, 0] - VPERM T_0, R5_3, T_1, R5_3 // [_, 5r₂₆[3], _, 0] - VPERM T_0, R5_4, T_1, R5_4 // [_, 5r₂₆[4], _, 0] - - // Set the value of lane 1 to be 1. - VLEIF $3, $1, R_0 // [_, r₂₆[0], _, 1] - - MOVD $0, R3 - BR multiply diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go deleted file mode 100644 index 4fad24f8..00000000 --- a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 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. - -//go:build !purego -// +build !purego - -// Package subtle implements functions that are often useful in cryptographic -// code but require careful thought to use correctly. -package subtle // import "golang.org/x/crypto/internal/subtle" - -import "unsafe" - -// AnyOverlap reports whether x and y share memory at any (not necessarily -// corresponding) index. The memory beyond the slice length is ignored. -func AnyOverlap(x, y []byte) bool { - return len(x) > 0 && len(y) > 0 && - uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && - uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) -} - -// InexactOverlap reports whether x and y share memory at any non-corresponding -// index. The memory beyond the slice length is ignored. Note that x and y can -// have different lengths and still not have any inexact overlap. -// -// InexactOverlap can be used to implement the requirements of the crypto/cipher -// AEAD, Block, BlockMode and Stream interfaces. -func InexactOverlap(x, y []byte) bool { - if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { - return false - } - return AnyOverlap(x, y) -} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go deleted file mode 100644 index 80ccbed2..00000000 --- a/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 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. - -//go:build purego -// +build purego - -// Package subtle implements functions that are often useful in cryptographic -// code but require careful thought to use correctly. -package subtle // import "golang.org/x/crypto/internal/subtle" - -// This is the Google App Engine standard variant based on reflect -// because the unsafe package and cgo are disallowed. - -import "reflect" - -// AnyOverlap reports whether x and y share memory at any (not necessarily -// corresponding) index. The memory beyond the slice length is ignored. -func AnyOverlap(x, y []byte) bool { - return len(x) > 0 && len(y) > 0 && - reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && - reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() -} - -// InexactOverlap reports whether x and y share memory at any non-corresponding -// index. The memory beyond the slice length is ignored. Note that x and y can -// have different lengths and still not have any inexact overlap. -// -// InexactOverlap can be used to implement the requirements of the crypto/cipher -// AEAD, Block, BlockMode and Stream interfaces. -func InexactOverlap(x, y []byte) bool { - if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { - return false - } - return AnyOverlap(x, y) -} diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go deleted file mode 100644 index 3c4d18a1..00000000 --- a/vendor/golang.org/x/crypto/ssh/agent/client.go +++ /dev/null @@ -1,847 +0,0 @@ -// 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 agent implements the ssh-agent protocol, and provides both -// a client and a server. The client can talk to a standard ssh-agent -// that uses UNIX sockets, and one could implement an alternative -// ssh-agent process using the sample server. -// -// References: -// -// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00 -package agent // import "golang.org/x/crypto/ssh/agent" - -import ( - "bytes" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rsa" - "encoding/base64" - "encoding/binary" - "errors" - "fmt" - "io" - "math/big" - "sync" - - "golang.org/x/crypto/ed25519" - "golang.org/x/crypto/ssh" -) - -// SignatureFlags represent additional flags that can be passed to the signature -// requests an defined in [PROTOCOL.agent] section 4.5.1. -type SignatureFlags uint32 - -// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. -const ( - SignatureFlagReserved SignatureFlags = 1 << iota - SignatureFlagRsaSha256 - SignatureFlagRsaSha512 -) - -// Agent represents the capabilities of an ssh-agent. -type Agent interface { - // List returns the identities known to the agent. - List() ([]*Key, error) - - // Sign has the agent sign the data using a protocol 2 key as defined - // in [PROTOCOL.agent] section 2.6.2. - Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) - - // Add adds a private key to the agent. - Add(key AddedKey) error - - // Remove removes all identities with the given public key. - Remove(key ssh.PublicKey) error - - // RemoveAll removes all identities. - RemoveAll() error - - // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. - Lock(passphrase []byte) error - - // Unlock undoes the effect of Lock - Unlock(passphrase []byte) error - - // Signers returns signers for all the known keys. - Signers() ([]ssh.Signer, error) -} - -type ExtendedAgent interface { - Agent - - // SignWithFlags signs like Sign, but allows for additional flags to be sent/received - SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) - - // Extension processes a custom extension request. Standard-compliant agents are not - // required to support any extensions, but this method allows agents to implement - // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. - // If agent extensions are unsupported entirely this method MUST return an - // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in - // the request is unsupported by the agent then ErrExtensionUnsupported MUST be - // returned. - // - // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents - // of the response are unspecified (including the type of the message), the complete - // response will be returned as a []byte slice, including the "type" byte of the message. - Extension(extensionType string, contents []byte) ([]byte, error) -} - -// ConstraintExtension describes an optional constraint defined by users. -type ConstraintExtension struct { - // ExtensionName consist of a UTF-8 string suffixed by the - // implementation domain following the naming scheme defined - // in Section 4.2 of [RFC4251], e.g. "foo@example.com". - ExtensionName string - // ExtensionDetails contains the actual content of the extended - // constraint. - ExtensionDetails []byte -} - -// AddedKey describes an SSH key to be added to an Agent. -type AddedKey struct { - // PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey, - // ed25519.PrivateKey or *ecdsa.PrivateKey, which will be inserted into the - // agent. - PrivateKey interface{} - // Certificate, if not nil, is communicated to the agent and will be - // stored with the key. - Certificate *ssh.Certificate - // Comment is an optional, free-form string. - Comment string - // LifetimeSecs, if not zero, is the number of seconds that the - // agent will store the key for. - LifetimeSecs uint32 - // ConfirmBeforeUse, if true, requests that the agent confirm with the - // user before each use of this key. - ConfirmBeforeUse bool - // ConstraintExtensions are the experimental or private-use constraints - // defined by users. - ConstraintExtensions []ConstraintExtension -} - -// See [PROTOCOL.agent], section 3. -const ( - agentRequestV1Identities = 1 - agentRemoveAllV1Identities = 9 - - // 3.2 Requests from client to agent for protocol 2 key operations - agentAddIdentity = 17 - agentRemoveIdentity = 18 - agentRemoveAllIdentities = 19 - agentAddIDConstrained = 25 - - // 3.3 Key-type independent requests from client to agent - agentAddSmartcardKey = 20 - agentRemoveSmartcardKey = 21 - agentLock = 22 - agentUnlock = 23 - agentAddSmartcardKeyConstrained = 26 - - // 3.7 Key constraint identifiers - agentConstrainLifetime = 1 - agentConstrainConfirm = 2 - agentConstrainExtension = 3 -) - -// maxAgentResponseBytes is the maximum agent reply size that is accepted. This -// is a sanity check, not a limit in the spec. -const maxAgentResponseBytes = 16 << 20 - -// Agent messages: -// These structures mirror the wire format of the corresponding ssh agent -// messages found in [PROTOCOL.agent]. - -// 3.4 Generic replies from agent to client -const agentFailure = 5 - -type failureAgentMsg struct{} - -const agentSuccess = 6 - -type successAgentMsg struct{} - -// See [PROTOCOL.agent], section 2.5.2. -const agentRequestIdentities = 11 - -type requestIdentitiesAgentMsg struct{} - -// See [PROTOCOL.agent], section 2.5.2. -const agentIdentitiesAnswer = 12 - -type identitiesAnswerAgentMsg struct { - NumKeys uint32 `sshtype:"12"` - Keys []byte `ssh:"rest"` -} - -// See [PROTOCOL.agent], section 2.6.2. -const agentSignRequest = 13 - -type signRequestAgentMsg struct { - KeyBlob []byte `sshtype:"13"` - Data []byte - Flags uint32 -} - -// See [PROTOCOL.agent], section 2.6.2. - -// 3.6 Replies from agent to client for protocol 2 key operations -const agentSignResponse = 14 - -type signResponseAgentMsg struct { - SigBlob []byte `sshtype:"14"` -} - -type publicKey struct { - Format string - Rest []byte `ssh:"rest"` -} - -// 3.7 Key constraint identifiers -type constrainLifetimeAgentMsg struct { - LifetimeSecs uint32 `sshtype:"1"` -} - -type constrainExtensionAgentMsg struct { - ExtensionName string `sshtype:"3"` - ExtensionDetails []byte - - // Rest is a field used for parsing, not part of message - Rest []byte `ssh:"rest"` -} - -// See [PROTOCOL.agent], section 4.7 -const agentExtension = 27 -const agentExtensionFailure = 28 - -// ErrExtensionUnsupported indicates that an extension defined in -// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this -// error indicates that the agent returned a standard SSH_AGENT_FAILURE message -// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol -// specification (and therefore this error) does not distinguish between a -// specific extension being unsupported and extensions being unsupported entirely. -var ErrExtensionUnsupported = errors.New("agent: extension unsupported") - -type extensionAgentMsg struct { - ExtensionType string `sshtype:"27"` - Contents []byte -} - -// Key represents a protocol 2 public key as defined in -// [PROTOCOL.agent], section 2.5.2. -type Key struct { - Format string - Blob []byte - Comment string -} - -func clientErr(err error) error { - return fmt.Errorf("agent: client error: %v", err) -} - -// String returns the storage form of an agent key with the format, base64 -// encoded serialized key, and the comment if it is not empty. -func (k *Key) String() string { - s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob) - - if k.Comment != "" { - s += " " + k.Comment - } - - return s -} - -// Type returns the public key type. -func (k *Key) Type() string { - return k.Format -} - -// Marshal returns key blob to satisfy the ssh.PublicKey interface. -func (k *Key) Marshal() []byte { - return k.Blob -} - -// Verify satisfies the ssh.PublicKey interface. -func (k *Key) Verify(data []byte, sig *ssh.Signature) error { - pubKey, err := ssh.ParsePublicKey(k.Blob) - if err != nil { - return fmt.Errorf("agent: bad public key: %v", err) - } - return pubKey.Verify(data, sig) -} - -type wireKey struct { - Format string - Rest []byte `ssh:"rest"` -} - -func parseKey(in []byte) (out *Key, rest []byte, err error) { - var record struct { - Blob []byte - Comment string - Rest []byte `ssh:"rest"` - } - - if err := ssh.Unmarshal(in, &record); err != nil { - return nil, nil, err - } - - var wk wireKey - if err := ssh.Unmarshal(record.Blob, &wk); err != nil { - return nil, nil, err - } - - return &Key{ - Format: wk.Format, - Blob: record.Blob, - Comment: record.Comment, - }, record.Rest, nil -} - -// client is a client for an ssh-agent process. -type client struct { - // conn is typically a *net.UnixConn - conn io.ReadWriter - // mu is used to prevent concurrent access to the agent - mu sync.Mutex -} - -// NewClient returns an Agent that talks to an ssh-agent process over -// the given connection. -func NewClient(rw io.ReadWriter) ExtendedAgent { - return &client{conn: rw} -} - -// call sends an RPC to the agent. On success, the reply is -// unmarshaled into reply and replyType is set to the first byte of -// the reply, which contains the type of the message. -func (c *client) call(req []byte) (reply interface{}, err error) { - buf, err := c.callRaw(req) - if err != nil { - return nil, err - } - reply, err = unmarshal(buf) - if err != nil { - return nil, clientErr(err) - } - return reply, nil -} - -// callRaw sends an RPC to the agent. On success, the raw -// bytes of the response are returned; no unmarshalling is -// performed on the response. -func (c *client) callRaw(req []byte) (reply []byte, err error) { - c.mu.Lock() - defer c.mu.Unlock() - - msg := make([]byte, 4+len(req)) - binary.BigEndian.PutUint32(msg, uint32(len(req))) - copy(msg[4:], req) - if _, err = c.conn.Write(msg); err != nil { - return nil, clientErr(err) - } - - var respSizeBuf [4]byte - if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil { - return nil, clientErr(err) - } - respSize := binary.BigEndian.Uint32(respSizeBuf[:]) - if respSize > maxAgentResponseBytes { - return nil, clientErr(errors.New("response too large")) - } - - buf := make([]byte, respSize) - if _, err = io.ReadFull(c.conn, buf); err != nil { - return nil, clientErr(err) - } - return buf, nil -} - -func (c *client) simpleCall(req []byte) error { - resp, err := c.call(req) - if err != nil { - return err - } - if _, ok := resp.(*successAgentMsg); ok { - return nil - } - return errors.New("agent: failure") -} - -func (c *client) RemoveAll() error { - return c.simpleCall([]byte{agentRemoveAllIdentities}) -} - -func (c *client) Remove(key ssh.PublicKey) error { - req := ssh.Marshal(&agentRemoveIdentityMsg{ - KeyBlob: key.Marshal(), - }) - return c.simpleCall(req) -} - -func (c *client) Lock(passphrase []byte) error { - req := ssh.Marshal(&agentLockMsg{ - Passphrase: passphrase, - }) - return c.simpleCall(req) -} - -func (c *client) Unlock(passphrase []byte) error { - req := ssh.Marshal(&agentUnlockMsg{ - Passphrase: passphrase, - }) - return c.simpleCall(req) -} - -// List returns the identities known to the agent. -func (c *client) List() ([]*Key, error) { - // see [PROTOCOL.agent] section 2.5.2. - req := []byte{agentRequestIdentities} - - msg, err := c.call(req) - if err != nil { - return nil, err - } - - switch msg := msg.(type) { - case *identitiesAnswerAgentMsg: - if msg.NumKeys > maxAgentResponseBytes/8 { - return nil, errors.New("agent: too many keys in agent reply") - } - keys := make([]*Key, msg.NumKeys) - data := msg.Keys - for i := uint32(0); i < msg.NumKeys; i++ { - var key *Key - var err error - if key, data, err = parseKey(data); err != nil { - return nil, err - } - keys[i] = key - } - return keys, nil - case *failureAgentMsg: - return nil, errors.New("agent: failed to list keys") - } - panic("unreachable") -} - -// Sign has the agent sign the data using a protocol 2 key as defined -// in [PROTOCOL.agent] section 2.6.2. -func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { - return c.SignWithFlags(key, data, 0) -} - -func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { - req := ssh.Marshal(signRequestAgentMsg{ - KeyBlob: key.Marshal(), - Data: data, - Flags: uint32(flags), - }) - - msg, err := c.call(req) - if err != nil { - return nil, err - } - - switch msg := msg.(type) { - case *signResponseAgentMsg: - var sig ssh.Signature - if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil { - return nil, err - } - - return &sig, nil - case *failureAgentMsg: - return nil, errors.New("agent: failed to sign challenge") - } - panic("unreachable") -} - -// unmarshal parses an agent message in packet, returning the parsed -// form and the message type of packet. -func unmarshal(packet []byte) (interface{}, error) { - if len(packet) < 1 { - return nil, errors.New("agent: empty packet") - } - var msg interface{} - switch packet[0] { - case agentFailure: - return new(failureAgentMsg), nil - case agentSuccess: - return new(successAgentMsg), nil - case agentIdentitiesAnswer: - msg = new(identitiesAnswerAgentMsg) - case agentSignResponse: - msg = new(signResponseAgentMsg) - case agentV1IdentitiesAnswer: - msg = new(agentV1IdentityMsg) - default: - return nil, fmt.Errorf("agent: unknown type tag %d", packet[0]) - } - if err := ssh.Unmarshal(packet, msg); err != nil { - return nil, err - } - return msg, nil -} - -type rsaKeyMsg struct { - Type string `sshtype:"17|25"` - N *big.Int - E *big.Int - D *big.Int - Iqmp *big.Int // IQMP = Inverse Q Mod P - P *big.Int - Q *big.Int - Comments string - Constraints []byte `ssh:"rest"` -} - -type dsaKeyMsg struct { - Type string `sshtype:"17|25"` - P *big.Int - Q *big.Int - G *big.Int - Y *big.Int - X *big.Int - Comments string - Constraints []byte `ssh:"rest"` -} - -type ecdsaKeyMsg struct { - Type string `sshtype:"17|25"` - Curve string - KeyBytes []byte - D *big.Int - Comments string - Constraints []byte `ssh:"rest"` -} - -type ed25519KeyMsg struct { - Type string `sshtype:"17|25"` - Pub []byte - Priv []byte - Comments string - Constraints []byte `ssh:"rest"` -} - -// Insert adds a private key to the agent. -func (c *client) insertKey(s interface{}, comment string, constraints []byte) error { - var req []byte - switch k := s.(type) { - case *rsa.PrivateKey: - if len(k.Primes) != 2 { - return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) - } - k.Precompute() - req = ssh.Marshal(rsaKeyMsg{ - Type: ssh.KeyAlgoRSA, - N: k.N, - E: big.NewInt(int64(k.E)), - D: k.D, - Iqmp: k.Precomputed.Qinv, - P: k.Primes[0], - Q: k.Primes[1], - Comments: comment, - Constraints: constraints, - }) - case *dsa.PrivateKey: - req = ssh.Marshal(dsaKeyMsg{ - Type: ssh.KeyAlgoDSA, - P: k.P, - Q: k.Q, - G: k.G, - Y: k.Y, - X: k.X, - Comments: comment, - Constraints: constraints, - }) - case *ecdsa.PrivateKey: - nistID := fmt.Sprintf("nistp%d", k.Params().BitSize) - req = ssh.Marshal(ecdsaKeyMsg{ - Type: "ecdsa-sha2-" + nistID, - Curve: nistID, - KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y), - D: k.D, - Comments: comment, - Constraints: constraints, - }) - case ed25519.PrivateKey: - req = ssh.Marshal(ed25519KeyMsg{ - Type: ssh.KeyAlgoED25519, - Pub: []byte(k)[32:], - Priv: []byte(k), - Comments: comment, - Constraints: constraints, - }) - // This function originally supported only *ed25519.PrivateKey, however the - // general idiom is to pass ed25519.PrivateKey by value, not by pointer. - // We still support the pointer variant for backwards compatibility. - case *ed25519.PrivateKey: - req = ssh.Marshal(ed25519KeyMsg{ - Type: ssh.KeyAlgoED25519, - Pub: []byte(*k)[32:], - Priv: []byte(*k), - Comments: comment, - Constraints: constraints, - }) - default: - return fmt.Errorf("agent: unsupported key type %T", s) - } - - // if constraints are present then the message type needs to be changed. - if len(constraints) != 0 { - req[0] = agentAddIDConstrained - } - - resp, err := c.call(req) - if err != nil { - return err - } - if _, ok := resp.(*successAgentMsg); ok { - return nil - } - return errors.New("agent: failure") -} - -type rsaCertMsg struct { - Type string `sshtype:"17|25"` - CertBytes []byte - D *big.Int - Iqmp *big.Int // IQMP = Inverse Q Mod P - P *big.Int - Q *big.Int - Comments string - Constraints []byte `ssh:"rest"` -} - -type dsaCertMsg struct { - Type string `sshtype:"17|25"` - CertBytes []byte - X *big.Int - Comments string - Constraints []byte `ssh:"rest"` -} - -type ecdsaCertMsg struct { - Type string `sshtype:"17|25"` - CertBytes []byte - D *big.Int - Comments string - Constraints []byte `ssh:"rest"` -} - -type ed25519CertMsg struct { - Type string `sshtype:"17|25"` - CertBytes []byte - Pub []byte - Priv []byte - Comments string - Constraints []byte `ssh:"rest"` -} - -// Add adds a private key to the agent. If a certificate is given, -// that certificate is added instead as public key. -func (c *client) Add(key AddedKey) error { - var constraints []byte - - if secs := key.LifetimeSecs; secs != 0 { - constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...) - } - - if key.ConfirmBeforeUse { - constraints = append(constraints, agentConstrainConfirm) - } - - cert := key.Certificate - if cert == nil { - return c.insertKey(key.PrivateKey, key.Comment, constraints) - } - return c.insertCert(key.PrivateKey, cert, key.Comment, constraints) -} - -func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error { - var req []byte - switch k := s.(type) { - case *rsa.PrivateKey: - if len(k.Primes) != 2 { - return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) - } - k.Precompute() - req = ssh.Marshal(rsaCertMsg{ - Type: cert.Type(), - CertBytes: cert.Marshal(), - D: k.D, - Iqmp: k.Precomputed.Qinv, - P: k.Primes[0], - Q: k.Primes[1], - Comments: comment, - Constraints: constraints, - }) - case *dsa.PrivateKey: - req = ssh.Marshal(dsaCertMsg{ - Type: cert.Type(), - CertBytes: cert.Marshal(), - X: k.X, - Comments: comment, - Constraints: constraints, - }) - case *ecdsa.PrivateKey: - req = ssh.Marshal(ecdsaCertMsg{ - Type: cert.Type(), - CertBytes: cert.Marshal(), - D: k.D, - Comments: comment, - Constraints: constraints, - }) - case ed25519.PrivateKey: - req = ssh.Marshal(ed25519CertMsg{ - Type: cert.Type(), - CertBytes: cert.Marshal(), - Pub: []byte(k)[32:], - Priv: []byte(k), - Comments: comment, - Constraints: constraints, - }) - // This function originally supported only *ed25519.PrivateKey, however the - // general idiom is to pass ed25519.PrivateKey by value, not by pointer. - // We still support the pointer variant for backwards compatibility. - case *ed25519.PrivateKey: - req = ssh.Marshal(ed25519CertMsg{ - Type: cert.Type(), - CertBytes: cert.Marshal(), - Pub: []byte(*k)[32:], - Priv: []byte(*k), - Comments: comment, - Constraints: constraints, - }) - default: - return fmt.Errorf("agent: unsupported key type %T", s) - } - - // if constraints are present then the message type needs to be changed. - if len(constraints) != 0 { - req[0] = agentAddIDConstrained - } - - signer, err := ssh.NewSignerFromKey(s) - if err != nil { - return err - } - if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { - return errors.New("agent: signer and cert have different public key") - } - - resp, err := c.call(req) - if err != nil { - return err - } - if _, ok := resp.(*successAgentMsg); ok { - return nil - } - return errors.New("agent: failure") -} - -// Signers provides a callback for client authentication. -func (c *client) Signers() ([]ssh.Signer, error) { - keys, err := c.List() - if err != nil { - return nil, err - } - - var result []ssh.Signer - for _, k := range keys { - result = append(result, &agentKeyringSigner{c, k}) - } - return result, nil -} - -type agentKeyringSigner struct { - agent *client - pub ssh.PublicKey -} - -func (s *agentKeyringSigner) PublicKey() ssh.PublicKey { - return s.pub -} - -func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) { - // The agent has its own entropy source, so the rand argument is ignored. - return s.agent.Sign(s.pub, data) -} - -func (s *agentKeyringSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*ssh.Signature, error) { - if algorithm == "" || algorithm == underlyingAlgo(s.pub.Type()) { - return s.Sign(rand, data) - } - - var flags SignatureFlags - switch algorithm { - case ssh.KeyAlgoRSASHA256: - flags = SignatureFlagRsaSha256 - case ssh.KeyAlgoRSASHA512: - flags = SignatureFlagRsaSha512 - default: - return nil, fmt.Errorf("agent: unsupported algorithm %q", algorithm) - } - - return s.agent.SignWithFlags(s.pub, data, flags) -} - -var _ ssh.AlgorithmSigner = &agentKeyringSigner{} - -// certKeyAlgoNames is a mapping from known certificate algorithm names to the -// corresponding public key signature algorithm. -// -// This map must be kept in sync with the one in certs.go. -var certKeyAlgoNames = map[string]string{ - ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA, - ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256, - ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512, - ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA, - ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256, - ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384, - ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521, - ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256, - ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519, - ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519, -} - -// underlyingAlgo returns the signature algorithm associated with algo (which is -// an advertised or negotiated public key or host key algorithm). These are -// usually the same, except for certificate algorithms. -func underlyingAlgo(algo string) string { - if a, ok := certKeyAlgoNames[algo]; ok { - return a - } - return algo -} - -// Calls an extension method. It is up to the agent implementation as to whether or not -// any particular extension is supported and may always return an error. Because the -// type of the response is up to the implementation, this returns the bytes of the -// response and does not attempt any type of unmarshalling. -func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { - req := ssh.Marshal(extensionAgentMsg{ - ExtensionType: extensionType, - Contents: contents, - }) - buf, err := c.callRaw(req) - if err != nil { - return nil, err - } - if len(buf) == 0 { - return nil, errors.New("agent: failure; empty response") - } - // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message - // represents an agent that does not support the extension - if buf[0] == agentFailure { - return nil, ErrExtensionUnsupported - } - if buf[0] == agentExtensionFailure { - return nil, errors.New("agent: generic extension failure") - } - - return buf, nil -} diff --git a/vendor/golang.org/x/crypto/ssh/agent/forward.go b/vendor/golang.org/x/crypto/ssh/agent/forward.go deleted file mode 100644 index fd24ba90..00000000 --- a/vendor/golang.org/x/crypto/ssh/agent/forward.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014 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 agent - -import ( - "errors" - "io" - "net" - "sync" - - "golang.org/x/crypto/ssh" -) - -// RequestAgentForwarding sets up agent forwarding for the session. -// ForwardToAgent or ForwardToRemote should be called to route -// the authentication requests. -func RequestAgentForwarding(session *ssh.Session) error { - ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil) - if err != nil { - return err - } - if !ok { - return errors.New("forwarding request denied") - } - return nil -} - -// ForwardToAgent routes authentication requests to the given keyring. -func ForwardToAgent(client *ssh.Client, keyring Agent) error { - channels := client.HandleChannelOpen(channelType) - if channels == nil { - return errors.New("agent: already have handler for " + channelType) - } - - go func() { - for ch := range channels { - channel, reqs, err := ch.Accept() - if err != nil { - continue - } - go ssh.DiscardRequests(reqs) - go func() { - ServeAgent(keyring, channel) - channel.Close() - }() - } - }() - return nil -} - -const channelType = "auth-agent@openssh.com" - -// ForwardToRemote routes authentication requests to the ssh-agent -// process serving on the given unix socket. -func ForwardToRemote(client *ssh.Client, addr string) error { - channels := client.HandleChannelOpen(channelType) - if channels == nil { - return errors.New("agent: already have handler for " + channelType) - } - conn, err := net.Dial("unix", addr) - if err != nil { - return err - } - conn.Close() - - go func() { - for ch := range channels { - channel, reqs, err := ch.Accept() - if err != nil { - continue - } - go ssh.DiscardRequests(reqs) - go forwardUnixSocket(channel, addr) - } - }() - return nil -} - -func forwardUnixSocket(channel ssh.Channel, addr string) { - conn, err := net.Dial("unix", addr) - if err != nil { - return - } - - var wg sync.WaitGroup - wg.Add(2) - go func() { - io.Copy(conn, channel) - conn.(*net.UnixConn).CloseWrite() - wg.Done() - }() - go func() { - io.Copy(channel, conn) - channel.CloseWrite() - wg.Done() - }() - - wg.Wait() - conn.Close() - channel.Close() -} diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go deleted file mode 100644 index 21bfa870..00000000 --- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2014 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 agent - -import ( - "bytes" - "crypto/rand" - "crypto/subtle" - "errors" - "fmt" - "sync" - "time" - - "golang.org/x/crypto/ssh" -) - -type privKey struct { - signer ssh.Signer - comment string - expire *time.Time -} - -type keyring struct { - mu sync.Mutex - keys []privKey - - locked bool - passphrase []byte -} - -var errLocked = errors.New("agent: locked") - -// NewKeyring returns an Agent that holds keys in memory. It is safe -// for concurrent use by multiple goroutines. -func NewKeyring() Agent { - return &keyring{} -} - -// RemoveAll removes all identities. -func (r *keyring) RemoveAll() error { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - return errLocked - } - - r.keys = nil - return nil -} - -// removeLocked does the actual key removal. The caller must already be holding the -// keyring mutex. -func (r *keyring) removeLocked(want []byte) error { - found := false - for i := 0; i < len(r.keys); { - if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { - found = true - r.keys[i] = r.keys[len(r.keys)-1] - r.keys = r.keys[:len(r.keys)-1] - continue - } else { - i++ - } - } - - if !found { - return errors.New("agent: key not found") - } - return nil -} - -// Remove removes all identities with the given public key. -func (r *keyring) Remove(key ssh.PublicKey) error { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - return errLocked - } - - return r.removeLocked(key.Marshal()) -} - -// Lock locks the agent. Sign and Remove will fail, and List will return an empty list. -func (r *keyring) Lock(passphrase []byte) error { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - return errLocked - } - - r.locked = true - r.passphrase = passphrase - return nil -} - -// Unlock undoes the effect of Lock -func (r *keyring) Unlock(passphrase []byte) error { - r.mu.Lock() - defer r.mu.Unlock() - if !r.locked { - return errors.New("agent: not locked") - } - if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { - return fmt.Errorf("agent: incorrect passphrase") - } - - r.locked = false - r.passphrase = nil - return nil -} - -// expireKeysLocked removes expired keys from the keyring. If a key was added -// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have -// elapsed, it is removed. The caller *must* be holding the keyring mutex. -func (r *keyring) expireKeysLocked() { - for _, k := range r.keys { - if k.expire != nil && time.Now().After(*k.expire) { - r.removeLocked(k.signer.PublicKey().Marshal()) - } - } -} - -// List returns the identities known to the agent. -func (r *keyring) List() ([]*Key, error) { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - // section 2.7: locked agents return empty. - return nil, nil - } - - r.expireKeysLocked() - var ids []*Key - for _, k := range r.keys { - pub := k.signer.PublicKey() - ids = append(ids, &Key{ - Format: pub.Type(), - Blob: pub.Marshal(), - Comment: k.comment}) - } - return ids, nil -} - -// Insert adds a private key to the keyring. If a certificate -// is given, that certificate is added as public key. Note that -// any constraints given are ignored. -func (r *keyring) Add(key AddedKey) error { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - return errLocked - } - signer, err := ssh.NewSignerFromKey(key.PrivateKey) - - if err != nil { - return err - } - - if cert := key.Certificate; cert != nil { - signer, err = ssh.NewCertSigner(cert, signer) - if err != nil { - return err - } - } - - p := privKey{ - signer: signer, - comment: key.Comment, - } - - if key.LifetimeSecs > 0 { - t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second) - p.expire = &t - } - - r.keys = append(r.keys, p) - - return nil -} - -// Sign returns a signature for the data. -func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { - return r.SignWithFlags(key, data, 0) -} - -func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - return nil, errLocked - } - - r.expireKeysLocked() - wanted := key.Marshal() - for _, k := range r.keys { - if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { - if flags == 0 { - return k.signer.Sign(rand.Reader, data) - } else { - if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { - return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) - } else { - var algorithm string - switch flags { - case SignatureFlagRsaSha256: - algorithm = ssh.KeyAlgoRSASHA256 - case SignatureFlagRsaSha512: - algorithm = ssh.KeyAlgoRSASHA512 - default: - return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) - } - return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) - } - } - } - } - return nil, errors.New("not found") -} - -// Signers returns signers for all the known keys. -func (r *keyring) Signers() ([]ssh.Signer, error) { - r.mu.Lock() - defer r.mu.Unlock() - if r.locked { - return nil, errLocked - } - - r.expireKeysLocked() - s := make([]ssh.Signer, 0, len(r.keys)) - for _, k := range r.keys { - s = append(s, k.signer) - } - return s, nil -} - -// The keyring does not support any extensions -func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { - return nil, ErrExtensionUnsupported -} diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go deleted file mode 100644 index 6e7a1e02..00000000 --- a/vendor/golang.org/x/crypto/ssh/agent/server.go +++ /dev/null @@ -1,570 +0,0 @@ -// 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 agent - -import ( - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rsa" - "encoding/binary" - "errors" - "fmt" - "io" - "log" - "math/big" - - "golang.org/x/crypto/ed25519" - "golang.org/x/crypto/ssh" -) - -// Server wraps an Agent and uses it to implement the agent side of -// the SSH-agent, wire protocol. -type server struct { - agent Agent -} - -func (s *server) processRequestBytes(reqData []byte) []byte { - rep, err := s.processRequest(reqData) - if err != nil { - if err != errLocked { - // TODO(hanwen): provide better logging interface? - log.Printf("agent %d: %v", reqData[0], err) - } - return []byte{agentFailure} - } - - if err == nil && rep == nil { - return []byte{agentSuccess} - } - - return ssh.Marshal(rep) -} - -func marshalKey(k *Key) []byte { - var record struct { - Blob []byte - Comment string - } - record.Blob = k.Marshal() - record.Comment = k.Comment - - return ssh.Marshal(&record) -} - -// See [PROTOCOL.agent], section 2.5.1. -const agentV1IdentitiesAnswer = 2 - -type agentV1IdentityMsg struct { - Numkeys uint32 `sshtype:"2"` -} - -type agentRemoveIdentityMsg struct { - KeyBlob []byte `sshtype:"18"` -} - -type agentLockMsg struct { - Passphrase []byte `sshtype:"22"` -} - -type agentUnlockMsg struct { - Passphrase []byte `sshtype:"23"` -} - -func (s *server) processRequest(data []byte) (interface{}, error) { - switch data[0] { - case agentRequestV1Identities: - return &agentV1IdentityMsg{0}, nil - - case agentRemoveAllV1Identities: - return nil, nil - - case agentRemoveIdentity: - var req agentRemoveIdentityMsg - if err := ssh.Unmarshal(data, &req); err != nil { - return nil, err - } - - var wk wireKey - if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { - return nil, err - } - - return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) - - case agentRemoveAllIdentities: - return nil, s.agent.RemoveAll() - - case agentLock: - var req agentLockMsg - if err := ssh.Unmarshal(data, &req); err != nil { - return nil, err - } - - return nil, s.agent.Lock(req.Passphrase) - - case agentUnlock: - var req agentUnlockMsg - if err := ssh.Unmarshal(data, &req); err != nil { - return nil, err - } - return nil, s.agent.Unlock(req.Passphrase) - - case agentSignRequest: - var req signRequestAgentMsg - if err := ssh.Unmarshal(data, &req); err != nil { - return nil, err - } - - var wk wireKey - if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { - return nil, err - } - - k := &Key{ - Format: wk.Format, - Blob: req.KeyBlob, - } - - var sig *ssh.Signature - var err error - if extendedAgent, ok := s.agent.(ExtendedAgent); ok { - sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) - } else { - sig, err = s.agent.Sign(k, req.Data) - } - - if err != nil { - return nil, err - } - return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil - - case agentRequestIdentities: - keys, err := s.agent.List() - if err != nil { - return nil, err - } - - rep := identitiesAnswerAgentMsg{ - NumKeys: uint32(len(keys)), - } - for _, k := range keys { - rep.Keys = append(rep.Keys, marshalKey(k)...) - } - return rep, nil - - case agentAddIDConstrained, agentAddIdentity: - return nil, s.insertIdentity(data) - - case agentExtension: - // Return a stub object where the whole contents of the response gets marshaled. - var responseStub struct { - Rest []byte `ssh:"rest"` - } - - if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { - // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 - // requires that we return a standard SSH_AGENT_FAILURE message. - responseStub.Rest = []byte{agentFailure} - } else { - var req extensionAgentMsg - if err := ssh.Unmarshal(data, &req); err != nil { - return nil, err - } - res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) - if err != nil { - // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE - // message as required by [PROTOCOL.agent] section 4.7. - if err == ErrExtensionUnsupported { - responseStub.Rest = []byte{agentFailure} - } else { - // As the result of any other error processing an extension request, - // [PROTOCOL.agent] section 4.7 requires that we return a - // SSH_AGENT_EXTENSION_FAILURE code. - responseStub.Rest = []byte{agentExtensionFailure} - } - } else { - if len(res) == 0 { - return nil, nil - } - responseStub.Rest = res - } - } - - return responseStub, nil - } - - return nil, fmt.Errorf("unknown opcode %d", data[0]) -} - -func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) { - for len(constraints) != 0 { - switch constraints[0] { - case agentConstrainLifetime: - lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5]) - constraints = constraints[5:] - case agentConstrainConfirm: - confirmBeforeUse = true - constraints = constraints[1:] - case agentConstrainExtension: - var msg constrainExtensionAgentMsg - if err = ssh.Unmarshal(constraints, &msg); err != nil { - return 0, false, nil, err - } - extensions = append(extensions, ConstraintExtension{ - ExtensionName: msg.ExtensionName, - ExtensionDetails: msg.ExtensionDetails, - }) - constraints = msg.Rest - default: - return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0]) - } - } - return -} - -func setConstraints(key *AddedKey, constraintBytes []byte) error { - lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes) - if err != nil { - return err - } - - key.LifetimeSecs = lifetimeSecs - key.ConfirmBeforeUse = confirmBeforeUse - key.ConstraintExtensions = constraintExtensions - return nil -} - -func parseRSAKey(req []byte) (*AddedKey, error) { - var k rsaKeyMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - if k.E.BitLen() > 30 { - return nil, errors.New("agent: RSA public exponent too large") - } - priv := &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - E: int(k.E.Int64()), - N: k.N, - }, - D: k.D, - Primes: []*big.Int{k.P, k.Q}, - } - priv.Precompute() - - addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func parseEd25519Key(req []byte) (*AddedKey, error) { - var k ed25519KeyMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - priv := ed25519.PrivateKey(k.Priv) - - addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func parseDSAKey(req []byte) (*AddedKey, error) { - var k dsaKeyMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - priv := &dsa.PrivateKey{ - PublicKey: dsa.PublicKey{ - Parameters: dsa.Parameters{ - P: k.P, - Q: k.Q, - G: k.G, - }, - Y: k.Y, - }, - X: k.X, - } - - addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) { - priv = &ecdsa.PrivateKey{ - D: privScalar, - } - - switch curveName { - case "nistp256": - priv.Curve = elliptic.P256() - case "nistp384": - priv.Curve = elliptic.P384() - case "nistp521": - priv.Curve = elliptic.P521() - default: - return nil, fmt.Errorf("agent: unknown curve %q", curveName) - } - - priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes) - if priv.X == nil || priv.Y == nil { - return nil, errors.New("agent: point not on curve") - } - - return priv, nil -} - -func parseEd25519Cert(req []byte) (*AddedKey, error) { - var k ed25519CertMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - pubKey, err := ssh.ParsePublicKey(k.CertBytes) - if err != nil { - return nil, err - } - priv := ed25519.PrivateKey(k.Priv) - cert, ok := pubKey.(*ssh.Certificate) - if !ok { - return nil, errors.New("agent: bad ED25519 certificate") - } - - addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func parseECDSAKey(req []byte) (*AddedKey, error) { - var k ecdsaKeyMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - - priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D) - if err != nil { - return nil, err - } - - addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func parseRSACert(req []byte) (*AddedKey, error) { - var k rsaCertMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - - pubKey, err := ssh.ParsePublicKey(k.CertBytes) - if err != nil { - return nil, err - } - - cert, ok := pubKey.(*ssh.Certificate) - if !ok { - return nil, errors.New("agent: bad RSA certificate") - } - - // An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go - var rsaPub struct { - Name string - E *big.Int - N *big.Int - } - if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil { - return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) - } - - if rsaPub.E.BitLen() > 30 { - return nil, errors.New("agent: RSA public exponent too large") - } - - priv := rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - E: int(rsaPub.E.Int64()), - N: rsaPub.N, - }, - D: k.D, - Primes: []*big.Int{k.Q, k.P}, - } - priv.Precompute() - - addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func parseDSACert(req []byte) (*AddedKey, error) { - var k dsaCertMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - pubKey, err := ssh.ParsePublicKey(k.CertBytes) - if err != nil { - return nil, err - } - cert, ok := pubKey.(*ssh.Certificate) - if !ok { - return nil, errors.New("agent: bad DSA certificate") - } - - // A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go - var w struct { - Name string - P, Q, G, Y *big.Int - } - if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil { - return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) - } - - priv := &dsa.PrivateKey{ - PublicKey: dsa.PublicKey{ - Parameters: dsa.Parameters{ - P: w.P, - Q: w.Q, - G: w.G, - }, - Y: w.Y, - }, - X: k.X, - } - - addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func parseECDSACert(req []byte) (*AddedKey, error) { - var k ecdsaCertMsg - if err := ssh.Unmarshal(req, &k); err != nil { - return nil, err - } - - pubKey, err := ssh.ParsePublicKey(k.CertBytes) - if err != nil { - return nil, err - } - cert, ok := pubKey.(*ssh.Certificate) - if !ok { - return nil, errors.New("agent: bad ECDSA certificate") - } - - // An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go - var ecdsaPub struct { - Name string - ID string - Key []byte - } - if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil { - return nil, err - } - - priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D) - if err != nil { - return nil, err - } - - addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} - if err := setConstraints(addedKey, k.Constraints); err != nil { - return nil, err - } - return addedKey, nil -} - -func (s *server) insertIdentity(req []byte) error { - var record struct { - Type string `sshtype:"17|25"` - Rest []byte `ssh:"rest"` - } - - if err := ssh.Unmarshal(req, &record); err != nil { - return err - } - - var addedKey *AddedKey - var err error - - switch record.Type { - case ssh.KeyAlgoRSA: - addedKey, err = parseRSAKey(req) - case ssh.KeyAlgoDSA: - addedKey, err = parseDSAKey(req) - case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: - addedKey, err = parseECDSAKey(req) - case ssh.KeyAlgoED25519: - addedKey, err = parseEd25519Key(req) - case ssh.CertAlgoRSAv01: - addedKey, err = parseRSACert(req) - case ssh.CertAlgoDSAv01: - addedKey, err = parseDSACert(req) - case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01: - addedKey, err = parseECDSACert(req) - case ssh.CertAlgoED25519v01: - addedKey, err = parseEd25519Cert(req) - default: - return fmt.Errorf("agent: not implemented: %q", record.Type) - } - - if err != nil { - return err - } - return s.agent.Add(*addedKey) -} - -// ServeAgent serves the agent protocol on the given connection. It -// returns when an I/O error occurs. -func ServeAgent(agent Agent, c io.ReadWriter) error { - s := &server{agent} - - var length [4]byte - for { - if _, err := io.ReadFull(c, length[:]); err != nil { - return err - } - l := binary.BigEndian.Uint32(length[:]) - if l == 0 { - return fmt.Errorf("agent: request size is 0") - } - if l > maxAgentResponseBytes { - // We also cap requests. - return fmt.Errorf("agent: request too large: %d", l) - } - - req := make([]byte, l) - if _, err := io.ReadFull(c, req); err != nil { - return err - } - - repData := s.processRequestBytes(req) - if len(repData) > maxAgentResponseBytes { - return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) - } - - binary.BigEndian.PutUint32(length[:], uint32(len(repData))) - if _, err := c.Write(length[:]); err != nil { - return err - } - if _, err := c.Write(repData); err != nil { - return err - } - } -} diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go deleted file mode 100644 index 1ab07d07..00000000 --- a/vendor/golang.org/x/crypto/ssh/buffer.go +++ /dev/null @@ -1,97 +0,0 @@ -// 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 ssh - -import ( - "io" - "sync" -) - -// buffer provides a linked list buffer for data exchange -// between producer and consumer. Theoretically the buffer is -// of unlimited capacity as it does no allocation of its own. -type buffer struct { - // protects concurrent access to head, tail and closed - *sync.Cond - - head *element // the buffer that will be read first - tail *element // the buffer that will be read last - - closed bool -} - -// An element represents a single link in a linked list. -type element struct { - buf []byte - next *element -} - -// newBuffer returns an empty buffer that is not closed. -func newBuffer() *buffer { - e := new(element) - b := &buffer{ - Cond: newCond(), - head: e, - tail: e, - } - return b -} - -// write makes buf available for Read to receive. -// buf must not be modified after the call to write. -func (b *buffer) write(buf []byte) { - b.Cond.L.Lock() - e := &element{buf: buf} - b.tail.next = e - b.tail = e - b.Cond.Signal() - b.Cond.L.Unlock() -} - -// eof closes the buffer. Reads from the buffer once all -// the data has been consumed will receive io.EOF. -func (b *buffer) eof() { - b.Cond.L.Lock() - b.closed = true - b.Cond.Signal() - b.Cond.L.Unlock() -} - -// Read reads data from the internal buffer in buf. Reads will block -// if no data is available, or until the buffer is closed. -func (b *buffer) Read(buf []byte) (n int, err error) { - b.Cond.L.Lock() - defer b.Cond.L.Unlock() - - for len(buf) > 0 { - // if there is data in b.head, copy it - if len(b.head.buf) > 0 { - r := copy(buf, b.head.buf) - buf, b.head.buf = buf[r:], b.head.buf[r:] - n += r - continue - } - // if there is a next buffer, make it the head - if len(b.head.buf) == 0 && b.head != b.tail { - b.head = b.head.next - continue - } - - // if at least one byte has been copied, return - if n > 0 { - break - } - - // if nothing was read, and there is nothing outstanding - // check to see if the buffer is closed. - if b.closed { - err = io.EOF - break - } - // out of buffers, wait for producer - b.Cond.Wait() - } - return -} diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go deleted file mode 100644 index 4600c207..00000000 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ /dev/null @@ -1,589 +0,0 @@ -// 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 ssh - -import ( - "bytes" - "errors" - "fmt" - "io" - "net" - "sort" - "time" -) - -// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear -// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms. -// Unlike key algorithm names, these are not passed to AlgorithmSigner and don't -// appear in the Signature.Format field. -const ( - CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" - CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" - CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" - CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" - CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" - CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" - CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com" - CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com" - - // CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a - // Certificate.Type (or PublicKey.Type), but only in - // ClientConfig.HostKeyAlgorithms. - CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com" - CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com" -) - -const ( - // Deprecated: use CertAlgoRSAv01. - CertSigAlgoRSAv01 = CertAlgoRSAv01 - // Deprecated: use CertAlgoRSASHA256v01. - CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01 - // Deprecated: use CertAlgoRSASHA512v01. - CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01 -) - -// Certificate types distinguish between host and user -// certificates. The values can be set in the CertType field of -// Certificate. -const ( - UserCert = 1 - HostCert = 2 -) - -// Signature represents a cryptographic signature. -type Signature struct { - Format string - Blob []byte - Rest []byte `ssh:"rest"` -} - -// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that -// a certificate does not expire. -const CertTimeInfinity = 1<<64 - 1 - -// An Certificate represents an OpenSSH certificate as defined in -// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the -// PublicKey interface, so it can be unmarshaled using -// ParsePublicKey. -type Certificate struct { - Nonce []byte - Key PublicKey - Serial uint64 - CertType uint32 - KeyId string - ValidPrincipals []string - ValidAfter uint64 - ValidBefore uint64 - Permissions - Reserved []byte - SignatureKey PublicKey - Signature *Signature -} - -// genericCertData holds the key-independent part of the certificate data. -// Overall, certificates contain an nonce, public key fields and -// key-independent fields. -type genericCertData struct { - Serial uint64 - CertType uint32 - KeyId string - ValidPrincipals []byte - ValidAfter uint64 - ValidBefore uint64 - CriticalOptions []byte - Extensions []byte - Reserved []byte - SignatureKey []byte - Signature []byte -} - -func marshalStringList(namelist []string) []byte { - var to []byte - for _, name := range namelist { - s := struct{ N string }{name} - to = append(to, Marshal(&s)...) - } - return to -} - -type optionsTuple struct { - Key string - Value []byte -} - -type optionsTupleValue struct { - Value string -} - -// serialize a map of critical options or extensions -// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, -// we need two length prefixes for a non-empty string value -func marshalTuples(tups map[string]string) []byte { - keys := make([]string, 0, len(tups)) - for key := range tups { - keys = append(keys, key) - } - sort.Strings(keys) - - var ret []byte - for _, key := range keys { - s := optionsTuple{Key: key} - if value := tups[key]; len(value) > 0 { - s.Value = Marshal(&optionsTupleValue{value}) - } - ret = append(ret, Marshal(&s)...) - } - return ret -} - -// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, -// we need two length prefixes for a non-empty option value -func parseTuples(in []byte) (map[string]string, error) { - tups := map[string]string{} - var lastKey string - var haveLastKey bool - - for len(in) > 0 { - var key, val, extra []byte - var ok bool - - if key, in, ok = parseString(in); !ok { - return nil, errShortRead - } - keyStr := string(key) - // according to [PROTOCOL.certkeys], the names must be in - // lexical order. - if haveLastKey && keyStr <= lastKey { - return nil, fmt.Errorf("ssh: certificate options are not in lexical order") - } - lastKey, haveLastKey = keyStr, true - // the next field is a data field, which if non-empty has a string embedded - if val, in, ok = parseString(in); !ok { - return nil, errShortRead - } - if len(val) > 0 { - val, extra, ok = parseString(val) - if !ok { - return nil, errShortRead - } - if len(extra) > 0 { - return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") - } - tups[keyStr] = string(val) - } else { - tups[keyStr] = "" - } - } - return tups, nil -} - -func parseCert(in []byte, privAlgo string) (*Certificate, error) { - nonce, rest, ok := parseString(in) - if !ok { - return nil, errShortRead - } - - key, rest, err := parsePubKey(rest, privAlgo) - if err != nil { - return nil, err - } - - var g genericCertData - if err := Unmarshal(rest, &g); err != nil { - return nil, err - } - - c := &Certificate{ - Nonce: nonce, - Key: key, - Serial: g.Serial, - CertType: g.CertType, - KeyId: g.KeyId, - ValidAfter: g.ValidAfter, - ValidBefore: g.ValidBefore, - } - - for principals := g.ValidPrincipals; len(principals) > 0; { - principal, rest, ok := parseString(principals) - if !ok { - return nil, errShortRead - } - c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) - principals = rest - } - - c.CriticalOptions, err = parseTuples(g.CriticalOptions) - if err != nil { - return nil, err - } - c.Extensions, err = parseTuples(g.Extensions) - if err != nil { - return nil, err - } - c.Reserved = g.Reserved - k, err := ParsePublicKey(g.SignatureKey) - if err != nil { - return nil, err - } - - c.SignatureKey = k - c.Signature, rest, ok = parseSignatureBody(g.Signature) - if !ok || len(rest) > 0 { - return nil, errors.New("ssh: signature parse error") - } - - return c, nil -} - -type openSSHCertSigner struct { - pub *Certificate - signer Signer -} - -type algorithmOpenSSHCertSigner struct { - *openSSHCertSigner - algorithmSigner AlgorithmSigner -} - -// NewCertSigner returns a Signer that signs with the given Certificate, whose -// private key is held by signer. It returns an error if the public key in cert -// doesn't match the key used by signer. -func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { - if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { - return nil, errors.New("ssh: signer and cert have different public key") - } - - if algorithmSigner, ok := signer.(AlgorithmSigner); ok { - return &algorithmOpenSSHCertSigner{ - &openSSHCertSigner{cert, signer}, algorithmSigner}, nil - } else { - return &openSSHCertSigner{cert, signer}, nil - } -} - -func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { - return s.signer.Sign(rand, data) -} - -func (s *openSSHCertSigner) PublicKey() PublicKey { - return s.pub -} - -func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { - return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) -} - -const sourceAddressCriticalOption = "source-address" - -// CertChecker does the work of verifying a certificate. Its methods -// can be plugged into ClientConfig.HostKeyCallback and -// ServerConfig.PublicKeyCallback. For the CertChecker to work, -// minimally, the IsAuthority callback should be set. -type CertChecker struct { - // SupportedCriticalOptions lists the CriticalOptions that the - // server application layer understands. These are only used - // for user certificates. - SupportedCriticalOptions []string - - // IsUserAuthority should return true if the key is recognized as an - // authority for the given user certificate. This allows for - // certificates to be signed by other certificates. This must be set - // if this CertChecker will be checking user certificates. - IsUserAuthority func(auth PublicKey) bool - - // IsHostAuthority should report whether the key is recognized as - // an authority for this host. This allows for certificates to be - // signed by other keys, and for those other keys to only be valid - // signers for particular hostnames. This must be set if this - // CertChecker will be checking host certificates. - IsHostAuthority func(auth PublicKey, address string) bool - - // Clock is used for verifying time stamps. If nil, time.Now - // is used. - Clock func() time.Time - - // UserKeyFallback is called when CertChecker.Authenticate encounters a - // public key that is not a certificate. It must implement validation - // of user keys or else, if nil, all such keys are rejected. - UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) - - // HostKeyFallback is called when CertChecker.CheckHostKey encounters a - // public key that is not a certificate. It must implement host key - // validation or else, if nil, all such keys are rejected. - HostKeyFallback HostKeyCallback - - // IsRevoked is called for each certificate so that revocation checking - // can be implemented. It should return true if the given certificate - // is revoked and false otherwise. If nil, no certificates are - // considered to have been revoked. - IsRevoked func(cert *Certificate) bool -} - -// CheckHostKey checks a host key certificate. This method can be -// plugged into ClientConfig.HostKeyCallback. -func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { - cert, ok := key.(*Certificate) - if !ok { - if c.HostKeyFallback != nil { - return c.HostKeyFallback(addr, remote, key) - } - return errors.New("ssh: non-certificate host key") - } - if cert.CertType != HostCert { - return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) - } - if !c.IsHostAuthority(cert.SignatureKey, addr) { - return fmt.Errorf("ssh: no authorities for hostname: %v", addr) - } - - hostname, _, err := net.SplitHostPort(addr) - if err != nil { - return err - } - - // Pass hostname only as principal for host certificates (consistent with OpenSSH) - return c.CheckCert(hostname, cert) -} - -// Authenticate checks a user certificate. Authenticate can be used as -// a value for ServerConfig.PublicKeyCallback. -func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { - cert, ok := pubKey.(*Certificate) - if !ok { - if c.UserKeyFallback != nil { - return c.UserKeyFallback(conn, pubKey) - } - return nil, errors.New("ssh: normal key pairs not accepted") - } - - if cert.CertType != UserCert { - return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) - } - if !c.IsUserAuthority(cert.SignatureKey) { - return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") - } - - if err := c.CheckCert(conn.User(), cert); err != nil { - return nil, err - } - - return &cert.Permissions, nil -} - -// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and -// the signature of the certificate. -func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { - if c.IsRevoked != nil && c.IsRevoked(cert) { - return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial) - } - - for opt := range cert.CriticalOptions { - // sourceAddressCriticalOption will be enforced by - // serverAuthenticate - if opt == sourceAddressCriticalOption { - continue - } - - found := false - for _, supp := range c.SupportedCriticalOptions { - if supp == opt { - found = true - break - } - } - if !found { - return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) - } - } - - if len(cert.ValidPrincipals) > 0 { - // By default, certs are valid for all users/hosts. - found := false - for _, p := range cert.ValidPrincipals { - if p == principal { - found = true - break - } - } - if !found { - return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) - } - } - - clock := c.Clock - if clock == nil { - clock = time.Now - } - - unixNow := clock().Unix() - if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { - return fmt.Errorf("ssh: cert is not yet valid") - } - if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { - return fmt.Errorf("ssh: cert has expired") - } - if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { - return fmt.Errorf("ssh: certificate signature does not verify") - } - - return nil -} - -// SignCert signs the certificate with an authority, setting the Nonce, -// SignatureKey, and Signature fields. -func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { - c.Nonce = make([]byte, 32) - if _, err := io.ReadFull(rand, c.Nonce); err != nil { - return err - } - c.SignatureKey = authority.PublicKey() - - // Default to KeyAlgoRSASHA512 for ssh-rsa signers. - if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA { - sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512) - if err != nil { - return err - } - c.Signature = sig - return nil - } - - sig, err := authority.Sign(rand, c.bytesForSigning()) - if err != nil { - return err - } - c.Signature = sig - return nil -} - -// certKeyAlgoNames is a mapping from known certificate algorithm names to the -// corresponding public key signature algorithm. -// -// This map must be kept in sync with the one in agent/client.go. -var certKeyAlgoNames = map[string]string{ - CertAlgoRSAv01: KeyAlgoRSA, - CertAlgoRSASHA256v01: KeyAlgoRSASHA256, - CertAlgoRSASHA512v01: KeyAlgoRSASHA512, - CertAlgoDSAv01: KeyAlgoDSA, - CertAlgoECDSA256v01: KeyAlgoECDSA256, - CertAlgoECDSA384v01: KeyAlgoECDSA384, - CertAlgoECDSA521v01: KeyAlgoECDSA521, - CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256, - CertAlgoED25519v01: KeyAlgoED25519, - CertAlgoSKED25519v01: KeyAlgoSKED25519, -} - -// underlyingAlgo returns the signature algorithm associated with algo (which is -// an advertised or negotiated public key or host key algorithm). These are -// usually the same, except for certificate algorithms. -func underlyingAlgo(algo string) string { - if a, ok := certKeyAlgoNames[algo]; ok { - return a - } - return algo -} - -// certificateAlgo returns the certificate algorithms that uses the provided -// underlying signature algorithm. -func certificateAlgo(algo string) (certAlgo string, ok bool) { - for certName, algoName := range certKeyAlgoNames { - if algoName == algo { - return certName, true - } - } - return "", false -} - -func (cert *Certificate) bytesForSigning() []byte { - c2 := *cert - c2.Signature = nil - out := c2.Marshal() - // Drop trailing signature length. - return out[:len(out)-4] -} - -// Marshal serializes c into OpenSSH's wire format. It is part of the -// PublicKey interface. -func (c *Certificate) Marshal() []byte { - generic := genericCertData{ - Serial: c.Serial, - CertType: c.CertType, - KeyId: c.KeyId, - ValidPrincipals: marshalStringList(c.ValidPrincipals), - ValidAfter: uint64(c.ValidAfter), - ValidBefore: uint64(c.ValidBefore), - CriticalOptions: marshalTuples(c.CriticalOptions), - Extensions: marshalTuples(c.Extensions), - Reserved: c.Reserved, - SignatureKey: c.SignatureKey.Marshal(), - } - if c.Signature != nil { - generic.Signature = Marshal(c.Signature) - } - genericBytes := Marshal(&generic) - keyBytes := c.Key.Marshal() - _, keyBytes, _ = parseString(keyBytes) - prefix := Marshal(&struct { - Name string - Nonce []byte - Key []byte `ssh:"rest"` - }{c.Type(), c.Nonce, keyBytes}) - - result := make([]byte, 0, len(prefix)+len(genericBytes)) - result = append(result, prefix...) - result = append(result, genericBytes...) - return result -} - -// Type returns the certificate algorithm name. It is part of the PublicKey interface. -func (c *Certificate) Type() string { - certName, ok := certificateAlgo(c.Key.Type()) - if !ok { - panic("unknown certificate type for key type " + c.Key.Type()) - } - return certName -} - -// Verify verifies a signature against the certificate's public -// key. It is part of the PublicKey interface. -func (c *Certificate) Verify(data []byte, sig *Signature) error { - return c.Key.Verify(data, sig) -} - -func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { - format, in, ok := parseString(in) - if !ok { - return - } - - out = &Signature{ - Format: string(format), - } - - if out.Blob, in, ok = parseString(in); !ok { - return - } - - switch out.Format { - case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01: - out.Rest = in - return out, nil, ok - } - - return out, in, ok -} - -func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { - sigBytes, rest, ok := parseString(in) - if !ok { - return - } - - out, trailing, ok := parseSignatureBody(sigBytes) - if !ok || len(trailing) > 0 { - return nil, nil, false - } - return -} diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go deleted file mode 100644 index c0834c00..00000000 --- a/vendor/golang.org/x/crypto/ssh/channel.go +++ /dev/null @@ -1,633 +0,0 @@ -// 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 ssh - -import ( - "encoding/binary" - "errors" - "fmt" - "io" - "log" - "sync" -) - -const ( - minPacketLength = 9 - // channelMaxPacket contains the maximum number of bytes that will be - // sent in a single packet. As per RFC 4253, section 6.1, 32k is also - // the minimum. - channelMaxPacket = 1 << 15 - // We follow OpenSSH here. - channelWindowSize = 64 * channelMaxPacket -) - -// NewChannel represents an incoming request to a channel. It must either be -// accepted for use by calling Accept, or rejected by calling Reject. -type NewChannel interface { - // Accept accepts the channel creation request. It returns the Channel - // and a Go channel containing SSH requests. The Go channel must be - // serviced otherwise the Channel will hang. - Accept() (Channel, <-chan *Request, error) - - // Reject rejects the channel creation request. After calling - // this, no other methods on the Channel may be called. - Reject(reason RejectionReason, message string) error - - // ChannelType returns the type of the channel, as supplied by the - // client. - ChannelType() string - - // ExtraData returns the arbitrary payload for this channel, as supplied - // by the client. This data is specific to the channel type. - ExtraData() []byte -} - -// A Channel is an ordered, reliable, flow-controlled, duplex stream -// that is multiplexed over an SSH connection. -type Channel interface { - // Read reads up to len(data) bytes from the channel. - Read(data []byte) (int, error) - - // Write writes len(data) bytes to the channel. - Write(data []byte) (int, error) - - // Close signals end of channel use. No data may be sent after this - // call. - Close() error - - // CloseWrite signals the end of sending in-band - // data. Requests may still be sent, and the other side may - // still send data - CloseWrite() error - - // SendRequest sends a channel request. If wantReply is true, - // it will wait for a reply and return the result as a - // boolean, otherwise the return value will be false. Channel - // requests are out-of-band messages so they may be sent even - // if the data stream is closed or blocked by flow control. - // If the channel is closed before a reply is returned, io.EOF - // is returned. - SendRequest(name string, wantReply bool, payload []byte) (bool, error) - - // Stderr returns an io.ReadWriter that writes to this channel - // with the extended data type set to stderr. Stderr may - // safely be read and written from a different goroutine than - // Read and Write respectively. - Stderr() io.ReadWriter -} - -// Request is a request sent outside of the normal stream of -// data. Requests can either be specific to an SSH channel, or they -// can be global. -type Request struct { - Type string - WantReply bool - Payload []byte - - ch *channel - mux *mux -} - -// Reply sends a response to a request. It must be called for all requests -// where WantReply is true and is a no-op otherwise. The payload argument is -// ignored for replies to channel-specific requests. -func (r *Request) Reply(ok bool, payload []byte) error { - if !r.WantReply { - return nil - } - - if r.ch == nil { - return r.mux.ackRequest(ok, payload) - } - - return r.ch.ackRequest(ok) -} - -// RejectionReason is an enumeration used when rejecting channel creation -// requests. See RFC 4254, section 5.1. -type RejectionReason uint32 - -const ( - Prohibited RejectionReason = iota + 1 - ConnectionFailed - UnknownChannelType - ResourceShortage -) - -// String converts the rejection reason to human readable form. -func (r RejectionReason) String() string { - switch r { - case Prohibited: - return "administratively prohibited" - case ConnectionFailed: - return "connect failed" - case UnknownChannelType: - return "unknown channel type" - case ResourceShortage: - return "resource shortage" - } - return fmt.Sprintf("unknown reason %d", int(r)) -} - -func min(a uint32, b int) uint32 { - if a < uint32(b) { - return a - } - return uint32(b) -} - -type channelDirection uint8 - -const ( - channelInbound channelDirection = iota - channelOutbound -) - -// channel is an implementation of the Channel interface that works -// with the mux class. -type channel struct { - // R/O after creation - chanType string - extraData []byte - localId, remoteId uint32 - - // maxIncomingPayload and maxRemotePayload are the maximum - // payload sizes of normal and extended data packets for - // receiving and sending, respectively. The wire packet will - // be 9 or 13 bytes larger (excluding encryption overhead). - maxIncomingPayload uint32 - maxRemotePayload uint32 - - mux *mux - - // decided is set to true if an accept or reject message has been sent - // (for outbound channels) or received (for inbound channels). - decided bool - - // direction contains either channelOutbound, for channels created - // locally, or channelInbound, for channels created by the peer. - direction channelDirection - - // Pending internal channel messages. - msg chan interface{} - - // Since requests have no ID, there can be only one request - // with WantReply=true outstanding. This lock is held by a - // goroutine that has such an outgoing request pending. - sentRequestMu sync.Mutex - - incomingRequests chan *Request - - sentEOF bool - - // thread-safe data - remoteWin window - pending *buffer - extPending *buffer - - // windowMu protects myWindow, the flow-control window. - windowMu sync.Mutex - myWindow uint32 - - // writeMu serializes calls to mux.conn.writePacket() and - // protects sentClose and packetPool. This mutex must be - // different from windowMu, as writePacket can block if there - // is a key exchange pending. - writeMu sync.Mutex - sentClose bool - - // packetPool has a buffer for each extended channel ID to - // save allocations during writes. - packetPool map[uint32][]byte -} - -// writePacket sends a packet. If the packet is a channel close, it updates -// sentClose. This method takes the lock c.writeMu. -func (ch *channel) writePacket(packet []byte) error { - ch.writeMu.Lock() - if ch.sentClose { - ch.writeMu.Unlock() - return io.EOF - } - ch.sentClose = (packet[0] == msgChannelClose) - err := ch.mux.conn.writePacket(packet) - ch.writeMu.Unlock() - return err -} - -func (ch *channel) sendMessage(msg interface{}) error { - if debugMux { - log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg) - } - - p := Marshal(msg) - binary.BigEndian.PutUint32(p[1:], ch.remoteId) - return ch.writePacket(p) -} - -// WriteExtended writes data to a specific extended stream. These streams are -// used, for example, for stderr. -func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { - if ch.sentEOF { - return 0, io.EOF - } - // 1 byte message type, 4 bytes remoteId, 4 bytes data length - opCode := byte(msgChannelData) - headerLength := uint32(9) - if extendedCode > 0 { - headerLength += 4 - opCode = msgChannelExtendedData - } - - ch.writeMu.Lock() - packet := ch.packetPool[extendedCode] - // We don't remove the buffer from packetPool, so - // WriteExtended calls from different goroutines will be - // flagged as errors by the race detector. - ch.writeMu.Unlock() - - for len(data) > 0 { - space := min(ch.maxRemotePayload, len(data)) - if space, err = ch.remoteWin.reserve(space); err != nil { - return n, err - } - if want := headerLength + space; uint32(cap(packet)) < want { - packet = make([]byte, want) - } else { - packet = packet[:want] - } - - todo := data[:space] - - packet[0] = opCode - binary.BigEndian.PutUint32(packet[1:], ch.remoteId) - if extendedCode > 0 { - binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) - } - binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) - copy(packet[headerLength:], todo) - if err = ch.writePacket(packet); err != nil { - return n, err - } - - n += len(todo) - data = data[len(todo):] - } - - ch.writeMu.Lock() - ch.packetPool[extendedCode] = packet - ch.writeMu.Unlock() - - return n, err -} - -func (ch *channel) handleData(packet []byte) error { - headerLen := 9 - isExtendedData := packet[0] == msgChannelExtendedData - if isExtendedData { - headerLen = 13 - } - if len(packet) < headerLen { - // malformed data packet - return parseError(packet[0]) - } - - var extended uint32 - if isExtendedData { - extended = binary.BigEndian.Uint32(packet[5:]) - } - - length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) - if length == 0 { - return nil - } - if length > ch.maxIncomingPayload { - // TODO(hanwen): should send Disconnect? - return errors.New("ssh: incoming packet exceeds maximum payload size") - } - - data := packet[headerLen:] - if length != uint32(len(data)) { - return errors.New("ssh: wrong packet length") - } - - ch.windowMu.Lock() - if ch.myWindow < length { - ch.windowMu.Unlock() - // TODO(hanwen): should send Disconnect with reason? - return errors.New("ssh: remote side wrote too much") - } - ch.myWindow -= length - ch.windowMu.Unlock() - - if extended == 1 { - ch.extPending.write(data) - } else if extended > 0 { - // discard other extended data. - } else { - ch.pending.write(data) - } - return nil -} - -func (c *channel) adjustWindow(n uint32) error { - c.windowMu.Lock() - // Since myWindow is managed on our side, and can never exceed - // the initial window setting, we don't worry about overflow. - c.myWindow += uint32(n) - c.windowMu.Unlock() - return c.sendMessage(windowAdjustMsg{ - AdditionalBytes: uint32(n), - }) -} - -func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { - switch extended { - case 1: - n, err = c.extPending.Read(data) - case 0: - n, err = c.pending.Read(data) - default: - return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) - } - - if n > 0 { - err = c.adjustWindow(uint32(n)) - // sendWindowAdjust can return io.EOF if the remote - // peer has closed the connection, however we want to - // defer forwarding io.EOF to the caller of Read until - // the buffer has been drained. - if n > 0 && err == io.EOF { - err = nil - } - } - - return n, err -} - -func (c *channel) close() { - c.pending.eof() - c.extPending.eof() - close(c.msg) - close(c.incomingRequests) - c.writeMu.Lock() - // This is not necessary for a normal channel teardown, but if - // there was another error, it is. - c.sentClose = true - c.writeMu.Unlock() - // Unblock writers. - c.remoteWin.close() -} - -// responseMessageReceived is called when a success or failure message is -// received on a channel to check that such a message is reasonable for the -// given channel. -func (ch *channel) responseMessageReceived() error { - if ch.direction == channelInbound { - return errors.New("ssh: channel response message received on inbound channel") - } - if ch.decided { - return errors.New("ssh: duplicate response received for channel") - } - ch.decided = true - return nil -} - -func (ch *channel) handlePacket(packet []byte) error { - switch packet[0] { - case msgChannelData, msgChannelExtendedData: - return ch.handleData(packet) - case msgChannelClose: - ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId}) - ch.mux.chanList.remove(ch.localId) - ch.close() - return nil - case msgChannelEOF: - // RFC 4254 is mute on how EOF affects dataExt messages but - // it is logical to signal EOF at the same time. - ch.extPending.eof() - ch.pending.eof() - return nil - } - - decoded, err := decode(packet) - if err != nil { - return err - } - - switch msg := decoded.(type) { - case *channelOpenFailureMsg: - if err := ch.responseMessageReceived(); err != nil { - return err - } - ch.mux.chanList.remove(msg.PeersID) - ch.msg <- msg - case *channelOpenConfirmMsg: - if err := ch.responseMessageReceived(); err != nil { - return err - } - if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { - return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) - } - ch.remoteId = msg.MyID - ch.maxRemotePayload = msg.MaxPacketSize - ch.remoteWin.add(msg.MyWindow) - ch.msg <- msg - case *windowAdjustMsg: - if !ch.remoteWin.add(msg.AdditionalBytes) { - return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) - } - case *channelRequestMsg: - req := Request{ - Type: msg.Request, - WantReply: msg.WantReply, - Payload: msg.RequestSpecificData, - ch: ch, - } - - ch.incomingRequests <- &req - default: - ch.msg <- msg - } - return nil -} - -func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { - ch := &channel{ - remoteWin: window{Cond: newCond()}, - myWindow: channelWindowSize, - pending: newBuffer(), - extPending: newBuffer(), - direction: direction, - incomingRequests: make(chan *Request, chanSize), - msg: make(chan interface{}, chanSize), - chanType: chanType, - extraData: extraData, - mux: m, - packetPool: make(map[uint32][]byte), - } - ch.localId = m.chanList.add(ch) - return ch -} - -var errUndecided = errors.New("ssh: must Accept or Reject channel") -var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") - -type extChannel struct { - code uint32 - ch *channel -} - -func (e *extChannel) Write(data []byte) (n int, err error) { - return e.ch.WriteExtended(data, e.code) -} - -func (e *extChannel) Read(data []byte) (n int, err error) { - return e.ch.ReadExtended(data, e.code) -} - -func (ch *channel) Accept() (Channel, <-chan *Request, error) { - if ch.decided { - return nil, nil, errDecidedAlready - } - ch.maxIncomingPayload = channelMaxPacket - confirm := channelOpenConfirmMsg{ - PeersID: ch.remoteId, - MyID: ch.localId, - MyWindow: ch.myWindow, - MaxPacketSize: ch.maxIncomingPayload, - } - ch.decided = true - if err := ch.sendMessage(confirm); err != nil { - return nil, nil, err - } - - return ch, ch.incomingRequests, nil -} - -func (ch *channel) Reject(reason RejectionReason, message string) error { - if ch.decided { - return errDecidedAlready - } - reject := channelOpenFailureMsg{ - PeersID: ch.remoteId, - Reason: reason, - Message: message, - Language: "en", - } - ch.decided = true - return ch.sendMessage(reject) -} - -func (ch *channel) Read(data []byte) (int, error) { - if !ch.decided { - return 0, errUndecided - } - return ch.ReadExtended(data, 0) -} - -func (ch *channel) Write(data []byte) (int, error) { - if !ch.decided { - return 0, errUndecided - } - return ch.WriteExtended(data, 0) -} - -func (ch *channel) CloseWrite() error { - if !ch.decided { - return errUndecided - } - ch.sentEOF = true - return ch.sendMessage(channelEOFMsg{ - PeersID: ch.remoteId}) -} - -func (ch *channel) Close() error { - if !ch.decided { - return errUndecided - } - - return ch.sendMessage(channelCloseMsg{ - PeersID: ch.remoteId}) -} - -// Extended returns an io.ReadWriter that sends and receives data on the given, -// SSH extended stream. Such streams are used, for example, for stderr. -func (ch *channel) Extended(code uint32) io.ReadWriter { - if !ch.decided { - return nil - } - return &extChannel{code, ch} -} - -func (ch *channel) Stderr() io.ReadWriter { - return ch.Extended(1) -} - -func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { - if !ch.decided { - return false, errUndecided - } - - if wantReply { - ch.sentRequestMu.Lock() - defer ch.sentRequestMu.Unlock() - } - - msg := channelRequestMsg{ - PeersID: ch.remoteId, - Request: name, - WantReply: wantReply, - RequestSpecificData: payload, - } - - if err := ch.sendMessage(msg); err != nil { - return false, err - } - - if wantReply { - m, ok := (<-ch.msg) - if !ok { - return false, io.EOF - } - switch m.(type) { - case *channelRequestFailureMsg: - return false, nil - case *channelRequestSuccessMsg: - return true, nil - default: - return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) - } - } - - return false, nil -} - -// ackRequest either sends an ack or nack to the channel request. -func (ch *channel) ackRequest(ok bool) error { - if !ch.decided { - return errUndecided - } - - var msg interface{} - if !ok { - msg = channelRequestFailureMsg{ - PeersID: ch.remoteId, - } - } else { - msg = channelRequestSuccessMsg{ - PeersID: ch.remoteId, - } - } - return ch.sendMessage(msg) -} - -func (ch *channel) ChannelType() string { - return ch.chanType -} - -func (ch *channel) ExtraData() []byte { - return ch.extraData -} diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go deleted file mode 100644 index 770e8a66..00000000 --- a/vendor/golang.org/x/crypto/ssh/cipher.go +++ /dev/null @@ -1,789 +0,0 @@ -// 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 ssh - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/rc4" - "crypto/subtle" - "encoding/binary" - "errors" - "fmt" - "hash" - "io" - "io/ioutil" - - "golang.org/x/crypto/chacha20" - "golang.org/x/crypto/internal/poly1305" -) - -const ( - packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. - - // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations - // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC - // indicates implementations SHOULD be able to handle larger packet sizes, but then - // waffles on about reasonable limits. - // - // OpenSSH caps their maxPacket at 256kB so we choose to do - // the same. maxPacket is also used to ensure that uint32 - // length fields do not overflow, so it should remain well - // below 4G. - maxPacket = 256 * 1024 -) - -// noneCipher implements cipher.Stream and provides no encryption. It is used -// by the transport before the first key-exchange. -type noneCipher struct{} - -func (c noneCipher) XORKeyStream(dst, src []byte) { - copy(dst, src) -} - -func newAESCTR(key, iv []byte) (cipher.Stream, error) { - c, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - return cipher.NewCTR(c, iv), nil -} - -func newRC4(key, iv []byte) (cipher.Stream, error) { - return rc4.NewCipher(key) -} - -type cipherMode struct { - keySize int - ivSize int - create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) -} - -func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) { - return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { - stream, err := createFunc(key, iv) - if err != nil { - return nil, err - } - - var streamDump []byte - if skip > 0 { - streamDump = make([]byte, 512) - } - - for remainingToDump := skip; remainingToDump > 0; { - dumpThisTime := remainingToDump - if dumpThisTime > len(streamDump) { - dumpThisTime = len(streamDump) - } - stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) - remainingToDump -= dumpThisTime - } - - mac := macModes[algs.MAC].new(macKey) - return &streamPacketCipher{ - mac: mac, - etm: macModes[algs.MAC].etm, - macResult: make([]byte, mac.Size()), - cipher: stream, - }, nil - } -} - -// cipherModes documents properties of supported ciphers. Ciphers not included -// are not supported and will not be negotiated, even if explicitly requested in -// ClientConfig.Crypto.Ciphers. -var cipherModes = map[string]*cipherMode{ - // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms - // are defined in the order specified in the RFC. - "aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, - "aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, - "aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, - - // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. - // They are defined in the order specified in the RFC. - "arcfour128": {16, 0, streamCipherMode(1536, newRC4)}, - "arcfour256": {32, 0, streamCipherMode(1536, newRC4)}, - - // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. - // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and - // RC4) has problems with weak keys, and should be used with caution." - // RFC4345 introduces improved versions of Arcfour. - "arcfour": {16, 0, streamCipherMode(0, newRC4)}, - - // AEAD ciphers - gcmCipherID: {16, 12, newGCMCipher}, - chacha20Poly1305ID: {64, 0, newChaCha20Cipher}, - - // CBC mode is insecure and so is not included in the default config. - // (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely - // needed, it's possible to specify a custom Config to enable it. - // You should expect that an active attacker can recover plaintext if - // you do. - aes128cbcID: {16, aes.BlockSize, newAESCBCCipher}, - - // 3des-cbc is insecure and is not included in the default - // config. - tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher}, -} - -// prefixLen is the length of the packet prefix that contains the packet length -// and number of padding bytes. -const prefixLen = 5 - -// streamPacketCipher is a packetCipher using a stream cipher. -type streamPacketCipher struct { - mac hash.Hash - cipher cipher.Stream - etm bool - - // The following members are to avoid per-packet allocations. - prefix [prefixLen]byte - seqNumBytes [4]byte - padding [2 * packetSizeMultiple]byte - packetData []byte - macResult []byte -} - -// readCipherPacket reads and decrypt a single packet from the reader argument. -func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { - if _, err := io.ReadFull(r, s.prefix[:]); err != nil { - return nil, err - } - - var encryptedPaddingLength [1]byte - if s.mac != nil && s.etm { - copy(encryptedPaddingLength[:], s.prefix[4:5]) - s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) - } else { - s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) - } - - length := binary.BigEndian.Uint32(s.prefix[0:4]) - paddingLength := uint32(s.prefix[4]) - - var macSize uint32 - if s.mac != nil { - s.mac.Reset() - binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) - s.mac.Write(s.seqNumBytes[:]) - if s.etm { - s.mac.Write(s.prefix[:4]) - s.mac.Write(encryptedPaddingLength[:]) - } else { - s.mac.Write(s.prefix[:]) - } - macSize = uint32(s.mac.Size()) - } - - if length <= paddingLength+1 { - return nil, errors.New("ssh: invalid packet length, packet too small") - } - - if length > maxPacket { - return nil, errors.New("ssh: invalid packet length, packet too large") - } - - // the maxPacket check above ensures that length-1+macSize - // does not overflow. - if uint32(cap(s.packetData)) < length-1+macSize { - s.packetData = make([]byte, length-1+macSize) - } else { - s.packetData = s.packetData[:length-1+macSize] - } - - if _, err := io.ReadFull(r, s.packetData); err != nil { - return nil, err - } - mac := s.packetData[length-1:] - data := s.packetData[:length-1] - - if s.mac != nil && s.etm { - s.mac.Write(data) - } - - s.cipher.XORKeyStream(data, data) - - if s.mac != nil { - if !s.etm { - s.mac.Write(data) - } - s.macResult = s.mac.Sum(s.macResult[:0]) - if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { - return nil, errors.New("ssh: MAC failure") - } - } - - return s.packetData[:length-paddingLength-1], nil -} - -// writeCipherPacket encrypts and sends a packet of data to the writer argument -func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { - if len(packet) > maxPacket { - return errors.New("ssh: packet too large") - } - - aadlen := 0 - if s.mac != nil && s.etm { - // packet length is not encrypted for EtM modes - aadlen = 4 - } - - paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple - if paddingLength < 4 { - paddingLength += packetSizeMultiple - } - - length := len(packet) + 1 + paddingLength - binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) - s.prefix[4] = byte(paddingLength) - padding := s.padding[:paddingLength] - if _, err := io.ReadFull(rand, padding); err != nil { - return err - } - - if s.mac != nil { - s.mac.Reset() - binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) - s.mac.Write(s.seqNumBytes[:]) - - if s.etm { - // For EtM algorithms, the packet length must stay unencrypted, - // but the following data (padding length) must be encrypted - s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) - } - - s.mac.Write(s.prefix[:]) - - if !s.etm { - // For non-EtM algorithms, the algorithm is applied on unencrypted data - s.mac.Write(packet) - s.mac.Write(padding) - } - } - - if !(s.mac != nil && s.etm) { - // For EtM algorithms, the padding length has already been encrypted - // and the packet length must remain unencrypted - s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) - } - - s.cipher.XORKeyStream(packet, packet) - s.cipher.XORKeyStream(padding, padding) - - if s.mac != nil && s.etm { - // For EtM algorithms, packet and padding must be encrypted - s.mac.Write(packet) - s.mac.Write(padding) - } - - if _, err := w.Write(s.prefix[:]); err != nil { - return err - } - if _, err := w.Write(packet); err != nil { - return err - } - if _, err := w.Write(padding); err != nil { - return err - } - - if s.mac != nil { - s.macResult = s.mac.Sum(s.macResult[:0]) - if _, err := w.Write(s.macResult); err != nil { - return err - } - } - - return nil -} - -type gcmCipher struct { - aead cipher.AEAD - prefix [4]byte - iv []byte - buf []byte -} - -func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { - c, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - aead, err := cipher.NewGCM(c) - if err != nil { - return nil, err - } - - return &gcmCipher{ - aead: aead, - iv: iv, - }, nil -} - -const gcmTagSize = 16 - -func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { - // Pad out to multiple of 16 bytes. This is different from the - // stream cipher because that encrypts the length too. - padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) - if padding < 4 { - padding += packetSizeMultiple - } - - length := uint32(len(packet) + int(padding) + 1) - binary.BigEndian.PutUint32(c.prefix[:], length) - if _, err := w.Write(c.prefix[:]); err != nil { - return err - } - - if cap(c.buf) < int(length) { - c.buf = make([]byte, length) - } else { - c.buf = c.buf[:length] - } - - c.buf[0] = padding - copy(c.buf[1:], packet) - if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { - return err - } - c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) - if _, err := w.Write(c.buf); err != nil { - return err - } - c.incIV() - - return nil -} - -func (c *gcmCipher) incIV() { - for i := 4 + 7; i >= 4; i-- { - c.iv[i]++ - if c.iv[i] != 0 { - break - } - } -} - -func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { - if _, err := io.ReadFull(r, c.prefix[:]); err != nil { - return nil, err - } - length := binary.BigEndian.Uint32(c.prefix[:]) - if length > maxPacket { - return nil, errors.New("ssh: max packet length exceeded") - } - - if cap(c.buf) < int(length+gcmTagSize) { - c.buf = make([]byte, length+gcmTagSize) - } else { - c.buf = c.buf[:length+gcmTagSize] - } - - if _, err := io.ReadFull(r, c.buf); err != nil { - return nil, err - } - - plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) - if err != nil { - return nil, err - } - c.incIV() - - if len(plain) == 0 { - return nil, errors.New("ssh: empty packet") - } - - padding := plain[0] - if padding < 4 { - // padding is a byte, so it automatically satisfies - // the maximum size, which is 255. - return nil, fmt.Errorf("ssh: illegal padding %d", padding) - } - - if int(padding+1) >= len(plain) { - return nil, fmt.Errorf("ssh: padding %d too large", padding) - } - plain = plain[1 : length-uint32(padding)] - return plain, nil -} - -// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 -type cbcCipher struct { - mac hash.Hash - macSize uint32 - decrypter cipher.BlockMode - encrypter cipher.BlockMode - - // The following members are to avoid per-packet allocations. - seqNumBytes [4]byte - packetData []byte - macResult []byte - - // Amount of data we should still read to hide which - // verification error triggered. - oracleCamouflage uint32 -} - -func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { - cbc := &cbcCipher{ - mac: macModes[algs.MAC].new(macKey), - decrypter: cipher.NewCBCDecrypter(c, iv), - encrypter: cipher.NewCBCEncrypter(c, iv), - packetData: make([]byte, 1024), - } - if cbc.mac != nil { - cbc.macSize = uint32(cbc.mac.Size()) - } - - return cbc, nil -} - -func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { - c, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - cbc, err := newCBCCipher(c, key, iv, macKey, algs) - if err != nil { - return nil, err - } - - return cbc, nil -} - -func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { - c, err := des.NewTripleDESCipher(key) - if err != nil { - return nil, err - } - - cbc, err := newCBCCipher(c, key, iv, macKey, algs) - if err != nil { - return nil, err - } - - return cbc, nil -} - -func maxUInt32(a, b int) uint32 { - if a > b { - return uint32(a) - } - return uint32(b) -} - -const ( - cbcMinPacketSizeMultiple = 8 - cbcMinPacketSize = 16 - cbcMinPaddingSize = 4 -) - -// cbcError represents a verification error that may leak information. -type cbcError string - -func (e cbcError) Error() string { return string(e) } - -func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { - p, err := c.readCipherPacketLeaky(seqNum, r) - if err != nil { - if _, ok := err.(cbcError); ok { - // Verification error: read a fixed amount of - // data, to make distinguishing between - // failing MAC and failing length check more - // difficult. - io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) - } - } - return p, err -} - -func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { - blockSize := c.decrypter.BlockSize() - - // Read the header, which will include some of the subsequent data in the - // case of block ciphers - this is copied back to the payload later. - // How many bytes of payload/padding will be read with this first read. - firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) - firstBlock := c.packetData[:firstBlockLength] - if _, err := io.ReadFull(r, firstBlock); err != nil { - return nil, err - } - - c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength - - c.decrypter.CryptBlocks(firstBlock, firstBlock) - length := binary.BigEndian.Uint32(firstBlock[:4]) - if length > maxPacket { - return nil, cbcError("ssh: packet too large") - } - if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { - // The minimum size of a packet is 16 (or the cipher block size, whichever - // is larger) bytes. - return nil, cbcError("ssh: packet too small") - } - // The length of the packet (including the length field but not the MAC) must - // be a multiple of the block size or 8, whichever is larger. - if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { - return nil, cbcError("ssh: invalid packet length multiple") - } - - paddingLength := uint32(firstBlock[4]) - if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { - return nil, cbcError("ssh: invalid packet length") - } - - // Positions within the c.packetData buffer: - macStart := 4 + length - paddingStart := macStart - paddingLength - - // Entire packet size, starting before length, ending at end of mac. - entirePacketSize := macStart + c.macSize - - // Ensure c.packetData is large enough for the entire packet data. - if uint32(cap(c.packetData)) < entirePacketSize { - // Still need to upsize and copy, but this should be rare at runtime, only - // on upsizing the packetData buffer. - c.packetData = make([]byte, entirePacketSize) - copy(c.packetData, firstBlock) - } else { - c.packetData = c.packetData[:entirePacketSize] - } - - n, err := io.ReadFull(r, c.packetData[firstBlockLength:]) - if err != nil { - return nil, err - } - c.oracleCamouflage -= uint32(n) - - remainingCrypted := c.packetData[firstBlockLength:macStart] - c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) - - mac := c.packetData[macStart:] - if c.mac != nil { - c.mac.Reset() - binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) - c.mac.Write(c.seqNumBytes[:]) - c.mac.Write(c.packetData[:macStart]) - c.macResult = c.mac.Sum(c.macResult[:0]) - if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { - return nil, cbcError("ssh: MAC failure") - } - } - - return c.packetData[prefixLen:paddingStart], nil -} - -func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { - effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) - - // Length of encrypted portion of the packet (header, payload, padding). - // Enforce minimum padding and packet size. - encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) - // Enforce block size. - encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize - - length := encLength - 4 - paddingLength := int(length) - (1 + len(packet)) - - // Overall buffer contains: header, payload, padding, mac. - // Space for the MAC is reserved in the capacity but not the slice length. - bufferSize := encLength + c.macSize - if uint32(cap(c.packetData)) < bufferSize { - c.packetData = make([]byte, encLength, bufferSize) - } else { - c.packetData = c.packetData[:encLength] - } - - p := c.packetData - - // Packet header. - binary.BigEndian.PutUint32(p, length) - p = p[4:] - p[0] = byte(paddingLength) - - // Payload. - p = p[1:] - copy(p, packet) - - // Padding. - p = p[len(packet):] - if _, err := io.ReadFull(rand, p); err != nil { - return err - } - - if c.mac != nil { - c.mac.Reset() - binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) - c.mac.Write(c.seqNumBytes[:]) - c.mac.Write(c.packetData) - // The MAC is now appended into the capacity reserved for it earlier. - c.packetData = c.mac.Sum(c.packetData) - } - - c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) - - if _, err := w.Write(c.packetData); err != nil { - return err - } - - return nil -} - -const chacha20Poly1305ID = "chacha20-poly1305@openssh.com" - -// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com -// AEAD, which is described here: -// -// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 -// -// the methods here also implement padding, which RFC4253 Section 6 -// also requires of stream ciphers. -type chacha20Poly1305Cipher struct { - lengthKey [32]byte - contentKey [32]byte - buf []byte -} - -func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { - if len(key) != 64 { - panic(len(key)) - } - - c := &chacha20Poly1305Cipher{ - buf: make([]byte, 256), - } - - copy(c.contentKey[:], key[:32]) - copy(c.lengthKey[:], key[32:]) - return c, nil -} - -func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { - nonce := make([]byte, 12) - binary.BigEndian.PutUint32(nonce[8:], seqNum) - s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce) - if err != nil { - return nil, err - } - var polyKey, discardBuf [32]byte - s.XORKeyStream(polyKey[:], polyKey[:]) - s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes - - encryptedLength := c.buf[:4] - if _, err := io.ReadFull(r, encryptedLength); err != nil { - return nil, err - } - - var lenBytes [4]byte - ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce) - if err != nil { - return nil, err - } - ls.XORKeyStream(lenBytes[:], encryptedLength) - - length := binary.BigEndian.Uint32(lenBytes[:]) - if length > maxPacket { - return nil, errors.New("ssh: invalid packet length, packet too large") - } - - contentEnd := 4 + length - packetEnd := contentEnd + poly1305.TagSize - if uint32(cap(c.buf)) < packetEnd { - c.buf = make([]byte, packetEnd) - copy(c.buf[:], encryptedLength) - } else { - c.buf = c.buf[:packetEnd] - } - - if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil { - return nil, err - } - - var mac [poly1305.TagSize]byte - copy(mac[:], c.buf[contentEnd:packetEnd]) - if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) { - return nil, errors.New("ssh: MAC failure") - } - - plain := c.buf[4:contentEnd] - s.XORKeyStream(plain, plain) - - if len(plain) == 0 { - return nil, errors.New("ssh: empty packet") - } - - padding := plain[0] - if padding < 4 { - // padding is a byte, so it automatically satisfies - // the maximum size, which is 255. - return nil, fmt.Errorf("ssh: illegal padding %d", padding) - } - - if int(padding)+1 >= len(plain) { - return nil, fmt.Errorf("ssh: padding %d too large", padding) - } - - plain = plain[1 : len(plain)-int(padding)] - - return plain, nil -} - -func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { - nonce := make([]byte, 12) - binary.BigEndian.PutUint32(nonce[8:], seqNum) - s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce) - if err != nil { - return err - } - var polyKey, discardBuf [32]byte - s.XORKeyStream(polyKey[:], polyKey[:]) - s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes - - // There is no blocksize, so fall back to multiple of 8 byte - // padding, as described in RFC 4253, Sec 6. - const packetSizeMultiple = 8 - - padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple - if padding < 4 { - padding += packetSizeMultiple - } - - // size (4 bytes), padding (1), payload, padding, tag. - totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize - if cap(c.buf) < totalLength { - c.buf = make([]byte, totalLength) - } else { - c.buf = c.buf[:totalLength] - } - - binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) - ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce) - if err != nil { - return err - } - ls.XORKeyStream(c.buf, c.buf[:4]) - c.buf[4] = byte(padding) - copy(c.buf[5:], payload) - packetEnd := 5 + len(payload) + padding - if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil { - return err - } - - s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) - - var mac [poly1305.TagSize]byte - poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) - - copy(c.buf[packetEnd:], mac[:]) - - if _, err := w.Write(c.buf); err != nil { - return err - } - return nil -} diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go deleted file mode 100644 index bdc356cb..00000000 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ /dev/null @@ -1,282 +0,0 @@ -// 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 ssh - -import ( - "bytes" - "errors" - "fmt" - "net" - "os" - "sync" - "time" -) - -// Client implements a traditional SSH client that supports shells, -// subprocesses, TCP port/streamlocal forwarding and tunneled dialing. -type Client struct { - Conn - - handleForwardsOnce sync.Once // guards calling (*Client).handleForwards - - forwards forwardList // forwarded tcpip connections from the remote side - mu sync.Mutex - channelHandlers map[string]chan NewChannel -} - -// HandleChannelOpen returns a channel on which NewChannel requests -// for the given type are sent. If the type already is being handled, -// nil is returned. The channel is closed when the connection is closed. -func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { - c.mu.Lock() - defer c.mu.Unlock() - if c.channelHandlers == nil { - // The SSH channel has been closed. - c := make(chan NewChannel) - close(c) - return c - } - - ch := c.channelHandlers[channelType] - if ch != nil { - return nil - } - - ch = make(chan NewChannel, chanSize) - c.channelHandlers[channelType] = ch - return ch -} - -// NewClient creates a Client on top of the given connection. -func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { - conn := &Client{ - Conn: c, - channelHandlers: make(map[string]chan NewChannel, 1), - } - - go conn.handleGlobalRequests(reqs) - go conn.handleChannelOpens(chans) - go func() { - conn.Wait() - conn.forwards.closeAll() - }() - return conn -} - -// NewClientConn establishes an authenticated SSH connection using c -// as the underlying transport. The Request and NewChannel channels -// must be serviced or the connection will hang. -func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { - fullConf := *config - fullConf.SetDefaults() - if fullConf.HostKeyCallback == nil { - c.Close() - return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback") - } - - conn := &connection{ - sshConn: sshConn{conn: c, user: fullConf.User}, - } - - if err := conn.clientHandshake(addr, &fullConf); err != nil { - c.Close() - return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) - } - conn.mux = newMux(conn.transport) - return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil -} - -// clientHandshake performs the client side key exchange. See RFC 4253 Section -// 7. -func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { - if config.ClientVersion != "" { - c.clientVersion = []byte(config.ClientVersion) - } else { - c.clientVersion = []byte(packageVersion) - } - var err error - c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) - if err != nil { - return err - } - - c.transport = newClientTransport( - newTransport(c.sshConn.conn, config.Rand, true /* is client */), - c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) - if err := c.transport.waitSession(); err != nil { - return err - } - - c.sessionID = c.transport.getSessionID() - return c.clientAuthenticate(config) -} - -// verifyHostKeySignature verifies the host key obtained in the key exchange. -// algo is the negotiated algorithm, and may be a certificate type. -func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error { - sig, rest, ok := parseSignatureBody(result.Signature) - if len(rest) > 0 || !ok { - return errors.New("ssh: signature parse error") - } - - if a := underlyingAlgo(algo); sig.Format != a { - return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, a) - } - - return hostKey.Verify(result.H, sig) -} - -// NewSession opens a new Session for this client. (A session is a remote -// execution of a program.) -func (c *Client) NewSession() (*Session, error) { - ch, in, err := c.OpenChannel("session", nil) - if err != nil { - return nil, err - } - return newSession(ch, in) -} - -func (c *Client) handleGlobalRequests(incoming <-chan *Request) { - for r := range incoming { - // This handles keepalive messages and matches - // the behaviour of OpenSSH. - r.Reply(false, nil) - } -} - -// handleChannelOpens channel open messages from the remote side. -func (c *Client) handleChannelOpens(in <-chan NewChannel) { - for ch := range in { - c.mu.Lock() - handler := c.channelHandlers[ch.ChannelType()] - c.mu.Unlock() - - if handler != nil { - handler <- ch - } else { - ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) - } - } - - c.mu.Lock() - for _, ch := range c.channelHandlers { - close(ch) - } - c.channelHandlers = nil - c.mu.Unlock() -} - -// Dial starts a client connection to the given SSH server. It is a -// convenience function that connects to the given network address, -// initiates the SSH handshake, and then sets up a Client. For access -// to incoming channels and requests, use net.Dial with NewClientConn -// instead. -func Dial(network, addr string, config *ClientConfig) (*Client, error) { - conn, err := net.DialTimeout(network, addr, config.Timeout) - if err != nil { - return nil, err - } - c, chans, reqs, err := NewClientConn(conn, addr, config) - if err != nil { - return nil, err - } - return NewClient(c, chans, reqs), nil -} - -// HostKeyCallback is the function type used for verifying server -// keys. A HostKeyCallback must return nil if the host key is OK, or -// an error to reject it. It receives the hostname as passed to Dial -// or NewClientConn. The remote address is the RemoteAddr of the -// net.Conn underlying the SSH connection. -type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error - -// BannerCallback is the function type used for treat the banner sent by -// the server. A BannerCallback receives the message sent by the remote server. -type BannerCallback func(message string) error - -// A ClientConfig structure is used to configure a Client. It must not be -// modified after having been passed to an SSH function. -type ClientConfig struct { - // Config contains configuration that is shared between clients and - // servers. - Config - - // User contains the username to authenticate as. - User string - - // Auth contains possible authentication methods to use with the - // server. Only the first instance of a particular RFC 4252 method will - // be used during authentication. - Auth []AuthMethod - - // HostKeyCallback is called during the cryptographic - // handshake to validate the server's host key. The client - // configuration must supply this callback for the connection - // to succeed. The functions InsecureIgnoreHostKey or - // FixedHostKey can be used for simplistic host key checks. - HostKeyCallback HostKeyCallback - - // BannerCallback is called during the SSH dance to display a custom - // server's message. The client configuration can supply this callback to - // handle it as wished. The function BannerDisplayStderr can be used for - // simplistic display on Stderr. - BannerCallback BannerCallback - - // ClientVersion contains the version identification string that will - // be used for the connection. If empty, a reasonable default is used. - ClientVersion string - - // HostKeyAlgorithms lists the public key algorithms that the client will - // accept from the server for host key authentication, in order of - // preference. If empty, a reasonable default is used. Any - // string returned from a PublicKey.Type method may be used, or - // any of the CertAlgo and KeyAlgo constants. - HostKeyAlgorithms []string - - // Timeout is the maximum amount of time for the TCP connection to establish. - // - // A Timeout of zero means no timeout. - Timeout time.Duration -} - -// InsecureIgnoreHostKey returns a function that can be used for -// ClientConfig.HostKeyCallback to accept any host key. It should -// not be used for production code. -func InsecureIgnoreHostKey() HostKeyCallback { - return func(hostname string, remote net.Addr, key PublicKey) error { - return nil - } -} - -type fixedHostKey struct { - key PublicKey -} - -func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error { - if f.key == nil { - return fmt.Errorf("ssh: required host key was nil") - } - if !bytes.Equal(key.Marshal(), f.key.Marshal()) { - return fmt.Errorf("ssh: host key mismatch") - } - return nil -} - -// FixedHostKey returns a function for use in -// ClientConfig.HostKeyCallback to accept only a specific host key. -func FixedHostKey(key PublicKey) HostKeyCallback { - hk := &fixedHostKey{key} - return hk.check -} - -// BannerDisplayStderr returns a function that can be used for -// ClientConfig.BannerCallback to display banners on os.Stderr. -func BannerDisplayStderr() BannerCallback { - return func(banner string) error { - _, err := os.Stderr.WriteString(banner) - - return err - } -} diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go deleted file mode 100644 index 409b5ea1..00000000 --- a/vendor/golang.org/x/crypto/ssh/client_auth.go +++ /dev/null @@ -1,725 +0,0 @@ -// 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 ssh - -import ( - "bytes" - "errors" - "fmt" - "io" - "strings" -) - -type authResult int - -const ( - authFailure authResult = iota - authPartialSuccess - authSuccess -) - -// clientAuthenticate authenticates with the remote server. See RFC 4252. -func (c *connection) clientAuthenticate(config *ClientConfig) error { - // initiate user auth session - if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { - return err - } - packet, err := c.transport.readPacket() - if err != nil { - return err - } - // The server may choose to send a SSH_MSG_EXT_INFO at this point (if we - // advertised willingness to receive one, which we always do) or not. See - // RFC 8308, Section 2.4. - extensions := make(map[string][]byte) - if len(packet) > 0 && packet[0] == msgExtInfo { - var extInfo extInfoMsg - if err := Unmarshal(packet, &extInfo); err != nil { - return err - } - payload := extInfo.Payload - for i := uint32(0); i < extInfo.NumExtensions; i++ { - name, rest, ok := parseString(payload) - if !ok { - return parseError(msgExtInfo) - } - value, rest, ok := parseString(rest) - if !ok { - return parseError(msgExtInfo) - } - extensions[string(name)] = value - payload = rest - } - packet, err = c.transport.readPacket() - if err != nil { - return err - } - } - var serviceAccept serviceAcceptMsg - if err := Unmarshal(packet, &serviceAccept); err != nil { - return err - } - - // during the authentication phase the client first attempts the "none" method - // then any untried methods suggested by the server. - var tried []string - var lastMethods []string - - sessionID := c.transport.getSessionID() - for auth := AuthMethod(new(noneAuth)); auth != nil; { - ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions) - if err != nil { - return err - } - if ok == authSuccess { - // success - return nil - } else if ok == authFailure { - if m := auth.method(); !contains(tried, m) { - tried = append(tried, m) - } - } - if methods == nil { - methods = lastMethods - } - lastMethods = methods - - auth = nil - - findNext: - for _, a := range config.Auth { - candidateMethod := a.method() - if contains(tried, candidateMethod) { - continue - } - for _, meth := range methods { - if meth == candidateMethod { - auth = a - break findNext - } - } - } - } - return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried) -} - -func contains(list []string, e string) bool { - for _, s := range list { - if s == e { - return true - } - } - return false -} - -// An AuthMethod represents an instance of an RFC 4252 authentication method. -type AuthMethod interface { - // auth authenticates user over transport t. - // Returns true if authentication is successful. - // If authentication is not successful, a []string of alternative - // method names is returned. If the slice is nil, it will be ignored - // and the previous set of possible methods will be reused. - auth(session []byte, user string, p packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) - - // method returns the RFC 4252 method name. - method() string -} - -// "none" authentication, RFC 4252 section 5.2. -type noneAuth int - -func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { - if err := c.writePacket(Marshal(&userAuthRequestMsg{ - User: user, - Service: serviceSSH, - Method: "none", - })); err != nil { - return authFailure, nil, err - } - - return handleAuthResponse(c) -} - -func (n *noneAuth) method() string { - return "none" -} - -// passwordCallback is an AuthMethod that fetches the password through -// a function call, e.g. by prompting the user. -type passwordCallback func() (password string, err error) - -func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { - type passwordAuthMsg struct { - User string `sshtype:"50"` - Service string - Method string - Reply bool - Password string - } - - pw, err := cb() - // REVIEW NOTE: is there a need to support skipping a password attempt? - // The program may only find out that the user doesn't have a password - // when prompting. - if err != nil { - return authFailure, nil, err - } - - if err := c.writePacket(Marshal(&passwordAuthMsg{ - User: user, - Service: serviceSSH, - Method: cb.method(), - Reply: false, - Password: pw, - })); err != nil { - return authFailure, nil, err - } - - return handleAuthResponse(c) -} - -func (cb passwordCallback) method() string { - return "password" -} - -// Password returns an AuthMethod using the given password. -func Password(secret string) AuthMethod { - return passwordCallback(func() (string, error) { return secret, nil }) -} - -// PasswordCallback returns an AuthMethod that uses a callback for -// fetching a password. -func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { - return passwordCallback(prompt) -} - -type publickeyAuthMsg struct { - User string `sshtype:"50"` - Service string - Method string - // HasSig indicates to the receiver packet that the auth request is signed and - // should be used for authentication of the request. - HasSig bool - Algoname string - PubKey []byte - // Sig is tagged with "rest" so Marshal will exclude it during - // validateKey - Sig []byte `ssh:"rest"` -} - -// publicKeyCallback is an AuthMethod that uses a set of key -// pairs for authentication. -type publicKeyCallback func() ([]Signer, error) - -func (cb publicKeyCallback) method() string { - return "publickey" -} - -func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) { - keyFormat := signer.PublicKey().Type() - - // Like in sendKexInit, if the public key implements AlgorithmSigner we - // assume it supports all algorithms, otherwise only the key format one. - as, ok := signer.(AlgorithmSigner) - if !ok { - return algorithmSignerWrapper{signer}, keyFormat - } - - extPayload, ok := extensions["server-sig-algs"] - if !ok { - // If there is no "server-sig-algs" extension, fall back to the key - // format algorithm. - return as, keyFormat - } - - // The server-sig-algs extension only carries underlying signature - // algorithm, but we are trying to select a protocol-level public key - // algorithm, which might be a certificate type. Extend the list of server - // supported algorithms to include the corresponding certificate algorithms. - serverAlgos := strings.Split(string(extPayload), ",") - for _, algo := range serverAlgos { - if certAlgo, ok := certificateAlgo(algo); ok { - serverAlgos = append(serverAlgos, certAlgo) - } - } - - keyAlgos := algorithmsForKeyFormat(keyFormat) - algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos) - if err != nil { - // If there is no overlap, try the key anyway with the key format - // algorithm, to support servers that fail to list all supported - // algorithms. - return as, keyFormat - } - return as, algo -} - -func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) { - // Authentication is performed by sending an enquiry to test if a key is - // acceptable to the remote. If the key is acceptable, the client will - // attempt to authenticate with the valid key. If not the client will repeat - // the process with the remaining keys. - - signers, err := cb() - if err != nil { - return authFailure, nil, err - } - var methods []string - for _, signer := range signers { - pub := signer.PublicKey() - as, algo := pickSignatureAlgorithm(signer, extensions) - - ok, err := validateKey(pub, algo, user, c) - if err != nil { - return authFailure, nil, err - } - if !ok { - continue - } - - pubKey := pub.Marshal() - data := buildDataSignedForAuth(session, userAuthRequestMsg{ - User: user, - Service: serviceSSH, - Method: cb.method(), - }, algo, pubKey) - sign, err := as.SignWithAlgorithm(rand, data, underlyingAlgo(algo)) - if err != nil { - return authFailure, nil, err - } - - // manually wrap the serialized signature in a string - s := Marshal(sign) - sig := make([]byte, stringLength(len(s))) - marshalString(sig, s) - msg := publickeyAuthMsg{ - User: user, - Service: serviceSSH, - Method: cb.method(), - HasSig: true, - Algoname: algo, - PubKey: pubKey, - Sig: sig, - } - p := Marshal(&msg) - if err := c.writePacket(p); err != nil { - return authFailure, nil, err - } - var success authResult - success, methods, err = handleAuthResponse(c) - if err != nil { - return authFailure, nil, err - } - - // If authentication succeeds or the list of available methods does not - // contain the "publickey" method, do not attempt to authenticate with any - // other keys. According to RFC 4252 Section 7, the latter can occur when - // additional authentication methods are required. - if success == authSuccess || !containsMethod(methods, cb.method()) { - return success, methods, err - } - } - - return authFailure, methods, nil -} - -func containsMethod(methods []string, method string) bool { - for _, m := range methods { - if m == method { - return true - } - } - - return false -} - -// validateKey validates the key provided is acceptable to the server. -func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, error) { - pubKey := key.Marshal() - msg := publickeyAuthMsg{ - User: user, - Service: serviceSSH, - Method: "publickey", - HasSig: false, - Algoname: algo, - PubKey: pubKey, - } - if err := c.writePacket(Marshal(&msg)); err != nil { - return false, err - } - - return confirmKeyAck(key, algo, c) -} - -func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) { - pubKey := key.Marshal() - - for { - packet, err := c.readPacket() - if err != nil { - return false, err - } - switch packet[0] { - case msgUserAuthBanner: - if err := handleBannerResponse(c, packet); err != nil { - return false, err - } - case msgUserAuthPubKeyOk: - var msg userAuthPubKeyOkMsg - if err := Unmarshal(packet, &msg); err != nil { - return false, err - } - if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) { - return false, nil - } - return true, nil - case msgUserAuthFailure: - return false, nil - default: - return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0]) - } - } -} - -// PublicKeys returns an AuthMethod that uses the given key -// pairs. -func PublicKeys(signers ...Signer) AuthMethod { - return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) -} - -// PublicKeysCallback returns an AuthMethod that runs the given -// function to obtain a list of key pairs. -func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { - return publicKeyCallback(getSigners) -} - -// handleAuthResponse returns whether the preceding authentication request succeeded -// along with a list of remaining authentication methods to try next and -// an error if an unexpected response was received. -func handleAuthResponse(c packetConn) (authResult, []string, error) { - gotMsgExtInfo := false - for { - packet, err := c.readPacket() - if err != nil { - return authFailure, nil, err - } - - switch packet[0] { - case msgUserAuthBanner: - if err := handleBannerResponse(c, packet); err != nil { - return authFailure, nil, err - } - case msgExtInfo: - // Ignore post-authentication RFC 8308 extensions, once. - if gotMsgExtInfo { - return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) - } - gotMsgExtInfo = true - case msgUserAuthFailure: - var msg userAuthFailureMsg - if err := Unmarshal(packet, &msg); err != nil { - return authFailure, nil, err - } - if msg.PartialSuccess { - return authPartialSuccess, msg.Methods, nil - } - return authFailure, msg.Methods, nil - case msgUserAuthSuccess: - return authSuccess, nil, nil - default: - return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) - } - } -} - -func handleBannerResponse(c packetConn, packet []byte) error { - var msg userAuthBannerMsg - if err := Unmarshal(packet, &msg); err != nil { - return err - } - - transport, ok := c.(*handshakeTransport) - if !ok { - return nil - } - - if transport.bannerCallback != nil { - return transport.bannerCallback(msg.Message) - } - - return nil -} - -// KeyboardInteractiveChallenge should print questions, optionally -// disabling echoing (e.g. for passwords), and return all the answers. -// Challenge may be called multiple times in a single session. After -// successful authentication, the server may send a challenge with no -// questions, for which the name and instruction messages should be -// printed. RFC 4256 section 3.3 details how the UI should behave for -// both CLI and GUI environments. -type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error) - -// KeyboardInteractive returns an AuthMethod using a prompt/response -// sequence controlled by the server. -func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { - return challenge -} - -func (cb KeyboardInteractiveChallenge) method() string { - return "keyboard-interactive" -} - -func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { - type initiateMsg struct { - User string `sshtype:"50"` - Service string - Method string - Language string - Submethods string - } - - if err := c.writePacket(Marshal(&initiateMsg{ - User: user, - Service: serviceSSH, - Method: "keyboard-interactive", - })); err != nil { - return authFailure, nil, err - } - - gotMsgExtInfo := false - for { - packet, err := c.readPacket() - if err != nil { - return authFailure, nil, err - } - - // like handleAuthResponse, but with less options. - switch packet[0] { - case msgUserAuthBanner: - if err := handleBannerResponse(c, packet); err != nil { - return authFailure, nil, err - } - continue - case msgExtInfo: - // Ignore post-authentication RFC 8308 extensions, once. - if gotMsgExtInfo { - return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) - } - gotMsgExtInfo = true - continue - case msgUserAuthInfoRequest: - // OK - case msgUserAuthFailure: - var msg userAuthFailureMsg - if err := Unmarshal(packet, &msg); err != nil { - return authFailure, nil, err - } - if msg.PartialSuccess { - return authPartialSuccess, msg.Methods, nil - } - return authFailure, msg.Methods, nil - case msgUserAuthSuccess: - return authSuccess, nil, nil - default: - return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) - } - - var msg userAuthInfoRequestMsg - if err := Unmarshal(packet, &msg); err != nil { - return authFailure, nil, err - } - - // Manually unpack the prompt/echo pairs. - rest := msg.Prompts - var prompts []string - var echos []bool - for i := 0; i < int(msg.NumPrompts); i++ { - prompt, r, ok := parseString(rest) - if !ok || len(r) == 0 { - return authFailure, nil, errors.New("ssh: prompt format error") - } - prompts = append(prompts, string(prompt)) - echos = append(echos, r[0] != 0) - rest = r[1:] - } - - if len(rest) != 0 { - return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") - } - - answers, err := cb(msg.Name, msg.Instruction, prompts, echos) - if err != nil { - return authFailure, nil, err - } - - if len(answers) != len(prompts) { - return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(answers), len(prompts)) - } - responseLength := 1 + 4 - for _, a := range answers { - responseLength += stringLength(len(a)) - } - serialized := make([]byte, responseLength) - p := serialized - p[0] = msgUserAuthInfoResponse - p = p[1:] - p = marshalUint32(p, uint32(len(answers))) - for _, a := range answers { - p = marshalString(p, []byte(a)) - } - - if err := c.writePacket(serialized); err != nil { - return authFailure, nil, err - } - } -} - -type retryableAuthMethod struct { - authMethod AuthMethod - maxTries int -} - -func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (ok authResult, methods []string, err error) { - for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { - ok, methods, err = r.authMethod.auth(session, user, c, rand, extensions) - if ok != authFailure || err != nil { // either success, partial success or error terminate - return ok, methods, err - } - } - return ok, methods, err -} - -func (r *retryableAuthMethod) method() string { - return r.authMethod.method() -} - -// RetryableAuthMethod is a decorator for other auth methods enabling them to -// be retried up to maxTries before considering that AuthMethod itself failed. -// If maxTries is <= 0, will retry indefinitely -// -// This is useful for interactive clients using challenge/response type -// authentication (e.g. Keyboard-Interactive, Password, etc) where the user -// could mistype their response resulting in the server issuing a -// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 -// [keyboard-interactive]); Without this decorator, the non-retryable -// AuthMethod would be removed from future consideration, and never tried again -// (and so the user would never be able to retry their entry). -func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { - return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} -} - -// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication. -// See RFC 4462 section 3 -// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details. -// target is the server host you want to log in to. -func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod { - if gssAPIClient == nil { - panic("gss-api client must be not nil with enable gssapi-with-mic") - } - return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target} -} - -type gssAPIWithMICCallback struct { - gssAPIClient GSSAPIClient - target string -} - -func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { - m := &userAuthRequestMsg{ - User: user, - Service: serviceSSH, - Method: g.method(), - } - // The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST. - // See RFC 4462 section 3.2. - m.Payload = appendU32(m.Payload, 1) - m.Payload = appendString(m.Payload, string(krb5OID)) - if err := c.writePacket(Marshal(m)); err != nil { - return authFailure, nil, err - } - // The server responds to the SSH_MSG_USERAUTH_REQUEST with either an - // SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or - // with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE. - // See RFC 4462 section 3.3. - // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check - // selected mech if it is valid. - packet, err := c.readPacket() - if err != nil { - return authFailure, nil, err - } - userAuthGSSAPIResp := &userAuthGSSAPIResponse{} - if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil { - return authFailure, nil, err - } - // Start the loop into the exchange token. - // See RFC 4462 section 3.4. - var token []byte - defer g.gssAPIClient.DeleteSecContext() - for { - // Initiates the establishment of a security context between the application and a remote peer. - nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false) - if err != nil { - return authFailure, nil, err - } - if len(nextToken) > 0 { - if err := c.writePacket(Marshal(&userAuthGSSAPIToken{ - Token: nextToken, - })); err != nil { - return authFailure, nil, err - } - } - if !needContinue { - break - } - packet, err = c.readPacket() - if err != nil { - return authFailure, nil, err - } - switch packet[0] { - case msgUserAuthFailure: - var msg userAuthFailureMsg - if err := Unmarshal(packet, &msg); err != nil { - return authFailure, nil, err - } - if msg.PartialSuccess { - return authPartialSuccess, msg.Methods, nil - } - return authFailure, msg.Methods, nil - case msgUserAuthGSSAPIError: - userAuthGSSAPIErrorResp := &userAuthGSSAPIError{} - if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil { - return authFailure, nil, err - } - return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+ - "Major Status: %d\n"+ - "Minor Status: %d\n"+ - "Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus, - userAuthGSSAPIErrorResp.Message) - case msgUserAuthGSSAPIToken: - userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} - if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { - return authFailure, nil, err - } - token = userAuthGSSAPITokenReq.Token - } - } - // Binding Encryption Keys. - // See RFC 4462 section 3.5. - micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic") - micToken, err := g.gssAPIClient.GetMIC(micField) - if err != nil { - return authFailure, nil, err - } - if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{ - MIC: micToken, - })); err != nil { - return authFailure, nil, err - } - return handleAuthResponse(c) -} - -func (g *gssAPIWithMICCallback) method() string { - return "gssapi-with-mic" -} diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go deleted file mode 100644 index 2a47a61d..00000000 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ /dev/null @@ -1,430 +0,0 @@ -// 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 ssh - -import ( - "crypto" - "crypto/rand" - "fmt" - "io" - "math" - "sync" - - _ "crypto/sha1" - _ "crypto/sha256" - _ "crypto/sha512" -) - -// These are string constants in the SSH protocol. -const ( - compressionNone = "none" - serviceUserAuth = "ssh-userauth" - serviceSSH = "ssh-connection" -) - -// supportedCiphers lists ciphers we support but might not recommend. -var supportedCiphers = []string{ - "aes128-ctr", "aes192-ctr", "aes256-ctr", - "aes128-gcm@openssh.com", - chacha20Poly1305ID, - "arcfour256", "arcfour128", "arcfour", - aes128cbcID, - tripledescbcID, -} - -// preferredCiphers specifies the default preference for ciphers. -var preferredCiphers = []string{ - "aes128-gcm@openssh.com", - chacha20Poly1305ID, - "aes128-ctr", "aes192-ctr", "aes256-ctr", -} - -// supportedKexAlgos specifies the supported key-exchange algorithms in -// preference order. -var supportedKexAlgos = []string{ - kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH, - // P384 and P521 are not constant-time yet, but since we don't - // reuse ephemeral keys, using them for ECDH should be OK. - kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, - kexAlgoDH14SHA256, kexAlgoDH14SHA1, kexAlgoDH1SHA1, -} - -// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden -// for the server half. -var serverForbiddenKexAlgos = map[string]struct{}{ - kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests - kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests -} - -// preferredKexAlgos specifies the default preference for key-exchange algorithms -// in preference order. -var preferredKexAlgos = []string{ - kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH, - kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, - kexAlgoDH14SHA256, kexAlgoDH14SHA1, -} - -// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods -// of authenticating servers) in preference order. -var supportedHostKeyAlgos = []string{ - CertAlgoRSASHA512v01, CertAlgoRSASHA256v01, - CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, - CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, - - KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, - KeyAlgoRSASHA512, KeyAlgoRSASHA256, - KeyAlgoRSA, KeyAlgoDSA, - - KeyAlgoED25519, -} - -// supportedMACs specifies a default set of MAC algorithms in preference order. -// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed -// because they have reached the end of their useful life. -var supportedMACs = []string{ - "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", -} - -var supportedCompressions = []string{compressionNone} - -// hashFuncs keeps the mapping of supported signature algorithms to their -// respective hashes needed for signing and verification. -var hashFuncs = map[string]crypto.Hash{ - KeyAlgoRSA: crypto.SHA1, - KeyAlgoRSASHA256: crypto.SHA256, - KeyAlgoRSASHA512: crypto.SHA512, - KeyAlgoDSA: crypto.SHA1, - KeyAlgoECDSA256: crypto.SHA256, - KeyAlgoECDSA384: crypto.SHA384, - KeyAlgoECDSA521: crypto.SHA512, - // KeyAlgoED25519 doesn't pre-hash. - KeyAlgoSKECDSA256: crypto.SHA256, - KeyAlgoSKED25519: crypto.SHA256, -} - -// algorithmsForKeyFormat returns the supported signature algorithms for a given -// public key format (PublicKey.Type), in order of preference. See RFC 8332, -// Section 2. See also the note in sendKexInit on backwards compatibility. -func algorithmsForKeyFormat(keyFormat string) []string { - switch keyFormat { - case KeyAlgoRSA: - return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA} - case CertAlgoRSAv01: - return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01} - default: - return []string{keyFormat} - } -} - -// unexpectedMessageError results when the SSH message that we received didn't -// match what we wanted. -func unexpectedMessageError(expected, got uint8) error { - return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) -} - -// parseError results from a malformed SSH message. -func parseError(tag uint8) error { - return fmt.Errorf("ssh: parse error in message type %d", tag) -} - -func findCommon(what string, client []string, server []string) (common string, err error) { - for _, c := range client { - for _, s := range server { - if c == s { - return c, nil - } - } - } - return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) -} - -// directionAlgorithms records algorithm choices in one direction (either read or write) -type directionAlgorithms struct { - Cipher string - MAC string - Compression string -} - -// rekeyBytes returns a rekeying intervals in bytes. -func (a *directionAlgorithms) rekeyBytes() int64 { - // According to RFC4344 block ciphers should rekey after - // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is - // 128. - switch a.Cipher { - case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID: - return 16 * (1 << 32) - - } - - // For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. - return 1 << 30 -} - -var aeadCiphers = map[string]bool{ - gcmCipherID: true, - chacha20Poly1305ID: true, -} - -type algorithms struct { - kex string - hostKey string - w directionAlgorithms - r directionAlgorithms -} - -func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { - result := &algorithms{} - - result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) - if err != nil { - return - } - - result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) - if err != nil { - return - } - - stoc, ctos := &result.w, &result.r - if isClient { - ctos, stoc = stoc, ctos - } - - ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) - if err != nil { - return - } - - stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) - if err != nil { - return - } - - if !aeadCiphers[ctos.Cipher] { - ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) - if err != nil { - return - } - } - - if !aeadCiphers[stoc.Cipher] { - stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) - if err != nil { - return - } - } - - ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) - if err != nil { - return - } - - stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) - if err != nil { - return - } - - return result, nil -} - -// If rekeythreshold is too small, we can't make any progress sending -// stuff. -const minRekeyThreshold uint64 = 256 - -// Config contains configuration data common to both ServerConfig and -// ClientConfig. -type Config struct { - // Rand provides the source of entropy for cryptographic - // primitives. If Rand is nil, the cryptographic random reader - // in package crypto/rand will be used. - Rand io.Reader - - // The maximum number of bytes sent or received after which a - // new key is negotiated. It must be at least 256. If - // unspecified, a size suitable for the chosen cipher is used. - RekeyThreshold uint64 - - // The allowed key exchanges algorithms. If unspecified then a - // default set of algorithms is used. - KeyExchanges []string - - // The allowed cipher algorithms. If unspecified then a sensible - // default is used. - Ciphers []string - - // The allowed MAC algorithms. If unspecified then a sensible default - // is used. - MACs []string -} - -// SetDefaults sets sensible values for unset fields in config. This is -// exported for testing: Configs passed to SSH functions are copied and have -// default values set automatically. -func (c *Config) SetDefaults() { - if c.Rand == nil { - c.Rand = rand.Reader - } - if c.Ciphers == nil { - c.Ciphers = preferredCiphers - } - var ciphers []string - for _, c := range c.Ciphers { - if cipherModes[c] != nil { - // reject the cipher if we have no cipherModes definition - ciphers = append(ciphers, c) - } - } - c.Ciphers = ciphers - - if c.KeyExchanges == nil { - c.KeyExchanges = preferredKexAlgos - } - - if c.MACs == nil { - c.MACs = supportedMACs - } - - if c.RekeyThreshold == 0 { - // cipher specific default - } else if c.RekeyThreshold < minRekeyThreshold { - c.RekeyThreshold = minRekeyThreshold - } else if c.RekeyThreshold >= math.MaxInt64 { - // Avoid weirdness if somebody uses -1 as a threshold. - c.RekeyThreshold = math.MaxInt64 - } -} - -// buildDataSignedForAuth returns the data that is signed in order to prove -// possession of a private key. See RFC 4252, section 7. algo is the advertised -// algorithm, and may be a certificate type. -func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte { - data := struct { - Session []byte - Type byte - User string - Service string - Method string - Sign bool - Algo string - PubKey []byte - }{ - sessionID, - msgUserAuthRequest, - req.User, - req.Service, - req.Method, - true, - algo, - pubKey, - } - return Marshal(data) -} - -func appendU16(buf []byte, n uint16) []byte { - return append(buf, byte(n>>8), byte(n)) -} - -func appendU32(buf []byte, n uint32) []byte { - return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) -} - -func appendU64(buf []byte, n uint64) []byte { - return append(buf, - byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), - byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) -} - -func appendInt(buf []byte, n int) []byte { - return appendU32(buf, uint32(n)) -} - -func appendString(buf []byte, s string) []byte { - buf = appendU32(buf, uint32(len(s))) - buf = append(buf, s...) - return buf -} - -func appendBool(buf []byte, b bool) []byte { - if b { - return append(buf, 1) - } - return append(buf, 0) -} - -// newCond is a helper to hide the fact that there is no usable zero -// value for sync.Cond. -func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } - -// window represents the buffer available to clients -// wishing to write to a channel. -type window struct { - *sync.Cond - win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 - writeWaiters int - closed bool -} - -// add adds win to the amount of window available -// for consumers. -func (w *window) add(win uint32) bool { - // a zero sized window adjust is a noop. - if win == 0 { - return true - } - w.L.Lock() - if w.win+win < win { - w.L.Unlock() - return false - } - w.win += win - // It is unusual that multiple goroutines would be attempting to reserve - // window space, but not guaranteed. Use broadcast to notify all waiters - // that additional window is available. - w.Broadcast() - w.L.Unlock() - return true -} - -// close sets the window to closed, so all reservations fail -// immediately. -func (w *window) close() { - w.L.Lock() - w.closed = true - w.Broadcast() - w.L.Unlock() -} - -// reserve reserves win from the available window capacity. -// If no capacity remains, reserve will block. reserve may -// return less than requested. -func (w *window) reserve(win uint32) (uint32, error) { - var err error - w.L.Lock() - w.writeWaiters++ - w.Broadcast() - for w.win == 0 && !w.closed { - w.Wait() - } - w.writeWaiters-- - if w.win < win { - win = w.win - } - w.win -= win - if w.closed { - err = io.EOF - } - w.L.Unlock() - return win, err -} - -// waitWriterBlocked waits until some goroutine is blocked for further -// writes. It is used in tests only. -func (w *window) waitWriterBlocked() { - w.Cond.L.Lock() - for w.writeWaiters == 0 { - w.Cond.Wait() - } - w.Cond.L.Unlock() -} diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go deleted file mode 100644 index fd6b0681..00000000 --- a/vendor/golang.org/x/crypto/ssh/connection.go +++ /dev/null @@ -1,143 +0,0 @@ -// 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 ssh - -import ( - "fmt" - "net" -) - -// OpenChannelError is returned if the other side rejects an -// OpenChannel request. -type OpenChannelError struct { - Reason RejectionReason - Message string -} - -func (e *OpenChannelError) Error() string { - return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) -} - -// ConnMetadata holds metadata for the connection. -type ConnMetadata interface { - // User returns the user ID for this connection. - User() string - - // SessionID returns the session hash, also denoted by H. - SessionID() []byte - - // ClientVersion returns the client's version string as hashed - // into the session ID. - ClientVersion() []byte - - // ServerVersion returns the server's version string as hashed - // into the session ID. - ServerVersion() []byte - - // RemoteAddr returns the remote address for this connection. - RemoteAddr() net.Addr - - // LocalAddr returns the local address for this connection. - LocalAddr() net.Addr -} - -// Conn represents an SSH connection for both server and client roles. -// Conn is the basis for implementing an application layer, such -// as ClientConn, which implements the traditional shell access for -// clients. -type Conn interface { - ConnMetadata - - // SendRequest sends a global request, and returns the - // reply. If wantReply is true, it returns the response status - // and payload. See also RFC4254, section 4. - SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) - - // OpenChannel tries to open an channel. If the request is - // rejected, it returns *OpenChannelError. On success it returns - // the SSH Channel and a Go channel for incoming, out-of-band - // requests. The Go channel must be serviced, or the - // connection will hang. - OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) - - // Close closes the underlying network connection - Close() error - - // Wait blocks until the connection has shut down, and returns the - // error causing the shutdown. - Wait() error - - // TODO(hanwen): consider exposing: - // RequestKeyChange - // Disconnect -} - -// DiscardRequests consumes and rejects all requests from the -// passed-in channel. -func DiscardRequests(in <-chan *Request) { - for req := range in { - if req.WantReply { - req.Reply(false, nil) - } - } -} - -// A connection represents an incoming connection. -type connection struct { - transport *handshakeTransport - sshConn - - // The connection protocol. - *mux -} - -func (c *connection) Close() error { - return c.sshConn.conn.Close() -} - -// sshconn provides net.Conn metadata, but disallows direct reads and -// writes. -type sshConn struct { - conn net.Conn - - user string - sessionID []byte - clientVersion []byte - serverVersion []byte -} - -func dup(src []byte) []byte { - dst := make([]byte, len(src)) - copy(dst, src) - return dst -} - -func (c *sshConn) User() string { - return c.user -} - -func (c *sshConn) RemoteAddr() net.Addr { - return c.conn.RemoteAddr() -} - -func (c *sshConn) Close() error { - return c.conn.Close() -} - -func (c *sshConn) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -func (c *sshConn) SessionID() []byte { - return dup(c.sessionID) -} - -func (c *sshConn) ClientVersion() []byte { - return dup(c.clientVersion) -} - -func (c *sshConn) ServerVersion() []byte { - return dup(c.serverVersion) -} diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go deleted file mode 100644 index f6bff60d..00000000 --- a/vendor/golang.org/x/crypto/ssh/doc.go +++ /dev/null @@ -1,22 +0,0 @@ -// 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 ssh implements an SSH client and server. - -SSH is a transport security protocol, an authentication protocol and a -family of application protocols. The most typical application level -protocol is a remote shell and this is specifically implemented. However, -the multiplexed nature of SSH is exposed to users that wish to support -others. - -References: - - [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD - [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 - -This package does not fall under the stability promise of the Go language itself, -so its API may be changed when pressing needs arise. -*/ -package ssh // import "golang.org/x/crypto/ssh" diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go deleted file mode 100644 index 653dc4d2..00000000 --- a/vendor/golang.org/x/crypto/ssh/handshake.go +++ /dev/null @@ -1,704 +0,0 @@ -// 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 ssh - -import ( - "crypto/rand" - "errors" - "fmt" - "io" - "log" - "net" - "sync" -) - -// debugHandshake, if set, prints messages sent and received. Key -// exchange messages are printed as if DH were used, so the debug -// messages are wrong when using ECDH. -const debugHandshake = false - -// chanSize sets the amount of buffering SSH connections. This is -// primarily for testing: setting chanSize=0 uncovers deadlocks more -// quickly. -const chanSize = 16 - -// keyingTransport is a packet based transport that supports key -// changes. It need not be thread-safe. It should pass through -// msgNewKeys in both directions. -type keyingTransport interface { - packetConn - - // prepareKeyChange sets up a key change. The key change for a - // direction will be effected if a msgNewKeys message is sent - // or received. - prepareKeyChange(*algorithms, *kexResult) error -} - -// handshakeTransport implements rekeying on top of a keyingTransport -// and offers a thread-safe writePacket() interface. -type handshakeTransport struct { - conn keyingTransport - config *Config - - serverVersion []byte - clientVersion []byte - - // hostKeys is non-empty if we are the server. In that case, - // it contains all host keys that can be used to sign the - // connection. - hostKeys []Signer - - // hostKeyAlgorithms is non-empty if we are the client. In that case, - // we accept these key types from the server as host key. - hostKeyAlgorithms []string - - // On read error, incoming is closed, and readError is set. - incoming chan []byte - readError error - - mu sync.Mutex - writeError error - sentInitPacket []byte - sentInitMsg *kexInitMsg - pendingPackets [][]byte // Used when a key exchange is in progress. - - // If the read loop wants to schedule a kex, it pings this - // channel, and the write loop will send out a kex - // message. - requestKex chan struct{} - - // If the other side requests or confirms a kex, its kexInit - // packet is sent here for the write loop to find it. - startKex chan *pendingKex - - // data for host key checking - hostKeyCallback HostKeyCallback - dialAddress string - remoteAddr net.Addr - - // bannerCallback is non-empty if we are the client and it has been set in - // ClientConfig. In that case it is called during the user authentication - // dance to handle a custom server's message. - bannerCallback BannerCallback - - // Algorithms agreed in the last key exchange. - algorithms *algorithms - - readPacketsLeft uint32 - readBytesLeft int64 - - writePacketsLeft uint32 - writeBytesLeft int64 - - // The session ID or nil if first kex did not complete yet. - sessionID []byte -} - -type pendingKex struct { - otherInit []byte - done chan error -} - -func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { - t := &handshakeTransport{ - conn: conn, - serverVersion: serverVersion, - clientVersion: clientVersion, - incoming: make(chan []byte, chanSize), - requestKex: make(chan struct{}, 1), - startKex: make(chan *pendingKex, 1), - - config: config, - } - t.resetReadThresholds() - t.resetWriteThresholds() - - // We always start with a mandatory key exchange. - t.requestKex <- struct{}{} - return t -} - -func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { - t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) - t.dialAddress = dialAddr - t.remoteAddr = addr - t.hostKeyCallback = config.HostKeyCallback - t.bannerCallback = config.BannerCallback - if config.HostKeyAlgorithms != nil { - t.hostKeyAlgorithms = config.HostKeyAlgorithms - } else { - t.hostKeyAlgorithms = supportedHostKeyAlgos - } - go t.readLoop() - go t.kexLoop() - return t -} - -func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { - t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) - t.hostKeys = config.hostKeys - go t.readLoop() - go t.kexLoop() - return t -} - -func (t *handshakeTransport) getSessionID() []byte { - return t.sessionID -} - -// waitSession waits for the session to be established. This should be -// the first thing to call after instantiating handshakeTransport. -func (t *handshakeTransport) waitSession() error { - p, err := t.readPacket() - if err != nil { - return err - } - if p[0] != msgNewKeys { - return fmt.Errorf("ssh: first packet should be msgNewKeys") - } - - return nil -} - -func (t *handshakeTransport) id() string { - if len(t.hostKeys) > 0 { - return "server" - } - return "client" -} - -func (t *handshakeTransport) printPacket(p []byte, write bool) { - action := "got" - if write { - action = "sent" - } - - if p[0] == msgChannelData || p[0] == msgChannelExtendedData { - log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) - } else { - msg, err := decode(p) - log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) - } -} - -func (t *handshakeTransport) readPacket() ([]byte, error) { - p, ok := <-t.incoming - if !ok { - return nil, t.readError - } - return p, nil -} - -func (t *handshakeTransport) readLoop() { - first := true - for { - p, err := t.readOnePacket(first) - first = false - if err != nil { - t.readError = err - close(t.incoming) - break - } - if p[0] == msgIgnore || p[0] == msgDebug { - continue - } - t.incoming <- p - } - - // Stop writers too. - t.recordWriteError(t.readError) - - // Unblock the writer should it wait for this. - close(t.startKex) - - // Don't close t.requestKex; it's also written to from writePacket. -} - -func (t *handshakeTransport) pushPacket(p []byte) error { - if debugHandshake { - t.printPacket(p, true) - } - return t.conn.writePacket(p) -} - -func (t *handshakeTransport) getWriteError() error { - t.mu.Lock() - defer t.mu.Unlock() - return t.writeError -} - -func (t *handshakeTransport) recordWriteError(err error) { - t.mu.Lock() - defer t.mu.Unlock() - if t.writeError == nil && err != nil { - t.writeError = err - } -} - -func (t *handshakeTransport) requestKeyExchange() { - select { - case t.requestKex <- struct{}{}: - default: - // something already requested a kex, so do nothing. - } -} - -func (t *handshakeTransport) resetWriteThresholds() { - t.writePacketsLeft = packetRekeyThreshold - if t.config.RekeyThreshold > 0 { - t.writeBytesLeft = int64(t.config.RekeyThreshold) - } else if t.algorithms != nil { - t.writeBytesLeft = t.algorithms.w.rekeyBytes() - } else { - t.writeBytesLeft = 1 << 30 - } -} - -func (t *handshakeTransport) kexLoop() { - -write: - for t.getWriteError() == nil { - var request *pendingKex - var sent bool - - for request == nil || !sent { - var ok bool - select { - case request, ok = <-t.startKex: - if !ok { - break write - } - case <-t.requestKex: - break - } - - if !sent { - if err := t.sendKexInit(); err != nil { - t.recordWriteError(err) - break - } - sent = true - } - } - - if err := t.getWriteError(); err != nil { - if request != nil { - request.done <- err - } - break - } - - // We're not servicing t.requestKex, but that is OK: - // we never block on sending to t.requestKex. - - // We're not servicing t.startKex, but the remote end - // has just sent us a kexInitMsg, so it can't send - // another key change request, until we close the done - // channel on the pendingKex request. - - err := t.enterKeyExchange(request.otherInit) - - t.mu.Lock() - t.writeError = err - t.sentInitPacket = nil - t.sentInitMsg = nil - - t.resetWriteThresholds() - - // we have completed the key exchange. Since the - // reader is still blocked, it is safe to clear out - // the requestKex channel. This avoids the situation - // where: 1) we consumed our own request for the - // initial kex, and 2) the kex from the remote side - // caused another send on the requestKex channel, - clear: - for { - select { - case <-t.requestKex: - // - default: - break clear - } - } - - request.done <- t.writeError - - // kex finished. Push packets that we received while - // the kex was in progress. Don't look at t.startKex - // and don't increment writtenSinceKex: if we trigger - // another kex while we are still busy with the last - // one, things will become very confusing. - for _, p := range t.pendingPackets { - t.writeError = t.pushPacket(p) - if t.writeError != nil { - break - } - } - t.pendingPackets = t.pendingPackets[:0] - t.mu.Unlock() - } - - // drain startKex channel. We don't service t.requestKex - // because nobody does blocking sends there. - go func() { - for init := range t.startKex { - init.done <- t.writeError - } - }() - - // Unblock reader. - t.conn.Close() -} - -// The protocol uses uint32 for packet counters, so we can't let them -// reach 1<<32. We will actually read and write more packets than -// this, though: the other side may send more packets, and after we -// hit this limit on writing we will send a few more packets for the -// key exchange itself. -const packetRekeyThreshold = (1 << 31) - -func (t *handshakeTransport) resetReadThresholds() { - t.readPacketsLeft = packetRekeyThreshold - if t.config.RekeyThreshold > 0 { - t.readBytesLeft = int64(t.config.RekeyThreshold) - } else if t.algorithms != nil { - t.readBytesLeft = t.algorithms.r.rekeyBytes() - } else { - t.readBytesLeft = 1 << 30 - } -} - -func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { - p, err := t.conn.readPacket() - if err != nil { - return nil, err - } - - if t.readPacketsLeft > 0 { - t.readPacketsLeft-- - } else { - t.requestKeyExchange() - } - - if t.readBytesLeft > 0 { - t.readBytesLeft -= int64(len(p)) - } else { - t.requestKeyExchange() - } - - if debugHandshake { - t.printPacket(p, false) - } - - if first && p[0] != msgKexInit { - return nil, fmt.Errorf("ssh: first packet should be msgKexInit") - } - - if p[0] != msgKexInit { - return p, nil - } - - firstKex := t.sessionID == nil - - kex := pendingKex{ - done: make(chan error, 1), - otherInit: p, - } - t.startKex <- &kex - err = <-kex.done - - if debugHandshake { - log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) - } - - if err != nil { - return nil, err - } - - t.resetReadThresholds() - - // By default, a key exchange is hidden from higher layers by - // translating it into msgIgnore. - successPacket := []byte{msgIgnore} - if firstKex { - // sendKexInit() for the first kex waits for - // msgNewKeys so the authentication process is - // guaranteed to happen over an encrypted transport. - successPacket = []byte{msgNewKeys} - } - - return successPacket, nil -} - -// sendKexInit sends a key change message. -func (t *handshakeTransport) sendKexInit() error { - t.mu.Lock() - defer t.mu.Unlock() - if t.sentInitMsg != nil { - // kexInits may be sent either in response to the other side, - // or because our side wants to initiate a key change, so we - // may have already sent a kexInit. In that case, don't send a - // second kexInit. - return nil - } - - msg := &kexInitMsg{ - KexAlgos: t.config.KeyExchanges, - CiphersClientServer: t.config.Ciphers, - CiphersServerClient: t.config.Ciphers, - MACsClientServer: t.config.MACs, - MACsServerClient: t.config.MACs, - CompressionClientServer: supportedCompressions, - CompressionServerClient: supportedCompressions, - } - io.ReadFull(rand.Reader, msg.Cookie[:]) - - isServer := len(t.hostKeys) > 0 - if isServer { - for _, k := range t.hostKeys { - // If k is an AlgorithmSigner, presume it supports all signature algorithms - // associated with the key format. (Ideally AlgorithmSigner would have a - // method to advertise supported algorithms, but it doesn't. This means that - // adding support for a new algorithm is a breaking change, as we will - // immediately negotiate it even if existing implementations don't support - // it. If that ever happens, we'll have to figure something out.) - // If k is not an AlgorithmSigner, we can only assume it only supports the - // algorithms that matches the key format. (This means that Sign can't pick - // a different default.) - keyFormat := k.PublicKey().Type() - if _, ok := k.(AlgorithmSigner); ok { - msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...) - } else { - msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat) - } - } - } else { - msg.ServerHostKeyAlgos = t.hostKeyAlgorithms - - // As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what - // algorithms the server supports for public key authentication. See RFC - // 8308, Section 2.1. - if firstKeyExchange := t.sessionID == nil; firstKeyExchange { - msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1) - msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...) - msg.KexAlgos = append(msg.KexAlgos, "ext-info-c") - } - } - - packet := Marshal(msg) - - // writePacket destroys the contents, so save a copy. - packetCopy := make([]byte, len(packet)) - copy(packetCopy, packet) - - if err := t.pushPacket(packetCopy); err != nil { - return err - } - - t.sentInitMsg = msg - t.sentInitPacket = packet - - return nil -} - -func (t *handshakeTransport) writePacket(p []byte) error { - switch p[0] { - case msgKexInit: - return errors.New("ssh: only handshakeTransport can send kexInit") - case msgNewKeys: - return errors.New("ssh: only handshakeTransport can send newKeys") - } - - t.mu.Lock() - defer t.mu.Unlock() - if t.writeError != nil { - return t.writeError - } - - if t.sentInitMsg != nil { - // Copy the packet so the writer can reuse the buffer. - cp := make([]byte, len(p)) - copy(cp, p) - t.pendingPackets = append(t.pendingPackets, cp) - return nil - } - - if t.writeBytesLeft > 0 { - t.writeBytesLeft -= int64(len(p)) - } else { - t.requestKeyExchange() - } - - if t.writePacketsLeft > 0 { - t.writePacketsLeft-- - } else { - t.requestKeyExchange() - } - - if err := t.pushPacket(p); err != nil { - t.writeError = err - } - - return nil -} - -func (t *handshakeTransport) Close() error { - return t.conn.Close() -} - -func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { - if debugHandshake { - log.Printf("%s entered key exchange", t.id()) - } - - otherInit := &kexInitMsg{} - if err := Unmarshal(otherInitPacket, otherInit); err != nil { - return err - } - - magics := handshakeMagics{ - clientVersion: t.clientVersion, - serverVersion: t.serverVersion, - clientKexInit: otherInitPacket, - serverKexInit: t.sentInitPacket, - } - - clientInit := otherInit - serverInit := t.sentInitMsg - isClient := len(t.hostKeys) == 0 - if isClient { - clientInit, serverInit = serverInit, clientInit - - magics.clientKexInit = t.sentInitPacket - magics.serverKexInit = otherInitPacket - } - - var err error - t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit) - if err != nil { - return err - } - - // We don't send FirstKexFollows, but we handle receiving it. - // - // RFC 4253 section 7 defines the kex and the agreement method for - // first_kex_packet_follows. It states that the guessed packet - // should be ignored if the "kex algorithm and/or the host - // key algorithm is guessed wrong (server and client have - // different preferred algorithm), or if any of the other - // algorithms cannot be agreed upon". The other algorithms have - // already been checked above so the kex algorithm and host key - // algorithm are checked here. - if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) { - // other side sent a kex message for the wrong algorithm, - // which we have to ignore. - if _, err := t.conn.readPacket(); err != nil { - return err - } - } - - kex, ok := kexAlgoMap[t.algorithms.kex] - if !ok { - return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) - } - - var result *kexResult - if len(t.hostKeys) > 0 { - result, err = t.server(kex, &magics) - } else { - result, err = t.client(kex, &magics) - } - - if err != nil { - return err - } - - if t.sessionID == nil { - t.sessionID = result.H - } - result.SessionID = t.sessionID - - if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil { - return err - } - if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { - return err - } - if packet, err := t.conn.readPacket(); err != nil { - return err - } else if packet[0] != msgNewKeys { - return unexpectedMessageError(msgNewKeys, packet[0]) - } - - return nil -} - -// algorithmSignerWrapper is an AlgorithmSigner that only supports the default -// key format algorithm. -// -// This is technically a violation of the AlgorithmSigner interface, but it -// should be unreachable given where we use this. Anyway, at least it returns an -// error instead of panicing or producing an incorrect signature. -type algorithmSignerWrapper struct { - Signer -} - -func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { - if algorithm != underlyingAlgo(a.PublicKey().Type()) { - return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm") - } - return a.Sign(rand, data) -} - -func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner { - for _, k := range hostKeys { - if algo == k.PublicKey().Type() { - return algorithmSignerWrapper{k} - } - k, ok := k.(AlgorithmSigner) - if !ok { - continue - } - for _, a := range algorithmsForKeyFormat(k.PublicKey().Type()) { - if algo == a { - return k - } - } - } - return nil -} - -func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) { - hostKey := pickHostKey(t.hostKeys, t.algorithms.hostKey) - if hostKey == nil { - return nil, errors.New("ssh: internal error: negotiated unsupported signature type") - } - - r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.hostKey) - return r, err -} - -func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) { - result, err := kex.Client(t.conn, t.config.Rand, magics) - if err != nil { - return nil, err - } - - hostKey, err := ParsePublicKey(result.HostKey) - if err != nil { - return nil, err - } - - if err := verifyHostKeySignature(hostKey, t.algorithms.hostKey, result); err != nil { - return nil, err - } - - err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) - if err != nil { - return nil, err - } - - return result, nil -} diff --git a/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go b/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go deleted file mode 100644 index af81d266..00000000 --- a/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2014 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 bcrypt_pbkdf implements bcrypt_pbkdf(3) from OpenBSD. -// -// See https://flak.tedunangst.com/post/bcrypt-pbkdf and -// https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libutil/bcrypt_pbkdf.c. -package bcrypt_pbkdf - -import ( - "crypto/sha512" - "errors" - "golang.org/x/crypto/blowfish" -) - -const blockSize = 32 - -// Key derives a key from the password, salt and rounds count, returning a -// []byte of length keyLen that can be used as cryptographic key. -func Key(password, salt []byte, rounds, keyLen int) ([]byte, error) { - if rounds < 1 { - return nil, errors.New("bcrypt_pbkdf: number of rounds is too small") - } - if len(password) == 0 { - return nil, errors.New("bcrypt_pbkdf: empty password") - } - if len(salt) == 0 || len(salt) > 1<<20 { - return nil, errors.New("bcrypt_pbkdf: bad salt length") - } - if keyLen > 1024 { - return nil, errors.New("bcrypt_pbkdf: keyLen is too large") - } - - numBlocks := (keyLen + blockSize - 1) / blockSize - key := make([]byte, numBlocks*blockSize) - - h := sha512.New() - h.Write(password) - shapass := h.Sum(nil) - - shasalt := make([]byte, 0, sha512.Size) - cnt, tmp := make([]byte, 4), make([]byte, blockSize) - for block := 1; block <= numBlocks; block++ { - h.Reset() - h.Write(salt) - cnt[0] = byte(block >> 24) - cnt[1] = byte(block >> 16) - cnt[2] = byte(block >> 8) - cnt[3] = byte(block) - h.Write(cnt) - bcryptHash(tmp, shapass, h.Sum(shasalt)) - - out := make([]byte, blockSize) - copy(out, tmp) - for i := 2; i <= rounds; i++ { - h.Reset() - h.Write(tmp) - bcryptHash(tmp, shapass, h.Sum(shasalt)) - for j := 0; j < len(out); j++ { - out[j] ^= tmp[j] - } - } - - for i, v := range out { - key[i*numBlocks+(block-1)] = v - } - } - return key[:keyLen], nil -} - -var magic = []byte("OxychromaticBlowfishSwatDynamite") - -func bcryptHash(out, shapass, shasalt []byte) { - c, err := blowfish.NewSaltedCipher(shapass, shasalt) - if err != nil { - panic(err) - } - for i := 0; i < 64; i++ { - blowfish.ExpandKey(shasalt, c) - blowfish.ExpandKey(shapass, c) - } - copy(out, magic) - for i := 0; i < 32; i += 8 { - for j := 0; j < 64; j++ { - c.Encrypt(out[i:i+8], out[i:i+8]) - } - } - // Swap bytes due to different endianness. - for i := 0; i < 32; i += 4 { - out[i+3], out[i+2], out[i+1], out[i] = out[i], out[i+1], out[i+2], out[i+3] - } -} diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go deleted file mode 100644 index 927a90cd..00000000 --- a/vendor/golang.org/x/crypto/ssh/kex.go +++ /dev/null @@ -1,774 +0,0 @@ -// 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 ssh - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/subtle" - "encoding/binary" - "errors" - "fmt" - "io" - "math/big" - - "golang.org/x/crypto/curve25519" -) - -const ( - kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" - kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" - kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256" - kexAlgoECDH256 = "ecdh-sha2-nistp256" - kexAlgoECDH384 = "ecdh-sha2-nistp384" - kexAlgoECDH521 = "ecdh-sha2-nistp521" - kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org" - kexAlgoCurve25519SHA256 = "curve25519-sha256" - - // For the following kex only the client half contains a production - // ready implementation. The server half only consists of a minimal - // implementation to satisfy the automated tests. - kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1" - kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256" -) - -// kexResult captures the outcome of a key exchange. -type kexResult struct { - // Session hash. See also RFC 4253, section 8. - H []byte - - // Shared secret. See also RFC 4253, section 8. - K []byte - - // Host key as hashed into H. - HostKey []byte - - // Signature of H. - Signature []byte - - // A cryptographic hash function that matches the security - // level of the key exchange algorithm. It is used for - // calculating H, and for deriving keys from H and K. - Hash crypto.Hash - - // The session ID, which is the first H computed. This is used - // to derive key material inside the transport. - SessionID []byte -} - -// handshakeMagics contains data that is always included in the -// session hash. -type handshakeMagics struct { - clientVersion, serverVersion []byte - clientKexInit, serverKexInit []byte -} - -func (m *handshakeMagics) write(w io.Writer) { - writeString(w, m.clientVersion) - writeString(w, m.serverVersion) - writeString(w, m.clientKexInit) - writeString(w, m.serverKexInit) -} - -// kexAlgorithm abstracts different key exchange algorithms. -type kexAlgorithm interface { - // Server runs server-side key agreement, signing the result - // with a hostkey. algo is the negotiated algorithm, and may - // be a certificate type. - Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error) - - // Client runs the client-side key agreement. Caller is - // responsible for verifying the host key signature. - Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) -} - -// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. -type dhGroup struct { - g, p, pMinus1 *big.Int - hashFunc crypto.Hash -} - -func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { - if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { - return nil, errors.New("ssh: DH parameter out of bounds") - } - return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil -} - -func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { - var x *big.Int - for { - var err error - if x, err = rand.Int(randSource, group.pMinus1); err != nil { - return nil, err - } - if x.Sign() > 0 { - break - } - } - - X := new(big.Int).Exp(group.g, x, group.p) - kexDHInit := kexDHInitMsg{ - X: X, - } - if err := c.writePacket(Marshal(&kexDHInit)); err != nil { - return nil, err - } - - packet, err := c.readPacket() - if err != nil { - return nil, err - } - - var kexDHReply kexDHReplyMsg - if err = Unmarshal(packet, &kexDHReply); err != nil { - return nil, err - } - - ki, err := group.diffieHellman(kexDHReply.Y, x) - if err != nil { - return nil, err - } - - h := group.hashFunc.New() - magics.write(h) - writeString(h, kexDHReply.HostKey) - writeInt(h, X) - writeInt(h, kexDHReply.Y) - K := make([]byte, intLength(ki)) - marshalInt(K, ki) - h.Write(K) - - return &kexResult{ - H: h.Sum(nil), - K: K, - HostKey: kexDHReply.HostKey, - Signature: kexDHReply.Signature, - Hash: group.hashFunc, - }, nil -} - -func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { - packet, err := c.readPacket() - if err != nil { - return - } - var kexDHInit kexDHInitMsg - if err = Unmarshal(packet, &kexDHInit); err != nil { - return - } - - var y *big.Int - for { - if y, err = rand.Int(randSource, group.pMinus1); err != nil { - return - } - if y.Sign() > 0 { - break - } - } - - Y := new(big.Int).Exp(group.g, y, group.p) - ki, err := group.diffieHellman(kexDHInit.X, y) - if err != nil { - return nil, err - } - - hostKeyBytes := priv.PublicKey().Marshal() - - h := group.hashFunc.New() - magics.write(h) - writeString(h, hostKeyBytes) - writeInt(h, kexDHInit.X) - writeInt(h, Y) - - K := make([]byte, intLength(ki)) - marshalInt(K, ki) - h.Write(K) - - H := h.Sum(nil) - - // H is already a hash, but the hostkey signing will apply its - // own key-specific hash algorithm. - sig, err := signAndMarshal(priv, randSource, H, algo) - if err != nil { - return nil, err - } - - kexDHReply := kexDHReplyMsg{ - HostKey: hostKeyBytes, - Y: Y, - Signature: sig, - } - packet = Marshal(&kexDHReply) - - err = c.writePacket(packet) - return &kexResult{ - H: H, - K: K, - HostKey: hostKeyBytes, - Signature: sig, - Hash: group.hashFunc, - }, err -} - -// ecdh performs Elliptic Curve Diffie-Hellman key exchange as -// described in RFC 5656, section 4. -type ecdh struct { - curve elliptic.Curve -} - -func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { - ephKey, err := ecdsa.GenerateKey(kex.curve, rand) - if err != nil { - return nil, err - } - - kexInit := kexECDHInitMsg{ - ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), - } - - serialized := Marshal(&kexInit) - if err := c.writePacket(serialized); err != nil { - return nil, err - } - - packet, err := c.readPacket() - if err != nil { - return nil, err - } - - var reply kexECDHReplyMsg - if err = Unmarshal(packet, &reply); err != nil { - return nil, err - } - - x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) - if err != nil { - return nil, err - } - - // generate shared secret - secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) - - h := ecHash(kex.curve).New() - magics.write(h) - writeString(h, reply.HostKey) - writeString(h, kexInit.ClientPubKey) - writeString(h, reply.EphemeralPubKey) - K := make([]byte, intLength(secret)) - marshalInt(K, secret) - h.Write(K) - - return &kexResult{ - H: h.Sum(nil), - K: K, - HostKey: reply.HostKey, - Signature: reply.Signature, - Hash: ecHash(kex.curve), - }, nil -} - -// unmarshalECKey parses and checks an EC key. -func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { - x, y = elliptic.Unmarshal(curve, pubkey) - if x == nil { - return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") - } - if !validateECPublicKey(curve, x, y) { - return nil, nil, errors.New("ssh: public key not on curve") - } - return x, y, nil -} - -// validateECPublicKey checks that the point is a valid public key for -// the given curve. See [SEC1], 3.2.2 -func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { - if x.Sign() == 0 && y.Sign() == 0 { - return false - } - - if x.Cmp(curve.Params().P) >= 0 { - return false - } - - if y.Cmp(curve.Params().P) >= 0 { - return false - } - - if !curve.IsOnCurve(x, y) { - return false - } - - // We don't check if N * PubKey == 0, since - // - // - the NIST curves have cofactor = 1, so this is implicit. - // (We don't foresee an implementation that supports non NIST - // curves) - // - // - for ephemeral keys, we don't need to worry about small - // subgroup attacks. - return true -} - -func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { - packet, err := c.readPacket() - if err != nil { - return nil, err - } - - var kexECDHInit kexECDHInitMsg - if err = Unmarshal(packet, &kexECDHInit); err != nil { - return nil, err - } - - clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) - if err != nil { - return nil, err - } - - // We could cache this key across multiple users/multiple - // connection attempts, but the benefit is small. OpenSSH - // generates a new key for each incoming connection. - ephKey, err := ecdsa.GenerateKey(kex.curve, rand) - if err != nil { - return nil, err - } - - hostKeyBytes := priv.PublicKey().Marshal() - - serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) - - // generate shared secret - secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) - - h := ecHash(kex.curve).New() - magics.write(h) - writeString(h, hostKeyBytes) - writeString(h, kexECDHInit.ClientPubKey) - writeString(h, serializedEphKey) - - K := make([]byte, intLength(secret)) - marshalInt(K, secret) - h.Write(K) - - H := h.Sum(nil) - - // H is already a hash, but the hostkey signing will apply its - // own key-specific hash algorithm. - sig, err := signAndMarshal(priv, rand, H, algo) - if err != nil { - return nil, err - } - - reply := kexECDHReplyMsg{ - EphemeralPubKey: serializedEphKey, - HostKey: hostKeyBytes, - Signature: sig, - } - - serialized := Marshal(&reply) - if err := c.writePacket(serialized); err != nil { - return nil, err - } - - return &kexResult{ - H: H, - K: K, - HostKey: reply.HostKey, - Signature: sig, - Hash: ecHash(kex.curve), - }, nil -} - -// ecHash returns the hash to match the given elliptic curve, see RFC -// 5656, section 6.2.1 -func ecHash(curve elliptic.Curve) crypto.Hash { - bitSize := curve.Params().BitSize - switch { - case bitSize <= 256: - return crypto.SHA256 - case bitSize <= 384: - return crypto.SHA384 - } - return crypto.SHA512 -} - -var kexAlgoMap = map[string]kexAlgorithm{} - -func init() { - // This is the group called diffie-hellman-group1-sha1 in - // RFC 4253 and Oakley Group 2 in RFC 2409. - p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) - kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ - g: new(big.Int).SetInt64(2), - p: p, - pMinus1: new(big.Int).Sub(p, bigOne), - hashFunc: crypto.SHA1, - } - - // This are the groups called diffie-hellman-group14-sha1 and - // diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268, - // and Oakley Group 14 in RFC 3526. - p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) - group14 := &dhGroup{ - g: new(big.Int).SetInt64(2), - p: p, - pMinus1: new(big.Int).Sub(p, bigOne), - } - - kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ - g: group14.g, p: group14.p, pMinus1: group14.pMinus1, - hashFunc: crypto.SHA1, - } - kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{ - g: group14.g, p: group14.p, pMinus1: group14.pMinus1, - hashFunc: crypto.SHA256, - } - - kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} - kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} - kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} - kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} - kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{} - kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} - kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} -} - -// curve25519sha256 implements the curve25519-sha256 (formerly known as -// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731. -type curve25519sha256 struct{} - -type curve25519KeyPair struct { - priv [32]byte - pub [32]byte -} - -func (kp *curve25519KeyPair) generate(rand io.Reader) error { - if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { - return err - } - curve25519.ScalarBaseMult(&kp.pub, &kp.priv) - return nil -} - -// curve25519Zeros is just an array of 32 zero bytes so that we have something -// convenient to compare against in order to reject curve25519 points with the -// wrong order. -var curve25519Zeros [32]byte - -func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { - var kp curve25519KeyPair - if err := kp.generate(rand); err != nil { - return nil, err - } - if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { - return nil, err - } - - packet, err := c.readPacket() - if err != nil { - return nil, err - } - - var reply kexECDHReplyMsg - if err = Unmarshal(packet, &reply); err != nil { - return nil, err - } - if len(reply.EphemeralPubKey) != 32 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong length") - } - - var servPub, secret [32]byte - copy(servPub[:], reply.EphemeralPubKey) - curve25519.ScalarMult(&secret, &kp.priv, &servPub) - if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong order") - } - - h := crypto.SHA256.New() - magics.write(h) - writeString(h, reply.HostKey) - writeString(h, kp.pub[:]) - writeString(h, reply.EphemeralPubKey) - - ki := new(big.Int).SetBytes(secret[:]) - K := make([]byte, intLength(ki)) - marshalInt(K, ki) - h.Write(K) - - return &kexResult{ - H: h.Sum(nil), - K: K, - HostKey: reply.HostKey, - Signature: reply.Signature, - Hash: crypto.SHA256, - }, nil -} - -func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { - packet, err := c.readPacket() - if err != nil { - return - } - var kexInit kexECDHInitMsg - if err = Unmarshal(packet, &kexInit); err != nil { - return - } - - if len(kexInit.ClientPubKey) != 32 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong length") - } - - var kp curve25519KeyPair - if err := kp.generate(rand); err != nil { - return nil, err - } - - var clientPub, secret [32]byte - copy(clientPub[:], kexInit.ClientPubKey) - curve25519.ScalarMult(&secret, &kp.priv, &clientPub) - if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong order") - } - - hostKeyBytes := priv.PublicKey().Marshal() - - h := crypto.SHA256.New() - magics.write(h) - writeString(h, hostKeyBytes) - writeString(h, kexInit.ClientPubKey) - writeString(h, kp.pub[:]) - - ki := new(big.Int).SetBytes(secret[:]) - K := make([]byte, intLength(ki)) - marshalInt(K, ki) - h.Write(K) - - H := h.Sum(nil) - - sig, err := signAndMarshal(priv, rand, H, algo) - if err != nil { - return nil, err - } - - reply := kexECDHReplyMsg{ - EphemeralPubKey: kp.pub[:], - HostKey: hostKeyBytes, - Signature: sig, - } - if err := c.writePacket(Marshal(&reply)); err != nil { - return nil, err - } - return &kexResult{ - H: H, - K: K, - HostKey: hostKeyBytes, - Signature: sig, - Hash: crypto.SHA256, - }, nil -} - -// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and -// diffie-hellman-group-exchange-sha256 key agreement protocols, -// as described in RFC 4419 -type dhGEXSHA struct { - hashFunc crypto.Hash -} - -const ( - dhGroupExchangeMinimumBits = 2048 - dhGroupExchangePreferredBits = 2048 - dhGroupExchangeMaximumBits = 8192 -) - -func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { - // Send GexRequest - kexDHGexRequest := kexDHGexRequestMsg{ - MinBits: dhGroupExchangeMinimumBits, - PreferedBits: dhGroupExchangePreferredBits, - MaxBits: dhGroupExchangeMaximumBits, - } - if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil { - return nil, err - } - - // Receive GexGroup - packet, err := c.readPacket() - if err != nil { - return nil, err - } - - var msg kexDHGexGroupMsg - if err = Unmarshal(packet, &msg); err != nil { - return nil, err - } - - // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits - if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits { - return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen()) - } - - // Check if g is safe by verifying that 1 < g < p-1 - pMinusOne := new(big.Int).Sub(msg.P, bigOne) - if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 { - return nil, fmt.Errorf("ssh: server provided gex g is not safe") - } - - // Send GexInit - pHalf := new(big.Int).Rsh(msg.P, 1) - x, err := rand.Int(randSource, pHalf) - if err != nil { - return nil, err - } - X := new(big.Int).Exp(msg.G, x, msg.P) - kexDHGexInit := kexDHGexInitMsg{ - X: X, - } - if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil { - return nil, err - } - - // Receive GexReply - packet, err = c.readPacket() - if err != nil { - return nil, err - } - - var kexDHGexReply kexDHGexReplyMsg - if err = Unmarshal(packet, &kexDHGexReply); err != nil { - return nil, err - } - - if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 { - return nil, errors.New("ssh: DH parameter out of bounds") - } - kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P) - - // Check if k is safe by verifying that k > 1 and k < p - 1 - if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 { - return nil, fmt.Errorf("ssh: derived k is not safe") - } - - h := gex.hashFunc.New() - magics.write(h) - writeString(h, kexDHGexReply.HostKey) - binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) - binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) - binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) - writeInt(h, msg.P) - writeInt(h, msg.G) - writeInt(h, X) - writeInt(h, kexDHGexReply.Y) - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) - h.Write(K) - - return &kexResult{ - H: h.Sum(nil), - K: K, - HostKey: kexDHGexReply.HostKey, - Signature: kexDHGexReply.Signature, - Hash: gex.hashFunc, - }, nil -} - -// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. -// -// This is a minimal implementation to satisfy the automated tests. -func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { - // Receive GexRequest - packet, err := c.readPacket() - if err != nil { - return - } - var kexDHGexRequest kexDHGexRequestMsg - if err = Unmarshal(packet, &kexDHGexRequest); err != nil { - return - } - - // Send GexGroup - // This is the group called diffie-hellman-group14-sha1 in RFC - // 4253 and Oakley Group 14 in RFC 3526. - p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) - g := big.NewInt(2) - - msg := &kexDHGexGroupMsg{ - P: p, - G: g, - } - if err := c.writePacket(Marshal(msg)); err != nil { - return nil, err - } - - // Receive GexInit - packet, err = c.readPacket() - if err != nil { - return - } - var kexDHGexInit kexDHGexInitMsg - if err = Unmarshal(packet, &kexDHGexInit); err != nil { - return - } - - pHalf := new(big.Int).Rsh(p, 1) - - y, err := rand.Int(randSource, pHalf) - if err != nil { - return - } - Y := new(big.Int).Exp(g, y, p) - - pMinusOne := new(big.Int).Sub(p, bigOne) - if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 { - return nil, errors.New("ssh: DH parameter out of bounds") - } - kInt := new(big.Int).Exp(kexDHGexInit.X, y, p) - - hostKeyBytes := priv.PublicKey().Marshal() - - h := gex.hashFunc.New() - magics.write(h) - writeString(h, hostKeyBytes) - binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) - binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) - binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) - writeInt(h, p) - writeInt(h, g) - writeInt(h, kexDHGexInit.X) - writeInt(h, Y) - - K := make([]byte, intLength(kInt)) - marshalInt(K, kInt) - h.Write(K) - - H := h.Sum(nil) - - // H is already a hash, but the hostkey signing will apply its - // own key-specific hash algorithm. - sig, err := signAndMarshal(priv, randSource, H, algo) - if err != nil { - return nil, err - } - - kexDHGexReply := kexDHGexReplyMsg{ - HostKey: hostKeyBytes, - Y: Y, - Signature: sig, - } - packet = Marshal(&kexDHGexReply) - - err = c.writePacket(packet) - - return &kexResult{ - H: H, - K: K, - HostKey: hostKeyBytes, - Signature: sig, - Hash: gex.hashFunc, - }, err -} diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go deleted file mode 100644 index 1c7de1a6..00000000 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ /dev/null @@ -1,1447 +0,0 @@ -// 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 ssh - -import ( - "bytes" - "crypto" - "crypto/aes" - "crypto/cipher" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/md5" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/asn1" - "encoding/base64" - "encoding/hex" - "encoding/pem" - "errors" - "fmt" - "io" - "math/big" - "strings" - - "golang.org/x/crypto/ed25519" - "golang.org/x/crypto/ssh/internal/bcrypt_pbkdf" -) - -// Public key algorithms names. These values can appear in PublicKey.Type, -// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner -// arguments. -const ( - KeyAlgoRSA = "ssh-rsa" - KeyAlgoDSA = "ssh-dss" - KeyAlgoECDSA256 = "ecdsa-sha2-nistp256" - KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com" - KeyAlgoECDSA384 = "ecdsa-sha2-nistp384" - KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" - KeyAlgoED25519 = "ssh-ed25519" - KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com" - - // KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not - // public key formats, so they can't appear as a PublicKey.Type. The - // corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2. - KeyAlgoRSASHA256 = "rsa-sha2-256" - KeyAlgoRSASHA512 = "rsa-sha2-512" -) - -const ( - // Deprecated: use KeyAlgoRSA. - SigAlgoRSA = KeyAlgoRSA - // Deprecated: use KeyAlgoRSASHA256. - SigAlgoRSASHA2256 = KeyAlgoRSASHA256 - // Deprecated: use KeyAlgoRSASHA512. - SigAlgoRSASHA2512 = KeyAlgoRSASHA512 -) - -// parsePubKey parses a public key of the given algorithm. -// Use ParsePublicKey for keys with prepended algorithm. -func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { - switch algo { - case KeyAlgoRSA: - return parseRSA(in) - case KeyAlgoDSA: - return parseDSA(in) - case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: - return parseECDSA(in) - case KeyAlgoSKECDSA256: - return parseSKECDSA(in) - case KeyAlgoED25519: - return parseED25519(in) - case KeyAlgoSKED25519: - return parseSKEd25519(in) - case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: - cert, err := parseCert(in, certKeyAlgoNames[algo]) - if err != nil { - return nil, nil, err - } - return cert, nil, nil - } - return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) -} - -// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format -// (see sshd(8) manual page) once the options and key type fields have been -// removed. -func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) { - in = bytes.TrimSpace(in) - - i := bytes.IndexAny(in, " \t") - if i == -1 { - i = len(in) - } - base64Key := in[:i] - - key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key))) - n, err := base64.StdEncoding.Decode(key, base64Key) - if err != nil { - return nil, "", err - } - key = key[:n] - out, err = ParsePublicKey(key) - if err != nil { - return nil, "", err - } - comment = string(bytes.TrimSpace(in[i:])) - return out, comment, nil -} - -// ParseKnownHosts parses an entry in the format of the known_hosts file. -// -// The known_hosts format is documented in the sshd(8) manual page. This -// function will parse a single entry from in. On successful return, marker -// will contain the optional marker value (i.e. "cert-authority" or "revoked") -// or else be empty, hosts will contain the hosts that this entry matches, -// pubKey will contain the public key and comment will contain any trailing -// comment at the end of the line. See the sshd(8) manual page for the various -// forms that a host string can take. -// -// The unparsed remainder of the input will be returned in rest. This function -// can be called repeatedly to parse multiple entries. -// -// If no entries were found in the input then err will be io.EOF. Otherwise a -// non-nil err value indicates a parse error. -func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) { - for len(in) > 0 { - end := bytes.IndexByte(in, '\n') - if end != -1 { - rest = in[end+1:] - in = in[:end] - } else { - rest = nil - } - - end = bytes.IndexByte(in, '\r') - if end != -1 { - in = in[:end] - } - - in = bytes.TrimSpace(in) - if len(in) == 0 || in[0] == '#' { - in = rest - continue - } - - i := bytes.IndexAny(in, " \t") - if i == -1 { - in = rest - continue - } - - // Strip out the beginning of the known_host key. - // This is either an optional marker or a (set of) hostname(s). - keyFields := bytes.Fields(in) - if len(keyFields) < 3 || len(keyFields) > 5 { - return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data") - } - - // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated - // list of hosts - marker := "" - if keyFields[0][0] == '@' { - marker = string(keyFields[0][1:]) - keyFields = keyFields[1:] - } - - hosts := string(keyFields[0]) - // keyFields[1] contains the key type (e.g. “ssh-rsa”). - // However, that information is duplicated inside the - // base64-encoded key and so is ignored here. - - key := bytes.Join(keyFields[2:], []byte(" ")) - if pubKey, comment, err = parseAuthorizedKey(key); err != nil { - return "", nil, nil, "", nil, err - } - - return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil - } - - return "", nil, nil, "", nil, io.EOF -} - -// ParseAuthorizedKeys parses a public key from an authorized_keys -// file used in OpenSSH according to the sshd(8) manual page. -func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { - for len(in) > 0 { - end := bytes.IndexByte(in, '\n') - if end != -1 { - rest = in[end+1:] - in = in[:end] - } else { - rest = nil - } - - end = bytes.IndexByte(in, '\r') - if end != -1 { - in = in[:end] - } - - in = bytes.TrimSpace(in) - if len(in) == 0 || in[0] == '#' { - in = rest - continue - } - - i := bytes.IndexAny(in, " \t") - if i == -1 { - in = rest - continue - } - - if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { - return out, comment, options, rest, nil - } - - // No key type recognised. Maybe there's an options field at - // the beginning. - var b byte - inQuote := false - var candidateOptions []string - optionStart := 0 - for i, b = range in { - isEnd := !inQuote && (b == ' ' || b == '\t') - if (b == ',' && !inQuote) || isEnd { - if i-optionStart > 0 { - candidateOptions = append(candidateOptions, string(in[optionStart:i])) - } - optionStart = i + 1 - } - if isEnd { - break - } - if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) { - inQuote = !inQuote - } - } - for i < len(in) && (in[i] == ' ' || in[i] == '\t') { - i++ - } - if i == len(in) { - // Invalid line: unmatched quote - in = rest - continue - } - - in = in[i:] - i = bytes.IndexAny(in, " \t") - if i == -1 { - in = rest - continue - } - - if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { - options = candidateOptions - return out, comment, options, rest, nil - } - - in = rest - continue - } - - return nil, "", nil, nil, errors.New("ssh: no key found") -} - -// ParsePublicKey parses an SSH public key formatted for use in -// the SSH wire protocol according to RFC 4253, section 6.6. -func ParsePublicKey(in []byte) (out PublicKey, err error) { - algo, in, ok := parseString(in) - if !ok { - return nil, errShortRead - } - var rest []byte - out, rest, err = parsePubKey(in, string(algo)) - if len(rest) > 0 { - return nil, errors.New("ssh: trailing junk in public key") - } - - return out, err -} - -// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH -// authorized_keys file. The return value ends with newline. -func MarshalAuthorizedKey(key PublicKey) []byte { - b := &bytes.Buffer{} - b.WriteString(key.Type()) - b.WriteByte(' ') - e := base64.NewEncoder(base64.StdEncoding, b) - e.Write(key.Marshal()) - e.Close() - b.WriteByte('\n') - return b.Bytes() -} - -// PublicKey represents a public key using an unspecified algorithm. -// -// Some PublicKeys provided by this package also implement CryptoPublicKey. -type PublicKey interface { - // Type returns the key format name, e.g. "ssh-rsa". - Type() string - - // Marshal returns the serialized key data in SSH wire format, with the name - // prefix. To unmarshal the returned data, use the ParsePublicKey function. - Marshal() []byte - - // Verify that sig is a signature on the given data using this key. This - // method will hash the data appropriately first. sig.Format is allowed to - // be any signature algorithm compatible with the key type, the caller - // should check if it has more stringent requirements. - Verify(data []byte, sig *Signature) error -} - -// CryptoPublicKey, if implemented by a PublicKey, -// returns the underlying crypto.PublicKey form of the key. -type CryptoPublicKey interface { - CryptoPublicKey() crypto.PublicKey -} - -// A Signer can create signatures that verify against a public key. -// -// Some Signers provided by this package also implement AlgorithmSigner. -type Signer interface { - // PublicKey returns the associated PublicKey. - PublicKey() PublicKey - - // Sign returns a signature for the given data. This method will hash the - // data appropriately first. The signature algorithm is expected to match - // the key format returned by the PublicKey.Type method (and not to be any - // alternative algorithm supported by the key format). - Sign(rand io.Reader, data []byte) (*Signature, error) -} - -// An AlgorithmSigner is a Signer that also supports specifying an algorithm to -// use for signing. -// -// An AlgorithmSigner can't advertise the algorithms it supports, so it should -// be prepared to be invoked with every algorithm supported by the public key -// format. -type AlgorithmSigner interface { - Signer - - // SignWithAlgorithm is like Signer.Sign, but allows specifying a desired - // signing algorithm. Callers may pass an empty string for the algorithm in - // which case the AlgorithmSigner will use a default algorithm. This default - // doesn't currently control any behavior in this package. - SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) -} - -type rsaPublicKey rsa.PublicKey - -func (r *rsaPublicKey) Type() string { - return "ssh-rsa" -} - -// parseRSA parses an RSA key according to RFC 4253, section 6.6. -func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { - var w struct { - E *big.Int - N *big.Int - Rest []byte `ssh:"rest"` - } - if err := Unmarshal(in, &w); err != nil { - return nil, nil, err - } - - if w.E.BitLen() > 24 { - return nil, nil, errors.New("ssh: exponent too large") - } - e := w.E.Int64() - if e < 3 || e&1 == 0 { - return nil, nil, errors.New("ssh: incorrect exponent") - } - - var key rsa.PublicKey - key.E = int(e) - key.N = w.N - return (*rsaPublicKey)(&key), w.Rest, nil -} - -func (r *rsaPublicKey) Marshal() []byte { - e := new(big.Int).SetInt64(int64(r.E)) - // RSA publickey struct layout should match the struct used by - // parseRSACert in the x/crypto/ssh/agent package. - wirekey := struct { - Name string - E *big.Int - N *big.Int - }{ - KeyAlgoRSA, - e, - r.N, - } - return Marshal(&wirekey) -} - -func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { - supportedAlgos := algorithmsForKeyFormat(r.Type()) - if !contains(supportedAlgos, sig.Format) { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) - } - hash := hashFuncs[sig.Format] - h := hash.New() - h.Write(data) - digest := h.Sum(nil) - return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) -} - -func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { - return (*rsa.PublicKey)(r) -} - -type dsaPublicKey dsa.PublicKey - -func (k *dsaPublicKey) Type() string { - return "ssh-dss" -} - -func checkDSAParams(param *dsa.Parameters) error { - // SSH specifies FIPS 186-2, which only provided a single size - // (1024 bits) DSA key. FIPS 186-3 allows for larger key - // sizes, which would confuse SSH. - if l := param.P.BitLen(); l != 1024 { - return fmt.Errorf("ssh: unsupported DSA key size %d", l) - } - - return nil -} - -// parseDSA parses an DSA key according to RFC 4253, section 6.6. -func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { - var w struct { - P, Q, G, Y *big.Int - Rest []byte `ssh:"rest"` - } - if err := Unmarshal(in, &w); err != nil { - return nil, nil, err - } - - param := dsa.Parameters{ - P: w.P, - Q: w.Q, - G: w.G, - } - if err := checkDSAParams(¶m); err != nil { - return nil, nil, err - } - - key := &dsaPublicKey{ - Parameters: param, - Y: w.Y, - } - return key, w.Rest, nil -} - -func (k *dsaPublicKey) Marshal() []byte { - // DSA publickey struct layout should match the struct used by - // parseDSACert in the x/crypto/ssh/agent package. - w := struct { - Name string - P, Q, G, Y *big.Int - }{ - k.Type(), - k.P, - k.Q, - k.G, - k.Y, - } - - return Marshal(&w) -} - -func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != k.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) - } - h := hashFuncs[sig.Format].New() - h.Write(data) - digest := h.Sum(nil) - - // Per RFC 4253, section 6.6, - // The value for 'dss_signature_blob' is encoded as a string containing - // r, followed by s (which are 160-bit integers, without lengths or - // padding, unsigned, and in network byte order). - // For DSS purposes, sig.Blob should be exactly 40 bytes in length. - if len(sig.Blob) != 40 { - return errors.New("ssh: DSA signature parse error") - } - r := new(big.Int).SetBytes(sig.Blob[:20]) - s := new(big.Int).SetBytes(sig.Blob[20:]) - if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) { - return nil - } - return errors.New("ssh: signature did not verify") -} - -func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { - return (*dsa.PublicKey)(k) -} - -type dsaPrivateKey struct { - *dsa.PrivateKey -} - -func (k *dsaPrivateKey) PublicKey() PublicKey { - return (*dsaPublicKey)(&k.PrivateKey.PublicKey) -} - -func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { - return k.SignWithAlgorithm(rand, data, k.PublicKey().Type()) -} - -func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { - if algorithm != "" && algorithm != k.PublicKey().Type() { - return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) - } - - h := hashFuncs[k.PublicKey().Type()].New() - h.Write(data) - digest := h.Sum(nil) - r, s, err := dsa.Sign(rand, k.PrivateKey, digest) - if err != nil { - return nil, err - } - - sig := make([]byte, 40) - rb := r.Bytes() - sb := s.Bytes() - - copy(sig[20-len(rb):20], rb) - copy(sig[40-len(sb):], sb) - - return &Signature{ - Format: k.PublicKey().Type(), - Blob: sig, - }, nil -} - -type ecdsaPublicKey ecdsa.PublicKey - -func (k *ecdsaPublicKey) Type() string { - return "ecdsa-sha2-" + k.nistID() -} - -func (k *ecdsaPublicKey) nistID() string { - switch k.Params().BitSize { - case 256: - return "nistp256" - case 384: - return "nistp384" - case 521: - return "nistp521" - } - panic("ssh: unsupported ecdsa key size") -} - -type ed25519PublicKey ed25519.PublicKey - -func (k ed25519PublicKey) Type() string { - return KeyAlgoED25519 -} - -func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { - var w struct { - KeyBytes []byte - Rest []byte `ssh:"rest"` - } - - if err := Unmarshal(in, &w); err != nil { - return nil, nil, err - } - - if l := len(w.KeyBytes); l != ed25519.PublicKeySize { - return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l) - } - - return ed25519PublicKey(w.KeyBytes), w.Rest, nil -} - -func (k ed25519PublicKey) Marshal() []byte { - w := struct { - Name string - KeyBytes []byte - }{ - KeyAlgoED25519, - []byte(k), - } - return Marshal(&w) -} - -func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error { - if sig.Format != k.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) - } - if l := len(k); l != ed25519.PublicKeySize { - return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l) - } - - if ok := ed25519.Verify(ed25519.PublicKey(k), b, sig.Blob); !ok { - return errors.New("ssh: signature did not verify") - } - - return nil -} - -func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { - return ed25519.PublicKey(k) -} - -func supportedEllipticCurve(curve elliptic.Curve) bool { - return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() -} - -// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. -func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { - var w struct { - Curve string - KeyBytes []byte - Rest []byte `ssh:"rest"` - } - - if err := Unmarshal(in, &w); err != nil { - return nil, nil, err - } - - key := new(ecdsa.PublicKey) - - switch w.Curve { - case "nistp256": - key.Curve = elliptic.P256() - case "nistp384": - key.Curve = elliptic.P384() - case "nistp521": - key.Curve = elliptic.P521() - default: - return nil, nil, errors.New("ssh: unsupported curve") - } - - key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) - if key.X == nil || key.Y == nil { - return nil, nil, errors.New("ssh: invalid curve point") - } - return (*ecdsaPublicKey)(key), w.Rest, nil -} - -func (k *ecdsaPublicKey) Marshal() []byte { - // See RFC 5656, section 3.1. - keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) - // ECDSA publickey struct layout should match the struct used by - // parseECDSACert in the x/crypto/ssh/agent package. - w := struct { - Name string - ID string - Key []byte - }{ - k.Type(), - k.nistID(), - keyBytes, - } - - return Marshal(&w) -} - -func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != k.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) - } - - h := hashFuncs[sig.Format].New() - h.Write(data) - digest := h.Sum(nil) - - // Per RFC 5656, section 3.1.2, - // The ecdsa_signature_blob value has the following specific encoding: - // mpint r - // mpint s - var ecSig struct { - R *big.Int - S *big.Int - } - - if err := Unmarshal(sig.Blob, &ecSig); err != nil { - return err - } - - if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) { - return nil - } - return errors.New("ssh: signature did not verify") -} - -func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { - return (*ecdsa.PublicKey)(k) -} - -// skFields holds the additional fields present in U2F/FIDO2 signatures. -// See openssh/PROTOCOL.u2f 'SSH U2F Signatures' for details. -type skFields struct { - // Flags contains U2F/FIDO2 flags such as 'user present' - Flags byte - // Counter is a monotonic signature counter which can be - // used to detect concurrent use of a private key, should - // it be extracted from hardware. - Counter uint32 -} - -type skECDSAPublicKey struct { - // application is a URL-like string, typically "ssh:" for SSH. - // see openssh/PROTOCOL.u2f for details. - application string - ecdsa.PublicKey -} - -func (k *skECDSAPublicKey) Type() string { - return KeyAlgoSKECDSA256 -} - -func (k *skECDSAPublicKey) nistID() string { - return "nistp256" -} - -func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) { - var w struct { - Curve string - KeyBytes []byte - Application string - Rest []byte `ssh:"rest"` - } - - if err := Unmarshal(in, &w); err != nil { - return nil, nil, err - } - - key := new(skECDSAPublicKey) - key.application = w.Application - - if w.Curve != "nistp256" { - return nil, nil, errors.New("ssh: unsupported curve") - } - key.Curve = elliptic.P256() - - key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) - if key.X == nil || key.Y == nil { - return nil, nil, errors.New("ssh: invalid curve point") - } - - return key, w.Rest, nil -} - -func (k *skECDSAPublicKey) Marshal() []byte { - // See RFC 5656, section 3.1. - keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) - w := struct { - Name string - ID string - Key []byte - Application string - }{ - k.Type(), - k.nistID(), - keyBytes, - k.application, - } - - return Marshal(&w) -} - -func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != k.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) - } - - h := hashFuncs[sig.Format].New() - h.Write([]byte(k.application)) - appDigest := h.Sum(nil) - - h.Reset() - h.Write(data) - dataDigest := h.Sum(nil) - - var ecSig struct { - R *big.Int - S *big.Int - } - if err := Unmarshal(sig.Blob, &ecSig); err != nil { - return err - } - - var skf skFields - if err := Unmarshal(sig.Rest, &skf); err != nil { - return err - } - - blob := struct { - ApplicationDigest []byte `ssh:"rest"` - Flags byte - Counter uint32 - MessageDigest []byte `ssh:"rest"` - }{ - appDigest, - skf.Flags, - skf.Counter, - dataDigest, - } - - original := Marshal(blob) - - h.Reset() - h.Write(original) - digest := h.Sum(nil) - - if ecdsa.Verify((*ecdsa.PublicKey)(&k.PublicKey), digest, ecSig.R, ecSig.S) { - return nil - } - return errors.New("ssh: signature did not verify") -} - -type skEd25519PublicKey struct { - // application is a URL-like string, typically "ssh:" for SSH. - // see openssh/PROTOCOL.u2f for details. - application string - ed25519.PublicKey -} - -func (k *skEd25519PublicKey) Type() string { - return KeyAlgoSKED25519 -} - -func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) { - var w struct { - KeyBytes []byte - Application string - Rest []byte `ssh:"rest"` - } - - if err := Unmarshal(in, &w); err != nil { - return nil, nil, err - } - - if l := len(w.KeyBytes); l != ed25519.PublicKeySize { - return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l) - } - - key := new(skEd25519PublicKey) - key.application = w.Application - key.PublicKey = ed25519.PublicKey(w.KeyBytes) - - return key, w.Rest, nil -} - -func (k *skEd25519PublicKey) Marshal() []byte { - w := struct { - Name string - KeyBytes []byte - Application string - }{ - KeyAlgoSKED25519, - []byte(k.PublicKey), - k.application, - } - return Marshal(&w) -} - -func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != k.Type() { - return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) - } - if l := len(k.PublicKey); l != ed25519.PublicKeySize { - return fmt.Errorf("invalid size %d for Ed25519 public key", l) - } - - h := hashFuncs[sig.Format].New() - h.Write([]byte(k.application)) - appDigest := h.Sum(nil) - - h.Reset() - h.Write(data) - dataDigest := h.Sum(nil) - - var edSig struct { - Signature []byte `ssh:"rest"` - } - - if err := Unmarshal(sig.Blob, &edSig); err != nil { - return err - } - - var skf skFields - if err := Unmarshal(sig.Rest, &skf); err != nil { - return err - } - - blob := struct { - ApplicationDigest []byte `ssh:"rest"` - Flags byte - Counter uint32 - MessageDigest []byte `ssh:"rest"` - }{ - appDigest, - skf.Flags, - skf.Counter, - dataDigest, - } - - original := Marshal(blob) - - if ok := ed25519.Verify(k.PublicKey, original, edSig.Signature); !ok { - return errors.New("ssh: signature did not verify") - } - - return nil -} - -// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, -// *ecdsa.PrivateKey or any other crypto.Signer and returns a -// corresponding Signer instance. ECDSA keys must use P-256, P-384 or -// P-521. DSA keys must use parameter size L1024N160. -func NewSignerFromKey(key interface{}) (Signer, error) { - switch key := key.(type) { - case crypto.Signer: - return NewSignerFromSigner(key) - case *dsa.PrivateKey: - return newDSAPrivateKey(key) - default: - return nil, fmt.Errorf("ssh: unsupported key type %T", key) - } -} - -func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) { - if err := checkDSAParams(&key.PublicKey.Parameters); err != nil { - return nil, err - } - - return &dsaPrivateKey{key}, nil -} - -type wrappedSigner struct { - signer crypto.Signer - pubKey PublicKey -} - -// NewSignerFromSigner takes any crypto.Signer implementation and -// returns a corresponding Signer interface. This can be used, for -// example, with keys kept in hardware modules. -func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { - pubKey, err := NewPublicKey(signer.Public()) - if err != nil { - return nil, err - } - - return &wrappedSigner{signer, pubKey}, nil -} - -func (s *wrappedSigner) PublicKey() PublicKey { - return s.pubKey -} - -func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { - return s.SignWithAlgorithm(rand, data, s.pubKey.Type()) -} - -func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { - if algorithm == "" { - algorithm = s.pubKey.Type() - } - - supportedAlgos := algorithmsForKeyFormat(s.pubKey.Type()) - if !contains(supportedAlgos, algorithm) { - return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type()) - } - - hashFunc := hashFuncs[algorithm] - var digest []byte - if hashFunc != 0 { - h := hashFunc.New() - h.Write(data) - digest = h.Sum(nil) - } else { - digest = data - } - - signature, err := s.signer.Sign(rand, digest, hashFunc) - if err != nil { - return nil, err - } - - // crypto.Signer.Sign is expected to return an ASN.1-encoded signature - // for ECDSA and DSA, but that's not the encoding expected by SSH, so - // re-encode. - switch s.pubKey.(type) { - case *ecdsaPublicKey, *dsaPublicKey: - type asn1Signature struct { - R, S *big.Int - } - asn1Sig := new(asn1Signature) - _, err := asn1.Unmarshal(signature, asn1Sig) - if err != nil { - return nil, err - } - - switch s.pubKey.(type) { - case *ecdsaPublicKey: - signature = Marshal(asn1Sig) - - case *dsaPublicKey: - signature = make([]byte, 40) - r := asn1Sig.R.Bytes() - s := asn1Sig.S.Bytes() - copy(signature[20-len(r):20], r) - copy(signature[40-len(s):40], s) - } - } - - return &Signature{ - Format: algorithm, - Blob: signature, - }, nil -} - -// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, -// or ed25519.PublicKey returns a corresponding PublicKey instance. -// ECDSA keys must use P-256, P-384 or P-521. -func NewPublicKey(key interface{}) (PublicKey, error) { - switch key := key.(type) { - case *rsa.PublicKey: - return (*rsaPublicKey)(key), nil - case *ecdsa.PublicKey: - if !supportedEllipticCurve(key.Curve) { - return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported") - } - return (*ecdsaPublicKey)(key), nil - case *dsa.PublicKey: - return (*dsaPublicKey)(key), nil - case ed25519.PublicKey: - if l := len(key); l != ed25519.PublicKeySize { - return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l) - } - return ed25519PublicKey(key), nil - default: - return nil, fmt.Errorf("ssh: unsupported key type %T", key) - } -} - -// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports -// the same keys as ParseRawPrivateKey. If the private key is encrypted, it -// will return a PassphraseMissingError. -func ParsePrivateKey(pemBytes []byte) (Signer, error) { - key, err := ParseRawPrivateKey(pemBytes) - if err != nil { - return nil, err - } - - return NewSignerFromKey(key) -} - -// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private -// key and passphrase. It supports the same keys as -// ParseRawPrivateKeyWithPassphrase. -func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error) { - key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase) - if err != nil { - return nil, err - } - - return NewSignerFromKey(key) -} - -// encryptedBlock tells whether a private key is -// encrypted by examining its Proc-Type header -// for a mention of ENCRYPTED -// according to RFC 1421 Section 4.6.1.1. -func encryptedBlock(block *pem.Block) bool { - return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") -} - -// A PassphraseMissingError indicates that parsing this private key requires a -// passphrase. Use ParsePrivateKeyWithPassphrase. -type PassphraseMissingError struct { - // PublicKey will be set if the private key format includes an unencrypted - // public key along with the encrypted private key. - PublicKey PublicKey -} - -func (*PassphraseMissingError) Error() string { - return "ssh: this private key is passphrase protected" -} - -// ParseRawPrivateKey returns a private key from a PEM encoded private key. It -// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. If the -// private key is encrypted, it will return a PassphraseMissingError. -func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { - block, _ := pem.Decode(pemBytes) - if block == nil { - return nil, errors.New("ssh: no key found") - } - - if encryptedBlock(block) { - return nil, &PassphraseMissingError{} - } - - switch block.Type { - case "RSA PRIVATE KEY": - return x509.ParsePKCS1PrivateKey(block.Bytes) - // RFC5208 - https://tools.ietf.org/html/rfc5208 - case "PRIVATE KEY": - return x509.ParsePKCS8PrivateKey(block.Bytes) - case "EC PRIVATE KEY": - return x509.ParseECPrivateKey(block.Bytes) - case "DSA PRIVATE KEY": - return ParseDSAPrivateKey(block.Bytes) - case "OPENSSH PRIVATE KEY": - return parseOpenSSHPrivateKey(block.Bytes, unencryptedOpenSSHKey) - default: - return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) - } -} - -// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with -// passphrase from a PEM encoded private key. If the passphrase is wrong, it -// will return x509.IncorrectPasswordError. -func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error) { - block, _ := pem.Decode(pemBytes) - if block == nil { - return nil, errors.New("ssh: no key found") - } - - if block.Type == "OPENSSH PRIVATE KEY" { - return parseOpenSSHPrivateKey(block.Bytes, passphraseProtectedOpenSSHKey(passphrase)) - } - - if !encryptedBlock(block) || !x509.IsEncryptedPEMBlock(block) { - return nil, errors.New("ssh: not an encrypted key") - } - - buf, err := x509.DecryptPEMBlock(block, passphrase) - if err != nil { - if err == x509.IncorrectPasswordError { - return nil, err - } - return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err) - } - - switch block.Type { - case "RSA PRIVATE KEY": - return x509.ParsePKCS1PrivateKey(buf) - case "EC PRIVATE KEY": - return x509.ParseECPrivateKey(buf) - case "DSA PRIVATE KEY": - return ParseDSAPrivateKey(buf) - default: - return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) - } -} - -// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as -// specified by the OpenSSL DSA man page. -func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { - var k struct { - Version int - P *big.Int - Q *big.Int - G *big.Int - Pub *big.Int - Priv *big.Int - } - rest, err := asn1.Unmarshal(der, &k) - if err != nil { - return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) - } - if len(rest) > 0 { - return nil, errors.New("ssh: garbage after DSA key") - } - - return &dsa.PrivateKey{ - PublicKey: dsa.PublicKey{ - Parameters: dsa.Parameters{ - P: k.P, - Q: k.Q, - G: k.G, - }, - Y: k.Pub, - }, - X: k.Priv, - }, nil -} - -func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) { - if kdfName != "none" || cipherName != "none" { - return nil, &PassphraseMissingError{} - } - if kdfOpts != "" { - return nil, errors.New("ssh: invalid openssh private key") - } - return privKeyBlock, nil -} - -func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc { - return func(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) { - if kdfName == "none" || cipherName == "none" { - return nil, errors.New("ssh: key is not password protected") - } - if kdfName != "bcrypt" { - return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", kdfName, "bcrypt") - } - - var opts struct { - Salt string - Rounds uint32 - } - if err := Unmarshal([]byte(kdfOpts), &opts); err != nil { - return nil, err - } - - k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16) - if err != nil { - return nil, err - } - key, iv := k[:32], k[32:] - - c, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - switch cipherName { - case "aes256-ctr": - ctr := cipher.NewCTR(c, iv) - ctr.XORKeyStream(privKeyBlock, privKeyBlock) - case "aes256-cbc": - if len(privKeyBlock)%c.BlockSize() != 0 { - return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size") - } - cbc := cipher.NewCBCDecrypter(c, iv) - cbc.CryptBlocks(privKeyBlock, privKeyBlock) - default: - return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc") - } - - return privKeyBlock, nil - } -} - -type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error) - -// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt -// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used -// as the decrypt function to parse an unencrypted private key. See -// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key. -func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) { - const magic = "openssh-key-v1\x00" - if len(key) < len(magic) || string(key[:len(magic)]) != magic { - return nil, errors.New("ssh: invalid openssh private key format") - } - remaining := key[len(magic):] - - var w struct { - CipherName string - KdfName string - KdfOpts string - NumKeys uint32 - PubKey []byte - PrivKeyBlock []byte - } - - if err := Unmarshal(remaining, &w); err != nil { - return nil, err - } - if w.NumKeys != 1 { - // We only support single key files, and so does OpenSSH. - // https://github.com/openssh/openssh-portable/blob/4103a3ec7/sshkey.c#L4171 - return nil, errors.New("ssh: multi-key files are not supported") - } - - privKeyBlock, err := decrypt(w.CipherName, w.KdfName, w.KdfOpts, w.PrivKeyBlock) - if err != nil { - if err, ok := err.(*PassphraseMissingError); ok { - pub, errPub := ParsePublicKey(w.PubKey) - if errPub != nil { - return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", errPub) - } - err.PublicKey = pub - } - return nil, err - } - - pk1 := struct { - Check1 uint32 - Check2 uint32 - Keytype string - Rest []byte `ssh:"rest"` - }{} - - if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 { - if w.CipherName != "none" { - return nil, x509.IncorrectPasswordError - } - return nil, errors.New("ssh: malformed OpenSSH key") - } - - switch pk1.Keytype { - case KeyAlgoRSA: - // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773 - key := struct { - N *big.Int - E *big.Int - D *big.Int - Iqmp *big.Int - P *big.Int - Q *big.Int - Comment string - Pad []byte `ssh:"rest"` - }{} - - if err := Unmarshal(pk1.Rest, &key); err != nil { - return nil, err - } - - if err := checkOpenSSHKeyPadding(key.Pad); err != nil { - return nil, err - } - - pk := &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: key.N, - E: int(key.E.Int64()), - }, - D: key.D, - Primes: []*big.Int{key.P, key.Q}, - } - - if err := pk.Validate(); err != nil { - return nil, err - } - - pk.Precompute() - - return pk, nil - case KeyAlgoED25519: - key := struct { - Pub []byte - Priv []byte - Comment string - Pad []byte `ssh:"rest"` - }{} - - if err := Unmarshal(pk1.Rest, &key); err != nil { - return nil, err - } - - if len(key.Priv) != ed25519.PrivateKeySize { - return nil, errors.New("ssh: private key unexpected length") - } - - if err := checkOpenSSHKeyPadding(key.Pad); err != nil { - return nil, err - } - - pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) - copy(pk, key.Priv) - return &pk, nil - case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: - key := struct { - Curve string - Pub []byte - D *big.Int - Comment string - Pad []byte `ssh:"rest"` - }{} - - if err := Unmarshal(pk1.Rest, &key); err != nil { - return nil, err - } - - if err := checkOpenSSHKeyPadding(key.Pad); err != nil { - return nil, err - } - - var curve elliptic.Curve - switch key.Curve { - case "nistp256": - curve = elliptic.P256() - case "nistp384": - curve = elliptic.P384() - case "nistp521": - curve = elliptic.P521() - default: - return nil, errors.New("ssh: unhandled elliptic curve: " + key.Curve) - } - - X, Y := elliptic.Unmarshal(curve, key.Pub) - if X == nil || Y == nil { - return nil, errors.New("ssh: failed to unmarshal public key") - } - - if key.D.Cmp(curve.Params().N) >= 0 { - return nil, errors.New("ssh: scalar is out of range") - } - - x, y := curve.ScalarBaseMult(key.D.Bytes()) - if x.Cmp(X) != 0 || y.Cmp(Y) != 0 { - return nil, errors.New("ssh: public key does not match private key") - } - - return &ecdsa.PrivateKey{ - PublicKey: ecdsa.PublicKey{ - Curve: curve, - X: X, - Y: Y, - }, - D: key.D, - }, nil - default: - return nil, errors.New("ssh: unhandled key type") - } -} - -func checkOpenSSHKeyPadding(pad []byte) error { - for i, b := range pad { - if int(b) != i+1 { - return errors.New("ssh: padding not as expected") - } - } - return nil -} - -// FingerprintLegacyMD5 returns the user presentation of the key's -// fingerprint as described by RFC 4716 section 4. -func FingerprintLegacyMD5(pubKey PublicKey) string { - md5sum := md5.Sum(pubKey.Marshal()) - hexarray := make([]string, len(md5sum)) - for i, c := range md5sum { - hexarray[i] = hex.EncodeToString([]byte{c}) - } - return strings.Join(hexarray, ":") -} - -// FingerprintSHA256 returns the user presentation of the key's -// fingerprint as unpadded base64 encoded sha256 hash. -// This format was introduced from OpenSSH 6.8. -// https://www.openssh.com/txt/release-6.8 -// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding) -func FingerprintSHA256(pubKey PublicKey) string { - sha256sum := sha256.Sum256(pubKey.Marshal()) - hash := base64.RawStdEncoding.EncodeToString(sha256sum[:]) - return "SHA256:" + hash -} diff --git a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go deleted file mode 100644 index 260cfe58..00000000 --- a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright 2017 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 knownhosts implements a parser for the OpenSSH known_hosts -// host key database, and provides utility functions for writing -// OpenSSH compliant known_hosts files. -package knownhosts - -import ( - "bufio" - "bytes" - "crypto/hmac" - "crypto/rand" - "crypto/sha1" - "encoding/base64" - "errors" - "fmt" - "io" - "net" - "os" - "strings" - - "golang.org/x/crypto/ssh" -) - -// See the sshd manpage -// (http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT) for -// background. - -type addr struct{ host, port string } - -func (a *addr) String() string { - h := a.host - if strings.Contains(h, ":") { - h = "[" + h + "]" - } - return h + ":" + a.port -} - -type matcher interface { - match(addr) bool -} - -type hostPattern struct { - negate bool - addr addr -} - -func (p *hostPattern) String() string { - n := "" - if p.negate { - n = "!" - } - - return n + p.addr.String() -} - -type hostPatterns []hostPattern - -func (ps hostPatterns) match(a addr) bool { - matched := false - for _, p := range ps { - if !p.match(a) { - continue - } - if p.negate { - return false - } - matched = true - } - return matched -} - -// See -// https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/addrmatch.c -// The matching of * has no regard for separators, unlike filesystem globs -func wildcardMatch(pat []byte, str []byte) bool { - for { - if len(pat) == 0 { - return len(str) == 0 - } - if len(str) == 0 { - return false - } - - if pat[0] == '*' { - if len(pat) == 1 { - return true - } - - for j := range str { - if wildcardMatch(pat[1:], str[j:]) { - return true - } - } - return false - } - - if pat[0] == '?' || pat[0] == str[0] { - pat = pat[1:] - str = str[1:] - } else { - return false - } - } -} - -func (p *hostPattern) match(a addr) bool { - return wildcardMatch([]byte(p.addr.host), []byte(a.host)) && p.addr.port == a.port -} - -type keyDBLine struct { - cert bool - matcher matcher - knownKey KnownKey -} - -func serialize(k ssh.PublicKey) string { - return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal()) -} - -func (l *keyDBLine) match(a addr) bool { - return l.matcher.match(a) -} - -type hostKeyDB struct { - // Serialized version of revoked keys - revoked map[string]*KnownKey - lines []keyDBLine -} - -func newHostKeyDB() *hostKeyDB { - db := &hostKeyDB{ - revoked: make(map[string]*KnownKey), - } - - return db -} - -func keyEq(a, b ssh.PublicKey) bool { - return bytes.Equal(a.Marshal(), b.Marshal()) -} - -// IsAuthorityForHost can be used as a callback in ssh.CertChecker -func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool { - h, p, err := net.SplitHostPort(address) - if err != nil { - return false - } - a := addr{host: h, port: p} - - for _, l := range db.lines { - if l.cert && keyEq(l.knownKey.Key, remote) && l.match(a) { - return true - } - } - return false -} - -// IsRevoked can be used as a callback in ssh.CertChecker -func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool { - _, ok := db.revoked[string(key.Marshal())] - return ok -} - -const markerCert = "@cert-authority" -const markerRevoked = "@revoked" - -func nextWord(line []byte) (string, []byte) { - i := bytes.IndexAny(line, "\t ") - if i == -1 { - return string(line), nil - } - - return string(line[:i]), bytes.TrimSpace(line[i:]) -} - -func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error) { - if w, next := nextWord(line); w == markerCert || w == markerRevoked { - marker = w - line = next - } - - host, line = nextWord(line) - if len(line) == 0 { - return "", "", nil, errors.New("knownhosts: missing host pattern") - } - - // ignore the keytype as it's in the key blob anyway. - _, line = nextWord(line) - if len(line) == 0 { - return "", "", nil, errors.New("knownhosts: missing key type pattern") - } - - keyBlob, _ := nextWord(line) - - keyBytes, err := base64.StdEncoding.DecodeString(keyBlob) - if err != nil { - return "", "", nil, err - } - key, err = ssh.ParsePublicKey(keyBytes) - if err != nil { - return "", "", nil, err - } - - return marker, host, key, nil -} - -func (db *hostKeyDB) parseLine(line []byte, filename string, linenum int) error { - marker, pattern, key, err := parseLine(line) - if err != nil { - return err - } - - if marker == markerRevoked { - db.revoked[string(key.Marshal())] = &KnownKey{ - Key: key, - Filename: filename, - Line: linenum, - } - - return nil - } - - entry := keyDBLine{ - cert: marker == markerCert, - knownKey: KnownKey{ - Filename: filename, - Line: linenum, - Key: key, - }, - } - - if pattern[0] == '|' { - entry.matcher, err = newHashedHost(pattern) - } else { - entry.matcher, err = newHostnameMatcher(pattern) - } - - if err != nil { - return err - } - - db.lines = append(db.lines, entry) - return nil -} - -func newHostnameMatcher(pattern string) (matcher, error) { - var hps hostPatterns - for _, p := range strings.Split(pattern, ",") { - if len(p) == 0 { - continue - } - - var a addr - var negate bool - if p[0] == '!' { - negate = true - p = p[1:] - } - - if len(p) == 0 { - return nil, errors.New("knownhosts: negation without following hostname") - } - - var err error - if p[0] == '[' { - a.host, a.port, err = net.SplitHostPort(p) - if err != nil { - return nil, err - } - } else { - a.host, a.port, err = net.SplitHostPort(p) - if err != nil { - a.host = p - a.port = "22" - } - } - hps = append(hps, hostPattern{ - negate: negate, - addr: a, - }) - } - return hps, nil -} - -// KnownKey represents a key declared in a known_hosts file. -type KnownKey struct { - Key ssh.PublicKey - Filename string - Line int -} - -func (k *KnownKey) String() string { - return fmt.Sprintf("%s:%d: %s", k.Filename, k.Line, serialize(k.Key)) -} - -// KeyError is returned if we did not find the key in the host key -// database, or there was a mismatch. Typically, in batch -// applications, this should be interpreted as failure. Interactive -// applications can offer an interactive prompt to the user. -type KeyError struct { - // Want holds the accepted host keys. For each key algorithm, - // there can be one hostkey. If Want is empty, the host is - // unknown. If Want is non-empty, there was a mismatch, which - // can signify a MITM attack. - Want []KnownKey -} - -func (u *KeyError) Error() string { - if len(u.Want) == 0 { - return "knownhosts: key is unknown" - } - return "knownhosts: key mismatch" -} - -// RevokedError is returned if we found a key that was revoked. -type RevokedError struct { - Revoked KnownKey -} - -func (r *RevokedError) Error() string { - return "knownhosts: key is revoked" -} - -// check checks a key against the host database. This should not be -// used for verifying certificates. -func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.PublicKey) error { - if revoked := db.revoked[string(remoteKey.Marshal())]; revoked != nil { - return &RevokedError{Revoked: *revoked} - } - - host, port, err := net.SplitHostPort(remote.String()) - if err != nil { - return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err) - } - - hostToCheck := addr{host, port} - if address != "" { - // Give preference to the hostname if available. - host, port, err := net.SplitHostPort(address) - if err != nil { - return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err) - } - - hostToCheck = addr{host, port} - } - - return db.checkAddr(hostToCheck, remoteKey) -} - -// checkAddr checks if we can find the given public key for the -// given address. If we only find an entry for the IP address, -// or only the hostname, then this still succeeds. -func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { - // TODO(hanwen): are these the right semantics? What if there - // is just a key for the IP address, but not for the - // hostname? - - // Algorithm => key. - knownKeys := map[string]KnownKey{} - for _, l := range db.lines { - if l.match(a) { - typ := l.knownKey.Key.Type() - if _, ok := knownKeys[typ]; !ok { - knownKeys[typ] = l.knownKey - } - } - } - - keyErr := &KeyError{} - for _, v := range knownKeys { - keyErr.Want = append(keyErr.Want, v) - } - - // Unknown remote host. - if len(knownKeys) == 0 { - return keyErr - } - - // If the remote host starts using a different, unknown key type, we - // also interpret that as a mismatch. - if known, ok := knownKeys[remoteKey.Type()]; !ok || !keyEq(known.Key, remoteKey) { - return keyErr - } - - return nil -} - -// The Read function parses file contents. -func (db *hostKeyDB) Read(r io.Reader, filename string) error { - scanner := bufio.NewScanner(r) - - lineNum := 0 - for scanner.Scan() { - lineNum++ - line := scanner.Bytes() - line = bytes.TrimSpace(line) - if len(line) == 0 || line[0] == '#' { - continue - } - - if err := db.parseLine(line, filename, lineNum); err != nil { - return fmt.Errorf("knownhosts: %s:%d: %v", filename, lineNum, err) - } - } - return scanner.Err() -} - -// New creates a host key callback from the given OpenSSH host key -// files. The returned callback is for use in -// ssh.ClientConfig.HostKeyCallback. By preference, the key check -// operates on the hostname if available, i.e. if a server changes its -// IP address, the host key check will still succeed, even though a -// record of the new IP address is not available. -func New(files ...string) (ssh.HostKeyCallback, error) { - db := newHostKeyDB() - for _, fn := range files { - f, err := os.Open(fn) - if err != nil { - return nil, err - } - defer f.Close() - if err := db.Read(f, fn); err != nil { - return nil, err - } - } - - var certChecker ssh.CertChecker - certChecker.IsHostAuthority = db.IsHostAuthority - certChecker.IsRevoked = db.IsRevoked - certChecker.HostKeyFallback = db.check - - return certChecker.CheckHostKey, nil -} - -// Normalize normalizes an address into the form used in known_hosts -func Normalize(address string) string { - host, port, err := net.SplitHostPort(address) - if err != nil { - host = address - port = "22" - } - entry := host - if port != "22" { - entry = "[" + entry + "]:" + port - } else if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { - entry = "[" + entry + "]" - } - return entry -} - -// Line returns a line to add append to the known_hosts files. -func Line(addresses []string, key ssh.PublicKey) string { - var trimmed []string - for _, a := range addresses { - trimmed = append(trimmed, Normalize(a)) - } - - return strings.Join(trimmed, ",") + " " + serialize(key) -} - -// HashHostname hashes the given hostname. The hostname is not -// normalized before hashing. -func HashHostname(hostname string) string { - // TODO(hanwen): check if we can safely normalize this always. - salt := make([]byte, sha1.Size) - - _, err := rand.Read(salt) - if err != nil { - panic(fmt.Sprintf("crypto/rand failure %v", err)) - } - - hash := hashHost(hostname, salt) - return encodeHash(sha1HashType, salt, hash) -} - -func decodeHash(encoded string) (hashType string, salt, hash []byte, err error) { - if len(encoded) == 0 || encoded[0] != '|' { - err = errors.New("knownhosts: hashed host must start with '|'") - return - } - components := strings.Split(encoded, "|") - if len(components) != 4 { - err = fmt.Errorf("knownhosts: got %d components, want 3", len(components)) - return - } - - hashType = components[1] - if salt, err = base64.StdEncoding.DecodeString(components[2]); err != nil { - return - } - if hash, err = base64.StdEncoding.DecodeString(components[3]); err != nil { - return - } - return -} - -func encodeHash(typ string, salt []byte, hash []byte) string { - return strings.Join([]string{"", - typ, - base64.StdEncoding.EncodeToString(salt), - base64.StdEncoding.EncodeToString(hash), - }, "|") -} - -// See https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 -func hashHost(hostname string, salt []byte) []byte { - mac := hmac.New(sha1.New, salt) - mac.Write([]byte(hostname)) - return mac.Sum(nil) -} - -type hashedHost struct { - salt []byte - hash []byte -} - -const sha1HashType = "1" - -func newHashedHost(encoded string) (*hashedHost, error) { - typ, salt, hash, err := decodeHash(encoded) - if err != nil { - return nil, err - } - - // The type field seems for future algorithm agility, but it's - // actually hardcoded in openssh currently, see - // https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 - if typ != sha1HashType { - return nil, fmt.Errorf("knownhosts: got hash type %s, must be '1'", typ) - } - - return &hashedHost{salt: salt, hash: hash}, nil -} - -func (h *hashedHost) match(a addr) bool { - return bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) -} diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go deleted file mode 100644 index c07a0628..00000000 --- a/vendor/golang.org/x/crypto/ssh/mac.go +++ /dev/null @@ -1,61 +0,0 @@ -// 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 ssh - -// Message authentication support - -import ( - "crypto/hmac" - "crypto/sha1" - "crypto/sha256" - "hash" -) - -type macMode struct { - keySize int - etm bool - new func(key []byte) hash.Hash -} - -// truncatingMAC wraps around a hash.Hash and truncates the output digest to -// a given size. -type truncatingMAC struct { - length int - hmac hash.Hash -} - -func (t truncatingMAC) Write(data []byte) (int, error) { - return t.hmac.Write(data) -} - -func (t truncatingMAC) Sum(in []byte) []byte { - out := t.hmac.Sum(in) - return out[:len(in)+t.length] -} - -func (t truncatingMAC) Reset() { - t.hmac.Reset() -} - -func (t truncatingMAC) Size() int { - return t.length -} - -func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } - -var macModes = map[string]*macMode{ - "hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { - return hmac.New(sha256.New, key) - }}, - "hmac-sha2-256": {32, false, func(key []byte) hash.Hash { - return hmac.New(sha256.New, key) - }}, - "hmac-sha1": {20, false, func(key []byte) hash.Hash { - return hmac.New(sha1.New, key) - }}, - "hmac-sha1-96": {20, false, func(key []byte) hash.Hash { - return truncatingMAC{12, hmac.New(sha1.New, key)} - }}, -} diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go deleted file mode 100644 index 19bc67c4..00000000 --- a/vendor/golang.org/x/crypto/ssh/messages.go +++ /dev/null @@ -1,877 +0,0 @@ -// 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 ssh - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "math/big" - "reflect" - "strconv" - "strings" -) - -// These are SSH message type numbers. They are scattered around several -// documents but many were taken from [SSH-PARAMETERS]. -const ( - msgIgnore = 2 - msgUnimplemented = 3 - msgDebug = 4 - msgNewKeys = 21 -) - -// SSH messages: -// -// These structures mirror the wire format of the corresponding SSH messages. -// They are marshaled using reflection with the marshal and unmarshal functions -// in this file. The only wrinkle is that a final member of type []byte with a -// ssh tag of "rest" receives the remainder of a packet when unmarshaling. - -// See RFC 4253, section 11.1. -const msgDisconnect = 1 - -// disconnectMsg is the message that signals a disconnect. It is also -// the error type returned from mux.Wait() -type disconnectMsg struct { - Reason uint32 `sshtype:"1"` - Message string - Language string -} - -func (d *disconnectMsg) Error() string { - return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message) -} - -// See RFC 4253, section 7.1. -const msgKexInit = 20 - -type kexInitMsg struct { - Cookie [16]byte `sshtype:"20"` - KexAlgos []string - ServerHostKeyAlgos []string - CiphersClientServer []string - CiphersServerClient []string - MACsClientServer []string - MACsServerClient []string - CompressionClientServer []string - CompressionServerClient []string - LanguagesClientServer []string - LanguagesServerClient []string - FirstKexFollows bool - Reserved uint32 -} - -// See RFC 4253, section 8. - -// Diffie-Helman -const msgKexDHInit = 30 - -type kexDHInitMsg struct { - X *big.Int `sshtype:"30"` -} - -const msgKexECDHInit = 30 - -type kexECDHInitMsg struct { - ClientPubKey []byte `sshtype:"30"` -} - -const msgKexECDHReply = 31 - -type kexECDHReplyMsg struct { - HostKey []byte `sshtype:"31"` - EphemeralPubKey []byte - Signature []byte -} - -const msgKexDHReply = 31 - -type kexDHReplyMsg struct { - HostKey []byte `sshtype:"31"` - Y *big.Int - Signature []byte -} - -// See RFC 4419, section 5. -const msgKexDHGexGroup = 31 - -type kexDHGexGroupMsg struct { - P *big.Int `sshtype:"31"` - G *big.Int -} - -const msgKexDHGexInit = 32 - -type kexDHGexInitMsg struct { - X *big.Int `sshtype:"32"` -} - -const msgKexDHGexReply = 33 - -type kexDHGexReplyMsg struct { - HostKey []byte `sshtype:"33"` - Y *big.Int - Signature []byte -} - -const msgKexDHGexRequest = 34 - -type kexDHGexRequestMsg struct { - MinBits uint32 `sshtype:"34"` - PreferedBits uint32 - MaxBits uint32 -} - -// See RFC 4253, section 10. -const msgServiceRequest = 5 - -type serviceRequestMsg struct { - Service string `sshtype:"5"` -} - -// See RFC 4253, section 10. -const msgServiceAccept = 6 - -type serviceAcceptMsg struct { - Service string `sshtype:"6"` -} - -// See RFC 8308, section 2.3 -const msgExtInfo = 7 - -type extInfoMsg struct { - NumExtensions uint32 `sshtype:"7"` - Payload []byte `ssh:"rest"` -} - -// See RFC 4252, section 5. -const msgUserAuthRequest = 50 - -type userAuthRequestMsg struct { - User string `sshtype:"50"` - Service string - Method string - Payload []byte `ssh:"rest"` -} - -// Used for debug printouts of packets. -type userAuthSuccessMsg struct { -} - -// See RFC 4252, section 5.1 -const msgUserAuthFailure = 51 - -type userAuthFailureMsg struct { - Methods []string `sshtype:"51"` - PartialSuccess bool -} - -// See RFC 4252, section 5.1 -const msgUserAuthSuccess = 52 - -// See RFC 4252, section 5.4 -const msgUserAuthBanner = 53 - -type userAuthBannerMsg struct { - Message string `sshtype:"53"` - // unused, but required to allow message parsing - Language string -} - -// See RFC 4256, section 3.2 -const msgUserAuthInfoRequest = 60 -const msgUserAuthInfoResponse = 61 - -type userAuthInfoRequestMsg struct { - Name string `sshtype:"60"` - Instruction string - Language string - NumPrompts uint32 - Prompts []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.1. -const msgChannelOpen = 90 - -type channelOpenMsg struct { - ChanType string `sshtype:"90"` - PeersID uint32 - PeersWindow uint32 - MaxPacketSize uint32 - TypeSpecificData []byte `ssh:"rest"` -} - -const msgChannelExtendedData = 95 -const msgChannelData = 94 - -// Used for debug print outs of packets. -type channelDataMsg struct { - PeersID uint32 `sshtype:"94"` - Length uint32 - Rest []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.1. -const msgChannelOpenConfirm = 91 - -type channelOpenConfirmMsg struct { - PeersID uint32 `sshtype:"91"` - MyID uint32 - MyWindow uint32 - MaxPacketSize uint32 - TypeSpecificData []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.1. -const msgChannelOpenFailure = 92 - -type channelOpenFailureMsg struct { - PeersID uint32 `sshtype:"92"` - Reason RejectionReason - Message string - Language string -} - -const msgChannelRequest = 98 - -type channelRequestMsg struct { - PeersID uint32 `sshtype:"98"` - Request string - WantReply bool - RequestSpecificData []byte `ssh:"rest"` -} - -// See RFC 4254, section 5.4. -const msgChannelSuccess = 99 - -type channelRequestSuccessMsg struct { - PeersID uint32 `sshtype:"99"` -} - -// See RFC 4254, section 5.4. -const msgChannelFailure = 100 - -type channelRequestFailureMsg struct { - PeersID uint32 `sshtype:"100"` -} - -// See RFC 4254, section 5.3 -const msgChannelClose = 97 - -type channelCloseMsg struct { - PeersID uint32 `sshtype:"97"` -} - -// See RFC 4254, section 5.3 -const msgChannelEOF = 96 - -type channelEOFMsg struct { - PeersID uint32 `sshtype:"96"` -} - -// See RFC 4254, section 4 -const msgGlobalRequest = 80 - -type globalRequestMsg struct { - Type string `sshtype:"80"` - WantReply bool - Data []byte `ssh:"rest"` -} - -// See RFC 4254, section 4 -const msgRequestSuccess = 81 - -type globalRequestSuccessMsg struct { - Data []byte `ssh:"rest" sshtype:"81"` -} - -// See RFC 4254, section 4 -const msgRequestFailure = 82 - -type globalRequestFailureMsg struct { - Data []byte `ssh:"rest" sshtype:"82"` -} - -// See RFC 4254, section 5.2 -const msgChannelWindowAdjust = 93 - -type windowAdjustMsg struct { - PeersID uint32 `sshtype:"93"` - AdditionalBytes uint32 -} - -// See RFC 4252, section 7 -const msgUserAuthPubKeyOk = 60 - -type userAuthPubKeyOkMsg struct { - Algo string `sshtype:"60"` - PubKey []byte -} - -// See RFC 4462, section 3 -const msgUserAuthGSSAPIResponse = 60 - -type userAuthGSSAPIResponse struct { - SupportMech []byte `sshtype:"60"` -} - -const msgUserAuthGSSAPIToken = 61 - -type userAuthGSSAPIToken struct { - Token []byte `sshtype:"61"` -} - -const msgUserAuthGSSAPIMIC = 66 - -type userAuthGSSAPIMIC struct { - MIC []byte `sshtype:"66"` -} - -// See RFC 4462, section 3.9 -const msgUserAuthGSSAPIErrTok = 64 - -type userAuthGSSAPIErrTok struct { - ErrorToken []byte `sshtype:"64"` -} - -// See RFC 4462, section 3.8 -const msgUserAuthGSSAPIError = 65 - -type userAuthGSSAPIError struct { - MajorStatus uint32 `sshtype:"65"` - MinorStatus uint32 - Message string - LanguageTag string -} - -// typeTags returns the possible type bytes for the given reflect.Type, which -// should be a struct. The possible values are separated by a '|' character. -func typeTags(structType reflect.Type) (tags []byte) { - tagStr := structType.Field(0).Tag.Get("sshtype") - - for _, tag := range strings.Split(tagStr, "|") { - i, err := strconv.Atoi(tag) - if err == nil { - tags = append(tags, byte(i)) - } - } - - return tags -} - -func fieldError(t reflect.Type, field int, problem string) error { - if problem != "" { - problem = ": " + problem - } - return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem) -} - -var errShortRead = errors.New("ssh: short read") - -// Unmarshal parses data in SSH wire format into a structure. The out -// argument should be a pointer to struct. If the first member of the -// struct has the "sshtype" tag set to a '|'-separated set of numbers -// in decimal, the packet must start with one of those numbers. In -// case of error, Unmarshal returns a ParseError or -// UnexpectedMessageError. -func Unmarshal(data []byte, out interface{}) error { - v := reflect.ValueOf(out).Elem() - structType := v.Type() - expectedTypes := typeTags(structType) - - var expectedType byte - if len(expectedTypes) > 0 { - expectedType = expectedTypes[0] - } - - if len(data) == 0 { - return parseError(expectedType) - } - - if len(expectedTypes) > 0 { - goodType := false - for _, e := range expectedTypes { - if e > 0 && data[0] == e { - goodType = true - break - } - } - if !goodType { - return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes) - } - data = data[1:] - } - - var ok bool - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - t := field.Type() - switch t.Kind() { - case reflect.Bool: - if len(data) < 1 { - return errShortRead - } - field.SetBool(data[0] != 0) - data = data[1:] - case reflect.Array: - if t.Elem().Kind() != reflect.Uint8 { - return fieldError(structType, i, "array of unsupported type") - } - if len(data) < t.Len() { - return errShortRead - } - for j, n := 0, t.Len(); j < n; j++ { - field.Index(j).Set(reflect.ValueOf(data[j])) - } - data = data[t.Len():] - case reflect.Uint64: - var u64 uint64 - if u64, data, ok = parseUint64(data); !ok { - return errShortRead - } - field.SetUint(u64) - case reflect.Uint32: - var u32 uint32 - if u32, data, ok = parseUint32(data); !ok { - return errShortRead - } - field.SetUint(uint64(u32)) - case reflect.Uint8: - if len(data) < 1 { - return errShortRead - } - field.SetUint(uint64(data[0])) - data = data[1:] - case reflect.String: - var s []byte - if s, data, ok = parseString(data); !ok { - return fieldError(structType, i, "") - } - field.SetString(string(s)) - case reflect.Slice: - switch t.Elem().Kind() { - case reflect.Uint8: - if structType.Field(i).Tag.Get("ssh") == "rest" { - field.Set(reflect.ValueOf(data)) - data = nil - } else { - var s []byte - if s, data, ok = parseString(data); !ok { - return errShortRead - } - field.Set(reflect.ValueOf(s)) - } - case reflect.String: - var nl []string - if nl, data, ok = parseNameList(data); !ok { - return errShortRead - } - field.Set(reflect.ValueOf(nl)) - default: - return fieldError(structType, i, "slice of unsupported type") - } - case reflect.Ptr: - if t == bigIntType { - var n *big.Int - if n, data, ok = parseInt(data); !ok { - return errShortRead - } - field.Set(reflect.ValueOf(n)) - } else { - return fieldError(structType, i, "pointer to unsupported type") - } - default: - return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t)) - } - } - - if len(data) != 0 { - return parseError(expectedType) - } - - return nil -} - -// Marshal serializes the message in msg to SSH wire format. The msg -// argument should be a struct or pointer to struct. If the first -// member has the "sshtype" tag set to a number in decimal, that -// number is prepended to the result. If the last of member has the -// "ssh" tag set to "rest", its contents are appended to the output. -func Marshal(msg interface{}) []byte { - out := make([]byte, 0, 64) - return marshalStruct(out, msg) -} - -func marshalStruct(out []byte, msg interface{}) []byte { - v := reflect.Indirect(reflect.ValueOf(msg)) - msgTypes := typeTags(v.Type()) - if len(msgTypes) > 0 { - out = append(out, msgTypes[0]) - } - - for i, n := 0, v.NumField(); i < n; i++ { - field := v.Field(i) - switch t := field.Type(); t.Kind() { - case reflect.Bool: - var v uint8 - if field.Bool() { - v = 1 - } - out = append(out, v) - case reflect.Array: - if t.Elem().Kind() != reflect.Uint8 { - panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface())) - } - for j, l := 0, t.Len(); j < l; j++ { - out = append(out, uint8(field.Index(j).Uint())) - } - case reflect.Uint32: - out = appendU32(out, uint32(field.Uint())) - case reflect.Uint64: - out = appendU64(out, uint64(field.Uint())) - case reflect.Uint8: - out = append(out, uint8(field.Uint())) - case reflect.String: - s := field.String() - out = appendInt(out, len(s)) - out = append(out, s...) - case reflect.Slice: - switch t.Elem().Kind() { - case reflect.Uint8: - if v.Type().Field(i).Tag.Get("ssh") != "rest" { - out = appendInt(out, field.Len()) - } - out = append(out, field.Bytes()...) - case reflect.String: - offset := len(out) - out = appendU32(out, 0) - if n := field.Len(); n > 0 { - for j := 0; j < n; j++ { - f := field.Index(j) - if j != 0 { - out = append(out, ',') - } - out = append(out, f.String()...) - } - // overwrite length value - binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4)) - } - default: - panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface())) - } - case reflect.Ptr: - if t == bigIntType { - var n *big.Int - nValue := reflect.ValueOf(&n) - nValue.Elem().Set(field) - needed := intLength(n) - oldLength := len(out) - - if cap(out)-len(out) < needed { - newOut := make([]byte, len(out), 2*(len(out)+needed)) - copy(newOut, out) - out = newOut - } - out = out[:oldLength+needed] - marshalInt(out[oldLength:], n) - } else { - panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface())) - } - } - } - - return out -} - -var bigOne = big.NewInt(1) - -func parseString(in []byte) (out, rest []byte, ok bool) { - if len(in) < 4 { - return - } - length := binary.BigEndian.Uint32(in) - in = in[4:] - if uint32(len(in)) < length { - return - } - out = in[:length] - rest = in[length:] - ok = true - return -} - -var ( - comma = []byte{','} - emptyNameList = []string{} -) - -func parseNameList(in []byte) (out []string, rest []byte, ok bool) { - contents, rest, ok := parseString(in) - if !ok { - return - } - if len(contents) == 0 { - out = emptyNameList - return - } - parts := bytes.Split(contents, comma) - out = make([]string, len(parts)) - for i, part := range parts { - out[i] = string(part) - } - return -} - -func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { - contents, rest, ok := parseString(in) - if !ok { - return - } - out = new(big.Int) - - if len(contents) > 0 && contents[0]&0x80 == 0x80 { - // This is a negative number - notBytes := make([]byte, len(contents)) - for i := range notBytes { - notBytes[i] = ^contents[i] - } - out.SetBytes(notBytes) - out.Add(out, bigOne) - out.Neg(out) - } else { - // Positive number - out.SetBytes(contents) - } - ok = true - return -} - -func parseUint32(in []byte) (uint32, []byte, bool) { - if len(in) < 4 { - return 0, nil, false - } - return binary.BigEndian.Uint32(in), in[4:], true -} - -func parseUint64(in []byte) (uint64, []byte, bool) { - if len(in) < 8 { - return 0, nil, false - } - return binary.BigEndian.Uint64(in), in[8:], true -} - -func intLength(n *big.Int) int { - length := 4 /* length bytes */ - if n.Sign() < 0 { - nMinus1 := new(big.Int).Neg(n) - nMinus1.Sub(nMinus1, bigOne) - bitLen := nMinus1.BitLen() - if bitLen%8 == 0 { - // The number will need 0xff padding - length++ - } - length += (bitLen + 7) / 8 - } else if n.Sign() == 0 { - // A zero is the zero length string - } else { - bitLen := n.BitLen() - if bitLen%8 == 0 { - // The number will need 0x00 padding - length++ - } - length += (bitLen + 7) / 8 - } - - return length -} - -func marshalUint32(to []byte, n uint32) []byte { - binary.BigEndian.PutUint32(to, n) - return to[4:] -} - -func marshalUint64(to []byte, n uint64) []byte { - binary.BigEndian.PutUint64(to, n) - return to[8:] -} - -func marshalInt(to []byte, n *big.Int) []byte { - lengthBytes := to - to = to[4:] - length := 0 - - if n.Sign() < 0 { - // A negative number has to be converted to two's-complement - // form. So we'll subtract 1 and invert. If the - // most-significant-bit isn't set then we'll need to pad the - // beginning with 0xff in order to keep the number negative. - nMinus1 := new(big.Int).Neg(n) - nMinus1.Sub(nMinus1, bigOne) - bytes := nMinus1.Bytes() - for i := range bytes { - bytes[i] ^= 0xff - } - if len(bytes) == 0 || bytes[0]&0x80 == 0 { - to[0] = 0xff - to = to[1:] - length++ - } - nBytes := copy(to, bytes) - to = to[nBytes:] - length += nBytes - } else if n.Sign() == 0 { - // A zero is the zero length string - } else { - bytes := n.Bytes() - if len(bytes) > 0 && bytes[0]&0x80 != 0 { - // We'll have to pad this with a 0x00 in order to - // stop it looking like a negative number. - to[0] = 0 - to = to[1:] - length++ - } - nBytes := copy(to, bytes) - to = to[nBytes:] - length += nBytes - } - - lengthBytes[0] = byte(length >> 24) - lengthBytes[1] = byte(length >> 16) - lengthBytes[2] = byte(length >> 8) - lengthBytes[3] = byte(length) - return to -} - -func writeInt(w io.Writer, n *big.Int) { - length := intLength(n) - buf := make([]byte, length) - marshalInt(buf, n) - w.Write(buf) -} - -func writeString(w io.Writer, s []byte) { - var lengthBytes [4]byte - lengthBytes[0] = byte(len(s) >> 24) - lengthBytes[1] = byte(len(s) >> 16) - lengthBytes[2] = byte(len(s) >> 8) - lengthBytes[3] = byte(len(s)) - w.Write(lengthBytes[:]) - w.Write(s) -} - -func stringLength(n int) int { - return 4 + n -} - -func marshalString(to []byte, s []byte) []byte { - to[0] = byte(len(s) >> 24) - to[1] = byte(len(s) >> 16) - to[2] = byte(len(s) >> 8) - to[3] = byte(len(s)) - to = to[4:] - copy(to, s) - return to[len(s):] -} - -var bigIntType = reflect.TypeOf((*big.Int)(nil)) - -// Decode a packet into its corresponding message. -func decode(packet []byte) (interface{}, error) { - var msg interface{} - switch packet[0] { - case msgDisconnect: - msg = new(disconnectMsg) - case msgServiceRequest: - msg = new(serviceRequestMsg) - case msgServiceAccept: - msg = new(serviceAcceptMsg) - case msgExtInfo: - msg = new(extInfoMsg) - case msgKexInit: - msg = new(kexInitMsg) - case msgKexDHInit: - msg = new(kexDHInitMsg) - case msgKexDHReply: - msg = new(kexDHReplyMsg) - case msgUserAuthRequest: - msg = new(userAuthRequestMsg) - case msgUserAuthSuccess: - return new(userAuthSuccessMsg), nil - case msgUserAuthFailure: - msg = new(userAuthFailureMsg) - case msgUserAuthPubKeyOk: - msg = new(userAuthPubKeyOkMsg) - case msgGlobalRequest: - msg = new(globalRequestMsg) - case msgRequestSuccess: - msg = new(globalRequestSuccessMsg) - case msgRequestFailure: - msg = new(globalRequestFailureMsg) - case msgChannelOpen: - msg = new(channelOpenMsg) - case msgChannelData: - msg = new(channelDataMsg) - case msgChannelOpenConfirm: - msg = new(channelOpenConfirmMsg) - case msgChannelOpenFailure: - msg = new(channelOpenFailureMsg) - case msgChannelWindowAdjust: - msg = new(windowAdjustMsg) - case msgChannelEOF: - msg = new(channelEOFMsg) - case msgChannelClose: - msg = new(channelCloseMsg) - case msgChannelRequest: - msg = new(channelRequestMsg) - case msgChannelSuccess: - msg = new(channelRequestSuccessMsg) - case msgChannelFailure: - msg = new(channelRequestFailureMsg) - case msgUserAuthGSSAPIToken: - msg = new(userAuthGSSAPIToken) - case msgUserAuthGSSAPIMIC: - msg = new(userAuthGSSAPIMIC) - case msgUserAuthGSSAPIErrTok: - msg = new(userAuthGSSAPIErrTok) - case msgUserAuthGSSAPIError: - msg = new(userAuthGSSAPIError) - default: - return nil, unexpectedMessageError(0, packet[0]) - } - if err := Unmarshal(packet, msg); err != nil { - return nil, err - } - return msg, nil -} - -var packetTypeNames = map[byte]string{ - msgDisconnect: "disconnectMsg", - msgServiceRequest: "serviceRequestMsg", - msgServiceAccept: "serviceAcceptMsg", - msgExtInfo: "extInfoMsg", - msgKexInit: "kexInitMsg", - msgKexDHInit: "kexDHInitMsg", - msgKexDHReply: "kexDHReplyMsg", - msgUserAuthRequest: "userAuthRequestMsg", - msgUserAuthSuccess: "userAuthSuccessMsg", - msgUserAuthFailure: "userAuthFailureMsg", - msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg", - msgGlobalRequest: "globalRequestMsg", - msgRequestSuccess: "globalRequestSuccessMsg", - msgRequestFailure: "globalRequestFailureMsg", - msgChannelOpen: "channelOpenMsg", - msgChannelData: "channelDataMsg", - msgChannelOpenConfirm: "channelOpenConfirmMsg", - msgChannelOpenFailure: "channelOpenFailureMsg", - msgChannelWindowAdjust: "windowAdjustMsg", - msgChannelEOF: "channelEOFMsg", - msgChannelClose: "channelCloseMsg", - msgChannelRequest: "channelRequestMsg", - msgChannelSuccess: "channelRequestSuccessMsg", - msgChannelFailure: "channelRequestFailureMsg", -} diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go deleted file mode 100644 index 9654c018..00000000 --- a/vendor/golang.org/x/crypto/ssh/mux.go +++ /dev/null @@ -1,351 +0,0 @@ -// 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 ssh - -import ( - "encoding/binary" - "fmt" - "io" - "log" - "sync" - "sync/atomic" -) - -// debugMux, if set, causes messages in the connection protocol to be -// logged. -const debugMux = false - -// chanList is a thread safe channel list. -type chanList struct { - // protects concurrent access to chans - sync.Mutex - - // chans are indexed by the local id of the channel, which the - // other side should send in the PeersId field. - chans []*channel - - // This is a debugging aid: it offsets all IDs by this - // amount. This helps distinguish otherwise identical - // server/client muxes - offset uint32 -} - -// Assigns a channel ID to the given channel. -func (c *chanList) add(ch *channel) uint32 { - c.Lock() - defer c.Unlock() - for i := range c.chans { - if c.chans[i] == nil { - c.chans[i] = ch - return uint32(i) + c.offset - } - } - c.chans = append(c.chans, ch) - return uint32(len(c.chans)-1) + c.offset -} - -// getChan returns the channel for the given ID. -func (c *chanList) getChan(id uint32) *channel { - id -= c.offset - - c.Lock() - defer c.Unlock() - if id < uint32(len(c.chans)) { - return c.chans[id] - } - return nil -} - -func (c *chanList) remove(id uint32) { - id -= c.offset - c.Lock() - if id < uint32(len(c.chans)) { - c.chans[id] = nil - } - c.Unlock() -} - -// dropAll forgets all channels it knows, returning them in a slice. -func (c *chanList) dropAll() []*channel { - c.Lock() - defer c.Unlock() - var r []*channel - - for _, ch := range c.chans { - if ch == nil { - continue - } - r = append(r, ch) - } - c.chans = nil - return r -} - -// mux represents the state for the SSH connection protocol, which -// multiplexes many channels onto a single packet transport. -type mux struct { - conn packetConn - chanList chanList - - incomingChannels chan NewChannel - - globalSentMu sync.Mutex - globalResponses chan interface{} - incomingRequests chan *Request - - errCond *sync.Cond - err error -} - -// When debugging, each new chanList instantiation has a different -// offset. -var globalOff uint32 - -func (m *mux) Wait() error { - m.errCond.L.Lock() - defer m.errCond.L.Unlock() - for m.err == nil { - m.errCond.Wait() - } - return m.err -} - -// newMux returns a mux that runs over the given connection. -func newMux(p packetConn) *mux { - m := &mux{ - conn: p, - incomingChannels: make(chan NewChannel, chanSize), - globalResponses: make(chan interface{}, 1), - incomingRequests: make(chan *Request, chanSize), - errCond: newCond(), - } - if debugMux { - m.chanList.offset = atomic.AddUint32(&globalOff, 1) - } - - go m.loop() - return m -} - -func (m *mux) sendMessage(msg interface{}) error { - p := Marshal(msg) - if debugMux { - log.Printf("send global(%d): %#v", m.chanList.offset, msg) - } - return m.conn.writePacket(p) -} - -func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { - if wantReply { - m.globalSentMu.Lock() - defer m.globalSentMu.Unlock() - } - - if err := m.sendMessage(globalRequestMsg{ - Type: name, - WantReply: wantReply, - Data: payload, - }); err != nil { - return false, nil, err - } - - if !wantReply { - return false, nil, nil - } - - msg, ok := <-m.globalResponses - if !ok { - return false, nil, io.EOF - } - switch msg := msg.(type) { - case *globalRequestFailureMsg: - return false, msg.Data, nil - case *globalRequestSuccessMsg: - return true, msg.Data, nil - default: - return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) - } -} - -// ackRequest must be called after processing a global request that -// has WantReply set. -func (m *mux) ackRequest(ok bool, data []byte) error { - if ok { - return m.sendMessage(globalRequestSuccessMsg{Data: data}) - } - return m.sendMessage(globalRequestFailureMsg{Data: data}) -} - -func (m *mux) Close() error { - return m.conn.Close() -} - -// loop runs the connection machine. It will process packets until an -// error is encountered. To synchronize on loop exit, use mux.Wait. -func (m *mux) loop() { - var err error - for err == nil { - err = m.onePacket() - } - - for _, ch := range m.chanList.dropAll() { - ch.close() - } - - close(m.incomingChannels) - close(m.incomingRequests) - close(m.globalResponses) - - m.conn.Close() - - m.errCond.L.Lock() - m.err = err - m.errCond.Broadcast() - m.errCond.L.Unlock() - - if debugMux { - log.Println("loop exit", err) - } -} - -// onePacket reads and processes one packet. -func (m *mux) onePacket() error { - packet, err := m.conn.readPacket() - if err != nil { - return err - } - - if debugMux { - if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { - log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) - } else { - p, _ := decode(packet) - log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) - } - } - - switch packet[0] { - case msgChannelOpen: - return m.handleChannelOpen(packet) - case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: - return m.handleGlobalPacket(packet) - } - - // assume a channel packet. - if len(packet) < 5 { - return parseError(packet[0]) - } - id := binary.BigEndian.Uint32(packet[1:]) - ch := m.chanList.getChan(id) - if ch == nil { - return m.handleUnknownChannelPacket(id, packet) - } - - return ch.handlePacket(packet) -} - -func (m *mux) handleGlobalPacket(packet []byte) error { - msg, err := decode(packet) - if err != nil { - return err - } - - switch msg := msg.(type) { - case *globalRequestMsg: - m.incomingRequests <- &Request{ - Type: msg.Type, - WantReply: msg.WantReply, - Payload: msg.Data, - mux: m, - } - case *globalRequestSuccessMsg, *globalRequestFailureMsg: - m.globalResponses <- msg - default: - panic(fmt.Sprintf("not a global message %#v", msg)) - } - - return nil -} - -// handleChannelOpen schedules a channel to be Accept()ed. -func (m *mux) handleChannelOpen(packet []byte) error { - var msg channelOpenMsg - if err := Unmarshal(packet, &msg); err != nil { - return err - } - - if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { - failMsg := channelOpenFailureMsg{ - PeersID: msg.PeersID, - Reason: ConnectionFailed, - Message: "invalid request", - Language: "en_US.UTF-8", - } - return m.sendMessage(failMsg) - } - - c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) - c.remoteId = msg.PeersID - c.maxRemotePayload = msg.MaxPacketSize - c.remoteWin.add(msg.PeersWindow) - m.incomingChannels <- c - return nil -} - -func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { - ch, err := m.openChannel(chanType, extra) - if err != nil { - return nil, nil, err - } - - return ch, ch.incomingRequests, nil -} - -func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { - ch := m.newChannel(chanType, channelOutbound, extra) - - ch.maxIncomingPayload = channelMaxPacket - - open := channelOpenMsg{ - ChanType: chanType, - PeersWindow: ch.myWindow, - MaxPacketSize: ch.maxIncomingPayload, - TypeSpecificData: extra, - PeersID: ch.localId, - } - if err := m.sendMessage(open); err != nil { - return nil, err - } - - switch msg := (<-ch.msg).(type) { - case *channelOpenConfirmMsg: - return ch, nil - case *channelOpenFailureMsg: - return nil, &OpenChannelError{msg.Reason, msg.Message} - default: - return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) - } -} - -func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) error { - msg, err := decode(packet) - if err != nil { - return err - } - - switch msg := msg.(type) { - // RFC 4254 section 5.4 says unrecognized channel requests should - // receive a failure response. - case *channelRequestMsg: - if msg.WantReply { - return m.sendMessage(channelRequestFailureMsg{ - PeersID: msg.PeersID, - }) - } - return nil - default: - return fmt.Errorf("ssh: invalid channel %d", id) - } -} diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go deleted file mode 100644 index 70045bdf..00000000 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ /dev/null @@ -1,752 +0,0 @@ -// 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 ssh - -import ( - "bytes" - "errors" - "fmt" - "io" - "net" - "strings" -) - -// The Permissions type holds fine-grained permissions that are -// specific to a user or a specific authentication method for a user. -// The Permissions value for a successful authentication attempt is -// available in ServerConn, so it can be used to pass information from -// the user-authentication phase to the application layer. -type Permissions struct { - // CriticalOptions indicate restrictions to the default - // permissions, and are typically used in conjunction with - // user certificates. The standard for SSH certificates - // defines "force-command" (only allow the given command to - // execute) and "source-address" (only allow connections from - // the given address). The SSH package currently only enforces - // the "source-address" critical option. It is up to server - // implementations to enforce other critical options, such as - // "force-command", by checking them after the SSH handshake - // is successful. In general, SSH servers should reject - // connections that specify critical options that are unknown - // or not supported. - CriticalOptions map[string]string - - // Extensions are extra functionality that the server may - // offer on authenticated connections. Lack of support for an - // extension does not preclude authenticating a user. Common - // extensions are "permit-agent-forwarding", - // "permit-X11-forwarding". The Go SSH library currently does - // not act on any extension, and it is up to server - // implementations to honor them. Extensions can be used to - // pass data from the authentication callbacks to the server - // application layer. - Extensions map[string]string -} - -type GSSAPIWithMICConfig struct { - // AllowLogin, must be set, is called when gssapi-with-mic - // authentication is selected (RFC 4462 section 3). The srcName is from the - // results of the GSS-API authentication. The format is username@DOMAIN. - // GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions. - // This callback is called after the user identity is established with GSSAPI to decide if the user can login with - // which permissions. If the user is allowed to login, it should return a nil error. - AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error) - - // Server must be set. It's the implementation - // of the GSSAPIServer interface. See GSSAPIServer interface for details. - Server GSSAPIServer -} - -// ServerConfig holds server specific configuration data. -type ServerConfig struct { - // Config contains configuration shared between client and server. - Config - - hostKeys []Signer - - // NoClientAuth is true if clients are allowed to connect without - // authenticating. - NoClientAuth bool - - // MaxAuthTries specifies the maximum number of authentication attempts - // permitted per connection. If set to a negative number, the number of - // attempts are unlimited. If set to zero, the number of attempts are limited - // to 6. - MaxAuthTries int - - // PasswordCallback, if non-nil, is called when a user - // attempts to authenticate using a password. - PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) - - // PublicKeyCallback, if non-nil, is called when a client - // offers a public key for authentication. It must return a nil error - // if the given public key can be used to authenticate the - // given user. For example, see CertChecker.Authenticate. A - // call to this function does not guarantee that the key - // offered is in fact used to authenticate. To record any data - // depending on the public key, store it inside a - // Permissions.Extensions entry. - PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) - - // KeyboardInteractiveCallback, if non-nil, is called when - // keyboard-interactive authentication is selected (RFC - // 4256). The client object's Challenge function should be - // used to query the user. The callback may offer multiple - // Challenge rounds. To avoid information leaks, the client - // should be presented a challenge even if the user is - // unknown. - KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) - - // AuthLogCallback, if non-nil, is called to log all authentication - // attempts. - AuthLogCallback func(conn ConnMetadata, method string, err error) - - // ServerVersion is the version identification string to announce in - // the public handshake. - // If empty, a reasonable default is used. - // Note that RFC 4253 section 4.2 requires that this string start with - // "SSH-2.0-". - ServerVersion string - - // BannerCallback, if present, is called and the return string is sent to - // the client after key exchange completed but before authentication. - BannerCallback func(conn ConnMetadata) string - - // GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used - // when gssapi-with-mic authentication is selected (RFC 4462 section 3). - GSSAPIWithMICConfig *GSSAPIWithMICConfig -} - -// AddHostKey adds a private key as a host key. If an existing host -// key exists with the same public key format, it is replaced. Each server -// config must have at least one host key. -func (s *ServerConfig) AddHostKey(key Signer) { - for i, k := range s.hostKeys { - if k.PublicKey().Type() == key.PublicKey().Type() { - s.hostKeys[i] = key - return - } - } - - s.hostKeys = append(s.hostKeys, key) -} - -// cachedPubKey contains the results of querying whether a public key is -// acceptable for a user. -type cachedPubKey struct { - user string - pubKeyData []byte - result error - perms *Permissions -} - -const maxCachedPubKeys = 16 - -// pubKeyCache caches tests for public keys. Since SSH clients -// will query whether a public key is acceptable before attempting to -// authenticate with it, we end up with duplicate queries for public -// key validity. The cache only applies to a single ServerConn. -type pubKeyCache struct { - keys []cachedPubKey -} - -// get returns the result for a given user/algo/key tuple. -func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { - for _, k := range c.keys { - if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { - return k, true - } - } - return cachedPubKey{}, false -} - -// add adds the given tuple to the cache. -func (c *pubKeyCache) add(candidate cachedPubKey) { - if len(c.keys) < maxCachedPubKeys { - c.keys = append(c.keys, candidate) - } -} - -// ServerConn is an authenticated SSH connection, as seen from the -// server -type ServerConn struct { - Conn - - // If the succeeding authentication callback returned a - // non-nil Permissions pointer, it is stored here. - Permissions *Permissions -} - -// NewServerConn starts a new SSH server with c as the underlying -// transport. It starts with a handshake and, if the handshake is -// unsuccessful, it closes the connection and returns an error. The -// Request and NewChannel channels must be serviced, or the connection -// will hang. -// -// The returned error may be of type *ServerAuthError for -// authentication errors. -func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { - fullConf := *config - fullConf.SetDefaults() - if fullConf.MaxAuthTries == 0 { - fullConf.MaxAuthTries = 6 - } - // Check if the config contains any unsupported key exchanges - for _, kex := range fullConf.KeyExchanges { - if _, ok := serverForbiddenKexAlgos[kex]; ok { - return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex) - } - } - - s := &connection{ - sshConn: sshConn{conn: c}, - } - perms, err := s.serverHandshake(&fullConf) - if err != nil { - c.Close() - return nil, nil, nil, err - } - return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil -} - -// signAndMarshal signs the data with the appropriate algorithm, -// and serializes the result in SSH wire format. algo is the negotiate -// algorithm and may be a certificate type. -func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) { - sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo)) - if err != nil { - return nil, err - } - - return Marshal(sig), nil -} - -// handshake performs key exchange and user authentication. -func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { - if len(config.hostKeys) == 0 { - return nil, errors.New("ssh: server has no host keys") - } - - if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && - config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil || - config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) { - return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") - } - - if config.ServerVersion != "" { - s.serverVersion = []byte(config.ServerVersion) - } else { - s.serverVersion = []byte(packageVersion) - } - var err error - s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) - if err != nil { - return nil, err - } - - tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) - s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) - - if err := s.transport.waitSession(); err != nil { - return nil, err - } - - // We just did the key change, so the session ID is established. - s.sessionID = s.transport.getSessionID() - - var packet []byte - if packet, err = s.transport.readPacket(); err != nil { - return nil, err - } - - var serviceRequest serviceRequestMsg - if err = Unmarshal(packet, &serviceRequest); err != nil { - return nil, err - } - if serviceRequest.Service != serviceUserAuth { - return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") - } - serviceAccept := serviceAcceptMsg{ - Service: serviceUserAuth, - } - if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { - return nil, err - } - - perms, err := s.serverAuthenticate(config) - if err != nil { - return nil, err - } - s.mux = newMux(s.transport) - return perms, err -} - -func isAcceptableAlgo(algo string) bool { - switch algo { - case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519, - CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: - return true - } - return false -} - -func checkSourceAddress(addr net.Addr, sourceAddrs string) error { - if addr == nil { - return errors.New("ssh: no address known for client, but source-address match required") - } - - tcpAddr, ok := addr.(*net.TCPAddr) - if !ok { - return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) - } - - for _, sourceAddr := range strings.Split(sourceAddrs, ",") { - if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { - if allowedIP.Equal(tcpAddr.IP) { - return nil - } - } else { - _, ipNet, err := net.ParseCIDR(sourceAddr) - if err != nil { - return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) - } - - if ipNet.Contains(tcpAddr.IP) { - return nil - } - } - } - - return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) -} - -func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection, - sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) { - gssAPIServer := gssapiConfig.Server - defer gssAPIServer.DeleteSecContext() - var srcName string - for { - var ( - outToken []byte - needContinue bool - ) - outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken) - if err != nil { - return err, nil, nil - } - if len(outToken) != 0 { - if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{ - Token: outToken, - })); err != nil { - return nil, nil, err - } - } - if !needContinue { - break - } - packet, err := s.transport.readPacket() - if err != nil { - return nil, nil, err - } - userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} - if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { - return nil, nil, err - } - } - packet, err := s.transport.readPacket() - if err != nil { - return nil, nil, err - } - userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{} - if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil { - return nil, nil, err - } - mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method) - if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil { - return err, nil, nil - } - perms, authErr = gssapiConfig.AllowLogin(s, srcName) - return authErr, perms, nil -} - -// ServerAuthError represents server authentication errors and is -// sometimes returned by NewServerConn. It appends any authentication -// errors that may occur, and is returned if all of the authentication -// methods provided by the user failed to authenticate. -type ServerAuthError struct { - // Errors contains authentication errors returned by the authentication - // callback methods. The first entry is typically ErrNoAuth. - Errors []error -} - -func (l ServerAuthError) Error() string { - var errs []string - for _, err := range l.Errors { - errs = append(errs, err.Error()) - } - return "[" + strings.Join(errs, ", ") + "]" -} - -// ErrNoAuth is the error value returned if no -// authentication method has been passed yet. This happens as a normal -// part of the authentication loop, since the client first tries -// 'none' authentication to discover available methods. -// It is returned in ServerAuthError.Errors from NewServerConn. -var ErrNoAuth = errors.New("ssh: no auth passed yet") - -func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { - sessionID := s.transport.getSessionID() - var cache pubKeyCache - var perms *Permissions - - authFailures := 0 - var authErrs []error - var displayedBanner bool - -userAuthLoop: - for { - if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { - discMsg := &disconnectMsg{ - Reason: 2, - Message: "too many authentication failures", - } - - if err := s.transport.writePacket(Marshal(discMsg)); err != nil { - return nil, err - } - - return nil, discMsg - } - - var userAuthReq userAuthRequestMsg - if packet, err := s.transport.readPacket(); err != nil { - if err == io.EOF { - return nil, &ServerAuthError{Errors: authErrs} - } - return nil, err - } else if err = Unmarshal(packet, &userAuthReq); err != nil { - return nil, err - } - - if userAuthReq.Service != serviceSSH { - return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) - } - - s.user = userAuthReq.User - - if !displayedBanner && config.BannerCallback != nil { - displayedBanner = true - msg := config.BannerCallback(s) - if msg != "" { - bannerMsg := &userAuthBannerMsg{ - Message: msg, - } - if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil { - return nil, err - } - } - } - - perms = nil - authErr := ErrNoAuth - - switch userAuthReq.Method { - case "none": - if config.NoClientAuth { - authErr = nil - } - - // allow initial attempt of 'none' without penalty - if authFailures == 0 { - authFailures-- - } - case "password": - if config.PasswordCallback == nil { - authErr = errors.New("ssh: password auth not configured") - break - } - payload := userAuthReq.Payload - if len(payload) < 1 || payload[0] != 0 { - return nil, parseError(msgUserAuthRequest) - } - payload = payload[1:] - password, payload, ok := parseString(payload) - if !ok || len(payload) > 0 { - return nil, parseError(msgUserAuthRequest) - } - - perms, authErr = config.PasswordCallback(s, password) - case "keyboard-interactive": - if config.KeyboardInteractiveCallback == nil { - authErr = errors.New("ssh: keyboard-interactive auth not configured") - break - } - - prompter := &sshClientKeyboardInteractive{s} - perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) - case "publickey": - if config.PublicKeyCallback == nil { - authErr = errors.New("ssh: publickey auth not configured") - break - } - payload := userAuthReq.Payload - if len(payload) < 1 { - return nil, parseError(msgUserAuthRequest) - } - isQuery := payload[0] == 0 - payload = payload[1:] - algoBytes, payload, ok := parseString(payload) - if !ok { - return nil, parseError(msgUserAuthRequest) - } - algo := string(algoBytes) - if !isAcceptableAlgo(algo) { - authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) - break - } - - pubKeyData, payload, ok := parseString(payload) - if !ok { - return nil, parseError(msgUserAuthRequest) - } - - pubKey, err := ParsePublicKey(pubKeyData) - if err != nil { - return nil, err - } - - candidate, ok := cache.get(s.user, pubKeyData) - if !ok { - candidate.user = s.user - candidate.pubKeyData = pubKeyData - candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) - if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { - candidate.result = checkSourceAddress( - s.RemoteAddr(), - candidate.perms.CriticalOptions[sourceAddressCriticalOption]) - } - cache.add(candidate) - } - - if isQuery { - // The client can query if the given public key - // would be okay. - - if len(payload) > 0 { - return nil, parseError(msgUserAuthRequest) - } - - if candidate.result == nil { - okMsg := userAuthPubKeyOkMsg{ - Algo: algo, - PubKey: pubKeyData, - } - if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { - return nil, err - } - continue userAuthLoop - } - authErr = candidate.result - } else { - sig, payload, ok := parseSignature(payload) - if !ok || len(payload) > 0 { - return nil, parseError(msgUserAuthRequest) - } - - // Ensure the public key algo and signature algo - // are supported. Compare the private key - // algorithm name that corresponds to algo with - // sig.Format. This is usually the same, but - // for certs, the names differ. - if !isAcceptableAlgo(sig.Format) { - authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) - break - } - if underlyingAlgo(algo) != sig.Format { - authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo) - break - } - - signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData) - - if err := pubKey.Verify(signedData, sig); err != nil { - return nil, err - } - - authErr = candidate.result - perms = candidate.perms - } - case "gssapi-with-mic": - if config.GSSAPIWithMICConfig == nil { - authErr = errors.New("ssh: gssapi-with-mic auth not configured") - break - } - gssapiConfig := config.GSSAPIWithMICConfig - userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload) - if err != nil { - return nil, parseError(msgUserAuthRequest) - } - // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication. - if userAuthRequestGSSAPI.N == 0 { - authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported") - break - } - var i uint32 - present := false - for i = 0; i < userAuthRequestGSSAPI.N; i++ { - if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) { - present = true - break - } - } - if !present { - authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism") - break - } - // Initial server response, see RFC 4462 section 3.3. - if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{ - SupportMech: krb5OID, - })); err != nil { - return nil, err - } - // Exchange token, see RFC 4462 section 3.4. - packet, err := s.transport.readPacket() - if err != nil { - return nil, err - } - userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} - if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { - return nil, err - } - authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID, - userAuthReq) - if err != nil { - return nil, err - } - default: - authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) - } - - authErrs = append(authErrs, authErr) - - if config.AuthLogCallback != nil { - config.AuthLogCallback(s, userAuthReq.Method, authErr) - } - - if authErr == nil { - break userAuthLoop - } - - authFailures++ - if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries { - // If we have hit the max attempts, don't bother sending the - // final SSH_MSG_USERAUTH_FAILURE message, since there are - // no more authentication methods which can be attempted, - // and this message may cause the client to re-attempt - // authentication while we send the disconnect message. - // Continue, and trigger the disconnect at the start of - // the loop. - // - // The SSH specification is somewhat confusing about this, - // RFC 4252 Section 5.1 requires each authentication failure - // be responded to with a respective SSH_MSG_USERAUTH_FAILURE - // message, but Section 4 says the server should disconnect - // after some number of attempts, but it isn't explicit which - // message should take precedence (i.e. should there be a failure - // message than a disconnect message, or if we are going to - // disconnect, should we only send that message.) - // - // Either way, OpenSSH disconnects immediately after the last - // failed authnetication attempt, and given they are typically - // considered the golden implementation it seems reasonable - // to match that behavior. - continue - } - - var failureMsg userAuthFailureMsg - if config.PasswordCallback != nil { - failureMsg.Methods = append(failureMsg.Methods, "password") - } - if config.PublicKeyCallback != nil { - failureMsg.Methods = append(failureMsg.Methods, "publickey") - } - if config.KeyboardInteractiveCallback != nil { - failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") - } - if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil && - config.GSSAPIWithMICConfig.AllowLogin != nil { - failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic") - } - - if len(failureMsg.Methods) == 0 { - return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") - } - - if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { - return nil, err - } - } - - if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { - return nil, err - } - return perms, nil -} - -// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by -// asking the client on the other side of a ServerConn. -type sshClientKeyboardInteractive struct { - *connection -} - -func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) { - if len(questions) != len(echos) { - return nil, errors.New("ssh: echos and questions must have equal length") - } - - var prompts []byte - for i := range questions { - prompts = appendString(prompts, questions[i]) - prompts = appendBool(prompts, echos[i]) - } - - if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ - Name: name, - Instruction: instruction, - NumPrompts: uint32(len(questions)), - Prompts: prompts, - })); err != nil { - return nil, err - } - - packet, err := c.transport.readPacket() - if err != nil { - return nil, err - } - if packet[0] != msgUserAuthInfoResponse { - return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) - } - packet = packet[1:] - - n, packet, ok := parseUint32(packet) - if !ok || int(n) != len(questions) { - return nil, parseError(msgUserAuthInfoResponse) - } - - for i := uint32(0); i < n; i++ { - ans, rest, ok := parseString(packet) - if !ok { - return nil, parseError(msgUserAuthInfoResponse) - } - - answers = append(answers, string(ans)) - packet = rest - } - if len(packet) != 0 { - return nil, errors.New("ssh: junk at end of message") - } - - return answers, nil -} diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go deleted file mode 100644 index eca31a22..00000000 --- a/vendor/golang.org/x/crypto/ssh/session.go +++ /dev/null @@ -1,648 +0,0 @@ -// 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 ssh - -// Session implements an interactive session described in -// "RFC 4254, section 6". - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "io/ioutil" - "sync" -) - -type Signal string - -// POSIX signals as listed in RFC 4254 Section 6.10. -const ( - SIGABRT Signal = "ABRT" - SIGALRM Signal = "ALRM" - SIGFPE Signal = "FPE" - SIGHUP Signal = "HUP" - SIGILL Signal = "ILL" - SIGINT Signal = "INT" - SIGKILL Signal = "KILL" - SIGPIPE Signal = "PIPE" - SIGQUIT Signal = "QUIT" - SIGSEGV Signal = "SEGV" - SIGTERM Signal = "TERM" - SIGUSR1 Signal = "USR1" - SIGUSR2 Signal = "USR2" -) - -var signals = map[Signal]int{ - SIGABRT: 6, - SIGALRM: 14, - SIGFPE: 8, - SIGHUP: 1, - SIGILL: 4, - SIGINT: 2, - SIGKILL: 9, - SIGPIPE: 13, - SIGQUIT: 3, - SIGSEGV: 11, - SIGTERM: 15, -} - -type TerminalModes map[uint8]uint32 - -// POSIX terminal mode flags as listed in RFC 4254 Section 8. -const ( - tty_OP_END = 0 - VINTR = 1 - VQUIT = 2 - VERASE = 3 - VKILL = 4 - VEOF = 5 - VEOL = 6 - VEOL2 = 7 - VSTART = 8 - VSTOP = 9 - VSUSP = 10 - VDSUSP = 11 - VREPRINT = 12 - VWERASE = 13 - VLNEXT = 14 - VFLUSH = 15 - VSWTCH = 16 - VSTATUS = 17 - VDISCARD = 18 - IGNPAR = 30 - PARMRK = 31 - INPCK = 32 - ISTRIP = 33 - INLCR = 34 - IGNCR = 35 - ICRNL = 36 - IUCLC = 37 - IXON = 38 - IXANY = 39 - IXOFF = 40 - IMAXBEL = 41 - IUTF8 = 42 // RFC 8160 - ISIG = 50 - ICANON = 51 - XCASE = 52 - ECHO = 53 - ECHOE = 54 - ECHOK = 55 - ECHONL = 56 - NOFLSH = 57 - TOSTOP = 58 - IEXTEN = 59 - ECHOCTL = 60 - ECHOKE = 61 - PENDIN = 62 - OPOST = 70 - OLCUC = 71 - ONLCR = 72 - OCRNL = 73 - ONOCR = 74 - ONLRET = 75 - CS7 = 90 - CS8 = 91 - PARENB = 92 - PARODD = 93 - TTY_OP_ISPEED = 128 - TTY_OP_OSPEED = 129 -) - -// A Session represents a connection to a remote command or shell. -type Session struct { - // Stdin specifies the remote process's standard input. - // If Stdin is nil, the remote process reads from an empty - // bytes.Buffer. - Stdin io.Reader - - // Stdout and Stderr specify the remote process's standard - // output and error. - // - // If either is nil, Run connects the corresponding file - // descriptor to an instance of ioutil.Discard. There is a - // fixed amount of buffering that is shared for the two streams. - // If either blocks it may eventually cause the remote - // command to block. - Stdout io.Writer - Stderr io.Writer - - ch Channel // the channel backing this session - started bool // true once Start, Run or Shell is invoked. - copyFuncs []func() error - errors chan error // one send per copyFunc - - // true if pipe method is active - stdinpipe, stdoutpipe, stderrpipe bool - - // stdinPipeWriter is non-nil if StdinPipe has not been called - // and Stdin was specified by the user; it is the write end of - // a pipe connecting Session.Stdin to the stdin channel. - stdinPipeWriter io.WriteCloser - - exitStatus chan error -} - -// SendRequest sends an out-of-band channel request on the SSH channel -// underlying the session. -func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { - return s.ch.SendRequest(name, wantReply, payload) -} - -func (s *Session) Close() error { - return s.ch.Close() -} - -// RFC 4254 Section 6.4. -type setenvRequest struct { - Name string - Value string -} - -// Setenv sets an environment variable that will be applied to any -// command executed by Shell or Run. -func (s *Session) Setenv(name, value string) error { - msg := setenvRequest{ - Name: name, - Value: value, - } - ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) - if err == nil && !ok { - err = errors.New("ssh: setenv failed") - } - return err -} - -// RFC 4254 Section 6.2. -type ptyRequestMsg struct { - Term string - Columns uint32 - Rows uint32 - Width uint32 - Height uint32 - Modelist string -} - -// RequestPty requests the association of a pty with the session on the remote host. -func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { - var tm []byte - for k, v := range termmodes { - kv := struct { - Key byte - Val uint32 - }{k, v} - - tm = append(tm, Marshal(&kv)...) - } - tm = append(tm, tty_OP_END) - req := ptyRequestMsg{ - Term: term, - Columns: uint32(w), - Rows: uint32(h), - Width: uint32(w * 8), - Height: uint32(h * 8), - Modelist: string(tm), - } - ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) - if err == nil && !ok { - err = errors.New("ssh: pty-req failed") - } - return err -} - -// RFC 4254 Section 6.5. -type subsystemRequestMsg struct { - Subsystem string -} - -// RequestSubsystem requests the association of a subsystem with the session on the remote host. -// A subsystem is a predefined command that runs in the background when the ssh session is initiated -func (s *Session) RequestSubsystem(subsystem string) error { - msg := subsystemRequestMsg{ - Subsystem: subsystem, - } - ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) - if err == nil && !ok { - err = errors.New("ssh: subsystem request failed") - } - return err -} - -// RFC 4254 Section 6.7. -type ptyWindowChangeMsg struct { - Columns uint32 - Rows uint32 - Width uint32 - Height uint32 -} - -// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. -func (s *Session) WindowChange(h, w int) error { - req := ptyWindowChangeMsg{ - Columns: uint32(w), - Rows: uint32(h), - Width: uint32(w * 8), - Height: uint32(h * 8), - } - _, err := s.ch.SendRequest("window-change", false, Marshal(&req)) - return err -} - -// RFC 4254 Section 6.9. -type signalMsg struct { - Signal string -} - -// Signal sends the given signal to the remote process. -// sig is one of the SIG* constants. -func (s *Session) Signal(sig Signal) error { - msg := signalMsg{ - Signal: string(sig), - } - - _, err := s.ch.SendRequest("signal", false, Marshal(&msg)) - return err -} - -// RFC 4254 Section 6.5. -type execMsg struct { - Command string -} - -// Start runs cmd on the remote host. Typically, the remote -// server passes cmd to the shell for interpretation. -// A Session only accepts one call to Run, Start or Shell. -func (s *Session) Start(cmd string) error { - if s.started { - return errors.New("ssh: session already started") - } - req := execMsg{ - Command: cmd, - } - - ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) - if err == nil && !ok { - err = fmt.Errorf("ssh: command %v failed", cmd) - } - if err != nil { - return err - } - return s.start() -} - -// Run runs cmd on the remote host. Typically, the remote -// server passes cmd to the shell for interpretation. -// A Session only accepts one call to Run, Start, Shell, Output, -// or CombinedOutput. -// -// The returned error is nil if the command runs, has no problems -// copying stdin, stdout, and stderr, and exits with a zero exit -// status. -// -// If the remote server does not send an exit status, an error of type -// *ExitMissingError is returned. If the command completes -// unsuccessfully or is interrupted by a signal, the error is of type -// *ExitError. Other error types may be returned for I/O problems. -func (s *Session) Run(cmd string) error { - err := s.Start(cmd) - if err != nil { - return err - } - return s.Wait() -} - -// Output runs cmd on the remote host and returns its standard output. -func (s *Session) Output(cmd string) ([]byte, error) { - if s.Stdout != nil { - return nil, errors.New("ssh: Stdout already set") - } - var b bytes.Buffer - s.Stdout = &b - err := s.Run(cmd) - return b.Bytes(), err -} - -type singleWriter struct { - b bytes.Buffer - mu sync.Mutex -} - -func (w *singleWriter) Write(p []byte) (int, error) { - w.mu.Lock() - defer w.mu.Unlock() - return w.b.Write(p) -} - -// CombinedOutput runs cmd on the remote host and returns its combined -// standard output and standard error. -func (s *Session) CombinedOutput(cmd string) ([]byte, error) { - if s.Stdout != nil { - return nil, errors.New("ssh: Stdout already set") - } - if s.Stderr != nil { - return nil, errors.New("ssh: Stderr already set") - } - var b singleWriter - s.Stdout = &b - s.Stderr = &b - err := s.Run(cmd) - return b.b.Bytes(), err -} - -// Shell starts a login shell on the remote host. A Session only -// accepts one call to Run, Start, Shell, Output, or CombinedOutput. -func (s *Session) Shell() error { - if s.started { - return errors.New("ssh: session already started") - } - - ok, err := s.ch.SendRequest("shell", true, nil) - if err == nil && !ok { - return errors.New("ssh: could not start shell") - } - if err != nil { - return err - } - return s.start() -} - -func (s *Session) start() error { - s.started = true - - type F func(*Session) - for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { - setupFd(s) - } - - s.errors = make(chan error, len(s.copyFuncs)) - for _, fn := range s.copyFuncs { - go func(fn func() error) { - s.errors <- fn() - }(fn) - } - return nil -} - -// Wait waits for the remote command to exit. -// -// The returned error is nil if the command runs, has no problems -// copying stdin, stdout, and stderr, and exits with a zero exit -// status. -// -// If the remote server does not send an exit status, an error of type -// *ExitMissingError is returned. If the command completes -// unsuccessfully or is interrupted by a signal, the error is of type -// *ExitError. Other error types may be returned for I/O problems. -func (s *Session) Wait() error { - if !s.started { - return errors.New("ssh: session not started") - } - waitErr := <-s.exitStatus - - if s.stdinPipeWriter != nil { - s.stdinPipeWriter.Close() - } - var copyError error - for range s.copyFuncs { - if err := <-s.errors; err != nil && copyError == nil { - copyError = err - } - } - if waitErr != nil { - return waitErr - } - return copyError -} - -func (s *Session) wait(reqs <-chan *Request) error { - wm := Waitmsg{status: -1} - // Wait for msg channel to be closed before returning. - for msg := range reqs { - switch msg.Type { - case "exit-status": - wm.status = int(binary.BigEndian.Uint32(msg.Payload)) - case "exit-signal": - var sigval struct { - Signal string - CoreDumped bool - Error string - Lang string - } - if err := Unmarshal(msg.Payload, &sigval); err != nil { - return err - } - - // Must sanitize strings? - wm.signal = sigval.Signal - wm.msg = sigval.Error - wm.lang = sigval.Lang - default: - // This handles keepalives and matches - // OpenSSH's behaviour. - if msg.WantReply { - msg.Reply(false, nil) - } - } - } - if wm.status == 0 { - return nil - } - if wm.status == -1 { - // exit-status was never sent from server - if wm.signal == "" { - // signal was not sent either. RFC 4254 - // section 6.10 recommends against this - // behavior, but it is allowed, so we let - // clients handle it. - return &ExitMissingError{} - } - wm.status = 128 - if _, ok := signals[Signal(wm.signal)]; ok { - wm.status += signals[Signal(wm.signal)] - } - } - - return &ExitError{wm} -} - -// ExitMissingError is returned if a session is torn down cleanly, but -// the server sends no confirmation of the exit status. -type ExitMissingError struct{} - -func (e *ExitMissingError) Error() string { - return "wait: remote command exited without exit status or exit signal" -} - -func (s *Session) stdin() { - if s.stdinpipe { - return - } - var stdin io.Reader - if s.Stdin == nil { - stdin = new(bytes.Buffer) - } else { - r, w := io.Pipe() - go func() { - _, err := io.Copy(w, s.Stdin) - w.CloseWithError(err) - }() - stdin, s.stdinPipeWriter = r, w - } - s.copyFuncs = append(s.copyFuncs, func() error { - _, err := io.Copy(s.ch, stdin) - if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { - err = err1 - } - return err - }) -} - -func (s *Session) stdout() { - if s.stdoutpipe { - return - } - if s.Stdout == nil { - s.Stdout = ioutil.Discard - } - s.copyFuncs = append(s.copyFuncs, func() error { - _, err := io.Copy(s.Stdout, s.ch) - return err - }) -} - -func (s *Session) stderr() { - if s.stderrpipe { - return - } - if s.Stderr == nil { - s.Stderr = ioutil.Discard - } - s.copyFuncs = append(s.copyFuncs, func() error { - _, err := io.Copy(s.Stderr, s.ch.Stderr()) - return err - }) -} - -// sessionStdin reroutes Close to CloseWrite. -type sessionStdin struct { - io.Writer - ch Channel -} - -func (s *sessionStdin) Close() error { - return s.ch.CloseWrite() -} - -// StdinPipe returns a pipe that will be connected to the -// remote command's standard input when the command starts. -func (s *Session) StdinPipe() (io.WriteCloser, error) { - if s.Stdin != nil { - return nil, errors.New("ssh: Stdin already set") - } - if s.started { - return nil, errors.New("ssh: StdinPipe after process started") - } - s.stdinpipe = true - return &sessionStdin{s.ch, s.ch}, nil -} - -// StdoutPipe returns a pipe that will be connected to the -// remote command's standard output when the command starts. -// There is a fixed amount of buffering that is shared between -// stdout and stderr streams. If the StdoutPipe reader is -// not serviced fast enough it may eventually cause the -// remote command to block. -func (s *Session) StdoutPipe() (io.Reader, error) { - if s.Stdout != nil { - return nil, errors.New("ssh: Stdout already set") - } - if s.started { - return nil, errors.New("ssh: StdoutPipe after process started") - } - s.stdoutpipe = true - return s.ch, nil -} - -// StderrPipe returns a pipe that will be connected to the -// remote command's standard error when the command starts. -// There is a fixed amount of buffering that is shared between -// stdout and stderr streams. If the StderrPipe reader is -// not serviced fast enough it may eventually cause the -// remote command to block. -func (s *Session) StderrPipe() (io.Reader, error) { - if s.Stderr != nil { - return nil, errors.New("ssh: Stderr already set") - } - if s.started { - return nil, errors.New("ssh: StderrPipe after process started") - } - s.stderrpipe = true - return s.ch.Stderr(), nil -} - -// newSession returns a new interactive session on the remote host. -func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { - s := &Session{ - ch: ch, - } - s.exitStatus = make(chan error, 1) - go func() { - s.exitStatus <- s.wait(reqs) - }() - - return s, nil -} - -// An ExitError reports unsuccessful completion of a remote command. -type ExitError struct { - Waitmsg -} - -func (e *ExitError) Error() string { - return e.Waitmsg.String() -} - -// Waitmsg stores the information about an exited remote command -// as reported by Wait. -type Waitmsg struct { - status int - signal string - msg string - lang string -} - -// ExitStatus returns the exit status of the remote command. -func (w Waitmsg) ExitStatus() int { - return w.status -} - -// Signal returns the exit signal of the remote command if -// it was terminated violently. -func (w Waitmsg) Signal() string { - return w.signal -} - -// Msg returns the exit message given by the remote command -func (w Waitmsg) Msg() string { - return w.msg -} - -// Lang returns the language tag. See RFC 3066 -func (w Waitmsg) Lang() string { - return w.lang -} - -func (w Waitmsg) String() string { - str := fmt.Sprintf("Process exited with status %v", w.status) - if w.signal != "" { - str += fmt.Sprintf(" from signal %v", w.signal) - } - if w.msg != "" { - str += fmt.Sprintf(". Reason was: %v", w.msg) - } - return str -} diff --git a/vendor/golang.org/x/crypto/ssh/ssh_gss.go b/vendor/golang.org/x/crypto/ssh/ssh_gss.go deleted file mode 100644 index 24bd7c8e..00000000 --- a/vendor/golang.org/x/crypto/ssh/ssh_gss.go +++ /dev/null @@ -1,139 +0,0 @@ -// 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 ssh - -import ( - "encoding/asn1" - "errors" -) - -var krb5OID []byte - -func init() { - krb5OID, _ = asn1.Marshal(krb5Mesh) -} - -// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins. -type GSSAPIClient interface { - // InitSecContext initiates the establishment of a security context for GSS-API between the - // ssh client and ssh server. Initially the token parameter should be specified as nil. - // The routine may return a outputToken which should be transferred to - // the ssh server, where the ssh server will present it to - // AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting - // needContinue to false. To complete the context - // establishment, one or more reply tokens may be required from the ssh - // server;if so, InitSecContext will return a needContinue which is true. - // In this case, InitSecContext should be called again when the - // reply token is received from the ssh server, passing the reply - // token to InitSecContext via the token parameters. - // See RFC 2743 section 2.2.1 and RFC 4462 section 3.4. - InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error) - // GetMIC generates a cryptographic MIC for the SSH2 message, and places - // the MIC in a token for transfer to the ssh server. - // The contents of the MIC field are obtained by calling GSS_GetMIC() - // over the following, using the GSS-API context that was just - // established: - // string session identifier - // byte SSH_MSG_USERAUTH_REQUEST - // string user name - // string service - // string "gssapi-with-mic" - // See RFC 2743 section 2.3.1 and RFC 4462 3.5. - GetMIC(micFiled []byte) ([]byte, error) - // Whenever possible, it should be possible for - // DeleteSecContext() calls to be successfully processed even - // if other calls cannot succeed, thereby enabling context-related - // resources to be released. - // In addition to deleting established security contexts, - // gss_delete_sec_context must also be able to delete "half-built" - // security contexts resulting from an incomplete sequence of - // InitSecContext()/AcceptSecContext() calls. - // See RFC 2743 section 2.2.3. - DeleteSecContext() error -} - -// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins. -type GSSAPIServer interface { - // AcceptSecContext allows a remotely initiated security context between the application - // and a remote peer to be established by the ssh client. The routine may return a - // outputToken which should be transferred to the ssh client, - // where the ssh client will present it to InitSecContext. - // If no token need be sent, AcceptSecContext will indicate this - // by setting the needContinue to false. To - // complete the context establishment, one or more reply tokens may be - // required from the ssh client. if so, AcceptSecContext - // will return a needContinue which is true, in which case it - // should be called again when the reply token is received from the ssh - // client, passing the token to AcceptSecContext via the - // token parameters. - // The srcName return value is the authenticated username. - // See RFC 2743 section 2.2.2 and RFC 4462 section 3.4. - AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error) - // VerifyMIC verifies that a cryptographic MIC, contained in the token parameter, - // fits the supplied message is received from the ssh client. - // See RFC 2743 section 2.3.2. - VerifyMIC(micField []byte, micToken []byte) error - // Whenever possible, it should be possible for - // DeleteSecContext() calls to be successfully processed even - // if other calls cannot succeed, thereby enabling context-related - // resources to be released. - // In addition to deleting established security contexts, - // gss_delete_sec_context must also be able to delete "half-built" - // security contexts resulting from an incomplete sequence of - // InitSecContext()/AcceptSecContext() calls. - // See RFC 2743 section 2.2.3. - DeleteSecContext() error -} - -var ( - // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication, - // so we also support the krb5 mechanism only. - // See RFC 1964 section 1. - krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2} -) - -// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST -// See RFC 4462 section 3.2. -type userAuthRequestGSSAPI struct { - N uint32 - OIDS []asn1.ObjectIdentifier -} - -func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { - n, rest, ok := parseUint32(payload) - if !ok { - return nil, errors.New("parse uint32 failed") - } - s := &userAuthRequestGSSAPI{ - N: n, - OIDS: make([]asn1.ObjectIdentifier, n), - } - for i := 0; i < int(n); i++ { - var ( - desiredMech []byte - err error - ) - desiredMech, rest, ok = parseString(rest) - if !ok { - return nil, errors.New("parse string failed") - } - if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil { - return nil, err - } - - } - return s, nil -} - -// See RFC 4462 section 3.6. -func buildMIC(sessionID string, username string, service string, authMethod string) []byte { - out := make([]byte, 0, 0) - out = appendString(out, sessionID) - out = append(out, msgUserAuthRequest) - out = appendString(out, username) - out = appendString(out, service) - out = appendString(out, authMethod) - return out -} diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go deleted file mode 100644 index b171b330..00000000 --- a/vendor/golang.org/x/crypto/ssh/streamlocal.go +++ /dev/null @@ -1,116 +0,0 @@ -package ssh - -import ( - "errors" - "io" - "net" -) - -// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message -// with "direct-streamlocal@openssh.com" string. -// -// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding -// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235 -type streamLocalChannelOpenDirectMsg struct { - socketPath string - reserved0 string - reserved1 uint32 -} - -// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message -// with "forwarded-streamlocal@openssh.com" string. -type forwardedStreamLocalPayload struct { - SocketPath string - Reserved0 string -} - -// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message -// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string. -type streamLocalChannelForwardMsg struct { - socketPath string -} - -// ListenUnix is similar to ListenTCP but uses a Unix domain socket. -func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { - c.handleForwardsOnce.Do(c.handleForwards) - m := streamLocalChannelForwardMsg{ - socketPath, - } - // send message - ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m)) - if err != nil { - return nil, err - } - if !ok { - return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") - } - ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) - - return &unixListener{socketPath, c, ch}, nil -} - -func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { - msg := streamLocalChannelOpenDirectMsg{ - socketPath: socketPath, - } - ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg)) - if err != nil { - return nil, err - } - go DiscardRequests(in) - return ch, err -} - -type unixListener struct { - socketPath string - - conn *Client - in <-chan forward -} - -// Accept waits for and returns the next connection to the listener. -func (l *unixListener) Accept() (net.Conn, error) { - s, ok := <-l.in - if !ok { - return nil, io.EOF - } - ch, incoming, err := s.newCh.Accept() - if err != nil { - return nil, err - } - go DiscardRequests(incoming) - - return &chanConn{ - Channel: ch, - laddr: &net.UnixAddr{ - Name: l.socketPath, - Net: "unix", - }, - raddr: &net.UnixAddr{ - Name: "@", - Net: "unix", - }, - }, nil -} - -// Close closes the listener. -func (l *unixListener) Close() error { - // this also closes the listener. - l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) - m := streamLocalChannelForwardMsg{ - l.socketPath, - } - ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m)) - if err == nil && !ok { - err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed") - } - return err -} - -// Addr returns the listener's network address. -func (l *unixListener) Addr() net.Addr { - return &net.UnixAddr{ - Name: l.socketPath, - Net: "unix", - } -} diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go deleted file mode 100644 index 80d35f5e..00000000 --- a/vendor/golang.org/x/crypto/ssh/tcpip.go +++ /dev/null @@ -1,474 +0,0 @@ -// 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 ssh - -import ( - "errors" - "fmt" - "io" - "math/rand" - "net" - "strconv" - "strings" - "sync" - "time" -) - -// Listen requests the remote peer open a listening socket on -// addr. Incoming connections will be available by calling Accept on -// the returned net.Listener. The listener must be serviced, or the -// SSH connection may hang. -// N must be "tcp", "tcp4", "tcp6", or "unix". -func (c *Client) Listen(n, addr string) (net.Listener, error) { - switch n { - case "tcp", "tcp4", "tcp6": - laddr, err := net.ResolveTCPAddr(n, addr) - if err != nil { - return nil, err - } - return c.ListenTCP(laddr) - case "unix": - return c.ListenUnix(addr) - default: - return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) - } -} - -// Automatic port allocation is broken with OpenSSH before 6.0. See -// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In -// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, -// rather than the actual port number. This means you can never open -// two different listeners with auto allocated ports. We work around -// this by trying explicit ports until we succeed. - -const openSSHPrefix = "OpenSSH_" - -var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) - -// isBrokenOpenSSHVersion returns true if the given version string -// specifies a version of OpenSSH that is known to have a bug in port -// forwarding. -func isBrokenOpenSSHVersion(versionStr string) bool { - i := strings.Index(versionStr, openSSHPrefix) - if i < 0 { - return false - } - i += len(openSSHPrefix) - j := i - for ; j < len(versionStr); j++ { - if versionStr[j] < '0' || versionStr[j] > '9' { - break - } - } - version, _ := strconv.Atoi(versionStr[i:j]) - return version < 6 -} - -// autoPortListenWorkaround simulates automatic port allocation by -// trying random ports repeatedly. -func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { - var sshListener net.Listener - var err error - const tries = 10 - for i := 0; i < tries; i++ { - addr := *laddr - addr.Port = 1024 + portRandomizer.Intn(60000) - sshListener, err = c.ListenTCP(&addr) - if err == nil { - laddr.Port = addr.Port - return sshListener, err - } - } - return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) -} - -// RFC 4254 7.1 -type channelForwardMsg struct { - addr string - rport uint32 -} - -// handleForwards starts goroutines handling forwarded connections. -// It's called on first use by (*Client).ListenTCP to not launch -// goroutines until needed. -func (c *Client) handleForwards() { - go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip")) - go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com")) -} - -// ListenTCP requests the remote peer open a listening socket -// on laddr. Incoming connections will be available by calling -// Accept on the returned net.Listener. -func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { - c.handleForwardsOnce.Do(c.handleForwards) - if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { - return c.autoPortListenWorkaround(laddr) - } - - m := channelForwardMsg{ - laddr.IP.String(), - uint32(laddr.Port), - } - // send message - ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) - if err != nil { - return nil, err - } - if !ok { - return nil, errors.New("ssh: tcpip-forward request denied by peer") - } - - // If the original port was 0, then the remote side will - // supply a real port number in the response. - if laddr.Port == 0 { - var p struct { - Port uint32 - } - if err := Unmarshal(resp, &p); err != nil { - return nil, err - } - laddr.Port = int(p.Port) - } - - // Register this forward, using the port number we obtained. - ch := c.forwards.add(laddr) - - return &tcpListener{laddr, c, ch}, nil -} - -// forwardList stores a mapping between remote -// forward requests and the tcpListeners. -type forwardList struct { - sync.Mutex - entries []forwardEntry -} - -// forwardEntry represents an established mapping of a laddr on a -// remote ssh server to a channel connected to a tcpListener. -type forwardEntry struct { - laddr net.Addr - c chan forward -} - -// forward represents an incoming forwarded tcpip connection. The -// arguments to add/remove/lookup should be address as specified in -// the original forward-request. -type forward struct { - newCh NewChannel // the ssh client channel underlying this forward - raddr net.Addr // the raddr of the incoming connection -} - -func (l *forwardList) add(addr net.Addr) chan forward { - l.Lock() - defer l.Unlock() - f := forwardEntry{ - laddr: addr, - c: make(chan forward, 1), - } - l.entries = append(l.entries, f) - return f.c -} - -// See RFC 4254, section 7.2 -type forwardedTCPPayload struct { - Addr string - Port uint32 - OriginAddr string - OriginPort uint32 -} - -// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. -func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { - if port == 0 || port > 65535 { - return nil, fmt.Errorf("ssh: port number out of range: %d", port) - } - ip := net.ParseIP(string(addr)) - if ip == nil { - return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) - } - return &net.TCPAddr{IP: ip, Port: int(port)}, nil -} - -func (l *forwardList) handleChannels(in <-chan NewChannel) { - for ch := range in { - var ( - laddr net.Addr - raddr net.Addr - err error - ) - switch channelType := ch.ChannelType(); channelType { - case "forwarded-tcpip": - var payload forwardedTCPPayload - if err = Unmarshal(ch.ExtraData(), &payload); err != nil { - ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) - continue - } - - // RFC 4254 section 7.2 specifies that incoming - // addresses should list the address, in string - // format. It is implied that this should be an IP - // address, as it would be impossible to connect to it - // otherwise. - laddr, err = parseTCPAddr(payload.Addr, payload.Port) - if err != nil { - ch.Reject(ConnectionFailed, err.Error()) - continue - } - raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort) - if err != nil { - ch.Reject(ConnectionFailed, err.Error()) - continue - } - - case "forwarded-streamlocal@openssh.com": - var payload forwardedStreamLocalPayload - if err = Unmarshal(ch.ExtraData(), &payload); err != nil { - ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error()) - continue - } - laddr = &net.UnixAddr{ - Name: payload.SocketPath, - Net: "unix", - } - raddr = &net.UnixAddr{ - Name: "@", - Net: "unix", - } - default: - panic(fmt.Errorf("ssh: unknown channel type %s", channelType)) - } - if ok := l.forward(laddr, raddr, ch); !ok { - // Section 7.2, implementations MUST reject spurious incoming - // connections. - ch.Reject(Prohibited, "no forward for address") - continue - } - - } -} - -// remove removes the forward entry, and the channel feeding its -// listener. -func (l *forwardList) remove(addr net.Addr) { - l.Lock() - defer l.Unlock() - for i, f := range l.entries { - if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() { - l.entries = append(l.entries[:i], l.entries[i+1:]...) - close(f.c) - return - } - } -} - -// closeAll closes and clears all forwards. -func (l *forwardList) closeAll() { - l.Lock() - defer l.Unlock() - for _, f := range l.entries { - close(f.c) - } - l.entries = nil -} - -func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { - l.Lock() - defer l.Unlock() - for _, f := range l.entries { - if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() { - f.c <- forward{newCh: ch, raddr: raddr} - return true - } - } - return false -} - -type tcpListener struct { - laddr *net.TCPAddr - - conn *Client - in <-chan forward -} - -// Accept waits for and returns the next connection to the listener. -func (l *tcpListener) Accept() (net.Conn, error) { - s, ok := <-l.in - if !ok { - return nil, io.EOF - } - ch, incoming, err := s.newCh.Accept() - if err != nil { - return nil, err - } - go DiscardRequests(incoming) - - return &chanConn{ - Channel: ch, - laddr: l.laddr, - raddr: s.raddr, - }, nil -} - -// Close closes the listener. -func (l *tcpListener) Close() error { - m := channelForwardMsg{ - l.laddr.IP.String(), - uint32(l.laddr.Port), - } - - // this also closes the listener. - l.conn.forwards.remove(l.laddr) - ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) - if err == nil && !ok { - err = errors.New("ssh: cancel-tcpip-forward failed") - } - return err -} - -// Addr returns the listener's network address. -func (l *tcpListener) Addr() net.Addr { - return l.laddr -} - -// Dial initiates a connection to the addr from the remote host. -// The resulting connection has a zero LocalAddr() and RemoteAddr(). -func (c *Client) Dial(n, addr string) (net.Conn, error) { - var ch Channel - switch n { - case "tcp", "tcp4", "tcp6": - // Parse the address into host and numeric port. - host, portString, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - port, err := strconv.ParseUint(portString, 10, 16) - if err != nil { - return nil, err - } - ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port)) - if err != nil { - return nil, err - } - // Use a zero address for local and remote address. - zeroAddr := &net.TCPAddr{ - IP: net.IPv4zero, - Port: 0, - } - return &chanConn{ - Channel: ch, - laddr: zeroAddr, - raddr: zeroAddr, - }, nil - case "unix": - var err error - ch, err = c.dialStreamLocal(addr) - if err != nil { - return nil, err - } - return &chanConn{ - Channel: ch, - laddr: &net.UnixAddr{ - Name: "@", - Net: "unix", - }, - raddr: &net.UnixAddr{ - Name: addr, - Net: "unix", - }, - }, nil - default: - return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) - } -} - -// DialTCP connects to the remote address raddr on the network net, -// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used -// as the local address for the connection. -func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { - if laddr == nil { - laddr = &net.TCPAddr{ - IP: net.IPv4zero, - Port: 0, - } - } - ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) - if err != nil { - return nil, err - } - return &chanConn{ - Channel: ch, - laddr: laddr, - raddr: raddr, - }, nil -} - -// RFC 4254 7.2 -type channelOpenDirectMsg struct { - raddr string - rport uint32 - laddr string - lport uint32 -} - -func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { - msg := channelOpenDirectMsg{ - raddr: raddr, - rport: uint32(rport), - laddr: laddr, - lport: uint32(lport), - } - ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) - if err != nil { - return nil, err - } - go DiscardRequests(in) - return ch, err -} - -type tcpChan struct { - Channel // the backing channel -} - -// chanConn fulfills the net.Conn interface without -// the tcpChan having to hold laddr or raddr directly. -type chanConn struct { - Channel - laddr, raddr net.Addr -} - -// LocalAddr returns the local network address. -func (t *chanConn) LocalAddr() net.Addr { - return t.laddr -} - -// RemoteAddr returns the remote network address. -func (t *chanConn) RemoteAddr() net.Addr { - return t.raddr -} - -// SetDeadline sets the read and write deadlines associated -// with the connection. -func (t *chanConn) SetDeadline(deadline time.Time) error { - if err := t.SetReadDeadline(deadline); err != nil { - return err - } - return t.SetWriteDeadline(deadline) -} - -// SetReadDeadline sets the read deadline. -// A zero value for t means Read will not time out. -// After the deadline, the error from Read will implement net.Error -// with Timeout() == true. -func (t *chanConn) SetReadDeadline(deadline time.Time) error { - // for compatibility with previous version, - // the error message contains "tcpChan" - return errors.New("ssh: tcpChan: deadline not supported") -} - -// SetWriteDeadline exists to satisfy the net.Conn interface -// but is not implemented by this type. It always returns an error. -func (t *chanConn) SetWriteDeadline(deadline time.Time) error { - return errors.New("ssh: tcpChan: deadline not supported") -} diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go deleted file mode 100644 index acf5a21b..00000000 --- a/vendor/golang.org/x/crypto/ssh/transport.go +++ /dev/null @@ -1,357 +0,0 @@ -// 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 ssh - -import ( - "bufio" - "bytes" - "errors" - "io" - "log" -) - -// debugTransport if set, will print packet types as they go over the -// wire. No message decoding is done, to minimize the impact on timing. -const debugTransport = false - -const ( - gcmCipherID = "aes128-gcm@openssh.com" - aes128cbcID = "aes128-cbc" - tripledescbcID = "3des-cbc" -) - -// packetConn represents a transport that implements packet based -// operations. -type packetConn interface { - // Encrypt and send a packet of data to the remote peer. - writePacket(packet []byte) error - - // Read a packet from the connection. The read is blocking, - // i.e. if error is nil, then the returned byte slice is - // always non-empty. - readPacket() ([]byte, error) - - // Close closes the write-side of the connection. - Close() error -} - -// transport is the keyingTransport that implements the SSH packet -// protocol. -type transport struct { - reader connectionState - writer connectionState - - bufReader *bufio.Reader - bufWriter *bufio.Writer - rand io.Reader - isClient bool - io.Closer -} - -// packetCipher represents a combination of SSH encryption/MAC -// protocol. A single instance should be used for one direction only. -type packetCipher interface { - // writeCipherPacket encrypts the packet and writes it to w. The - // contents of the packet are generally scrambled. - writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error - - // readCipherPacket reads and decrypts a packet of data. The - // returned packet may be overwritten by future calls of - // readPacket. - readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error) -} - -// connectionState represents one side (read or write) of the -// connection. This is necessary because each direction has its own -// keys, and can even have its own algorithms -type connectionState struct { - packetCipher - seqNum uint32 - dir direction - pendingKeyChange chan packetCipher -} - -// prepareKeyChange sets up key material for a keychange. The key changes in -// both directions are triggered by reading and writing a msgNewKey packet -// respectively. -func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { - ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult) - if err != nil { - return err - } - t.reader.pendingKeyChange <- ciph - - ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult) - if err != nil { - return err - } - t.writer.pendingKeyChange <- ciph - - return nil -} - -func (t *transport) printPacket(p []byte, write bool) { - if len(p) == 0 { - return - } - who := "server" - if t.isClient { - who = "client" - } - what := "read" - if write { - what = "write" - } - - log.Println(what, who, p[0]) -} - -// Read and decrypt next packet. -func (t *transport) readPacket() (p []byte, err error) { - for { - p, err = t.reader.readPacket(t.bufReader) - if err != nil { - break - } - if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { - break - } - } - if debugTransport { - t.printPacket(p, false) - } - - return p, err -} - -func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { - packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) - s.seqNum++ - if err == nil && len(packet) == 0 { - err = errors.New("ssh: zero length packet") - } - - if len(packet) > 0 { - switch packet[0] { - case msgNewKeys: - select { - case cipher := <-s.pendingKeyChange: - s.packetCipher = cipher - default: - return nil, errors.New("ssh: got bogus newkeys message") - } - - case msgDisconnect: - // Transform a disconnect message into an - // error. Since this is lowest level at which - // we interpret message types, doing it here - // ensures that we don't have to handle it - // elsewhere. - var msg disconnectMsg - if err := Unmarshal(packet, &msg); err != nil { - return nil, err - } - return nil, &msg - } - } - - // The packet may point to an internal buffer, so copy the - // packet out here. - fresh := make([]byte, len(packet)) - copy(fresh, packet) - - return fresh, err -} - -func (t *transport) writePacket(packet []byte) error { - if debugTransport { - t.printPacket(packet, true) - } - return t.writer.writePacket(t.bufWriter, t.rand, packet) -} - -func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { - changeKeys := len(packet) > 0 && packet[0] == msgNewKeys - - err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) - if err != nil { - return err - } - if err = w.Flush(); err != nil { - return err - } - s.seqNum++ - if changeKeys { - select { - case cipher := <-s.pendingKeyChange: - s.packetCipher = cipher - default: - panic("ssh: no key material for msgNewKeys") - } - } - return err -} - -func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { - t := &transport{ - bufReader: bufio.NewReader(rwc), - bufWriter: bufio.NewWriter(rwc), - rand: rand, - reader: connectionState{ - packetCipher: &streamPacketCipher{cipher: noneCipher{}}, - pendingKeyChange: make(chan packetCipher, 1), - }, - writer: connectionState{ - packetCipher: &streamPacketCipher{cipher: noneCipher{}}, - pendingKeyChange: make(chan packetCipher, 1), - }, - Closer: rwc, - } - t.isClient = isClient - - if isClient { - t.reader.dir = serverKeys - t.writer.dir = clientKeys - } else { - t.reader.dir = clientKeys - t.writer.dir = serverKeys - } - - return t -} - -type direction struct { - ivTag []byte - keyTag []byte - macKeyTag []byte -} - -var ( - serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} - clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} -) - -// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as -// described in RFC 4253, section 6.4. direction should either be serverKeys -// (to setup server->client keys) or clientKeys (for client->server keys). -func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { - cipherMode := cipherModes[algs.Cipher] - - iv := make([]byte, cipherMode.ivSize) - key := make([]byte, cipherMode.keySize) - - generateKeyMaterial(iv, d.ivTag, kex) - generateKeyMaterial(key, d.keyTag, kex) - - var macKey []byte - if !aeadCiphers[algs.Cipher] { - macMode := macModes[algs.MAC] - macKey = make([]byte, macMode.keySize) - generateKeyMaterial(macKey, d.macKeyTag, kex) - } - - return cipherModes[algs.Cipher].create(key, iv, macKey, algs) -} - -// generateKeyMaterial fills out with key material generated from tag, K, H -// and sessionId, as specified in RFC 4253, section 7.2. -func generateKeyMaterial(out, tag []byte, r *kexResult) { - var digestsSoFar []byte - - h := r.Hash.New() - for len(out) > 0 { - h.Reset() - h.Write(r.K) - h.Write(r.H) - - if len(digestsSoFar) == 0 { - h.Write(tag) - h.Write(r.SessionID) - } else { - h.Write(digestsSoFar) - } - - digest := h.Sum(nil) - n := copy(out, digest) - out = out[n:] - if len(out) > 0 { - digestsSoFar = append(digestsSoFar, digest...) - } - } -} - -const packageVersion = "SSH-2.0-Go" - -// Sends and receives a version line. The versionLine string should -// be US ASCII, start with "SSH-2.0-", and should not include a -// newline. exchangeVersions returns the other side's version line. -func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { - // Contrary to the RFC, we do not ignore lines that don't - // start with "SSH-2.0-" to make the library usable with - // nonconforming servers. - for _, c := range versionLine { - // The spec disallows non US-ASCII chars, and - // specifically forbids null chars. - if c < 32 { - return nil, errors.New("ssh: junk character in version line") - } - } - if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { - return - } - - them, err = readVersion(rw) - return them, err -} - -// maxVersionStringBytes is the maximum number of bytes that we'll -// accept as a version string. RFC 4253 section 4.2 limits this at 255 -// chars -const maxVersionStringBytes = 255 - -// Read version string as specified by RFC 4253, section 4.2. -func readVersion(r io.Reader) ([]byte, error) { - versionString := make([]byte, 0, 64) - var ok bool - var buf [1]byte - - for length := 0; length < maxVersionStringBytes; length++ { - _, err := io.ReadFull(r, buf[:]) - if err != nil { - return nil, err - } - // The RFC says that the version should be terminated with \r\n - // but several SSH servers actually only send a \n. - if buf[0] == '\n' { - if !bytes.HasPrefix(versionString, []byte("SSH-")) { - // RFC 4253 says we need to ignore all version string lines - // except the one containing the SSH version (provided that - // all the lines do not exceed 255 bytes in total). - versionString = versionString[:0] - continue - } - ok = true - break - } - - // non ASCII chars are disallowed, but we are lenient, - // since Go doesn't use null-terminated strings. - - // The RFC allows a comment after a space, however, - // all of it (version and comments) goes into the - // session hash. - versionString = append(versionString, buf[0]) - } - - if !ok { - return nil, errors.New("ssh: overflow reading version string") - } - - // There might be a '\r' on the end which we should remove. - if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { - versionString = versionString[:len(versionString)-1] - } - return versionString, nil -} diff --git a/vendor/golang.org/x/net/internal/socks/client.go b/vendor/golang.org/x/net/internal/socks/client.go deleted file mode 100644 index 3d6f516a..00000000 --- a/vendor/golang.org/x/net/internal/socks/client.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2018 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 socks - -import ( - "context" - "errors" - "io" - "net" - "strconv" - "time" -) - -var ( - noDeadline = time.Time{} - aLongTimeAgo = time.Unix(1, 0) -) - -func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { - host, port, err := splitHostPort(address) - if err != nil { - return nil, err - } - if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { - c.SetDeadline(deadline) - defer c.SetDeadline(noDeadline) - } - if ctx != context.Background() { - errCh := make(chan error, 1) - done := make(chan struct{}) - defer func() { - close(done) - if ctxErr == nil { - ctxErr = <-errCh - } - }() - go func() { - select { - case <-ctx.Done(): - c.SetDeadline(aLongTimeAgo) - errCh <- ctx.Err() - case <-done: - errCh <- nil - } - }() - } - - b := make([]byte, 0, 6+len(host)) // the size here is just an estimate - b = append(b, Version5) - if len(d.AuthMethods) == 0 || d.Authenticate == nil { - b = append(b, 1, byte(AuthMethodNotRequired)) - } else { - ams := d.AuthMethods - if len(ams) > 255 { - return nil, errors.New("too many authentication methods") - } - b = append(b, byte(len(ams))) - for _, am := range ams { - b = append(b, byte(am)) - } - } - if _, ctxErr = c.Write(b); ctxErr != nil { - return - } - - if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { - return - } - if b[0] != Version5 { - return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) - } - am := AuthMethod(b[1]) - if am == AuthMethodNoAcceptableMethods { - return nil, errors.New("no acceptable authentication methods") - } - if d.Authenticate != nil { - if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { - return - } - } - - b = b[:0] - b = append(b, Version5, byte(d.cmd), 0) - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - b = append(b, AddrTypeIPv4) - b = append(b, ip4...) - } else if ip6 := ip.To16(); ip6 != nil { - b = append(b, AddrTypeIPv6) - b = append(b, ip6...) - } else { - return nil, errors.New("unknown address type") - } - } else { - if len(host) > 255 { - return nil, errors.New("FQDN too long") - } - b = append(b, AddrTypeFQDN) - b = append(b, byte(len(host))) - b = append(b, host...) - } - b = append(b, byte(port>>8), byte(port)) - if _, ctxErr = c.Write(b); ctxErr != nil { - return - } - - if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { - return - } - if b[0] != Version5 { - return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) - } - if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { - return nil, errors.New("unknown error " + cmdErr.String()) - } - if b[2] != 0 { - return nil, errors.New("non-zero reserved field") - } - l := 2 - var a Addr - switch b[3] { - case AddrTypeIPv4: - l += net.IPv4len - a.IP = make(net.IP, net.IPv4len) - case AddrTypeIPv6: - l += net.IPv6len - a.IP = make(net.IP, net.IPv6len) - case AddrTypeFQDN: - if _, err := io.ReadFull(c, b[:1]); err != nil { - return nil, err - } - l += int(b[0]) - default: - return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) - } - if cap(b) < l { - b = make([]byte, l) - } else { - b = b[:l] - } - if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { - return - } - if a.IP != nil { - copy(a.IP, b) - } else { - a.Name = string(b[:len(b)-2]) - } - a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) - return &a, nil -} - -func splitHostPort(address string) (string, int, error) { - host, port, err := net.SplitHostPort(address) - if err != nil { - return "", 0, err - } - portnum, err := strconv.Atoi(port) - if err != nil { - return "", 0, err - } - if 1 > portnum || portnum > 0xffff { - return "", 0, errors.New("port number out of range " + port) - } - return host, portnum, nil -} diff --git a/vendor/golang.org/x/net/internal/socks/socks.go b/vendor/golang.org/x/net/internal/socks/socks.go deleted file mode 100644 index 97db2340..00000000 --- a/vendor/golang.org/x/net/internal/socks/socks.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2018 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 socks provides a SOCKS version 5 client implementation. -// -// SOCKS protocol version 5 is defined in RFC 1928. -// Username/Password authentication for SOCKS version 5 is defined in -// RFC 1929. -package socks - -import ( - "context" - "errors" - "io" - "net" - "strconv" -) - -// A Command represents a SOCKS command. -type Command int - -func (cmd Command) String() string { - switch cmd { - case CmdConnect: - return "socks connect" - case cmdBind: - return "socks bind" - default: - return "socks " + strconv.Itoa(int(cmd)) - } -} - -// An AuthMethod represents a SOCKS authentication method. -type AuthMethod int - -// A Reply represents a SOCKS command reply code. -type Reply int - -func (code Reply) String() string { - switch code { - case StatusSucceeded: - return "succeeded" - case 0x01: - return "general SOCKS server failure" - case 0x02: - return "connection not allowed by ruleset" - case 0x03: - return "network unreachable" - case 0x04: - return "host unreachable" - case 0x05: - return "connection refused" - case 0x06: - return "TTL expired" - case 0x07: - return "command not supported" - case 0x08: - return "address type not supported" - default: - return "unknown code: " + strconv.Itoa(int(code)) - } -} - -// Wire protocol constants. -const ( - Version5 = 0x05 - - AddrTypeIPv4 = 0x01 - AddrTypeFQDN = 0x03 - AddrTypeIPv6 = 0x04 - - CmdConnect Command = 0x01 // establishes an active-open forward proxy connection - cmdBind Command = 0x02 // establishes a passive-open forward proxy connection - - AuthMethodNotRequired AuthMethod = 0x00 // no authentication required - AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password - AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods - - StatusSucceeded Reply = 0x00 -) - -// An Addr represents a SOCKS-specific address. -// Either Name or IP is used exclusively. -type Addr struct { - Name string // fully-qualified domain name - IP net.IP - Port int -} - -func (a *Addr) Network() string { return "socks" } - -func (a *Addr) String() string { - if a == nil { - return "" - } - port := strconv.Itoa(a.Port) - if a.IP == nil { - return net.JoinHostPort(a.Name, port) - } - return net.JoinHostPort(a.IP.String(), port) -} - -// A Conn represents a forward proxy connection. -type Conn struct { - net.Conn - - boundAddr net.Addr -} - -// BoundAddr returns the address assigned by the proxy server for -// connecting to the command target address from the proxy server. -func (c *Conn) BoundAddr() net.Addr { - if c == nil { - return nil - } - return c.boundAddr -} - -// A Dialer holds SOCKS-specific options. -type Dialer struct { - cmd Command // either CmdConnect or cmdBind - proxyNetwork string // network between a proxy server and a client - proxyAddress string // proxy server address - - // ProxyDial specifies the optional dial function for - // establishing the transport connection. - ProxyDial func(context.Context, string, string) (net.Conn, error) - - // AuthMethods specifies the list of request authentication - // methods. - // If empty, SOCKS client requests only AuthMethodNotRequired. - AuthMethods []AuthMethod - - // Authenticate specifies the optional authentication - // function. It must be non-nil when AuthMethods is not empty. - // It must return an error when the authentication is failed. - Authenticate func(context.Context, io.ReadWriter, AuthMethod) error -} - -// DialContext connects to the provided address on the provided -// network. -// -// The returned error value may be a net.OpError. When the Op field of -// net.OpError contains "socks", the Source field contains a proxy -// server address and the Addr field contains a command target -// address. -// -// See func Dial of the net package of standard library for a -// description of the network and address parameters. -func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - if err := d.validateTarget(network, address); err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - if ctx == nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} - } - var err error - var c net.Conn - if d.ProxyDial != nil { - c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) - } else { - var dd net.Dialer - c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) - } - if err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - a, err := d.connect(ctx, c, address) - if err != nil { - c.Close() - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - return &Conn{Conn: c, boundAddr: a}, nil -} - -// DialWithConn initiates a connection from SOCKS server to the target -// network and address using the connection c that is already -// connected to the SOCKS server. -// -// It returns the connection's local address assigned by the SOCKS -// server. -func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { - if err := d.validateTarget(network, address); err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - if ctx == nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} - } - a, err := d.connect(ctx, c, address) - if err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - return a, nil -} - -// Dial connects to the provided address on the provided network. -// -// Unlike DialContext, it returns a raw transport connection instead -// of a forward proxy connection. -// -// Deprecated: Use DialContext or DialWithConn instead. -func (d *Dialer) Dial(network, address string) (net.Conn, error) { - if err := d.validateTarget(network, address); err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - var err error - var c net.Conn - if d.ProxyDial != nil { - c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) - } else { - c, err = net.Dial(d.proxyNetwork, d.proxyAddress) - } - if err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { - c.Close() - return nil, err - } - return c, nil -} - -func (d *Dialer) validateTarget(network, address string) error { - switch network { - case "tcp", "tcp6", "tcp4": - default: - return errors.New("network not implemented") - } - switch d.cmd { - case CmdConnect, cmdBind: - default: - return errors.New("command not implemented") - } - return nil -} - -func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { - for i, s := range []string{d.proxyAddress, address} { - host, port, err := splitHostPort(s) - if err != nil { - return nil, nil, err - } - a := &Addr{Port: port} - a.IP = net.ParseIP(host) - if a.IP == nil { - a.Name = host - } - if i == 0 { - proxy = a - } else { - dst = a - } - } - return -} - -// NewDialer returns a new Dialer that dials through the provided -// proxy server's network and address. -func NewDialer(network, address string) *Dialer { - return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} -} - -const ( - authUsernamePasswordVersion = 0x01 - authStatusSucceeded = 0x00 -) - -// UsernamePassword are the credentials for the username/password -// authentication method. -type UsernamePassword struct { - Username string - Password string -} - -// Authenticate authenticates a pair of username and password with the -// proxy server. -func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { - switch auth { - case AuthMethodNotRequired: - return nil - case AuthMethodUsernamePassword: - if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 { - return errors.New("invalid username/password") - } - b := []byte{authUsernamePasswordVersion} - b = append(b, byte(len(up.Username))) - b = append(b, up.Username...) - b = append(b, byte(len(up.Password))) - b = append(b, up.Password...) - // TODO(mikio): handle IO deadlines and cancelation if - // necessary - if _, err := rw.Write(b); err != nil { - return err - } - if _, err := io.ReadFull(rw, b[:2]); err != nil { - return err - } - if b[0] != authUsernamePasswordVersion { - return errors.New("invalid username/password version") - } - if b[1] != authStatusSucceeded { - return errors.New("username/password authentication failed") - } - return nil - } - return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) -} diff --git a/vendor/golang.org/x/net/proxy/dial.go b/vendor/golang.org/x/net/proxy/dial.go deleted file mode 100644 index 811c2e4e..00000000 --- a/vendor/golang.org/x/net/proxy/dial.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proxy - -import ( - "context" - "net" -) - -// A ContextDialer dials using a context. -type ContextDialer interface { - DialContext(ctx context.Context, network, address string) (net.Conn, error) -} - -// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment. -// -// The passed ctx is only used for returning the Conn, not the lifetime of the Conn. -// -// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer -// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout. -// -// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. -func Dial(ctx context.Context, network, address string) (net.Conn, error) { - d := FromEnvironment() - if xd, ok := d.(ContextDialer); ok { - return xd.DialContext(ctx, network, address) - } - return dialContext(ctx, d, network, address) -} - -// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout -// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. -func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) { - var ( - conn net.Conn - done = make(chan struct{}, 1) - err error - ) - go func() { - conn, err = d.Dial(network, address) - close(done) - if conn != nil && ctx.Err() != nil { - conn.Close() - } - }() - select { - case <-ctx.Done(): - err = ctx.Err() - case <-done: - } - return conn, err -} diff --git a/vendor/golang.org/x/net/proxy/direct.go b/vendor/golang.org/x/net/proxy/direct.go deleted file mode 100644 index 3d66bdef..00000000 --- a/vendor/golang.org/x/net/proxy/direct.go +++ /dev/null @@ -1,31 +0,0 @@ -// 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 proxy - -import ( - "context" - "net" -) - -type direct struct{} - -// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext. -var Direct = direct{} - -var ( - _ Dialer = Direct - _ ContextDialer = Direct -) - -// Dial directly invokes net.Dial with the supplied parameters. -func (direct) Dial(network, addr string) (net.Conn, error) { - return net.Dial(network, addr) -} - -// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters. -func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { - var d net.Dialer - return d.DialContext(ctx, network, addr) -} diff --git a/vendor/golang.org/x/net/proxy/per_host.go b/vendor/golang.org/x/net/proxy/per_host.go deleted file mode 100644 index 573fe79e..00000000 --- a/vendor/golang.org/x/net/proxy/per_host.go +++ /dev/null @@ -1,155 +0,0 @@ -// 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 proxy - -import ( - "context" - "net" - "strings" -) - -// A PerHost directs connections to a default Dialer unless the host name -// requested matches one of a number of exceptions. -type PerHost struct { - def, bypass Dialer - - bypassNetworks []*net.IPNet - bypassIPs []net.IP - bypassZones []string - bypassHosts []string -} - -// NewPerHost returns a PerHost Dialer that directs connections to either -// defaultDialer or bypass, depending on whether the connection matches one of -// the configured rules. -func NewPerHost(defaultDialer, bypass Dialer) *PerHost { - return &PerHost{ - def: defaultDialer, - bypass: bypass, - } -} - -// Dial connects to the address addr on the given network through either -// defaultDialer or bypass. -func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - - return p.dialerForRequest(host).Dial(network, addr) -} - -// DialContext connects to the address addr on the given network through either -// defaultDialer or bypass. -func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - d := p.dialerForRequest(host) - if x, ok := d.(ContextDialer); ok { - return x.DialContext(ctx, network, addr) - } - return dialContext(ctx, d, network, addr) -} - -func (p *PerHost) dialerForRequest(host string) Dialer { - if ip := net.ParseIP(host); ip != nil { - for _, net := range p.bypassNetworks { - if net.Contains(ip) { - return p.bypass - } - } - for _, bypassIP := range p.bypassIPs { - if bypassIP.Equal(ip) { - return p.bypass - } - } - return p.def - } - - for _, zone := range p.bypassZones { - if strings.HasSuffix(host, zone) { - return p.bypass - } - if host == zone[1:] { - // For a zone ".example.com", we match "example.com" - // too. - return p.bypass - } - } - for _, bypassHost := range p.bypassHosts { - if bypassHost == host { - return p.bypass - } - } - return p.def -} - -// AddFromString parses a string that contains comma-separated values -// specifying hosts that should use the bypass proxy. Each value is either an -// IP address, a CIDR range, a zone (*.example.com) or a host name -// (localhost). A best effort is made to parse the string and errors are -// ignored. -func (p *PerHost) AddFromString(s string) { - hosts := strings.Split(s, ",") - for _, host := range hosts { - host = strings.TrimSpace(host) - if len(host) == 0 { - continue - } - if strings.Contains(host, "/") { - // We assume that it's a CIDR address like 127.0.0.0/8 - if _, net, err := net.ParseCIDR(host); err == nil { - p.AddNetwork(net) - } - continue - } - if ip := net.ParseIP(host); ip != nil { - p.AddIP(ip) - continue - } - if strings.HasPrefix(host, "*.") { - p.AddZone(host[1:]) - continue - } - p.AddHost(host) - } -} - -// AddIP specifies an IP address that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match an IP. -func (p *PerHost) AddIP(ip net.IP) { - p.bypassIPs = append(p.bypassIPs, ip) -} - -// AddNetwork specifies an IP range that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match. -func (p *PerHost) AddNetwork(net *net.IPNet) { - p.bypassNetworks = append(p.bypassNetworks, net) -} - -// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of -// "example.com" matches "example.com" and all of its subdomains. -func (p *PerHost) AddZone(zone string) { - if strings.HasSuffix(zone, ".") { - zone = zone[:len(zone)-1] - } - if !strings.HasPrefix(zone, ".") { - zone = "." + zone - } - p.bypassZones = append(p.bypassZones, zone) -} - -// AddHost specifies a host name that will use the bypass proxy. -func (p *PerHost) AddHost(host string) { - if strings.HasSuffix(host, ".") { - host = host[:len(host)-1] - } - p.bypassHosts = append(p.bypassHosts, host) -} diff --git a/vendor/golang.org/x/net/proxy/proxy.go b/vendor/golang.org/x/net/proxy/proxy.go deleted file mode 100644 index 9ff4b9a7..00000000 --- a/vendor/golang.org/x/net/proxy/proxy.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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 proxy provides support for a variety of protocols to proxy network -// data. -package proxy // import "golang.org/x/net/proxy" - -import ( - "errors" - "net" - "net/url" - "os" - "sync" -) - -// A Dialer is a means to establish a connection. -// Custom dialers should also implement ContextDialer. -type Dialer interface { - // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, err error) -} - -// Auth contains authentication parameters that specific Dialers may require. -type Auth struct { - User, Password string -} - -// FromEnvironment returns the dialer specified by the proxy-related -// variables in the environment and makes underlying connections -// directly. -func FromEnvironment() Dialer { - return FromEnvironmentUsing(Direct) -} - -// FromEnvironmentUsing returns the dialer specify by the proxy-related -// variables in the environment and makes underlying connections -// using the provided forwarding Dialer (for instance, a *net.Dialer -// with desired configuration). -func FromEnvironmentUsing(forward Dialer) Dialer { - allProxy := allProxyEnv.Get() - if len(allProxy) == 0 { - return forward - } - - proxyURL, err := url.Parse(allProxy) - if err != nil { - return forward - } - proxy, err := FromURL(proxyURL, forward) - if err != nil { - return forward - } - - noProxy := noProxyEnv.Get() - if len(noProxy) == 0 { - return proxy - } - - perHost := NewPerHost(proxy, forward) - perHost.AddFromString(noProxy) - return perHost -} - -// proxySchemes is a map from URL schemes to a function that creates a Dialer -// from a URL with such a scheme. -var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) - -// RegisterDialerType takes a URL scheme and a function to generate Dialers from -// a URL with that scheme and a forwarding Dialer. Registered schemes are used -// by FromURL. -func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { - if proxySchemes == nil { - proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) - } - proxySchemes[scheme] = f -} - -// FromURL returns a Dialer given a URL specification and an underlying -// Dialer for it to make network requests. -func FromURL(u *url.URL, forward Dialer) (Dialer, error) { - var auth *Auth - if u.User != nil { - auth = new(Auth) - auth.User = u.User.Username() - if p, ok := u.User.Password(); ok { - auth.Password = p - } - } - - switch u.Scheme { - case "socks5", "socks5h": - addr := u.Hostname() - port := u.Port() - if port == "" { - port = "1080" - } - return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) - } - - // If the scheme doesn't match any of the built-in schemes, see if it - // was registered by another package. - if proxySchemes != nil { - if f, ok := proxySchemes[u.Scheme]; ok { - return f(u, forward) - } - } - - return nil, errors.New("proxy: unknown scheme: " + u.Scheme) -} - -var ( - allProxyEnv = &envOnce{ - names: []string{"ALL_PROXY", "all_proxy"}, - } - noProxyEnv = &envOnce{ - names: []string{"NO_PROXY", "no_proxy"}, - } -) - -// envOnce looks up an environment variable (optionally by multiple -// names) once. It mitigates expensive lookups on some platforms -// (e.g. Windows). -// (Borrowed from net/http/transport.go) -type envOnce struct { - names []string - once sync.Once - val string -} - -func (e *envOnce) Get() string { - e.once.Do(e.init) - return e.val -} - -func (e *envOnce) init() { - for _, n := range e.names { - e.val = os.Getenv(n) - if e.val != "" { - return - } - } -} - -// reset is used by tests -func (e *envOnce) reset() { - e.once = sync.Once{} - e.val = "" -} diff --git a/vendor/golang.org/x/net/proxy/socks5.go b/vendor/golang.org/x/net/proxy/socks5.go deleted file mode 100644 index c91651f9..00000000 --- a/vendor/golang.org/x/net/proxy/socks5.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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 proxy - -import ( - "context" - "net" - - "golang.org/x/net/internal/socks" -) - -// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given -// address with an optional username and password. -// See RFC 1928 and RFC 1929. -func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { - d := socks.NewDialer(network, address) - if forward != nil { - if f, ok := forward.(ContextDialer); ok { - d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { - return f.DialContext(ctx, network, address) - } - } else { - d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { - return dialContext(ctx, forward, network, address) - } - } - } - if auth != nil { - up := socks.UsernamePassword{ - Username: auth.User, - Password: auth.Password, - } - d.AuthMethods = []socks.AuthMethod{ - socks.AuthMethodNotRequired, - socks.AuthMethodUsernamePassword, - } - d.Authenticate = up.Authenticate - } - return d, nil -} diff --git a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s deleted file mode 100644 index db9171c2..00000000 --- a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 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. - -//go:build gc -// +build gc - -#include "textflag.h" - -// -// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go -// - -TEXT ·syscall6(SB),NOSPLIT,$0-88 - JMP syscall·syscall6(SB) - -TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 - JMP syscall·rawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/cpu/byteorder.go b/vendor/golang.org/x/sys/cpu/byteorder.go deleted file mode 100644 index 271055be..00000000 --- a/vendor/golang.org/x/sys/cpu/byteorder.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cpu - -import ( - "runtime" -) - -// byteOrder is a subset of encoding/binary.ByteOrder. -type byteOrder interface { - Uint32([]byte) uint32 - Uint64([]byte) uint64 -} - -type littleEndian struct{} -type bigEndian struct{} - -func (littleEndian) Uint32(b []byte) uint32 { - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 -} - -func (littleEndian) Uint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 -} - -func (bigEndian) Uint32(b []byte) uint32 { - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 -} - -func (bigEndian) Uint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -// hostByteOrder returns littleEndian on little-endian machines and -// bigEndian on big-endian machines. -func hostByteOrder() byteOrder { - switch runtime.GOARCH { - case "386", "amd64", "amd64p32", - "alpha", - "arm", "arm64", - "loong64", - "mipsle", "mips64le", "mips64p32le", - "nios2", - "ppc64le", - "riscv", "riscv64", - "sh": - return littleEndian{} - case "armbe", "arm64be", - "m68k", - "mips", "mips64", "mips64p32", - "ppc", "ppc64", - "s390", "s390x", - "shbe", - "sparc", "sparc64": - return bigEndian{} - } - panic("unknown architecture") -} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go deleted file mode 100644 index 83f112c4..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2018 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 cpu implements processor feature detection for -// various CPU architectures. -package cpu - -import ( - "os" - "strings" -) - -// Initialized reports whether the CPU features were initialized. -// -// For some GOOS/GOARCH combinations initialization of the CPU features depends -// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm -// Initialized will report false if reading the file fails. -var Initialized bool - -// CacheLinePad is used to pad structs to avoid false sharing. -type CacheLinePad struct{ _ [cacheLineSize]byte } - -// X86 contains the supported CPU features of the -// current X86/AMD64 platform. If the current platform -// is not X86/AMD64 then all feature flags are false. -// -// X86 is padded to avoid false sharing. Further the HasAVX -// and HasAVX2 are only set if the OS supports XMM and YMM -// registers in addition to the CPUID feature bit being set. -var X86 struct { - _ CacheLinePad - HasAES bool // AES hardware implementation (AES NI) - HasADX bool // Multi-precision add-carry instruction extensions - HasAVX bool // Advanced vector extension - HasAVX2 bool // Advanced vector extension 2 - HasAVX512 bool // Advanced vector extension 512 - HasAVX512F bool // Advanced vector extension 512 Foundation Instructions - HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions - HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions - HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions Instructions - HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions - HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions - HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions - HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add - HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions - HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision - HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision - HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions - HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations - HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions - HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions - HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions - HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 - HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms - HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions - HasBMI1 bool // Bit manipulation instruction set 1 - HasBMI2 bool // Bit manipulation instruction set 2 - HasCX16 bool // Compare and exchange 16 Bytes - HasERMS bool // Enhanced REP for MOVSB and STOSB - HasFMA bool // Fused-multiply-add instructions - HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. - HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM - HasPOPCNT bool // Hamming weight instruction POPCNT. - HasRDRAND bool // RDRAND instruction (on-chip random number generator) - HasRDSEED bool // RDSEED instruction (on-chip random number generator) - HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) - HasSSE3 bool // Streaming SIMD extension 3 - HasSSSE3 bool // Supplemental streaming SIMD extension 3 - HasSSE41 bool // Streaming SIMD extension 4 and 4.1 - HasSSE42 bool // Streaming SIMD extension 4 and 4.2 - _ CacheLinePad -} - -// ARM64 contains the supported CPU features of the -// current ARMv8(aarch64) platform. If the current platform -// is not arm64 then all feature flags are false. -var ARM64 struct { - _ CacheLinePad - HasFP bool // Floating-point instruction set (always available) - HasASIMD bool // Advanced SIMD (always available) - HasEVTSTRM bool // Event stream support - HasAES bool // AES hardware implementation - HasPMULL bool // Polynomial multiplication instruction set - HasSHA1 bool // SHA1 hardware implementation - HasSHA2 bool // SHA2 hardware implementation - HasCRC32 bool // CRC32 hardware implementation - HasATOMICS bool // Atomic memory operation instruction set - HasFPHP bool // Half precision floating-point instruction set - HasASIMDHP bool // Advanced SIMD half precision instruction set - HasCPUID bool // CPUID identification scheme registers - HasASIMDRDM bool // Rounding double multiply add/subtract instruction set - HasJSCVT bool // Javascript conversion from floating-point to integer - HasFCMA bool // Floating-point multiplication and addition of complex numbers - HasLRCPC bool // Release Consistent processor consistent support - HasDCPOP bool // Persistent memory support - HasSHA3 bool // SHA3 hardware implementation - HasSM3 bool // SM3 hardware implementation - HasSM4 bool // SM4 hardware implementation - HasASIMDDP bool // Advanced SIMD double precision instruction set - HasSHA512 bool // SHA512 hardware implementation - HasSVE bool // Scalable Vector Extensions - HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 - _ CacheLinePad -} - -// ARM contains the supported CPU features of the current ARM (32-bit) platform. -// All feature flags are false if: -// 1. the current platform is not arm, or -// 2. the current operating system is not Linux. -var ARM struct { - _ CacheLinePad - HasSWP bool // SWP instruction support - HasHALF bool // Half-word load and store support - HasTHUMB bool // ARM Thumb instruction set - Has26BIT bool // Address space limited to 26-bits - HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support - HasFPA bool // Floating point arithmetic support - HasVFP bool // Vector floating point support - HasEDSP bool // DSP Extensions support - HasJAVA bool // Java instruction set - HasIWMMXT bool // Intel Wireless MMX technology support - HasCRUNCH bool // MaverickCrunch context switching and handling - HasTHUMBEE bool // Thumb EE instruction set - HasNEON bool // NEON instruction set - HasVFPv3 bool // Vector floating point version 3 support - HasVFPv3D16 bool // Vector floating point version 3 D8-D15 - HasTLS bool // Thread local storage support - HasVFPv4 bool // Vector floating point version 4 support - HasIDIVA bool // Integer divide instruction support in ARM mode - HasIDIVT bool // Integer divide instruction support in Thumb mode - HasVFPD32 bool // Vector floating point version 3 D15-D31 - HasLPAE bool // Large Physical Address Extensions - HasEVTSTRM bool // Event stream support - HasAES bool // AES hardware implementation - HasPMULL bool // Polynomial multiplication instruction set - HasSHA1 bool // SHA1 hardware implementation - HasSHA2 bool // SHA2 hardware implementation - HasCRC32 bool // CRC32 hardware implementation - _ CacheLinePad -} - -// MIPS64X contains the supported CPU features of the current mips64/mips64le -// platforms. If the current platform is not mips64/mips64le or the current -// operating system is not Linux then all feature flags are false. -var MIPS64X struct { - _ CacheLinePad - HasMSA bool // MIPS SIMD architecture - _ CacheLinePad -} - -// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. -// If the current platform is not ppc64/ppc64le then all feature flags are false. -// -// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, -// since there are no optional categories. There are some exceptions that also -// require kernel support to work (DARN, SCV), so there are feature bits for -// those as well. The struct is padded to avoid false sharing. -var PPC64 struct { - _ CacheLinePad - HasDARN bool // Hardware random number generator (requires kernel enablement) - HasSCV bool // Syscall vectored (requires kernel enablement) - IsPOWER8 bool // ISA v2.07 (POWER8) - IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 - _ CacheLinePad -} - -// S390X contains the supported CPU features of the current IBM Z -// (s390x) platform. If the current platform is not IBM Z then all -// feature flags are false. -// -// S390X is padded to avoid false sharing. Further HasVX is only set -// if the OS supports vector registers in addition to the STFLE -// feature bit being set. -var S390X struct { - _ CacheLinePad - HasZARCH bool // z/Architecture mode is active [mandatory] - HasSTFLE bool // store facility list extended - HasLDISP bool // long (20-bit) displacements - HasEIMM bool // 32-bit immediates - HasDFP bool // decimal floating point - HasETF3EH bool // ETF-3 enhanced - HasMSA bool // message security assist (CPACF) - HasAES bool // KM-AES{128,192,256} functions - HasAESCBC bool // KMC-AES{128,192,256} functions - HasAESCTR bool // KMCTR-AES{128,192,256} functions - HasAESGCM bool // KMA-GCM-AES{128,192,256} functions - HasGHASH bool // KIMD-GHASH function - HasSHA1 bool // K{I,L}MD-SHA-1 functions - HasSHA256 bool // K{I,L}MD-SHA-256 functions - HasSHA512 bool // K{I,L}MD-SHA-512 functions - HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions - HasVX bool // vector facility - HasVXE bool // vector-enhancements facility 1 - _ CacheLinePad -} - -func init() { - archInit() - initOptions() - processOptions() -} - -// options contains the cpu debug options that can be used in GODEBUG. -// Options are arch dependent and are added by the arch specific initOptions functions. -// Features that are mandatory for the specific GOARCH should have the Required field set -// (e.g. SSE2 on amd64). -var options []option - -// Option names should be lower case. e.g. avx instead of AVX. -type option struct { - Name string - Feature *bool - Specified bool // whether feature value was specified in GODEBUG - Enable bool // whether feature should be enabled - Required bool // whether feature is mandatory and can not be disabled -} - -func processOptions() { - env := os.Getenv("GODEBUG") -field: - for env != "" { - field := "" - i := strings.IndexByte(env, ',') - if i < 0 { - field, env = env, "" - } else { - field, env = env[:i], env[i+1:] - } - if len(field) < 4 || field[:4] != "cpu." { - continue - } - i = strings.IndexByte(field, '=') - if i < 0 { - print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") - continue - } - key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" - - var enable bool - switch value { - case "on": - enable = true - case "off": - enable = false - default: - print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") - continue field - } - - if key == "all" { - for i := range options { - options[i].Specified = true - options[i].Enable = enable || options[i].Required - } - continue field - } - - for i := range options { - if options[i].Name == key { - options[i].Specified = true - options[i].Enable = enable - continue field - } - } - - print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") - } - - for _, o := range options { - if !o.Specified { - continue - } - - if o.Enable && !*o.Feature { - print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") - continue - } - - if !o.Enable && o.Required { - print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") - continue - } - - *o.Feature = o.Enable - } -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_aix.go b/vendor/golang.org/x/sys/cpu/cpu_aix.go deleted file mode 100644 index 8aaeef54..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_aix.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix -// +build aix - -package cpu - -const ( - // getsystemcfg constants - _SC_IMPL = 2 - _IMPL_POWER8 = 0x10000 - _IMPL_POWER9 = 0x20000 -) - -func archInit() { - impl := getsystemcfg(_SC_IMPL) - if impl&_IMPL_POWER8 != 0 { - PPC64.IsPOWER8 = true - } - if impl&_IMPL_POWER9 != 0 { - PPC64.IsPOWER8 = true - PPC64.IsPOWER9 = true - } - - Initialized = true -} - -func getsystemcfg(label int) (n uint64) { - r0, _ := callgetsystemcfg(label) - n = uint64(r0) - return -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go deleted file mode 100644 index 301b752e..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_arm.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 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 cpu - -const cacheLineSize = 32 - -// HWCAP/HWCAP2 bits. -// These are specific to Linux. -const ( - hwcap_SWP = 1 << 0 - hwcap_HALF = 1 << 1 - hwcap_THUMB = 1 << 2 - hwcap_26BIT = 1 << 3 - hwcap_FAST_MULT = 1 << 4 - hwcap_FPA = 1 << 5 - hwcap_VFP = 1 << 6 - hwcap_EDSP = 1 << 7 - hwcap_JAVA = 1 << 8 - hwcap_IWMMXT = 1 << 9 - hwcap_CRUNCH = 1 << 10 - hwcap_THUMBEE = 1 << 11 - hwcap_NEON = 1 << 12 - hwcap_VFPv3 = 1 << 13 - hwcap_VFPv3D16 = 1 << 14 - hwcap_TLS = 1 << 15 - hwcap_VFPv4 = 1 << 16 - hwcap_IDIVA = 1 << 17 - hwcap_IDIVT = 1 << 18 - hwcap_VFPD32 = 1 << 19 - hwcap_LPAE = 1 << 20 - hwcap_EVTSTRM = 1 << 21 - - hwcap2_AES = 1 << 0 - hwcap2_PMULL = 1 << 1 - hwcap2_SHA1 = 1 << 2 - hwcap2_SHA2 = 1 << 3 - hwcap2_CRC32 = 1 << 4 -) - -func initOptions() { - options = []option{ - {Name: "pmull", Feature: &ARM.HasPMULL}, - {Name: "sha1", Feature: &ARM.HasSHA1}, - {Name: "sha2", Feature: &ARM.HasSHA2}, - {Name: "swp", Feature: &ARM.HasSWP}, - {Name: "thumb", Feature: &ARM.HasTHUMB}, - {Name: "thumbee", Feature: &ARM.HasTHUMBEE}, - {Name: "tls", Feature: &ARM.HasTLS}, - {Name: "vfp", Feature: &ARM.HasVFP}, - {Name: "vfpd32", Feature: &ARM.HasVFPD32}, - {Name: "vfpv3", Feature: &ARM.HasVFPv3}, - {Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16}, - {Name: "vfpv4", Feature: &ARM.HasVFPv4}, - {Name: "half", Feature: &ARM.HasHALF}, - {Name: "26bit", Feature: &ARM.Has26BIT}, - {Name: "fastmul", Feature: &ARM.HasFASTMUL}, - {Name: "fpa", Feature: &ARM.HasFPA}, - {Name: "edsp", Feature: &ARM.HasEDSP}, - {Name: "java", Feature: &ARM.HasJAVA}, - {Name: "iwmmxt", Feature: &ARM.HasIWMMXT}, - {Name: "crunch", Feature: &ARM.HasCRUNCH}, - {Name: "neon", Feature: &ARM.HasNEON}, - {Name: "idivt", Feature: &ARM.HasIDIVT}, - {Name: "idiva", Feature: &ARM.HasIDIVA}, - {Name: "lpae", Feature: &ARM.HasLPAE}, - {Name: "evtstrm", Feature: &ARM.HasEVTSTRM}, - {Name: "aes", Feature: &ARM.HasAES}, - {Name: "crc32", Feature: &ARM.HasCRC32}, - } - -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_arm64.go deleted file mode 100644 index 87dd5e30..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_arm64.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cpu - -import "runtime" - -const cacheLineSize = 64 - -func initOptions() { - options = []option{ - {Name: "fp", Feature: &ARM64.HasFP}, - {Name: "asimd", Feature: &ARM64.HasASIMD}, - {Name: "evstrm", Feature: &ARM64.HasEVTSTRM}, - {Name: "aes", Feature: &ARM64.HasAES}, - {Name: "fphp", Feature: &ARM64.HasFPHP}, - {Name: "jscvt", Feature: &ARM64.HasJSCVT}, - {Name: "lrcpc", Feature: &ARM64.HasLRCPC}, - {Name: "pmull", Feature: &ARM64.HasPMULL}, - {Name: "sha1", Feature: &ARM64.HasSHA1}, - {Name: "sha2", Feature: &ARM64.HasSHA2}, - {Name: "sha3", Feature: &ARM64.HasSHA3}, - {Name: "sha512", Feature: &ARM64.HasSHA512}, - {Name: "sm3", Feature: &ARM64.HasSM3}, - {Name: "sm4", Feature: &ARM64.HasSM4}, - {Name: "sve", Feature: &ARM64.HasSVE}, - {Name: "crc32", Feature: &ARM64.HasCRC32}, - {Name: "atomics", Feature: &ARM64.HasATOMICS}, - {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, - {Name: "cpuid", Feature: &ARM64.HasCPUID}, - {Name: "asimrdm", Feature: &ARM64.HasASIMDRDM}, - {Name: "fcma", Feature: &ARM64.HasFCMA}, - {Name: "dcpop", Feature: &ARM64.HasDCPOP}, - {Name: "asimddp", Feature: &ARM64.HasASIMDDP}, - {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, - } -} - -func archInit() { - switch runtime.GOOS { - case "freebsd": - readARM64Registers() - case "linux", "netbsd": - doinit() - default: - // Most platforms don't seem to allow reading these registers. - // - // OpenBSD: - // See https://golang.org/issue/31746 - setMinimalFeatures() - } -} - -// setMinimalFeatures fakes the minimal ARM64 features expected by -// TestARM64minimalFeatures. -func setMinimalFeatures() { - ARM64.HasASIMD = true - ARM64.HasFP = true -} - -func readARM64Registers() { - Initialized = true - - parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0()) -} - -func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { - // ID_AA64ISAR0_EL1 - switch extractBits(isar0, 4, 7) { - case 1: - ARM64.HasAES = true - case 2: - ARM64.HasAES = true - ARM64.HasPMULL = true - } - - switch extractBits(isar0, 8, 11) { - case 1: - ARM64.HasSHA1 = true - } - - switch extractBits(isar0, 12, 15) { - case 1: - ARM64.HasSHA2 = true - case 2: - ARM64.HasSHA2 = true - ARM64.HasSHA512 = true - } - - switch extractBits(isar0, 16, 19) { - case 1: - ARM64.HasCRC32 = true - } - - switch extractBits(isar0, 20, 23) { - case 2: - ARM64.HasATOMICS = true - } - - switch extractBits(isar0, 28, 31) { - case 1: - ARM64.HasASIMDRDM = true - } - - switch extractBits(isar0, 32, 35) { - case 1: - ARM64.HasSHA3 = true - } - - switch extractBits(isar0, 36, 39) { - case 1: - ARM64.HasSM3 = true - } - - switch extractBits(isar0, 40, 43) { - case 1: - ARM64.HasSM4 = true - } - - switch extractBits(isar0, 44, 47) { - case 1: - ARM64.HasASIMDDP = true - } - - // ID_AA64ISAR1_EL1 - switch extractBits(isar1, 0, 3) { - case 1: - ARM64.HasDCPOP = true - } - - switch extractBits(isar1, 12, 15) { - case 1: - ARM64.HasJSCVT = true - } - - switch extractBits(isar1, 16, 19) { - case 1: - ARM64.HasFCMA = true - } - - switch extractBits(isar1, 20, 23) { - case 1: - ARM64.HasLRCPC = true - } - - // ID_AA64PFR0_EL1 - switch extractBits(pfr0, 16, 19) { - case 0: - ARM64.HasFP = true - case 1: - ARM64.HasFP = true - ARM64.HasFPHP = true - } - - switch extractBits(pfr0, 20, 23) { - case 0: - ARM64.HasASIMD = true - case 1: - ARM64.HasASIMD = true - ARM64.HasASIMDHP = true - } - - switch extractBits(pfr0, 32, 35) { - case 1: - ARM64.HasSVE = true - } -} - -func extractBits(data uint64, start, end uint) uint { - return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_arm64.s deleted file mode 100644 index c61f95a0..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_arm64.s +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc -// +build gc - -#include "textflag.h" - -// func getisar0() uint64 -TEXT ·getisar0(SB),NOSPLIT,$0-8 - // get Instruction Set Attributes 0 into x0 - // mrs x0, ID_AA64ISAR0_EL1 = d5380600 - WORD $0xd5380600 - MOVD R0, ret+0(FP) - RET - -// func getisar1() uint64 -TEXT ·getisar1(SB),NOSPLIT,$0-8 - // get Instruction Set Attributes 1 into x0 - // mrs x0, ID_AA64ISAR1_EL1 = d5380620 - WORD $0xd5380620 - MOVD R0, ret+0(FP) - RET - -// func getpfr0() uint64 -TEXT ·getpfr0(SB),NOSPLIT,$0-8 - // get Processor Feature Register 0 into x0 - // mrs x0, ID_AA64PFR0_EL1 = d5380400 - WORD $0xd5380400 - MOVD R0, ret+0(FP) - RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go deleted file mode 100644 index ccf542a7..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc -// +build gc - -package cpu - -func getisar0() uint64 -func getisar1() uint64 -func getpfr0() uint64 diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go deleted file mode 100644 index 0af2f248..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc -// +build gc - -package cpu - -// haveAsmFunctions reports whether the other functions in this file can -// be safely called. -func haveAsmFunctions() bool { return true } - -// The following feature detection functions are defined in cpu_s390x.s. -// They are likely to be expensive to call so the results should be cached. -func stfle() facilityList -func kmQuery() queryResult -func kmcQuery() queryResult -func kmctrQuery() queryResult -func kmaQuery() queryResult -func kimdQuery() queryResult -func klmdQuery() queryResult diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go deleted file mode 100644 index fa7cdb9b..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 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. - -//go:build (386 || amd64 || amd64p32) && gc -// +build 386 amd64 amd64p32 -// +build gc - -package cpu - -// cpuid is implemented in cpu_x86.s for gc compiler -// and in cpu_gccgo.c for gccgo. -func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) - -// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler -// and in cpu_gccgo.c for gccgo. -func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go deleted file mode 100644 index 2aff3189..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gccgo -// +build gccgo - -package cpu - -func getisar0() uint64 { return 0 } -func getisar1() uint64 { return 0 } -func getpfr0() uint64 { return 0 } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go deleted file mode 100644 index 4bfbda61..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gccgo -// +build gccgo - -package cpu - -// haveAsmFunctions reports whether the other functions in this file can -// be safely called. -func haveAsmFunctions() bool { return false } - -// TODO(mundaym): the following feature detection functions are currently -// stubs. See https://golang.org/cl/162887 for how to fix this. -// They are likely to be expensive to call so the results should be cached. -func stfle() facilityList { panic("not implemented for gccgo") } -func kmQuery() queryResult { panic("not implemented for gccgo") } -func kmcQuery() queryResult { panic("not implemented for gccgo") } -func kmctrQuery() queryResult { panic("not implemented for gccgo") } -func kmaQuery() queryResult { panic("not implemented for gccgo") } -func kimdQuery() queryResult { panic("not implemented for gccgo") } -func klmdQuery() queryResult { panic("not implemented for gccgo") } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c deleted file mode 100644 index a4605e6d..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 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 386 amd64 amd64p32 -// +build gccgo - -#include -#include -#include - -// Need to wrap __get_cpuid_count because it's declared as static. -int -gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, - uint32_t *eax, uint32_t *ebx, - uint32_t *ecx, uint32_t *edx) -{ - return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); -} - -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#pragma GCC push_options -#pragma GCC target("xsave") -#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function) - -// xgetbv reads the contents of an XCR (Extended Control Register) -// specified in the ECX register into registers EDX:EAX. -// Currently, the only supported value for XCR is 0. -void -gccgoXgetbv(uint32_t *eax, uint32_t *edx) -{ - uint64_t v = _xgetbv(0); - *eax = v & 0xffffffff; - *edx = v >> 32; -} - -#pragma clang attribute pop -#pragma GCC pop_options diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go deleted file mode 100644 index 863d415a..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 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. - -//go:build (386 || amd64 || amd64p32) && gccgo -// +build 386 amd64 amd64p32 -// +build gccgo - -package cpu - -//extern gccgoGetCpuidCount -func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) - -func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { - var a, b, c, d uint32 - gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) - return a, b, c, d -} - -//extern gccgoXgetbv -func gccgoXgetbv(eax, edx *uint32) - -func xgetbv() (eax, edx uint32) { - var a, d uint32 - gccgoXgetbv(&a, &d) - return a, d -} - -// gccgo doesn't build on Darwin, per: -// https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76 -func darwinSupportsAVX512() bool { - return false -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/golang.org/x/sys/cpu/cpu_linux.go deleted file mode 100644 index 159a686f..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 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. - -//go:build !386 && !amd64 && !amd64p32 && !arm64 -// +build !386,!amd64,!amd64p32,!arm64 - -package cpu - -func archInit() { - if err := readHWCAP(); err != nil { - return - } - doinit() - Initialized = true -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go deleted file mode 100644 index 2057006d..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cpu - -func doinit() { - ARM.HasSWP = isSet(hwCap, hwcap_SWP) - ARM.HasHALF = isSet(hwCap, hwcap_HALF) - ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB) - ARM.Has26BIT = isSet(hwCap, hwcap_26BIT) - ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT) - ARM.HasFPA = isSet(hwCap, hwcap_FPA) - ARM.HasVFP = isSet(hwCap, hwcap_VFP) - ARM.HasEDSP = isSet(hwCap, hwcap_EDSP) - ARM.HasJAVA = isSet(hwCap, hwcap_JAVA) - ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT) - ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH) - ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE) - ARM.HasNEON = isSet(hwCap, hwcap_NEON) - ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3) - ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16) - ARM.HasTLS = isSet(hwCap, hwcap_TLS) - ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4) - ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA) - ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT) - ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32) - ARM.HasLPAE = isSet(hwCap, hwcap_LPAE) - ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) - ARM.HasAES = isSet(hwCap2, hwcap2_AES) - ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL) - ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1) - ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2) - ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32) -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go deleted file mode 100644 index 79a38a0b..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018 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 cpu - -// HWCAP/HWCAP2 bits. These are exposed by Linux. -const ( - hwcap_FP = 1 << 0 - hwcap_ASIMD = 1 << 1 - hwcap_EVTSTRM = 1 << 2 - hwcap_AES = 1 << 3 - hwcap_PMULL = 1 << 4 - hwcap_SHA1 = 1 << 5 - hwcap_SHA2 = 1 << 6 - hwcap_CRC32 = 1 << 7 - hwcap_ATOMICS = 1 << 8 - hwcap_FPHP = 1 << 9 - hwcap_ASIMDHP = 1 << 10 - hwcap_CPUID = 1 << 11 - hwcap_ASIMDRDM = 1 << 12 - hwcap_JSCVT = 1 << 13 - hwcap_FCMA = 1 << 14 - hwcap_LRCPC = 1 << 15 - hwcap_DCPOP = 1 << 16 - hwcap_SHA3 = 1 << 17 - hwcap_SM3 = 1 << 18 - hwcap_SM4 = 1 << 19 - hwcap_ASIMDDP = 1 << 20 - hwcap_SHA512 = 1 << 21 - hwcap_SVE = 1 << 22 - hwcap_ASIMDFHM = 1 << 23 -) - -func doinit() { - if err := readHWCAP(); err != nil { - // failed to read /proc/self/auxv, try reading registers directly - readARM64Registers() - return - } - - // HWCAP feature bits - ARM64.HasFP = isSet(hwCap, hwcap_FP) - ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) - ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) - ARM64.HasAES = isSet(hwCap, hwcap_AES) - ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL) - ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1) - ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2) - ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32) - ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS) - ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP) - ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP) - ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID) - ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM) - ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT) - ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA) - ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC) - ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP) - ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3) - ARM64.HasSM3 = isSet(hwCap, hwcap_SM3) - ARM64.HasSM4 = isSet(hwCap, hwcap_SM4) - ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP) - ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) - ARM64.HasSVE = isSet(hwCap, hwcap_SVE) - ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go deleted file mode 100644 index 6000db4c..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2020 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. - -//go:build linux && (mips64 || mips64le) -// +build linux -// +build mips64 mips64le - -package cpu - -// HWCAP bits. These are exposed by the Linux kernel 5.4. -const ( - // CPU features - hwcap_MIPS_MSA = 1 << 1 -) - -func doinit() { - // HWCAP feature bits - MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA) -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go deleted file mode 100644 index f4992b1a..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x -// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x - -package cpu - -func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go deleted file mode 100644 index 021356d6..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2018 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. - -//go:build linux && (ppc64 || ppc64le) -// +build linux -// +build ppc64 ppc64le - -package cpu - -// HWCAP/HWCAP2 bits. These are exposed by the kernel. -const ( - // ISA Level - _PPC_FEATURE2_ARCH_2_07 = 0x80000000 - _PPC_FEATURE2_ARCH_3_00 = 0x00800000 - - // CPU features - _PPC_FEATURE2_DARN = 0x00200000 - _PPC_FEATURE2_SCV = 0x00100000 -) - -func doinit() { - // HWCAP2 feature bits - PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07) - PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00) - PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN) - PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV) -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go deleted file mode 100644 index 1517ac61..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cpu - -const ( - // bit mask values from /usr/include/bits/hwcap.h - hwcap_ZARCH = 2 - hwcap_STFLE = 4 - hwcap_MSA = 8 - hwcap_LDISP = 16 - hwcap_EIMM = 32 - hwcap_DFP = 64 - hwcap_ETF3EH = 256 - hwcap_VX = 2048 - hwcap_VXE = 8192 -) - -func initS390Xbase() { - // test HWCAP bit vector - has := func(featureMask uint) bool { - return hwCap&featureMask == featureMask - } - - // mandatory - S390X.HasZARCH = has(hwcap_ZARCH) - - // optional - S390X.HasSTFLE = has(hwcap_STFLE) - S390X.HasLDISP = has(hwcap_LDISP) - S390X.HasEIMM = has(hwcap_EIMM) - S390X.HasETF3EH = has(hwcap_ETF3EH) - S390X.HasDFP = has(hwcap_DFP) - S390X.HasMSA = has(hwcap_MSA) - S390X.HasVX = has(hwcap_VX) - if S390X.HasVX { - S390X.HasVXE = has(hwcap_VXE) - } -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_loong64.go deleted file mode 100644 index 0f57b05b..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_loong64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2022 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. - -//go:build loong64 -// +build loong64 - -package cpu - -const cacheLineSize = 64 - -func initOptions() { -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go deleted file mode 100644 index f4063c66..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 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. - -//go:build mips64 || mips64le -// +build mips64 mips64le - -package cpu - -const cacheLineSize = 32 - -func initOptions() { - options = []option{ - {Name: "msa", Feature: &MIPS64X.HasMSA}, - } -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go deleted file mode 100644 index 07c4e36d..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018 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. - -//go:build mips || mipsle -// +build mips mipsle - -package cpu - -const cacheLineSize = 32 - -func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go deleted file mode 100644 index ebfb3fc8..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2020 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 cpu - -import ( - "syscall" - "unsafe" -) - -// Minimal copy of functionality from x/sys/unix so the cpu package can call -// sysctl without depending on x/sys/unix. - -const ( - _CTL_QUERY = -2 - - _SYSCTL_VERS_1 = 0x1000000 -) - -var _zero uintptr - -func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, errno := syscall.Syscall6( - syscall.SYS___SYSCTL, - uintptr(_p0), - uintptr(len(mib)), - uintptr(unsafe.Pointer(old)), - uintptr(unsafe.Pointer(oldlen)), - uintptr(unsafe.Pointer(new)), - uintptr(newlen)) - if errno != 0 { - return errno - } - return nil -} - -type sysctlNode struct { - Flags uint32 - Num int32 - Name [32]int8 - Ver uint32 - __rsvd uint32 - Un [16]byte - _sysctl_size [8]byte - _sysctl_func [8]byte - _sysctl_parent [8]byte - _sysctl_desc [8]byte -} - -func sysctlNodes(mib []int32) ([]sysctlNode, error) { - var olen uintptr - - // Get a list of all sysctl nodes below the given MIB by performing - // a sysctl for the given MIB with CTL_QUERY appended. - mib = append(mib, _CTL_QUERY) - qnode := sysctlNode{Flags: _SYSCTL_VERS_1} - qp := (*byte)(unsafe.Pointer(&qnode)) - sz := unsafe.Sizeof(qnode) - if err := sysctl(mib, nil, &olen, qp, sz); err != nil { - return nil, err - } - - // Now that we know the size, get the actual nodes. - nodes := make([]sysctlNode, olen/sz) - np := (*byte)(unsafe.Pointer(&nodes[0])) - if err := sysctl(mib, np, &olen, qp, sz); err != nil { - return nil, err - } - - return nodes, nil -} - -func nametomib(name string) ([]int32, error) { - // Split name into components. - var parts []string - last := 0 - for i := 0; i < len(name); i++ { - if name[i] == '.' { - parts = append(parts, name[last:i]) - last = i + 1 - } - } - parts = append(parts, name[last:]) - - mib := []int32{} - // Discover the nodes and construct the MIB OID. - for partno, part := range parts { - nodes, err := sysctlNodes(mib) - if err != nil { - return nil, err - } - for _, node := range nodes { - n := make([]byte, 0) - for i := range node.Name { - if node.Name[i] != 0 { - n = append(n, byte(node.Name[i])) - } - } - if string(n) == part { - mib = append(mib, int32(node.Num)) - break - } - } - if len(mib) != partno+1 { - return nil, err - } - } - - return mib, nil -} - -// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's -type aarch64SysctlCPUID struct { - midr uint64 /* Main ID Register */ - revidr uint64 /* Revision ID Register */ - mpidr uint64 /* Multiprocessor Affinity Register */ - aa64dfr0 uint64 /* A64 Debug Feature Register 0 */ - aa64dfr1 uint64 /* A64 Debug Feature Register 1 */ - aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */ - aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */ - aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */ - aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */ - aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */ - aa64pfr0 uint64 /* A64 Processor Feature Register 0 */ - aa64pfr1 uint64 /* A64 Processor Feature Register 1 */ - aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */ - mvfr0 uint32 /* Media and VFP Feature Register 0 */ - mvfr1 uint32 /* Media and VFP Feature Register 1 */ - mvfr2 uint32 /* Media and VFP Feature Register 2 */ - pad uint32 - clidr uint64 /* Cache Level ID Register */ - ctr uint64 /* Cache Type Register */ -} - -func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) { - mib, err := nametomib(name) - if err != nil { - return nil, err - } - - out := aarch64SysctlCPUID{} - n := unsafe.Sizeof(out) - _, _, errno := syscall.Syscall6( - syscall.SYS___SYSCTL, - uintptr(unsafe.Pointer(&mib[0])), - uintptr(len(mib)), - uintptr(unsafe.Pointer(&out)), - uintptr(unsafe.Pointer(&n)), - uintptr(0), - uintptr(0)) - if errno != 0 { - return nil, errno - } - return &out, nil -} - -func doinit() { - cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id") - if err != nil { - setMinimalFeatures() - return - } - parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0) - - Initialized = true -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go deleted file mode 100644 index d7b4fb4c..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_other_arm.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2020 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. - -//go:build !linux && arm -// +build !linux,arm - -package cpu - -func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go deleted file mode 100644 index f8c484f5..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !linux && !netbsd && arm64 -// +build !linux,!netbsd,arm64 - -package cpu - -func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go deleted file mode 100644 index 0dafe964..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2020 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. - -//go:build !linux && (mips64 || mips64le) -// +build !linux -// +build mips64 mips64le - -package cpu - -func archInit() { - Initialized = true -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go deleted file mode 100644 index dd10eb79..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2022 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. - -//go:build !linux && riscv64 -// +build !linux,riscv64 - -package cpu - -func archInit() { - Initialized = true -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go deleted file mode 100644 index 4e8acd16..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020 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. - -//go:build ppc64 || ppc64le -// +build ppc64 ppc64le - -package cpu - -const cacheLineSize = 128 - -func initOptions() { - options = []option{ - {Name: "darn", Feature: &PPC64.HasDARN}, - {Name: "scv", Feature: &PPC64.HasSCV}, - } -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go deleted file mode 100644 index bd6c128a..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build riscv64 -// +build riscv64 - -package cpu - -const cacheLineSize = 32 - -func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_s390x.go deleted file mode 100644 index 5881b883..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_s390x.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2020 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 cpu - -const cacheLineSize = 256 - -func initOptions() { - options = []option{ - {Name: "zarch", Feature: &S390X.HasZARCH, Required: true}, - {Name: "stfle", Feature: &S390X.HasSTFLE, Required: true}, - {Name: "ldisp", Feature: &S390X.HasLDISP, Required: true}, - {Name: "eimm", Feature: &S390X.HasEIMM, Required: true}, - {Name: "dfp", Feature: &S390X.HasDFP}, - {Name: "etf3eh", Feature: &S390X.HasETF3EH}, - {Name: "msa", Feature: &S390X.HasMSA}, - {Name: "aes", Feature: &S390X.HasAES}, - {Name: "aescbc", Feature: &S390X.HasAESCBC}, - {Name: "aesctr", Feature: &S390X.HasAESCTR}, - {Name: "aesgcm", Feature: &S390X.HasAESGCM}, - {Name: "ghash", Feature: &S390X.HasGHASH}, - {Name: "sha1", Feature: &S390X.HasSHA1}, - {Name: "sha256", Feature: &S390X.HasSHA256}, - {Name: "sha3", Feature: &S390X.HasSHA3}, - {Name: "sha512", Feature: &S390X.HasSHA512}, - {Name: "vx", Feature: &S390X.HasVX}, - {Name: "vxe", Feature: &S390X.HasVXE}, - } -} - -// bitIsSet reports whether the bit at index is set. The bit index -// is in big endian order, so bit index 0 is the leftmost bit. -func bitIsSet(bits []uint64, index uint) bool { - return bits[index/64]&((1<<63)>>(index%64)) != 0 -} - -// facility is a bit index for the named facility. -type facility uint8 - -const ( - // mandatory facilities - zarch facility = 1 // z architecture mode is active - stflef facility = 7 // store-facility-list-extended - ldisp facility = 18 // long-displacement - eimm facility = 21 // extended-immediate - - // miscellaneous facilities - dfp facility = 42 // decimal-floating-point - etf3eh facility = 30 // extended-translation 3 enhancement - - // cryptography facilities - msa facility = 17 // message-security-assist - msa3 facility = 76 // message-security-assist extension 3 - msa4 facility = 77 // message-security-assist extension 4 - msa5 facility = 57 // message-security-assist extension 5 - msa8 facility = 146 // message-security-assist extension 8 - msa9 facility = 155 // message-security-assist extension 9 - - // vector facilities - vx facility = 129 // vector facility - vxe facility = 135 // vector-enhancements 1 - vxe2 facility = 148 // vector-enhancements 2 -) - -// facilityList contains the result of an STFLE call. -// Bits are numbered in big endian order so the -// leftmost bit (the MSB) is at index 0. -type facilityList struct { - bits [4]uint64 -} - -// Has reports whether the given facilities are present. -func (s *facilityList) Has(fs ...facility) bool { - if len(fs) == 0 { - panic("no facility bits provided") - } - for _, f := range fs { - if !bitIsSet(s.bits[:], uint(f)) { - return false - } - } - return true -} - -// function is the code for the named cryptographic function. -type function uint8 - -const ( - // KM{,A,C,CTR} function codes - aes128 function = 18 // AES-128 - aes192 function = 19 // AES-192 - aes256 function = 20 // AES-256 - - // K{I,L}MD function codes - sha1 function = 1 // SHA-1 - sha256 function = 2 // SHA-256 - sha512 function = 3 // SHA-512 - sha3_224 function = 32 // SHA3-224 - sha3_256 function = 33 // SHA3-256 - sha3_384 function = 34 // SHA3-384 - sha3_512 function = 35 // SHA3-512 - shake128 function = 36 // SHAKE-128 - shake256 function = 37 // SHAKE-256 - - // KLMD function codes - ghash function = 65 // GHASH -) - -// queryResult contains the result of a Query function -// call. Bits are numbered in big endian order so the -// leftmost bit (the MSB) is at index 0. -type queryResult struct { - bits [2]uint64 -} - -// Has reports whether the given functions are present. -func (q *queryResult) Has(fns ...function) bool { - if len(fns) == 0 { - panic("no function codes provided") - } - for _, f := range fns { - if !bitIsSet(q.bits[:], uint(f)) { - return false - } - } - return true -} - -func doinit() { - initS390Xbase() - - // We need implementations of stfle, km and so on - // to detect cryptographic features. - if !haveAsmFunctions() { - return - } - - // optional cryptographic functions - if S390X.HasMSA { - aes := []function{aes128, aes192, aes256} - - // cipher message - km, kmc := kmQuery(), kmcQuery() - S390X.HasAES = km.Has(aes...) - S390X.HasAESCBC = kmc.Has(aes...) - if S390X.HasSTFLE { - facilities := stfle() - if facilities.Has(msa4) { - kmctr := kmctrQuery() - S390X.HasAESCTR = kmctr.Has(aes...) - } - if facilities.Has(msa8) { - kma := kmaQuery() - S390X.HasAESGCM = kma.Has(aes...) - } - } - - // compute message digest - kimd := kimdQuery() // intermediate (no padding) - klmd := klmdQuery() // last (padding) - S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) - S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) - S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) - S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist - sha3 := []function{ - sha3_224, sha3_256, sha3_384, sha3_512, - shake128, shake256, - } - S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) - } -} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/vendor/golang.org/x/sys/cpu/cpu_s390x.s deleted file mode 100644 index 96f81e20..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_s390x.s +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc -// +build gc - -#include "textflag.h" - -// func stfle() facilityList -TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 - MOVD $ret+0(FP), R1 - MOVD $3, R0 // last doubleword index to store - XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) - WORD $0xb2b01000 // store facility list extended (STFLE) - RET - -// func kmQuery() queryResult -TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KM-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - WORD $0xB92E0024 // cipher message (KM) - RET - -// func kmcQuery() queryResult -TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KMC-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - WORD $0xB92F0024 // cipher message with chaining (KMC) - RET - -// func kmctrQuery() queryResult -TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KMCTR-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - WORD $0xB92D4024 // cipher message with counter (KMCTR) - RET - -// func kmaQuery() queryResult -TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KMA-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - WORD $0xb9296024 // cipher message with authentication (KMA) - RET - -// func kimdQuery() queryResult -TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KIMD-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - WORD $0xB93E0024 // compute intermediate message digest (KIMD) - RET - -// func klmdQuery() queryResult -TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KLMD-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - WORD $0xB93F0024 // compute last message digest (KLMD) - RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/vendor/golang.org/x/sys/cpu/cpu_wasm.go deleted file mode 100644 index 7747d888..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_wasm.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build wasm -// +build wasm - -package cpu - -// We're compiling the cpu package for an unknown (software-abstracted) CPU. -// Make CacheLinePad an empty struct and hope that the usual struct alignment -// rules are good enough. - -const cacheLineSize = 0 - -func initOptions() {} - -func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go deleted file mode 100644 index f5aacfc8..00000000 --- a/vendor/golang.org/x/sys/cpu/cpu_x86.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2018 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. - -//go:build 386 || amd64 || amd64p32 -// +build 386 amd64 amd64p32 - -package cpu - -import "runtime" - -const cacheLineSize = 64 - -func initOptions() { - options = []option{ - {Name: "adx", Feature: &X86.HasADX}, - {Name: "aes", Feature: &X86.HasAES}, - {Name: "avx", Feature: &X86.HasAVX}, - {Name: "avx2", Feature: &X86.HasAVX2}, - {Name: "avx512", Feature: &X86.HasAVX512}, - {Name: "avx512f", Feature: &X86.HasAVX512F}, - {Name: "avx512cd", Feature: &X86.HasAVX512CD}, - {Name: "avx512er", Feature: &X86.HasAVX512ER}, - {Name: "avx512pf", Feature: &X86.HasAVX512PF}, - {Name: "avx512vl", Feature: &X86.HasAVX512VL}, - {Name: "avx512bw", Feature: &X86.HasAVX512BW}, - {Name: "avx512dq", Feature: &X86.HasAVX512DQ}, - {Name: "avx512ifma", Feature: &X86.HasAVX512IFMA}, - {Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI}, - {Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW}, - {Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS}, - {Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ}, - {Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ}, - {Name: "avx512vnni", Feature: &X86.HasAVX512VNNI}, - {Name: "avx512gfni", Feature: &X86.HasAVX512GFNI}, - {Name: "avx512vaes", Feature: &X86.HasAVX512VAES}, - {Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2}, - {Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG}, - {Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, - {Name: "bmi1", Feature: &X86.HasBMI1}, - {Name: "bmi2", Feature: &X86.HasBMI2}, - {Name: "cx16", Feature: &X86.HasCX16}, - {Name: "erms", Feature: &X86.HasERMS}, - {Name: "fma", Feature: &X86.HasFMA}, - {Name: "osxsave", Feature: &X86.HasOSXSAVE}, - {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, - {Name: "popcnt", Feature: &X86.HasPOPCNT}, - {Name: "rdrand", Feature: &X86.HasRDRAND}, - {Name: "rdseed", Feature: &X86.HasRDSEED}, - {Name: "sse3", Feature: &X86.HasSSE3}, - {Name: "sse41", Feature: &X86.HasSSE41}, - {Name: "sse42", Feature: &X86.HasSSE42}, - {Name: "ssse3", Feature: &X86.HasSSSE3}, - - // These capabilities should always be enabled on amd64: - {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, - } -} - -func archInit() { - - Initialized = true - - maxID, _, _, _ := cpuid(0, 0) - - if maxID < 1 { - return - } - - _, _, ecx1, edx1 := cpuid(1, 0) - X86.HasSSE2 = isSet(26, edx1) - - X86.HasSSE3 = isSet(0, ecx1) - X86.HasPCLMULQDQ = isSet(1, ecx1) - X86.HasSSSE3 = isSet(9, ecx1) - X86.HasFMA = isSet(12, ecx1) - X86.HasCX16 = isSet(13, ecx1) - X86.HasSSE41 = isSet(19, ecx1) - X86.HasSSE42 = isSet(20, ecx1) - X86.HasPOPCNT = isSet(23, ecx1) - X86.HasAES = isSet(25, ecx1) - X86.HasOSXSAVE = isSet(27, ecx1) - X86.HasRDRAND = isSet(30, ecx1) - - var osSupportsAVX, osSupportsAVX512 bool - // For XGETBV, OSXSAVE bit is required and sufficient. - if X86.HasOSXSAVE { - eax, _ := xgetbv() - // Check if XMM and YMM registers have OS support. - osSupportsAVX = isSet(1, eax) && isSet(2, eax) - - if runtime.GOOS == "darwin" { - // Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers. - // Since users can't rely on mask register contents, let's not advertise AVX-512 support. - // See issue 49233. - osSupportsAVX512 = false - } else { - // Check if OPMASK and ZMM registers have OS support. - osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) - } - } - - X86.HasAVX = isSet(28, ecx1) && osSupportsAVX - - if maxID < 7 { - return - } - - _, ebx7, ecx7, edx7 := cpuid(7, 0) - X86.HasBMI1 = isSet(3, ebx7) - X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX - X86.HasBMI2 = isSet(8, ebx7) - X86.HasERMS = isSet(9, ebx7) - X86.HasRDSEED = isSet(18, ebx7) - X86.HasADX = isSet(19, ebx7) - - X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension - if X86.HasAVX512 { - X86.HasAVX512F = true - X86.HasAVX512CD = isSet(28, ebx7) - X86.HasAVX512ER = isSet(27, ebx7) - X86.HasAVX512PF = isSet(26, ebx7) - X86.HasAVX512VL = isSet(31, ebx7) - X86.HasAVX512BW = isSet(30, ebx7) - X86.HasAVX512DQ = isSet(17, ebx7) - X86.HasAVX512IFMA = isSet(21, ebx7) - X86.HasAVX512VBMI = isSet(1, ecx7) - X86.HasAVX5124VNNIW = isSet(2, edx7) - X86.HasAVX5124FMAPS = isSet(3, edx7) - X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) - X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) - X86.HasAVX512VNNI = isSet(11, ecx7) - X86.HasAVX512GFNI = isSet(8, ecx7) - X86.HasAVX512VAES = isSet(9, ecx7) - X86.HasAVX512VBMI2 = isSet(6, ecx7) - X86.HasAVX512BITALG = isSet(12, ecx7) - - eax71, _, _, _ := cpuid(7, 1) - X86.HasAVX512BF16 = isSet(5, eax71) - } -} - -func isSet(bitpos uint, value uint32) bool { - return value&(1<> 63)) -) - -// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 -// These are initialized in cpu_$GOARCH.go -// and should not be changed after they are initialized. -var hwCap uint -var hwCap2 uint - -func readHWCAP() error { - buf, err := ioutil.ReadFile(procAuxv) - if err != nil { - // e.g. on android /proc/self/auxv is not accessible, so silently - // ignore the error and leave Initialized = false. On some - // architectures (e.g. arm64) doinit() implements a fallback - // readout and will set Initialized = true again. - return err - } - bo := hostByteOrder() - for len(buf) >= 2*(uintSize/8) { - var tag, val uint - switch uintSize { - case 32: - tag = uint(bo.Uint32(buf[0:])) - val = uint(bo.Uint32(buf[4:])) - buf = buf[8:] - case 64: - tag = uint(bo.Uint64(buf[0:])) - val = uint(bo.Uint64(buf[8:])) - buf = buf[16:] - } - switch tag { - case _AT_HWCAP: - hwCap = val - case _AT_HWCAP2: - hwCap2 = val - } - } - return nil -} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go deleted file mode 100644 index 96134157..00000000 --- a/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2020 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. - -// Recreate a getsystemcfg syscall handler instead of -// using the one provided by x/sys/unix to avoid having -// the dependency between them. (See golang.org/issue/32102) -// Moreover, this file will be used during the building of -// gccgo's libgo and thus must not used a CGo method. - -//go:build aix && gccgo -// +build aix,gccgo - -package cpu - -import ( - "syscall" -) - -//extern getsystemcfg -func gccgoGetsystemcfg(label uint32) (r uint64) - -func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { - r1 = uintptr(gccgoGetsystemcfg(uint32(label))) - e1 = syscall.GetErrno() - return -} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go deleted file mode 100644 index 904be42f..00000000 --- a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Minimal copy of x/sys/unix so the cpu package can make a -// system call on AIX without depending on x/sys/unix. -// (See golang.org/issue/32102) - -//go:build aix && ppc64 && gc -// +build aix,ppc64,gc - -package cpu - -import ( - "syscall" - "unsafe" -) - -//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o" - -//go:linkname libc_getsystemcfg libc_getsystemcfg - -type syscallFunc uintptr - -var libc_getsystemcfg syscallFunc - -type errno = syscall.Errno - -// Implemented in runtime/syscall_aix.go. -func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) -func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) - -func callgetsystemcfg(label int) (r1 uintptr, e1 errno) { - r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0) - return -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/.gitignore b/vendor/gopkg.in/src-d/go-billy.v4/.gitignore deleted file mode 100644 index 7aeb4669..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/coverage.txt -/vendor -Gopkg.lock -Gopkg.toml diff --git a/vendor/gopkg.in/src-d/go-billy.v4/.travis.yml b/vendor/gopkg.in/src-d/go-billy.v4/.travis.yml deleted file mode 100644 index a70b470d..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: go - -go: - - 1.9.x - - 1.10.x - -go_import_path: gopkg.in/src-d/go-billy.v4 - -install: - - go get -v -t ./... - -script: - - make test-coverage - - ./.ci/test-building-binaries-for-supported-os.sh - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/gopkg.in/src-d/go-billy.v4/DCO b/vendor/gopkg.in/src-d/go-billy.v4/DCO deleted file mode 100644 index 29c1b920..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/DCO +++ /dev/null @@ -1,25 +0,0 @@ - Developer's Certificate of Origin 1.1 - - By making a contribution to this project, I certify that: - - (a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - - (b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - - (c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - - (d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. diff --git a/vendor/gopkg.in/src-d/go-billy.v4/LICENSE b/vendor/gopkg.in/src-d/go-billy.v4/LICENSE deleted file mode 100644 index 9d607568..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/LICENSE +++ /dev/null @@ -1,201 +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 - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 Sourced Technologies S.L. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS b/vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS deleted file mode 100644 index 8dbba477..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS +++ /dev/null @@ -1 +0,0 @@ -Máximo Cuadros (@mcuadros) diff --git a/vendor/gopkg.in/src-d/go-billy.v4/Makefile b/vendor/gopkg.in/src-d/go-billy.v4/Makefile deleted file mode 100644 index 19e74337..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# General -WORKDIR = $(PWD) - -# Go parameters -GOCMD = go -GOTEST = $(GOCMD) test -v - -# Coverage -COVERAGE_REPORT = coverage.txt -COVERAGE_PROFILE = profile.out -COVERAGE_MODE = atomic - -test-coverage: - cd $(WORKDIR); \ - echo "" > $(COVERAGE_REPORT); \ - for dir in `find . -name "*.go" | grep -o '.*/' | sort | uniq`; do \ - $(GOTEST) $$dir -coverprofile=$(COVERAGE_PROFILE) -covermode=$(COVERAGE_MODE); \ - if [ $$? != 0 ]; then \ - exit 2; \ - fi; \ - if [ -f $(COVERAGE_PROFILE) ]; then \ - cat $(COVERAGE_PROFILE) >> $(COVERAGE_REPORT); \ - rm $(COVERAGE_PROFILE); \ - fi; \ - done; \ diff --git a/vendor/gopkg.in/src-d/go-billy.v4/README.md b/vendor/gopkg.in/src-d/go-billy.v4/README.md deleted file mode 100644 index ae4a3f86..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# go-billy [![GoDoc](https://godoc.org/gopkg.in/src-d/go-billy.v4?status.svg)](https://godoc.org/gopkg.in/src-d/go-billy.v4) [![Build Status](https://travis-ci.com/src-d/go-billy.svg)](https://travis-ci.com/src-d/go-billy) [![Build status](https://ci.appveyor.com/api/projects/status/vx2qn6vlakbi724t?svg=true)](https://ci.appveyor.com/project/mcuadros/go-billy) [![codecov](https://codecov.io/gh/src-d/go-billy/branch/master/graph/badge.svg)](https://codecov.io/gh/src-d/go-billy) - -The missing interface filesystem abstraction for Go. -Billy implements an interface based on the `os` standard library, allowing to develop applications without dependency on the underlying storage. Makes it virtually free to implement mocks and testing over filesystem operations. - -Billy was born as part of [src-d/go-git](https://github.com/src-d/go-git) project. - -## Installation - -```go -go get -u gopkg.in/src-d/go-billy.v4/... -``` - -## Usage - -Billy exposes filesystems using the -[`Filesystem` interface](https://godoc.org/github.com/src-d/go-billy#Filesystem). -Each filesystem implementation gives you a `New` method, whose arguments depend on -the implementation itself, that returns a new `Filesystem`. - -The following example caches in memory all readable files in a directory from any -billy's filesystem implementation. - -```go -func LoadToMemory(origin billy.Filesystem, path string) (*memory.Memory, error) { - memory := memory.New() - - files, err := origin.ReadDir("/") - if err != nil { - return nil, err - } - - for _, file := range files { - if file.IsDir() { - continue - } - - src, err := origin.Open(file.Name()) - if err != nil { - return nil, err - } - - dst, err := memory.Create(file.Name()) - if err != nil { - return nil, err - } - - if _, err = io.Copy(dst, src); err != nil { - return nil, err - } - - if err := dst.Close(); err != nil { - return nil, err - } - - if err := src.Close(); err != nil { - return nil, err - } - } - - return memory, nil -} -``` - -## Why billy? - -The library billy deals with storage systems and Billy is the name of a well-known, IKEA -bookcase. That's it. - -## License - -Apache License Version 2.0, see [LICENSE](LICENSE) diff --git a/vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml b/vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml deleted file mode 100644 index 91c0b40c..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: "{build}" -platform: x64 - -clone_folder: c:\gopath\src\gopkg.in\src-d\go-billy.v4 - -environment: - GOPATH: c:\gopath - -install: - - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - - go version - - go get -v -t ./... - -build_script: - - go test -v ./... diff --git a/vendor/gopkg.in/src-d/go-billy.v4/fs.go b/vendor/gopkg.in/src-d/go-billy.v4/fs.go deleted file mode 100644 index a9efccde..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/fs.go +++ /dev/null @@ -1,202 +0,0 @@ -package billy - -import ( - "errors" - "io" - "os" - "time" -) - -var ( - ErrReadOnly = errors.New("read-only filesystem") - ErrNotSupported = errors.New("feature not supported") - ErrCrossedBoundary = errors.New("chroot boundary crossed") -) - -// Capability holds the supported features of a billy filesystem. This does -// not mean that the capability has to be supported by the underlying storage. -// For example, a billy filesystem may support WriteCapability but the -// storage be mounted in read only mode. -type Capability uint64 - -const ( - // WriteCapability means that the fs is writable. - WriteCapability Capability = 1 << iota - // ReadCapability means that the fs is readable. - ReadCapability - // ReadAndWriteCapability is the ability to open a file in read and write mode. - ReadAndWriteCapability - // SeekCapability means it is able to move position inside the file. - SeekCapability - // TruncateCapability means that a file can be truncated. - TruncateCapability - // LockCapability is the ability to lock a file. - LockCapability - - // DefaultCapabilities lists all capable features supported by filesystems - // without Capability interface. This list should not be changed until a - // major version is released. - DefaultCapabilities Capability = WriteCapability | ReadCapability | - ReadAndWriteCapability | SeekCapability | TruncateCapability | - LockCapability - - // AllCapabilities lists all capable features. - AllCapabilities Capability = WriteCapability | ReadCapability | - ReadAndWriteCapability | SeekCapability | TruncateCapability | - LockCapability -) - -// Filesystem abstract the operations in a storage-agnostic interface. -// Each method implementation mimics the behavior of the equivalent functions -// at the os package from the standard library. -type Filesystem interface { - Basic - TempFile - Dir - Symlink - Chroot -} - -// Basic abstract the basic operations in a storage-agnostic interface as -// an extension to the Basic interface. -type Basic interface { - // Create 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. - Create(filename string) (File, error) - // Open 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. - Open(filename string) (File, error) - // OpenFile 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. - OpenFile(filename string, flag int, perm os.FileMode) (File, error) - // Stat returns a FileInfo describing the named file. - Stat(filename string) (os.FileInfo, error) - // Rename renames (moves) oldpath to newpath. If newpath already exists and - // is not a directory, Rename replaces it. OS-specific restrictions may - // apply when oldpath and newpath are in different directories. - Rename(oldpath, newpath string) error - // Remove removes the named file or directory. - Remove(filename string) error - // Join joins any number of path elements into a single path, adding a - // Separator if necessary. Join calls filepath.Clean on the result; in - // particular, all empty strings are ignored. On Windows, the result is a - // UNC path if and only if the first path element is a UNC path. - Join(elem ...string) string -} - -type TempFile interface { - // 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. - TempFile(dir, prefix string) (File, error) -} - -// Dir abstract the dir related operations in a storage-agnostic interface as -// an extension to the Basic interface. -type Dir interface { - // ReadDir reads the directory named by dirname and returns a list of - // directory entries sorted by filename. - ReadDir(path string) ([]os.FileInfo, error) - // MkdirAll creates a directory named path, along with any necessary - // parents, and returns nil, or else returns an error. The permission bits - // perm are used for all directories that MkdirAll creates. If path is/ - // already a directory, MkdirAll does nothing and returns nil. - MkdirAll(filename string, perm os.FileMode) error -} - -// Symlink abstract the symlink related operations in a storage-agnostic -// interface as an extension to the Basic interface. -type Symlink interface { - // Lstat returns a FileInfo describing the named file. If the file is a - // symbolic link, the returned FileInfo describes the symbolic link. Lstat - // makes no attempt to follow the link. - Lstat(filename string) (os.FileInfo, error) - // Symlink creates a symbolic-link from link to target. target may be an - // absolute or relative path, and need not refer to an existing node. - // Parent directories of link are created as necessary. - Symlink(target, link string) error - // Readlink returns the target path of link. - Readlink(link string) (string, error) -} - -// Change abstract the FileInfo change related operations in a storage-agnostic -// interface as an extension to the Basic interface -type Change interface { - // Chmod changes the mode of the named file to mode. If the file is a - // symbolic link, it changes the mode of the link's target. - Chmod(name string, mode os.FileMode) error - // Lchown changes the numeric uid and gid of the named file. If the file is - // a symbolic link, it changes the uid and gid of the link itself. - Lchown(name string, uid, gid int) error - // Chown changes the numeric uid and gid of the named file. If the file is a - // symbolic link, it changes the uid and gid of the link's target. - Chown(name string, uid, gid int) error - // Chtimes changes the access and modification times of the named file, - // similar to the Unix utime() or utimes() functions. - // - // The underlying filesystem may truncate or round the values to a less - // precise time unit. - Chtimes(name string, atime time.Time, mtime time.Time) error -} - -// Chroot abstract the chroot related operations in a storage-agnostic interface -// as an extension to the Basic interface. -type Chroot interface { - // Chroot returns a new filesystem from the same type where the new root is - // the given path. Files outside of the designated directory tree cannot be - // accessed. - Chroot(path string) (Filesystem, error) - // Root returns the root path of the filesystem. - Root() string -} - -// File represent a file, being a subset of the os.File -type File interface { - // Name returns the name of the file as presented to Open. - Name() string - io.Writer - io.Reader - io.ReaderAt - io.Seeker - io.Closer - // Lock locks the file like e.g. flock. It protects against access from - // other processes. - Lock() error - // Unlock unlocks the file. - Unlock() error - // Truncate the file. - Truncate(size int64) error -} - -// Capable interface can return the available features of a filesystem. -type Capable interface { - // Capabilities returns the capabilities of a filesystem in bit flags. - Capabilities() Capability -} - -// Capabilities returns the features supported by a filesystem. If the FS -// does not implement Capable interface it returns all features. -func Capabilities(fs Basic) Capability { - capable, ok := fs.(Capable) - if !ok { - return DefaultCapabilities - } - - return capable.Capabilities() -} - -// CapabilityCheck tests the filesystem for the provided capabilities and -// returns true in case it supports all of them. -func CapabilityCheck(fs Basic, capabilities Capability) bool { - fsCaps := Capabilities(fs) - return fsCaps&capabilities == capabilities -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go b/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go deleted file mode 100644 index 44ddb3db..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go +++ /dev/null @@ -1,242 +0,0 @@ -package chroot - -import ( - "os" - "path/filepath" - "strings" - - "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-billy.v4/helper/polyfill" -) - -// ChrootHelper is a helper to implement billy.Chroot. -type ChrootHelper struct { - underlying billy.Filesystem - base string -} - -// New creates a new filesystem wrapping up the given 'fs'. -// The created filesystem has its base in the given ChrootHelperectory of the -// underlying filesystem. -func New(fs billy.Basic, base string) billy.Filesystem { - return &ChrootHelper{ - underlying: polyfill.New(fs), - base: base, - } -} - -func (fs *ChrootHelper) underlyingPath(filename string) (string, error) { - if isCrossBoundaries(filename) { - return "", billy.ErrCrossedBoundary - } - - return fs.Join(fs.Root(), filename), nil -} - -func isCrossBoundaries(path string) bool { - path = filepath.ToSlash(path) - path = filepath.Clean(path) - - return strings.HasPrefix(path, ".."+string(filepath.Separator)) -} - -func (fs *ChrootHelper) Create(filename string) (billy.File, error) { - fullpath, err := fs.underlyingPath(filename) - if err != nil { - return nil, err - } - - f, err := fs.underlying.Create(fullpath) - if err != nil { - return nil, err - } - - return newFile(fs, f, filename), nil -} - -func (fs *ChrootHelper) Open(filename string) (billy.File, error) { - fullpath, err := fs.underlyingPath(filename) - if err != nil { - return nil, err - } - - f, err := fs.underlying.Open(fullpath) - if err != nil { - return nil, err - } - - return newFile(fs, f, filename), nil -} - -func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (billy.File, error) { - fullpath, err := fs.underlyingPath(filename) - if err != nil { - return nil, err - } - - f, err := fs.underlying.OpenFile(fullpath, flag, mode) - if err != nil { - return nil, err - } - - return newFile(fs, f, filename), nil -} - -func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) { - fullpath, err := fs.underlyingPath(filename) - if err != nil { - return nil, err - } - - return fs.underlying.Stat(fullpath) -} - -func (fs *ChrootHelper) Rename(from, to string) error { - var err error - from, err = fs.underlyingPath(from) - if err != nil { - return err - } - - to, err = fs.underlyingPath(to) - if err != nil { - return err - } - - return fs.underlying.Rename(from, to) -} - -func (fs *ChrootHelper) Remove(path string) error { - fullpath, err := fs.underlyingPath(path) - if err != nil { - return err - } - - return fs.underlying.Remove(fullpath) -} - -func (fs *ChrootHelper) Join(elem ...string) string { - return fs.underlying.Join(elem...) -} - -func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) { - fullpath, err := fs.underlyingPath(dir) - if err != nil { - return nil, err - } - - f, err := fs.underlying.(billy.TempFile).TempFile(fullpath, prefix) - if err != nil { - return nil, err - } - - return newFile(fs, f, fs.Join(dir, filepath.Base(f.Name()))), nil -} - -func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) { - fullpath, err := fs.underlyingPath(path) - if err != nil { - return nil, err - } - - return fs.underlying.(billy.Dir).ReadDir(fullpath) -} - -func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error { - fullpath, err := fs.underlyingPath(filename) - if err != nil { - return err - } - - return fs.underlying.(billy.Dir).MkdirAll(fullpath, perm) -} - -func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) { - fullpath, err := fs.underlyingPath(filename) - if err != nil { - return nil, err - } - - return fs.underlying.(billy.Symlink).Lstat(fullpath) -} - -func (fs *ChrootHelper) Symlink(target, link string) error { - target = filepath.FromSlash(target) - - // only rewrite target if it's already absolute - if filepath.IsAbs(target) || strings.HasPrefix(target, string(filepath.Separator)) { - target = fs.Join(fs.Root(), target) - target = filepath.Clean(filepath.FromSlash(target)) - } - - link, err := fs.underlyingPath(link) - if err != nil { - return err - } - - return fs.underlying.(billy.Symlink).Symlink(target, link) -} - -func (fs *ChrootHelper) Readlink(link string) (string, error) { - fullpath, err := fs.underlyingPath(link) - if err != nil { - return "", err - } - - target, err := fs.underlying.(billy.Symlink).Readlink(fullpath) - if err != nil { - return "", err - } - - if !filepath.IsAbs(target) && !strings.HasPrefix(target, string(filepath.Separator)) { - return target, nil - } - - target, err = filepath.Rel(fs.base, target) - if err != nil { - return "", err - } - - return string(os.PathSeparator) + target, nil -} - -func (fs *ChrootHelper) Chroot(path string) (billy.Filesystem, error) { - fullpath, err := fs.underlyingPath(path) - if err != nil { - return nil, err - } - - return New(fs.underlying, fullpath), nil -} - -func (fs *ChrootHelper) Root() string { - return fs.base -} - -func (fs *ChrootHelper) Underlying() billy.Basic { - return fs.underlying -} - -// Capabilities implements the Capable interface. -func (fs *ChrootHelper) Capabilities() billy.Capability { - return billy.Capabilities(fs.underlying) -} - -type file struct { - billy.File - name string -} - -func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File { - filename = fs.Join(fs.Root(), filename) - filename, _ = filepath.Rel(fs.Root(), filename) - - return &file{ - File: f, - name: filename, - } -} - -func (f *file) Name() string { - return f.name -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go b/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go deleted file mode 100644 index f613c255..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go +++ /dev/null @@ -1,105 +0,0 @@ -package polyfill - -import ( - "os" - "path/filepath" - - "gopkg.in/src-d/go-billy.v4" -) - -// Polyfill is a helper that implements all missing method from billy.Filesystem. -type Polyfill struct { - billy.Basic - c capabilities -} - -type capabilities struct{ tempfile, dir, symlink, chroot bool } - -// New creates a new filesystem wrapping up 'fs' the intercepts all the calls -// made and errors if fs doesn't implement any of the billy interfaces. -func New(fs billy.Basic) billy.Filesystem { - if original, ok := fs.(billy.Filesystem); ok { - return original - } - - h := &Polyfill{Basic: fs} - - _, h.c.tempfile = h.Basic.(billy.TempFile) - _, h.c.dir = h.Basic.(billy.Dir) - _, h.c.symlink = h.Basic.(billy.Symlink) - _, h.c.chroot = h.Basic.(billy.Chroot) - return h -} - -func (h *Polyfill) TempFile(dir, prefix string) (billy.File, error) { - if !h.c.tempfile { - return nil, billy.ErrNotSupported - } - - return h.Basic.(billy.TempFile).TempFile(dir, prefix) -} - -func (h *Polyfill) ReadDir(path string) ([]os.FileInfo, error) { - if !h.c.dir { - return nil, billy.ErrNotSupported - } - - return h.Basic.(billy.Dir).ReadDir(path) -} - -func (h *Polyfill) MkdirAll(filename string, perm os.FileMode) error { - if !h.c.dir { - return billy.ErrNotSupported - } - - return h.Basic.(billy.Dir).MkdirAll(filename, perm) -} - -func (h *Polyfill) Symlink(target, link string) error { - if !h.c.symlink { - return billy.ErrNotSupported - } - - return h.Basic.(billy.Symlink).Symlink(target, link) -} - -func (h *Polyfill) Readlink(link string) (string, error) { - if !h.c.symlink { - return "", billy.ErrNotSupported - } - - return h.Basic.(billy.Symlink).Readlink(link) -} - -func (h *Polyfill) Lstat(path string) (os.FileInfo, error) { - if !h.c.symlink { - return nil, billy.ErrNotSupported - } - - return h.Basic.(billy.Symlink).Lstat(path) -} - -func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) { - if !h.c.chroot { - return nil, billy.ErrNotSupported - } - - return h.Basic.(billy.Chroot).Chroot(path) -} - -func (h *Polyfill) Root() string { - if !h.c.chroot { - return string(filepath.Separator) - } - - return h.Basic.(billy.Chroot).Root() -} - -func (h *Polyfill) Underlying() billy.Basic { - return h.Basic -} - -// Capabilities implements the Capable interface. -func (h *Polyfill) Capabilities() billy.Capability { - return billy.Capabilities(h.Basic) -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go deleted file mode 100644 index ff35a3ba..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go +++ /dev/null @@ -1,139 +0,0 @@ -// Package osfs provides a billy filesystem for the OS. -package osfs // import "gopkg.in/src-d/go-billy.v4/osfs" - -import ( - "io/ioutil" - "os" - "path/filepath" - "sync" - - "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-billy.v4/helper/chroot" -) - -const ( - defaultDirectoryMode = 0755 - defaultCreateMode = 0666 -) - -// OS is a filesystem based on the os filesystem. -type OS struct{} - -// New returns a new OS filesystem. -func New(baseDir string) billy.Filesystem { - return chroot.New(&OS{}, baseDir) -} - -func (fs *OS) Create(filename string) (billy.File, error) { - return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, defaultCreateMode) -} - -func (fs *OS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) { - if flag&os.O_CREATE != 0 { - if err := fs.createDir(filename); err != nil { - return nil, err - } - } - - f, err := os.OpenFile(filename, flag, perm) - if err != nil { - return nil, err - } - return &file{File: f}, err -} - -func (fs *OS) createDir(fullpath string) error { - dir := filepath.Dir(fullpath) - if dir != "." { - if err := os.MkdirAll(dir, defaultDirectoryMode); err != nil { - return err - } - } - - return nil -} - -func (fs *OS) ReadDir(path string) ([]os.FileInfo, error) { - l, err := ioutil.ReadDir(path) - if err != nil { - return nil, err - } - - var s = make([]os.FileInfo, len(l)) - for i, f := range l { - s[i] = f - } - - return s, nil -} - -func (fs *OS) Rename(from, to string) error { - if err := fs.createDir(to); err != nil { - return err - } - - return os.Rename(from, to) -} - -func (fs *OS) MkdirAll(path string, perm os.FileMode) error { - return os.MkdirAll(path, defaultDirectoryMode) -} - -func (fs *OS) Open(filename string) (billy.File, error) { - return fs.OpenFile(filename, os.O_RDONLY, 0) -} - -func (fs *OS) Stat(filename string) (os.FileInfo, error) { - return os.Stat(filename) -} - -func (fs *OS) Remove(filename string) error { - return os.Remove(filename) -} - -func (fs *OS) TempFile(dir, prefix string) (billy.File, error) { - if err := fs.createDir(dir + string(os.PathSeparator)); err != nil { - return nil, err - } - - f, err := ioutil.TempFile(dir, prefix) - if err != nil { - return nil, err - } - return &file{File: f}, nil -} - -func (fs *OS) Join(elem ...string) string { - return filepath.Join(elem...) -} - -func (fs *OS) RemoveAll(path string) error { - return os.RemoveAll(filepath.Clean(path)) -} - -func (fs *OS) Lstat(filename string) (os.FileInfo, error) { - return os.Lstat(filepath.Clean(filename)) -} - -func (fs *OS) Symlink(target, link string) error { - if err := fs.createDir(link); err != nil { - return err - } - - return os.Symlink(target, link) -} - -func (fs *OS) Readlink(link string) (string, error) { - return os.Readlink(link) -} - -// Capabilities implements the Capable interface. -func (fs *OS) Capabilities() billy.Capability { - return billy.DefaultCapabilities -} - -// file is a wrapper for an os.File which adds support for file locking. -type file struct { - *os.File - m sync.Mutex -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go deleted file mode 100644 index 144cde1c..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go +++ /dev/null @@ -1,21 +0,0 @@ -// +build !windows - -package osfs - -import ( - "golang.org/x/sys/unix" -) - -func (f *file) Lock() error { - f.m.Lock() - defer f.m.Unlock() - - return unix.Flock(int(f.File.Fd()), unix.LOCK_EX) -} - -func (f *file) Unlock() error { - f.m.Lock() - defer f.m.Unlock() - - return unix.Flock(int(f.File.Fd()), unix.LOCK_UN) -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go deleted file mode 100644 index 5eb98829..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go +++ /dev/null @@ -1,57 +0,0 @@ -// +build windows - -package osfs - -import ( - "os" - "runtime" - "unsafe" - - "golang.org/x/sys/windows" -) - -type fileInfo struct { - os.FileInfo - name string -} - -func (fi *fileInfo) Name() string { - return fi.name -} - -var ( - kernel32DLL = windows.NewLazySystemDLL("kernel32.dll") - lockFileExProc = kernel32DLL.NewProc("LockFileEx") - unlockFileProc = kernel32DLL.NewProc("UnlockFile") -) - -const ( - lockfileExclusiveLock = 0x2 -) - -func (f *file) Lock() error { - f.m.Lock() - defer f.m.Unlock() - - var overlapped windows.Overlapped - // err is always non-nil as per sys/windows semantics. - ret, _, err := lockFileExProc.Call(f.File.Fd(), lockfileExclusiveLock, 0, 0xFFFFFFFF, 0, - uintptr(unsafe.Pointer(&overlapped))) - runtime.KeepAlive(&overlapped) - if ret == 0 { - return err - } - return nil -} - -func (f *file) Unlock() error { - f.m.Lock() - defer f.m.Unlock() - - // err is always non-nil as per sys/windows semantics. - ret, _, err := unlockFileProc.Call(f.File.Fd(), 0, 0, 0xFFFFFFFF, 0) - if ret == 0 { - return err - } - return nil -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go b/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go deleted file mode 100644 index fdcb3e5f..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go +++ /dev/null @@ -1,111 +0,0 @@ -package util - -import ( - "path/filepath" - "sort" - "strings" - - "gopkg.in/src-d/go-billy.v4" -) - -// Glob returns the names of all files matching pattern or nil -// if there is no matching file. The syntax of patterns is the same -// as in Match. The pattern may describe hierarchical names such as -// /usr/*/bin/ed (assuming the Separator is '/'). -// -// Glob ignores file system errors such as I/O errors reading directories. -// The only possible returned error is ErrBadPattern, when pattern -// is malformed. -// -// Function originally from https://golang.org/src/path/filepath/match_test.go -func Glob(fs billy.Filesystem, pattern string) (matches []string, err error) { - if !hasMeta(pattern) { - if _, err = fs.Lstat(pattern); err != nil { - return nil, nil - } - return []string{pattern}, nil - } - - dir, file := filepath.Split(pattern) - // Prevent infinite recursion. See issue 15879. - if dir == pattern { - return nil, filepath.ErrBadPattern - } - - var m []string - m, err = Glob(fs, cleanGlobPath(dir)) - if err != nil { - return - } - for _, d := range m { - matches, err = glob(fs, d, file, matches) - if err != nil { - return - } - } - return -} - -// cleanGlobPath prepares path for glob matching. -func cleanGlobPath(path string) string { - switch path { - case "": - return "." - case string(filepath.Separator): - // do nothing to the path - return path - default: - return path[0 : len(path)-1] // chop off trailing separator - } -} - -// glob searches for files matching pattern in the directory dir -// and appends them to matches. If the directory cannot be -// opened, it returns the existing matches. New matches are -// added in lexicographical order. -func glob(fs billy.Filesystem, dir, pattern string, matches []string) (m []string, e error) { - m = matches - fi, err := fs.Stat(dir) - if err != nil { - return - } - - if !fi.IsDir() { - return - } - - names, _ := readdirnames(fs, dir) - sort.Strings(names) - - for _, n := range names { - matched, err := filepath.Match(pattern, n) - if err != nil { - return m, err - } - if matched { - m = append(m, filepath.Join(dir, n)) - } - } - return -} - -// hasMeta reports whether path contains any of the magic characters -// recognized by Match. -func hasMeta(path string) bool { - // TODO(niemeyer): Should other magic characters be added here? - return strings.ContainsAny(path, "*?[") -} - -func readdirnames(fs billy.Filesystem, dir string) ([]string, error) { - files, err := fs.ReadDir(dir) - if err != nil { - return nil, err - } - - var names []string - for _, file := range files { - names = append(names, file.Name()) - } - - return names, nil -} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/util/util.go b/vendor/gopkg.in/src-d/go-billy.v4/util/util.go deleted file mode 100644 index cf7fb57f..00000000 --- a/vendor/gopkg.in/src-d/go-billy.v4/util/util.go +++ /dev/null @@ -1,224 +0,0 @@ -package util - -import ( - "io" - "os" - "path/filepath" - "strconv" - "sync" - "time" - - "gopkg.in/src-d/go-billy.v4" -) - -// RemoveAll removes path and any children it contains. It removes everything it -// can but returns the first error it encounters. If the path does not exist, -// RemoveAll returns nil (no error). -func RemoveAll(fs billy.Basic, path string) error { - fs, path = getUnderlyingAndPath(fs, path) - - if r, ok := fs.(removerAll); ok { - return r.RemoveAll(path) - } - - return removeAll(fs, path) -} - -type removerAll interface { - RemoveAll(string) error -} - -func removeAll(fs billy.Basic, path string) error { - // This implementation is adapted from os.RemoveAll. - - // Simple case: if Remove works, we're done. - err := fs.Remove(path) - if err == nil || os.IsNotExist(err) { - return nil - } - - // Otherwise, is this a directory we need to recurse into? - dir, serr := fs.Stat(path) - if serr != nil { - if os.IsNotExist(serr) { - return nil - } - - return serr - } - - if !dir.IsDir() { - // Not a directory; return the error from Remove. - return err - } - - dirfs, ok := fs.(billy.Dir) - if !ok { - return billy.ErrNotSupported - } - - // Directory. - fis, err := dirfs.ReadDir(path) - if err != nil { - if os.IsNotExist(err) { - // Race. It was deleted between the Lstat and Open. - // Return nil per RemoveAll's docs. - return nil - } - - return err - } - - // Remove contents & return first error. - err = nil - for _, fi := range fis { - cpath := fs.Join(path, fi.Name()) - err1 := removeAll(fs, cpath) - if err == nil { - err = err1 - } - } - - // Remove directory. - err1 := fs.Remove(path) - if err1 == nil || os.IsNotExist(err1) { - return nil - } - - if err == nil { - err = err1 - } - - return err - -} - -// WriteFile writes data to a file named by filename in the given filesystem. -// If the file does not exist, WriteFile creates it with permissions perm; -// otherwise WriteFile truncates it before writing. -func WriteFile(fs billy.Basic, filename string, data []byte, perm os.FileMode) error { - f, err := fs.OpenFile(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 -} - -// Random number state. -// We generate random temporary file names so that there's a good -// chance the file doesn't exist yet - keeps the number of tries in -// TempFile to a minimum. -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:] -} - -// 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 TempFile(fs billy.Basic, dir, prefix string) (f billy.File, err error) { - // This implementation is based on stdlib ioutil.TempFile. - - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - name := filepath.Join(dir, prefix+nextSuffix()) - f, err = fs.OpenFile(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 -} - -// TempDir creates a new temporary directory in the directory dir -// with a name beginning with prefix and returns the path of the -// new directory. If dir is the empty string, TempDir uses the -// default directory for temporary files (see os.TempDir). -// Multiple programs calling TempDir simultaneously -// will not choose the same directory. It is the caller's responsibility -// to remove the directory when no longer needed. -func TempDir(fs billy.Dir, dir, prefix string) (name string, err error) { - // This implementation is based on stdlib ioutil.TempDir - - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - try := filepath.Join(dir, prefix+nextSuffix()) - err = fs.MkdirAll(try, 0700) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - if os.IsNotExist(err) { - if _, err := os.Stat(dir); os.IsNotExist(err) { - return "", err - } - } - if err == nil { - name = try - } - break - } - return -} - -type underlying interface { - Underlying() billy.Basic -} - -func getUnderlyingAndPath(fs billy.Basic, path string) (billy.Basic, string) { - u, ok := fs.(underlying) - if !ok { - return fs, path - } - if ch, ok := fs.(billy.Chroot); ok { - path = fs.Join(ch.Root(), path) - } - - return u.Underlying(), path -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/.gitignore b/vendor/gopkg.in/src-d/go-git.v4/.gitignore deleted file mode 100644 index 038dd9f1..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -coverage.out -*~ -coverage.txt -profile.out diff --git a/vendor/gopkg.in/src-d/go-git.v4/.travis.yml b/vendor/gopkg.in/src-d/go-git.v4/.travis.yml deleted file mode 100644 index 3a65f3e0..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: go - -go: - - "1.11" - - "1.12" - -go_import_path: gopkg.in/src-d/go-git.v4 - -env: - - GIT_VERSION=master - - GIT_VERSION=v1.9.3 - - GIT_VERSION=v2.11.0 - -cache: - directories: - - $HOME/.git-dist - -before_script: - - export GIT_DIST_PATH=$HOME/.git-dist - - make build-git - -before_install: - - git config --global user.email "travis@example.com" - - git config --global user.name "Travis CI" - -install: - - go get -v -t ./... - -script: - - export GIT_EXEC_PATH=$GIT_DIST_PATH - - export PATH=$GIT_DIST_PATH:$PATH - - git version - - make test-coverage - - go vet ./... - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/gopkg.in/src-d/go-git.v4/CODE_OF_CONDUCT.md b/vendor/gopkg.in/src-d/go-git.v4/CODE_OF_CONDUCT.md deleted file mode 100644 index a689fa3c..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at conduct@sourced.tech. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - diff --git a/vendor/gopkg.in/src-d/go-git.v4/COMPATIBILITY.md b/vendor/gopkg.in/src-d/go-git.v4/COMPATIBILITY.md deleted file mode 100644 index 4a3da62f..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/COMPATIBILITY.md +++ /dev/null @@ -1,111 +0,0 @@ -Supported Capabilities -====================== - -Here is a non-comprehensive table of git commands and features whose equivalent -is supported by go-git. - -| Feature | Status | Notes | -|---------------------------------------|--------|-------| -| **config** | -| config | ✔ | Reading and modifying per-repository configuration (`.git/config`) is supported. Global configuration (`$HOME/.gitconfig`) is not. | -| **getting and creating repositories** | -| init | ✔ | Plain init and `--bare` are supported. Flags `--template`, `--separate-git-dir` and `--shared` are not. | -| clone | ✔ | Plain clone and equivalents to `--progress`, `--single-branch`, `--depth`, `--origin`, `--recurse-submodules` are supported. Others are not. | -| **basic snapshotting** | -| add | ✔ | Plain add is supported. Any other flag aren't supported | -| status | ✔ | -| commit | ✔ | -| reset | ✔ | -| rm | ✔ | -| mv | ✔ | -| **branching and merging** | -| branch | ✔ | -| checkout | ✔ | Basic usages of checkout are supported. | -| merge | ✖ | -| mergetool | ✖ | -| stash | ✖ | -| tag | ✔ | -| **sharing and updating projects** | -| fetch | ✔ | -| pull | ✔ | Only supports merges where the merge can be resolved as a fast-forward. | -| push | ✔ | -| remote | ✔ | -| submodule | ✔ | -| **inspection and comparison** | -| show | ✔ | -| log | ✔ | -| shortlog | (see log) | -| describe | | -| **patching** | -| apply | ✖ | -| cherry-pick | ✖ | -| diff | ✔ | Patch object with UnifiedDiff output representation | -| rebase | ✖ | -| revert | ✖ | -| **debugging** | -| bisect | ✖ | -| blame | ✔ | -| grep | ✔ | -| **email** || -| am | ✖ | -| apply | ✖ | -| format-patch | ✖ | -| send-email | ✖ | -| request-pull | ✖ | -| **external systems** | -| svn | ✖ | -| fast-import | ✖ | -| **administration** | -| clean | ✔ | -| gc | ✖ | -| fsck | ✖ | -| reflog | ✖ | -| filter-branch | ✖ | -| instaweb | ✖ | -| archive | ✖ | -| bundle | ✖ | -| prune | ✖ | -| repack | ✖ | -| **server admin** | -| daemon | | -| update-server-info | | -| **advanced** | -| notes | ✖ | -| replace | ✖ | -| worktree | ✖ | -| annotate | (see blame) | -| **gpg** | -| git-verify-commit | ✔ | -| git-verify-tag | ✔ | -| **plumbing commands** | -| cat-file | ✔ | -| check-ignore | | -| commit-tree | | -| count-objects | | -| diff-index | | -| for-each-ref | ✔ | -| hash-object | ✔ | -| ls-files | ✔ | -| merge-base | ✔ | Calculates the merge-base only between two commits, and supports `--independent` and `--is-ancestor` modifiers; Does not support `--fork-point` nor `--octopus` modifiers. | -| read-tree | | -| rev-list | ✔ | -| rev-parse | | -| show-ref | ✔ | -| symbolic-ref | ✔ | -| update-index | | -| update-ref | | -| verify-pack | | -| write-tree | | -| **protocols** | -| http(s):// (dumb) | ✖ | -| http(s):// (smart) | ✔ | -| git:// | ✔ | -| ssh:// | ✔ | -| file:// | ✔ | -| custom | ✔ | -| **other features** | -| gitignore | ✔ | -| gitattributes | ✖ | -| index version | | -| packfile version | | -| push-certs | ✖ | diff --git a/vendor/gopkg.in/src-d/go-git.v4/CONTRIBUTING.md b/vendor/gopkg.in/src-d/go-git.v4/CONTRIBUTING.md deleted file mode 100644 index bdb5f733..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/CONTRIBUTING.md +++ /dev/null @@ -1,59 +0,0 @@ -# Contributing Guidelines - -source{d} go-git project is [Apache 2.0 licensed](LICENSE) and accepts -contributions via GitHub pull requests. This document outlines some of the -conventions on development workflow, commit message formatting, contact points, -and other resources to make it easier to get your contribution accepted. - -## Certificate of Origin - -By contributing to this project you agree to the [Developer Certificate of -Origin (DCO)](DCO). This document was created by the Linux Kernel community and is a -simple statement that you, as a contributor, have the legal right to make the -contribution. - -In order to show your agreement with the DCO you should include at the end of commit message, -the following line: `Signed-off-by: John Doe `, using your real name. - -This can be done easily using the [`-s`](https://github.com/git/git/blob/b2c150d3aa82f6583b9aadfecc5f8fa1c74aca09/Documentation/git-commit.txt#L154-L161) flag on the `git commit`. - -## Support Channels - -The official support channels, for both users and contributors, are: - -- [StackOverflow go-git tag](https://stackoverflow.com/questions/tagged/go-git) for user questions. -- GitHub [Issues](https://github.com/src-d/go-git/issues)* for bug reports and feature requests. -- Slack: #go-git room in the [source{d} Slack](https://join.slack.com/t/sourced-community/shared_invite/enQtMjc4Njk5MzEyNzM2LTFjNzY4NjEwZGEwMzRiNTM4MzRlMzQ4MmIzZjkwZmZlM2NjODUxZmJjNDI1OTcxNDAyMmZlNmFjODZlNTg0YWM) - -*Before opening a new issue or submitting a new pull request, it's helpful to -search the project - it's likely that another user has already reported the -issue you're facing, or it's a known issue that we're already aware of. - - -## How to Contribute - -Pull Requests (PRs) are the main and exclusive way to contribute to the official go-git project. -In order for a PR to be accepted it needs to pass a list of requirements: - -- You should be able to run the same query using `git`. We don't accept features that are not implemented in the official git implementation. -- The expected behavior must match the [official git implementation](https://github.com/git/git). -- The actual behavior must be correctly explained with natural language and providing a minimum working example in Go that reproduces it. -- All PRs must be written in idiomatic Go, formatted according to [gofmt](https://golang.org/cmd/gofmt/), and without any warnings from [go lint](https://github.com/golang/lint) nor [go vet](https://golang.org/cmd/vet/). -- They should in general include tests, and those shall pass. -- If the PR is a bug fix, it has to include a suite of unit tests for the new functionality. -- If the PR is a new feature, it has to come with a suite of unit tests, that tests the new functionality. -- In any case, all the PRs have to pass the personal evaluation of at least one of the [maintainers](MAINTAINERS) of go-git. - -### Format of the commit message - -Every commit message should describe what was changed, under which context and, if applicable, the GitHub issue it relates to: - -``` -plumbing: packp, Skip argument validations for unknown capabilities. Fixes #623 -``` - -The format can be described more formally as follows: - -``` -: , . [Fixes #] -``` diff --git a/vendor/gopkg.in/src-d/go-git.v4/DCO b/vendor/gopkg.in/src-d/go-git.v4/DCO deleted file mode 100644 index 3aca339d..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/DCO +++ /dev/null @@ -1,36 +0,0 @@ -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. \ No newline at end of file diff --git a/vendor/gopkg.in/src-d/go-git.v4/MAINTAINERS b/vendor/gopkg.in/src-d/go-git.v4/MAINTAINERS deleted file mode 100644 index ff2129c4..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/MAINTAINERS +++ /dev/null @@ -1,3 +0,0 @@ -Máximo Cuadros (@mcuadros) -Jeremy Stribling (@strib) -Ori Rawlings (@orirawlings) diff --git a/vendor/gopkg.in/src-d/go-git.v4/Makefile b/vendor/gopkg.in/src-d/go-git.v4/Makefile deleted file mode 100644 index d576778f..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -# General -WORKDIR = $(PWD) - -# Go parameters -GOCMD = go -GOTEST = $(GOCMD) test -v - -# Git config -GIT_VERSION ?= -GIT_DIST_PATH ?= $(PWD)/.git-dist -GIT_REPOSITORY = http://github.com/git/git.git - -# Coverage -COVERAGE_REPORT = coverage.txt -COVERAGE_PROFILE = profile.out -COVERAGE_MODE = atomic - -ifneq ($(origin CI), undefined) - WORKDIR := $(GOPATH)/src/gopkg.in/src-d/go-git.v4 -endif - -build-git: - @if [ -f $(GIT_DIST_PATH)/git ]; then \ - echo "nothing to do, using cache $(GIT_DIST_PATH)"; \ - else \ - git clone $(GIT_REPOSITORY) -b $(GIT_VERSION) --depth 1 --single-branch $(GIT_DIST_PATH); \ - cd $(GIT_DIST_PATH); \ - make configure; \ - ./configure; \ - make all; \ - fi - -test: - @cd $(WORKDIR); \ - $(GOTEST) ./... - -test-coverage: - @cd $(WORKDIR); \ - echo "" > $(COVERAGE_REPORT); \ - for dir in `find . -name "*.go" | grep -o '.*/' | sort | uniq`; do \ - $(GOTEST) $$dir -coverprofile=$(COVERAGE_PROFILE) -covermode=$(COVERAGE_MODE); \ - if [ $$? != 0 ]; then \ - exit 2; \ - fi; \ - if [ -f $(COVERAGE_PROFILE) ]; then \ - cat $(COVERAGE_PROFILE) >> $(COVERAGE_REPORT); \ - rm $(COVERAGE_PROFILE); \ - fi; \ - done; \ - -clean: - rm -rf $(GIT_DIST_PATH) \ No newline at end of file diff --git a/vendor/gopkg.in/src-d/go-git.v4/README.md b/vendor/gopkg.in/src-d/go-git.v4/README.md deleted file mode 100644 index ed9306c8..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/README.md +++ /dev/null @@ -1,123 +0,0 @@ -![go-git logo](https://cdn.rawgit.com/src-d/artwork/02036484/go-git/files/go-git-github-readme-header.png) -[![GoDoc](https://godoc.org/gopkg.in/src-d/go-git.v4?status.svg)](https://godoc.org/github.com/src-d/go-git) [![Build Status](https://travis-ci.org/src-d/go-git.svg)](https://travis-ci.org/src-d/go-git) [![Build status](https://ci.appveyor.com/api/projects/status/nyidskwifo4py6ub?svg=true)](https://ci.appveyor.com/project/mcuadros/go-git) [![codecov.io](https://codecov.io/github/src-d/go-git/coverage.svg)](https://codecov.io/github/src-d/go-git) [![Go Report Card](https://goreportcard.com/badge/github.com/src-d/go-git)](https://goreportcard.com/report/github.com/src-d/go-git) - -*go-git* is a highly extensible git implementation library written in **pure Go**. - -It can be used to manipulate git repositories at low level *(plumbing)* or high level *(porcelain)*, through an idiomatic Go API. It also supports several types of storage, such as in-memory filesystems, or custom implementations thanks to the [`Storer`](https://godoc.org/gopkg.in/src-d/go-git.v4/plumbing/storer) interface. - -It's being actively developed since 2015 and is being used extensively by [source{d}](https://sourced.tech/) and [Keybase](https://keybase.io/blog/encrypted-git-for-everyone), and by many other libraries and tools. - -Comparison with git -------------------- - -*go-git* aims to be fully compatible with [git](https://github.com/git/git), all the *porcelain* operations are implemented to work exactly as *git* does. - -*git* is a humongous project with years of development by thousands of contributors, making it challenging for *go-git* to implement all the features. You can find a comparison of *go-git* vs *git* in the [compatibility documentation](COMPATIBILITY.md). - - -Installation ------------- - -The recommended way to install *go-git* is: - -``` -go get -u gopkg.in/src-d/go-git.v4/... -``` - -> We use [gopkg.in](http://labix.org/gopkg.in) to version the API, this means that when `go get` clones the package, it's the latest tag matching `v4.*` that is cloned and not the master branch. - -Examples --------- - -> Please note that the `CheckIfError` and `Info` functions used in the examples are from the [examples package](https://github.com/src-d/go-git/blob/master/_examples/common.go#L17) just to be used in the examples. - - -### Basic example - -A basic example that mimics the standard `git clone` command - -```go -// Clone the given repository to the given directory -Info("git clone https://github.com/src-d/go-git") - -_, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{ - URL: "https://github.com/src-d/go-git", - Progress: os.Stdout, -}) - -CheckIfError(err) -``` - -Outputs: -``` -Counting objects: 4924, done. -Compressing objects: 100% (1333/1333), done. -Total 4924 (delta 530), reused 6 (delta 6), pack-reused 3533 -``` - -### In-memory example - -Cloning a repository into memory and printing the history of HEAD, just like `git log` does - - -```go -// Clones the given repository in memory, creating the remote, the local -// branches and fetching the objects, exactly as: -Info("git clone https://github.com/src-d/go-siva") - -r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{ - URL: "https://github.com/src-d/go-siva", -}) - -CheckIfError(err) - -// Gets the HEAD history from HEAD, just like this command: -Info("git log") - -// ... retrieves the branch pointed by HEAD -ref, err := r.Head() -CheckIfError(err) - - -// ... retrieves the commit history -cIter, err := r.Log(&git.LogOptions{From: ref.Hash()}) -CheckIfError(err) - -// ... just iterates over the commits, printing it -err = cIter.ForEach(func(c *object.Commit) error { - fmt.Println(c) - return nil -}) -CheckIfError(err) -``` - -Outputs: -``` -commit ded8054fd0c3994453e9c8aacaf48d118d42991e -Author: Santiago M. Mola -Date: Sat Nov 12 21:18:41 2016 +0100 - - index: ReadFrom/WriteTo returns IndexReadError/IndexWriteError. (#9) - -commit df707095626f384ce2dc1a83b30f9a21d69b9dfc -Author: Santiago M. Mola -Date: Fri Nov 11 13:23:22 2016 +0100 - - readwriter: fix bug when writing index. (#10) - - When using ReadWriter on an existing siva file, absolute offset for - index entries was not being calculated correctly. -... -``` - -You can find this [example](_examples/log/main.go) and many others in the [examples](_examples) folder. - -Contribute ----------- - -[Contributions](https://github.com/src-d/go-git/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) are more than welcome, if you are interested please take a look to -our [Contributing Guidelines](CONTRIBUTING.md). - -License -------- -Apache License Version 2.0, see [LICENSE](LICENSE) diff --git a/vendor/gopkg.in/src-d/go-git.v4/appveyor.yml b/vendor/gopkg.in/src-d/go-git.v4/appveyor.yml deleted file mode 100644 index 160616be..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/appveyor.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: "{build}" -platform: x64 - -matrix: - allow_failures: - - platform: x64 - -clone_folder: c:\gopath\src\gopkg.in\src-d\go-git.v4 - -environment: - GOPATH: c:\gopath - -install: - - set PATH=%GOPATH%\bin;c:\go\bin;"C:\Program Files\Git\mingw64\bin";%PATH% - - go version - - go get -v -t ./... - - git config --global user.email "travis@example.com" - - git config --global user.name "Travis CI - -build_script: - - go test -v ./... diff --git a/vendor/gopkg.in/src-d/go-git.v4/internal/revision/parser.go b/vendor/gopkg.in/src-d/go-git.v4/internal/revision/parser.go deleted file mode 100644 index d2c509e5..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/internal/revision/parser.go +++ /dev/null @@ -1,622 +0,0 @@ -// Package revision extracts git revision from string -// More informations about revision : https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html -package revision - -import ( - "bytes" - "fmt" - "io" - "regexp" - "strconv" - "time" -) - -// ErrInvalidRevision is emitted if string doesn't match valid revision -type ErrInvalidRevision struct { - s string -} - -func (e *ErrInvalidRevision) Error() string { - return "Revision invalid : " + e.s -} - -// Revisioner represents a revision component. -// A revision is made of multiple revision components -// obtained after parsing a revision string, -// for instance revision "master~" will be converted in -// two revision components Ref and TildePath -type Revisioner interface { -} - -// Ref represents a reference name : HEAD, master -type Ref string - -// TildePath represents ~, ~{n} -type TildePath struct { - Depth int -} - -// CaretPath represents ^, ^{n} -type CaretPath struct { - Depth int -} - -// CaretReg represents ^{/foo bar} -type CaretReg struct { - Regexp *regexp.Regexp - Negate bool -} - -// CaretType represents ^{commit} -type CaretType struct { - ObjectType string -} - -// AtReflog represents @{n} -type AtReflog struct { - Depth int -} - -// AtCheckout represents @{-n} -type AtCheckout struct { - Depth int -} - -// AtUpstream represents @{upstream}, @{u} -type AtUpstream struct { - BranchName string -} - -// AtPush represents @{push} -type AtPush struct { - BranchName string -} - -// AtDate represents @{"2006-01-02T15:04:05Z"} -type AtDate struct { - Date time.Time -} - -// ColonReg represents :/foo bar -type ColonReg struct { - Regexp *regexp.Regexp - Negate bool -} - -// ColonPath represents :./ : -type ColonPath struct { - Path string -} - -// ColonStagePath represents ::/ -type ColonStagePath struct { - Path string - Stage int -} - -// Parser represents a parser -// use to tokenize and transform to revisioner chunks -// a given string -type Parser struct { - s *scanner - currentParsedChar struct { - tok token - lit string - } - unreadLastChar bool -} - -// NewParserFromString returns a new instance of parser from a string. -func NewParserFromString(s string) *Parser { - return NewParser(bytes.NewBufferString(s)) -} - -// NewParser returns a new instance of parser. -func NewParser(r io.Reader) *Parser { - return &Parser{s: newScanner(r)} -} - -// scan returns the next token from the underlying scanner -// or the last scanned token if an unscan was requested -func (p *Parser) scan() (token, string, error) { - if p.unreadLastChar { - p.unreadLastChar = false - return p.currentParsedChar.tok, p.currentParsedChar.lit, nil - } - - tok, lit, err := p.s.scan() - - p.currentParsedChar.tok, p.currentParsedChar.lit = tok, lit - - return tok, lit, err -} - -// unscan pushes the previously read token back onto the buffer. -func (p *Parser) unscan() { p.unreadLastChar = true } - -// Parse explode a revision string into revisioner chunks -func (p *Parser) Parse() ([]Revisioner, error) { - var rev Revisioner - var revs []Revisioner - var tok token - var err error - - for { - tok, _, err = p.scan() - - if err != nil { - return nil, err - } - - switch tok { - case at: - rev, err = p.parseAt() - case tilde: - rev, err = p.parseTilde() - case caret: - rev, err = p.parseCaret() - case colon: - rev, err = p.parseColon() - case eof: - err = p.validateFullRevision(&revs) - - if err != nil { - return []Revisioner{}, err - } - - return revs, nil - default: - p.unscan() - rev, err = p.parseRef() - } - - if err != nil { - return []Revisioner{}, err - } - - revs = append(revs, rev) - } -} - -// validateFullRevision ensures all revisioner chunks make a valid revision -func (p *Parser) validateFullRevision(chunks *[]Revisioner) error { - var hasReference bool - - for i, chunk := range *chunks { - switch chunk.(type) { - case Ref: - if i == 0 { - hasReference = true - } else { - return &ErrInvalidRevision{`reference must be defined once at the beginning`} - } - case AtDate: - if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { - return nil - } - - return &ErrInvalidRevision{`"@" statement is not valid, could be : @{}, @{}`} - case AtReflog: - if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { - return nil - } - - return &ErrInvalidRevision{`"@" statement is not valid, could be : @{}, @{}`} - case AtCheckout: - if len(*chunks) == 1 { - return nil - } - - return &ErrInvalidRevision{`"@" statement is not valid, could be : @{-}`} - case AtUpstream: - if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { - return nil - } - - return &ErrInvalidRevision{`"@" statement is not valid, could be : @{upstream}, @{upstream}, @{u}, @{u}`} - case AtPush: - if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { - return nil - } - - return &ErrInvalidRevision{`"@" statement is not valid, could be : @{push}, @{push}`} - case TildePath, CaretPath, CaretReg: - if !hasReference { - return &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`} - } - case ColonReg: - if len(*chunks) == 1 { - return nil - } - - return &ErrInvalidRevision{`":" statement is not valid, could be : :/`} - case ColonPath: - if i == len(*chunks)-1 && hasReference || len(*chunks) == 1 { - return nil - } - - return &ErrInvalidRevision{`":" statement is not valid, could be : :`} - case ColonStagePath: - if len(*chunks) == 1 { - return nil - } - - return &ErrInvalidRevision{`":" statement is not valid, could be : ::`} - } - } - - return nil -} - -// parseAt extract @ statements -func (p *Parser) parseAt() (Revisioner, error) { - var tok, nextTok token - var lit, nextLit string - var err error - - tok, _, err = p.scan() - - if err != nil { - return nil, err - } - - if tok != obrace { - p.unscan() - - return Ref("HEAD"), nil - } - - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - nextTok, nextLit, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == word && (lit == "u" || lit == "upstream") && nextTok == cbrace: - return AtUpstream{}, nil - case tok == word && lit == "push" && nextTok == cbrace: - return AtPush{}, nil - case tok == number && nextTok == cbrace: - n, _ := strconv.Atoi(lit) - - return AtReflog{n}, nil - case tok == minus && nextTok == number: - n, _ := strconv.Atoi(nextLit) - - t, _, err := p.scan() - - if err != nil { - return nil, err - } - - if t != cbrace { - return nil, &ErrInvalidRevision{fmt.Sprintf(`missing "}" in @{-n} structure`)} - } - - return AtCheckout{n}, nil - default: - p.unscan() - - date := lit - - for { - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == cbrace: - t, err := time.Parse("2006-01-02T15:04:05Z", date) - - if err != nil { - return nil, &ErrInvalidRevision{fmt.Sprintf(`wrong date "%s" must fit ISO-8601 format : 2006-01-02T15:04:05Z`, date)} - } - - return AtDate{t}, nil - default: - date += lit - } - } - } -} - -// parseTilde extract ~ statements -func (p *Parser) parseTilde() (Revisioner, error) { - var tok token - var lit string - var err error - - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == number: - n, _ := strconv.Atoi(lit) - - return TildePath{n}, nil - default: - p.unscan() - return TildePath{1}, nil - } -} - -// parseCaret extract ^ statements -func (p *Parser) parseCaret() (Revisioner, error) { - var tok token - var lit string - var err error - - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == obrace: - r, err := p.parseCaretBraces() - - if err != nil { - return nil, err - } - - return r, nil - case tok == number: - n, _ := strconv.Atoi(lit) - - if n > 2 { - return nil, &ErrInvalidRevision{fmt.Sprintf(`"%s" found must be 0, 1 or 2 after "^"`, lit)} - } - - return CaretPath{n}, nil - default: - p.unscan() - return CaretPath{1}, nil - } -} - -// parseCaretBraces extract ^{} statements -func (p *Parser) parseCaretBraces() (Revisioner, error) { - var tok, nextTok token - var lit, _ string - start := true - var re string - var negate bool - var err error - - for { - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - nextTok, _, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == word && nextTok == cbrace && (lit == "commit" || lit == "tree" || lit == "blob" || lit == "tag" || lit == "object"): - return CaretType{lit}, nil - case re == "" && tok == cbrace: - return CaretType{"tag"}, nil - case re == "" && tok == emark && nextTok == emark: - re += lit - case re == "" && tok == emark && nextTok == minus: - negate = true - case re == "" && tok == emark: - return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)} - case re == "" && tok == slash: - p.unscan() - case tok != slash && start: - return nil, &ErrInvalidRevision{fmt.Sprintf(`"%s" is not a valid revision suffix brace component`, lit)} - case tok != cbrace: - p.unscan() - re += lit - case tok == cbrace: - p.unscan() - - reg, err := regexp.Compile(re) - - if err != nil { - return CaretReg{}, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component, %s`, err.Error())} - } - - return CaretReg{reg, negate}, nil - } - - start = false - } -} - -// parseColon extract : statements -func (p *Parser) parseColon() (Revisioner, error) { - var tok token - var err error - - tok, _, err = p.scan() - - if err != nil { - return nil, err - } - - switch tok { - case slash: - return p.parseColonSlash() - default: - p.unscan() - return p.parseColonDefault() - } -} - -// parseColonSlash extract :/ statements -func (p *Parser) parseColonSlash() (Revisioner, error) { - var tok, nextTok token - var lit string - var re string - var negate bool - var err error - - for { - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - nextTok, _, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == emark && nextTok == emark: - re += lit - case re == "" && tok == emark && nextTok == minus: - negate = true - case re == "" && tok == emark: - return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)} - case tok == eof: - p.unscan() - reg, err := regexp.Compile(re) - - if err != nil { - return ColonReg{}, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component, %s`, err.Error())} - } - - return ColonReg{reg, negate}, nil - default: - p.unscan() - re += lit - } - } -} - -// parseColonDefault extract : statements -func (p *Parser) parseColonDefault() (Revisioner, error) { - var tok token - var lit string - var path string - var stage int - var err error - var n = -1 - - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - nextTok, _, err := p.scan() - - if err != nil { - return nil, err - } - - if tok == number && nextTok == colon { - n, _ = strconv.Atoi(lit) - } - - switch n { - case 0, 1, 2, 3: - stage = n - default: - path += lit - p.unscan() - } - - for { - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - switch { - case tok == eof && n == -1: - return ColonPath{path}, nil - case tok == eof: - return ColonStagePath{path, stage}, nil - default: - path += lit - } - } -} - -// parseRef extract reference name -func (p *Parser) parseRef() (Revisioner, error) { - var tok, prevTok token - var lit, buf string - var endOfRef bool - var err error - - for { - tok, lit, err = p.scan() - - if err != nil { - return nil, err - } - - switch tok { - case eof, at, colon, tilde, caret: - endOfRef = true - } - - err := p.checkRefFormat(tok, lit, prevTok, buf, endOfRef) - - if err != nil { - return "", err - } - - if endOfRef { - p.unscan() - return Ref(buf), nil - } - - buf += lit - prevTok = tok - } -} - -// checkRefFormat ensure reference name follow rules defined here : -// https://git-scm.com/docs/git-check-ref-format -func (p *Parser) checkRefFormat(token token, literal string, previousToken token, buffer string, endOfRef bool) error { - switch token { - case aslash, space, control, qmark, asterisk, obracket: - return &ErrInvalidRevision{fmt.Sprintf(`must not contains "%s"`, literal)} - } - - switch { - case (token == dot || token == slash) && buffer == "": - return &ErrInvalidRevision{fmt.Sprintf(`must not start with "%s"`, literal)} - case previousToken == slash && endOfRef: - return &ErrInvalidRevision{`must not end with "/"`} - case previousToken == dot && endOfRef: - return &ErrInvalidRevision{`must not end with "."`} - case token == dot && previousToken == slash: - return &ErrInvalidRevision{`must not contains "/."`} - case previousToken == dot && token == dot: - return &ErrInvalidRevision{`must not contains ".."`} - case previousToken == slash && token == slash: - return &ErrInvalidRevision{`must not contains consecutively "/"`} - case (token == slash || endOfRef) && len(buffer) > 4 && buffer[len(buffer)-5:] == ".lock": - return &ErrInvalidRevision{"cannot end with .lock"} - } - - return nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/internal/revision/scanner.go b/vendor/gopkg.in/src-d/go-git.v4/internal/revision/scanner.go deleted file mode 100644 index fb5f333f..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/internal/revision/scanner.go +++ /dev/null @@ -1,117 +0,0 @@ -package revision - -import ( - "bufio" - "io" - "unicode" -) - -// runeCategoryValidator takes a rune as input and -// validates it belongs to a rune category -type runeCategoryValidator func(r rune) bool - -// tokenizeExpression aggegates a series of runes matching check predicate into a single -// string and provides given tokenType as token type -func tokenizeExpression(ch rune, tokenType token, check runeCategoryValidator, r *bufio.Reader) (token, string, error) { - var data []rune - data = append(data, ch) - - for { - c, _, err := r.ReadRune() - - if c == zeroRune { - break - } - - if err != nil { - return tokenError, "", err - } - - if check(c) { - data = append(data, c) - } else { - err := r.UnreadRune() - - if err != nil { - return tokenError, "", err - } - - return tokenType, string(data), nil - } - } - - return tokenType, string(data), nil -} - -var zeroRune = rune(0) - -// scanner represents a lexical scanner. -type scanner struct { - r *bufio.Reader -} - -// newScanner returns a new instance of scanner. -func newScanner(r io.Reader) *scanner { - return &scanner{r: bufio.NewReader(r)} -} - -// Scan extracts tokens and their strings counterpart -// from the reader -func (s *scanner) scan() (token, string, error) { - ch, _, err := s.r.ReadRune() - - if err != nil && err != io.EOF { - return tokenError, "", err - } - - switch ch { - case zeroRune: - return eof, "", nil - case ':': - return colon, string(ch), nil - case '~': - return tilde, string(ch), nil - case '^': - return caret, string(ch), nil - case '.': - return dot, string(ch), nil - case '/': - return slash, string(ch), nil - case '{': - return obrace, string(ch), nil - case '}': - return cbrace, string(ch), nil - case '-': - return minus, string(ch), nil - case '@': - return at, string(ch), nil - case '\\': - return aslash, string(ch), nil - case '?': - return qmark, string(ch), nil - case '*': - return asterisk, string(ch), nil - case '[': - return obracket, string(ch), nil - case '!': - return emark, string(ch), nil - } - - if unicode.IsSpace(ch) { - return space, string(ch), nil - } - - if unicode.IsControl(ch) { - return control, string(ch), nil - } - - if unicode.IsLetter(ch) { - return tokenizeExpression(ch, word, unicode.IsLetter, s.r) - } - - if unicode.IsNumber(ch) { - return tokenizeExpression(ch, number, unicode.IsNumber, s.r) - } - - return tokenError, string(ch), nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/internal/revision/token.go b/vendor/gopkg.in/src-d/go-git.v4/internal/revision/token.go deleted file mode 100644 index abc40488..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/internal/revision/token.go +++ /dev/null @@ -1,28 +0,0 @@ -package revision - -// token represents a entity extracted from string parsing -type token int - -const ( - eof token = iota - - aslash - asterisk - at - caret - cbrace - colon - control - dot - emark - minus - number - obrace - obracket - qmark - slash - space - tilde - tokenError - word -) diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/buffer_lru.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/buffer_lru.go deleted file mode 100644 index acaf1952..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/buffer_lru.go +++ /dev/null @@ -1,98 +0,0 @@ -package cache - -import ( - "container/list" - "sync" -) - -// BufferLRU implements an object cache with an LRU eviction policy and a -// maximum size (measured in object size). -type BufferLRU struct { - MaxSize FileSize - - actualSize FileSize - ll *list.List - cache map[int64]*list.Element - mut sync.Mutex -} - -// NewBufferLRU creates a new BufferLRU with the given maximum size. The maximum -// size will never be exceeded. -func NewBufferLRU(maxSize FileSize) *BufferLRU { - return &BufferLRU{MaxSize: maxSize} -} - -// NewBufferLRUDefault creates a new BufferLRU with the default cache size. -func NewBufferLRUDefault() *BufferLRU { - return &BufferLRU{MaxSize: DefaultMaxSize} -} - -type buffer struct { - Key int64 - Slice []byte -} - -// Put puts a buffer into the cache. If the buffer is already in the cache, it -// will be marked as used. Otherwise, it will be inserted. A buffers might -// be evicted to make room for the new one. -func (c *BufferLRU) Put(key int64, slice []byte) { - c.mut.Lock() - defer c.mut.Unlock() - - if c.cache == nil { - c.actualSize = 0 - c.cache = make(map[int64]*list.Element, 1000) - c.ll = list.New() - } - - bufSize := FileSize(len(slice)) - if ee, ok := c.cache[key]; ok { - oldBuf := ee.Value.(buffer) - // in this case bufSize is a delta: new size - old size - bufSize -= FileSize(len(oldBuf.Slice)) - c.ll.MoveToFront(ee) - ee.Value = buffer{key, slice} - } else { - if bufSize > c.MaxSize { - return - } - ee := c.ll.PushFront(buffer{key, slice}) - c.cache[key] = ee - } - - c.actualSize += bufSize - for c.actualSize > c.MaxSize { - last := c.ll.Back() - lastObj := last.Value.(buffer) - lastSize := FileSize(len(lastObj.Slice)) - - c.ll.Remove(last) - delete(c.cache, lastObj.Key) - c.actualSize -= lastSize - } -} - -// Get returns a buffer by its key. It marks the buffer as used. If the buffer -// is not in the cache, (nil, false) will be returned. -func (c *BufferLRU) Get(key int64) ([]byte, bool) { - c.mut.Lock() - defer c.mut.Unlock() - - ee, ok := c.cache[key] - if !ok { - return nil, false - } - - c.ll.MoveToFront(ee) - return ee.Value.(buffer).Slice, true -} - -// Clear the content of this buffer cache. -func (c *BufferLRU) Clear() { - c.mut.Lock() - defer c.mut.Unlock() - - c.ll = nil - c.cache = nil - c.actualSize = 0 -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/common.go deleted file mode 100644 index 2b7f36a5..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/common.go +++ /dev/null @@ -1,39 +0,0 @@ -package cache - -import "gopkg.in/src-d/go-git.v4/plumbing" - -const ( - Byte FileSize = 1 << (iota * 10) - KiByte - MiByte - GiByte -) - -type FileSize int64 - -const DefaultMaxSize FileSize = 96 * MiByte - -// Object is an interface to a object cache. -type Object interface { - // Put puts the given object into the cache. Whether this object will - // actually be put into the cache or not is implementation specific. - Put(o plumbing.EncodedObject) - // Get gets an object from the cache given its hash. The second return value - // is true if the object was returned, and false otherwise. - Get(k plumbing.Hash) (plumbing.EncodedObject, bool) - // Clear clears every object from the cache. - Clear() -} - -// Buffer is an interface to a buffer cache. -type Buffer interface { - // Put puts a buffer into the cache. If the buffer is already in the cache, - // it will be marked as used. Otherwise, it will be inserted. Buffer might - // be evicted to make room for the new one. - Put(key int64, slice []byte) - // Get returns a buffer by its key. It marks the buffer as used. If the - // buffer is not in the cache, (nil, false) will be returned. - Get(key int64) ([]byte, bool) - // Clear clears every object from the cache. - Clear() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go deleted file mode 100644 index cd3712b7..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/cache/object_lru.go +++ /dev/null @@ -1,101 +0,0 @@ -package cache - -import ( - "container/list" - "sync" - - "gopkg.in/src-d/go-git.v4/plumbing" -) - -// ObjectLRU implements an object cache with an LRU eviction policy and a -// maximum size (measured in object size). -type ObjectLRU struct { - MaxSize FileSize - - actualSize FileSize - ll *list.List - cache map[interface{}]*list.Element - mut sync.Mutex -} - -// NewObjectLRU creates a new ObjectLRU with the given maximum size. The maximum -// size will never be exceeded. -func NewObjectLRU(maxSize FileSize) *ObjectLRU { - return &ObjectLRU{MaxSize: maxSize} -} - -// NewObjectLRUDefault creates a new ObjectLRU with the default cache size. -func NewObjectLRUDefault() *ObjectLRU { - return &ObjectLRU{MaxSize: DefaultMaxSize} -} - -// Put puts an object into the cache. If the object is already in the cache, it -// will be marked as used. Otherwise, it will be inserted. A single object might -// be evicted to make room for the new object. -func (c *ObjectLRU) Put(obj plumbing.EncodedObject) { - c.mut.Lock() - defer c.mut.Unlock() - - if c.cache == nil { - c.actualSize = 0 - c.cache = make(map[interface{}]*list.Element, 1000) - c.ll = list.New() - } - - objSize := FileSize(obj.Size()) - key := obj.Hash() - if ee, ok := c.cache[key]; ok { - oldObj := ee.Value.(plumbing.EncodedObject) - // in this case objSize is a delta: new size - old size - objSize -= FileSize(oldObj.Size()) - c.ll.MoveToFront(ee) - ee.Value = obj - } else { - if objSize > c.MaxSize { - return - } - ee := c.ll.PushFront(obj) - c.cache[key] = ee - } - - c.actualSize += objSize - for c.actualSize > c.MaxSize { - last := c.ll.Back() - if last == nil { - c.actualSize = 0 - break - } - - lastObj := last.Value.(plumbing.EncodedObject) - lastSize := FileSize(lastObj.Size()) - - c.ll.Remove(last) - delete(c.cache, lastObj.Hash()) - c.actualSize -= lastSize - } -} - -// Get returns an object by its hash. It marks the object as used. If the object -// is not in the cache, (nil, false) will be returned. -func (c *ObjectLRU) Get(k plumbing.Hash) (plumbing.EncodedObject, bool) { - c.mut.Lock() - defer c.mut.Unlock() - - ee, ok := c.cache[k] - if !ok { - return nil, false - } - - c.ll.MoveToFront(ee) - return ee.Value.(plumbing.EncodedObject), true -} - -// Clear the content of this object cache. -func (c *ObjectLRU) Clear() { - c.mut.Lock() - defer c.mut.Unlock() - - c.ll = nil - c.cache = nil - c.actualSize = 0 -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/dir.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/dir.go deleted file mode 100644 index 1e88970e..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/dir.go +++ /dev/null @@ -1,136 +0,0 @@ -package gitignore - -import ( - "bytes" - "io/ioutil" - "os" - "os/user" - "strings" - - "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-git.v4/plumbing/format/config" - gioutil "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -const ( - commentPrefix = "#" - coreSection = "core" - eol = "\n" - excludesfile = "excludesfile" - gitDir = ".git" - gitignoreFile = ".gitignore" - gitconfigFile = ".gitconfig" - systemFile = "/etc/gitconfig" -) - -// readIgnoreFile reads a specific git ignore file. -func readIgnoreFile(fs billy.Filesystem, path []string, ignoreFile string) (ps []Pattern, err error) { - f, err := fs.Open(fs.Join(append(path, ignoreFile)...)) - if err == nil { - defer f.Close() - - if data, err := ioutil.ReadAll(f); err == nil { - for _, s := range strings.Split(string(data), eol) { - if !strings.HasPrefix(s, commentPrefix) && len(strings.TrimSpace(s)) > 0 { - ps = append(ps, ParsePattern(s, path)) - } - } - } - } else if !os.IsNotExist(err) { - return nil, err - } - - return -} - -// ReadPatterns reads gitignore patterns recursively traversing through the directory -// structure. The result is in the ascending order of priority (last higher). -func ReadPatterns(fs billy.Filesystem, path []string) (ps []Pattern, err error) { - ps, _ = readIgnoreFile(fs, path, gitignoreFile) - - var fis []os.FileInfo - fis, err = fs.ReadDir(fs.Join(path...)) - if err != nil { - return - } - - for _, fi := range fis { - if fi.IsDir() && fi.Name() != gitDir { - var subps []Pattern - subps, err = ReadPatterns(fs, append(path, fi.Name())) - if err != nil { - return - } - - if len(subps) > 0 { - ps = append(ps, subps...) - } - } - } - - return -} - -func loadPatterns(fs billy.Filesystem, path string) (ps []Pattern, err error) { - f, err := fs.Open(path) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - - defer gioutil.CheckClose(f, &err) - - b, err := ioutil.ReadAll(f) - if err != nil { - return - } - - d := config.NewDecoder(bytes.NewBuffer(b)) - - raw := config.New() - if err = d.Decode(raw); err != nil { - return - } - - s := raw.Section(coreSection) - efo := s.Options.Get(excludesfile) - if efo == "" { - return nil, nil - } - - ps, err = readIgnoreFile(fs, nil, efo) - if os.IsNotExist(err) { - return nil, nil - } - - return -} - -// LoadGlobalPatterns loads gitignore patterns from from the gitignore file -// declared in a user's ~/.gitconfig file. If the ~/.gitconfig file does not -// exist the function will return nil. If the core.excludesfile property -// is not declared, the function will return nil. If the file pointed to by -// the core.excludesfile property does not exist, the function will return nil. -// -// The function assumes fs is rooted at the root filesystem. -func LoadGlobalPatterns(fs billy.Filesystem) (ps []Pattern, err error) { - usr, err := user.Current() - if err != nil { - return - } - - return loadPatterns(fs, fs.Join(usr.HomeDir, gitconfigFile)) -} - -// LoadSystemPatterns loads gitignore patterns from from the gitignore file -// declared in a system's /etc/gitconfig file. If the ~/.gitconfig file does -// not exist the function will return nil. If the core.excludesfile property -// is not declared, the function will return nil. If the file pointed to by -// the core.excludesfile property does not exist, the function will return nil. -// -// The function assumes fs is rooted at the root filesystem. -func LoadSystemPatterns(fs billy.Filesystem) (ps []Pattern, err error) { - return loadPatterns(fs, systemFile) -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/doc.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/doc.go deleted file mode 100644 index eecd4bac..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/doc.go +++ /dev/null @@ -1,70 +0,0 @@ -// Package gitignore implements matching file system paths to gitignore patterns that -// can be automatically read from a git repository tree in the order of definition -// priorities. It support all pattern formats as specified in the original gitignore -// documentation, copied below: -// -// Pattern format -// ============== -// -// - A blank line matches no files, so it can serve as a separator for readability. -// -// - A line starting with # serves as a comment. Put a backslash ("\") in front of -// the first hash for patterns that begin with a hash. -// -// - Trailing spaces are ignored unless they are quoted with backslash ("\"). -// -// - An optional prefix "!" which negates the pattern; any matching file excluded -// by a previous pattern will become included again. It is not possible to -// re-include a file if a parent directory of that file is excluded. -// Git doesn’t list excluded directories for performance reasons, so -// any patterns on contained files have no effect, no matter where they are -// defined. Put a backslash ("\") in front of the first "!" for patterns -// that begin with a literal "!", for example, "\!important!.txt". -// -// - If the pattern ends with a slash, it is removed for the purpose of the -// following description, but it would only find a match with a directory. -// In other words, foo/ will match a directory foo and paths underneath it, -// but will not match a regular file or a symbolic link foo (this is consistent -// with the way how pathspec works in general in Git). -// -// - If the pattern does not contain a slash /, Git treats it as a shell glob -// pattern and checks for a match against the pathname relative to the location -// of the .gitignore file (relative to the toplevel of the work tree if not -// from a .gitignore file). -// -// - Otherwise, Git treats the pattern as a shell glob suitable for consumption -// by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will -// not match a / in the pathname. For example, "Documentation/*.html" matches -// "Documentation/git.html" but not "Documentation/ppc/ppc.html" or -// "tools/perf/Documentation/perf.html". -// -// - A leading slash matches the beginning of the pathname. For example, -// "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". -// -// Two consecutive asterisks ("**") in patterns matched against full pathname -// may have special meaning: -// -// - A leading "**" followed by a slash means match in all directories. -// For example, "**/foo" matches file or directory "foo" anywhere, the same as -// pattern "foo". "**/foo/bar" matches file or directory "bar" -// anywhere that is directly under directory "foo". -// -// - A trailing "/**" matches everything inside. For example, "abc/**" matches -// all files inside directory "abc", relative to the location of the -// .gitignore file, with infinite depth. -// -// - A slash followed by two consecutive asterisks then a slash matches -// zero or more directories. For example, "a/**/b" matches "a/b", "a/x/b", -// "a/x/y/b" and so on. -// -// - Other consecutive asterisks are considered invalid. -// -// Copyright and license -// ===================== -// -// Copyright (c) Oleg Sklyar, Silvertern and source{d} -// -// The package code was donated to source{d} to include, modify and develop -// further as a part of the `go-git` project, release it on the license of -// the whole project or delete it from the project. -package gitignore diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/matcher.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/matcher.go deleted file mode 100644 index bd1e9e2d..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/matcher.go +++ /dev/null @@ -1,30 +0,0 @@ -package gitignore - -// Matcher defines a global multi-pattern matcher for gitignore patterns -type Matcher interface { - // Match matches patterns in the order of priorities. As soon as an inclusion or - // exclusion is found, not further matching is performed. - Match(path []string, isDir bool) bool -} - -// NewMatcher constructs a new global matcher. Patterns must be given in the order of -// increasing priority. That is most generic settings files first, then the content of -// the repo .gitignore, then content of .gitignore down the path or the repo and then -// the content command line arguments. -func NewMatcher(ps []Pattern) Matcher { - return &matcher{ps} -} - -type matcher struct { - patterns []Pattern -} - -func (m *matcher) Match(path []string, isDir bool) bool { - n := len(m.patterns) - for i := n - 1; i >= 0; i-- { - if match := m.patterns[i].Match(path, isDir); match > NoMatch { - return match == Exclude - } - } - return false -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/pattern.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/pattern.go deleted file mode 100644 index 098cb502..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/gitignore/pattern.go +++ /dev/null @@ -1,153 +0,0 @@ -package gitignore - -import ( - "path/filepath" - "strings" -) - -// MatchResult defines outcomes of a match, no match, exclusion or inclusion. -type MatchResult int - -const ( - // NoMatch defines the no match outcome of a match check - NoMatch MatchResult = iota - // Exclude defines an exclusion of a file as a result of a match check - Exclude - // Include defines an explicit inclusion of a file as a result of a match check - Include -) - -const ( - inclusionPrefix = "!" - zeroToManyDirs = "**" - patternDirSep = "/" -) - -// Pattern defines a single gitignore pattern. -type Pattern interface { - // Match matches the given path to the pattern. - Match(path []string, isDir bool) MatchResult -} - -type pattern struct { - domain []string - pattern []string - inclusion bool - dirOnly bool - isGlob bool -} - -// ParsePattern parses a gitignore pattern string into the Pattern structure. -func ParsePattern(p string, domain []string) Pattern { - res := pattern{domain: domain} - - if strings.HasPrefix(p, inclusionPrefix) { - res.inclusion = true - p = p[1:] - } - - if !strings.HasSuffix(p, "\\ ") { - p = strings.TrimRight(p, " ") - } - - if strings.HasSuffix(p, patternDirSep) { - res.dirOnly = true - p = p[:len(p)-1] - } - - if strings.Contains(p, patternDirSep) { - res.isGlob = true - } - - res.pattern = strings.Split(p, patternDirSep) - return &res -} - -func (p *pattern) Match(path []string, isDir bool) MatchResult { - if len(path) <= len(p.domain) { - return NoMatch - } - for i, e := range p.domain { - if path[i] != e { - return NoMatch - } - } - - path = path[len(p.domain):] - if p.isGlob && !p.globMatch(path, isDir) { - return NoMatch - } else if !p.isGlob && !p.simpleNameMatch(path, isDir) { - return NoMatch - } - - if p.inclusion { - return Include - } else { - return Exclude - } -} - -func (p *pattern) simpleNameMatch(path []string, isDir bool) bool { - for i, name := range path { - if match, err := filepath.Match(p.pattern[0], name); err != nil { - return false - } else if !match { - continue - } - if p.dirOnly && !isDir && i == len(path)-1 { - return false - } - return true - } - return false -} - -func (p *pattern) globMatch(path []string, isDir bool) bool { - matched := false - canTraverse := false - for i, pattern := range p.pattern { - if pattern == "" { - canTraverse = false - continue - } - if pattern == zeroToManyDirs { - if i == len(p.pattern)-1 { - break - } - canTraverse = true - continue - } - if strings.Contains(pattern, zeroToManyDirs) { - return false - } - if len(path) == 0 { - return false - } - if canTraverse { - canTraverse = false - for len(path) > 0 { - e := path[0] - path = path[1:] - if match, err := filepath.Match(pattern, e); err != nil { - return false - } else if match { - matched = true - break - } else if len(path) == 0 { - // if nothing left then fail - matched = false - } - } - } else { - if match, err := filepath.Match(pattern, path[0]); err != nil || !match { - return false - } - matched = true - path = path[1:] - } - } - if matched && p.dirOnly && !isDir && len(path) == 0 { - matched = false - } - return matched -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/decoder.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/decoder.go deleted file mode 100644 index 9e9c1769..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/decoder.go +++ /dev/null @@ -1,177 +0,0 @@ -package idxfile - -import ( - "bufio" - "bytes" - "errors" - "io" - - "gopkg.in/src-d/go-git.v4/utils/binary" -) - -var ( - // ErrUnsupportedVersion is returned by Decode when the idx file version - // is not supported. - ErrUnsupportedVersion = errors.New("Unsuported version") - // ErrMalformedIdxFile is returned by Decode when the idx file is corrupted. - ErrMalformedIdxFile = errors.New("Malformed IDX file") -) - -const ( - fanout = 256 - objectIDLength = 20 -) - -// Decoder reads and decodes idx files from an input stream. -type Decoder struct { - *bufio.Reader -} - -// NewDecoder builds a new idx stream decoder, that reads from r. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{bufio.NewReader(r)} -} - -// Decode reads from the stream and decode the content into the MemoryIndex struct. -func (d *Decoder) Decode(idx *MemoryIndex) error { - if err := validateHeader(d); err != nil { - return err - } - - flow := []func(*MemoryIndex, io.Reader) error{ - readVersion, - readFanout, - readObjectNames, - readCRC32, - readOffsets, - readChecksums, - } - - for _, f := range flow { - if err := f(idx, d); err != nil { - return err - } - } - - return nil -} - -func validateHeader(r io.Reader) error { - var h = make([]byte, 4) - if _, err := io.ReadFull(r, h); err != nil { - return err - } - - if !bytes.Equal(h, idxHeader) { - return ErrMalformedIdxFile - } - - return nil -} - -func readVersion(idx *MemoryIndex, r io.Reader) error { - v, err := binary.ReadUint32(r) - if err != nil { - return err - } - - if v > VersionSupported { - return ErrUnsupportedVersion - } - - idx.Version = v - return nil -} - -func readFanout(idx *MemoryIndex, r io.Reader) error { - for k := 0; k < fanout; k++ { - n, err := binary.ReadUint32(r) - if err != nil { - return err - } - - idx.Fanout[k] = n - idx.FanoutMapping[k] = noMapping - } - - return nil -} - -func readObjectNames(idx *MemoryIndex, r io.Reader) error { - for k := 0; k < fanout; k++ { - var buckets uint32 - if k == 0 { - buckets = idx.Fanout[k] - } else { - buckets = idx.Fanout[k] - idx.Fanout[k-1] - } - - if buckets == 0 { - continue - } - - idx.FanoutMapping[k] = len(idx.Names) - - nameLen := int(buckets * objectIDLength) - bin := make([]byte, nameLen) - if _, err := io.ReadFull(r, bin); err != nil { - return err - } - - idx.Names = append(idx.Names, bin) - idx.Offset32 = append(idx.Offset32, make([]byte, buckets*4)) - idx.CRC32 = append(idx.CRC32, make([]byte, buckets*4)) - } - - return nil -} - -func readCRC32(idx *MemoryIndex, r io.Reader) error { - for k := 0; k < fanout; k++ { - if pos := idx.FanoutMapping[k]; pos != noMapping { - if _, err := io.ReadFull(r, idx.CRC32[pos]); err != nil { - return err - } - } - } - - return nil -} - -func readOffsets(idx *MemoryIndex, r io.Reader) error { - var o64cnt int - for k := 0; k < fanout; k++ { - if pos := idx.FanoutMapping[k]; pos != noMapping { - if _, err := io.ReadFull(r, idx.Offset32[pos]); err != nil { - return err - } - - for p := 0; p < len(idx.Offset32[pos]); p += 4 { - if idx.Offset32[pos][p]&(byte(1)<<7) > 0 { - o64cnt++ - } - } - } - } - - if o64cnt > 0 { - idx.Offset64 = make([]byte, o64cnt*8) - if _, err := io.ReadFull(r, idx.Offset64); err != nil { - return err - } - } - - return nil -} - -func readChecksums(idx *MemoryIndex, r io.Reader) error { - if _, err := io.ReadFull(r, idx.PackfileChecksum[:]); err != nil { - return err - } - - if _, err := io.ReadFull(r, idx.IdxChecksum[:]); err != nil { - return err - } - - return nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/doc.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/doc.go deleted file mode 100644 index 1e628ab4..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/doc.go +++ /dev/null @@ -1,128 +0,0 @@ -// Package idxfile implements encoding and decoding of packfile idx files. -// -// == Original (version 1) pack-*.idx files have the following format: -// -// - The header consists of 256 4-byte network byte order -// integers. N-th entry of this table records the number of -// objects in the corresponding pack, the first byte of whose -// object name is less than or equal to N. This is called the -// 'first-level fan-out' table. -// -// - The header is followed by sorted 24-byte entries, one entry -// per object in the pack. Each entry is: -// -// 4-byte network byte order integer, recording where the -// object is stored in the packfile as the offset from the -// beginning. -// -// 20-byte object name. -// -// - The file is concluded with a trailer: -// -// A copy of the 20-byte SHA1 checksum at the end of -// corresponding packfile. -// -// 20-byte SHA1-checksum of all of the above. -// -// Pack Idx file: -// -// -- +--------------------------------+ -// fanout | fanout[0] = 2 (for example) |-. -// table +--------------------------------+ | -// | fanout[1] | | -// +--------------------------------+ | -// | fanout[2] | | -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | -// | fanout[255] = total objects |---. -// -- +--------------------------------+ | | -// main | offset | | | -// index | object name 00XXXXXXXXXXXXXXXX | | | -// tab +--------------------------------+ | | -// | offset | | | -// | object name 00XXXXXXXXXXXXXXXX | | | -// +--------------------------------+<+ | -// .-| offset | | -// | | object name 01XXXXXXXXXXXXXXXX | | -// | +--------------------------------+ | -// | | offset | | -// | | object name 01XXXXXXXXXXXXXXXX | | -// | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | -// | | offset | | -// | | object name FFXXXXXXXXXXXXXXXX | | -// --| +--------------------------------+<--+ -// trailer | | packfile checksum | -// | +--------------------------------+ -// | | idxfile checksum | -// | +--------------------------------+ -// .---------. -// | -// Pack file entry: <+ -// -// packed object header: -// 1-byte size extension bit (MSB) -// type (next 3 bit) -// size0 (lower 4-bit) -// n-byte sizeN (as long as MSB is set, each 7-bit) -// size0..sizeN form 4+7+7+..+7 bit integer, size0 -// is the least significant part, and sizeN is the -// most significant part. -// packed object data: -// If it is not DELTA, then deflated bytes (the size above -// is the size before compression). -// If it is REF_DELTA, then -// 20-byte base object name SHA1 (the size above is the -// size of the delta data that follows). -// delta data, deflated. -// If it is OFS_DELTA, then -// n-byte offset (see below) interpreted as a negative -// offset from the type-byte of the header of the -// ofs-delta entry (the size above is the size of -// the delta data that follows). -// delta data, deflated. -// -// offset encoding: -// n bytes with MSB set in all but the last one. -// The offset is then the number constructed by -// concatenating the lower 7 bit of each byte, and -// for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1)) -// to the result. -// -// == Version 2 pack-*.idx files support packs larger than 4 GiB, and -// have some other reorganizations. They have the format: -// -// - A 4-byte magic number '\377tOc' which is an unreasonable -// fanout[0] value. -// -// - A 4-byte version number (= 2) -// -// - A 256-entry fan-out table just like v1. -// -// - A table of sorted 20-byte SHA1 object names. These are -// packed together without offset values to reduce the cache -// footprint of the binary search for a specific object name. -// -// - A table of 4-byte CRC32 values of the packed object data. -// This is new in v2 so compressed data can be copied directly -// from pack to pack during repacking without undetected -// data corruption. -// -// - A table of 4-byte offset values (in network byte order). -// These are usually 31-bit pack file offsets, but large -// offsets are encoded as an index into the next table with -// the msbit set. -// -// - A table of 8-byte offset entries (empty for pack files less -// than 2 GiB). Pack files are organized with heavily used -// objects toward the front, so most object references should -// not need to refer to this table. -// -// - The same trailer as a v1 pack file: -// -// A copy of the 20-byte SHA1 checksum at the end of -// corresponding packfile. -// -// 20-byte SHA1-checksum of all of the above. -// -// Source: -// https://www.kernel.org/pub/software/scm/git/docs/v1.7.5/technical/pack-format.txt -package idxfile diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/encoder.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/encoder.go deleted file mode 100644 index e4795110..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/encoder.go +++ /dev/null @@ -1,142 +0,0 @@ -package idxfile - -import ( - "crypto/sha1" - "hash" - "io" - - "gopkg.in/src-d/go-git.v4/utils/binary" -) - -// Encoder writes MemoryIndex structs to an output stream. -type Encoder struct { - io.Writer - hash hash.Hash -} - -// NewEncoder returns a new stream encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - h := sha1.New() - mw := io.MultiWriter(w, h) - return &Encoder{mw, h} -} - -// Encode encodes an MemoryIndex to the encoder writer. -func (e *Encoder) Encode(idx *MemoryIndex) (int, error) { - flow := []func(*MemoryIndex) (int, error){ - e.encodeHeader, - e.encodeFanout, - e.encodeHashes, - e.encodeCRC32, - e.encodeOffsets, - e.encodeChecksums, - } - - sz := 0 - for _, f := range flow { - i, err := f(idx) - sz += i - - if err != nil { - return sz, err - } - } - - return sz, nil -} - -func (e *Encoder) encodeHeader(idx *MemoryIndex) (int, error) { - c, err := e.Write(idxHeader) - if err != nil { - return c, err - } - - return c + 4, binary.WriteUint32(e, idx.Version) -} - -func (e *Encoder) encodeFanout(idx *MemoryIndex) (int, error) { - for _, c := range idx.Fanout { - if err := binary.WriteUint32(e, c); err != nil { - return 0, err - } - } - - return fanout * 4, nil -} - -func (e *Encoder) encodeHashes(idx *MemoryIndex) (int, error) { - var size int - for k := 0; k < fanout; k++ { - pos := idx.FanoutMapping[k] - if pos == noMapping { - continue - } - - n, err := e.Write(idx.Names[pos]) - if err != nil { - return size, err - } - size += n - } - return size, nil -} - -func (e *Encoder) encodeCRC32(idx *MemoryIndex) (int, error) { - var size int - for k := 0; k < fanout; k++ { - pos := idx.FanoutMapping[k] - if pos == noMapping { - continue - } - - n, err := e.Write(idx.CRC32[pos]) - if err != nil { - return size, err - } - - size += n - } - - return size, nil -} - -func (e *Encoder) encodeOffsets(idx *MemoryIndex) (int, error) { - var size int - for k := 0; k < fanout; k++ { - pos := idx.FanoutMapping[k] - if pos == noMapping { - continue - } - - n, err := e.Write(idx.Offset32[pos]) - if err != nil { - return size, err - } - - size += n - } - - if len(idx.Offset64) > 0 { - n, err := e.Write(idx.Offset64) - if err != nil { - return size, err - } - - size += n - } - - return size, nil -} - -func (e *Encoder) encodeChecksums(idx *MemoryIndex) (int, error) { - if _, err := e.Write(idx.PackfileChecksum[:]); err != nil { - return 0, err - } - - copy(idx.IdxChecksum[:], e.hash.Sum(nil)[:20]) - if _, err := e.Write(idx.IdxChecksum[:]); err != nil { - return 0, err - } - - return 40, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/idxfile.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/idxfile.go deleted file mode 100644 index 14b58603..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/idxfile.go +++ /dev/null @@ -1,346 +0,0 @@ -package idxfile - -import ( - "bytes" - "io" - "sort" - - encbin "encoding/binary" - - "gopkg.in/src-d/go-git.v4/plumbing" -) - -const ( - // VersionSupported is the only idx version supported. - VersionSupported = 2 - - noMapping = -1 -) - -var ( - idxHeader = []byte{255, 't', 'O', 'c'} -) - -// Index represents an index of a packfile. -type Index interface { - // Contains checks whether the given hash is in the index. - Contains(h plumbing.Hash) (bool, error) - // FindOffset finds the offset in the packfile for the object with - // the given hash. - FindOffset(h plumbing.Hash) (int64, error) - // FindCRC32 finds the CRC32 of the object with the given hash. - FindCRC32(h plumbing.Hash) (uint32, error) - // FindHash finds the hash for the object with the given offset. - FindHash(o int64) (plumbing.Hash, error) - // Count returns the number of entries in the index. - Count() (int64, error) - // Entries returns an iterator to retrieve all index entries. - Entries() (EntryIter, error) - // EntriesByOffset returns an iterator to retrieve all index entries ordered - // by offset. - EntriesByOffset() (EntryIter, error) -} - -// MemoryIndex is the in memory representation of an idx file. -type MemoryIndex struct { - Version uint32 - Fanout [256]uint32 - // FanoutMapping maps the position in the fanout table to the position - // in the Names, Offset32 and CRC32 slices. This improves the memory - // usage by not needing an array with unnecessary empty slots. - FanoutMapping [256]int - Names [][]byte - Offset32 [][]byte - CRC32 [][]byte - Offset64 []byte - PackfileChecksum [20]byte - IdxChecksum [20]byte - - offsetHash map[int64]plumbing.Hash - offsetHashIsFull bool -} - -var _ Index = (*MemoryIndex)(nil) - -// NewMemoryIndex returns an instance of a new MemoryIndex. -func NewMemoryIndex() *MemoryIndex { - return &MemoryIndex{} -} - -func (idx *MemoryIndex) findHashIndex(h plumbing.Hash) (int, bool) { - k := idx.FanoutMapping[h[0]] - if k == noMapping { - return 0, false - } - - if len(idx.Names) <= k { - return 0, false - } - - data := idx.Names[k] - high := uint64(len(idx.Offset32[k])) >> 2 - if high == 0 { - return 0, false - } - - low := uint64(0) - for { - mid := (low + high) >> 1 - offset := mid * objectIDLength - - cmp := bytes.Compare(h[:], data[offset:offset+objectIDLength]) - if cmp < 0 { - high = mid - } else if cmp == 0 { - return int(mid), true - } else { - low = mid + 1 - } - - if low >= high { - break - } - } - - return 0, false -} - -// Contains implements the Index interface. -func (idx *MemoryIndex) Contains(h plumbing.Hash) (bool, error) { - _, ok := idx.findHashIndex(h) - return ok, nil -} - -// FindOffset implements the Index interface. -func (idx *MemoryIndex) FindOffset(h plumbing.Hash) (int64, error) { - if len(idx.FanoutMapping) <= int(h[0]) { - return 0, plumbing.ErrObjectNotFound - } - - k := idx.FanoutMapping[h[0]] - i, ok := idx.findHashIndex(h) - if !ok { - return 0, plumbing.ErrObjectNotFound - } - - offset := idx.getOffset(k, i) - - if !idx.offsetHashIsFull { - // Save the offset for reverse lookup - if idx.offsetHash == nil { - idx.offsetHash = make(map[int64]plumbing.Hash) - } - idx.offsetHash[int64(offset)] = h - } - - return int64(offset), nil -} - -const isO64Mask = uint64(1) << 31 - -func (idx *MemoryIndex) getOffset(firstLevel, secondLevel int) uint64 { - offset := secondLevel << 2 - ofs := encbin.BigEndian.Uint32(idx.Offset32[firstLevel][offset : offset+4]) - - if (uint64(ofs) & isO64Mask) != 0 { - offset := 8 * (uint64(ofs) & ^isO64Mask) - n := encbin.BigEndian.Uint64(idx.Offset64[offset : offset+8]) - return n - } - - return uint64(ofs) -} - -// FindCRC32 implements the Index interface. -func (idx *MemoryIndex) FindCRC32(h plumbing.Hash) (uint32, error) { - k := idx.FanoutMapping[h[0]] - i, ok := idx.findHashIndex(h) - if !ok { - return 0, plumbing.ErrObjectNotFound - } - - return idx.getCRC32(k, i), nil -} - -func (idx *MemoryIndex) getCRC32(firstLevel, secondLevel int) uint32 { - offset := secondLevel << 2 - return encbin.BigEndian.Uint32(idx.CRC32[firstLevel][offset : offset+4]) -} - -// FindHash implements the Index interface. -func (idx *MemoryIndex) FindHash(o int64) (plumbing.Hash, error) { - var hash plumbing.Hash - var ok bool - - if idx.offsetHash != nil { - if hash, ok = idx.offsetHash[o]; ok { - return hash, nil - } - } - - // Lazily generate the reverse offset/hash map if required. - if !idx.offsetHashIsFull || idx.offsetHash == nil { - if err := idx.genOffsetHash(); err != nil { - return plumbing.ZeroHash, err - } - - hash, ok = idx.offsetHash[o] - } - - if !ok { - return plumbing.ZeroHash, plumbing.ErrObjectNotFound - } - - return hash, nil -} - -// genOffsetHash generates the offset/hash mapping for reverse search. -func (idx *MemoryIndex) genOffsetHash() error { - count, err := idx.Count() - if err != nil { - return err - } - - idx.offsetHash = make(map[int64]plumbing.Hash, count) - idx.offsetHashIsFull = true - - var hash plumbing.Hash - i := uint32(0) - for firstLevel, fanoutValue := range idx.Fanout { - mappedFirstLevel := idx.FanoutMapping[firstLevel] - for secondLevel := uint32(0); i < fanoutValue; i++ { - copy(hash[:], idx.Names[mappedFirstLevel][secondLevel*objectIDLength:]) - offset := int64(idx.getOffset(mappedFirstLevel, int(secondLevel))) - idx.offsetHash[offset] = hash - secondLevel++ - } - } - - return nil -} - -// Count implements the Index interface. -func (idx *MemoryIndex) Count() (int64, error) { - return int64(idx.Fanout[fanout-1]), nil -} - -// Entries implements the Index interface. -func (idx *MemoryIndex) Entries() (EntryIter, error) { - return &idxfileEntryIter{idx, 0, 0, 0}, nil -} - -// EntriesByOffset implements the Index interface. -func (idx *MemoryIndex) EntriesByOffset() (EntryIter, error) { - count, err := idx.Count() - if err != nil { - return nil, err - } - - iter := &idxfileEntryOffsetIter{ - entries: make(entriesByOffset, count), - } - - entries, err := idx.Entries() - if err != nil { - return nil, err - } - - for pos := 0; int64(pos) < count; pos++ { - entry, err := entries.Next() - if err != nil { - return nil, err - } - - iter.entries[pos] = entry - } - - sort.Sort(iter.entries) - - return iter, nil -} - -// EntryIter is an iterator that will return the entries in a packfile index. -type EntryIter interface { - // Next returns the next entry in the packfile index. - Next() (*Entry, error) - // Close closes the iterator. - Close() error -} - -type idxfileEntryIter struct { - idx *MemoryIndex - total int - firstLevel, secondLevel int -} - -func (i *idxfileEntryIter) Next() (*Entry, error) { - for { - if i.firstLevel >= fanout { - return nil, io.EOF - } - - if i.total >= int(i.idx.Fanout[i.firstLevel]) { - i.firstLevel++ - i.secondLevel = 0 - continue - } - - mappedFirstLevel := i.idx.FanoutMapping[i.firstLevel] - entry := new(Entry) - copy(entry.Hash[:], i.idx.Names[mappedFirstLevel][i.secondLevel*objectIDLength:]) - entry.Offset = i.idx.getOffset(mappedFirstLevel, i.secondLevel) - entry.CRC32 = i.idx.getCRC32(mappedFirstLevel, i.secondLevel) - - i.secondLevel++ - i.total++ - - return entry, nil - } -} - -func (i *idxfileEntryIter) Close() error { - i.firstLevel = fanout - return nil -} - -// Entry is the in memory representation of an object entry in the idx file. -type Entry struct { - Hash plumbing.Hash - CRC32 uint32 - Offset uint64 -} - -type idxfileEntryOffsetIter struct { - entries entriesByOffset - pos int -} - -func (i *idxfileEntryOffsetIter) Next() (*Entry, error) { - if i.pos >= len(i.entries) { - return nil, io.EOF - } - - entry := i.entries[i.pos] - i.pos++ - - return entry, nil -} - -func (i *idxfileEntryOffsetIter) Close() error { - i.pos = len(i.entries) + 1 - return nil -} - -type entriesByOffset []*Entry - -func (o entriesByOffset) Len() int { - return len(o) -} - -func (o entriesByOffset) Less(i int, j int) bool { - return o[i].Offset < o[j].Offset -} - -func (o entriesByOffset) Swap(i int, j int) { - o[i], o[j] = o[j], o[i] -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/writer.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/writer.go deleted file mode 100644 index fcc78c56..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/idxfile/writer.go +++ /dev/null @@ -1,186 +0,0 @@ -package idxfile - -import ( - "bytes" - "fmt" - "math" - "sort" - "sync" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/utils/binary" -) - -// objects implements sort.Interface and uses hash as sorting key. -type objects []Entry - -// Writer implements a packfile Observer interface and is used to generate -// indexes. -type Writer struct { - m sync.Mutex - - count uint32 - checksum plumbing.Hash - objects objects - offset64 uint32 - finished bool - index *MemoryIndex - added map[plumbing.Hash]struct{} -} - -// Index returns a previously created MemoryIndex or creates a new one if -// needed. -func (w *Writer) Index() (*MemoryIndex, error) { - w.m.Lock() - defer w.m.Unlock() - - if w.index == nil { - return w.createIndex() - } - - return w.index, nil -} - -// Add appends new object data. -func (w *Writer) Add(h plumbing.Hash, pos uint64, crc uint32) { - w.m.Lock() - defer w.m.Unlock() - - if w.added == nil { - w.added = make(map[plumbing.Hash]struct{}) - } - - if _, ok := w.added[h]; !ok { - w.added[h] = struct{}{} - w.objects = append(w.objects, Entry{h, crc, pos}) - } - -} - -func (w *Writer) Finished() bool { - return w.finished -} - -// OnHeader implements packfile.Observer interface. -func (w *Writer) OnHeader(count uint32) error { - w.count = count - w.objects = make(objects, 0, count) - return nil -} - -// OnInflatedObjectHeader implements packfile.Observer interface. -func (w *Writer) OnInflatedObjectHeader(t plumbing.ObjectType, objSize int64, pos int64) error { - return nil -} - -// OnInflatedObjectContent implements packfile.Observer interface. -func (w *Writer) OnInflatedObjectContent(h plumbing.Hash, pos int64, crc uint32, _ []byte) error { - w.Add(h, uint64(pos), crc) - return nil -} - -// OnFooter implements packfile.Observer interface. -func (w *Writer) OnFooter(h plumbing.Hash) error { - w.checksum = h - w.finished = true - _, err := w.createIndex() - if err != nil { - return err - } - - return nil -} - -// creatIndex returns a filled MemoryIndex with the information filled by -// the observer callbacks. -func (w *Writer) createIndex() (*MemoryIndex, error) { - if !w.finished { - return nil, fmt.Errorf("the index still hasn't finished building") - } - - idx := new(MemoryIndex) - w.index = idx - - sort.Sort(w.objects) - - // unmap all fans by default - for i := range idx.FanoutMapping { - idx.FanoutMapping[i] = noMapping - } - - buf := new(bytes.Buffer) - - last := -1 - bucket := -1 - for i, o := range w.objects { - fan := o.Hash[0] - - // fill the gaps between fans - for j := last + 1; j < int(fan); j++ { - idx.Fanout[j] = uint32(i) - } - - // update the number of objects for this position - idx.Fanout[fan] = uint32(i + 1) - - // we move from one bucket to another, update counters and allocate - // memory - if last != int(fan) { - bucket++ - idx.FanoutMapping[fan] = bucket - last = int(fan) - - idx.Names = append(idx.Names, make([]byte, 0)) - idx.Offset32 = append(idx.Offset32, make([]byte, 0)) - idx.CRC32 = append(idx.CRC32, make([]byte, 0)) - } - - idx.Names[bucket] = append(idx.Names[bucket], o.Hash[:]...) - - offset := o.Offset - if offset > math.MaxInt32 { - offset = w.addOffset64(offset) - } - - buf.Truncate(0) - binary.WriteUint32(buf, uint32(offset)) - idx.Offset32[bucket] = append(idx.Offset32[bucket], buf.Bytes()...) - - buf.Truncate(0) - binary.WriteUint32(buf, o.CRC32) - idx.CRC32[bucket] = append(idx.CRC32[bucket], buf.Bytes()...) - } - - for j := last + 1; j < 256; j++ { - idx.Fanout[j] = uint32(len(w.objects)) - } - - idx.Version = VersionSupported - idx.PackfileChecksum = w.checksum - - return idx, nil -} - -func (w *Writer) addOffset64(pos uint64) uint64 { - buf := new(bytes.Buffer) - binary.WriteUint64(buf, pos) - w.index.Offset64 = append(w.index.Offset64, buf.Bytes()...) - - index := uint64(w.offset64 | (1 << 31)) - w.offset64++ - - return index -} - -func (o objects) Len() int { - return len(o) -} - -func (o objects) Less(i int, j int) bool { - cmp := bytes.Compare(o[i].Hash[:], o[j].Hash[:]) - return cmp < 0 -} - -func (o objects) Swap(i int, j int) { - o[i], o[j] = o[j], o[i] -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/doc.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/doc.go deleted file mode 100644 index a7145160..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package objfile implements encoding and decoding of object files. -package objfile diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/reader.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/reader.go deleted file mode 100644 index c4467e48..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/reader.go +++ /dev/null @@ -1,114 +0,0 @@ -package objfile - -import ( - "compress/zlib" - "errors" - "io" - "strconv" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" -) - -var ( - ErrClosed = errors.New("objfile: already closed") - ErrHeader = errors.New("objfile: invalid header") - ErrNegativeSize = errors.New("objfile: negative object size") -) - -// Reader reads and decodes compressed objfile data from a provided io.Reader. -// Reader implements io.ReadCloser. Close should be called when finished with -// the Reader. Close will not close the underlying io.Reader. -type Reader struct { - multi io.Reader - zlib io.ReadCloser - hasher plumbing.Hasher -} - -// NewReader returns a new Reader reading from r. -func NewReader(r io.Reader) (*Reader, error) { - zlib, err := zlib.NewReader(r) - if err != nil { - return nil, packfile.ErrZLib.AddDetails(err.Error()) - } - - return &Reader{ - zlib: zlib, - }, nil -} - -// Header reads the type and the size of object, and prepares the reader for read -func (r *Reader) Header() (t plumbing.ObjectType, size int64, err error) { - var raw []byte - raw, err = r.readUntil(' ') - if err != nil { - return - } - - t, err = plumbing.ParseObjectType(string(raw)) - if err != nil { - return - } - - raw, err = r.readUntil(0) - if err != nil { - return - } - - size, err = strconv.ParseInt(string(raw), 10, 64) - if err != nil { - err = ErrHeader - return - } - - defer r.prepareForRead(t, size) - return -} - -// readSlice reads one byte at a time from r until it encounters delim or an -// error. -func (r *Reader) readUntil(delim byte) ([]byte, error) { - var buf [1]byte - value := make([]byte, 0, 16) - for { - if n, err := r.zlib.Read(buf[:]); err != nil && (err != io.EOF || n == 0) { - if err == io.EOF { - return nil, ErrHeader - } - return nil, err - } - - if buf[0] == delim { - return value, nil - } - - value = append(value, buf[0]) - } -} - -func (r *Reader) prepareForRead(t plumbing.ObjectType, size int64) { - r.hasher = plumbing.NewHasher(t, size) - r.multi = io.TeeReader(r.zlib, r.hasher) -} - -// Read reads len(p) bytes into p from the object data stream. It returns -// the number of bytes read (0 <= n <= len(p)) and any error encountered. Even -// if Read returns n < len(p), it may use all of p as scratch space during the -// call. -// -// If Read encounters the end of the data stream it will return err == io.EOF, -// either in the current call if n > 0 or in a subsequent call. -func (r *Reader) Read(p []byte) (n int, err error) { - return r.multi.Read(p) -} - -// Hash returns the hash of the object data stream that has been read so far. -func (r *Reader) Hash() plumbing.Hash { - return r.hasher.Sum() -} - -// Close releases any resources consumed by the Reader. Calling Close does not -// close the wrapped io.Reader originally passed to NewReader. -func (r *Reader) Close() error { - return r.zlib.Close() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/writer.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/writer.go deleted file mode 100644 index 55552434..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/objfile/writer.go +++ /dev/null @@ -1,109 +0,0 @@ -package objfile - -import ( - "compress/zlib" - "errors" - "io" - "strconv" - - "gopkg.in/src-d/go-git.v4/plumbing" -) - -var ( - ErrOverflow = errors.New("objfile: declared data length exceeded (overflow)") -) - -// Writer writes and encodes data in compressed objfile format to a provided -// io.Writer. Close should be called when finished with the Writer. Close will -// not close the underlying io.Writer. -type Writer struct { - raw io.Writer - zlib io.WriteCloser - hasher plumbing.Hasher - multi io.Writer - - closed bool - pending int64 // number of unwritten bytes -} - -// NewWriter returns a new Writer writing to w. -// -// The returned Writer implements io.WriteCloser. Close should be called when -// finished with the Writer. Close will not close the underlying io.Writer. -func NewWriter(w io.Writer) *Writer { - return &Writer{ - raw: w, - zlib: zlib.NewWriter(w), - } -} - -// WriteHeader writes the type and the size and prepares to accept the object's -// contents. If an invalid t is provided, plumbing.ErrInvalidType is returned. If a -// negative size is provided, ErrNegativeSize is returned. -func (w *Writer) WriteHeader(t plumbing.ObjectType, size int64) error { - if !t.Valid() { - return plumbing.ErrInvalidType - } - if size < 0 { - return ErrNegativeSize - } - - b := t.Bytes() - b = append(b, ' ') - b = append(b, []byte(strconv.FormatInt(size, 10))...) - b = append(b, 0) - - defer w.prepareForWrite(t, size) - _, err := w.zlib.Write(b) - - return err -} - -func (w *Writer) prepareForWrite(t plumbing.ObjectType, size int64) { - w.pending = size - - w.hasher = plumbing.NewHasher(t, size) - w.multi = io.MultiWriter(w.zlib, w.hasher) -} - -// Write writes the object's contents. Write returns the error ErrOverflow if -// more than size bytes are written after WriteHeader. -func (w *Writer) Write(p []byte) (n int, err error) { - if w.closed { - return 0, ErrClosed - } - - overwrite := false - if int64(len(p)) > w.pending { - p = p[0:w.pending] - overwrite = true - } - - n, err = w.multi.Write(p) - w.pending -= int64(n) - if err == nil && overwrite { - err = ErrOverflow - return - } - - return -} - -// Hash returns the hash of the object data stream that has been written so far. -// It can be called before or after Close. -func (w *Writer) Hash() plumbing.Hash { - return w.hasher.Sum() // Not yet closed, return hash of data written so far -} - -// Close releases any resources consumed by the Writer. -// -// Calling Close does not close the wrapped io.Writer originally passed to -// NewWriter. -func (w *Writer) Close() error { - if err := w.zlib.Close(); err != nil { - return err - } - - w.closed = true - return nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go deleted file mode 100644 index f82c1abe..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/common.go +++ /dev/null @@ -1,78 +0,0 @@ -package packfile - -import ( - "bytes" - "compress/zlib" - "io" - "sync" - - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -var signature = []byte{'P', 'A', 'C', 'K'} - -const ( - // VersionSupported is the packfile version supported by this package - VersionSupported uint32 = 2 - - firstLengthBits = uint8(4) // the first byte into object header has 4 bits to store the length - lengthBits = uint8(7) // subsequent bytes has 7 bits to store the length - maskFirstLength = 15 // 0000 1111 - maskContinue = 0x80 // 1000 0000 - maskLength = uint8(127) // 0111 1111 - maskType = uint8(112) // 0111 0000 -) - -// UpdateObjectStorage updates the storer with the objects in the given -// packfile. -func UpdateObjectStorage(s storer.Storer, packfile io.Reader) error { - if pw, ok := s.(storer.PackfileWriter); ok { - return WritePackfileToObjectStorage(pw, packfile) - } - - p, err := NewParserWithStorage(NewScanner(packfile), s) - if err != nil { - return err - } - - _, err = p.Parse() - return err -} - -// WritePackfileToObjectStorage writes all the packfile objects into the given -// object storage. -func WritePackfileToObjectStorage( - sw storer.PackfileWriter, - packfile io.Reader, -) (err error) { - w, err := sw.PackfileWriter() - if err != nil { - return err - } - - defer ioutil.CheckClose(w, &err) - - var n int64 - n, err = io.Copy(w, packfile) - if err == nil && n == 0 { - return ErrEmptyPackfile - } - - return err -} - -var bufPool = sync.Pool{ - New: func() interface{} { - return bytes.NewBuffer(nil) - }, -} - -var zlibInitBytes = []byte{0x78, 0x9c, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01} - -var zlibReaderPool = sync.Pool{ - New: func() interface{} { - r, _ := zlib.NewReader(bytes.NewReader(zlibInitBytes)) - return r - }, -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_index.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_index.go deleted file mode 100644 index 07a61120..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_index.go +++ /dev/null @@ -1,297 +0,0 @@ -package packfile - -const blksz = 16 -const maxChainLength = 64 - -// deltaIndex is a modified version of JGit's DeltaIndex adapted to our current -// design. -type deltaIndex struct { - table []int - entries []int - mask int -} - -func (idx *deltaIndex) init(buf []byte) { - scanner := newDeltaIndexScanner(buf, len(buf)) - idx.mask = scanner.mask - idx.table = scanner.table - idx.entries = make([]int, countEntries(scanner)+1) - idx.copyEntries(scanner) -} - -// findMatch returns the offset of src where the block starting at tgtOffset -// is and the length of the match. A length of 0 means there was no match. A -// length of -1 means the src length is lower than the blksz and whatever -// other positive length is the length of the match in bytes. -func (idx *deltaIndex) findMatch(src, tgt []byte, tgtOffset int) (srcOffset, l int) { - if len(tgt) < tgtOffset+s { - return 0, len(tgt) - tgtOffset - } - - if len(src) < blksz { - return 0, -1 - } - - if len(tgt) >= tgtOffset+s && len(src) >= blksz { - h := hashBlock(tgt, tgtOffset) - tIdx := h & idx.mask - eIdx := idx.table[tIdx] - if eIdx != 0 { - srcOffset = idx.entries[eIdx] - } else { - return - } - - l = matchLength(src, tgt, tgtOffset, srcOffset) - } - - return -} - -func matchLength(src, tgt []byte, otgt, osrc int) (l int) { - lensrc := len(src) - lentgt := len(tgt) - for (osrc < lensrc && otgt < lentgt) && src[osrc] == tgt[otgt] { - l++ - osrc++ - otgt++ - } - return -} - -func countEntries(scan *deltaIndexScanner) (cnt int) { - // Figure out exactly how many entries we need. As we do the - // enumeration truncate any delta chains longer than what we - // are willing to scan during encode. This keeps the encode - // logic linear in the size of the input rather than quadratic. - for i := 0; i < len(scan.table); i++ { - h := scan.table[i] - if h == 0 { - continue - } - - size := 0 - for { - size++ - if size == maxChainLength { - scan.next[h] = 0 - break - } - h = scan.next[h] - - if h == 0 { - break - } - } - cnt += size - } - - return -} - -func (idx *deltaIndex) copyEntries(scanner *deltaIndexScanner) { - // Rebuild the entries list from the scanner, positioning all - // blocks in the same hash chain next to each other. We can - // then later discard the next list, along with the scanner. - // - next := 1 - for i := 0; i < len(idx.table); i++ { - h := idx.table[i] - if h == 0 { - continue - } - - idx.table[i] = next - for { - idx.entries[next] = scanner.entries[h] - next++ - h = scanner.next[h] - - if h == 0 { - break - } - } - } -} - -type deltaIndexScanner struct { - table []int - entries []int - next []int - mask int - count int -} - -func newDeltaIndexScanner(buf []byte, size int) *deltaIndexScanner { - size -= size % blksz - worstCaseBlockCnt := size / blksz - if worstCaseBlockCnt < 1 { - return new(deltaIndexScanner) - } - - tableSize := tableSize(worstCaseBlockCnt) - scanner := &deltaIndexScanner{ - table: make([]int, tableSize), - mask: tableSize - 1, - entries: make([]int, worstCaseBlockCnt+1), - next: make([]int, worstCaseBlockCnt+1), - } - - scanner.scan(buf, size) - return scanner -} - -// slightly modified version of JGit's DeltaIndexScanner. We store the offset on the entries -// instead of the entries and the key, so we avoid operations to retrieve the offset later, as -// we don't use the key. -// See: https://github.com/eclipse/jgit/blob/005e5feb4ecd08c4e4d141a38b9e7942accb3212/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java -func (s *deltaIndexScanner) scan(buf []byte, end int) { - lastHash := 0 - ptr := end - blksz - - for { - key := hashBlock(buf, ptr) - tIdx := key & s.mask - head := s.table[tIdx] - if head != 0 && lastHash == key { - s.entries[head] = ptr - } else { - s.count++ - eIdx := s.count - s.entries[eIdx] = ptr - s.next[eIdx] = head - s.table[tIdx] = eIdx - } - - lastHash = key - ptr -= blksz - - if 0 > ptr { - break - } - } -} - -func tableSize(worstCaseBlockCnt int) int { - shift := 32 - leadingZeros(uint32(worstCaseBlockCnt)) - sz := 1 << uint(shift-1) - if sz < worstCaseBlockCnt { - sz <<= 1 - } - return sz -} - -// use https://golang.org/pkg/math/bits/#LeadingZeros32 in the future -func leadingZeros(x uint32) (n int) { - if x >= 1<<16 { - x >>= 16 - n = 16 - } - if x >= 1<<8 { - x >>= 8 - n += 8 - } - n += int(len8tab[x]) - return 32 - n -} - -var len8tab = [256]uint8{ - 0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, -} - -func hashBlock(raw []byte, ptr int) int { - // The first 4 steps collapse out into a 4 byte big-endian decode, - // with a larger right shift as we combined shift lefts together. - // - hash := ((uint32(raw[ptr]) & 0xff) << 24) | - ((uint32(raw[ptr+1]) & 0xff) << 16) | - ((uint32(raw[ptr+2]) & 0xff) << 8) | - (uint32(raw[ptr+3]) & 0xff) - hash ^= T[hash>>31] - - hash = ((hash << 8) | (uint32(raw[ptr+4]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+5]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+6]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+7]) & 0xff)) ^ T[hash>>23] - - hash = ((hash << 8) | (uint32(raw[ptr+8]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+9]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+10]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+11]) & 0xff)) ^ T[hash>>23] - - hash = ((hash << 8) | (uint32(raw[ptr+12]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+13]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+14]) & 0xff)) ^ T[hash>>23] - hash = ((hash << 8) | (uint32(raw[ptr+15]) & 0xff)) ^ T[hash>>23] - - return int(hash) -} - -var T = []uint32{0x00000000, 0xd4c6b32d, 0x7d4bd577, - 0xa98d665a, 0x2e5119c3, 0xfa97aaee, 0x531accb4, 0x87dc7f99, - 0x5ca23386, 0x886480ab, 0x21e9e6f1, 0xf52f55dc, 0x72f32a45, - 0xa6359968, 0x0fb8ff32, 0xdb7e4c1f, 0x6d82d421, 0xb944670c, - 0x10c90156, 0xc40fb27b, 0x43d3cde2, 0x97157ecf, 0x3e981895, - 0xea5eabb8, 0x3120e7a7, 0xe5e6548a, 0x4c6b32d0, 0x98ad81fd, - 0x1f71fe64, 0xcbb74d49, 0x623a2b13, 0xb6fc983e, 0x0fc31b6f, - 0xdb05a842, 0x7288ce18, 0xa64e7d35, 0x219202ac, 0xf554b181, - 0x5cd9d7db, 0x881f64f6, 0x536128e9, 0x87a79bc4, 0x2e2afd9e, - 0xfaec4eb3, 0x7d30312a, 0xa9f68207, 0x007be45d, 0xd4bd5770, - 0x6241cf4e, 0xb6877c63, 0x1f0a1a39, 0xcbcca914, 0x4c10d68d, - 0x98d665a0, 0x315b03fa, 0xe59db0d7, 0x3ee3fcc8, 0xea254fe5, - 0x43a829bf, 0x976e9a92, 0x10b2e50b, 0xc4745626, 0x6df9307c, - 0xb93f8351, 0x1f8636de, 0xcb4085f3, 0x62cde3a9, 0xb60b5084, - 0x31d72f1d, 0xe5119c30, 0x4c9cfa6a, 0x985a4947, 0x43240558, - 0x97e2b675, 0x3e6fd02f, 0xeaa96302, 0x6d751c9b, 0xb9b3afb6, - 0x103ec9ec, 0xc4f87ac1, 0x7204e2ff, 0xa6c251d2, 0x0f4f3788, - 0xdb8984a5, 0x5c55fb3c, 0x88934811, 0x211e2e4b, 0xf5d89d66, - 0x2ea6d179, 0xfa606254, 0x53ed040e, 0x872bb723, 0x00f7c8ba, - 0xd4317b97, 0x7dbc1dcd, 0xa97aaee0, 0x10452db1, 0xc4839e9c, - 0x6d0ef8c6, 0xb9c84beb, 0x3e143472, 0xead2875f, 0x435fe105, - 0x97995228, 0x4ce71e37, 0x9821ad1a, 0x31accb40, 0xe56a786d, - 0x62b607f4, 0xb670b4d9, 0x1ffdd283, 0xcb3b61ae, 0x7dc7f990, - 0xa9014abd, 0x008c2ce7, 0xd44a9fca, 0x5396e053, 0x8750537e, - 0x2edd3524, 0xfa1b8609, 0x2165ca16, 0xf5a3793b, 0x5c2e1f61, - 0x88e8ac4c, 0x0f34d3d5, 0xdbf260f8, 0x727f06a2, 0xa6b9b58f, - 0x3f0c6dbc, 0xebcade91, 0x4247b8cb, 0x96810be6, 0x115d747f, - 0xc59bc752, 0x6c16a108, 0xb8d01225, 0x63ae5e3a, 0xb768ed17, - 0x1ee58b4d, 0xca233860, 0x4dff47f9, 0x9939f4d4, 0x30b4928e, - 0xe47221a3, 0x528eb99d, 0x86480ab0, 0x2fc56cea, 0xfb03dfc7, - 0x7cdfa05e, 0xa8191373, 0x01947529, 0xd552c604, 0x0e2c8a1b, - 0xdaea3936, 0x73675f6c, 0xa7a1ec41, 0x207d93d8, 0xf4bb20f5, - 0x5d3646af, 0x89f0f582, 0x30cf76d3, 0xe409c5fe, 0x4d84a3a4, - 0x99421089, 0x1e9e6f10, 0xca58dc3d, 0x63d5ba67, 0xb713094a, - 0x6c6d4555, 0xb8abf678, 0x11269022, 0xc5e0230f, 0x423c5c96, - 0x96faefbb, 0x3f7789e1, 0xebb13acc, 0x5d4da2f2, 0x898b11df, - 0x20067785, 0xf4c0c4a8, 0x731cbb31, 0xa7da081c, 0x0e576e46, - 0xda91dd6b, 0x01ef9174, 0xd5292259, 0x7ca44403, 0xa862f72e, - 0x2fbe88b7, 0xfb783b9a, 0x52f55dc0, 0x8633eeed, 0x208a5b62, - 0xf44ce84f, 0x5dc18e15, 0x89073d38, 0x0edb42a1, 0xda1df18c, - 0x739097d6, 0xa75624fb, 0x7c2868e4, 0xa8eedbc9, 0x0163bd93, - 0xd5a50ebe, 0x52797127, 0x86bfc20a, 0x2f32a450, 0xfbf4177d, - 0x4d088f43, 0x99ce3c6e, 0x30435a34, 0xe485e919, 0x63599680, - 0xb79f25ad, 0x1e1243f7, 0xcad4f0da, 0x11aabcc5, 0xc56c0fe8, - 0x6ce169b2, 0xb827da9f, 0x3ffba506, 0xeb3d162b, 0x42b07071, - 0x9676c35c, 0x2f49400d, 0xfb8ff320, 0x5202957a, 0x86c42657, - 0x011859ce, 0xd5deeae3, 0x7c538cb9, 0xa8953f94, 0x73eb738b, - 0xa72dc0a6, 0x0ea0a6fc, 0xda6615d1, 0x5dba6a48, 0x897cd965, - 0x20f1bf3f, 0xf4370c12, 0x42cb942c, 0x960d2701, 0x3f80415b, - 0xeb46f276, 0x6c9a8def, 0xb85c3ec2, 0x11d15898, 0xc517ebb5, - 0x1e69a7aa, 0xcaaf1487, 0x632272dd, 0xb7e4c1f0, 0x3038be69, - 0xe4fe0d44, 0x4d736b1e, 0x99b5d833, -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_selector.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_selector.go deleted file mode 100644 index 67100855..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/delta_selector.go +++ /dev/null @@ -1,369 +0,0 @@ -package packfile - -import ( - "sort" - "sync" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" -) - -const ( - // deltas based on deltas, how many steps we can do. - // 50 is the default value used in JGit - maxDepth = int64(50) -) - -// applyDelta is the set of object types that we should apply deltas -var applyDelta = map[plumbing.ObjectType]bool{ - plumbing.BlobObject: true, - plumbing.TreeObject: true, -} - -type deltaSelector struct { - storer storer.EncodedObjectStorer -} - -func newDeltaSelector(s storer.EncodedObjectStorer) *deltaSelector { - return &deltaSelector{s} -} - -// ObjectsToPack creates a list of ObjectToPack from the hashes -// provided, creating deltas if it's suitable, using an specific -// internal logic. `packWindow` specifies the size of the sliding -// window used to compare objects for delta compression; 0 turns off -// delta compression entirely. -func (dw *deltaSelector) ObjectsToPack( - hashes []plumbing.Hash, - packWindow uint, -) ([]*ObjectToPack, error) { - otp, err := dw.objectsToPack(hashes, packWindow) - if err != nil { - return nil, err - } - - if packWindow == 0 { - return otp, nil - } - - dw.sort(otp) - - var objectGroups [][]*ObjectToPack - var prev *ObjectToPack - i := -1 - for _, obj := range otp { - if prev == nil || prev.Type() != obj.Type() { - objectGroups = append(objectGroups, []*ObjectToPack{obj}) - i++ - prev = obj - } else { - objectGroups[i] = append(objectGroups[i], obj) - } - } - - var wg sync.WaitGroup - var once sync.Once - for _, objs := range objectGroups { - objs := objs - wg.Add(1) - go func() { - if walkErr := dw.walk(objs, packWindow); walkErr != nil { - once.Do(func() { - err = walkErr - }) - } - wg.Done() - }() - } - wg.Wait() - - if err != nil { - return nil, err - } - - return otp, nil -} - -func (dw *deltaSelector) objectsToPack( - hashes []plumbing.Hash, - packWindow uint, -) ([]*ObjectToPack, error) { - var objectsToPack []*ObjectToPack - for _, h := range hashes { - var o plumbing.EncodedObject - var err error - if packWindow == 0 { - o, err = dw.encodedObject(h) - } else { - o, err = dw.encodedDeltaObject(h) - } - if err != nil { - return nil, err - } - - otp := newObjectToPack(o) - if _, ok := o.(plumbing.DeltaObject); ok { - otp.CleanOriginal() - } - - objectsToPack = append(objectsToPack, otp) - } - - if packWindow == 0 { - return objectsToPack, nil - } - - if err := dw.fixAndBreakChains(objectsToPack); err != nil { - return nil, err - } - - return objectsToPack, nil -} - -func (dw *deltaSelector) encodedDeltaObject(h plumbing.Hash) (plumbing.EncodedObject, error) { - edos, ok := dw.storer.(storer.DeltaObjectStorer) - if !ok { - return dw.encodedObject(h) - } - - return edos.DeltaObject(plumbing.AnyObject, h) -} - -func (dw *deltaSelector) encodedObject(h plumbing.Hash) (plumbing.EncodedObject, error) { - return dw.storer.EncodedObject(plumbing.AnyObject, h) -} - -func (dw *deltaSelector) fixAndBreakChains(objectsToPack []*ObjectToPack) error { - m := make(map[plumbing.Hash]*ObjectToPack, len(objectsToPack)) - for _, otp := range objectsToPack { - m[otp.Hash()] = otp - } - - for _, otp := range objectsToPack { - if err := dw.fixAndBreakChainsOne(m, otp); err != nil { - return err - } - } - - return nil -} - -func (dw *deltaSelector) fixAndBreakChainsOne(objectsToPack map[plumbing.Hash]*ObjectToPack, otp *ObjectToPack) error { - if !otp.Object.Type().IsDelta() { - return nil - } - - // Initial ObjectToPack instances might have a delta assigned to Object - // but no actual base initially. Once Base is assigned to a delta, it means - // we already fixed it. - if otp.Base != nil { - return nil - } - - do, ok := otp.Object.(plumbing.DeltaObject) - if !ok { - // if this is not a DeltaObject, then we cannot retrieve its base, - // so we have to break the delta chain here. - return dw.undeltify(otp) - } - - base, ok := objectsToPack[do.BaseHash()] - if !ok { - // The base of the delta is not in our list of objects to pack, so - // we break the chain. - return dw.undeltify(otp) - } - - if err := dw.fixAndBreakChainsOne(objectsToPack, base); err != nil { - return err - } - - otp.SetDelta(base, otp.Object) - return nil -} - -func (dw *deltaSelector) restoreOriginal(otp *ObjectToPack) error { - if otp.Original != nil { - return nil - } - - if !otp.Object.Type().IsDelta() { - return nil - } - - obj, err := dw.encodedObject(otp.Hash()) - if err != nil { - return err - } - - otp.SetOriginal(obj) - - return nil -} - -// undeltify undeltifies an *ObjectToPack by retrieving the original object from -// the storer and resetting it. -func (dw *deltaSelector) undeltify(otp *ObjectToPack) error { - if err := dw.restoreOriginal(otp); err != nil { - return err - } - - otp.Object = otp.Original - otp.Depth = 0 - return nil -} - -func (dw *deltaSelector) sort(objectsToPack []*ObjectToPack) { - sort.Sort(byTypeAndSize(objectsToPack)) -} - -func (dw *deltaSelector) walk( - objectsToPack []*ObjectToPack, - packWindow uint, -) error { - indexMap := make(map[plumbing.Hash]*deltaIndex) - for i := 0; i < len(objectsToPack); i++ { - // Clean up the index map and reconstructed delta objects for anything - // outside our pack window, to save memory. - if i > int(packWindow) { - obj := objectsToPack[i-int(packWindow)] - - delete(indexMap, obj.Hash()) - - if obj.IsDelta() { - obj.SaveOriginalMetadata() - obj.CleanOriginal() - } - } - - target := objectsToPack[i] - - // If we already have a delta, we don't try to find a new one for this - // object. This happens when a delta is set to be reused from an existing - // packfile. - if target.IsDelta() { - continue - } - - // We only want to create deltas from specific types. - if !applyDelta[target.Type()] { - continue - } - - for j := i - 1; j >= 0 && i-j < int(packWindow); j-- { - base := objectsToPack[j] - // Objects must use only the same type as their delta base. - // Since objectsToPack is sorted by type and size, once we find - // a different type, we know we won't find more of them. - if base.Type() != target.Type() { - break - } - - if err := dw.tryToDeltify(indexMap, base, target); err != nil { - return err - } - } - } - - return nil -} - -func (dw *deltaSelector) tryToDeltify(indexMap map[plumbing.Hash]*deltaIndex, base, target *ObjectToPack) error { - // Original object might not be present if we're reusing a delta, so we - // ensure it is restored. - if err := dw.restoreOriginal(target); err != nil { - return err - } - - if err := dw.restoreOriginal(base); err != nil { - return err - } - - // If the sizes are radically different, this is a bad pairing. - if target.Size() < base.Size()>>4 { - return nil - } - - msz := dw.deltaSizeLimit( - target.Object.Size(), - base.Depth, - target.Depth, - target.IsDelta(), - ) - - // Nearly impossible to fit useful delta. - if msz <= 8 { - return nil - } - - // If we have to insert a lot to make this work, find another. - if base.Size()-target.Size() > msz { - return nil - } - - if _, ok := indexMap[base.Hash()]; !ok { - indexMap[base.Hash()] = new(deltaIndex) - } - - // Now we can generate the delta using originals - delta, err := getDelta(indexMap[base.Hash()], base.Original, target.Original) - if err != nil { - return err - } - - // if delta better than target - if delta.Size() < msz { - target.SetDelta(base, delta) - } - - return nil -} - -func (dw *deltaSelector) deltaSizeLimit(targetSize int64, baseDepth int, - targetDepth int, targetDelta bool) int64 { - if !targetDelta { - // Any delta should be no more than 50% of the original size - // (for text files deflate of whole form should shrink 50%). - n := targetSize >> 1 - - // Evenly distribute delta size limits over allowed depth. - // If src is non-delta (depth = 0), delta <= 50% of original. - // If src is almost at limit (9/10), delta <= 10% of original. - return n * (maxDepth - int64(baseDepth)) / maxDepth - } - - // With a delta base chosen any new delta must be "better". - // Retain the distribution described above. - d := int64(targetDepth) - n := targetSize - - // If target depth is bigger than maxDepth, this delta is not suitable to be used. - if d >= maxDepth { - return 0 - } - - // If src is whole (depth=0) and base is near limit (depth=9/10) - // any delta using src can be 10x larger and still be better. - // - // If src is near limit (depth=9/10) and base is whole (depth=0) - // a new delta dependent on src must be 1/10th the size. - return n * (maxDepth - int64(baseDepth)) / (maxDepth - d) -} - -type byTypeAndSize []*ObjectToPack - -func (a byTypeAndSize) Len() int { return len(a) } - -func (a byTypeAndSize) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func (a byTypeAndSize) Less(i, j int) bool { - if a[i].Type() < a[j].Type() { - return false - } - - if a[i].Type() > a[j].Type() { - return true - } - - return a[i].Size() > a[j].Size() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/diff_delta.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/diff_delta.go deleted file mode 100644 index 43f87a0b..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/diff_delta.go +++ /dev/null @@ -1,200 +0,0 @@ -package packfile - -import ( - "bytes" - - "gopkg.in/src-d/go-git.v4/plumbing" -) - -// See https://github.com/jelmer/dulwich/blob/master/dulwich/pack.py and -// https://github.com/tarruda/node-git-core/blob/master/src/js/delta.js -// for more info - -const ( - // Standard chunk size used to generate fingerprints - s = 16 - - // https://github.com/git/git/blob/f7466e94375b3be27f229c78873f0acf8301c0a5/diff-delta.c#L428 - // Max size of a copy operation (64KB) - maxCopySize = 64 * 1024 -) - -// GetDelta returns an EncodedObject of type OFSDeltaObject. Base and Target object, -// will be loaded into memory to be able to create the delta object. -// To generate target again, you will need the obtained object and "base" one. -// Error will be returned if base or target object cannot be read. -func GetDelta(base, target plumbing.EncodedObject) (plumbing.EncodedObject, error) { - return getDelta(new(deltaIndex), base, target) -} - -func getDelta(index *deltaIndex, base, target plumbing.EncodedObject) (plumbing.EncodedObject, error) { - br, err := base.Reader() - if err != nil { - return nil, err - } - defer br.Close() - tr, err := target.Reader() - if err != nil { - return nil, err - } - defer tr.Close() - - bb := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(bb) - bb.Reset() - - _, err = bb.ReadFrom(br) - if err != nil { - return nil, err - } - - tb := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(tb) - tb.Reset() - - _, err = tb.ReadFrom(tr) - if err != nil { - return nil, err - } - - db := diffDelta(index, bb.Bytes(), tb.Bytes()) - delta := &plumbing.MemoryObject{} - _, err = delta.Write(db) - if err != nil { - return nil, err - } - - delta.SetSize(int64(len(db))) - delta.SetType(plumbing.OFSDeltaObject) - - return delta, nil -} - -// DiffDelta returns the delta that transforms src into tgt. -func DiffDelta(src, tgt []byte) []byte { - return diffDelta(new(deltaIndex), src, tgt) -} - -func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte { - buf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(buf) - buf.Reset() - buf.Write(deltaEncodeSize(len(src))) - buf.Write(deltaEncodeSize(len(tgt))) - - if len(index.entries) == 0 { - index.init(src) - } - - ibuf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(ibuf) - ibuf.Reset() - for i := 0; i < len(tgt); i++ { - offset, l := index.findMatch(src, tgt, i) - - if l == 0 { - // couldn't find a match, just write the current byte and continue - ibuf.WriteByte(tgt[i]) - } else if l < 0 { - // src is less than blksz, copy the rest of the target to avoid - // calls to findMatch - for ; i < len(tgt); i++ { - ibuf.WriteByte(tgt[i]) - } - } else if l < s { - // remaining target is less than blksz, copy what's left of it - // and avoid calls to findMatch - for j := i; j < i+l; j++ { - ibuf.WriteByte(tgt[j]) - } - i += l - 1 - } else { - encodeInsertOperation(ibuf, buf) - - rl := l - aOffset := offset - for rl > 0 { - if rl < maxCopySize { - buf.Write(encodeCopyOperation(aOffset, rl)) - break - } - - buf.Write(encodeCopyOperation(aOffset, maxCopySize)) - rl -= maxCopySize - aOffset += maxCopySize - } - - i += l - 1 - } - } - - encodeInsertOperation(ibuf, buf) - - // buf.Bytes() is only valid until the next modifying operation on the buffer. Copy it. - return append([]byte{}, buf.Bytes()...) -} - -func encodeInsertOperation(ibuf, buf *bytes.Buffer) { - if ibuf.Len() == 0 { - return - } - - b := ibuf.Bytes() - s := ibuf.Len() - o := 0 - for { - if s <= 127 { - break - } - buf.WriteByte(byte(127)) - buf.Write(b[o : o+127]) - s -= 127 - o += 127 - } - buf.WriteByte(byte(s)) - buf.Write(b[o : o+s]) - - ibuf.Reset() -} - -func deltaEncodeSize(size int) []byte { - var ret []byte - c := size & 0x7f - size >>= 7 - for { - if size == 0 { - break - } - - ret = append(ret, byte(c|0x80)) - c = size & 0x7f - size >>= 7 - } - ret = append(ret, byte(c)) - - return ret -} - -func encodeCopyOperation(offset, length int) []byte { - code := 0x80 - var opcodes []byte - - var i uint - for i = 0; i < 4; i++ { - f := 0xff << (i * 8) - if offset&f != 0 { - opcodes = append(opcodes, byte(offset&f>>(i*8))) - code |= 0x01 << i - } - } - - for i = 0; i < 3; i++ { - f := 0xff << (i * 8) - if length&f != 0 { - opcodes = append(opcodes, byte(length&f>>(i*8))) - code |= 0x10 << i - } - } - - return append([]byte{byte(code)}, opcodes...) -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/doc.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/doc.go deleted file mode 100644 index 2882a7f3..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/doc.go +++ /dev/null @@ -1,39 +0,0 @@ -// Package packfile implements encoding and decoding of packfile format. -// -// == pack-*.pack files have the following format: -// -// - A header appears at the beginning and consists of the following: -// -// 4-byte signature: -// The signature is: {'P', 'A', 'C', 'K'} -// -// 4-byte version number (network byte order): -// GIT currently accepts version number 2 or 3 but -// generates version 2 only. -// -// 4-byte number of objects contained in the pack (network byte order) -// -// Observation: we cannot have more than 4G versions ;-) and -// more than 4G objects in a pack. -// -// - The header is followed by number of object entries, each of -// which looks like this: -// -// (undeltified representation) -// n-byte type and length (3-bit type, (n-1)*7+4-bit length) -// compressed data -// -// (deltified representation) -// n-byte type and length (3-bit type, (n-1)*7+4-bit length) -// 20-byte base object name -// compressed delta data -// -// Observation: length of each object is encoded in a variable -// length format and is not constrained to 32-bit or anything. -// -// - The trailer records 20-byte SHA1 checksum of all of the above. -// -// -// Source: -// https://www.kernel.org/pub/software/scm/git/docs/v1.7.5/technical/pack-protocol.txt -package packfile diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/encoder.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/encoder.go deleted file mode 100644 index b0779187..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/encoder.go +++ /dev/null @@ -1,219 +0,0 @@ -package packfile - -import ( - "compress/zlib" - "crypto/sha1" - "fmt" - "io" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/utils/binary" -) - -// Encoder gets the data from the storage and write it into the writer in PACK -// format -type Encoder struct { - selector *deltaSelector - w *offsetWriter - zw *zlib.Writer - hasher plumbing.Hasher - - useRefDeltas bool -} - -// NewEncoder creates a new packfile encoder using a specific Writer and -// EncodedObjectStorer. By default deltas used to generate the packfile will be -// OFSDeltaObject. To use Reference deltas, set useRefDeltas to true. -func NewEncoder(w io.Writer, s storer.EncodedObjectStorer, useRefDeltas bool) *Encoder { - h := plumbing.Hasher{ - Hash: sha1.New(), - } - mw := io.MultiWriter(w, h) - ow := newOffsetWriter(mw) - zw := zlib.NewWriter(mw) - return &Encoder{ - selector: newDeltaSelector(s), - w: ow, - zw: zw, - hasher: h, - useRefDeltas: useRefDeltas, - } -} - -// Encode creates a packfile containing all the objects referenced in -// hashes and writes it to the writer in the Encoder. `packWindow` -// specifies the size of the sliding window used to compare objects -// for delta compression; 0 turns off delta compression entirely. -func (e *Encoder) Encode( - hashes []plumbing.Hash, - packWindow uint, -) (plumbing.Hash, error) { - objects, err := e.selector.ObjectsToPack(hashes, packWindow) - if err != nil { - return plumbing.ZeroHash, err - } - - return e.encode(objects) -} - -func (e *Encoder) encode(objects []*ObjectToPack) (plumbing.Hash, error) { - if err := e.head(len(objects)); err != nil { - return plumbing.ZeroHash, err - } - - for _, o := range objects { - if err := e.entry(o); err != nil { - return plumbing.ZeroHash, err - } - } - - return e.footer() -} - -func (e *Encoder) head(numEntries int) error { - return binary.Write( - e.w, - signature, - int32(VersionSupported), - int32(numEntries), - ) -} - -func (e *Encoder) entry(o *ObjectToPack) error { - if o.WantWrite() { - // A cycle exists in this delta chain. This should only occur if a - // selected object representation disappeared during writing - // (for example due to a concurrent repack) and a different base - // was chosen, forcing a cycle. Select something other than a - // delta, and write this object. - e.selector.restoreOriginal(o) - o.BackToOriginal() - } - - if o.IsWritten() { - return nil - } - - o.MarkWantWrite() - - if err := e.writeBaseIfDelta(o); err != nil { - return err - } - - // We need to check if we already write that object due a cyclic delta chain - if o.IsWritten() { - return nil - } - - o.Offset = e.w.Offset() - - if o.IsDelta() { - if err := e.writeDeltaHeader(o); err != nil { - return err - } - } else { - if err := e.entryHead(o.Type(), o.Size()); err != nil { - return err - } - } - - e.zw.Reset(e.w) - or, err := o.Object.Reader() - if err != nil { - return err - } - - _, err = io.Copy(e.zw, or) - if err != nil { - return err - } - - return e.zw.Close() -} - -func (e *Encoder) writeBaseIfDelta(o *ObjectToPack) error { - if o.IsDelta() && !o.Base.IsWritten() { - // We must write base first - return e.entry(o.Base) - } - - return nil -} - -func (e *Encoder) writeDeltaHeader(o *ObjectToPack) error { - // Write offset deltas by default - t := plumbing.OFSDeltaObject - if e.useRefDeltas { - t = plumbing.REFDeltaObject - } - - if err := e.entryHead(t, o.Object.Size()); err != nil { - return err - } - - if e.useRefDeltas { - return e.writeRefDeltaHeader(o.Base.Hash()) - } else { - return e.writeOfsDeltaHeader(o) - } -} - -func (e *Encoder) writeRefDeltaHeader(base plumbing.Hash) error { - return binary.Write(e.w, base) -} - -func (e *Encoder) writeOfsDeltaHeader(o *ObjectToPack) error { - // for OFS_DELTA, offset of the base is interpreted as negative offset - // relative to the type-byte of the header of the ofs-delta entry. - relativeOffset := o.Offset - o.Base.Offset - if relativeOffset <= 0 { - return fmt.Errorf("bad offset for OFS_DELTA entry: %d", relativeOffset) - } - - return binary.WriteVariableWidthInt(e.w, relativeOffset) -} - -func (e *Encoder) entryHead(typeNum plumbing.ObjectType, size int64) error { - t := int64(typeNum) - header := []byte{} - c := (t << firstLengthBits) | (size & maskFirstLength) - size >>= firstLengthBits - for { - if size == 0 { - break - } - header = append(header, byte(c|maskContinue)) - c = size & int64(maskLength) - size >>= lengthBits - } - - header = append(header, byte(c)) - _, err := e.w.Write(header) - - return err -} - -func (e *Encoder) footer() (plumbing.Hash, error) { - h := e.hasher.Sum() - return h, binary.Write(e.w, h) -} - -type offsetWriter struct { - w io.Writer - offset int64 -} - -func newOffsetWriter(w io.Writer) *offsetWriter { - return &offsetWriter{w: w} -} - -func (ow *offsetWriter) Write(p []byte) (n int, err error) { - n, err = ow.w.Write(p) - ow.offset += int64(n) - return n, err -} - -func (ow *offsetWriter) Offset() int64 { - return ow.offset -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/error.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/error.go deleted file mode 100644 index c0b91633..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/error.go +++ /dev/null @@ -1,30 +0,0 @@ -package packfile - -import "fmt" - -// Error specifies errors returned during packfile parsing. -type Error struct { - reason, details string -} - -// NewError returns a new error. -func NewError(reason string) *Error { - return &Error{reason: reason} -} - -// Error returns a text representation of the error. -func (e *Error) Error() string { - if e.details == "" { - return e.reason - } - - return fmt.Sprintf("%s: %s", e.reason, e.details) -} - -// AddDetails adds details to an error, with additional text. -func (e *Error) AddDetails(format string, args ...interface{}) *Error { - return &Error{ - reason: e.reason, - details: fmt.Sprintf(format, args...), - } -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go deleted file mode 100644 index a268bce7..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/fsobject.go +++ /dev/null @@ -1,116 +0,0 @@ -package packfile - -import ( - "io" - - billy "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile" -) - -// FSObject is an object from the packfile on the filesystem. -type FSObject struct { - hash plumbing.Hash - h *ObjectHeader - offset int64 - size int64 - typ plumbing.ObjectType - index idxfile.Index - fs billy.Filesystem - path string - cache cache.Object -} - -// NewFSObject creates a new filesystem object. -func NewFSObject( - hash plumbing.Hash, - finalType plumbing.ObjectType, - offset int64, - contentSize int64, - index idxfile.Index, - fs billy.Filesystem, - path string, - cache cache.Object, -) *FSObject { - return &FSObject{ - hash: hash, - offset: offset, - size: contentSize, - typ: finalType, - index: index, - fs: fs, - path: path, - cache: cache, - } -} - -// Reader implements the plumbing.EncodedObject interface. -func (o *FSObject) Reader() (io.ReadCloser, error) { - obj, ok := o.cache.Get(o.hash) - if ok && obj != o { - reader, err := obj.Reader() - if err != nil { - return nil, err - } - - return reader, nil - } - - f, err := o.fs.Open(o.path) - if err != nil { - return nil, err - } - - p := NewPackfileWithCache(o.index, nil, f, o.cache) - r, err := p.getObjectContent(o.offset) - if err != nil { - _ = f.Close() - return nil, err - } - - if err := f.Close(); err != nil { - return nil, err - } - - return r, nil -} - -// SetSize implements the plumbing.EncodedObject interface. This method -// is a noop. -func (o *FSObject) SetSize(int64) {} - -// SetType implements the plumbing.EncodedObject interface. This method is -// a noop. -func (o *FSObject) SetType(plumbing.ObjectType) {} - -// Hash implements the plumbing.EncodedObject interface. -func (o *FSObject) Hash() plumbing.Hash { return o.hash } - -// Size implements the plumbing.EncodedObject interface. -func (o *FSObject) Size() int64 { return o.size } - -// Type implements the plumbing.EncodedObject interface. -func (o *FSObject) Type() plumbing.ObjectType { - return o.typ -} - -// Writer implements the plumbing.EncodedObject interface. This method always -// returns a nil writer. -func (o *FSObject) Writer() (io.WriteCloser, error) { - return nil, nil -} - -type objectReader struct { - io.ReadCloser - f billy.File -} - -func (r *objectReader) Close() error { - if err := r.ReadCloser.Close(); err != nil { - _ = r.f.Close() - return err - } - - return r.f.Close() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/object_pack.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/object_pack.go deleted file mode 100644 index dfea5715..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/object_pack.go +++ /dev/null @@ -1,164 +0,0 @@ -package packfile - -import ( - "gopkg.in/src-d/go-git.v4/plumbing" -) - -// ObjectToPack is a representation of an object that is going to be into a -// pack file. -type ObjectToPack struct { - // The main object to pack, it could be any object, including deltas - Object plumbing.EncodedObject - // Base is the object that a delta is based on (it could be also another delta). - // If the main object is not a delta, Base will be null - Base *ObjectToPack - // Original is the object that we can generate applying the delta to - // Base, or the same object as Object in the case of a non-delta - // object. - Original plumbing.EncodedObject - // Depth is the amount of deltas needed to resolve to obtain Original - // (delta based on delta based on ...) - Depth int - - // offset in pack when object has been already written, or 0 if it - // has not been written yet - Offset int64 - - // Information from the original object - resolvedOriginal bool - originalType plumbing.ObjectType - originalSize int64 - originalHash plumbing.Hash -} - -// newObjectToPack creates a correct ObjectToPack based on a non-delta object -func newObjectToPack(o plumbing.EncodedObject) *ObjectToPack { - return &ObjectToPack{ - Object: o, - Original: o, - } -} - -// newDeltaObjectToPack creates a correct ObjectToPack for a delta object, based on -// his base (could be another delta), the delta target (in this case called original), -// and the delta Object itself -func newDeltaObjectToPack(base *ObjectToPack, original, delta plumbing.EncodedObject) *ObjectToPack { - return &ObjectToPack{ - Object: delta, - Base: base, - Original: original, - Depth: base.Depth + 1, - } -} - -// BackToOriginal converts that ObjectToPack to a non-deltified object if it was one -func (o *ObjectToPack) BackToOriginal() { - if o.IsDelta() && o.Original != nil { - o.Object = o.Original - o.Base = nil - o.Depth = 0 - } -} - -// IsWritten returns if that ObjectToPack was -// already written into the packfile or not -func (o *ObjectToPack) IsWritten() bool { - return o.Offset > 1 -} - -// MarkWantWrite marks this ObjectToPack as WantWrite -// to avoid delta chain loops -func (o *ObjectToPack) MarkWantWrite() { - o.Offset = 1 -} - -// WantWrite checks if this ObjectToPack was marked as WantWrite before -func (o *ObjectToPack) WantWrite() bool { - return o.Offset == 1 -} - -// SetOriginal sets both Original and saves size, type and hash. If object -// is nil Original is set but previous resolved values are kept -func (o *ObjectToPack) SetOriginal(obj plumbing.EncodedObject) { - o.Original = obj - o.SaveOriginalMetadata() -} - -// SaveOriginalMetadata saves size, type and hash of Original object -func (o *ObjectToPack) SaveOriginalMetadata() { - if o.Original != nil { - o.originalSize = o.Original.Size() - o.originalType = o.Original.Type() - o.originalHash = o.Original.Hash() - o.resolvedOriginal = true - } -} - -// CleanOriginal sets Original to nil -func (o *ObjectToPack) CleanOriginal() { - o.Original = nil -} - -func (o *ObjectToPack) Type() plumbing.ObjectType { - if o.Original != nil { - return o.Original.Type() - } - - if o.resolvedOriginal { - return o.originalType - } - - if o.Base != nil { - return o.Base.Type() - } - - if o.Object != nil { - return o.Object.Type() - } - - panic("cannot get type") -} - -func (o *ObjectToPack) Hash() plumbing.Hash { - if o.Original != nil { - return o.Original.Hash() - } - - if o.resolvedOriginal { - return o.originalHash - } - - do, ok := o.Object.(plumbing.DeltaObject) - if ok { - return do.ActualHash() - } - - panic("cannot get hash") -} - -func (o *ObjectToPack) Size() int64 { - if o.Original != nil { - return o.Original.Size() - } - - if o.resolvedOriginal { - return o.originalSize - } - - do, ok := o.Object.(plumbing.DeltaObject) - if ok { - return do.ActualSize() - } - - panic("cannot get ObjectToPack size") -} - -func (o *ObjectToPack) IsDelta() bool { - return o.Base != nil -} - -func (o *ObjectToPack) SetDelta(base *ObjectToPack, delta plumbing.EncodedObject) { - o.Object = delta - o.Base = base - o.Depth = base.Depth + 1 -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go deleted file mode 100644 index 21a15de0..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/packfile.go +++ /dev/null @@ -1,562 +0,0 @@ -package packfile - -import ( - "bytes" - "io" - "os" - - billy "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile" - "gopkg.in/src-d/go-git.v4/plumbing/storer" -) - -var ( - // ErrInvalidObject is returned by Decode when an invalid object is - // found in the packfile. - ErrInvalidObject = NewError("invalid git object") - // ErrZLib is returned by Decode when there was an error unzipping - // the packfile contents. - ErrZLib = NewError("zlib reading error") -) - -// When reading small objects from packfile it is beneficial to do so at -// once to exploit the buffered I/O. In many cases the objects are so small -// that they were already loaded to memory when the object header was -// loaded from the packfile. Wrapping in FSObject would cause this buffered -// data to be thrown away and then re-read later, with the additional -// seeking causing reloads from disk. Objects smaller than this threshold -// are now always read into memory and stored in cache instead of being -// wrapped in FSObject. -const smallObjectThreshold = 16 * 1024 - -// Packfile allows retrieving information from inside a packfile. -type Packfile struct { - idxfile.Index - fs billy.Filesystem - file billy.File - s *Scanner - deltaBaseCache cache.Object - offsetToType map[int64]plumbing.ObjectType -} - -// NewPackfileWithCache creates a new Packfile with the given object cache. -// If the filesystem is provided, the packfile will return FSObjects, otherwise -// it will return MemoryObjects. -func NewPackfileWithCache( - index idxfile.Index, - fs billy.Filesystem, - file billy.File, - cache cache.Object, -) *Packfile { - s := NewScanner(file) - return &Packfile{ - index, - fs, - file, - s, - cache, - make(map[int64]plumbing.ObjectType), - } -} - -// NewPackfile returns a packfile representation for the given packfile file -// and packfile idx. -// If the filesystem is provided, the packfile will return FSObjects, otherwise -// it will return MemoryObjects. -func NewPackfile(index idxfile.Index, fs billy.Filesystem, file billy.File) *Packfile { - return NewPackfileWithCache(index, fs, file, cache.NewObjectLRUDefault()) -} - -// Get retrieves the encoded object in the packfile with the given hash. -func (p *Packfile) Get(h plumbing.Hash) (plumbing.EncodedObject, error) { - offset, err := p.FindOffset(h) - if err != nil { - return nil, err - } - - return p.objectAtOffset(offset, h) -} - -// GetByOffset retrieves the encoded object from the packfile at the given -// offset. -func (p *Packfile) GetByOffset(o int64) (plumbing.EncodedObject, error) { - hash, err := p.FindHash(o) - if err != nil { - return nil, err - } - - return p.objectAtOffset(o, hash) -} - -// GetSizeByOffset retrieves the size of the encoded object from the -// packfile with the given offset. -func (p *Packfile) GetSizeByOffset(o int64) (size int64, err error) { - if _, err := p.s.SeekFromStart(o); err != nil { - if err == io.EOF || isInvalid(err) { - return 0, plumbing.ErrObjectNotFound - } - - return 0, err - } - - h, err := p.nextObjectHeader() - if err != nil { - return 0, err - } - return p.getObjectSize(h) -} - -func (p *Packfile) objectHeaderAtOffset(offset int64) (*ObjectHeader, error) { - h, err := p.s.SeekObjectHeader(offset) - p.s.pendingObject = nil - return h, err -} - -func (p *Packfile) nextObjectHeader() (*ObjectHeader, error) { - h, err := p.s.NextObjectHeader() - p.s.pendingObject = nil - return h, err -} - -func (p *Packfile) getDeltaObjectSize(buf *bytes.Buffer) int64 { - delta := buf.Bytes() - _, delta = decodeLEB128(delta) // skip src size - sz, _ := decodeLEB128(delta) - return int64(sz) -} - -func (p *Packfile) getObjectSize(h *ObjectHeader) (int64, error) { - switch h.Type { - case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject: - return h.Length, nil - case plumbing.REFDeltaObject, plumbing.OFSDeltaObject: - buf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(buf) - buf.Reset() - - if _, _, err := p.s.NextObject(buf); err != nil { - return 0, err - } - - return p.getDeltaObjectSize(buf), nil - default: - return 0, ErrInvalidObject.AddDetails("type %q", h.Type) - } -} - -func (p *Packfile) getObjectType(h *ObjectHeader) (typ plumbing.ObjectType, err error) { - switch h.Type { - case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject: - return h.Type, nil - case plumbing.REFDeltaObject, plumbing.OFSDeltaObject: - var offset int64 - if h.Type == plumbing.REFDeltaObject { - offset, err = p.FindOffset(h.Reference) - if err != nil { - return - } - } else { - offset = h.OffsetReference - } - - if baseType, ok := p.offsetToType[offset]; ok { - typ = baseType - } else { - h, err = p.objectHeaderAtOffset(offset) - if err != nil { - return - } - - typ, err = p.getObjectType(h) - if err != nil { - return - } - } - default: - err = ErrInvalidObject.AddDetails("type %q", h.Type) - } - - p.offsetToType[h.Offset] = typ - - return -} - -func (p *Packfile) objectAtOffset(offset int64, hash plumbing.Hash) (plumbing.EncodedObject, error) { - if obj, ok := p.cacheGet(hash); ok { - return obj, nil - } - - h, err := p.objectHeaderAtOffset(offset) - if err != nil { - if err == io.EOF || isInvalid(err) { - return nil, plumbing.ErrObjectNotFound - } - return nil, err - } - - return p.getNextObject(h, hash) -} - -func (p *Packfile) getNextObject(h *ObjectHeader, hash plumbing.Hash) (plumbing.EncodedObject, error) { - var err error - - // If we have no filesystem, we will return a MemoryObject instead - // of an FSObject. - if p.fs == nil { - return p.getNextMemoryObject(h) - } - - // If the object is small enough then read it completely into memory now since - // it is already read from disk into buffer anyway. For delta objects we want - // to perform the optimization too, but we have to be careful about applying - // small deltas on big objects. - var size int64 - if h.Length <= smallObjectThreshold { - if h.Type != plumbing.OFSDeltaObject && h.Type != plumbing.REFDeltaObject { - return p.getNextMemoryObject(h) - } - - // For delta objects we read the delta data and apply the small object - // optimization only if the expanded version of the object still meets - // the small object threshold condition. - buf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(buf) - buf.Reset() - if _, _, err := p.s.NextObject(buf); err != nil { - return nil, err - } - - size = p.getDeltaObjectSize(buf) - if size <= smallObjectThreshold { - var obj = new(plumbing.MemoryObject) - obj.SetSize(size) - if h.Type == plumbing.REFDeltaObject { - err = p.fillREFDeltaObjectContentWithBuffer(obj, h.Reference, buf) - } else { - err = p.fillOFSDeltaObjectContentWithBuffer(obj, h.OffsetReference, buf) - } - return obj, err - } - } else { - size, err = p.getObjectSize(h) - if err != nil { - return nil, err - } - } - - typ, err := p.getObjectType(h) - if err != nil { - return nil, err - } - - p.offsetToType[h.Offset] = typ - - return NewFSObject( - hash, - typ, - h.Offset, - size, - p.Index, - p.fs, - p.file.Name(), - p.deltaBaseCache, - ), nil -} - -func (p *Packfile) getObjectContent(offset int64) (io.ReadCloser, error) { - h, err := p.objectHeaderAtOffset(offset) - if err != nil { - return nil, err - } - - // getObjectContent is called from FSObject, so we have to explicitly - // get memory object here to avoid recursive cycle - obj, err := p.getNextMemoryObject(h) - if err != nil { - return nil, err - } - - return obj.Reader() -} - -func (p *Packfile) getNextMemoryObject(h *ObjectHeader) (plumbing.EncodedObject, error) { - var obj = new(plumbing.MemoryObject) - obj.SetSize(h.Length) - obj.SetType(h.Type) - - var err error - switch h.Type { - case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject: - err = p.fillRegularObjectContent(obj) - case plumbing.REFDeltaObject: - err = p.fillREFDeltaObjectContent(obj, h.Reference) - case plumbing.OFSDeltaObject: - err = p.fillOFSDeltaObjectContent(obj, h.OffsetReference) - default: - err = ErrInvalidObject.AddDetails("type %q", h.Type) - } - - if err != nil { - return nil, err - } - - p.offsetToType[h.Offset] = obj.Type() - - return obj, nil -} - -func (p *Packfile) fillRegularObjectContent(obj plumbing.EncodedObject) error { - w, err := obj.Writer() - if err != nil { - return err - } - - _, _, err = p.s.NextObject(w) - p.cachePut(obj) - - return err -} - -func (p *Packfile) fillREFDeltaObjectContent(obj plumbing.EncodedObject, ref plumbing.Hash) error { - buf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(buf) - buf.Reset() - _, _, err := p.s.NextObject(buf) - if err != nil { - return err - } - - return p.fillREFDeltaObjectContentWithBuffer(obj, ref, buf) -} - -func (p *Packfile) fillREFDeltaObjectContentWithBuffer(obj plumbing.EncodedObject, ref plumbing.Hash, buf *bytes.Buffer) error { - var err error - - base, ok := p.cacheGet(ref) - if !ok { - base, err = p.Get(ref) - if err != nil { - return err - } - } - - obj.SetType(base.Type()) - err = ApplyDelta(obj, base, buf.Bytes()) - p.cachePut(obj) - - return err -} - -func (p *Packfile) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset int64) error { - buf := bufPool.Get().(*bytes.Buffer) - defer bufPool.Put(buf) - buf.Reset() - _, _, err := p.s.NextObject(buf) - if err != nil { - return err - } - - return p.fillOFSDeltaObjectContentWithBuffer(obj, offset, buf) -} - -func (p *Packfile) fillOFSDeltaObjectContentWithBuffer(obj plumbing.EncodedObject, offset int64, buf *bytes.Buffer) error { - hash, err := p.FindHash(offset) - if err != nil { - return err - } - - base, err := p.objectAtOffset(offset, hash) - if err != nil { - return err - } - - obj.SetType(base.Type()) - err = ApplyDelta(obj, base, buf.Bytes()) - p.cachePut(obj) - - return err -} - -func (p *Packfile) cacheGet(h plumbing.Hash) (plumbing.EncodedObject, bool) { - if p.deltaBaseCache == nil { - return nil, false - } - - return p.deltaBaseCache.Get(h) -} - -func (p *Packfile) cachePut(obj plumbing.EncodedObject) { - if p.deltaBaseCache == nil { - return - } - - p.deltaBaseCache.Put(obj) -} - -// GetAll returns an iterator with all encoded objects in the packfile. -// The iterator returned is not thread-safe, it should be used in the same -// thread as the Packfile instance. -func (p *Packfile) GetAll() (storer.EncodedObjectIter, error) { - return p.GetByType(plumbing.AnyObject) -} - -// GetByType returns all the objects of the given type. -func (p *Packfile) GetByType(typ plumbing.ObjectType) (storer.EncodedObjectIter, error) { - switch typ { - case plumbing.AnyObject, - plumbing.BlobObject, - plumbing.TreeObject, - plumbing.CommitObject, - plumbing.TagObject: - entries, err := p.EntriesByOffset() - if err != nil { - return nil, err - } - - return &objectIter{ - // Easiest way to provide an object decoder is just to pass a Packfile - // instance. To not mess with the seeks, it's a new instance with a - // different scanner but the same cache and offset to hash map for - // reusing as much cache as possible. - p: p, - iter: entries, - typ: typ, - }, nil - default: - return nil, plumbing.ErrInvalidType - } -} - -// ID returns the ID of the packfile, which is the checksum at the end of it. -func (p *Packfile) ID() (plumbing.Hash, error) { - prev, err := p.file.Seek(-20, io.SeekEnd) - if err != nil { - return plumbing.ZeroHash, err - } - - var hash plumbing.Hash - if _, err := io.ReadFull(p.file, hash[:]); err != nil { - return plumbing.ZeroHash, err - } - - if _, err := p.file.Seek(prev, io.SeekStart); err != nil { - return plumbing.ZeroHash, err - } - - return hash, nil -} - -// Scanner returns the packfile's Scanner -func (p *Packfile) Scanner() *Scanner { - return p.s -} - -// Close the packfile and its resources. -func (p *Packfile) Close() error { - closer, ok := p.file.(io.Closer) - if !ok { - return nil - } - - return closer.Close() -} - -type objectIter struct { - p *Packfile - typ plumbing.ObjectType - iter idxfile.EntryIter -} - -func (i *objectIter) Next() (plumbing.EncodedObject, error) { - for { - e, err := i.iter.Next() - if err != nil { - return nil, err - } - - if i.typ != plumbing.AnyObject { - if typ, ok := i.p.offsetToType[int64(e.Offset)]; ok { - if typ != i.typ { - continue - } - } else if obj, ok := i.p.cacheGet(e.Hash); ok { - if obj.Type() != i.typ { - i.p.offsetToType[int64(e.Offset)] = obj.Type() - continue - } - return obj, nil - } else { - h, err := i.p.objectHeaderAtOffset(int64(e.Offset)) - if err != nil { - return nil, err - } - - if h.Type == plumbing.REFDeltaObject || h.Type == plumbing.OFSDeltaObject { - typ, err := i.p.getObjectType(h) - if err != nil { - return nil, err - } - if typ != i.typ { - i.p.offsetToType[int64(e.Offset)] = typ - continue - } - // getObjectType will seek in the file so we cannot use getNextObject safely - return i.p.objectAtOffset(int64(e.Offset), e.Hash) - } else { - if h.Type != i.typ { - i.p.offsetToType[int64(e.Offset)] = h.Type - continue - } - return i.p.getNextObject(h, e.Hash) - } - } - } - - obj, err := i.p.objectAtOffset(int64(e.Offset), e.Hash) - if err != nil { - return nil, err - } - - return obj, nil - } -} - -func (i *objectIter) ForEach(f func(plumbing.EncodedObject) error) error { - for { - o, err := i.Next() - if err != nil { - if err == io.EOF { - return nil - } - return err - } - - if err := f(o); err != nil { - return err - } - } -} - -func (i *objectIter) Close() { - i.iter.Close() -} - -// isInvalid checks whether an error is an os.PathError with an os.ErrInvalid -// error inside. It also checks for the windows error, which is different from -// os.ErrInvalid. -func isInvalid(err error) bool { - pe, ok := err.(*os.PathError) - if !ok { - return false - } - - errstr := pe.Err.Error() - return errstr == errInvalidUnix || errstr == errInvalidWindows -} - -// errInvalidWindows is the Windows equivalent to os.ErrInvalid -const errInvalidWindows = "The parameter is incorrect." - -var errInvalidUnix = os.ErrInvalid.Error() diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go deleted file mode 100644 index 71cbba98..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/parser.go +++ /dev/null @@ -1,483 +0,0 @@ -package packfile - -import ( - "bytes" - "errors" - "io" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/storer" -) - -var ( - // ErrReferenceDeltaNotFound is returned when the reference delta is not - // found. - ErrReferenceDeltaNotFound = errors.New("reference delta not found") - - // ErrNotSeekableSource is returned when the source for the parser is not - // seekable and a storage was not provided, so it can't be parsed. - ErrNotSeekableSource = errors.New("parser source is not seekable and storage was not provided") - - // ErrDeltaNotCached is returned when the delta could not be found in cache. - ErrDeltaNotCached = errors.New("delta could not be found in cache") -) - -// Observer interface is implemented by index encoders. -type Observer interface { - // OnHeader is called when a new packfile is opened. - OnHeader(count uint32) error - // OnInflatedObjectHeader is called for each object header read. - OnInflatedObjectHeader(t plumbing.ObjectType, objSize int64, pos int64) error - // OnInflatedObjectContent is called for each decoded object. - OnInflatedObjectContent(h plumbing.Hash, pos int64, crc uint32, content []byte) error - // OnFooter is called when decoding is done. - OnFooter(h plumbing.Hash) error -} - -// Parser decodes a packfile and calls any observer associated to it. Is used -// to generate indexes. -type Parser struct { - storage storer.EncodedObjectStorer - scanner *Scanner - count uint32 - oi []*objectInfo - oiByHash map[plumbing.Hash]*objectInfo - oiByOffset map[int64]*objectInfo - hashOffset map[plumbing.Hash]int64 - checksum plumbing.Hash - - cache *cache.BufferLRU - // delta content by offset, only used if source is not seekable - deltas map[int64][]byte - - ob []Observer -} - -// NewParser creates a new Parser. The Scanner source must be seekable. -// If it's not, NewParserWithStorage should be used instead. -func NewParser(scanner *Scanner, ob ...Observer) (*Parser, error) { - return NewParserWithStorage(scanner, nil, ob...) -} - -// NewParserWithStorage creates a new Parser. The scanner source must either -// be seekable or a storage must be provided. -func NewParserWithStorage( - scanner *Scanner, - storage storer.EncodedObjectStorer, - ob ...Observer, -) (*Parser, error) { - if !scanner.IsSeekable && storage == nil { - return nil, ErrNotSeekableSource - } - - var deltas map[int64][]byte - if !scanner.IsSeekable { - deltas = make(map[int64][]byte) - } - - return &Parser{ - storage: storage, - scanner: scanner, - ob: ob, - count: 0, - cache: cache.NewBufferLRUDefault(), - deltas: deltas, - }, nil -} - -func (p *Parser) forEachObserver(f func(o Observer) error) error { - for _, o := range p.ob { - if err := f(o); err != nil { - return err - } - } - return nil -} - -func (p *Parser) onHeader(count uint32) error { - return p.forEachObserver(func(o Observer) error { - return o.OnHeader(count) - }) -} - -func (p *Parser) onInflatedObjectHeader( - t plumbing.ObjectType, - objSize int64, - pos int64, -) error { - return p.forEachObserver(func(o Observer) error { - return o.OnInflatedObjectHeader(t, objSize, pos) - }) -} - -func (p *Parser) onInflatedObjectContent( - h plumbing.Hash, - pos int64, - crc uint32, - content []byte, -) error { - return p.forEachObserver(func(o Observer) error { - return o.OnInflatedObjectContent(h, pos, crc, content) - }) -} - -func (p *Parser) onFooter(h plumbing.Hash) error { - return p.forEachObserver(func(o Observer) error { - return o.OnFooter(h) - }) -} - -// Parse start decoding phase of the packfile. -func (p *Parser) Parse() (plumbing.Hash, error) { - if err := p.init(); err != nil { - return plumbing.ZeroHash, err - } - - if err := p.indexObjects(); err != nil { - return plumbing.ZeroHash, err - } - - var err error - p.checksum, err = p.scanner.Checksum() - if err != nil && err != io.EOF { - return plumbing.ZeroHash, err - } - - if err := p.resolveDeltas(); err != nil { - return plumbing.ZeroHash, err - } - - if err := p.onFooter(p.checksum); err != nil { - return plumbing.ZeroHash, err - } - - return p.checksum, nil -} - -func (p *Parser) init() error { - _, c, err := p.scanner.Header() - if err != nil { - return err - } - - if err := p.onHeader(c); err != nil { - return err - } - - p.count = c - p.oiByHash = make(map[plumbing.Hash]*objectInfo, p.count) - p.oiByOffset = make(map[int64]*objectInfo, p.count) - p.oi = make([]*objectInfo, p.count) - - return nil -} - -func (p *Parser) indexObjects() error { - buf := new(bytes.Buffer) - - for i := uint32(0); i < p.count; i++ { - buf.Reset() - - oh, err := p.scanner.NextObjectHeader() - if err != nil { - return err - } - - delta := false - var ota *objectInfo - switch t := oh.Type; t { - case plumbing.OFSDeltaObject: - delta = true - - parent, ok := p.oiByOffset[oh.OffsetReference] - if !ok { - return plumbing.ErrObjectNotFound - } - - ota = newDeltaObject(oh.Offset, oh.Length, t, parent) - parent.Children = append(parent.Children, ota) - case plumbing.REFDeltaObject: - delta = true - parent, ok := p.oiByHash[oh.Reference] - if !ok { - // can't find referenced object in this pack file - // this must be a "thin" pack. - parent = &objectInfo{ //Placeholder parent - SHA1: oh.Reference, - ExternalRef: true, // mark as an external reference that must be resolved - Type: plumbing.AnyObject, - DiskType: plumbing.AnyObject, - } - p.oiByHash[oh.Reference] = parent - } - ota = newDeltaObject(oh.Offset, oh.Length, t, parent) - parent.Children = append(parent.Children, ota) - - default: - ota = newBaseObject(oh.Offset, oh.Length, t) - } - - _, crc, err := p.scanner.NextObject(buf) - if err != nil { - return err - } - - ota.Crc32 = crc - ota.Length = oh.Length - - data := buf.Bytes() - if !delta { - sha1, err := getSHA1(ota.Type, data) - if err != nil { - return err - } - - ota.SHA1 = sha1 - p.oiByHash[ota.SHA1] = ota - } - - if p.storage != nil && !delta { - obj := new(plumbing.MemoryObject) - obj.SetSize(oh.Length) - obj.SetType(oh.Type) - if _, err := obj.Write(data); err != nil { - return err - } - - if _, err := p.storage.SetEncodedObject(obj); err != nil { - return err - } - } - - if delta && !p.scanner.IsSeekable { - p.deltas[oh.Offset] = make([]byte, len(data)) - copy(p.deltas[oh.Offset], data) - } - - p.oiByOffset[oh.Offset] = ota - p.oi[i] = ota - } - - return nil -} - -func (p *Parser) resolveDeltas() error { - for _, obj := range p.oi { - content, err := p.get(obj) - if err != nil { - return err - } - - if err := p.onInflatedObjectHeader(obj.Type, obj.Length, obj.Offset); err != nil { - return err - } - - if err := p.onInflatedObjectContent(obj.SHA1, obj.Offset, obj.Crc32, content); err != nil { - return err - } - - if !obj.IsDelta() && len(obj.Children) > 0 { - for _, child := range obj.Children { - if _, err := p.resolveObject(child, content); err != nil { - return err - } - } - - // Remove the delta from the cache. - if obj.DiskType.IsDelta() && !p.scanner.IsSeekable { - delete(p.deltas, obj.Offset) - } - } - } - - return nil -} - -func (p *Parser) get(o *objectInfo) (b []byte, err error) { - var ok bool - if !o.ExternalRef { // skip cache check for placeholder parents - b, ok = p.cache.Get(o.Offset) - } - - // If it's not on the cache and is not a delta we can try to find it in the - // storage, if there's one. External refs must enter here. - if !ok && p.storage != nil && !o.Type.IsDelta() { - e, err := p.storage.EncodedObject(plumbing.AnyObject, o.SHA1) - if err != nil { - return nil, err - } - o.Type = e.Type() - - r, err := e.Reader() - if err != nil { - return nil, err - } - - b = make([]byte, e.Size()) - if _, err = r.Read(b); err != nil { - return nil, err - } - } - - if b != nil { - return b, nil - } - - if o.ExternalRef { - // we were not able to resolve a ref in a thin pack - return nil, ErrReferenceDeltaNotFound - } - - var data []byte - if o.DiskType.IsDelta() { - base, err := p.get(o.Parent) - if err != nil { - return nil, err - } - - data, err = p.resolveObject(o, base) - if err != nil { - return nil, err - } - } else { - data, err = p.readData(o) - if err != nil { - return nil, err - } - } - - if len(o.Children) > 0 { - p.cache.Put(o.Offset, data) - } - - return data, nil -} - -func (p *Parser) resolveObject( - o *objectInfo, - base []byte, -) ([]byte, error) { - if !o.DiskType.IsDelta() { - return nil, nil - } - - data, err := p.readData(o) - if err != nil { - return nil, err - } - - data, err = applyPatchBase(o, data, base) - if err != nil { - return nil, err - } - - if p.storage != nil { - obj := new(plumbing.MemoryObject) - obj.SetSize(o.Size()) - obj.SetType(o.Type) - if _, err := obj.Write(data); err != nil { - return nil, err - } - - if _, err := p.storage.SetEncodedObject(obj); err != nil { - return nil, err - } - } - - return data, nil -} - -func (p *Parser) readData(o *objectInfo) ([]byte, error) { - if !p.scanner.IsSeekable && o.DiskType.IsDelta() { - data, ok := p.deltas[o.Offset] - if !ok { - return nil, ErrDeltaNotCached - } - - return data, nil - } - - if _, err := p.scanner.SeekObjectHeader(o.Offset); err != nil { - return nil, err - } - - buf := new(bytes.Buffer) - if _, _, err := p.scanner.NextObject(buf); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -func applyPatchBase(ota *objectInfo, data, base []byte) ([]byte, error) { - patched, err := PatchDelta(base, data) - if err != nil { - return nil, err - } - - if ota.SHA1 == plumbing.ZeroHash { - ota.Type = ota.Parent.Type - sha1, err := getSHA1(ota.Type, patched) - if err != nil { - return nil, err - } - - ota.SHA1 = sha1 - ota.Length = int64(len(patched)) - } - - return patched, nil -} - -func getSHA1(t plumbing.ObjectType, data []byte) (plumbing.Hash, error) { - hasher := plumbing.NewHasher(t, int64(len(data))) - if _, err := hasher.Write(data); err != nil { - return plumbing.ZeroHash, err - } - - return hasher.Sum(), nil -} - -type objectInfo struct { - Offset int64 - Length int64 - Type plumbing.ObjectType - DiskType plumbing.ObjectType - ExternalRef bool // indicates this is an external reference in a thin pack file - - Crc32 uint32 - - Parent *objectInfo - Children []*objectInfo - SHA1 plumbing.Hash -} - -func newBaseObject(offset, length int64, t plumbing.ObjectType) *objectInfo { - return newDeltaObject(offset, length, t, nil) -} - -func newDeltaObject( - offset, length int64, - t plumbing.ObjectType, - parent *objectInfo, -) *objectInfo { - obj := &objectInfo{ - Offset: offset, - Length: length, - Type: t, - DiskType: t, - Crc32: 0, - Parent: parent, - } - - return obj -} - -func (o *objectInfo) IsDelta() bool { - return o.Type.IsDelta() -} - -func (o *objectInfo) Size() int64 { - return o.Length -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/patch_delta.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/patch_delta.go deleted file mode 100644 index a972f1c4..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/patch_delta.go +++ /dev/null @@ -1,229 +0,0 @@ -package packfile - -import ( - "errors" - "io/ioutil" - - "gopkg.in/src-d/go-git.v4/plumbing" -) - -// See https://github.com/git/git/blob/49fa3dc76179e04b0833542fa52d0f287a4955ac/delta.h -// https://github.com/git/git/blob/c2c5f6b1e479f2c38e0e01345350620944e3527f/patch-delta.c, -// and https://github.com/tarruda/node-git-core/blob/master/src/js/delta.js -// for details about the delta format. - -const deltaSizeMin = 4 - -// ApplyDelta writes to target the result of applying the modification deltas in delta to base. -func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error { - r, err := base.Reader() - if err != nil { - return err - } - - w, err := target.Writer() - if err != nil { - return err - } - - src, err := ioutil.ReadAll(r) - if err != nil { - return err - } - - dst, err := PatchDelta(src, delta) - if err != nil { - return err - } - - target.SetSize(int64(len(dst))) - - _, err = w.Write(dst) - return err -} - -var ( - ErrInvalidDelta = errors.New("invalid delta") - ErrDeltaCmd = errors.New("wrong delta command") -) - -// PatchDelta returns the result of applying the modification deltas in delta to src. -// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command -// is not copy from source or copy from delta (ErrDeltaCmd). -func PatchDelta(src, delta []byte) ([]byte, error) { - if len(delta) < deltaSizeMin { - return nil, ErrInvalidDelta - } - - srcSz, delta := decodeLEB128(delta) - if srcSz != uint(len(src)) { - return nil, ErrInvalidDelta - } - - targetSz, delta := decodeLEB128(delta) - remainingTargetSz := targetSz - - var cmd byte - dest := make([]byte, 0, targetSz) - for { - if len(delta) == 0 { - return nil, ErrInvalidDelta - } - - cmd = delta[0] - delta = delta[1:] - if isCopyFromSrc(cmd) { - var offset, sz uint - var err error - offset, delta, err = decodeOffset(cmd, delta) - if err != nil { - return nil, err - } - - sz, delta, err = decodeSize(cmd, delta) - if err != nil { - return nil, err - } - - if invalidSize(sz, targetSz) || - invalidOffsetSize(offset, sz, srcSz) { - break - } - dest = append(dest, src[offset:offset+sz]...) - remainingTargetSz -= sz - } else if isCopyFromDelta(cmd) { - sz := uint(cmd) // cmd is the size itself - if invalidSize(sz, targetSz) { - return nil, ErrInvalidDelta - } - - if uint(len(delta)) < sz { - return nil, ErrInvalidDelta - } - - dest = append(dest, delta[0:sz]...) - remainingTargetSz -= sz - delta = delta[sz:] - } else { - return nil, ErrDeltaCmd - } - - if remainingTargetSz <= 0 { - break - } - } - - return dest, nil -} - -// Decodes a number encoded as an unsigned LEB128 at the start of some -// binary data and returns the decoded number and the rest of the -// stream. -// -// This must be called twice on the delta data buffer, first to get the -// expected source buffer size, and again to get the target buffer size. -func decodeLEB128(input []byte) (uint, []byte) { - var num, sz uint - var b byte - for { - b = input[sz] - num |= (uint(b) & payload) << (sz * 7) // concats 7 bits chunks - sz++ - - if uint(b)&continuation == 0 || sz == uint(len(input)) { - break - } - } - - return num, input[sz:] -} - -const ( - payload = 0x7f // 0111 1111 - continuation = 0x80 // 1000 0000 -) - -func isCopyFromSrc(cmd byte) bool { - return (cmd & 0x80) != 0 -} - -func isCopyFromDelta(cmd byte) bool { - return (cmd&0x80) == 0 && cmd != 0 -} - -func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) { - var offset uint - if (cmd & 0x01) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - offset = uint(delta[0]) - delta = delta[1:] - } - if (cmd & 0x02) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - offset |= uint(delta[0]) << 8 - delta = delta[1:] - } - if (cmd & 0x04) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - offset |= uint(delta[0]) << 16 - delta = delta[1:] - } - if (cmd & 0x08) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - offset |= uint(delta[0]) << 24 - delta = delta[1:] - } - - return offset, delta, nil -} - -func decodeSize(cmd byte, delta []byte) (uint, []byte, error) { - var sz uint - if (cmd & 0x10) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - sz = uint(delta[0]) - delta = delta[1:] - } - if (cmd & 0x20) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - sz |= uint(delta[0]) << 8 - delta = delta[1:] - } - if (cmd & 0x40) != 0 { - if len(delta) == 0 { - return 0, nil, ErrInvalidDelta - } - sz |= uint(delta[0]) << 16 - delta = delta[1:] - } - if sz == 0 { - sz = 0x10000 - } - - return sz, delta, nil -} - -func invalidSize(sz, targetSz uint) bool { - return sz > targetSz -} - -func invalidOffsetSize(offset, sz, srcSz uint) bool { - return sumOverflows(offset, sz) || - offset+sz > srcSz -} - -func sumOverflows(a, b uint) bool { - return a+b < a -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go deleted file mode 100644 index 7b44192a..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go +++ /dev/null @@ -1,466 +0,0 @@ -package packfile - -import ( - "bufio" - "bytes" - "compress/zlib" - "fmt" - "hash" - "hash/crc32" - "io" - stdioutil "io/ioutil" - "sync" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/utils/binary" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -var ( - // ErrEmptyPackfile is returned by ReadHeader when no data is found in the packfile - ErrEmptyPackfile = NewError("empty packfile") - // ErrBadSignature is returned by ReadHeader when the signature in the packfile is incorrect. - ErrBadSignature = NewError("malformed pack file signature") - // ErrUnsupportedVersion is returned by ReadHeader when the packfile version is - // different than VersionSupported. - ErrUnsupportedVersion = NewError("unsupported packfile version") - // ErrSeekNotSupported returned if seek is not support - ErrSeekNotSupported = NewError("not seek support") -) - -// ObjectHeader contains the information related to the object, this information -// is collected from the previous bytes to the content of the object. -type ObjectHeader struct { - Type plumbing.ObjectType - Offset int64 - Length int64 - Reference plumbing.Hash - OffsetReference int64 -} - -type Scanner struct { - r *scannerReader - crc hash.Hash32 - - // pendingObject is used to detect if an object has been read, or still - // is waiting to be read - pendingObject *ObjectHeader - version, objects uint32 - - // lsSeekable says if this scanner can do Seek or not, to have a Scanner - // seekable a r implementing io.Seeker is required - IsSeekable bool -} - -// NewScanner returns a new Scanner based on a reader, if the given reader -// implements io.ReadSeeker the Scanner will be also Seekable -func NewScanner(r io.Reader) *Scanner { - _, ok := r.(io.ReadSeeker) - - crc := crc32.NewIEEE() - return &Scanner{ - r: newScannerReader(r, crc), - crc: crc, - IsSeekable: ok, - } -} - -func (s *Scanner) Reset(r io.Reader) { - _, ok := r.(io.ReadSeeker) - - s.r.Reset(r) - s.crc.Reset() - s.IsSeekable = ok - s.pendingObject = nil - s.version = 0 - s.objects = 0 -} - -// Header reads the whole packfile header (signature, version and object count). -// It returns the version and the object count and performs checks on the -// validity of the signature and the version fields. -func (s *Scanner) Header() (version, objects uint32, err error) { - if s.version != 0 { - return s.version, s.objects, nil - } - - sig, err := s.readSignature() - if err != nil { - if err == io.EOF { - err = ErrEmptyPackfile - } - - return - } - - if !s.isValidSignature(sig) { - err = ErrBadSignature - return - } - - version, err = s.readVersion() - s.version = version - if err != nil { - return - } - - if !s.isSupportedVersion(version) { - err = ErrUnsupportedVersion.AddDetails("%d", version) - return - } - - objects, err = s.readCount() - s.objects = objects - return -} - -// readSignature reads an returns the signature field in the packfile. -func (s *Scanner) readSignature() ([]byte, error) { - var sig = make([]byte, 4) - if _, err := io.ReadFull(s.r, sig); err != nil { - return []byte{}, err - } - - return sig, nil -} - -// isValidSignature returns if sig is a valid packfile signature. -func (s *Scanner) isValidSignature(sig []byte) bool { - return bytes.Equal(sig, signature) -} - -// readVersion reads and returns the version field of a packfile. -func (s *Scanner) readVersion() (uint32, error) { - return binary.ReadUint32(s.r) -} - -// isSupportedVersion returns whether version v is supported by the parser. -// The current supported version is VersionSupported, defined above. -func (s *Scanner) isSupportedVersion(v uint32) bool { - return v == VersionSupported -} - -// readCount reads and returns the count of objects field of a packfile. -func (s *Scanner) readCount() (uint32, error) { - return binary.ReadUint32(s.r) -} - -// SeekObjectHeader seeks to specified offset and returns the ObjectHeader -// for the next object in the reader -func (s *Scanner) SeekObjectHeader(offset int64) (*ObjectHeader, error) { - // if seeking we assume that you are not interested in the header - if s.version == 0 { - s.version = VersionSupported - } - - if _, err := s.r.Seek(offset, io.SeekStart); err != nil { - return nil, err - } - - h, err := s.nextObjectHeader() - if err != nil { - return nil, err - } - - h.Offset = offset - return h, nil -} - -// NextObjectHeader returns the ObjectHeader for the next object in the reader -func (s *Scanner) NextObjectHeader() (*ObjectHeader, error) { - if err := s.doPending(); err != nil { - return nil, err - } - - offset, err := s.r.Seek(0, io.SeekCurrent) - if err != nil { - return nil, err - } - - h, err := s.nextObjectHeader() - if err != nil { - return nil, err - } - - h.Offset = offset - return h, nil -} - -// nextObjectHeader returns the ObjectHeader for the next object in the reader -// without the Offset field -func (s *Scanner) nextObjectHeader() (*ObjectHeader, error) { - s.r.Flush() - s.crc.Reset() - - h := &ObjectHeader{} - s.pendingObject = h - - var err error - h.Offset, err = s.r.Seek(0, io.SeekCurrent) - if err != nil { - return nil, err - } - - h.Type, h.Length, err = s.readObjectTypeAndLength() - if err != nil { - return nil, err - } - - switch h.Type { - case plumbing.OFSDeltaObject: - no, err := binary.ReadVariableWidthInt(s.r) - if err != nil { - return nil, err - } - - h.OffsetReference = h.Offset - no - case plumbing.REFDeltaObject: - var err error - h.Reference, err = binary.ReadHash(s.r) - if err != nil { - return nil, err - } - } - - return h, nil -} - -func (s *Scanner) doPending() error { - if s.version == 0 { - var err error - s.version, s.objects, err = s.Header() - if err != nil { - return err - } - } - - return s.discardObjectIfNeeded() -} - -func (s *Scanner) discardObjectIfNeeded() error { - if s.pendingObject == nil { - return nil - } - - h := s.pendingObject - n, _, err := s.NextObject(stdioutil.Discard) - if err != nil { - return err - } - - if n != h.Length { - return fmt.Errorf( - "error discarding object, discarded %d, expected %d", - n, h.Length, - ) - } - - return nil -} - -// ReadObjectTypeAndLength reads and returns the object type and the -// length field from an object entry in a packfile. -func (s *Scanner) readObjectTypeAndLength() (plumbing.ObjectType, int64, error) { - t, c, err := s.readType() - if err != nil { - return t, 0, err - } - - l, err := s.readLength(c) - - return t, l, err -} - -func (s *Scanner) readType() (plumbing.ObjectType, byte, error) { - var c byte - var err error - if c, err = s.r.ReadByte(); err != nil { - return plumbing.ObjectType(0), 0, err - } - - typ := parseType(c) - - return typ, c, nil -} - -func parseType(b byte) plumbing.ObjectType { - return plumbing.ObjectType((b & maskType) >> firstLengthBits) -} - -// the length is codified in the last 4 bits of the first byte and in -// the last 7 bits of subsequent bytes. Last byte has a 0 MSB. -func (s *Scanner) readLength(first byte) (int64, error) { - length := int64(first & maskFirstLength) - - c := first - shift := firstLengthBits - var err error - for c&maskContinue > 0 { - if c, err = s.r.ReadByte(); err != nil { - return 0, err - } - - length += int64(c&maskLength) << shift - shift += lengthBits - } - - return length, nil -} - -// NextObject writes the content of the next object into the reader, returns -// the number of bytes written, the CRC32 of the content and an error, if any -func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err error) { - s.pendingObject = nil - written, err = s.copyObject(w) - - s.r.Flush() - crc32 = s.crc.Sum32() - s.crc.Reset() - - return -} - -// ReadRegularObject reads and write a non-deltified object -// from it zlib stream in an object entry in the packfile. -func (s *Scanner) copyObject(w io.Writer) (n int64, err error) { - zr := zlibReaderPool.Get().(io.ReadCloser) - defer zlibReaderPool.Put(zr) - - if err = zr.(zlib.Resetter).Reset(s.r, nil); err != nil { - return 0, fmt.Errorf("zlib reset error: %s", err) - } - - defer ioutil.CheckClose(zr, &err) - buf := byteSlicePool.Get().([]byte) - n, err = io.CopyBuffer(w, zr, buf) - byteSlicePool.Put(buf) - return -} - -var byteSlicePool = sync.Pool{ - New: func() interface{} { - return make([]byte, 32*1024) - }, -} - -// SeekFromStart sets a new offset from start, returns the old position before -// the change. -func (s *Scanner) SeekFromStart(offset int64) (previous int64, err error) { - // if seeking we assume that you are not interested in the header - if s.version == 0 { - s.version = VersionSupported - } - - previous, err = s.r.Seek(0, io.SeekCurrent) - if err != nil { - return -1, err - } - - _, err = s.r.Seek(offset, io.SeekStart) - return previous, err -} - -// Checksum returns the checksum of the packfile -func (s *Scanner) Checksum() (plumbing.Hash, error) { - err := s.discardObjectIfNeeded() - if err != nil { - return plumbing.ZeroHash, err - } - - return binary.ReadHash(s.r) -} - -// Close reads the reader until io.EOF -func (s *Scanner) Close() error { - buf := byteSlicePool.Get().([]byte) - _, err := io.CopyBuffer(stdioutil.Discard, s.r, buf) - byteSlicePool.Put(buf) - return err -} - -// Flush is a no-op (deprecated) -func (s *Scanner) Flush() error { - return nil -} - -// scannerReader has the following characteristics: -// - Provides an io.SeekReader impl for bufio.Reader, when the underlying -// reader supports it. -// - Keeps track of the current read position, for when the underlying reader -// isn't an io.SeekReader, but we still want to know the current offset. -// - Writes to the hash writer what it reads, with the aid of a smaller buffer. -// The buffer helps avoid a performance penality for performing small writes -// to the crc32 hash writer. -type scannerReader struct { - reader io.Reader - crc io.Writer - rbuf *bufio.Reader - wbuf *bufio.Writer - offset int64 -} - -func newScannerReader(r io.Reader, h io.Writer) *scannerReader { - sr := &scannerReader{ - rbuf: bufio.NewReader(nil), - wbuf: bufio.NewWriterSize(nil, 64), - crc: h, - } - sr.Reset(r) - - return sr -} - -func (r *scannerReader) Reset(reader io.Reader) { - r.reader = reader - r.rbuf.Reset(r.reader) - r.wbuf.Reset(r.crc) - - r.offset = 0 - if seeker, ok := r.reader.(io.ReadSeeker); ok { - r.offset, _ = seeker.Seek(0, io.SeekCurrent) - } -} - -func (r *scannerReader) Read(p []byte) (n int, err error) { - n, err = r.rbuf.Read(p) - - r.offset += int64(n) - if _, err := r.wbuf.Write(p[:n]); err != nil { - return n, err - } - return -} - -func (r *scannerReader) ReadByte() (b byte, err error) { - b, err = r.rbuf.ReadByte() - if err == nil { - r.offset++ - return b, r.wbuf.WriteByte(b) - } - return -} - -func (r *scannerReader) Flush() error { - return r.wbuf.Flush() -} - -// Seek seeks to a location. If the underlying reader is not an io.ReadSeeker, -// then only whence=io.SeekCurrent is supported, any other operation fails. -func (r *scannerReader) Seek(offset int64, whence int) (int64, error) { - var err error - - if seeker, ok := r.reader.(io.ReadSeeker); !ok { - if whence != io.SeekCurrent || offset != 0 { - return -1, ErrSeekNotSupported - } - } else { - if whence == io.SeekCurrent && offset == 0 { - return r.offset, nil - } - - r.offset, err = seeker.Seek(offset, whence) - r.rbuf.Reset(r.reader) - } - - return r.offset, err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/revlist/revlist.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/revlist/revlist.go deleted file mode 100644 index 7ad71ac0..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/revlist/revlist.go +++ /dev/null @@ -1,230 +0,0 @@ -// Package revlist provides support to access the ancestors of commits, in a -// similar way as the git-rev-list command. -package revlist - -import ( - "fmt" - "io" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/plumbing/object" - "gopkg.in/src-d/go-git.v4/plumbing/storer" -) - -// Objects applies a complementary set. It gets all the hashes from all -// the reachable objects from the given objects. Ignore param are object hashes -// that we want to ignore on the result. All that objects must be accessible -// from the object storer. -func Objects( - s storer.EncodedObjectStorer, - objs, - ignore []plumbing.Hash, -) ([]plumbing.Hash, error) { - return ObjectsWithStorageForIgnores(s, s, objs, ignore) -} - -// ObjectsWithStorageForIgnores is the same as Objects, but a -// secondary storage layer can be provided, to be used to finding the -// full set of objects to be ignored while finding the reachable -// objects. This is useful when the main `s` storage layer is slow -// and/or remote, while the ignore list is available somewhere local. -func ObjectsWithStorageForIgnores( - s, ignoreStore storer.EncodedObjectStorer, - objs, - ignore []plumbing.Hash, -) ([]plumbing.Hash, error) { - ignore, err := objects(ignoreStore, ignore, nil, true) - if err != nil { - return nil, err - } - - return objects(s, objs, ignore, false) -} - -func objects( - s storer.EncodedObjectStorer, - objects, - ignore []plumbing.Hash, - allowMissingObjects bool, -) ([]plumbing.Hash, error) { - seen := hashListToSet(ignore) - result := make(map[plumbing.Hash]bool) - visited := make(map[plumbing.Hash]bool) - - walkerFunc := func(h plumbing.Hash) { - if !seen[h] { - result[h] = true - seen[h] = true - } - } - - for _, h := range objects { - if err := processObject(s, h, seen, visited, ignore, walkerFunc); err != nil { - if allowMissingObjects && err == plumbing.ErrObjectNotFound { - continue - } - - return nil, err - } - } - - return hashSetToList(result), nil -} - -// processObject obtains the object using the hash an process it depending of its type -func processObject( - s storer.EncodedObjectStorer, - h plumbing.Hash, - seen map[plumbing.Hash]bool, - visited map[plumbing.Hash]bool, - ignore []plumbing.Hash, - walkerFunc func(h plumbing.Hash), -) error { - if seen[h] { - return nil - } - - o, err := s.EncodedObject(plumbing.AnyObject, h) - if err != nil { - return err - } - - do, err := object.DecodeObject(s, o) - if err != nil { - return err - } - - switch do := do.(type) { - case *object.Commit: - return reachableObjects(do, seen, visited, ignore, walkerFunc) - case *object.Tree: - return iterateCommitTrees(seen, do, walkerFunc) - case *object.Tag: - walkerFunc(do.Hash) - return processObject(s, do.Target, seen, visited, ignore, walkerFunc) - case *object.Blob: - walkerFunc(do.Hash) - default: - return fmt.Errorf("object type not valid: %s. "+ - "Object reference: %s", o.Type(), o.Hash()) - } - - return nil -} - -// reachableObjects returns, using the callback function, all the reachable -// objects from the specified commit. To avoid to iterate over seen commits, -// if a commit hash is into the 'seen' set, we will not iterate all his trees -// and blobs objects. -func reachableObjects( - commit *object.Commit, - seen map[plumbing.Hash]bool, - visited map[plumbing.Hash]bool, - ignore []plumbing.Hash, - cb func(h plumbing.Hash), -) error { - i := object.NewCommitPreorderIter(commit, seen, ignore) - pending := make(map[plumbing.Hash]bool) - addPendingParents(pending, visited, commit) - for { - commit, err := i.Next() - if err == io.EOF { - break - } - - if err != nil { - return err - } - - if pending[commit.Hash] { - delete(pending, commit.Hash) - } - - addPendingParents(pending, visited, commit) - - if visited[commit.Hash] && len(pending) == 0 { - break - } - - if seen[commit.Hash] { - continue - } - - cb(commit.Hash) - - tree, err := commit.Tree() - if err != nil { - return err - } - - if err := iterateCommitTrees(seen, tree, cb); err != nil { - return err - } - } - - return nil -} - -func addPendingParents(pending, visited map[plumbing.Hash]bool, commit *object.Commit) { - for _, p := range commit.ParentHashes { - if !visited[p] { - pending[p] = true - } - } -} - -// iterateCommitTrees iterate all reachable trees from the given commit -func iterateCommitTrees( - seen map[plumbing.Hash]bool, - tree *object.Tree, - cb func(h plumbing.Hash), -) error { - if seen[tree.Hash] { - return nil - } - - cb(tree.Hash) - - treeWalker := object.NewTreeWalker(tree, true, seen) - - for { - _, e, err := treeWalker.Next() - if err == io.EOF { - break - } - if err != nil { - return err - } - - if e.Mode == filemode.Submodule { - continue - } - - if seen[e.Hash] { - continue - } - - cb(e.Hash) - } - - return nil -} - -func hashSetToList(hashes map[plumbing.Hash]bool) []plumbing.Hash { - var result []plumbing.Hash - for key := range hashes { - result = append(result, key) - } - - return result -} - -func hashListToSet(hashes []plumbing.Hash) map[plumbing.Hash]bool { - result := make(map[plumbing.Hash]bool) - for _, h := range hashes { - result[h] = true - } - - return result -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/client/client.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/client/client.go deleted file mode 100644 index 90635a5a..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/client/client.go +++ /dev/null @@ -1,48 +0,0 @@ -// Package client contains helper function to deal with the different client -// protocols. -package client - -import ( - "fmt" - - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/file" - "gopkg.in/src-d/go-git.v4/plumbing/transport/git" - "gopkg.in/src-d/go-git.v4/plumbing/transport/http" - "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" -) - -// Protocols are the protocols supported by default. -var Protocols = map[string]transport.Transport{ - "http": http.DefaultClient, - "https": http.DefaultClient, - "ssh": ssh.DefaultClient, - "git": git.DefaultClient, - "file": file.DefaultClient, -} - -// InstallProtocol adds or modifies an existing protocol. -func InstallProtocol(scheme string, c transport.Transport) { - if c == nil { - delete(Protocols, scheme) - return - } - - Protocols[scheme] = c -} - -// NewClient returns the appropriate client among of the set of known protocols: -// http://, https://, ssh:// and file://. -// See `InstallProtocol` to add or modify protocols. -func NewClient(endpoint *transport.Endpoint) (transport.Transport, error) { - f, ok := Protocols[endpoint.Protocol] - if !ok { - return nil, fmt.Errorf("unsupported scheme %q", endpoint.Protocol) - } - - if f == nil { - return nil, fmt.Errorf("malformed client for scheme %q, client is defined as nil", endpoint.Protocol) - } - - return f, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/client.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/client.go deleted file mode 100644 index e799ee13..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/client.go +++ /dev/null @@ -1,156 +0,0 @@ -// Package file implements the file transport protocol. -package file - -import ( - "bufio" - "errors" - "io" - "os" - "os/exec" - "path/filepath" - "strings" - - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common" -) - -// DefaultClient is the default local client. -var DefaultClient = NewClient( - transport.UploadPackServiceName, - transport.ReceivePackServiceName, -) - -type runner struct { - UploadPackBin string - ReceivePackBin string -} - -// NewClient returns a new local client using the given git-upload-pack and -// git-receive-pack binaries. -func NewClient(uploadPackBin, receivePackBin string) transport.Transport { - return common.NewClient(&runner{ - UploadPackBin: uploadPackBin, - ReceivePackBin: receivePackBin, - }) -} - -func prefixExecPath(cmd string) (string, error) { - // Use `git --exec-path` to find the exec path. - execCmd := exec.Command("git", "--exec-path") - - stdout, err := execCmd.StdoutPipe() - if err != nil { - return "", err - } - stdoutBuf := bufio.NewReader(stdout) - - err = execCmd.Start() - if err != nil { - return "", err - } - - execPathBytes, isPrefix, err := stdoutBuf.ReadLine() - if err != nil { - return "", err - } - if isPrefix { - return "", errors.New("Couldn't read exec-path line all at once") - } - - err = execCmd.Wait() - if err != nil { - return "", err - } - execPath := string(execPathBytes) - execPath = strings.TrimSpace(execPath) - cmd = filepath.Join(execPath, cmd) - - // Make sure it actually exists. - _, err = exec.LookPath(cmd) - if err != nil { - return "", err - } - return cmd, nil -} - -func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod, -) (common.Command, error) { - - switch cmd { - case transport.UploadPackServiceName: - cmd = r.UploadPackBin - case transport.ReceivePackServiceName: - cmd = r.ReceivePackBin - } - - _, err := exec.LookPath(cmd) - if err != nil { - if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { - cmd, err = prefixExecPath(cmd) - if err != nil { - return nil, err - } - } else { - return nil, err - } - } - - return &command{cmd: exec.Command(cmd, ep.Path)}, nil -} - -type command struct { - cmd *exec.Cmd - stderrCloser io.Closer - closed bool -} - -func (c *command) Start() error { - return c.cmd.Start() -} - -func (c *command) StderrPipe() (io.Reader, error) { - // Pipe returned by Command.StderrPipe has a race with Read + Command.Wait. - // We use an io.Pipe and close it after the command finishes. - r, w := io.Pipe() - c.cmd.Stderr = w - c.stderrCloser = r - return r, nil -} - -func (c *command) StdinPipe() (io.WriteCloser, error) { - return c.cmd.StdinPipe() -} - -func (c *command) StdoutPipe() (io.Reader, error) { - return c.cmd.StdoutPipe() -} - -func (c *command) Kill() error { - c.cmd.Process.Kill() - return c.Close() -} - -// Close waits for the command to exit. -func (c *command) Close() error { - if c.closed { - return nil - } - - defer func() { - c.closed = true - _ = c.stderrCloser.Close() - - }() - - err := c.cmd.Wait() - if _, ok := err.(*os.PathError); ok { - return nil - } - - // When a repository does not exist, the command exits with code 128. - if _, ok := err.(*exec.ExitError); ok { - return nil - } - - return err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/server.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/server.go deleted file mode 100644 index 61dd42d0..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/file/server.go +++ /dev/null @@ -1,53 +0,0 @@ -package file - -import ( - "fmt" - "os" - - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common" - "gopkg.in/src-d/go-git.v4/plumbing/transport/server" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -// ServeUploadPack serves a git-upload-pack request using standard output, input -// and error. This is meant to be used when implementing a git-upload-pack -// command. -func ServeUploadPack(path string) error { - ep, err := transport.NewEndpoint(path) - if err != nil { - return err - } - - // TODO: define and implement a server-side AuthMethod - s, err := server.DefaultServer.NewUploadPackSession(ep, nil) - if err != nil { - return fmt.Errorf("error creating session: %s", err) - } - - return common.ServeUploadPack(srvCmd, s) -} - -// ServeReceivePack serves a git-receive-pack request using standard output, -// input and error. This is meant to be used when implementing a -// git-receive-pack command. -func ServeReceivePack(path string) error { - ep, err := transport.NewEndpoint(path) - if err != nil { - return err - } - - // TODO: define and implement a server-side AuthMethod - s, err := server.DefaultServer.NewReceivePackSession(ep, nil) - if err != nil { - return fmt.Errorf("error creating session: %s", err) - } - - return common.ServeReceivePack(srvCmd, s) -} - -var srvCmd = common.ServerCommand{ - Stdin: os.Stdin, - Stdout: ioutil.WriteNopCloser(os.Stdout), - Stderr: os.Stderr, -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/git/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/git/common.go deleted file mode 100644 index 78aaa3b0..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/git/common.go +++ /dev/null @@ -1,109 +0,0 @@ -// Package git implements the git transport protocol. -package git - -import ( - "fmt" - "io" - "net" - - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -// DefaultClient is the default git client. -var DefaultClient = common.NewClient(&runner{}) - -const DefaultPort = 9418 - -type runner struct{} - -// Command returns a new Command for the given cmd in the given Endpoint -func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (common.Command, error) { - // auth not allowed since git protocol doesn't support authentication - if auth != nil { - return nil, transport.ErrInvalidAuthMethod - } - c := &command{command: cmd, endpoint: ep} - if err := c.connect(); err != nil { - return nil, err - } - return c, nil -} - -type command struct { - conn net.Conn - connected bool - command string - endpoint *transport.Endpoint -} - -// Start executes the command sending the required message to the TCP connection -func (c *command) Start() error { - cmd := endpointToCommand(c.command, c.endpoint) - - e := pktline.NewEncoder(c.conn) - return e.Encode([]byte(cmd)) -} - -func (c *command) connect() error { - if c.connected { - return transport.ErrAlreadyConnected - } - - var err error - c.conn, err = net.Dial("tcp", c.getHostWithPort()) - if err != nil { - return err - } - - c.connected = true - return nil -} - -func (c *command) getHostWithPort() string { - host := c.endpoint.Host - port := c.endpoint.Port - if port <= 0 { - port = DefaultPort - } - - return fmt.Sprintf("%s:%d", host, port) -} - -// StderrPipe git protocol doesn't have any dedicated error channel -func (c *command) StderrPipe() (io.Reader, error) { - return nil, nil -} - -// StdinPipe return the underlying connection as WriteCloser, wrapped to prevent -// call to the Close function from the connection, a command execution in git -// protocol can't be closed or killed -func (c *command) StdinPipe() (io.WriteCloser, error) { - return ioutil.WriteNopCloser(c.conn), nil -} - -// StdoutPipe return the underlying connection as Reader -func (c *command) StdoutPipe() (io.Reader, error) { - return c.conn, nil -} - -func endpointToCommand(cmd string, ep *transport.Endpoint) string { - host := ep.Host - if ep.Port != DefaultPort { - host = fmt.Sprintf("%s:%d", ep.Host, ep.Port) - } - - return fmt.Sprintf("%s %s%chost=%s%c", cmd, ep.Path, 0, host, 0) -} - -// Close closes the TCP connection and connection. -func (c *command) Close() error { - if !c.connected { - return nil - } - - c.connected = false - return c.conn.Close() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/common.go deleted file mode 100644 index 38e903d4..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/common.go +++ /dev/null @@ -1,281 +0,0 @@ -// Package http implements the HTTP transport protocol. -package http - -import ( - "bytes" - "fmt" - "net" - "net/http" - "strconv" - "strings" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -// it requires a bytes.Buffer, because we need to know the length -func applyHeadersToRequest(req *http.Request, content *bytes.Buffer, host string, requestType string) { - req.Header.Add("User-Agent", "git/1.0") - req.Header.Add("Host", host) // host:port - - if content == nil { - req.Header.Add("Accept", "*/*") - return - } - - req.Header.Add("Accept", fmt.Sprintf("application/x-%s-result", requestType)) - req.Header.Add("Content-Type", fmt.Sprintf("application/x-%s-request", requestType)) - req.Header.Add("Content-Length", strconv.Itoa(content.Len())) -} - -const infoRefsPath = "/info/refs" - -func advertisedReferences(s *session, serviceName string) (ref *packp.AdvRefs, err error) { - url := fmt.Sprintf( - "%s%s?service=%s", - s.endpoint.String(), infoRefsPath, serviceName, - ) - - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - return nil, err - } - - s.ApplyAuthToRequest(req) - applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName) - res, err := s.client.Do(req) - if err != nil { - return nil, err - } - - s.ModifyEndpointIfRedirect(res) - defer ioutil.CheckClose(res.Body, &err) - - if err = NewErr(res); err != nil { - return nil, err - } - - ar := packp.NewAdvRefs() - if err = ar.Decode(res.Body); err != nil { - if err == packp.ErrEmptyAdvRefs { - err = transport.ErrEmptyRemoteRepository - } - - return nil, err - } - - transport.FilterUnsupportedCapabilities(ar.Capabilities) - s.advRefs = ar - - return ar, nil -} - -type client struct { - c *http.Client -} - -// DefaultClient is the default HTTP client, which uses `http.DefaultClient`. -var DefaultClient = NewClient(nil) - -// NewClient creates a new client with a custom net/http client. -// See `InstallProtocol` to install and override default http client. -// Unless a properly initialized client is given, it will fall back into -// `http.DefaultClient`. -// -// Note that for HTTP client cannot distinguist between private repositories and -// unexistent repositories on GitHub. So it returns `ErrAuthorizationRequired` -// for both. -func NewClient(c *http.Client) transport.Transport { - if c == nil { - return &client{http.DefaultClient} - } - - return &client{ - c: c, - } -} - -func (c *client) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( - transport.UploadPackSession, error) { - - return newUploadPackSession(c.c, ep, auth) -} - -func (c *client) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( - transport.ReceivePackSession, error) { - - return newReceivePackSession(c.c, ep, auth) -} - -type session struct { - auth AuthMethod - client *http.Client - endpoint *transport.Endpoint - advRefs *packp.AdvRefs -} - -func newSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (*session, error) { - s := &session{ - auth: basicAuthFromEndpoint(ep), - client: c, - endpoint: ep, - } - if auth != nil { - a, ok := auth.(AuthMethod) - if !ok { - return nil, transport.ErrInvalidAuthMethod - } - - s.auth = a - } - - return s, nil -} - -func (s *session) ApplyAuthToRequest(req *http.Request) { - if s.auth == nil { - return - } - - s.auth.SetAuth(req) -} - -func (s *session) ModifyEndpointIfRedirect(res *http.Response) { - if res.Request == nil { - return - } - - r := res.Request - if !strings.HasSuffix(r.URL.Path, infoRefsPath) { - return - } - - h, p, err := net.SplitHostPort(r.URL.Host) - if err != nil { - h = r.URL.Host - } - if p != "" { - port, err := strconv.Atoi(p) - if err == nil { - s.endpoint.Port = port - } - } - s.endpoint.Host = h - - s.endpoint.Protocol = r.URL.Scheme - s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)] -} - -func (*session) Close() error { - return nil -} - -// AuthMethod is concrete implementation of common.AuthMethod for HTTP services -type AuthMethod interface { - transport.AuthMethod - SetAuth(r *http.Request) -} - -func basicAuthFromEndpoint(ep *transport.Endpoint) *BasicAuth { - u := ep.User - if u == "" { - return nil - } - - return &BasicAuth{u, ep.Password} -} - -// BasicAuth represent a HTTP basic auth -type BasicAuth struct { - Username, Password string -} - -func (a *BasicAuth) SetAuth(r *http.Request) { - if a == nil { - return - } - - r.SetBasicAuth(a.Username, a.Password) -} - -// Name is name of the auth -func (a *BasicAuth) Name() string { - return "http-basic-auth" -} - -func (a *BasicAuth) String() string { - masked := "*******" - if a.Password == "" { - masked = "" - } - - return fmt.Sprintf("%s - %s:%s", a.Name(), a.Username, masked) -} - -// TokenAuth implements an http.AuthMethod that can be used with http transport -// to authenticate with HTTP token authentication (also known as bearer -// authentication). -// -// IMPORTANT: If you are looking to use OAuth tokens with popular servers (e.g. -// GitHub, Bitbucket, GitLab) you should use BasicAuth instead. These servers -// use basic HTTP authentication, with the OAuth token as user or password. -// Check the documentation of your git server for details. -type TokenAuth struct { - Token string -} - -func (a *TokenAuth) SetAuth(r *http.Request) { - if a == nil { - return - } - r.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Token)) -} - -// Name is name of the auth -func (a *TokenAuth) Name() string { - return "http-token-auth" -} - -func (a *TokenAuth) String() string { - masked := "*******" - if a.Token == "" { - masked = "" - } - return fmt.Sprintf("%s - %s", a.Name(), masked) -} - -// Err is a dedicated error to return errors based on status code -type Err struct { - Response *http.Response -} - -// NewErr returns a new Err based on a http response -func NewErr(r *http.Response) error { - if r.StatusCode >= http.StatusOK && r.StatusCode < http.StatusMultipleChoices { - return nil - } - - switch r.StatusCode { - case http.StatusUnauthorized: - return transport.ErrAuthenticationRequired - case http.StatusForbidden: - return transport.ErrAuthorizationFailed - case http.StatusNotFound: - return transport.ErrRepositoryNotFound - } - - return plumbing.NewUnexpectedError(&Err{r}) -} - -// StatusCode returns the status code of the response -func (e *Err) StatusCode() int { - return e.Response.StatusCode -} - -func (e *Err) Error() string { - return fmt.Sprintf("unexpected requesting %q status code: %d", - e.Response.Request.URL, e.Response.StatusCode, - ) -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/receive_pack.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/receive_pack.go deleted file mode 100644 index 72ba0ec5..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/receive_pack.go +++ /dev/null @@ -1,106 +0,0 @@ -package http - -import ( - "bytes" - "context" - "fmt" - "io" - "net/http" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -type rpSession struct { - *session -} - -func newReceivePackSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) { - s, err := newSession(c, ep, auth) - return &rpSession{s}, err -} - -func (s *rpSession) AdvertisedReferences() (*packp.AdvRefs, error) { - return advertisedReferences(s.session, transport.ReceivePackServiceName) -} - -func (s *rpSession) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateRequest) ( - *packp.ReportStatus, error) { - url := fmt.Sprintf( - "%s/%s", - s.endpoint.String(), transport.ReceivePackServiceName, - ) - - buf := bytes.NewBuffer(nil) - if err := req.Encode(buf); err != nil { - return nil, err - } - - res, err := s.doRequest(ctx, http.MethodPost, url, buf) - if err != nil { - return nil, err - } - - r, err := ioutil.NonEmptyReader(res.Body) - if err == ioutil.ErrEmptyReader { - return nil, nil - } - - if err != nil { - return nil, err - } - - var d *sideband.Demuxer - if req.Capabilities.Supports(capability.Sideband64k) { - d = sideband.NewDemuxer(sideband.Sideband64k, r) - } else if req.Capabilities.Supports(capability.Sideband) { - d = sideband.NewDemuxer(sideband.Sideband, r) - } - if d != nil { - d.Progress = req.Progress - r = d - } - - rc := ioutil.NewReadCloser(r, res.Body) - - report := packp.NewReportStatus() - if err := report.Decode(rc); err != nil { - return nil, err - } - - return report, report.Error() -} - -func (s *rpSession) doRequest( - ctx context.Context, method, url string, content *bytes.Buffer, -) (*http.Response, error) { - - var body io.Reader - if content != nil { - body = content - } - - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, plumbing.NewPermanentError(err) - } - - applyHeadersToRequest(req, content, s.endpoint.Host, transport.ReceivePackServiceName) - s.ApplyAuthToRequest(req) - - res, err := s.client.Do(req.WithContext(ctx)) - if err != nil { - return nil, plumbing.NewUnexpectedError(err) - } - - if err := NewErr(res); err != nil { - _ = res.Body.Close() - return nil, err - } - - return res, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/upload_pack.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/upload_pack.go deleted file mode 100644 index fb5ac361..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/http/upload_pack.go +++ /dev/null @@ -1,123 +0,0 @@ -package http - -import ( - "bytes" - "context" - "fmt" - "io" - "net/http" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -type upSession struct { - *session -} - -func newUploadPackSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) { - s, err := newSession(c, ep, auth) - return &upSession{s}, err -} - -func (s *upSession) AdvertisedReferences() (*packp.AdvRefs, error) { - return advertisedReferences(s.session, transport.UploadPackServiceName) -} - -func (s *upSession) UploadPack( - ctx context.Context, req *packp.UploadPackRequest, -) (*packp.UploadPackResponse, error) { - - if req.IsEmpty() { - return nil, transport.ErrEmptyUploadPackRequest - } - - if err := req.Validate(); err != nil { - return nil, err - } - - url := fmt.Sprintf( - "%s/%s", - s.endpoint.String(), transport.UploadPackServiceName, - ) - - content, err := uploadPackRequestToReader(req) - if err != nil { - return nil, err - } - - res, err := s.doRequest(ctx, http.MethodPost, url, content) - if err != nil { - return nil, err - } - - r, err := ioutil.NonEmptyReader(res.Body) - if err != nil { - if err == ioutil.ErrEmptyReader || err == io.ErrUnexpectedEOF { - return nil, transport.ErrEmptyUploadPackRequest - } - - return nil, err - } - - rc := ioutil.NewReadCloser(r, res.Body) - return common.DecodeUploadPackResponse(rc, req) -} - -// Close does nothing. -func (s *upSession) Close() error { - return nil -} - -func (s *upSession) doRequest( - ctx context.Context, method, url string, content *bytes.Buffer, -) (*http.Response, error) { - - var body io.Reader - if content != nil { - body = content - } - - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, plumbing.NewPermanentError(err) - } - - applyHeadersToRequest(req, content, s.endpoint.Host, transport.UploadPackServiceName) - s.ApplyAuthToRequest(req) - - res, err := s.client.Do(req.WithContext(ctx)) - if err != nil { - return nil, plumbing.NewUnexpectedError(err) - } - - if err := NewErr(res); err != nil { - _ = res.Body.Close() - return nil, err - } - - return res, nil -} - -func uploadPackRequestToReader(req *packp.UploadPackRequest) (*bytes.Buffer, error) { - buf := bytes.NewBuffer(nil) - e := pktline.NewEncoder(buf) - - if err := req.UploadRequest.Encode(buf); err != nil { - return nil, fmt.Errorf("sending upload-req message: %s", err) - } - - if err := req.UploadHaves.Encode(buf, false); err != nil { - return nil, fmt.Errorf("sending haves message: %s", err) - } - - if err := e.EncodeString("done\n"); err != nil { - return nil, err - } - - return buf, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/common.go deleted file mode 100644 index 00497f3c..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/common.go +++ /dev/null @@ -1,467 +0,0 @@ -// Package common implements the git pack protocol with a pluggable transport. -// This is a low-level package to implement new transports. Use a concrete -// implementation instead (e.g. http, file, ssh). -// -// A simple example of usage can be found in the file package. -package common - -import ( - "bufio" - "context" - "errors" - "fmt" - "io" - stdioutil "io/ioutil" - "strings" - "time" - - "gopkg.in/src-d/go-git.v4/plumbing/format/pktline" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -const ( - readErrorSecondsTimeout = 10 -) - -var ( - ErrTimeoutExceeded = errors.New("timeout exceeded") -) - -// Commander creates Command instances. This is the main entry point for -// transport implementations. -type Commander interface { - // Command creates a new Command for the given git command and - // endpoint. cmd can be git-upload-pack or git-receive-pack. An - // error should be returned if the endpoint is not supported or the - // command cannot be created (e.g. binary does not exist, connection - // cannot be established). - Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (Command, error) -} - -// Command is used for a single command execution. -// This interface is modeled after exec.Cmd and ssh.Session in the standard -// library. -type Command interface { - // StderrPipe returns a pipe that will be connected to the command's - // standard error when the command starts. It should not be called after - // Start. - StderrPipe() (io.Reader, error) - // StdinPipe returns a pipe that will be connected to the command's - // standard input when the command starts. It should not be called after - // Start. The pipe should be closed when no more input is expected. - StdinPipe() (io.WriteCloser, error) - // StdoutPipe returns a pipe that will be connected to the command's - // standard output when the command starts. It should not be called after - // Start. - StdoutPipe() (io.Reader, error) - // Start starts the specified command. It does not wait for it to - // complete. - Start() error - // Close closes the command and releases any resources used by it. It - // will block until the command exits. - Close() error -} - -// CommandKiller expands the Command interface, enableing it for being killed. -type CommandKiller interface { - // Kill and close the session whatever the state it is. It will block until - // the command is terminated. - Kill() error -} - -type client struct { - cmdr Commander -} - -// NewClient creates a new client using the given Commander. -func NewClient(runner Commander) transport.Transport { - return &client{runner} -} - -// NewUploadPackSession creates a new UploadPackSession. -func (c *client) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( - transport.UploadPackSession, error) { - - return c.newSession(transport.UploadPackServiceName, ep, auth) -} - -// NewReceivePackSession creates a new ReceivePackSession. -func (c *client) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( - transport.ReceivePackSession, error) { - - return c.newSession(transport.ReceivePackServiceName, ep, auth) -} - -type session struct { - Stdin io.WriteCloser - Stdout io.Reader - Command Command - - isReceivePack bool - advRefs *packp.AdvRefs - packRun bool - finished bool - firstErrLine chan string -} - -func (c *client) newSession(s string, ep *transport.Endpoint, auth transport.AuthMethod) (*session, error) { - cmd, err := c.cmdr.Command(s, ep, auth) - if err != nil { - return nil, err - } - - stdin, err := cmd.StdinPipe() - if err != nil { - return nil, err - } - - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, err - } - - stderr, err := cmd.StderrPipe() - if err != nil { - return nil, err - } - - if err := cmd.Start(); err != nil { - return nil, err - } - - return &session{ - Stdin: stdin, - Stdout: stdout, - Command: cmd, - firstErrLine: c.listenFirstError(stderr), - isReceivePack: s == transport.ReceivePackServiceName, - }, nil -} - -func (c *client) listenFirstError(r io.Reader) chan string { - if r == nil { - return nil - } - - errLine := make(chan string, 1) - go func() { - s := bufio.NewScanner(r) - if s.Scan() { - errLine <- s.Text() - } else { - close(errLine) - } - - _, _ = io.Copy(stdioutil.Discard, r) - }() - - return errLine -} - -// AdvertisedReferences retrieves the advertised references from the server. -func (s *session) AdvertisedReferences() (*packp.AdvRefs, error) { - if s.advRefs != nil { - return s.advRefs, nil - } - - ar := packp.NewAdvRefs() - if err := ar.Decode(s.Stdout); err != nil { - if err := s.handleAdvRefDecodeError(err); err != nil { - return nil, err - } - } - - transport.FilterUnsupportedCapabilities(ar.Capabilities) - s.advRefs = ar - return ar, nil -} - -func (s *session) handleAdvRefDecodeError(err error) error { - // If repository is not found, we get empty stdout and server writes an - // error to stderr. - if err == packp.ErrEmptyInput { - s.finished = true - if err := s.checkNotFoundError(); err != nil { - return err - } - - return io.ErrUnexpectedEOF - } - - // For empty (but existing) repositories, we get empty advertised-references - // message. But valid. That is, it includes at least a flush. - if err == packp.ErrEmptyAdvRefs { - // Empty repositories are valid for git-receive-pack. - if s.isReceivePack { - return nil - } - - if err := s.finish(); err != nil { - return err - } - - return transport.ErrEmptyRemoteRepository - } - - // Some server sends the errors as normal content (git protocol), so when - // we try to decode it fails, we need to check the content of it, to detect - // not found errors - if uerr, ok := err.(*packp.ErrUnexpectedData); ok { - if isRepoNotFoundError(string(uerr.Data)) { - return transport.ErrRepositoryNotFound - } - } - - return err -} - -// UploadPack performs a request to the server to fetch a packfile. A reader is -// returned with the packfile content. The reader must be closed after reading. -func (s *session) UploadPack(ctx context.Context, req *packp.UploadPackRequest) (*packp.UploadPackResponse, error) { - if req.IsEmpty() { - return nil, transport.ErrEmptyUploadPackRequest - } - - if err := req.Validate(); err != nil { - return nil, err - } - - if _, err := s.AdvertisedReferences(); err != nil { - return nil, err - } - - s.packRun = true - - in := s.StdinContext(ctx) - out := s.StdoutContext(ctx) - - if err := uploadPack(in, out, req); err != nil { - return nil, err - } - - r, err := ioutil.NonEmptyReader(out) - if err == ioutil.ErrEmptyReader { - if c, ok := s.Stdout.(io.Closer); ok { - _ = c.Close() - } - - return nil, transport.ErrEmptyUploadPackRequest - } - - if err != nil { - return nil, err - } - - rc := ioutil.NewReadCloser(r, s) - return DecodeUploadPackResponse(rc, req) -} - -func (s *session) StdinContext(ctx context.Context) io.WriteCloser { - return ioutil.NewWriteCloserOnError( - ioutil.NewContextWriteCloser(ctx, s.Stdin), - s.onError, - ) -} - -func (s *session) StdoutContext(ctx context.Context) io.Reader { - return ioutil.NewReaderOnError( - ioutil.NewContextReader(ctx, s.Stdout), - s.onError, - ) -} - -func (s *session) onError(err error) { - if k, ok := s.Command.(CommandKiller); ok { - _ = k.Kill() - } - - _ = s.Close() -} - -func (s *session) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateRequest) (*packp.ReportStatus, error) { - if _, err := s.AdvertisedReferences(); err != nil { - return nil, err - } - - s.packRun = true - - w := s.StdinContext(ctx) - if err := req.Encode(w); err != nil { - return nil, err - } - - if err := w.Close(); err != nil { - return nil, err - } - - if !req.Capabilities.Supports(capability.ReportStatus) { - // If we don't have report-status, we can only - // check return value error. - return nil, s.Command.Close() - } - - r := s.StdoutContext(ctx) - - var d *sideband.Demuxer - if req.Capabilities.Supports(capability.Sideband64k) { - d = sideband.NewDemuxer(sideband.Sideband64k, r) - } else if req.Capabilities.Supports(capability.Sideband) { - d = sideband.NewDemuxer(sideband.Sideband, r) - } - if d != nil { - d.Progress = req.Progress - r = d - } - - report := packp.NewReportStatus() - if err := report.Decode(r); err != nil { - return nil, err - } - - if err := report.Error(); err != nil { - defer s.Close() - return report, err - } - - return report, s.Command.Close() -} - -func (s *session) finish() error { - if s.finished { - return nil - } - - s.finished = true - - // If we did not run a upload/receive-pack, we close the connection - // gracefully by sending a flush packet to the server. If the server - // operates correctly, it will exit with status 0. - if !s.packRun { - _, err := s.Stdin.Write(pktline.FlushPkt) - return err - } - - return nil -} - -func (s *session) Close() (err error) { - err = s.finish() - - defer ioutil.CheckClose(s.Command, &err) - return -} - -func (s *session) checkNotFoundError() error { - t := time.NewTicker(time.Second * readErrorSecondsTimeout) - defer t.Stop() - - select { - case <-t.C: - return ErrTimeoutExceeded - case line, ok := <-s.firstErrLine: - if !ok { - return nil - } - - if isRepoNotFoundError(line) { - return transport.ErrRepositoryNotFound - } - - return fmt.Errorf("unknown error: %s", line) - } -} - -var ( - githubRepoNotFoundErr = "ERROR: Repository not found." - bitbucketRepoNotFoundErr = "conq: repository does not exist." - localRepoNotFoundErr = "does not appear to be a git repository" - gitProtocolNotFoundErr = "ERR \n Repository not found." - gitProtocolNoSuchErr = "ERR no such repository" - gitProtocolAccessDeniedErr = "ERR access denied" - gogsAccessDeniedErr = "Gogs: Repository does not exist or you do not have access" -) - -func isRepoNotFoundError(s string) bool { - if strings.HasPrefix(s, githubRepoNotFoundErr) { - return true - } - - if strings.HasPrefix(s, bitbucketRepoNotFoundErr) { - return true - } - - if strings.HasSuffix(s, localRepoNotFoundErr) { - return true - } - - if strings.HasPrefix(s, gitProtocolNotFoundErr) { - return true - } - - if strings.HasPrefix(s, gitProtocolNoSuchErr) { - return true - } - - if strings.HasPrefix(s, gitProtocolAccessDeniedErr) { - return true - } - - if strings.HasPrefix(s, gogsAccessDeniedErr) { - return true - } - - return false -} - -var ( - nak = []byte("NAK") - eol = []byte("\n") -) - -// uploadPack implements the git-upload-pack protocol. -func uploadPack(w io.WriteCloser, r io.Reader, req *packp.UploadPackRequest) error { - // TODO support multi_ack mode - // TODO support multi_ack_detailed mode - // TODO support acks for common objects - // TODO build a proper state machine for all these processing options - - if err := req.UploadRequest.Encode(w); err != nil { - return fmt.Errorf("sending upload-req message: %s", err) - } - - if err := req.UploadHaves.Encode(w, true); err != nil { - return fmt.Errorf("sending haves message: %s", err) - } - - if err := sendDone(w); err != nil { - return fmt.Errorf("sending done message: %s", err) - } - - if err := w.Close(); err != nil { - return fmt.Errorf("closing input: %s", err) - } - - return nil -} - -func sendDone(w io.Writer) error { - e := pktline.NewEncoder(w) - - return e.Encodef("done\n") -} - -// DecodeUploadPackResponse decodes r into a new packp.UploadPackResponse -func DecodeUploadPackResponse(r io.ReadCloser, req *packp.UploadPackRequest) ( - *packp.UploadPackResponse, error, -) { - res := packp.NewUploadPackResponse(req) - if err := res.Decode(r); err != nil { - return nil, fmt.Errorf("error decoding upload-pack response: %s", err) - } - - return res, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/server.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/server.go deleted file mode 100644 index f4ca6924..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/server.go +++ /dev/null @@ -1,73 +0,0 @@ -package common - -import ( - "context" - "fmt" - "io" - - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -// ServerCommand is used for a single server command execution. -type ServerCommand struct { - Stderr io.Writer - Stdout io.WriteCloser - Stdin io.Reader -} - -func ServeUploadPack(cmd ServerCommand, s transport.UploadPackSession) (err error) { - ioutil.CheckClose(cmd.Stdout, &err) - - ar, err := s.AdvertisedReferences() - if err != nil { - return err - } - - if err := ar.Encode(cmd.Stdout); err != nil { - return err - } - - req := packp.NewUploadPackRequest() - if err := req.Decode(cmd.Stdin); err != nil { - return err - } - - var resp *packp.UploadPackResponse - resp, err = s.UploadPack(context.TODO(), req) - if err != nil { - return err - } - - return resp.Encode(cmd.Stdout) -} - -func ServeReceivePack(cmd ServerCommand, s transport.ReceivePackSession) error { - ar, err := s.AdvertisedReferences() - if err != nil { - return fmt.Errorf("internal error in advertised references: %s", err) - } - - if err := ar.Encode(cmd.Stdout); err != nil { - return fmt.Errorf("error in advertised references encoding: %s", err) - } - - req := packp.NewReferenceUpdateRequest() - if err := req.Decode(cmd.Stdin); err != nil { - return fmt.Errorf("error decoding: %s", err) - } - - rs, err := s.ReceivePack(context.TODO(), req) - if rs != nil { - if err := rs.Encode(cmd.Stdout); err != nil { - return fmt.Errorf("error in encoding report status %s", err) - } - } - - if err != nil { - return fmt.Errorf("error in receive pack: %s", err) - } - - return nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/loader.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/loader.go deleted file mode 100644 index 13b35262..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/loader.go +++ /dev/null @@ -1,64 +0,0 @@ -package server - -import ( - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/storage/filesystem" - - "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-billy.v4/osfs" -) - -// DefaultLoader is a filesystem loader ignoring host and resolving paths to /. -var DefaultLoader = NewFilesystemLoader(osfs.New("")) - -// Loader loads repository's storer.Storer based on an optional host and a path. -type Loader interface { - // Load loads a storer.Storer given a transport.Endpoint. - // Returns transport.ErrRepositoryNotFound if the repository does not - // exist. - Load(ep *transport.Endpoint) (storer.Storer, error) -} - -type fsLoader struct { - base billy.Filesystem -} - -// NewFilesystemLoader creates a Loader that ignores host and resolves paths -// with a given base filesystem. -func NewFilesystemLoader(base billy.Filesystem) Loader { - return &fsLoader{base} -} - -// Load looks up the endpoint's path in the base file system and returns a -// storer for it. Returns transport.ErrRepositoryNotFound if a repository does -// not exist in the given path. -func (l *fsLoader) Load(ep *transport.Endpoint) (storer.Storer, error) { - fs, err := l.base.Chroot(ep.Path) - if err != nil { - return nil, err - } - - if _, err := fs.Stat("config"); err != nil { - return nil, transport.ErrRepositoryNotFound - } - - return filesystem.NewStorage(fs, cache.NewObjectLRUDefault()), nil -} - -// MapLoader is a Loader that uses a lookup map of storer.Storer by -// transport.Endpoint. -type MapLoader map[string]storer.Storer - -// Load returns a storer.Storer for given a transport.Endpoint by looking it up -// in the map. Returns transport.ErrRepositoryNotFound if the endpoint does not -// exist. -func (l MapLoader) Load(ep *transport.Endpoint) (storer.Storer, error) { - s, ok := l[ep.String()] - if !ok { - return nil, transport.ErrRepositoryNotFound - } - - return s, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/server.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/server.go deleted file mode 100644 index 8e0dcc11..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/server/server.go +++ /dev/null @@ -1,422 +0,0 @@ -// Package server implements the git server protocol. For most use cases, the -// transport-specific implementations should be used. -package server - -import ( - "context" - "errors" - "fmt" - "io" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" - "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" - "gopkg.in/src-d/go-git.v4/plumbing/revlist" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -var DefaultServer = NewServer(DefaultLoader) - -type server struct { - loader Loader - handler *handler -} - -// NewServer returns a transport.Transport implementing a git server, -// independent of transport. Each transport must wrap this. -func NewServer(loader Loader) transport.Transport { - return &server{ - loader, - &handler{asClient: false}, - } -} - -// NewClient returns a transport.Transport implementing a client with an -// embedded server. -func NewClient(loader Loader) transport.Transport { - return &server{ - loader, - &handler{asClient: true}, - } -} - -func (s *server) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) { - sto, err := s.loader.Load(ep) - if err != nil { - return nil, err - } - - return s.handler.NewUploadPackSession(sto) -} - -func (s *server) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) { - sto, err := s.loader.Load(ep) - if err != nil { - return nil, err - } - - return s.handler.NewReceivePackSession(sto) -} - -type handler struct { - asClient bool -} - -func (h *handler) NewUploadPackSession(s storer.Storer) (transport.UploadPackSession, error) { - return &upSession{ - session: session{storer: s, asClient: h.asClient}, - }, nil -} - -func (h *handler) NewReceivePackSession(s storer.Storer) (transport.ReceivePackSession, error) { - return &rpSession{ - session: session{storer: s, asClient: h.asClient}, - cmdStatus: map[plumbing.ReferenceName]error{}, - }, nil -} - -type session struct { - storer storer.Storer - caps *capability.List - asClient bool -} - -func (s *session) Close() error { - return nil -} - -func (s *session) SetAuth(transport.AuthMethod) error { - //TODO: deprecate - return nil -} - -func (s *session) checkSupportedCapabilities(cl *capability.List) error { - for _, c := range cl.All() { - if !s.caps.Supports(c) { - return fmt.Errorf("unsupported capability: %s", c) - } - } - - return nil -} - -type upSession struct { - session -} - -func (s *upSession) AdvertisedReferences() (*packp.AdvRefs, error) { - ar := packp.NewAdvRefs() - - if err := s.setSupportedCapabilities(ar.Capabilities); err != nil { - return nil, err - } - - s.caps = ar.Capabilities - - if err := setReferences(s.storer, ar); err != nil { - return nil, err - } - - if err := setHEAD(s.storer, ar); err != nil { - return nil, err - } - - if s.asClient && len(ar.References) == 0 { - return nil, transport.ErrEmptyRemoteRepository - } - - return ar, nil -} - -func (s *upSession) UploadPack(ctx context.Context, req *packp.UploadPackRequest) (*packp.UploadPackResponse, error) { - if req.IsEmpty() { - return nil, transport.ErrEmptyUploadPackRequest - } - - if err := req.Validate(); err != nil { - return nil, err - } - - if s.caps == nil { - s.caps = capability.NewList() - if err := s.setSupportedCapabilities(s.caps); err != nil { - return nil, err - } - } - - if err := s.checkSupportedCapabilities(req.Capabilities); err != nil { - return nil, err - } - - s.caps = req.Capabilities - - if len(req.Shallows) > 0 { - return nil, fmt.Errorf("shallow not supported") - } - - objs, err := s.objectsToUpload(req) - if err != nil { - return nil, err - } - - pr, pw := io.Pipe() - e := packfile.NewEncoder(pw, s.storer, false) - go func() { - // TODO: plumb through a pack window. - _, err := e.Encode(objs, 10) - pw.CloseWithError(err) - }() - - return packp.NewUploadPackResponseWithPackfile(req, - ioutil.NewContextReadCloser(ctx, pr), - ), nil -} - -func (s *upSession) objectsToUpload(req *packp.UploadPackRequest) ([]plumbing.Hash, error) { - haves, err := revlist.Objects(s.storer, req.Haves, nil) - if err != nil { - return nil, err - } - - return revlist.Objects(s.storer, req.Wants, haves) -} - -func (*upSession) setSupportedCapabilities(c *capability.List) error { - if err := c.Set(capability.Agent, capability.DefaultAgent); err != nil { - return err - } - - if err := c.Set(capability.OFSDelta); err != nil { - return err - } - - return nil -} - -type rpSession struct { - session - cmdStatus map[plumbing.ReferenceName]error - firstErr error - unpackErr error -} - -func (s *rpSession) AdvertisedReferences() (*packp.AdvRefs, error) { - ar := packp.NewAdvRefs() - - if err := s.setSupportedCapabilities(ar.Capabilities); err != nil { - return nil, err - } - - s.caps = ar.Capabilities - - if err := setReferences(s.storer, ar); err != nil { - return nil, err - } - - if err := setHEAD(s.storer, ar); err != nil { - return nil, err - } - - return ar, nil -} - -var ( - ErrUpdateReference = errors.New("failed to update ref") -) - -func (s *rpSession) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateRequest) (*packp.ReportStatus, error) { - if s.caps == nil { - s.caps = capability.NewList() - if err := s.setSupportedCapabilities(s.caps); err != nil { - return nil, err - } - } - - if err := s.checkSupportedCapabilities(req.Capabilities); err != nil { - return nil, err - } - - s.caps = req.Capabilities - - //TODO: Implement 'atomic' update of references. - - r := ioutil.NewContextReadCloser(ctx, req.Packfile) - if err := s.writePackfile(r); err != nil { - s.unpackErr = err - s.firstErr = err - return s.reportStatus(), err - } - - s.updateReferences(req) - return s.reportStatus(), s.firstErr -} - -func (s *rpSession) updateReferences(req *packp.ReferenceUpdateRequest) { - for _, cmd := range req.Commands { - exists, err := referenceExists(s.storer, cmd.Name) - if err != nil { - s.setStatus(cmd.Name, err) - continue - } - - switch cmd.Action() { - case packp.Create: - if exists { - s.setStatus(cmd.Name, ErrUpdateReference) - continue - } - - ref := plumbing.NewHashReference(cmd.Name, cmd.New) - err := s.storer.SetReference(ref) - s.setStatus(cmd.Name, err) - case packp.Delete: - if !exists { - s.setStatus(cmd.Name, ErrUpdateReference) - continue - } - - err := s.storer.RemoveReference(cmd.Name) - s.setStatus(cmd.Name, err) - case packp.Update: - if !exists { - s.setStatus(cmd.Name, ErrUpdateReference) - continue - } - - ref := plumbing.NewHashReference(cmd.Name, cmd.New) - err := s.storer.SetReference(ref) - s.setStatus(cmd.Name, err) - } - } -} - -func (s *rpSession) writePackfile(r io.ReadCloser) error { - if r == nil { - return nil - } - - if err := packfile.UpdateObjectStorage(s.storer, r); err != nil { - _ = r.Close() - return err - } - - return r.Close() -} - -func (s *rpSession) setStatus(ref plumbing.ReferenceName, err error) { - s.cmdStatus[ref] = err - if s.firstErr == nil && err != nil { - s.firstErr = err - } -} - -func (s *rpSession) reportStatus() *packp.ReportStatus { - if !s.caps.Supports(capability.ReportStatus) { - return nil - } - - rs := packp.NewReportStatus() - rs.UnpackStatus = "ok" - - if s.unpackErr != nil { - rs.UnpackStatus = s.unpackErr.Error() - } - - if s.cmdStatus == nil { - return rs - } - - for ref, err := range s.cmdStatus { - msg := "ok" - if err != nil { - msg = err.Error() - } - status := &packp.CommandStatus{ - ReferenceName: ref, - Status: msg, - } - rs.CommandStatuses = append(rs.CommandStatuses, status) - } - - return rs -} - -func (*rpSession) setSupportedCapabilities(c *capability.List) error { - if err := c.Set(capability.Agent, capability.DefaultAgent); err != nil { - return err - } - - if err := c.Set(capability.OFSDelta); err != nil { - return err - } - - if err := c.Set(capability.DeleteRefs); err != nil { - return err - } - - return c.Set(capability.ReportStatus) -} - -func setHEAD(s storer.Storer, ar *packp.AdvRefs) error { - ref, err := s.Reference(plumbing.HEAD) - if err == plumbing.ErrReferenceNotFound { - return nil - } - - if err != nil { - return err - } - - if ref.Type() == plumbing.SymbolicReference { - if err := ar.AddReference(ref); err != nil { - return nil - } - - ref, err = storer.ResolveReference(s, ref.Target()) - if err == plumbing.ErrReferenceNotFound { - return nil - } - - if err != nil { - return err - } - } - - if ref.Type() != plumbing.HashReference { - return plumbing.ErrInvalidType - } - - h := ref.Hash() - ar.Head = &h - - return nil -} - -func setReferences(s storer.Storer, ar *packp.AdvRefs) error { - //TODO: add peeled references. - iter, err := s.IterReferences() - if err != nil { - return err - } - - return iter.ForEach(func(ref *plumbing.Reference) error { - if ref.Type() != plumbing.HashReference { - return nil - } - - ar.References[ref.Name().String()] = ref.Hash() - return nil - }) -} - -func referenceExists(s storer.ReferenceStorer, n plumbing.ReferenceName) (bool, error) { - _, err := s.Reference(n) - if err == plumbing.ErrReferenceNotFound { - return false, nil - } - - return err == nil, err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/auth_method.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/auth_method.go deleted file mode 100644 index 1e5c3837..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/auth_method.go +++ /dev/null @@ -1,322 +0,0 @@ -package ssh - -import ( - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "io/ioutil" - "os" - "os/user" - "path/filepath" - - "gopkg.in/src-d/go-git.v4/plumbing/transport" - - "github.com/mitchellh/go-homedir" - "github.com/xanzy/ssh-agent" - "golang.org/x/crypto/ssh" - "golang.org/x/crypto/ssh/knownhosts" -) - -const DefaultUsername = "git" - -// AuthMethod is the interface all auth methods for the ssh client -// must implement. The clientConfig method returns the ssh client -// configuration needed to establish an ssh connection. -type AuthMethod interface { - transport.AuthMethod - // ClientConfig should return a valid ssh.ClientConfig to be used to create - // a connection to the SSH server. - ClientConfig() (*ssh.ClientConfig, error) -} - -// The names of the AuthMethod implementations. To be returned by the -// Name() method. Most git servers only allow PublicKeysName and -// PublicKeysCallbackName. -const ( - KeyboardInteractiveName = "ssh-keyboard-interactive" - PasswordName = "ssh-password" - PasswordCallbackName = "ssh-password-callback" - PublicKeysName = "ssh-public-keys" - PublicKeysCallbackName = "ssh-public-key-callback" -) - -// KeyboardInteractive implements AuthMethod by using a -// prompt/response sequence controlled by the server. -type KeyboardInteractive struct { - User string - Challenge ssh.KeyboardInteractiveChallenge - HostKeyCallbackHelper -} - -func (a *KeyboardInteractive) Name() string { - return KeyboardInteractiveName -} - -func (a *KeyboardInteractive) String() string { - return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) -} - -func (a *KeyboardInteractive) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ - a.Challenge, - }, - }) -} - -// Password implements AuthMethod by using the given password. -type Password struct { - User string - Password string - HostKeyCallbackHelper -} - -func (a *Password) Name() string { - return PasswordName -} - -func (a *Password) String() string { - return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) -} - -func (a *Password) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.Password(a.Password)}, - }) -} - -// PasswordCallback implements AuthMethod by using a callback -// to fetch the password. -type PasswordCallback struct { - User string - Callback func() (pass string, err error) - HostKeyCallbackHelper -} - -func (a *PasswordCallback) Name() string { - return PasswordCallbackName -} - -func (a *PasswordCallback) String() string { - return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) -} - -func (a *PasswordCallback) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)}, - }) -} - -// PublicKeys implements AuthMethod by using the given key pairs. -type PublicKeys struct { - User string - Signer ssh.Signer - HostKeyCallbackHelper -} - -// NewPublicKeys returns a PublicKeys from a PEM encoded private key. An -// encryption password should be given if the pemBytes contains a password -// encrypted PEM block otherwise password should be empty. It supports RSA -// (PKCS#1), DSA (OpenSSL), and ECDSA private keys. -func NewPublicKeys(user string, pemBytes []byte, password string) (*PublicKeys, error) { - block, _ := pem.Decode(pemBytes) - if block == nil { - return nil, errors.New("invalid PEM data") - } - if x509.IsEncryptedPEMBlock(block) { - key, err := x509.DecryptPEMBlock(block, []byte(password)) - if err != nil { - return nil, err - } - - block = &pem.Block{Type: block.Type, Bytes: key} - pemBytes = pem.EncodeToMemory(block) - } - - signer, err := ssh.ParsePrivateKey(pemBytes) - if err != nil { - return nil, err - } - - return &PublicKeys{User: user, Signer: signer}, nil -} - -// NewPublicKeysFromFile returns a PublicKeys from a file containing a PEM -// encoded private key. An encryption password should be given if the pemBytes -// contains a password encrypted PEM block otherwise password should be empty. -func NewPublicKeysFromFile(user, pemFile, password string) (*PublicKeys, error) { - bytes, err := ioutil.ReadFile(pemFile) - if err != nil { - return nil, err - } - - return NewPublicKeys(user, bytes, password) -} - -func (a *PublicKeys) Name() string { - return PublicKeysName -} - -func (a *PublicKeys) String() string { - return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) -} - -func (a *PublicKeys) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)}, - }) -} - -func username() (string, error) { - var username string - if user, err := user.Current(); err == nil { - username = user.Username - } else { - username = os.Getenv("USER") - } - - if username == "" { - return "", errors.New("failed to get username") - } - - return username, nil -} - -// PublicKeysCallback implements AuthMethod by asking a -// ssh.agent.Agent to act as a signer. -type PublicKeysCallback struct { - User string - Callback func() (signers []ssh.Signer, err error) - HostKeyCallbackHelper -} - -// NewSSHAgentAuth returns a PublicKeysCallback based on a SSH agent, it opens -// a pipe with the SSH agent and uses the pipe as the implementer of the public -// key callback function. -func NewSSHAgentAuth(u string) (*PublicKeysCallback, error) { - var err error - if u == "" { - u, err = username() - if err != nil { - return nil, err - } - } - - a, _, err := sshagent.New() - if err != nil { - return nil, fmt.Errorf("error creating SSH agent: %q", err) - } - - return &PublicKeysCallback{ - User: u, - Callback: a.Signers, - }, nil -} - -func (a *PublicKeysCallback) Name() string { - return PublicKeysCallbackName -} - -func (a *PublicKeysCallback) String() string { - return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) -} - -func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) { - return a.SetHostKeyCallback(&ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)}, - }) -} - -// NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a -// known_hosts file. http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT -// -// If list of files is empty, then it will be read from the SSH_KNOWN_HOSTS -// environment variable, example: -// /home/foo/custom_known_hosts_file:/etc/custom_known/hosts_file -// -// If SSH_KNOWN_HOSTS is not set the following file locations will be used: -// ~/.ssh/known_hosts -// /etc/ssh/ssh_known_hosts -func NewKnownHostsCallback(files ...string) (ssh.HostKeyCallback, error) { - var err error - - if len(files) == 0 { - if files, err = getDefaultKnownHostsFiles(); err != nil { - return nil, err - } - } - - if files, err = filterKnownHostsFiles(files...); err != nil { - return nil, err - } - - return knownhosts.New(files...) -} - -func getDefaultKnownHostsFiles() ([]string, error) { - files := filepath.SplitList(os.Getenv("SSH_KNOWN_HOSTS")) - if len(files) != 0 { - return files, nil - } - - homeDirPath, err := homedir.Dir() - if err != nil { - return nil, err - } - - return []string{ - filepath.Join(homeDirPath, "/.ssh/known_hosts"), - "/etc/ssh/ssh_known_hosts", - }, nil -} - -func filterKnownHostsFiles(files ...string) ([]string, error) { - var out []string - for _, file := range files { - _, err := os.Stat(file) - if err == nil { - out = append(out, file) - continue - } - - if !os.IsNotExist(err) { - return nil, err - } - } - - if len(out) == 0 { - return nil, fmt.Errorf("unable to find any valid known_hosts file, set SSH_KNOWN_HOSTS env variable") - } - - return out, nil -} - -// HostKeyCallbackHelper is a helper that provides common functionality to -// configure HostKeyCallback into a ssh.ClientConfig. -type HostKeyCallbackHelper struct { - // HostKeyCallback is the function type used for verifying server keys. - // If nil default callback will be create using NewKnownHostsCallback - // without argument. - HostKeyCallback ssh.HostKeyCallback -} - -// SetHostKeyCallback sets the field HostKeyCallback in the given cfg. If -// HostKeyCallback is empty a default callback is created using -// NewKnownHostsCallback. -func (m *HostKeyCallbackHelper) SetHostKeyCallback(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) { - var err error - if m.HostKeyCallback == nil { - if m.HostKeyCallback, err = NewKnownHostsCallback(); err != nil { - return cfg, err - } - } - - cfg.HostKeyCallback = m.HostKeyCallback - return cfg, nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/common.go b/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/common.go deleted file mode 100644 index d320d433..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/ssh/common.go +++ /dev/null @@ -1,228 +0,0 @@ -// Package ssh implements the SSH transport protocol. -package ssh - -import ( - "context" - "fmt" - "reflect" - "strconv" - - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common" - - "github.com/kevinburke/ssh_config" - "golang.org/x/crypto/ssh" - "golang.org/x/net/proxy" -) - -// DefaultClient is the default SSH client. -var DefaultClient = NewClient(nil) - -// DefaultSSHConfig is the reader used to access parameters stored in the -// system's ssh_config files. If nil all the ssh_config are ignored. -var DefaultSSHConfig sshConfig = ssh_config.DefaultUserSettings - -type sshConfig interface { - Get(alias, key string) string -} - -// NewClient creates a new SSH client with an optional *ssh.ClientConfig. -func NewClient(config *ssh.ClientConfig) transport.Transport { - return common.NewClient(&runner{config: config}) -} - -// DefaultAuthBuilder is the function used to create a default AuthMethod, when -// the user doesn't provide any. -var DefaultAuthBuilder = func(user string) (AuthMethod, error) { - return NewSSHAgentAuth(user) -} - -const DefaultPort = 22 - -type runner struct { - config *ssh.ClientConfig -} - -func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (common.Command, error) { - c := &command{command: cmd, endpoint: ep, config: r.config} - if auth != nil { - c.setAuth(auth) - } - - if err := c.connect(); err != nil { - return nil, err - } - return c, nil -} - -type command struct { - *ssh.Session - connected bool - command string - endpoint *transport.Endpoint - client *ssh.Client - auth AuthMethod - config *ssh.ClientConfig -} - -func (c *command) setAuth(auth transport.AuthMethod) error { - a, ok := auth.(AuthMethod) - if !ok { - return transport.ErrInvalidAuthMethod - } - - c.auth = a - return nil -} - -func (c *command) Start() error { - return c.Session.Start(endpointToCommand(c.command, c.endpoint)) -} - -// Close closes the SSH session and connection. -func (c *command) Close() error { - if !c.connected { - return nil - } - - c.connected = false - - //XXX: If did read the full packfile, then the session might be already - // closed. - _ = c.Session.Close() - - return c.client.Close() -} - -// connect connects to the SSH server, unless a AuthMethod was set with -// SetAuth method, by default uses an auth method based on PublicKeysCallback, -// it connects to a SSH agent, using the address stored in the SSH_AUTH_SOCK -// environment var. -func (c *command) connect() error { - if c.connected { - return transport.ErrAlreadyConnected - } - - if c.auth == nil { - if err := c.setAuthFromEndpoint(); err != nil { - return err - } - } - - var err error - config, err := c.auth.ClientConfig() - if err != nil { - return err - } - - overrideConfig(c.config, config) - - c.client, err = dial("tcp", c.getHostWithPort(), config) - if err != nil { - return err - } - - c.Session, err = c.client.NewSession() - if err != nil { - _ = c.client.Close() - return err - } - - c.connected = true - return nil -} - -func dial(network, addr string, config *ssh.ClientConfig) (*ssh.Client, error) { - var ( - ctx = context.Background() - cancel context.CancelFunc - ) - if config.Timeout > 0 { - ctx, cancel = context.WithTimeout(ctx, config.Timeout) - } else { - ctx, cancel = context.WithCancel(ctx) - } - defer cancel() - - conn, err := proxy.Dial(ctx, network, addr) - if err != nil { - return nil, err - } - c, chans, reqs, err := ssh.NewClientConn(conn, addr, config) - if err != nil { - return nil, err - } - return ssh.NewClient(c, chans, reqs), nil -} - -func (c *command) getHostWithPort() string { - if addr, found := c.doGetHostWithPortFromSSHConfig(); found { - return addr - } - - host := c.endpoint.Host - port := c.endpoint.Port - if port <= 0 { - port = DefaultPort - } - - return fmt.Sprintf("%s:%d", host, port) -} - -func (c *command) doGetHostWithPortFromSSHConfig() (addr string, found bool) { - if DefaultSSHConfig == nil { - return - } - - host := c.endpoint.Host - port := c.endpoint.Port - - configHost := DefaultSSHConfig.Get(c.endpoint.Host, "Hostname") - if configHost != "" { - host = configHost - found = true - } - - if !found { - return - } - - configPort := DefaultSSHConfig.Get(c.endpoint.Host, "Port") - if configPort != "" { - if i, err := strconv.Atoi(configPort); err == nil { - port = i - } - } - - addr = fmt.Sprintf("%s:%d", host, port) - return -} - -func (c *command) setAuthFromEndpoint() error { - var err error - c.auth, err = DefaultAuthBuilder(c.endpoint.User) - return err -} - -func endpointToCommand(cmd string, ep *transport.Endpoint) string { - return fmt.Sprintf("%s '%s'", cmd, ep.Path) -} - -func overrideConfig(overrides *ssh.ClientConfig, c *ssh.ClientConfig) { - if overrides == nil { - return - } - - t := reflect.TypeOf(*c) - vc := reflect.ValueOf(c).Elem() - vo := reflect.ValueOf(overrides).Elem() - - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - vcf := vc.FieldByName(f.Name) - vof := vo.FieldByName(f.Name) - vcf.Set(vof) - } - - *c = vc.Interface().(ssh.ClientConfig) -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/config.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/config.go deleted file mode 100644 index be812e42..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/config.go +++ /dev/null @@ -1,61 +0,0 @@ -package filesystem - -import ( - stdioutil "io/ioutil" - "os" - - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -type ConfigStorage struct { - dir *dotgit.DotGit -} - -func (c *ConfigStorage) Config() (conf *config.Config, err error) { - cfg := config.NewConfig() - - f, err := c.dir.Config() - if err != nil { - if os.IsNotExist(err) { - return cfg, nil - } - - return nil, err - } - - defer ioutil.CheckClose(f, &err) - - b, err := stdioutil.ReadAll(f) - if err != nil { - return nil, err - } - - if err = cfg.Unmarshal(b); err != nil { - return nil, err - } - - return cfg, err -} - -func (c *ConfigStorage) SetConfig(cfg *config.Config) (err error) { - if err = cfg.Validate(); err != nil { - return err - } - - f, err := c.dir.ConfigWriter() - if err != nil { - return err - } - - defer ioutil.CheckClose(f, &err) - - b, err := cfg.Marshal() - if err != nil { - return err - } - - _, err = f.Write(b) - return err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/deltaobject.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/deltaobject.go deleted file mode 100644 index 66cfb716..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/deltaobject.go +++ /dev/null @@ -1,37 +0,0 @@ -package filesystem - -import ( - "gopkg.in/src-d/go-git.v4/plumbing" -) - -type deltaObject struct { - plumbing.EncodedObject - base plumbing.Hash - hash plumbing.Hash - size int64 -} - -func newDeltaObject( - obj plumbing.EncodedObject, - hash plumbing.Hash, - base plumbing.Hash, - size int64) plumbing.DeltaObject { - return &deltaObject{ - EncodedObject: obj, - hash: hash, - base: base, - size: size, - } -} - -func (o *deltaObject) BaseHash() plumbing.Hash { - return o.base -} - -func (o *deltaObject) ActualSize() int64 { - return o.size -} - -func (o *deltaObject) ActualHash() plumbing.Hash { - return o.hash -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit.go deleted file mode 100644 index 111769bf..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit.go +++ /dev/null @@ -1,1099 +0,0 @@ -// https://github.com/git/git/blob/master/Documentation/gitrepository-layout.txt -package dotgit - -import ( - "bufio" - "errors" - "fmt" - "io" - stdioutil "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - "gopkg.in/src-d/go-billy.v4/osfs" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/storage" - "gopkg.in/src-d/go-git.v4/utils/ioutil" - - "gopkg.in/src-d/go-billy.v4" -) - -const ( - suffix = ".git" - packedRefsPath = "packed-refs" - configPath = "config" - indexPath = "index" - shallowPath = "shallow" - modulePath = "modules" - objectsPath = "objects" - packPath = "pack" - refsPath = "refs" - - tmpPackedRefsPrefix = "._packed-refs" - - packExt = ".pack" - idxExt = ".idx" -) - -var ( - // ErrNotFound is returned by New when the path is not found. - ErrNotFound = errors.New("path not found") - // ErrIdxNotFound is returned by Idxfile when the idx file is not found - ErrIdxNotFound = errors.New("idx file not found") - // ErrPackfileNotFound is returned by Packfile when the packfile is not found - ErrPackfileNotFound = errors.New("packfile not found") - // ErrConfigNotFound is returned by Config when the config is not found - ErrConfigNotFound = errors.New("config file not found") - // ErrPackedRefsDuplicatedRef is returned when a duplicated reference is - // found in the packed-ref file. This is usually the case for corrupted git - // repositories. - ErrPackedRefsDuplicatedRef = errors.New("duplicated ref found in packed-ref file") - // ErrPackedRefsBadFormat is returned when the packed-ref file corrupt. - ErrPackedRefsBadFormat = errors.New("malformed packed-ref") - // ErrSymRefTargetNotFound is returned when a symbolic reference is - // targeting a non-existing object. This usually means the repository - // is corrupt. - ErrSymRefTargetNotFound = errors.New("symbolic reference target not found") -) - -// Options holds configuration for the storage. -type Options struct { - // ExclusiveAccess means that the filesystem is not modified externally - // while the repo is open. - ExclusiveAccess bool - // KeepDescriptors makes the file descriptors to be reused but they will - // need to be manually closed calling Close(). - KeepDescriptors bool -} - -// The DotGit type represents a local git repository on disk. This -// type is not zero-value-safe, use the New function to initialize it. -type DotGit struct { - options Options - fs billy.Filesystem - - // incoming object directory information - incomingChecked bool - incomingDirName string - - objectList []plumbing.Hash - objectMap map[plumbing.Hash]struct{} - packList []plumbing.Hash - packMap map[plumbing.Hash]struct{} - - files map[plumbing.Hash]billy.File -} - -// New returns a DotGit value ready to be used. The path argument must -// be the absolute path of a git repository directory (e.g. -// "/foo/bar/.git"). -func New(fs billy.Filesystem) *DotGit { - return NewWithOptions(fs, Options{}) -} - -// NewWithOptions sets non default configuration options. -// See New for complete help. -func NewWithOptions(fs billy.Filesystem, o Options) *DotGit { - return &DotGit{ - options: o, - fs: fs, - } -} - -// Initialize creates all the folder scaffolding. -func (d *DotGit) Initialize() error { - mustExists := []string{ - d.fs.Join("objects", "info"), - d.fs.Join("objects", "pack"), - d.fs.Join("refs", "heads"), - d.fs.Join("refs", "tags"), - } - - for _, path := range mustExists { - _, err := d.fs.Stat(path) - if err == nil { - continue - } - - if !os.IsNotExist(err) { - return err - } - - if err := d.fs.MkdirAll(path, os.ModeDir|os.ModePerm); err != nil { - return err - } - } - - return nil -} - -// Close closes all opened files. -func (d *DotGit) Close() error { - var firstError error - if d.files != nil { - for _, f := range d.files { - err := f.Close() - if err != nil && firstError == nil { - firstError = err - continue - } - } - - d.files = nil - } - - if firstError != nil { - return firstError - } - - return nil -} - -// ConfigWriter returns a file pointer for write to the config file -func (d *DotGit) ConfigWriter() (billy.File, error) { - return d.fs.Create(configPath) -} - -// Config returns a file pointer for read to the config file -func (d *DotGit) Config() (billy.File, error) { - return d.fs.Open(configPath) -} - -// IndexWriter returns a file pointer for write to the index file -func (d *DotGit) IndexWriter() (billy.File, error) { - return d.fs.Create(indexPath) -} - -// Index returns a file pointer for read to the index file -func (d *DotGit) Index() (billy.File, error) { - return d.fs.Open(indexPath) -} - -// ShallowWriter returns a file pointer for write to the shallow file -func (d *DotGit) ShallowWriter() (billy.File, error) { - return d.fs.Create(shallowPath) -} - -// Shallow returns a file pointer for read to the shallow file -func (d *DotGit) Shallow() (billy.File, error) { - f, err := d.fs.Open(shallowPath) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - - return nil, err - } - - return f, nil -} - -// NewObjectPack return a writer for a new packfile, it saves the packfile to -// disk and also generates and save the index for the given packfile. -func (d *DotGit) NewObjectPack() (*PackWriter, error) { - d.cleanPackList() - return newPackWrite(d.fs) -} - -// ObjectPacks returns the list of availables packfiles -func (d *DotGit) ObjectPacks() ([]plumbing.Hash, error) { - if !d.options.ExclusiveAccess { - return d.objectPacks() - } - - err := d.genPackList() - if err != nil { - return nil, err - } - - return d.packList, nil -} - -func (d *DotGit) objectPacks() ([]plumbing.Hash, error) { - packDir := d.fs.Join(objectsPath, packPath) - files, err := d.fs.ReadDir(packDir) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - - return nil, err - } - - var packs []plumbing.Hash - for _, f := range files { - if !strings.HasSuffix(f.Name(), packExt) { - continue - } - - n := f.Name() - h := plumbing.NewHash(n[5 : len(n)-5]) //pack-(hash).pack - if h.IsZero() { - // Ignore files with badly-formatted names. - continue - } - packs = append(packs, h) - } - - return packs, nil -} - -func (d *DotGit) objectPackPath(hash plumbing.Hash, extension string) string { - return d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.%s", hash.String(), extension)) -} - -func (d *DotGit) objectPackOpen(hash plumbing.Hash, extension string) (billy.File, error) { - if d.options.KeepDescriptors && extension == "pack" { - if d.files == nil { - d.files = make(map[plumbing.Hash]billy.File) - } - - f, ok := d.files[hash] - if ok { - return f, nil - } - } - - err := d.hasPack(hash) - if err != nil { - return nil, err - } - - path := d.objectPackPath(hash, extension) - pack, err := d.fs.Open(path) - if err != nil { - if os.IsNotExist(err) { - return nil, ErrPackfileNotFound - } - - return nil, err - } - - if d.options.KeepDescriptors && extension == "pack" { - d.files[hash] = pack - } - - return pack, nil -} - -// ObjectPack returns a fs.File of the given packfile -func (d *DotGit) ObjectPack(hash plumbing.Hash) (billy.File, error) { - err := d.hasPack(hash) - if err != nil { - return nil, err - } - - return d.objectPackOpen(hash, `pack`) -} - -// ObjectPackIdx returns a fs.File of the index file for a given packfile -func (d *DotGit) ObjectPackIdx(hash plumbing.Hash) (billy.File, error) { - err := d.hasPack(hash) - if err != nil { - return nil, err - } - - return d.objectPackOpen(hash, `idx`) -} - -func (d *DotGit) DeleteOldObjectPackAndIndex(hash plumbing.Hash, t time.Time) error { - d.cleanPackList() - - path := d.objectPackPath(hash, `pack`) - if !t.IsZero() { - fi, err := d.fs.Stat(path) - if err != nil { - return err - } - // too new, skip deletion. - if !fi.ModTime().Before(t) { - return nil - } - } - err := d.fs.Remove(path) - if err != nil { - return err - } - return d.fs.Remove(d.objectPackPath(hash, `idx`)) -} - -// NewObject return a writer for a new object file. -func (d *DotGit) NewObject() (*ObjectWriter, error) { - d.cleanObjectList() - - return newObjectWriter(d.fs) -} - -// Objects returns a slice with the hashes of objects found under the -// .git/objects/ directory. -func (d *DotGit) Objects() ([]plumbing.Hash, error) { - if d.options.ExclusiveAccess { - err := d.genObjectList() - if err != nil { - return nil, err - } - - return d.objectList, nil - } - - var objects []plumbing.Hash - err := d.ForEachObjectHash(func(hash plumbing.Hash) error { - objects = append(objects, hash) - return nil - }) - if err != nil { - return nil, err - } - return objects, nil -} - -// ForEachObjectHash iterates over the hashes of objects found under the -// .git/objects/ directory and executes the provided function. -func (d *DotGit) ForEachObjectHash(fun func(plumbing.Hash) error) error { - if !d.options.ExclusiveAccess { - return d.forEachObjectHash(fun) - } - - err := d.genObjectList() - if err != nil { - return err - } - - for _, h := range d.objectList { - err := fun(h) - if err != nil { - return err - } - } - - return nil -} - -func (d *DotGit) forEachObjectHash(fun func(plumbing.Hash) error) error { - files, err := d.fs.ReadDir(objectsPath) - if err != nil { - if os.IsNotExist(err) { - return nil - } - - return err - } - - for _, f := range files { - if f.IsDir() && len(f.Name()) == 2 && isHex(f.Name()) { - base := f.Name() - d, err := d.fs.ReadDir(d.fs.Join(objectsPath, base)) - if err != nil { - return err - } - - for _, o := range d { - h := plumbing.NewHash(base + o.Name()) - if h.IsZero() { - // Ignore files with badly-formatted names. - continue - } - err = fun(h) - if err != nil { - return err - } - } - } - } - - return nil -} - -func (d *DotGit) cleanObjectList() { - d.objectMap = nil - d.objectList = nil -} - -func (d *DotGit) genObjectList() error { - if d.objectMap != nil { - return nil - } - - d.objectMap = make(map[plumbing.Hash]struct{}) - return d.forEachObjectHash(func(h plumbing.Hash) error { - d.objectList = append(d.objectList, h) - d.objectMap[h] = struct{}{} - - return nil - }) -} - -func (d *DotGit) hasObject(h plumbing.Hash) error { - if !d.options.ExclusiveAccess { - return nil - } - - err := d.genObjectList() - if err != nil { - return err - } - - _, ok := d.objectMap[h] - if !ok { - return plumbing.ErrObjectNotFound - } - - return nil -} - -func (d *DotGit) cleanPackList() { - d.packMap = nil - d.packList = nil -} - -func (d *DotGit) genPackList() error { - if d.packMap != nil { - return nil - } - - op, err := d.objectPacks() - if err != nil { - return err - } - - d.packMap = make(map[plumbing.Hash]struct{}) - d.packList = nil - - for _, h := range op { - d.packList = append(d.packList, h) - d.packMap[h] = struct{}{} - } - - return nil -} - -func (d *DotGit) hasPack(h plumbing.Hash) error { - if !d.options.ExclusiveAccess { - return nil - } - - err := d.genPackList() - if err != nil { - return err - } - - _, ok := d.packMap[h] - if !ok { - return ErrPackfileNotFound - } - - return nil -} - -func (d *DotGit) objectPath(h plumbing.Hash) string { - hash := h.String() - return d.fs.Join(objectsPath, hash[0:2], hash[2:40]) -} - -// incomingObjectPath is intended to add support for a git pre-receive hook -// to be written it adds support for go-git to find objects in an "incoming" -// directory, so that the library can be used to write a pre-receive hook -// that deals with the incoming objects. -// -// More on git hooks found here : https://git-scm.com/docs/githooks -// More on 'quarantine'/incoming directory here: -// https://git-scm.com/docs/git-receive-pack -func (d *DotGit) incomingObjectPath(h plumbing.Hash) string { - hString := h.String() - - if d.incomingDirName == "" { - return d.fs.Join(objectsPath, hString[0:2], hString[2:40]) - } - - return d.fs.Join(objectsPath, d.incomingDirName, hString[0:2], hString[2:40]) -} - -// hasIncomingObjects searches for an incoming directory and keeps its name -// so it doesn't have to be found each time an object is accessed. -func (d *DotGit) hasIncomingObjects() bool { - if !d.incomingChecked { - directoryContents, err := d.fs.ReadDir(objectsPath) - if err == nil { - for _, file := range directoryContents { - if strings.HasPrefix(file.Name(), "incoming-") && file.IsDir() { - d.incomingDirName = file.Name() - } - } - } - - d.incomingChecked = true - } - - return d.incomingDirName != "" -} - -// Object returns a fs.File pointing the object file, if exists -func (d *DotGit) Object(h plumbing.Hash) (billy.File, error) { - err := d.hasObject(h) - if err != nil { - return nil, err - } - - obj1, err1 := d.fs.Open(d.objectPath(h)) - if os.IsNotExist(err1) && d.hasIncomingObjects() { - obj2, err2 := d.fs.Open(d.incomingObjectPath(h)) - if err2 != nil { - return obj1, err1 - } - return obj2, err2 - } - return obj1, err1 -} - -// ObjectStat returns a os.FileInfo pointing the object file, if exists -func (d *DotGit) ObjectStat(h plumbing.Hash) (os.FileInfo, error) { - err := d.hasObject(h) - if err != nil { - return nil, err - } - - obj1, err1 := d.fs.Stat(d.objectPath(h)) - if os.IsNotExist(err1) && d.hasIncomingObjects() { - obj2, err2 := d.fs.Stat(d.incomingObjectPath(h)) - if err2 != nil { - return obj1, err1 - } - return obj2, err2 - } - return obj1, err1 -} - -// ObjectDelete removes the object file, if exists -func (d *DotGit) ObjectDelete(h plumbing.Hash) error { - d.cleanObjectList() - - err1 := d.fs.Remove(d.objectPath(h)) - if os.IsNotExist(err1) && d.hasIncomingObjects() { - err2 := d.fs.Remove(d.incomingObjectPath(h)) - if err2 != nil { - return err1 - } - return err2 - } - return err1 -} - -func (d *DotGit) readReferenceFrom(rd io.Reader, name string) (ref *plumbing.Reference, err error) { - b, err := stdioutil.ReadAll(rd) - if err != nil { - return nil, err - } - - line := strings.TrimSpace(string(b)) - return plumbing.NewReferenceFromStrings(name, line), nil -} - -func (d *DotGit) checkReferenceAndTruncate(f billy.File, old *plumbing.Reference) error { - if old == nil { - return nil - } - ref, err := d.readReferenceFrom(f, old.Name().String()) - if err != nil { - return err - } - if ref.Hash() != old.Hash() { - return storage.ErrReferenceHasChanged - } - _, err = f.Seek(0, io.SeekStart) - if err != nil { - return err - } - return f.Truncate(0) -} - -func (d *DotGit) SetRef(r, old *plumbing.Reference) error { - var content string - switch r.Type() { - case plumbing.SymbolicReference: - content = fmt.Sprintf("ref: %s\n", r.Target()) - case plumbing.HashReference: - content = fmt.Sprintln(r.Hash().String()) - } - - fileName := r.Name().String() - - return d.setRef(fileName, content, old) -} - -// Refs scans the git directory collecting references, which it returns. -// Symbolic references are resolved and included in the output. -func (d *DotGit) Refs() ([]*plumbing.Reference, error) { - var refs []*plumbing.Reference - var seen = make(map[plumbing.ReferenceName]bool) - if err := d.addRefsFromRefDir(&refs, seen); err != nil { - return nil, err - } - - if err := d.addRefsFromPackedRefs(&refs, seen); err != nil { - return nil, err - } - - if err := d.addRefFromHEAD(&refs); err != nil { - return nil, err - } - - return refs, nil -} - -// Ref returns the reference for a given reference name. -func (d *DotGit) Ref(name plumbing.ReferenceName) (*plumbing.Reference, error) { - ref, err := d.readReferenceFile(".", name.String()) - if err == nil { - return ref, nil - } - - return d.packedRef(name) -} - -func (d *DotGit) findPackedRefsInFile(f billy.File) ([]*plumbing.Reference, error) { - s := bufio.NewScanner(f) - var refs []*plumbing.Reference - for s.Scan() { - ref, err := d.processLine(s.Text()) - if err != nil { - return nil, err - } - - if ref != nil { - refs = append(refs, ref) - } - } - - return refs, s.Err() -} - -func (d *DotGit) findPackedRefs() (r []*plumbing.Reference, err error) { - f, err := d.fs.Open(packedRefsPath) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - - defer ioutil.CheckClose(f, &err) - return d.findPackedRefsInFile(f) -} - -func (d *DotGit) packedRef(name plumbing.ReferenceName) (*plumbing.Reference, error) { - refs, err := d.findPackedRefs() - if err != nil { - return nil, err - } - - for _, ref := range refs { - if ref.Name() == name { - return ref, nil - } - } - - return nil, plumbing.ErrReferenceNotFound -} - -// RemoveRef removes a reference by name. -func (d *DotGit) RemoveRef(name plumbing.ReferenceName) error { - path := d.fs.Join(".", name.String()) - _, err := d.fs.Stat(path) - if err == nil { - err = d.fs.Remove(path) - // Drop down to remove it from the packed refs file, too. - } - - if err != nil && !os.IsNotExist(err) { - return err - } - - return d.rewritePackedRefsWithoutRef(name) -} - -func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference, seen map[plumbing.ReferenceName]bool) (err error) { - packedRefs, err := d.findPackedRefs() - if err != nil { - return err - } - - for _, ref := range packedRefs { - if !seen[ref.Name()] { - *refs = append(*refs, ref) - seen[ref.Name()] = true - } - } - return nil -} - -func (d *DotGit) addRefsFromPackedRefsFile(refs *[]*plumbing.Reference, f billy.File, seen map[plumbing.ReferenceName]bool) (err error) { - packedRefs, err := d.findPackedRefsInFile(f) - if err != nil { - return err - } - - for _, ref := range packedRefs { - if !seen[ref.Name()] { - *refs = append(*refs, ref) - seen[ref.Name()] = true - } - } - return nil -} - -func (d *DotGit) openAndLockPackedRefs(doCreate bool) ( - pr billy.File, err error) { - var f billy.File - defer func() { - if err != nil && f != nil { - ioutil.CheckClose(f, &err) - } - }() - - // File mode is retrieved from a constant defined in the target specific - // files (dotgit_rewrite_packed_refs_*). Some modes are not available - // in all filesystems. - openFlags := d.openAndLockPackedRefsMode() - if doCreate { - openFlags |= os.O_CREATE - } - - // Keep trying to open and lock the file until we're sure the file - // didn't change between the open and the lock. - for { - f, err = d.fs.OpenFile(packedRefsPath, openFlags, 0600) - if err != nil { - if os.IsNotExist(err) && !doCreate { - return nil, nil - } - - return nil, err - } - fi, err := d.fs.Stat(packedRefsPath) - if err != nil { - return nil, err - } - mtime := fi.ModTime() - - err = f.Lock() - if err != nil { - return nil, err - } - - fi, err = d.fs.Stat(packedRefsPath) - if err != nil { - return nil, err - } - if mtime.Equal(fi.ModTime()) { - break - } - // The file has changed since we opened it. Close and retry. - err = f.Close() - if err != nil { - return nil, err - } - } - return f, nil -} - -func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err error) { - pr, err := d.openAndLockPackedRefs(false) - if err != nil { - return err - } - if pr == nil { - return nil - } - defer ioutil.CheckClose(pr, &err) - - // Creating the temp file in the same directory as the target file - // improves our chances for rename operation to be atomic. - tmp, err := d.fs.TempFile("", tmpPackedRefsPrefix) - if err != nil { - return err - } - tmpName := tmp.Name() - defer func() { - ioutil.CheckClose(tmp, &err) - _ = d.fs.Remove(tmpName) // don't check err, we might have renamed it - }() - - s := bufio.NewScanner(pr) - found := false - for s.Scan() { - line := s.Text() - ref, err := d.processLine(line) - if err != nil { - return err - } - - if ref != nil && ref.Name() == name { - found = true - continue - } - - if _, err := fmt.Fprintln(tmp, line); err != nil { - return err - } - } - - if err := s.Err(); err != nil { - return err - } - - if !found { - return nil - } - - return d.rewritePackedRefsWhileLocked(tmp, pr) -} - -// process lines from a packed-refs file -func (d *DotGit) processLine(line string) (*plumbing.Reference, error) { - if len(line) == 0 { - return nil, nil - } - - switch line[0] { - case '#': // comment - ignore - return nil, nil - case '^': // annotated tag commit of the previous line - ignore - return nil, nil - default: - ws := strings.Split(line, " ") // hash then ref - if len(ws) != 2 { - return nil, ErrPackedRefsBadFormat - } - - return plumbing.NewReferenceFromStrings(ws[1], ws[0]), nil - } -} - -func (d *DotGit) addRefsFromRefDir(refs *[]*plumbing.Reference, seen map[plumbing.ReferenceName]bool) error { - return d.walkReferencesTree(refs, []string{refsPath}, seen) -} - -func (d *DotGit) walkReferencesTree(refs *[]*plumbing.Reference, relPath []string, seen map[plumbing.ReferenceName]bool) error { - files, err := d.fs.ReadDir(d.fs.Join(relPath...)) - if err != nil { - if os.IsNotExist(err) { - return nil - } - - return err - } - - for _, f := range files { - newRelPath := append(append([]string(nil), relPath...), f.Name()) - if f.IsDir() { - if err = d.walkReferencesTree(refs, newRelPath, seen); err != nil { - return err - } - - continue - } - - ref, err := d.readReferenceFile(".", strings.Join(newRelPath, "/")) - if err != nil { - return err - } - - if ref != nil && !seen[ref.Name()] { - *refs = append(*refs, ref) - seen[ref.Name()] = true - } - } - - return nil -} - -func (d *DotGit) addRefFromHEAD(refs *[]*plumbing.Reference) error { - ref, err := d.readReferenceFile(".", "HEAD") - if err != nil { - if os.IsNotExist(err) { - return nil - } - - return err - } - - *refs = append(*refs, ref) - return nil -} - -func (d *DotGit) readReferenceFile(path, name string) (ref *plumbing.Reference, err error) { - path = d.fs.Join(path, d.fs.Join(strings.Split(name, "/")...)) - f, err := d.fs.Open(path) - if err != nil { - return nil, err - } - defer ioutil.CheckClose(f, &err) - - return d.readReferenceFrom(f, name) -} - -func (d *DotGit) CountLooseRefs() (int, error) { - var refs []*plumbing.Reference - var seen = make(map[plumbing.ReferenceName]bool) - if err := d.addRefsFromRefDir(&refs, seen); err != nil { - return 0, err - } - - return len(refs), nil -} - -// PackRefs packs all loose refs into the packed-refs file. -// -// This implementation only works under the assumption that the view -// of the file system won't be updated during this operation. This -// strategy would not work on a general file system though, without -// locking each loose reference and checking it again before deleting -// the file, because otherwise an updated reference could sneak in and -// then be deleted by the packed-refs process. Alternatively, every -// ref update could also lock packed-refs, so only one lock is -// required during ref-packing. But that would worsen performance in -// the common case. -// -// TODO: add an "all" boolean like the `git pack-refs --all` flag. -// When `all` is false, it would only pack refs that have already been -// packed, plus all tags. -func (d *DotGit) PackRefs() (err error) { - // Lock packed-refs, and create it if it doesn't exist yet. - f, err := d.openAndLockPackedRefs(true) - if err != nil { - return err - } - defer ioutil.CheckClose(f, &err) - - // Gather all refs using addRefsFromRefDir and addRefsFromPackedRefs. - var refs []*plumbing.Reference - seen := make(map[plumbing.ReferenceName]bool) - if err = d.addRefsFromRefDir(&refs, seen); err != nil { - return err - } - if len(refs) == 0 { - // Nothing to do! - return nil - } - numLooseRefs := len(refs) - if err = d.addRefsFromPackedRefsFile(&refs, f, seen); err != nil { - return err - } - - // Write them all to a new temp packed-refs file. - tmp, err := d.fs.TempFile("", tmpPackedRefsPrefix) - if err != nil { - return err - } - tmpName := tmp.Name() - defer func() { - ioutil.CheckClose(tmp, &err) - _ = d.fs.Remove(tmpName) // don't check err, we might have renamed it - }() - - w := bufio.NewWriter(tmp) - for _, ref := range refs { - _, err = w.WriteString(ref.String() + "\n") - if err != nil { - return err - } - } - err = w.Flush() - if err != nil { - return err - } - - // Rename the temp packed-refs file. - err = d.rewritePackedRefsWhileLocked(tmp, f) - if err != nil { - return err - } - - // Delete all the loose refs, while still holding the packed-refs - // lock. - for _, ref := range refs[:numLooseRefs] { - path := d.fs.Join(".", ref.Name().String()) - err = d.fs.Remove(path) - if err != nil && !os.IsNotExist(err) { - return err - } - } - - return nil -} - -// Module return a billy.Filesystem pointing to the module folder -func (d *DotGit) Module(name string) (billy.Filesystem, error) { - return d.fs.Chroot(d.fs.Join(modulePath, name)) -} - -// Alternates returns DotGit(s) based off paths in objects/info/alternates if -// available. This can be used to checks if it's a shared repository. -func (d *DotGit) Alternates() ([]*DotGit, error) { - altpath := d.fs.Join("objects", "info", "alternates") - f, err := d.fs.Open(altpath) - if err != nil { - return nil, err - } - defer f.Close() - - var alternates []*DotGit - - // Read alternate paths line-by-line and create DotGit objects. - scanner := bufio.NewScanner(f) - for scanner.Scan() { - path := scanner.Text() - if !filepath.IsAbs(path) { - // For relative paths, we can perform an internal conversion to - // slash so that they work cross-platform. - slashPath := filepath.ToSlash(path) - // If the path is not absolute, it must be relative to object - // database (.git/objects/info). - // https://www.kernel.org/pub/software/scm/git/docs/gitrepository-layout.html - // Hence, derive a path relative to DotGit's root. - // "../../../reponame/.git/" -> "../../reponame/.git" - // Remove the first ../ - relpath := filepath.Join(strings.Split(slashPath, "/")[1:]...) - normalPath := filepath.FromSlash(relpath) - path = filepath.Join(d.fs.Root(), normalPath) - } - fs := osfs.New(filepath.Dir(path)) - alternates = append(alternates, New(fs)) - } - - if err = scanner.Err(); err != nil { - return nil, err - } - - return alternates, nil -} - -// Fs returns the underlying filesystem of the DotGit folder. -func (d *DotGit) Fs() billy.Filesystem { - return d.fs -} - -func isHex(s string) bool { - for _, b := range []byte(s) { - if isNum(b) { - continue - } - if isHexAlpha(b) { - continue - } - - return false - } - - return true -} - -func isNum(b byte) bool { - return b >= '0' && b <= '9' -} - -func isHexAlpha(b byte) bool { - return b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F' -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go deleted file mode 100644 index 7f1c02c1..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go +++ /dev/null @@ -1,81 +0,0 @@ -package dotgit - -import ( - "io" - "os" - "runtime" - - "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -func (d *DotGit) openAndLockPackedRefsMode() int { - if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) { - return os.O_RDWR - } - - return os.O_RDONLY -} - -func (d *DotGit) rewritePackedRefsWhileLocked( - tmp billy.File, pr billy.File) error { - // Try plain rename. If we aren't using the bare Windows filesystem as the - // storage layer, we might be able to get away with a rename over a locked - // file. - err := d.fs.Rename(tmp.Name(), pr.Name()) - if err == nil { - return nil - } - - // If we are in a filesystem that does not support rename (e.g. sivafs) - // a full copy is done. - if err == billy.ErrNotSupported { - return d.copyNewFile(tmp, pr) - } - - if runtime.GOOS != "windows" { - return err - } - - // Otherwise, Windows doesn't let us rename over a locked file, so - // we have to do a straight copy. Unfortunately this could result - // in a partially-written file if the process fails before the - // copy completes. - return d.copyToExistingFile(tmp, pr) -} - -func (d *DotGit) copyToExistingFile(tmp, pr billy.File) error { - _, err := pr.Seek(0, io.SeekStart) - if err != nil { - return err - } - err = pr.Truncate(0) - if err != nil { - return err - } - _, err = tmp.Seek(0, io.SeekStart) - if err != nil { - return err - } - _, err = io.Copy(pr, tmp) - - return err -} - -func (d *DotGit) copyNewFile(tmp billy.File, pr billy.File) (err error) { - prWrite, err := d.fs.Create(pr.Name()) - if err != nil { - return err - } - - defer ioutil.CheckClose(prWrite, &err) - - _, err = tmp.Seek(0, io.SeekStart) - if err != nil { - return err - } - - _, err = io.Copy(prWrite, tmp) - - return err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go deleted file mode 100644 index 9da2f31e..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/dotgit_setref.go +++ /dev/null @@ -1,90 +0,0 @@ -package dotgit - -import ( - "fmt" - "os" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/utils/ioutil" - - "gopkg.in/src-d/go-billy.v4" -) - -func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err error) { - if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) { - return d.setRefRwfs(fileName, content, old) - } - - return d.setRefNorwfs(fileName, content, old) -} - -func (d *DotGit) setRefRwfs(fileName, content string, old *plumbing.Reference) (err error) { - // If we are not checking an old ref, just truncate the file. - mode := os.O_RDWR | os.O_CREATE - if old == nil { - mode |= os.O_TRUNC - } - - f, err := d.fs.OpenFile(fileName, mode, 0666) - if err != nil { - return err - } - - defer ioutil.CheckClose(f, &err) - - // Lock is unlocked by the deferred Close above. This is because Unlock - // does not imply a fsync and thus there would be a race between - // Unlock+Close and other concurrent writers. Adding Sync to go-billy - // could work, but this is better (and avoids superfluous syncs). - err = f.Lock() - if err != nil { - return err - } - - // this is a no-op to call even when old is nil. - err = d.checkReferenceAndTruncate(f, old) - if err != nil { - return err - } - - _, err = f.Write([]byte(content)) - return err -} - -// There are some filesystems that don't support opening files in RDWD mode. -// In these filesystems the standard SetRef function can not be used as it -// reads the reference file to check that it's not modified before updating it. -// -// This version of the function writes the reference without extra checks -// making it compatible with these simple filesystems. This is usually not -// a problem as they should be accessed by only one process at a time. -func (d *DotGit) setRefNorwfs(fileName, content string, old *plumbing.Reference) error { - _, err := d.fs.Stat(fileName) - if err == nil && old != nil { - fRead, err := d.fs.Open(fileName) - if err != nil { - return err - } - - ref, err := d.readReferenceFrom(fRead, old.Name().String()) - fRead.Close() - - if err != nil { - return err - } - - if ref.Hash() != old.Hash() { - return fmt.Errorf("reference has changed concurrently") - } - } - - f, err := d.fs.Create(fileName) - if err != nil { - return err - } - - defer f.Close() - - _, err = f.Write([]byte(content)) - return err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/writers.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/writers.go deleted file mode 100644 index 93d2d8cc..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit/writers.go +++ /dev/null @@ -1,284 +0,0 @@ -package dotgit - -import ( - "fmt" - "io" - "sync/atomic" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile" - "gopkg.in/src-d/go-git.v4/plumbing/format/objfile" - "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" - - "gopkg.in/src-d/go-billy.v4" -) - -// PackWriter is a io.Writer that generates the packfile index simultaneously, -// a packfile.Decoder is used with a file reader to read the file being written -// this operation is synchronized with the write operations. -// The packfile is written in a temp file, when Close is called this file -// is renamed/moved (depends on the Filesystem implementation) to the final -// location, if the PackWriter is not used, nothing is written -type PackWriter struct { - Notify func(plumbing.Hash, *idxfile.Writer) - - fs billy.Filesystem - fr, fw billy.File - synced *syncedReader - checksum plumbing.Hash - parser *packfile.Parser - writer *idxfile.Writer - result chan error -} - -func newPackWrite(fs billy.Filesystem) (*PackWriter, error) { - fw, err := fs.TempFile(fs.Join(objectsPath, packPath), "tmp_pack_") - if err != nil { - return nil, err - } - - fr, err := fs.Open(fw.Name()) - if err != nil { - return nil, err - } - - writer := &PackWriter{ - fs: fs, - fw: fw, - fr: fr, - synced: newSyncedReader(fw, fr), - result: make(chan error), - } - - go writer.buildIndex() - return writer, nil -} - -func (w *PackWriter) buildIndex() { - s := packfile.NewScanner(w.synced) - w.writer = new(idxfile.Writer) - var err error - w.parser, err = packfile.NewParser(s, w.writer) - if err != nil { - w.result <- err - return - } - - checksum, err := w.parser.Parse() - if err != nil { - w.result <- err - return - } - - w.checksum = checksum - w.result <- err -} - -// waitBuildIndex waits until buildIndex function finishes, this can terminate -// with a packfile.ErrEmptyPackfile, this means that nothing was written so we -// ignore the error -func (w *PackWriter) waitBuildIndex() error { - err := <-w.result - if err == packfile.ErrEmptyPackfile { - return nil - } - - return err -} - -func (w *PackWriter) Write(p []byte) (int, error) { - return w.synced.Write(p) -} - -// Close closes all the file descriptors and save the final packfile, if nothing -// was written, the tempfiles are deleted without writing a packfile. -func (w *PackWriter) Close() error { - defer func() { - if w.Notify != nil && w.writer != nil && w.writer.Finished() { - w.Notify(w.checksum, w.writer) - } - - close(w.result) - }() - - if err := w.synced.Close(); err != nil { - return err - } - - if err := w.waitBuildIndex(); err != nil { - return err - } - - if err := w.fr.Close(); err != nil { - return err - } - - if err := w.fw.Close(); err != nil { - return err - } - - if w.writer == nil || !w.writer.Finished() { - return w.clean() - } - - return w.save() -} - -func (w *PackWriter) clean() error { - return w.fs.Remove(w.fw.Name()) -} - -func (w *PackWriter) save() error { - base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.checksum)) - idx, err := w.fs.Create(fmt.Sprintf("%s.idx", base)) - if err != nil { - return err - } - - if err := w.encodeIdx(idx); err != nil { - return err - } - - if err := idx.Close(); err != nil { - return err - } - - return w.fs.Rename(w.fw.Name(), fmt.Sprintf("%s.pack", base)) -} - -func (w *PackWriter) encodeIdx(writer io.Writer) error { - idx, err := w.writer.Index() - if err != nil { - return err - } - - e := idxfile.NewEncoder(writer) - _, err = e.Encode(idx) - return err -} - -type syncedReader struct { - w io.Writer - r io.ReadSeeker - - blocked, done uint32 - written, read uint64 - news chan bool -} - -func newSyncedReader(w io.Writer, r io.ReadSeeker) *syncedReader { - return &syncedReader{ - w: w, - r: r, - news: make(chan bool), - } -} - -func (s *syncedReader) Write(p []byte) (n int, err error) { - defer func() { - written := atomic.AddUint64(&s.written, uint64(n)) - read := atomic.LoadUint64(&s.read) - if written > read { - s.wake() - } - }() - - n, err = s.w.Write(p) - return -} - -func (s *syncedReader) Read(p []byte) (n int, err error) { - defer func() { atomic.AddUint64(&s.read, uint64(n)) }() - - for { - s.sleep() - n, err = s.r.Read(p) - if err == io.EOF && !s.isDone() && n == 0 { - continue - } - - break - } - - return -} - -func (s *syncedReader) isDone() bool { - return atomic.LoadUint32(&s.done) == 1 -} - -func (s *syncedReader) isBlocked() bool { - return atomic.LoadUint32(&s.blocked) == 1 -} - -func (s *syncedReader) wake() { - if s.isBlocked() { - atomic.StoreUint32(&s.blocked, 0) - s.news <- true - } -} - -func (s *syncedReader) sleep() { - read := atomic.LoadUint64(&s.read) - written := atomic.LoadUint64(&s.written) - if read >= written { - atomic.StoreUint32(&s.blocked, 1) - <-s.news - } - -} - -func (s *syncedReader) Seek(offset int64, whence int) (int64, error) { - if whence == io.SeekCurrent { - return s.r.Seek(offset, whence) - } - - p, err := s.r.Seek(offset, whence) - atomic.StoreUint64(&s.read, uint64(p)) - - return p, err -} - -func (s *syncedReader) Close() error { - atomic.StoreUint32(&s.done, 1) - close(s.news) - return nil -} - -type ObjectWriter struct { - objfile.Writer - fs billy.Filesystem - f billy.File -} - -func newObjectWriter(fs billy.Filesystem) (*ObjectWriter, error) { - f, err := fs.TempFile(fs.Join(objectsPath, packPath), "tmp_obj_") - if err != nil { - return nil, err - } - - return &ObjectWriter{ - Writer: (*objfile.NewWriter(f)), - fs: fs, - f: f, - }, nil -} - -func (w *ObjectWriter) Close() error { - if err := w.Writer.Close(); err != nil { - return err - } - - if err := w.f.Close(); err != nil { - return err - } - - return w.save() -} - -func (w *ObjectWriter) save() error { - hash := w.Hash().String() - file := w.fs.Join(objectsPath, hash[0:2], hash[2:40]) - - return w.fs.Rename(w.f.Name(), file) -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/index.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/index.go deleted file mode 100644 index be800eff..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/index.go +++ /dev/null @@ -1,54 +0,0 @@ -package filesystem - -import ( - "bufio" - "os" - - "gopkg.in/src-d/go-git.v4/plumbing/format/index" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -type IndexStorage struct { - dir *dotgit.DotGit -} - -func (s *IndexStorage) SetIndex(idx *index.Index) (err error) { - f, err := s.dir.IndexWriter() - if err != nil { - return err - } - - defer ioutil.CheckClose(f, &err) - bw := bufio.NewWriter(f) - defer func() { - if e := bw.Flush(); err == nil && e != nil { - err = e - } - }() - - e := index.NewEncoder(bw) - err = e.Encode(idx) - return err -} - -func (s *IndexStorage) Index() (i *index.Index, err error) { - idx := &index.Index{ - Version: 2, - } - - f, err := s.dir.Index() - if err != nil { - if os.IsNotExist(err) { - return idx, nil - } - - return nil, err - } - - defer ioutil.CheckClose(f, &err) - - d := index.NewDecoder(bufio.NewReader(f)) - err = d.Decode(idx) - return idx, err -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/module.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/module.go deleted file mode 100644 index 92722067..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/module.go +++ /dev/null @@ -1,20 +0,0 @@ -package filesystem - -import ( - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/storage" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" -) - -type ModuleStorage struct { - dir *dotgit.DotGit -} - -func (s *ModuleStorage) Module(name string) (storage.Storer, error) { - fs, err := s.dir.Module(name) - if err != nil { - return nil, err - } - - return NewStorage(fs, cache.NewObjectLRUDefault()), nil -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go deleted file mode 100644 index ad5d8d00..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/object.go +++ /dev/null @@ -1,815 +0,0 @@ -package filesystem - -import ( - "io" - "os" - "time" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/plumbing/format/idxfile" - "gopkg.in/src-d/go-git.v4/plumbing/format/objfile" - "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" - "gopkg.in/src-d/go-git.v4/utils/ioutil" - - "gopkg.in/src-d/go-billy.v4" -) - -type ObjectStorage struct { - options Options - - // objectCache is an object cache uses to cache delta's bases and also recently - // loaded loose objects - objectCache cache.Object - - dir *dotgit.DotGit - index map[plumbing.Hash]idxfile.Index - - packList []plumbing.Hash - packListIdx int - packfiles map[plumbing.Hash]*packfile.Packfile -} - -// NewObjectStorage creates a new ObjectStorage with the given .git directory and cache. -func NewObjectStorage(dir *dotgit.DotGit, objectCache cache.Object) *ObjectStorage { - return NewObjectStorageWithOptions(dir, objectCache, Options{}) -} - -// NewObjectStorageWithOptions creates a new ObjectStorage with the given .git directory, cache and extra options -func NewObjectStorageWithOptions(dir *dotgit.DotGit, objectCache cache.Object, ops Options) *ObjectStorage { - return &ObjectStorage{ - options: ops, - objectCache: objectCache, - dir: dir, - } -} - -func (s *ObjectStorage) requireIndex() error { - if s.index != nil { - return nil - } - - s.index = make(map[plumbing.Hash]idxfile.Index) - packs, err := s.dir.ObjectPacks() - if err != nil { - return err - } - - for _, h := range packs { - if err := s.loadIdxFile(h); err != nil { - return err - } - } - - return nil -} - -// Reindex indexes again all packfiles. Useful if git changed packfiles externally -func (s *ObjectStorage) Reindex() { - s.index = nil -} - -func (s *ObjectStorage) loadIdxFile(h plumbing.Hash) (err error) { - f, err := s.dir.ObjectPackIdx(h) - if err != nil { - return err - } - - defer ioutil.CheckClose(f, &err) - - idxf := idxfile.NewMemoryIndex() - d := idxfile.NewDecoder(f) - if err = d.Decode(idxf); err != nil { - return err - } - - s.index[h] = idxf - return err -} - -func (s *ObjectStorage) NewEncodedObject() plumbing.EncodedObject { - return &plumbing.MemoryObject{} -} - -func (s *ObjectStorage) PackfileWriter() (io.WriteCloser, error) { - if err := s.requireIndex(); err != nil { - return nil, err - } - - w, err := s.dir.NewObjectPack() - if err != nil { - return nil, err - } - - w.Notify = func(h plumbing.Hash, writer *idxfile.Writer) { - index, err := writer.Index() - if err == nil { - s.index[h] = index - } - } - - return w, nil -} - -// SetEncodedObject adds a new object to the storage. -func (s *ObjectStorage) SetEncodedObject(o plumbing.EncodedObject) (h plumbing.Hash, err error) { - if o.Type() == plumbing.OFSDeltaObject || o.Type() == plumbing.REFDeltaObject { - return plumbing.ZeroHash, plumbing.ErrInvalidType - } - - ow, err := s.dir.NewObject() - if err != nil { - return plumbing.ZeroHash, err - } - - defer ioutil.CheckClose(ow, &err) - - or, err := o.Reader() - if err != nil { - return plumbing.ZeroHash, err - } - - defer ioutil.CheckClose(or, &err) - - if err = ow.WriteHeader(o.Type(), o.Size()); err != nil { - return plumbing.ZeroHash, err - } - - if _, err = io.Copy(ow, or); err != nil { - return plumbing.ZeroHash, err - } - - return o.Hash(), err -} - -// HasEncodedObject returns nil if the object exists, without actually -// reading the object data from storage. -func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) { - // Check unpacked objects - f, err := s.dir.Object(h) - if err != nil { - if !os.IsNotExist(err) { - return err - } - // Fall through to check packed objects. - } else { - defer ioutil.CheckClose(f, &err) - return nil - } - - // Check packed objects. - if err := s.requireIndex(); err != nil { - return err - } - _, _, offset := s.findObjectInPackfile(h) - if offset == -1 { - return plumbing.ErrObjectNotFound - } - return nil -} - -func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) ( - size int64, err error) { - f, err := s.dir.Object(h) - if err != nil { - if os.IsNotExist(err) { - return 0, plumbing.ErrObjectNotFound - } - - return 0, err - } - - r, err := objfile.NewReader(f) - if err != nil { - return 0, err - } - defer ioutil.CheckClose(r, &err) - - _, size, err = r.Header() - return size, err -} - -func (s *ObjectStorage) packfile(idx idxfile.Index, pack plumbing.Hash) (*packfile.Packfile, error) { - if p := s.packfileFromCache(pack); p != nil { - return p, nil - } - - f, err := s.dir.ObjectPack(pack) - if err != nil { - return nil, err - } - - var p *packfile.Packfile - if s.objectCache != nil { - p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache) - } else { - p = packfile.NewPackfile(idx, s.dir.Fs(), f) - } - - return p, s.storePackfileInCache(pack, p) -} - -func (s *ObjectStorage) packfileFromCache(hash plumbing.Hash) *packfile.Packfile { - if s.packfiles == nil { - if s.options.KeepDescriptors { - s.packfiles = make(map[plumbing.Hash]*packfile.Packfile) - } else if s.options.MaxOpenDescriptors > 0 { - s.packList = make([]plumbing.Hash, s.options.MaxOpenDescriptors) - s.packfiles = make(map[plumbing.Hash]*packfile.Packfile, s.options.MaxOpenDescriptors) - } - } - - return s.packfiles[hash] -} - -func (s *ObjectStorage) storePackfileInCache(hash plumbing.Hash, p *packfile.Packfile) error { - if s.options.KeepDescriptors { - s.packfiles[hash] = p - return nil - } - - if s.options.MaxOpenDescriptors <= 0 { - return nil - } - - // start over as the limit of packList is hit - if s.packListIdx >= len(s.packList) { - s.packListIdx = 0 - } - - // close the existing packfile if open - if next := s.packList[s.packListIdx]; !next.IsZero() { - open := s.packfiles[next] - delete(s.packfiles, next) - if open != nil { - if err := open.Close(); err != nil { - return err - } - } - } - - // cache newly open packfile - s.packList[s.packListIdx] = hash - s.packfiles[hash] = p - s.packListIdx++ - - return nil -} - -func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) ( - size int64, err error) { - if err := s.requireIndex(); err != nil { - return 0, err - } - - pack, _, offset := s.findObjectInPackfile(h) - if offset == -1 { - return 0, plumbing.ErrObjectNotFound - } - - idx := s.index[pack] - hash, err := idx.FindHash(offset) - if err == nil { - obj, ok := s.objectCache.Get(hash) - if ok { - return obj.Size(), nil - } - } else if err != nil && err != plumbing.ErrObjectNotFound { - return 0, err - } - - p, err := s.packfile(idx, pack) - if err != nil { - return 0, err - } - - if !s.options.KeepDescriptors && s.options.MaxOpenDescriptors == 0 { - defer ioutil.CheckClose(p, &err) - } - - return p.GetSizeByOffset(offset) -} - -// EncodedObjectSize returns the plaintext size of the given object, -// without actually reading the full object data from storage. -func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) ( - size int64, err error) { - size, err = s.encodedObjectSizeFromUnpacked(h) - if err != nil && err != plumbing.ErrObjectNotFound { - return 0, err - } else if err == nil { - return size, nil - } - - return s.encodedObjectSizeFromPackfile(h) -} - -// EncodedObject returns the object with the given hash, by searching for it in -// the packfile and the git object directories. -func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) { - var obj plumbing.EncodedObject - var err error - - if s.index != nil { - obj, err = s.getFromPackfile(h, false) - if err == plumbing.ErrObjectNotFound { - obj, err = s.getFromUnpacked(h) - } - } else { - obj, err = s.getFromUnpacked(h) - if err == plumbing.ErrObjectNotFound { - obj, err = s.getFromPackfile(h, false) - } - } - - // If the error is still object not found, check if it's a shared object - // repository. - if err == plumbing.ErrObjectNotFound { - dotgits, e := s.dir.Alternates() - if e == nil { - // Create a new object storage with the DotGit(s) and check for the - // required hash object. Skip when not found. - for _, dg := range dotgits { - o := NewObjectStorage(dg, s.objectCache) - enobj, enerr := o.EncodedObject(t, h) - if enerr != nil { - continue - } - return enobj, nil - } - } - } - - if err != nil { - return nil, err - } - - if plumbing.AnyObject != t && obj.Type() != t { - return nil, plumbing.ErrObjectNotFound - } - - return obj, nil -} - -// DeltaObject returns the object with the given hash, by searching for -// it in the packfile and the git object directories. -func (s *ObjectStorage) DeltaObject(t plumbing.ObjectType, - h plumbing.Hash) (plumbing.EncodedObject, error) { - obj, err := s.getFromUnpacked(h) - if err == plumbing.ErrObjectNotFound { - obj, err = s.getFromPackfile(h, true) - } - - if err != nil { - return nil, err - } - - if plumbing.AnyObject != t && obj.Type() != t { - return nil, plumbing.ErrObjectNotFound - } - - return obj, nil -} - -func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedObject, err error) { - f, err := s.dir.Object(h) - if err != nil { - if os.IsNotExist(err) { - return nil, plumbing.ErrObjectNotFound - } - - return nil, err - } - defer ioutil.CheckClose(f, &err) - - if cacheObj, found := s.objectCache.Get(h); found { - return cacheObj, nil - } - - obj = s.NewEncodedObject() - r, err := objfile.NewReader(f) - if err != nil { - return nil, err - } - - defer ioutil.CheckClose(r, &err) - - t, size, err := r.Header() - if err != nil { - return nil, err - } - - obj.SetType(t) - obj.SetSize(size) - w, err := obj.Writer() - if err != nil { - return nil, err - } - - s.objectCache.Put(obj) - - _, err = io.Copy(w, r) - return obj, err -} - -// Get returns the object with the given hash, by searching for it in -// the packfile. -func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) ( - plumbing.EncodedObject, error) { - - if err := s.requireIndex(); err != nil { - return nil, err - } - - pack, hash, offset := s.findObjectInPackfile(h) - if offset == -1 { - return nil, plumbing.ErrObjectNotFound - } - - idx := s.index[pack] - p, err := s.packfile(idx, pack) - if err != nil { - return nil, err - } - - if !s.options.KeepDescriptors && s.options.MaxOpenDescriptors == 0 { - defer ioutil.CheckClose(p, &err) - } - - if canBeDelta { - return s.decodeDeltaObjectAt(p, offset, hash) - } - - return s.decodeObjectAt(p, offset) -} - -func (s *ObjectStorage) decodeObjectAt( - p *packfile.Packfile, - offset int64, -) (plumbing.EncodedObject, error) { - hash, err := p.FindHash(offset) - if err == nil { - obj, ok := s.objectCache.Get(hash) - if ok { - return obj, nil - } - } - - if err != nil && err != plumbing.ErrObjectNotFound { - return nil, err - } - - return p.GetByOffset(offset) -} - -func (s *ObjectStorage) decodeDeltaObjectAt( - p *packfile.Packfile, - offset int64, - hash plumbing.Hash, -) (plumbing.EncodedObject, error) { - scan := p.Scanner() - header, err := scan.SeekObjectHeader(offset) - if err != nil { - return nil, err - } - - var ( - base plumbing.Hash - ) - - switch header.Type { - case plumbing.REFDeltaObject: - base = header.Reference - case plumbing.OFSDeltaObject: - base, err = p.FindHash(header.OffsetReference) - if err != nil { - return nil, err - } - default: - return s.decodeObjectAt(p, offset) - } - - obj := &plumbing.MemoryObject{} - obj.SetType(header.Type) - w, err := obj.Writer() - if err != nil { - return nil, err - } - - if _, _, err := scan.NextObject(w); err != nil { - return nil, err - } - - return newDeltaObject(obj, hash, base, header.Length), nil -} - -func (s *ObjectStorage) findObjectInPackfile(h plumbing.Hash) (plumbing.Hash, plumbing.Hash, int64) { - for packfile, index := range s.index { - offset, err := index.FindOffset(h) - if err == nil { - return packfile, h, offset - } - } - - return plumbing.ZeroHash, plumbing.ZeroHash, -1 -} - -// IterEncodedObjects returns an iterator for all the objects in the packfile -// with the given type. -func (s *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) { - objects, err := s.dir.Objects() - if err != nil { - return nil, err - } - - seen := make(map[plumbing.Hash]struct{}) - var iters []storer.EncodedObjectIter - if len(objects) != 0 { - iters = append(iters, &objectsIter{s: s, t: t, h: objects}) - seen = hashListAsMap(objects) - } - - packi, err := s.buildPackfileIters(t, seen) - if err != nil { - return nil, err - } - - iters = append(iters, packi) - return storer.NewMultiEncodedObjectIter(iters), nil -} - -func (s *ObjectStorage) buildPackfileIters( - t plumbing.ObjectType, - seen map[plumbing.Hash]struct{}, -) (storer.EncodedObjectIter, error) { - if err := s.requireIndex(); err != nil { - return nil, err - } - - packs, err := s.dir.ObjectPacks() - if err != nil { - return nil, err - } - return &lazyPackfilesIter{ - hashes: packs, - open: func(h plumbing.Hash) (storer.EncodedObjectIter, error) { - pack, err := s.dir.ObjectPack(h) - if err != nil { - return nil, err - } - return newPackfileIter( - s.dir.Fs(), pack, t, seen, s.index[h], - s.objectCache, s.options.KeepDescriptors, - ) - }, - }, nil -} - -// Close closes all opened files. -func (s *ObjectStorage) Close() error { - var firstError error - if s.options.KeepDescriptors || s.options.MaxOpenDescriptors > 0 { - for _, packfile := range s.packfiles { - err := packfile.Close() - if firstError == nil && err != nil { - firstError = err - } - } - } - - s.packfiles = nil - s.dir.Close() - - return firstError -} - -type lazyPackfilesIter struct { - hashes []plumbing.Hash - open func(h plumbing.Hash) (storer.EncodedObjectIter, error) - cur storer.EncodedObjectIter -} - -func (it *lazyPackfilesIter) Next() (plumbing.EncodedObject, error) { - for { - if it.cur == nil { - if len(it.hashes) == 0 { - return nil, io.EOF - } - h := it.hashes[0] - it.hashes = it.hashes[1:] - - sub, err := it.open(h) - if err == io.EOF { - continue - } else if err != nil { - return nil, err - } - it.cur = sub - } - ob, err := it.cur.Next() - if err == io.EOF { - it.cur.Close() - it.cur = nil - continue - } else if err != nil { - return nil, err - } - return ob, nil - } -} - -func (it *lazyPackfilesIter) ForEach(cb func(plumbing.EncodedObject) error) error { - return storer.ForEachIterator(it, cb) -} - -func (it *lazyPackfilesIter) Close() { - if it.cur != nil { - it.cur.Close() - it.cur = nil - } - it.hashes = nil -} - -type packfileIter struct { - pack billy.File - iter storer.EncodedObjectIter - seen map[plumbing.Hash]struct{} - - // tells whether the pack file should be left open after iteration or not - keepPack bool -} - -// NewPackfileIter returns a new EncodedObjectIter for the provided packfile -// and object type. Packfile and index file will be closed after they're -// used. If keepPack is true the packfile won't be closed after the iteration -// finished. -func NewPackfileIter( - fs billy.Filesystem, - f billy.File, - idxFile billy.File, - t plumbing.ObjectType, - keepPack bool, -) (storer.EncodedObjectIter, error) { - idx := idxfile.NewMemoryIndex() - if err := idxfile.NewDecoder(idxFile).Decode(idx); err != nil { - return nil, err - } - - if err := idxFile.Close(); err != nil { - return nil, err - } - - seen := make(map[plumbing.Hash]struct{}) - return newPackfileIter(fs, f, t, seen, idx, nil, keepPack) -} - -func newPackfileIter( - fs billy.Filesystem, - f billy.File, - t plumbing.ObjectType, - seen map[plumbing.Hash]struct{}, - index idxfile.Index, - cache cache.Object, - keepPack bool, -) (storer.EncodedObjectIter, error) { - var p *packfile.Packfile - if cache != nil { - p = packfile.NewPackfileWithCache(index, fs, f, cache) - } else { - p = packfile.NewPackfile(index, fs, f) - } - - iter, err := p.GetByType(t) - if err != nil { - return nil, err - } - - return &packfileIter{ - pack: f, - iter: iter, - seen: seen, - keepPack: keepPack, - }, nil -} - -func (iter *packfileIter) Next() (plumbing.EncodedObject, error) { - for { - obj, err := iter.iter.Next() - if err != nil { - return nil, err - } - - if _, ok := iter.seen[obj.Hash()]; ok { - continue - } - - return obj, nil - } -} - -func (iter *packfileIter) ForEach(cb func(plumbing.EncodedObject) error) error { - for { - o, err := iter.Next() - if err != nil { - if err == io.EOF { - iter.Close() - return nil - } - return err - } - - if err := cb(o); err != nil { - return err - } - } -} - -func (iter *packfileIter) Close() { - iter.iter.Close() - if !iter.keepPack { - _ = iter.pack.Close() - } -} - -type objectsIter struct { - s *ObjectStorage - t plumbing.ObjectType - h []plumbing.Hash -} - -func (iter *objectsIter) Next() (plumbing.EncodedObject, error) { - if len(iter.h) == 0 { - return nil, io.EOF - } - - obj, err := iter.s.getFromUnpacked(iter.h[0]) - iter.h = iter.h[1:] - - if err != nil { - return nil, err - } - - if iter.t != plumbing.AnyObject && iter.t != obj.Type() { - return iter.Next() - } - - return obj, err -} - -func (iter *objectsIter) ForEach(cb func(plumbing.EncodedObject) error) error { - for { - o, err := iter.Next() - if err != nil { - if err == io.EOF { - return nil - } - return err - } - - if err := cb(o); err != nil { - return err - } - } -} - -func (iter *objectsIter) Close() { - iter.h = []plumbing.Hash{} -} - -func hashListAsMap(l []plumbing.Hash) map[plumbing.Hash]struct{} { - m := make(map[plumbing.Hash]struct{}, len(l)) - for _, h := range l { - m[h] = struct{}{} - } - return m -} - -func (s *ObjectStorage) ForEachObjectHash(fun func(plumbing.Hash) error) error { - err := s.dir.ForEachObjectHash(fun) - if err == storer.ErrStop { - return nil - } - return err -} - -func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) { - fi, err := s.dir.ObjectStat(hash) - if err != nil { - return time.Time{}, err - } - return fi.ModTime(), nil -} - -func (s *ObjectStorage) DeleteLooseObject(hash plumbing.Hash) error { - return s.dir.ObjectDelete(hash) -} - -func (s *ObjectStorage) ObjectPacks() ([]plumbing.Hash, error) { - return s.dir.ObjectPacks() -} - -func (s *ObjectStorage) DeleteOldObjectPackAndIndex(h plumbing.Hash, t time.Time) error { - return s.dir.DeleteOldObjectPackAndIndex(h, t) -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/reference.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/reference.go deleted file mode 100644 index a891b837..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/reference.go +++ /dev/null @@ -1,44 +0,0 @@ -package filesystem - -import ( - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/storer" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" -) - -type ReferenceStorage struct { - dir *dotgit.DotGit -} - -func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error { - return r.dir.SetRef(ref, nil) -} - -func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error { - return r.dir.SetRef(ref, old) -} - -func (r *ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) { - return r.dir.Ref(n) -} - -func (r *ReferenceStorage) IterReferences() (storer.ReferenceIter, error) { - refs, err := r.dir.Refs() - if err != nil { - return nil, err - } - - return storer.NewReferenceSliceIter(refs), nil -} - -func (r *ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error { - return r.dir.RemoveRef(n) -} - -func (r *ReferenceStorage) CountLooseRefs() (int, error) { - return r.dir.CountLooseRefs() -} - -func (r *ReferenceStorage) PackRefs() error { - return r.dir.PackRefs() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/shallow.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/shallow.go deleted file mode 100644 index 502d406d..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/shallow.go +++ /dev/null @@ -1,54 +0,0 @@ -package filesystem - -import ( - "bufio" - "fmt" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" - "gopkg.in/src-d/go-git.v4/utils/ioutil" -) - -// ShallowStorage where the shallow commits are stored, an internal to -// manipulate the shallow file -type ShallowStorage struct { - dir *dotgit.DotGit -} - -// SetShallow save the shallows in the shallow file in the .git folder as one -// commit per line represented by 40-byte hexadecimal object terminated by a -// newline. -func (s *ShallowStorage) SetShallow(commits []plumbing.Hash) error { - f, err := s.dir.ShallowWriter() - if err != nil { - return err - } - - defer ioutil.CheckClose(f, &err) - for _, h := range commits { - if _, err := fmt.Fprintf(f, "%s\n", h); err != nil { - return err - } - } - - return err -} - -// Shallow return the shallow commits reading from shallo file from .git -func (s *ShallowStorage) Shallow() ([]plumbing.Hash, error) { - f, err := s.dir.Shallow() - if f == nil || err != nil { - return nil, err - } - - defer ioutil.CheckClose(f, &err) - - var hash []plumbing.Hash - - scn := bufio.NewScanner(f) - for scn.Scan() { - hash = append(hash, plumbing.NewHash(scn.Text())) - } - - return hash, scn.Err() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go b/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go deleted file mode 100644 index 88d1ed48..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/storage/filesystem/storage.go +++ /dev/null @@ -1,73 +0,0 @@ -// Package filesystem is a storage backend base on filesystems -package filesystem - -import ( - "gopkg.in/src-d/go-git.v4/plumbing/cache" - "gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit" - - "gopkg.in/src-d/go-billy.v4" -) - -// Storage is an implementation of git.Storer that stores data on disk in the -// standard git format (this is, the .git directory). Zero values of this type -// are not safe to use, see the NewStorage function below. -type Storage struct { - fs billy.Filesystem - dir *dotgit.DotGit - - ObjectStorage - ReferenceStorage - IndexStorage - ShallowStorage - ConfigStorage - ModuleStorage -} - -// Options holds configuration for the storage. -type Options struct { - // ExclusiveAccess means that the filesystem is not modified externally - // while the repo is open. - ExclusiveAccess bool - // KeepDescriptors makes the file descriptors to be reused but they will - // need to be manually closed calling Close(). - KeepDescriptors bool - // MaxOpenDescriptors is the max number of file descriptors to keep - // open. If KeepDescriptors is true, all file descriptors will remain open. - MaxOpenDescriptors int -} - -// NewStorage returns a new Storage backed by a given `fs.Filesystem` and cache. -func NewStorage(fs billy.Filesystem, cache cache.Object) *Storage { - return NewStorageWithOptions(fs, cache, Options{}) -} - -// NewStorageWithOptions returns a new Storage with extra options, -// backed by a given `fs.Filesystem` and cache. -func NewStorageWithOptions(fs billy.Filesystem, cache cache.Object, ops Options) *Storage { - dirOps := dotgit.Options{ - ExclusiveAccess: ops.ExclusiveAccess, - } - dir := dotgit.NewWithOptions(fs, dirOps) - - return &Storage{ - fs: fs, - dir: dir, - - ObjectStorage: *NewObjectStorageWithOptions(dir, cache, ops), - ReferenceStorage: ReferenceStorage{dir: dir}, - IndexStorage: IndexStorage{dir: dir}, - ShallowStorage: ShallowStorage{dir: dir}, - ConfigStorage: ConfigStorage{dir: dir}, - ModuleStorage: ModuleStorage{dir: dir}, - } -} - -// Filesystem returns the underlying filesystem -func (s *Storage) Filesystem() billy.Filesystem { - return s.fs -} - -// Init initializes .git directory -func (s *Storage) Init() error { - return s.dir.Initialize() -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem/node.go b/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem/node.go deleted file mode 100644 index 12d00189..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem/node.go +++ /dev/null @@ -1,196 +0,0 @@ -package filesystem - -import ( - "io" - "os" - "path" - - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/filemode" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" - - "gopkg.in/src-d/go-billy.v4" -) - -var ignore = map[string]bool{ - ".git": true, -} - -// The node represents a file or a directory in a billy.Filesystem. It -// implements the interface noder.Noder of merkletrie package. -// -// This implementation implements a "standard" hash method being able to be -// compared with any other noder.Noder implementation inside of go-git. -type node struct { - fs billy.Filesystem - submodules map[string]plumbing.Hash - - path string - hash []byte - children []noder.Noder - isDir bool -} - -// NewRootNode returns the root node based on a given billy.Filesystem. -// -// In order to provide the submodule hash status, a map[string]plumbing.Hash -// should be provided where the key is the path of the submodule and the commit -// of the submodule HEAD -func NewRootNode( - fs billy.Filesystem, - submodules map[string]plumbing.Hash, -) noder.Noder { - return &node{fs: fs, submodules: submodules, isDir: true} -} - -// Hash the hash of a filesystem is the result of concatenating the computed -// plumbing.Hash of the file as a Blob and its plumbing.FileMode; that way the -// difftree algorithm will detect changes in the contents of files and also in -// their mode. -// -// The hash of a directory is always a 24-bytes slice of zero values -func (n *node) Hash() []byte { - return n.hash -} - -func (n *node) Name() string { - return path.Base(n.path) -} - -func (n *node) IsDir() bool { - return n.isDir -} - -func (n *node) Children() ([]noder.Noder, error) { - if err := n.calculateChildren(); err != nil { - return nil, err - } - - return n.children, nil -} - -func (n *node) NumChildren() (int, error) { - if err := n.calculateChildren(); err != nil { - return -1, err - } - - return len(n.children), nil -} - -func (n *node) calculateChildren() error { - if !n.IsDir() { - return nil - } - - if len(n.children) != 0 { - return nil - } - - files, err := n.fs.ReadDir(n.path) - if err != nil { - if os.IsNotExist(err) { - return nil - } - - return nil - } - - for _, file := range files { - if _, ok := ignore[file.Name()]; ok { - continue - } - - c, err := n.newChildNode(file) - if err != nil { - return err - } - - n.children = append(n.children, c) - } - - return nil -} - -func (n *node) newChildNode(file os.FileInfo) (*node, error) { - path := path.Join(n.path, file.Name()) - - hash, err := n.calculateHash(path, file) - if err != nil { - return nil, err - } - - node := &node{ - fs: n.fs, - submodules: n.submodules, - - path: path, - hash: hash, - isDir: file.IsDir(), - } - - if hash, isSubmodule := n.submodules[path]; isSubmodule { - node.hash = append(hash[:], filemode.Submodule.Bytes()...) - node.isDir = false - } - - return node, nil -} - -func (n *node) calculateHash(path string, file os.FileInfo) ([]byte, error) { - if file.IsDir() { - return make([]byte, 24), nil - } - - var hash plumbing.Hash - var err error - if file.Mode()&os.ModeSymlink != 0 { - hash, err = n.doCalculateHashForSymlink(path, file) - } else { - hash, err = n.doCalculateHashForRegular(path, file) - } - - if err != nil { - return nil, err - } - - mode, err := filemode.NewFromOSFileMode(file.Mode()) - if err != nil { - return nil, err - } - - return append(hash[:], mode.Bytes()...), nil -} - -func (n *node) doCalculateHashForRegular(path string, file os.FileInfo) (plumbing.Hash, error) { - f, err := n.fs.Open(path) - if err != nil { - return plumbing.ZeroHash, err - } - - defer f.Close() - - h := plumbing.NewHasher(plumbing.BlobObject, file.Size()) - if _, err := io.Copy(h, f); err != nil { - return plumbing.ZeroHash, err - } - - return h.Sum(), nil -} - -func (n *node) doCalculateHashForSymlink(path string, file os.FileInfo) (plumbing.Hash, error) { - target, err := n.fs.Readlink(path) - if err != nil { - return plumbing.ZeroHash, err - } - - h := plumbing.NewHasher(plumbing.BlobObject, file.Size()) - if _, err := h.Write([]byte(target)); err != nil { - return plumbing.ZeroHash, err - } - - return h.Sum(), nil -} - -func (n *node) String() string { - return n.path -} diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/index/node.go b/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/index/node.go deleted file mode 100644 index 96226224..00000000 --- a/vendor/gopkg.in/src-d/go-git.v4/utils/merkletrie/index/node.go +++ /dev/null @@ -1,90 +0,0 @@ -package index - -import ( - "path" - "strings" - - "gopkg.in/src-d/go-git.v4/plumbing/format/index" - "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" -) - -// The node represents a index.Entry or a directory inferred from the path -// of all entries. It implements the interface noder.Noder of merkletrie -// package. -// -// This implementation implements a "standard" hash method being able to be -// compared with any other noder.Noder implementation inside of go-git -type node struct { - path string - entry *index.Entry - children []noder.Noder - isDir bool -} - -// NewRootNode returns the root node of a computed tree from a index.Index, -func NewRootNode(idx *index.Index) noder.Noder { - const rootNode = "" - - m := map[string]*node{rootNode: {isDir: true}} - - for _, e := range idx.Entries { - parts := strings.Split(e.Name, string("/")) - - var fullpath string - for _, part := range parts { - parent := fullpath - fullpath = path.Join(fullpath, part) - - if _, ok := m[fullpath]; ok { - continue - } - - n := &node{path: fullpath} - if fullpath == e.Name { - n.entry = e - } else { - n.isDir = true - } - - m[n.path] = n - m[parent].children = append(m[parent].children, n) - } - } - - return m[rootNode] -} - -func (n *node) String() string { - return n.path -} - -// Hash the hash of a filesystem is a 24-byte slice, is the result of -// concatenating the computed plumbing.Hash of the file as a Blob and its -// plumbing.FileMode; that way the difftree algorithm will detect changes in the -// contents of files and also in their mode. -// -// If the node is computed and not based on a index.Entry the hash is equals -// to a 24-bytes slices of zero values. -func (n *node) Hash() []byte { - if n.entry == nil { - return make([]byte, 24) - } - - return append(n.entry.Hash[:], n.entry.Mode.Bytes()...) -} - -func (n *node) Name() string { - return path.Base(n.path) -} - -func (n *node) IsDir() bool { - return n.isDir -} - -func (n *node) Children() ([]noder.Noder, error) { - return n.children, nil -} - -func (n *node) NumChildren() (int, error) { - return len(n.children), nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index dea7bad2..f91aa18e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -14,6 +14,30 @@ github.com/davecgh/go-spew/spew ## explicit; go 1.18 github.com/devtron-labs/common-lib/pubsub-lib github.com/devtron-labs/common-lib/utils +# github.com/devtron-labs/go-git v1.5.0 +## explicit; go 1.20 +github.com/devtron-labs/go-git/config +github.com/devtron-labs/go-git/internal/url +github.com/devtron-labs/go-git/plumbing +github.com/devtron-labs/go-git/plumbing/filemode +github.com/devtron-labs/go-git/plumbing/format/config +github.com/devtron-labs/go-git/plumbing/format/diff +github.com/devtron-labs/go-git/plumbing/format/index +github.com/devtron-labs/go-git/plumbing/format/pktline +github.com/devtron-labs/go-git/plumbing/object +github.com/devtron-labs/go-git/plumbing/protocol/packp +github.com/devtron-labs/go-git/plumbing/protocol/packp/capability +github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband +github.com/devtron-labs/go-git/plumbing/storer +github.com/devtron-labs/go-git/plumbing/transport +github.com/devtron-labs/go-git/storage +github.com/devtron-labs/go-git/storage/memory +github.com/devtron-labs/go-git/utils/binary +github.com/devtron-labs/go-git/utils/diff +github.com/devtron-labs/go-git/utils/ioutil +github.com/devtron-labs/go-git/utils/merkletrie +github.com/devtron-labs/go-git/utils/merkletrie/internal/frame +github.com/devtron-labs/go-git/utils/merkletrie/noder # github.com/devtron-labs/protos v0.0.0-20230503113602-282404f70fd2 ## explicit; go 1.17 github.com/devtron-labs/protos/gitSensor @@ -67,7 +91,6 @@ github.com/jbenet/go-context/io github.com/jinzhu/inflection # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd ## explicit -github.com/kevinburke/ssh_config # github.com/klauspost/compress v1.15.12 ## explicit; go 1.17 # github.com/matttproud/golang_protobuf_extensions v1.0.1 @@ -77,7 +100,6 @@ github.com/matttproud/golang_protobuf_extensions/pbutil ## explicit; go 1.15 # github.com/mitchellh/go-homedir v1.1.0 ## explicit -github.com/mitchellh/go-homedir # github.com/nats-io/jwt/v2 v2.3.0 ## explicit; go 1.16 # github.com/nats-io/nats.go v1.19.0 @@ -122,7 +144,7 @@ github.com/prometheus/procfs/internal/util # github.com/robfig/cron/v3 v3.0.0 ## explicit; go 1.12 github.com/robfig/cron/v3 -# github.com/sergi/go-diff v1.1.0 +# github.com/sergi/go-diff v1.3.0 ## explicit; go 1.12 github.com/sergi/go-diff/diffmatchpatch # github.com/src-d/gcfg v1.4.0 @@ -149,7 +171,6 @@ github.com/tidwall/match github.com/tidwall/pretty # github.com/xanzy/ssh-agent v0.2.1 ## explicit -github.com/xanzy/ssh-agent # go.uber.org/atomic v1.7.0 ## explicit; go 1.13 go.uber.org/atomic @@ -166,14 +187,8 @@ go.uber.org/zap/internal/exit go.uber.org/zap/zapcore # golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa ## explicit; go 1.17 -golang.org/x/crypto/blowfish golang.org/x/crypto/cast5 -golang.org/x/crypto/chacha20 -golang.org/x/crypto/curve25519 -golang.org/x/crypto/curve25519/internal/field golang.org/x/crypto/ed25519 -golang.org/x/crypto/internal/poly1305 -golang.org/x/crypto/internal/subtle golang.org/x/crypto/openpgp golang.org/x/crypto/openpgp/armor golang.org/x/crypto/openpgp/elgamal @@ -181,10 +196,6 @@ golang.org/x/crypto/openpgp/errors golang.org/x/crypto/openpgp/packet golang.org/x/crypto/openpgp/s2k golang.org/x/crypto/pbkdf2 -golang.org/x/crypto/ssh -golang.org/x/crypto/ssh/agent -golang.org/x/crypto/ssh/internal/bcrypt_pbkdf -golang.org/x/crypto/ssh/knownhosts # golang.org/x/net v0.0.0-20220722155237-a158d28d115b ## explicit; go 1.17 golang.org/x/net/context @@ -192,13 +203,10 @@ golang.org/x/net/http/httpguts golang.org/x/net/http2 golang.org/x/net/http2/hpack golang.org/x/net/idna -golang.org/x/net/internal/socks golang.org/x/net/internal/timeseries -golang.org/x/net/proxy golang.org/x/net/trace # golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f ## explicit; go 1.17 -golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix golang.org/x/sys/windows @@ -302,54 +310,6 @@ google.golang.org/protobuf/types/known/timestamppb ## explicit # gopkg.in/src-d/go-billy.v4 v4.3.2 ## explicit -gopkg.in/src-d/go-billy.v4 -gopkg.in/src-d/go-billy.v4/helper/chroot -gopkg.in/src-d/go-billy.v4/helper/polyfill -gopkg.in/src-d/go-billy.v4/osfs -gopkg.in/src-d/go-billy.v4/util -# gopkg.in/src-d/go-git.v4 v4.13.1 -## explicit -gopkg.in/src-d/go-git.v4 -gopkg.in/src-d/go-git.v4/config -gopkg.in/src-d/go-git.v4/internal/revision -gopkg.in/src-d/go-git.v4/internal/url -gopkg.in/src-d/go-git.v4/plumbing -gopkg.in/src-d/go-git.v4/plumbing/cache -gopkg.in/src-d/go-git.v4/plumbing/filemode -gopkg.in/src-d/go-git.v4/plumbing/format/config -gopkg.in/src-d/go-git.v4/plumbing/format/diff -gopkg.in/src-d/go-git.v4/plumbing/format/gitignore -gopkg.in/src-d/go-git.v4/plumbing/format/idxfile -gopkg.in/src-d/go-git.v4/plumbing/format/index -gopkg.in/src-d/go-git.v4/plumbing/format/objfile -gopkg.in/src-d/go-git.v4/plumbing/format/packfile -gopkg.in/src-d/go-git.v4/plumbing/format/pktline -gopkg.in/src-d/go-git.v4/plumbing/object -gopkg.in/src-d/go-git.v4/plumbing/protocol/packp -gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability -gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband -gopkg.in/src-d/go-git.v4/plumbing/revlist -gopkg.in/src-d/go-git.v4/plumbing/storer -gopkg.in/src-d/go-git.v4/plumbing/transport -gopkg.in/src-d/go-git.v4/plumbing/transport/client -gopkg.in/src-d/go-git.v4/plumbing/transport/file -gopkg.in/src-d/go-git.v4/plumbing/transport/git -gopkg.in/src-d/go-git.v4/plumbing/transport/http -gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common -gopkg.in/src-d/go-git.v4/plumbing/transport/server -gopkg.in/src-d/go-git.v4/plumbing/transport/ssh -gopkg.in/src-d/go-git.v4/storage -gopkg.in/src-d/go-git.v4/storage/filesystem -gopkg.in/src-d/go-git.v4/storage/filesystem/dotgit -gopkg.in/src-d/go-git.v4/storage/memory -gopkg.in/src-d/go-git.v4/utils/binary -gopkg.in/src-d/go-git.v4/utils/diff -gopkg.in/src-d/go-git.v4/utils/ioutil -gopkg.in/src-d/go-git.v4/utils/merkletrie -gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem -gopkg.in/src-d/go-git.v4/utils/merkletrie/index -gopkg.in/src-d/go-git.v4/utils/merkletrie/internal/frame -gopkg.in/src-d/go-git.v4/utils/merkletrie/noder # gopkg.in/warnings.v0 v0.1.2 ## explicit gopkg.in/warnings.v0 From ef3162cf42588fa2bf5f173d75d00c4dbbc6a6e7 Mon Sep 17 00:00:00 2001 From: Avdhesh Kumar Date: Tue, 8 Aug 2023 14:53:59 +0530 Subject: [PATCH 2/2] fix: add missing imports --- pkg/git/GitCliUtil.go | 1 + pkg/git/RepositoryManager.go | 1 + .../github.com/devtron-labs/go-git/.gitignore | 6 + .../devtron-labs/go-git/.travis.yml | 37 + .../devtron-labs/go-git/CODE_OF_CONDUCT.md | 74 + .../devtron-labs/go-git/COMPATIBILITY.md | 111 + .../devtron-labs/go-git/CONTRIBUTING.md | 59 + vendor/github.com/devtron-labs/go-git/DCO | 36 + .../devtron-labs/go-git/MAINTAINERS | 3 + .../github.com/devtron-labs/go-git/Makefile | 52 + .../github.com/devtron-labs/go-git/README.md | 123 + .../devtron-labs/go-git/appveyor.yml | 21 + .../devtron-labs/go-git/blame_test.go | 551 ---- .../devtron-labs/go-git/common_test.go | 170 -- .../devtron-labs/go-git/example_test.go | 166 - .../go-git/internal/revision/parser.go | 622 ++++ .../go-git/internal/revision/scanner.go | 117 + .../go-git/internal/revision/token.go | 28 + .../devtron-labs/go-git/options_test.go | 35 - .../go-git/plumbing/cache/buffer_lru.go | 98 + .../go-git/plumbing/cache/common.go | 39 + .../go-git/plumbing/cache/object_lru.go | 101 + .../go-git/plumbing/format/gitignore/dir.go | 136 + .../go-git/plumbing/format/gitignore/doc.go | 70 + .../plumbing/format/gitignore/matcher.go | 30 + .../plumbing/format/gitignore/pattern.go | 153 + .../go-git/plumbing/format/idxfile/decoder.go | 177 ++ .../go-git/plumbing/format/idxfile/doc.go | 128 + .../go-git/plumbing/format/idxfile/encoder.go | 142 + .../go-git/plumbing/format/idxfile/idxfile.go | 346 +++ .../go-git/plumbing/format/idxfile/writer.go | 186 ++ .../go-git/plumbing/format/objfile/doc.go | 2 + .../go-git/plumbing/format/objfile/reader.go | 114 + .../go-git/plumbing/format/objfile/writer.go | 109 + .../go-git/plumbing/format/packfile/common.go | 78 + .../plumbing/format/packfile/delta_index.go | 297 ++ .../format/packfile/delta_selector.go | 369 +++ .../plumbing/format/packfile/diff_delta.go | 200 ++ .../go-git/plumbing/format/packfile/doc.go | 39 + .../plumbing/format/packfile/encoder.go | 219 ++ .../go-git/plumbing/format/packfile/error.go | 30 + .../plumbing/format/packfile/fsobject.go | 116 + .../plumbing/format/packfile/object_pack.go | 164 + .../plumbing/format/packfile/packfile.go | 562 ++++ .../go-git/plumbing/format/packfile/parser.go | 483 +++ .../plumbing/format/packfile/patch_delta.go | 229 ++ .../plumbing/format/packfile/scanner.go | 466 +++ .../go-git/plumbing/revlist/revlist.go | 230 ++ .../plumbing/transport/client/client.go | 48 + .../go-git/plumbing/transport/file/client.go | 156 + .../go-git/plumbing/transport/file/server.go | 53 + .../go-git/plumbing/transport/git/common.go | 109 + .../go-git/plumbing/transport/http/common.go | 281 ++ .../plumbing/transport/http/receive_pack.go | 106 + .../plumbing/transport/http/upload_pack.go | 123 + .../transport/internal/common/common.go | 467 +++ .../transport/internal/common/server.go | 73 + .../plumbing/transport/server/loader.go | 64 + .../plumbing/transport/server/server.go | 422 +++ .../plumbing/transport/ssh/auth_method.go | 324 ++ .../go-git/plumbing/transport/ssh/common.go | 228 ++ .../devtron-labs/go-git/prune_test.go | 75 - .../devtron-labs/go-git/references_test.go | 401 --- .../devtron-labs/go-git/remote_test.go | 889 ------ .../devtron-labs/go-git/repository_test.go | 2695 ----------------- .../go-git/repository_unix_test.go | 11 - .../go-git/repository_windows_test.go | 9 - .../go-git/storage/filesystem/config.go | 61 + .../go-git/storage/filesystem/deltaobject.go | 37 + .../storage/filesystem/dotgit/dotgit.go | 1100 +++++++ .../dotgit/dotgit_rewrite_packed_refs.go | 81 + .../filesystem/dotgit/dotgit_setref.go | 90 + .../storage/filesystem/dotgit/writers.go | 284 ++ .../go-git/storage/filesystem/index.go | 54 + .../go-git/storage/filesystem/module.go | 20 + .../go-git/storage/filesystem/object.go | 815 +++++ .../go-git/storage/filesystem/reference.go | 44 + .../go-git/storage/filesystem/shallow.go | 54 + .../go-git/storage/filesystem/storage.go | 73 + .../devtron-labs/go-git/submodule_test.go | 236 -- .../utils/merkletrie/filesystem/node.go | 196 ++ .../go-git/utils/merkletrie/index/node.go | 90 + .../go-git/worktree_commit_test.go | 369 --- .../devtron-labs/go-git/worktree_test.go | 2008 ------------ .../kevinburke/ssh_config/.gitattributes | 1 + .../kevinburke/ssh_config/.gitignore | 0 .../github.com/kevinburke/ssh_config/.mailmap | 1 + .../kevinburke/ssh_config/.travis.yml | 14 + .../kevinburke/ssh_config/AUTHORS.txt | 5 + .../github.com/kevinburke/ssh_config/LICENSE | 49 + .../github.com/kevinburke/ssh_config/Makefile | 30 + .../kevinburke/ssh_config/README.md | 81 + .../kevinburke/ssh_config/config.go | 649 ++++ .../github.com/kevinburke/ssh_config/lexer.go | 240 ++ .../kevinburke/ssh_config/parser.go | 191 ++ .../kevinburke/ssh_config/position.go | 25 + .../github.com/kevinburke/ssh_config/token.go | 49 + .../kevinburke/ssh_config/validators.go | 162 + .../github.com/mitchellh/go-homedir/LICENSE | 21 + .../github.com/mitchellh/go-homedir/README.md | 14 + .../mitchellh/go-homedir/homedir.go | 167 + vendor/github.com/xanzy/ssh-agent/.gitignore | 24 + vendor/github.com/xanzy/ssh-agent/LICENSE | 202 ++ vendor/github.com/xanzy/ssh-agent/README.md | 23 + .../xanzy/ssh-agent/pageant_windows.go | 146 + vendor/github.com/xanzy/ssh-agent/sshagent.go | 49 + .../xanzy/ssh-agent/sshagent_windows.go | 80 + vendor/golang.org/x/crypto/blowfish/block.go | 159 + vendor/golang.org/x/crypto/blowfish/cipher.go | 99 + vendor/golang.org/x/crypto/blowfish/const.go | 199 ++ .../x/crypto/chacha20/chacha_arm64.go | 17 + .../x/crypto/chacha20/chacha_arm64.s | 308 ++ .../x/crypto/chacha20/chacha_generic.go | 398 +++ .../x/crypto/chacha20/chacha_noasm.go | 14 + .../x/crypto/chacha20/chacha_ppc64le.go | 17 + .../x/crypto/chacha20/chacha_ppc64le.s | 450 +++ .../x/crypto/chacha20/chacha_s390x.go | 28 + .../x/crypto/chacha20/chacha_s390x.s | 225 ++ vendor/golang.org/x/crypto/chacha20/xor.go | 42 + .../x/crypto/curve25519/curve25519.go | 146 + .../x/crypto/curve25519/internal/field/README | 7 + .../x/crypto/curve25519/internal/field/fe.go | 416 +++ .../curve25519/internal/field/fe_amd64.go | 16 + .../curve25519/internal/field/fe_amd64.s | 379 +++ .../internal/field/fe_amd64_noasm.go | 12 + .../curve25519/internal/field/fe_arm64.go | 16 + .../curve25519/internal/field/fe_arm64.s | 43 + .../internal/field/fe_arm64_noasm.go | 12 + .../curve25519/internal/field/fe_generic.go | 264 ++ .../curve25519/internal/field/sync.checkpoint | 1 + .../crypto/curve25519/internal/field/sync.sh | 19 + .../x/crypto/internal/poly1305/bits_compat.go | 40 + .../x/crypto/internal/poly1305/bits_go1.13.go | 22 + .../x/crypto/internal/poly1305/mac_noasm.go | 10 + .../x/crypto/internal/poly1305/poly1305.go | 99 + .../x/crypto/internal/poly1305/sum_amd64.go | 48 + .../x/crypto/internal/poly1305/sum_amd64.s | 109 + .../x/crypto/internal/poly1305/sum_generic.go | 309 ++ .../x/crypto/internal/poly1305/sum_ppc64le.go | 48 + .../x/crypto/internal/poly1305/sum_ppc64le.s | 182 ++ .../x/crypto/internal/poly1305/sum_s390x.go | 77 + .../x/crypto/internal/poly1305/sum_s390x.s | 504 +++ .../x/crypto/internal/subtle/aliasing.go | 33 + .../crypto/internal/subtle/aliasing_purego.go | 36 + .../golang.org/x/crypto/ssh/agent/client.go | 847 ++++++ .../golang.org/x/crypto/ssh/agent/forward.go | 103 + .../golang.org/x/crypto/ssh/agent/keyring.go | 241 ++ .../golang.org/x/crypto/ssh/agent/server.go | 570 ++++ vendor/golang.org/x/crypto/ssh/buffer.go | 97 + vendor/golang.org/x/crypto/ssh/certs.go | 589 ++++ vendor/golang.org/x/crypto/ssh/channel.go | 633 ++++ vendor/golang.org/x/crypto/ssh/cipher.go | 789 +++++ vendor/golang.org/x/crypto/ssh/client.go | 282 ++ vendor/golang.org/x/crypto/ssh/client_auth.go | 725 +++++ vendor/golang.org/x/crypto/ssh/common.go | 430 +++ vendor/golang.org/x/crypto/ssh/connection.go | 143 + vendor/golang.org/x/crypto/ssh/doc.go | 22 + vendor/golang.org/x/crypto/ssh/handshake.go | 704 +++++ .../ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go | 93 + vendor/golang.org/x/crypto/ssh/kex.go | 774 +++++ vendor/golang.org/x/crypto/ssh/keys.go | 1447 +++++++++ .../x/crypto/ssh/knownhosts/knownhosts.go | 540 ++++ vendor/golang.org/x/crypto/ssh/mac.go | 61 + vendor/golang.org/x/crypto/ssh/messages.go | 877 ++++++ vendor/golang.org/x/crypto/ssh/mux.go | 351 +++ vendor/golang.org/x/crypto/ssh/server.go | 752 +++++ vendor/golang.org/x/crypto/ssh/session.go | 648 ++++ vendor/golang.org/x/crypto/ssh/ssh_gss.go | 139 + vendor/golang.org/x/crypto/ssh/streamlocal.go | 116 + vendor/golang.org/x/crypto/ssh/tcpip.go | 474 +++ vendor/golang.org/x/crypto/ssh/transport.go | 357 +++ .../golang.org/x/net/internal/socks/client.go | 168 + .../golang.org/x/net/internal/socks/socks.go | 317 ++ vendor/golang.org/x/net/proxy/dial.go | 54 + vendor/golang.org/x/net/proxy/direct.go | 31 + vendor/golang.org/x/net/proxy/per_host.go | 155 + vendor/golang.org/x/net/proxy/proxy.go | 149 + vendor/golang.org/x/net/proxy/socks5.go | 42 + vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 18 + vendor/golang.org/x/sys/cpu/byteorder.go | 66 + vendor/golang.org/x/sys/cpu/cpu.go | 287 ++ vendor/golang.org/x/sys/cpu/cpu_aix.go | 34 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 73 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 172 ++ vendor/golang.org/x/sys/cpu/cpu_arm64.s | 32 + vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 22 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 17 + .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 12 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 23 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c | 38 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 33 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 16 + vendor/golang.org/x/sys/cpu/cpu_linux_arm.go | 39 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 71 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 24 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 10 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 32 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 40 + vendor/golang.org/x/sys/cpu/cpu_loong64.go | 13 + vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 16 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 12 + .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 ++ vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 10 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 10 + .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 13 + .../golang.org/x/sys/cpu/cpu_other_riscv64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 17 + vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_s390x.go | 172 ++ vendor/golang.org/x/sys/cpu/cpu_s390x.s | 58 + vendor/golang.org/x/sys/cpu/cpu_wasm.go | 18 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 145 + vendor/golang.org/x/sys/cpu/cpu_x86.s | 28 + vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 + vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 + vendor/golang.org/x/sys/cpu/hwcap_linux.go | 56 + .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 27 + .../x/sys/cpu/syscall_aix_ppc64_gc.go | 36 + vendor/gopkg.in/src-d/go-billy.v4/.gitignore | 4 + vendor/gopkg.in/src-d/go-billy.v4/.travis.yml | 17 + vendor/gopkg.in/src-d/go-billy.v4/DCO | 25 + vendor/gopkg.in/src-d/go-billy.v4/LICENSE | 201 ++ vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS | 1 + vendor/gopkg.in/src-d/go-billy.v4/Makefile | 25 + vendor/gopkg.in/src-d/go-billy.v4/README.md | 72 + .../gopkg.in/src-d/go-billy.v4/appveyor.yml | 15 + vendor/gopkg.in/src-d/go-billy.v4/fs.go | 202 ++ .../src-d/go-billy.v4/helper/chroot/chroot.go | 242 ++ .../go-billy.v4/helper/polyfill/polyfill.go | 105 + vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go | 139 + .../src-d/go-billy.v4/osfs/os_posix.go | 21 + .../src-d/go-billy.v4/osfs/os_windows.go | 57 + .../gopkg.in/src-d/go-billy.v4/util/glob.go | 111 + .../gopkg.in/src-d/go-billy.v4/util/util.go | 224 ++ vendor/modules.txt | 40 + 236 files changed, 36239 insertions(+), 7615 deletions(-) create mode 100644 vendor/github.com/devtron-labs/go-git/.gitignore create mode 100644 vendor/github.com/devtron-labs/go-git/.travis.yml create mode 100644 vendor/github.com/devtron-labs/go-git/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/devtron-labs/go-git/COMPATIBILITY.md create mode 100644 vendor/github.com/devtron-labs/go-git/CONTRIBUTING.md create mode 100644 vendor/github.com/devtron-labs/go-git/DCO create mode 100644 vendor/github.com/devtron-labs/go-git/MAINTAINERS create mode 100644 vendor/github.com/devtron-labs/go-git/Makefile create mode 100644 vendor/github.com/devtron-labs/go-git/README.md create mode 100644 vendor/github.com/devtron-labs/go-git/appveyor.yml delete mode 100644 vendor/github.com/devtron-labs/go-git/blame_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/common_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/example_test.go create mode 100644 vendor/github.com/devtron-labs/go-git/internal/revision/parser.go create mode 100644 vendor/github.com/devtron-labs/go-git/internal/revision/scanner.go create mode 100644 vendor/github.com/devtron-labs/go-git/internal/revision/token.go delete mode 100644 vendor/github.com/devtron-labs/go-git/options_test.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/cache/buffer_lru.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/cache/common.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/cache/object_lru.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/dir.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/doc.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/matcher.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/pattern.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/decoder.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/doc.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/encoder.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/idxfile.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/writer.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/doc.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/reader.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/writer.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/common.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_index.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_selector.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/diff_delta.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/doc.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/encoder.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/error.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/fsobject.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/object_pack.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/packfile.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/parser.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/patch_delta.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/scanner.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/revlist/revlist.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/client/client.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/file/client.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/file/server.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/git/common.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/http/common.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/http/receive_pack.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/http/upload_pack.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/common.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/server.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/server/loader.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/server/server.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/auth_method.go create mode 100644 vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/common.go delete mode 100644 vendor/github.com/devtron-labs/go-git/prune_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/references_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/remote_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/repository_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/repository_unix_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/repository_windows_test.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/config.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/deltaobject.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_setref.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/writers.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/index.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/module.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/object.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/reference.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/shallow.go create mode 100644 vendor/github.com/devtron-labs/go-git/storage/filesystem/storage.go delete mode 100644 vendor/github.com/devtron-labs/go-git/submodule_test.go create mode 100644 vendor/github.com/devtron-labs/go-git/utils/merkletrie/filesystem/node.go create mode 100644 vendor/github.com/devtron-labs/go-git/utils/merkletrie/index/node.go delete mode 100644 vendor/github.com/devtron-labs/go-git/worktree_commit_test.go delete mode 100644 vendor/github.com/devtron-labs/go-git/worktree_test.go create mode 100644 vendor/github.com/kevinburke/ssh_config/.gitattributes create mode 100644 vendor/github.com/kevinburke/ssh_config/.gitignore create mode 100644 vendor/github.com/kevinburke/ssh_config/.mailmap create mode 100644 vendor/github.com/kevinburke/ssh_config/.travis.yml create mode 100644 vendor/github.com/kevinburke/ssh_config/AUTHORS.txt create mode 100644 vendor/github.com/kevinburke/ssh_config/LICENSE create mode 100644 vendor/github.com/kevinburke/ssh_config/Makefile create mode 100644 vendor/github.com/kevinburke/ssh_config/README.md create mode 100644 vendor/github.com/kevinburke/ssh_config/config.go create mode 100644 vendor/github.com/kevinburke/ssh_config/lexer.go create mode 100644 vendor/github.com/kevinburke/ssh_config/parser.go create mode 100644 vendor/github.com/kevinburke/ssh_config/position.go create mode 100644 vendor/github.com/kevinburke/ssh_config/token.go create mode 100644 vendor/github.com/kevinburke/ssh_config/validators.go create mode 100644 vendor/github.com/mitchellh/go-homedir/LICENSE create mode 100644 vendor/github.com/mitchellh/go-homedir/README.md create mode 100644 vendor/github.com/mitchellh/go-homedir/homedir.go create mode 100644 vendor/github.com/xanzy/ssh-agent/.gitignore create mode 100644 vendor/github.com/xanzy/ssh-agent/LICENSE create mode 100644 vendor/github.com/xanzy/ssh-agent/README.md create mode 100644 vendor/github.com/xanzy/ssh-agent/pageant_windows.go create mode 100644 vendor/github.com/xanzy/ssh-agent/sshagent.go create mode 100644 vendor/github.com/xanzy/ssh-agent/sshagent_windows.go create mode 100644 vendor/golang.org/x/crypto/blowfish/block.go create mode 100644 vendor/golang.org/x/crypto/blowfish/cipher.go create mode 100644 vendor/golang.org/x/crypto/blowfish/const.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.s create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_generic.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_noasm.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.s create mode 100644 vendor/golang.org/x/crypto/chacha20/xor.go create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/README create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint create mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/poly1305.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s create mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing.go create mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go create mode 100644 vendor/golang.org/x/crypto/ssh/agent/client.go create mode 100644 vendor/golang.org/x/crypto/ssh/agent/forward.go create mode 100644 vendor/golang.org/x/crypto/ssh/agent/keyring.go create mode 100644 vendor/golang.org/x/crypto/ssh/agent/server.go create mode 100644 vendor/golang.org/x/crypto/ssh/buffer.go create mode 100644 vendor/golang.org/x/crypto/ssh/certs.go create mode 100644 vendor/golang.org/x/crypto/ssh/channel.go create mode 100644 vendor/golang.org/x/crypto/ssh/cipher.go create mode 100644 vendor/golang.org/x/crypto/ssh/client.go create mode 100644 vendor/golang.org/x/crypto/ssh/client_auth.go create mode 100644 vendor/golang.org/x/crypto/ssh/common.go create mode 100644 vendor/golang.org/x/crypto/ssh/connection.go create mode 100644 vendor/golang.org/x/crypto/ssh/doc.go create mode 100644 vendor/golang.org/x/crypto/ssh/handshake.go create mode 100644 vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go create mode 100644 vendor/golang.org/x/crypto/ssh/kex.go create mode 100644 vendor/golang.org/x/crypto/ssh/keys.go create mode 100644 vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go create mode 100644 vendor/golang.org/x/crypto/ssh/mac.go create mode 100644 vendor/golang.org/x/crypto/ssh/messages.go create mode 100644 vendor/golang.org/x/crypto/ssh/mux.go create mode 100644 vendor/golang.org/x/crypto/ssh/server.go create mode 100644 vendor/golang.org/x/crypto/ssh/session.go create mode 100644 vendor/golang.org/x/crypto/ssh/ssh_gss.go create mode 100644 vendor/golang.org/x/crypto/ssh/streamlocal.go create mode 100644 vendor/golang.org/x/crypto/ssh/tcpip.go create mode 100644 vendor/golang.org/x/crypto/ssh/transport.go create mode 100644 vendor/golang.org/x/net/internal/socks/client.go create mode 100644 vendor/golang.org/x/net/internal/socks/socks.go create mode 100644 vendor/golang.org/x/net/proxy/dial.go create mode 100644 vendor/golang.org/x/net/proxy/direct.go create mode 100644 vendor/golang.org/x/net/proxy/per_host.go create mode 100644 vendor/golang.org/x/net/proxy/proxy.go create mode 100644 vendor/golang.org/x/net/proxy/socks5.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/hwcap_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/.gitignore create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/.travis.yml create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/DCO create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/LICENSE create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/Makefile create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/README.md create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/fs.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/util/glob.go create mode 100644 vendor/gopkg.in/src-d/go-billy.v4/util/util.go diff --git a/pkg/git/GitCliUtil.go b/pkg/git/GitCliUtil.go index 26389a23..54dc167f 100644 --- a/pkg/git/GitCliUtil.go +++ b/pkg/git/GitCliUtil.go @@ -2,6 +2,7 @@ package git import ( "fmt" + "github.com/devtron-labs/go-git" "github.com/devtron-labs/go-git/config" "go.uber.org/zap" "os" diff --git a/pkg/git/RepositoryManager.go b/pkg/git/RepositoryManager.go index a50d5bb5..2e8b8e0e 100644 --- a/pkg/git/RepositoryManager.go +++ b/pkg/git/RepositoryManager.go @@ -29,6 +29,7 @@ import ( "github.com/devtron-labs/git-sensor/internal/middleware" "github.com/devtron-labs/git-sensor/internal/sql" + "github.com/devtron-labs/go-git" "github.com/devtron-labs/go-git/plumbing" "github.com/devtron-labs/go-git/plumbing/object" "github.com/devtron-labs/go-git/plumbing/transport" diff --git a/vendor/github.com/devtron-labs/go-git/.gitignore b/vendor/github.com/devtron-labs/go-git/.gitignore new file mode 100644 index 00000000..44f68368 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/.gitignore @@ -0,0 +1,6 @@ +.idea +.tmp +coverage.out +*~ +coverage.txt +profile.out diff --git a/vendor/github.com/devtron-labs/go-git/.travis.yml b/vendor/github.com/devtron-labs/go-git/.travis.yml new file mode 100644 index 00000000..8625e939 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/.travis.yml @@ -0,0 +1,37 @@ +language: go + +go: + - "1.11" + - "1.12" + +go_import_path: github.com/devtron-labs/go-git + +env: + - GIT_VERSION=master + - GIT_VERSION=v1.9.3 + - GIT_VERSION=v2.11.0 + +cache: + directories: + - $HOME/.git-dist + +before_script: + - export GIT_DIST_PATH=$HOME/.git-dist + - make build-git + +before_install: + - git config --global user.email "travis@example.com" + - git config --global user.name "Travis CI" + +install: + - go get -v -t ./... + +script: + - export GIT_EXEC_PATH=$GIT_DIST_PATH + - export PATH=$GIT_DIST_PATH:$PATH + - git version + - make test-coverage + - go vet ./... + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/devtron-labs/go-git/CODE_OF_CONDUCT.md b/vendor/github.com/devtron-labs/go-git/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a689fa3c --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at conduct@sourced.tech. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff --git a/vendor/github.com/devtron-labs/go-git/COMPATIBILITY.md b/vendor/github.com/devtron-labs/go-git/COMPATIBILITY.md new file mode 100644 index 00000000..4a3da62f --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/COMPATIBILITY.md @@ -0,0 +1,111 @@ +Supported Capabilities +====================== + +Here is a non-comprehensive table of git commands and features whose equivalent +is supported by go-git. + +| Feature | Status | Notes | +|---------------------------------------|--------|-------| +| **config** | +| config | ✔ | Reading and modifying per-repository configuration (`.git/config`) is supported. Global configuration (`$HOME/.gitconfig`) is not. | +| **getting and creating repositories** | +| init | ✔ | Plain init and `--bare` are supported. Flags `--template`, `--separate-git-dir` and `--shared` are not. | +| clone | ✔ | Plain clone and equivalents to `--progress`, `--single-branch`, `--depth`, `--origin`, `--recurse-submodules` are supported. Others are not. | +| **basic snapshotting** | +| add | ✔ | Plain add is supported. Any other flag aren't supported | +| status | ✔ | +| commit | ✔ | +| reset | ✔ | +| rm | ✔ | +| mv | ✔ | +| **branching and merging** | +| branch | ✔ | +| checkout | ✔ | Basic usages of checkout are supported. | +| merge | ✖ | +| mergetool | ✖ | +| stash | ✖ | +| tag | ✔ | +| **sharing and updating projects** | +| fetch | ✔ | +| pull | ✔ | Only supports merges where the merge can be resolved as a fast-forward. | +| push | ✔ | +| remote | ✔ | +| submodule | ✔ | +| **inspection and comparison** | +| show | ✔ | +| log | ✔ | +| shortlog | (see log) | +| describe | | +| **patching** | +| apply | ✖ | +| cherry-pick | ✖ | +| diff | ✔ | Patch object with UnifiedDiff output representation | +| rebase | ✖ | +| revert | ✖ | +| **debugging** | +| bisect | ✖ | +| blame | ✔ | +| grep | ✔ | +| **email** || +| am | ✖ | +| apply | ✖ | +| format-patch | ✖ | +| send-email | ✖ | +| request-pull | ✖ | +| **external systems** | +| svn | ✖ | +| fast-import | ✖ | +| **administration** | +| clean | ✔ | +| gc | ✖ | +| fsck | ✖ | +| reflog | ✖ | +| filter-branch | ✖ | +| instaweb | ✖ | +| archive | ✖ | +| bundle | ✖ | +| prune | ✖ | +| repack | ✖ | +| **server admin** | +| daemon | | +| update-server-info | | +| **advanced** | +| notes | ✖ | +| replace | ✖ | +| worktree | ✖ | +| annotate | (see blame) | +| **gpg** | +| git-verify-commit | ✔ | +| git-verify-tag | ✔ | +| **plumbing commands** | +| cat-file | ✔ | +| check-ignore | | +| commit-tree | | +| count-objects | | +| diff-index | | +| for-each-ref | ✔ | +| hash-object | ✔ | +| ls-files | ✔ | +| merge-base | ✔ | Calculates the merge-base only between two commits, and supports `--independent` and `--is-ancestor` modifiers; Does not support `--fork-point` nor `--octopus` modifiers. | +| read-tree | | +| rev-list | ✔ | +| rev-parse | | +| show-ref | ✔ | +| symbolic-ref | ✔ | +| update-index | | +| update-ref | | +| verify-pack | | +| write-tree | | +| **protocols** | +| http(s):// (dumb) | ✖ | +| http(s):// (smart) | ✔ | +| git:// | ✔ | +| ssh:// | ✔ | +| file:// | ✔ | +| custom | ✔ | +| **other features** | +| gitignore | ✔ | +| gitattributes | ✖ | +| index version | | +| packfile version | | +| push-certs | ✖ | diff --git a/vendor/github.com/devtron-labs/go-git/CONTRIBUTING.md b/vendor/github.com/devtron-labs/go-git/CONTRIBUTING.md new file mode 100644 index 00000000..bdb5f733 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contributing Guidelines + +source{d} go-git project is [Apache 2.0 licensed](LICENSE) and accepts +contributions via GitHub pull requests. This document outlines some of the +conventions on development workflow, commit message formatting, contact points, +and other resources to make it easier to get your contribution accepted. + +## Certificate of Origin + +By contributing to this project you agree to the [Developer Certificate of +Origin (DCO)](DCO). This document was created by the Linux Kernel community and is a +simple statement that you, as a contributor, have the legal right to make the +contribution. + +In order to show your agreement with the DCO you should include at the end of commit message, +the following line: `Signed-off-by: John Doe `, using your real name. + +This can be done easily using the [`-s`](https://github.com/git/git/blob/b2c150d3aa82f6583b9aadfecc5f8fa1c74aca09/Documentation/git-commit.txt#L154-L161) flag on the `git commit`. + +## Support Channels + +The official support channels, for both users and contributors, are: + +- [StackOverflow go-git tag](https://stackoverflow.com/questions/tagged/go-git) for user questions. +- GitHub [Issues](https://github.com/src-d/go-git/issues)* for bug reports and feature requests. +- Slack: #go-git room in the [source{d} Slack](https://join.slack.com/t/sourced-community/shared_invite/enQtMjc4Njk5MzEyNzM2LTFjNzY4NjEwZGEwMzRiNTM4MzRlMzQ4MmIzZjkwZmZlM2NjODUxZmJjNDI1OTcxNDAyMmZlNmFjODZlNTg0YWM) + +*Before opening a new issue or submitting a new pull request, it's helpful to +search the project - it's likely that another user has already reported the +issue you're facing, or it's a known issue that we're already aware of. + + +## How to Contribute + +Pull Requests (PRs) are the main and exclusive way to contribute to the official go-git project. +In order for a PR to be accepted it needs to pass a list of requirements: + +- You should be able to run the same query using `git`. We don't accept features that are not implemented in the official git implementation. +- The expected behavior must match the [official git implementation](https://github.com/git/git). +- The actual behavior must be correctly explained with natural language and providing a minimum working example in Go that reproduces it. +- All PRs must be written in idiomatic Go, formatted according to [gofmt](https://golang.org/cmd/gofmt/), and without any warnings from [go lint](https://github.com/golang/lint) nor [go vet](https://golang.org/cmd/vet/). +- They should in general include tests, and those shall pass. +- If the PR is a bug fix, it has to include a suite of unit tests for the new functionality. +- If the PR is a new feature, it has to come with a suite of unit tests, that tests the new functionality. +- In any case, all the PRs have to pass the personal evaluation of at least one of the [maintainers](MAINTAINERS) of go-git. + +### Format of the commit message + +Every commit message should describe what was changed, under which context and, if applicable, the GitHub issue it relates to: + +``` +plumbing: packp, Skip argument validations for unknown capabilities. Fixes #623 +``` + +The format can be described more formally as follows: + +``` +: , . [Fixes #] +``` diff --git a/vendor/github.com/devtron-labs/go-git/DCO b/vendor/github.com/devtron-labs/go-git/DCO new file mode 100644 index 00000000..3aca339d --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/DCO @@ -0,0 +1,36 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. \ No newline at end of file diff --git a/vendor/github.com/devtron-labs/go-git/MAINTAINERS b/vendor/github.com/devtron-labs/go-git/MAINTAINERS new file mode 100644 index 00000000..ff2129c4 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/MAINTAINERS @@ -0,0 +1,3 @@ +Máximo Cuadros (@mcuadros) +Jeremy Stribling (@strib) +Ori Rawlings (@orirawlings) diff --git a/vendor/github.com/devtron-labs/go-git/Makefile b/vendor/github.com/devtron-labs/go-git/Makefile new file mode 100644 index 00000000..858e88eb --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/Makefile @@ -0,0 +1,52 @@ +# General +WORKDIR = $(PWD) + +# Go parameters +GOCMD = go +GOTEST = $(GOCMD) test -v + +# Git config +GIT_VERSION ?= +GIT_DIST_PATH ?= $(PWD)/.git-dist +GIT_REPOSITORY = http://github.com/git/git.git + +# Coverage +COVERAGE_REPORT = coverage.txt +COVERAGE_PROFILE = profile.out +COVERAGE_MODE = atomic + +ifneq ($(origin CI), undefined) + WORKDIR := $(GOPATH)/src/github.com/devtron-labs/go-git +endif + +build-git: + @if [ -f $(GIT_DIST_PATH)/git ]; then \ + echo "nothing to do, using cache $(GIT_DIST_PATH)"; \ + else \ + git clone $(GIT_REPOSITORY) -b $(GIT_VERSION) --depth 1 --single-branch $(GIT_DIST_PATH); \ + cd $(GIT_DIST_PATH); \ + make configure; \ + ./configure; \ + make all; \ + fi + +test: + @cd $(WORKDIR); \ + $(GOTEST) ./... + +test-coverage: + @cd $(WORKDIR); \ + echo "" > $(COVERAGE_REPORT); \ + for dir in `find . -name "*.go" | grep -o '.*/' | sort | uniq`; do \ + $(GOTEST) $$dir -coverprofile=$(COVERAGE_PROFILE) -covermode=$(COVERAGE_MODE); \ + if [ $$? != 0 ]; then \ + exit 2; \ + fi; \ + if [ -f $(COVERAGE_PROFILE) ]; then \ + cat $(COVERAGE_PROFILE) >> $(COVERAGE_REPORT); \ + rm $(COVERAGE_PROFILE); \ + fi; \ + done; \ + +clean: + rm -rf $(GIT_DIST_PATH) \ No newline at end of file diff --git a/vendor/github.com/devtron-labs/go-git/README.md b/vendor/github.com/devtron-labs/go-git/README.md new file mode 100644 index 00000000..9fc572d1 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/README.md @@ -0,0 +1,123 @@ +![go-git logo](https://cdn.rawgit.com/src-d/artwork/02036484/go-git/files/go-git-github-readme-header.png) +[![GoDoc](https://godoc.org/github.com/devtron-labs/go-git?status.svg)](https://godoc.org/github.com/src-d/go-git) [![Build Status](https://travis-ci.org/src-d/go-git.svg)](https://travis-ci.org/src-d/go-git) [![Build status](https://ci.appveyor.com/api/projects/status/nyidskwifo4py6ub?svg=true)](https://ci.appveyor.com/project/mcuadros/go-git) [![codecov.io](https://codecov.io/github/src-d/go-git/coverage.svg)](https://codecov.io/github/src-d/go-git) [![Go Report Card](https://goreportcard.com/badge/github.com/src-d/go-git)](https://goreportcard.com/report/github.com/src-d/go-git) + +*go-git* is a highly extensible git implementation library written in **pure Go**. + +It can be used to manipulate git repositories at low level *(plumbing)* or high level *(porcelain)*, through an idiomatic Go API. It also supports several types of storage, such as in-memory filesystems, or custom implementations thanks to the [`Storer`](https://godoc.org/github.com/devtron-labs/go-git/plumbing/storer) interface. + +It's being actively developed since 2015 and is being used extensively by [source{d}](https://sourced.tech/) and [Keybase](https://keybase.io/blog/encrypted-git-for-everyone), and by many other libraries and tools. + +Comparison with git +------------------- + +*go-git* aims to be fully compatible with [git](https://github.com/git/git), all the *porcelain* operations are implemented to work exactly as *git* does. + +*git* is a humongous project with years of development by thousands of contributors, making it challenging for *go-git* to implement all the features. You can find a comparison of *go-git* vs *git* in the [compatibility documentation](COMPATIBILITY.md). + + +Installation +------------ + +The recommended way to install *go-git* is: + +``` +go get -u github.com/devtron-labs/go-git/... +``` + +> We use [gopkg.in](http://labix.org/gopkg.in) to version the API, this means that when `go get` clones the package, it's the latest tag matching `v4.*` that is cloned and not the master branch. + +Examples +-------- + +> Please note that the `CheckIfError` and `Info` functions used in the examples are from the [examples package](https://github.com/src-d/go-git/blob/master/_examples/common.go#L17) just to be used in the examples. + + +### Basic example + +A basic example that mimics the standard `git clone` command + +```go +// Clone the given repository to the given directory +Info("git clone https://github.com/src-d/go-git") + +_, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{ + URL: "https://github.com/src-d/go-git", + Progress: os.Stdout, +}) + +CheckIfError(err) +``` + +Outputs: +``` +Counting objects: 4924, done. +Compressing objects: 100% (1333/1333), done. +Total 4924 (delta 530), reused 6 (delta 6), pack-reused 3533 +``` + +### In-memory example + +Cloning a repository into memory and printing the history of HEAD, just like `git log` does + + +```go +// Clones the given repository in memory, creating the remote, the local +// branches and fetching the objects, exactly as: +Info("git clone https://github.com/src-d/go-siva") + +r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{ + URL: "https://github.com/src-d/go-siva", +}) + +CheckIfError(err) + +// Gets the HEAD history from HEAD, just like this command: +Info("git log") + +// ... retrieves the branch pointed by HEAD +ref, err := r.Head() +CheckIfError(err) + + +// ... retrieves the commit history +cIter, err := r.Log(&git.LogOptions{From: ref.Hash()}) +CheckIfError(err) + +// ... just iterates over the commits, printing it +err = cIter.ForEach(func(c *object.Commit) error { + fmt.Println(c) + return nil +}) +CheckIfError(err) +``` + +Outputs: +``` +commit ded8054fd0c3994453e9c8aacaf48d118d42991e +Author: Santiago M. Mola +Date: Sat Nov 12 21:18:41 2016 +0100 + + index: ReadFrom/WriteTo returns IndexReadError/IndexWriteError. (#9) + +commit df707095626f384ce2dc1a83b30f9a21d69b9dfc +Author: Santiago M. Mola +Date: Fri Nov 11 13:23:22 2016 +0100 + + readwriter: fix bug when writing index. (#10) + + When using ReadWriter on an existing siva file, absolute offset for + index entries was not being calculated correctly. +... +``` + +You can find this [example](_examples/log/main.go) and many others in the [examples](_examples) folder. + +Contribute +---------- + +[Contributions](https://github.com/src-d/go-git/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) are more than welcome, if you are interested please take a look to +our [Contributing Guidelines](CONTRIBUTING.md). + +License +------- +Apache License Version 2.0, see [LICENSE](LICENSE) diff --git a/vendor/github.com/devtron-labs/go-git/appveyor.yml b/vendor/github.com/devtron-labs/go-git/appveyor.yml new file mode 100644 index 00000000..160616be --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/appveyor.yml @@ -0,0 +1,21 @@ +version: "{build}" +platform: x64 + +matrix: + allow_failures: + - platform: x64 + +clone_folder: c:\gopath\src\gopkg.in\src-d\go-git.v4 + +environment: + GOPATH: c:\gopath + +install: + - set PATH=%GOPATH%\bin;c:\go\bin;"C:\Program Files\Git\mingw64\bin";%PATH% + - go version + - go get -v -t ./... + - git config --global user.email "travis@example.com" + - git config --global user.name "Travis CI + +build_script: + - go test -v ./... diff --git a/vendor/github.com/devtron-labs/go-git/blame_test.go b/vendor/github.com/devtron-labs/go-git/blame_test.go deleted file mode 100644 index 797b7de1..00000000 --- a/vendor/github.com/devtron-labs/go-git/blame_test.go +++ /dev/null @@ -1,551 +0,0 @@ -package git - -import ( - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/object" - - "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" -) - -type BlameSuite struct { - BaseSuite -} - -var _ = Suite(&BlameSuite{}) - -func (s *BlameSuite) TestNewLines(c *C) { - h := plumbing.NewHash("ce9f123d790717599aaeb76bc62510de437761be") - lines, err := newLines([]string{"foo"}, []*object.Commit{{ - Hash: h, - Message: "foo", - }}) - - c.Assert(err, IsNil) - c.Assert(lines, HasLen, 1) - c.Assert(lines[0].Text, Equals, "foo") - c.Assert(lines[0].Hash, Equals, h) -} - -func (s *BlameSuite) TestNewLinesWithNewLine(c *C) { - lines, err := newLines([]string{"foo"}, []*object.Commit{ - {Message: "foo"}, - {Message: "bar"}, - }) - - c.Assert(err, IsNil) - c.Assert(lines, HasLen, 2) - c.Assert(lines[0].Text, Equals, "foo") - c.Assert(lines[1].Text, Equals, "\n") -} - -type blameTest struct { - repo string - rev string - path string - blames []string // the commits blamed for each line -} - -// run a blame on all the suite's tests -func (s *BlameSuite) TestBlame(c *C) { - for _, t := range blameTests { - r := s.NewRepositoryFromPackfile(fixtures.ByURL(t.repo).One()) - - exp := s.mockBlame(c, t, r) - commit, err := r.CommitObject(plumbing.NewHash(t.rev)) - c.Assert(err, IsNil) - - obt, err := Blame(commit, t.path) - c.Assert(err, IsNil) - c.Assert(obt, DeepEquals, exp) - - for i, l := range obt.Lines { - c.Assert(l.Hash.String(), Equals, t.blames[i]) - } - } -} - -func (s *BlameSuite) mockBlame(c *C, t blameTest, r *Repository) (blame *BlameResult) { - commit, err := r.CommitObject(plumbing.NewHash(t.rev)) - c.Assert(err, IsNil, Commentf("%v: repo=%s, rev=%s", err, t.repo, t.rev)) - - f, err := commit.File(t.path) - c.Assert(err, IsNil) - lines, err := f.Lines() - c.Assert(err, IsNil) - c.Assert(len(t.blames), Equals, len(lines), Commentf( - "repo=%s, path=%s, rev=%s: the number of lines in the file and the number of expected blames differ (len(blames)=%d, len(lines)=%d)\nblames=%#q\nlines=%#q", t.repo, t.path, t.rev, len(t.blames), len(lines), t.blames, lines)) - - blamedLines := make([]*Line, 0, len(t.blames)) - for i := range t.blames { - commit, err := r.CommitObject(plumbing.NewHash(t.blames[i])) - c.Assert(err, IsNil) - l := &Line{ - Author: commit.Author.Email, - Text: lines[i], - Date: commit.Author.When, - Hash: commit.Hash, - } - blamedLines = append(blamedLines, l) - } - - return &BlameResult{ - Path: t.path, - Rev: plumbing.NewHash(t.rev), - Lines: blamedLines, - } -} - -// utility function to avoid writing so many repeated commits -func repeat(s string, n int) []string { - if n < 0 { - panic("repeat: n < 0") - } - r := make([]string, 0, n) - for i := 0; i < n; i++ { - r = append(r, s) - } - - return r -} - -// utility function to concat slices -func concat(vargs ...[]string) []string { - var r []string - for _, ss := range vargs { - r = append(r, ss...) - } - - return r -} - -var blameTests = [...]blameTest{ - // use the blame2humantest.bash script to easily add more tests. - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", concat( - repeat("35e85108805c84807bc66a02d91535e1e24b38b9", 285), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", concat( - repeat("b8e471f58bcbca63b07bda20e428190409c2db47", 1), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", concat( - repeat("918c48b83bd081e863dbe1b80f8998f058cd8294", 142), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", concat( - repeat("af2d6a6954d532f8ffb47615169c8fdf9d383a1a", 6492), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", concat( - repeat("af2d6a6954d532f8ffb47615169c8fdf9d383a1a", 22), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", concat( - repeat("b029517f6300c2da0f4b651b8642506cd6aaf45d", 22), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", concat( - repeat("918c48b83bd081e863dbe1b80f8998f058cd8294", 259), - )}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", concat( - repeat("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 7), - )}, - /* - // Failed - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "InstallSpinnaker.sh", concat( - repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), - repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 1), - repeat("23673af3ad70b50bba7fdafadc2323302f5ba520", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 29), - repeat("9a06d3f20eabb254d0a1e2ff7735ef007ccd595e", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 4), - repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), - repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 2), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 3), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 7), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 2), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 7), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 6), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 10), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 4), - repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 2), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 4), - repeat("23673af3ad70b50bba7fdafadc2323302f5ba520", 4), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 4), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 13), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 2), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 6), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 2), - repeat("0c5bb1e4392e751f884f3c57de5d4aee72c40031", 1), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 4), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 3), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 4), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 3), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 15), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 1), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 8), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 2), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 12), - repeat("505577dc87d300cf562dc4702a05a5615d90d855", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 5), - repeat("370d61cdbc1f3c90db6759f1599ccbabd40ad6c1", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 4), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 5), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 3), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 2), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 2), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 9), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 3), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 4), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("8eb116de9128c314ac8a6f5310ca500b8c74f5db", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 6), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 6), - repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), - repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 4), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("c9c2a0ec03968ab17e8b16fdec9661eb1dbea173", 1), - repeat("d2f6214b625db706384b378a29cc4c22237db97a", 2), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 12), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 5), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 3), - repeat("a47d0aaeda421f06df248ad65bd58230766bf118", 5), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 2), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("b2c7142082d52b09ca20228606c31c7479c0833e", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("495c7118e7cf757aa04eab410b64bfb5b5149ad2", 1), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), - repeat("495c7118e7cf757aa04eab410b64bfb5b5149ad2", 3), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), - repeat("495c7118e7cf757aa04eab410b64bfb5b5149ad2", 1), - repeat("50d0556563599366f29cb286525780004fa5a317", 1), - repeat("dd2d03c19658ff96d371aef00e75e2e54702da0e", 1), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 1), - repeat("dd2d03c19658ff96d371aef00e75e2e54702da0e", 2), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("b5c6053a46993b20d1b91e7b7206bffa54669ad7", 1), - repeat("9e74d009894d73dd07773ea6b3bdd8323db980f7", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", 4), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 1), - repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 3), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 2), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 2), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 4), - repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), - repeat("b7015a5d36990d69a054482556127b9c7404a24a", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 5), - repeat("b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", 2), - repeat("d2f6214b625db706384b378a29cc4c22237db97a", 1), - repeat("ce9f123d790717599aaeb76bc62510de437761be", 5), - repeat("ba486de7c025457963701114c683dcd4708e1dee", 4), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 1), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 3), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 1), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 3), - repeat("6328ee836affafc1b52127147b5ca07300ac78e6", 2), - repeat("01e65d67eed8afcb67a6bdf1c962541f62b299c9", 3), - repeat("3de4f77c105f700f50d9549d32b9a05a01b46c4b", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 2), - repeat("370d61cdbc1f3c90db6759f1599ccbabd40ad6c1", 6), - repeat("dd7e66c862209e8b912694a582a09c0db3227f0d", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 2), - repeat("dd7e66c862209e8b912694a582a09c0db3227f0d", 3), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("dd7e66c862209e8b912694a582a09c0db3227f0d", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 3), - )}, - */ - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/reconfigure_spinnaker.py", concat( - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 22), - repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 7), - )}, - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/validate_configuration.py", concat( - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 29), - repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 19), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 15), - repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 8), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 4), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 46), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 42), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), - repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 8), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 2), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), - repeat("1e3d328a2cabda5d0aaddc5dec65271343e0dc37", 3), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 10), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 69), - repeat("b5d999e2986e190d81767cd3cfeda0260f9f6fb8", 7), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - )}, - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/run.py", concat( - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 185), - )}, - /* - // Fail by 3 - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/configurator.py", concat( - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 53), - repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - repeat("e805183c72f0426fb073728c01901c2fd2db1da6", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 6), - repeat("023d4fb17b76e0fe0764971df8b8538b735a1d67", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 36), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 3), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 13), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 18), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", 1), - repeat("023d4fb17b76e0fe0764971df8b8538b735a1d67", 17), - repeat("c89dab0d42f1856d157357e9010f8cc6a12f5b1f", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 43), - )}, - */ - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "pylib/spinnaker/__init__.py", []string{}}, - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "gradle/wrapper/gradle-wrapper.jar", concat( - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 7), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 2), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 10), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 11), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 29), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 7), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 58), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 13), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 4), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 13), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 9), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 1), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 17), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 6), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 6), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 5), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 4), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 3), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 2), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 1), - repeat("11d6c1020b1765e236ca65b2709d37b5bfdba0f4", 6), - repeat("bc02440df2ff95a014a7b3cb11b98c3a2bded777", 55), - )}, - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/settings.js", concat( - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 17), - repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 43), - repeat("d2838db9f6ef9628645e7d04cd9658a83e8708ea", 1), - repeat("637ba49300f701cfbd859c1ccf13c4f39a9ba1c8", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 13), - )}, - /* - // fail a few lines - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/default-spinnaker-local.yml", concat( - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 9), - repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 2), - repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 2), - repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 5), - repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 2), - repeat("a596972a661d9a7deca8abd18b52ce1a39516e89", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 5), - repeat("5e09821cbd7d710405b61cab0a795c2982a71b9c", 1), - repeat("8980daf661408a3faa1f22c225702a5c1d11d5c9", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 25), - repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), - repeat("eaf7614cad81e8ab5c813dd4821129d0c04ea449", 1), - repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 24), - repeat("974b775a8978b120ff710cac93a21c7387b914c9", 2), - repeat("3ce7b902a51bac2f10994f7d1f251b616c975e54", 1), - repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 6), - repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 14), - repeat("7c8d9a6081d9cb7a56c479bfe64d70540ea32795", 5), - repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2), - )}, - */ - /* - // fail one line - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "config/spinnaker.yml", concat( - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 32), - repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 2), - repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 1), - repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 6), - repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2), - repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 2), - repeat("5a2a845bc08974a36d599a4a4b7e25be833823b0", 2), - repeat("41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", 3), - repeat("7c8d9a6081d9cb7a56c479bfe64d70540ea32795", 3), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 50), - repeat("974b775a8978b120ff710cac93a21c7387b914c9", 2), - repeat("d4553dac205023fa77652308af1a2d1cf52138fb", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 9), - repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), - repeat("eaf7614cad81e8ab5c813dd4821129d0c04ea449", 1), - repeat("caf6d62e8285d4681514dd8027356fb019bc97ff", 1), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 39), - repeat("079e42e7c979541b6fab7343838f7b9fd4a360cd", 6), - repeat("ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", 15), - )}, - */ - /* - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/install_development.sh", concat( - repeat("99534ecc895fe17a1d562bb3049d4168a04d0865", 1), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 71), - )}, - */ - /* - // FAIL two lines interchanged - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/bootstrap_dev.sh", concat( - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 95), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 10), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 7), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 3), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 12), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 2), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 6), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 4), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("376599177551c3f04ccc94d71bbb4d037dec0c3f", 2), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 17), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 2), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 2), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 3), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 8), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 4), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 6), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 4), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 10), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 2), - repeat("fc28a378558cdb5bbc08b6dcb96ee77c5b716760", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 1), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 8), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), - repeat("fc28a378558cdb5bbc08b6dcb96ee77c5b716760", 1), - repeat("d1ff4e13e9e0b500821aa558373878f93487e34b", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 4), - repeat("24551a5d486969a2972ee05e87f16444890f9555", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 2), - repeat("24551a5d486969a2972ee05e87f16444890f9555", 1), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 8), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 13), - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 5), - repeat("24551a5d486969a2972ee05e87f16444890f9555", 1), - repeat("838aed816872c52ed435e4876a7b64dba0bed500", 8), - )}, - */ - /* - // FAIL move? - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "dev/create_google_dev_vm.sh", concat( - repeat("a24001f6938d425d0e7504bdf5d27fc866a85c3d", 20), - )}, - */ -} diff --git a/vendor/github.com/devtron-labs/go-git/common_test.go b/vendor/github.com/devtron-labs/go-git/common_test.go deleted file mode 100644 index fed07e23..00000000 --- a/vendor/github.com/devtron-labs/go-git/common_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package git - -import ( - "testing" - - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/cache" - "github.com/devtron-labs/go-git/plumbing/format/packfile" - "github.com/devtron-labs/go-git/plumbing/transport" - "github.com/devtron-labs/go-git/storage/filesystem" - "github.com/devtron-labs/go-git/storage/memory" - - "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-billy.v4" - "gopkg.in/src-d/go-billy.v4/memfs" - "gopkg.in/src-d/go-billy.v4/util" -) - -func Test(t *testing.T) { TestingT(t) } - -type BaseSuite struct { - fixtures.Suite - Repository *Repository - - backupProtocol transport.Transport - cache map[string]*Repository -} - -func (s *BaseSuite) SetUpSuite(c *C) { - s.Suite.SetUpSuite(c) - s.buildBasicRepository(c) - - s.cache = make(map[string]*Repository) -} - -func (s *BaseSuite) TearDownSuite(c *C) { - s.Suite.TearDownSuite(c) -} - -func (s *BaseSuite) buildBasicRepository(c *C) { - f := fixtures.Basic().One() - s.Repository = s.NewRepository(f) -} - -// NewRepository returns a new repository using the .git folder, if the fixture -// is tagged as worktree the filesystem from fixture is used, otherwise a new -// memfs filesystem is used as worktree. -func (s *BaseSuite) NewRepository(f *fixtures.Fixture) *Repository { - var worktree, dotgit billy.Filesystem - if f.Is("worktree") { - r, err := PlainOpen(f.Worktree().Root()) - if err != nil { - panic(err) - } - - return r - } - - dotgit = f.DotGit() - worktree = memfs.New() - - st := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()) - - r, err := Open(st, worktree) - if err != nil { - panic(err) - } - - return r -} - -// NewRepositoryWithEmptyWorktree returns a new repository using the .git folder -// from the fixture but without a empty memfs worktree, the index and the -// modules are deleted from the .git folder. -func (s *BaseSuite) NewRepositoryWithEmptyWorktree(f *fixtures.Fixture) *Repository { - dotgit := f.DotGit() - err := dotgit.Remove("index") - if err != nil { - panic(err) - } - - err = util.RemoveAll(dotgit, "modules") - if err != nil { - panic(err) - } - - worktree := memfs.New() - - st := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()) - - r, err := Open(st, worktree) - if err != nil { - panic(err) - } - - return r - -} - -func (s *BaseSuite) NewRepositoryFromPackfile(f *fixtures.Fixture) *Repository { - h := f.PackfileHash.String() - if r, ok := s.cache[h]; ok { - return r - } - - storer := memory.NewStorage() - p := f.Packfile() - defer p.Close() - - if err := packfile.UpdateObjectStorage(storer, p); err != nil { - panic(err) - } - - storer.SetReference(plumbing.NewHashReference(plumbing.HEAD, f.Head)) - - r, err := Open(storer, memfs.New()) - if err != nil { - panic(err) - } - - s.cache[h] = r - return r -} - -func (s *BaseSuite) GetBasicLocalRepositoryURL() string { - fixture := fixtures.Basic().One() - return s.GetLocalRepositoryURL(fixture) -} - -func (s *BaseSuite) GetLocalRepositoryURL(f *fixtures.Fixture) string { - return f.DotGit().Root() -} - -type SuiteCommon struct{} - -var _ = Suite(&SuiteCommon{}) - -var countLinesTests = [...]struct { - i string // the string we want to count lines from - e int // the expected number of lines in i -}{ - {"", 0}, - {"a", 1}, - {"a\n", 1}, - {"a\nb", 2}, - {"a\nb\n", 2}, - {"a\nb\nc", 3}, - {"a\nb\nc\n", 3}, - {"a\n\n\nb\n", 4}, - {"first line\n\tsecond line\nthird line\n", 3}, -} - -func (s *SuiteCommon) TestCountLines(c *C) { - for i, t := range countLinesTests { - o := countLines(t.i) - c.Assert(o, Equals, t.e, Commentf("subtest %d, input=%q", i, t.i)) - } -} - -func AssertReferences(c *C, r *Repository, expected map[string]string) { - for name, target := range expected { - expected := plumbing.NewReferenceFromStrings(name, target) - - obtained, err := r.Reference(expected.Name(), true) - c.Assert(err, IsNil) - - c.Assert(obtained, DeepEquals, expected) - } -} diff --git a/vendor/github.com/devtron-labs/go-git/example_test.go b/vendor/github.com/devtron-labs/go-git/example_test.go deleted file mode 100644 index cef709e8..00000000 --- a/vendor/github.com/devtron-labs/go-git/example_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package git_test - -import ( - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - - "github.com/devtron-labs/go-git" - "github.com/devtron-labs/go-git/config" - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/transport/http" - "github.com/devtron-labs/go-git/storage/memory" - - "gopkg.in/src-d/go-billy.v4/memfs" -) - -func ExampleClone() { - // Filesystem abstraction based on memory - fs := memfs.New() - // Git objects storer based on memory - storer := memory.NewStorage() - - // Clones the repository into the worktree (fs) and storer all the .git - // content into the storer - _, err := git.Clone(storer, fs, &git.CloneOptions{ - URL: "https://github.com/git-fixtures/basic.git", - }) - if err != nil { - log.Fatal(err) - } - - // Prints the content of the CHANGELOG file from the cloned repository - changelog, err := fs.Open("CHANGELOG") - if err != nil { - log.Fatal(err) - } - - io.Copy(os.Stdout, changelog) - // Output: Initial changelog -} - -func ExamplePlainClone() { - // Tempdir to clone the repository - dir, err := ioutil.TempDir("", "clone-example") - if err != nil { - log.Fatal(err) - } - - defer os.RemoveAll(dir) // clean up - - // Clones the repository into the given dir, just as a normal git clone does - _, err = git.PlainClone(dir, false, &git.CloneOptions{ - URL: "https://github.com/git-fixtures/basic.git", - }) - - if err != nil { - log.Fatal(err) - } - - // Prints the content of the CHANGELOG file from the cloned repository - changelog, err := os.Open(filepath.Join(dir, "CHANGELOG")) - if err != nil { - log.Fatal(err) - } - - io.Copy(os.Stdout, changelog) - // Output: Initial changelog -} - -func ExamplePlainClone_usernamePassword() { - // Tempdir to clone the repository - dir, err := ioutil.TempDir("", "clone-example") - if err != nil { - log.Fatal(err) - } - - defer os.RemoveAll(dir) // clean up - - // Clones the repository into the given dir, just as a normal git clone does - _, err = git.PlainClone(dir, false, &git.CloneOptions{ - URL: "https://github.com/git-fixtures/basic.git", - Auth: &http.BasicAuth{ - Username: "username", - Password: "password", - }, - }) - - if err != nil { - log.Fatal(err) - } -} - -func ExamplePlainClone_accessToken() { - // Tempdir to clone the repository - dir, err := ioutil.TempDir("", "clone-example") - if err != nil { - log.Fatal(err) - } - - defer os.RemoveAll(dir) // clean up - - // Clones the repository into the given dir, just as a normal git clone does - _, err = git.PlainClone(dir, false, &git.CloneOptions{ - URL: "https://github.com/git-fixtures/basic.git", - Auth: &http.BasicAuth{ - Username: "abc123", // anything except an empty string - Password: "github_access_token", - }, - }) - - if err != nil { - log.Fatal(err) - } -} - -func ExampleRepository_References() { - r, _ := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{ - URL: "https://github.com/git-fixtures/basic.git", - }) - - // simulating a git show-ref - refs, _ := r.References() - refs.ForEach(func(ref *plumbing.Reference) error { - if ref.Type() == plumbing.HashReference { - fmt.Println(ref) - } - - return nil - }) - - // Example Output: - // 6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/remotes/origin/master - // e8d3ffab552895c19b9fcf7aa264d277cde33881 refs/remotes/origin/branch - // 6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/heads/master - -} - -func ExampleRepository_CreateRemote() { - r, _ := git.Init(memory.NewStorage(), nil) - - // Add a new remote, with the default fetch refspec - _, err := r.CreateRemote(&config.RemoteConfig{ - Name: "example", - URLs: []string{"https://github.com/git-fixtures/basic.git"}, - }) - - if err != nil { - log.Fatal(err) - } - - list, err := r.Remotes() - if err != nil { - log.Fatal(err) - } - - for _, r := range list { - fmt.Println(r) - } - - // Example Output: - // example https://github.com/git-fixtures/basic.git (fetch) - // example https://github.com/git-fixtures/basic.git (push) -} diff --git a/vendor/github.com/devtron-labs/go-git/internal/revision/parser.go b/vendor/github.com/devtron-labs/go-git/internal/revision/parser.go new file mode 100644 index 00000000..d2c509e5 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/internal/revision/parser.go @@ -0,0 +1,622 @@ +// Package revision extracts git revision from string +// More informations about revision : https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html +package revision + +import ( + "bytes" + "fmt" + "io" + "regexp" + "strconv" + "time" +) + +// ErrInvalidRevision is emitted if string doesn't match valid revision +type ErrInvalidRevision struct { + s string +} + +func (e *ErrInvalidRevision) Error() string { + return "Revision invalid : " + e.s +} + +// Revisioner represents a revision component. +// A revision is made of multiple revision components +// obtained after parsing a revision string, +// for instance revision "master~" will be converted in +// two revision components Ref and TildePath +type Revisioner interface { +} + +// Ref represents a reference name : HEAD, master +type Ref string + +// TildePath represents ~, ~{n} +type TildePath struct { + Depth int +} + +// CaretPath represents ^, ^{n} +type CaretPath struct { + Depth int +} + +// CaretReg represents ^{/foo bar} +type CaretReg struct { + Regexp *regexp.Regexp + Negate bool +} + +// CaretType represents ^{commit} +type CaretType struct { + ObjectType string +} + +// AtReflog represents @{n} +type AtReflog struct { + Depth int +} + +// AtCheckout represents @{-n} +type AtCheckout struct { + Depth int +} + +// AtUpstream represents @{upstream}, @{u} +type AtUpstream struct { + BranchName string +} + +// AtPush represents @{push} +type AtPush struct { + BranchName string +} + +// AtDate represents @{"2006-01-02T15:04:05Z"} +type AtDate struct { + Date time.Time +} + +// ColonReg represents :/foo bar +type ColonReg struct { + Regexp *regexp.Regexp + Negate bool +} + +// ColonPath represents :./ : +type ColonPath struct { + Path string +} + +// ColonStagePath represents ::/ +type ColonStagePath struct { + Path string + Stage int +} + +// Parser represents a parser +// use to tokenize and transform to revisioner chunks +// a given string +type Parser struct { + s *scanner + currentParsedChar struct { + tok token + lit string + } + unreadLastChar bool +} + +// NewParserFromString returns a new instance of parser from a string. +func NewParserFromString(s string) *Parser { + return NewParser(bytes.NewBufferString(s)) +} + +// NewParser returns a new instance of parser. +func NewParser(r io.Reader) *Parser { + return &Parser{s: newScanner(r)} +} + +// scan returns the next token from the underlying scanner +// or the last scanned token if an unscan was requested +func (p *Parser) scan() (token, string, error) { + if p.unreadLastChar { + p.unreadLastChar = false + return p.currentParsedChar.tok, p.currentParsedChar.lit, nil + } + + tok, lit, err := p.s.scan() + + p.currentParsedChar.tok, p.currentParsedChar.lit = tok, lit + + return tok, lit, err +} + +// unscan pushes the previously read token back onto the buffer. +func (p *Parser) unscan() { p.unreadLastChar = true } + +// Parse explode a revision string into revisioner chunks +func (p *Parser) Parse() ([]Revisioner, error) { + var rev Revisioner + var revs []Revisioner + var tok token + var err error + + for { + tok, _, err = p.scan() + + if err != nil { + return nil, err + } + + switch tok { + case at: + rev, err = p.parseAt() + case tilde: + rev, err = p.parseTilde() + case caret: + rev, err = p.parseCaret() + case colon: + rev, err = p.parseColon() + case eof: + err = p.validateFullRevision(&revs) + + if err != nil { + return []Revisioner{}, err + } + + return revs, nil + default: + p.unscan() + rev, err = p.parseRef() + } + + if err != nil { + return []Revisioner{}, err + } + + revs = append(revs, rev) + } +} + +// validateFullRevision ensures all revisioner chunks make a valid revision +func (p *Parser) validateFullRevision(chunks *[]Revisioner) error { + var hasReference bool + + for i, chunk := range *chunks { + switch chunk.(type) { + case Ref: + if i == 0 { + hasReference = true + } else { + return &ErrInvalidRevision{`reference must be defined once at the beginning`} + } + case AtDate: + if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { + return nil + } + + return &ErrInvalidRevision{`"@" statement is not valid, could be : @{}, @{}`} + case AtReflog: + if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { + return nil + } + + return &ErrInvalidRevision{`"@" statement is not valid, could be : @{}, @{}`} + case AtCheckout: + if len(*chunks) == 1 { + return nil + } + + return &ErrInvalidRevision{`"@" statement is not valid, could be : @{-}`} + case AtUpstream: + if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { + return nil + } + + return &ErrInvalidRevision{`"@" statement is not valid, could be : @{upstream}, @{upstream}, @{u}, @{u}`} + case AtPush: + if len(*chunks) == 1 || hasReference && len(*chunks) == 2 { + return nil + } + + return &ErrInvalidRevision{`"@" statement is not valid, could be : @{push}, @{push}`} + case TildePath, CaretPath, CaretReg: + if !hasReference { + return &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`} + } + case ColonReg: + if len(*chunks) == 1 { + return nil + } + + return &ErrInvalidRevision{`":" statement is not valid, could be : :/`} + case ColonPath: + if i == len(*chunks)-1 && hasReference || len(*chunks) == 1 { + return nil + } + + return &ErrInvalidRevision{`":" statement is not valid, could be : :`} + case ColonStagePath: + if len(*chunks) == 1 { + return nil + } + + return &ErrInvalidRevision{`":" statement is not valid, could be : ::`} + } + } + + return nil +} + +// parseAt extract @ statements +func (p *Parser) parseAt() (Revisioner, error) { + var tok, nextTok token + var lit, nextLit string + var err error + + tok, _, err = p.scan() + + if err != nil { + return nil, err + } + + if tok != obrace { + p.unscan() + + return Ref("HEAD"), nil + } + + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + nextTok, nextLit, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == word && (lit == "u" || lit == "upstream") && nextTok == cbrace: + return AtUpstream{}, nil + case tok == word && lit == "push" && nextTok == cbrace: + return AtPush{}, nil + case tok == number && nextTok == cbrace: + n, _ := strconv.Atoi(lit) + + return AtReflog{n}, nil + case tok == minus && nextTok == number: + n, _ := strconv.Atoi(nextLit) + + t, _, err := p.scan() + + if err != nil { + return nil, err + } + + if t != cbrace { + return nil, &ErrInvalidRevision{fmt.Sprintf(`missing "}" in @{-n} structure`)} + } + + return AtCheckout{n}, nil + default: + p.unscan() + + date := lit + + for { + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == cbrace: + t, err := time.Parse("2006-01-02T15:04:05Z", date) + + if err != nil { + return nil, &ErrInvalidRevision{fmt.Sprintf(`wrong date "%s" must fit ISO-8601 format : 2006-01-02T15:04:05Z`, date)} + } + + return AtDate{t}, nil + default: + date += lit + } + } + } +} + +// parseTilde extract ~ statements +func (p *Parser) parseTilde() (Revisioner, error) { + var tok token + var lit string + var err error + + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == number: + n, _ := strconv.Atoi(lit) + + return TildePath{n}, nil + default: + p.unscan() + return TildePath{1}, nil + } +} + +// parseCaret extract ^ statements +func (p *Parser) parseCaret() (Revisioner, error) { + var tok token + var lit string + var err error + + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == obrace: + r, err := p.parseCaretBraces() + + if err != nil { + return nil, err + } + + return r, nil + case tok == number: + n, _ := strconv.Atoi(lit) + + if n > 2 { + return nil, &ErrInvalidRevision{fmt.Sprintf(`"%s" found must be 0, 1 or 2 after "^"`, lit)} + } + + return CaretPath{n}, nil + default: + p.unscan() + return CaretPath{1}, nil + } +} + +// parseCaretBraces extract ^{} statements +func (p *Parser) parseCaretBraces() (Revisioner, error) { + var tok, nextTok token + var lit, _ string + start := true + var re string + var negate bool + var err error + + for { + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + nextTok, _, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == word && nextTok == cbrace && (lit == "commit" || lit == "tree" || lit == "blob" || lit == "tag" || lit == "object"): + return CaretType{lit}, nil + case re == "" && tok == cbrace: + return CaretType{"tag"}, nil + case re == "" && tok == emark && nextTok == emark: + re += lit + case re == "" && tok == emark && nextTok == minus: + negate = true + case re == "" && tok == emark: + return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)} + case re == "" && tok == slash: + p.unscan() + case tok != slash && start: + return nil, &ErrInvalidRevision{fmt.Sprintf(`"%s" is not a valid revision suffix brace component`, lit)} + case tok != cbrace: + p.unscan() + re += lit + case tok == cbrace: + p.unscan() + + reg, err := regexp.Compile(re) + + if err != nil { + return CaretReg{}, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component, %s`, err.Error())} + } + + return CaretReg{reg, negate}, nil + } + + start = false + } +} + +// parseColon extract : statements +func (p *Parser) parseColon() (Revisioner, error) { + var tok token + var err error + + tok, _, err = p.scan() + + if err != nil { + return nil, err + } + + switch tok { + case slash: + return p.parseColonSlash() + default: + p.unscan() + return p.parseColonDefault() + } +} + +// parseColonSlash extract :/ statements +func (p *Parser) parseColonSlash() (Revisioner, error) { + var tok, nextTok token + var lit string + var re string + var negate bool + var err error + + for { + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + nextTok, _, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == emark && nextTok == emark: + re += lit + case re == "" && tok == emark && nextTok == minus: + negate = true + case re == "" && tok == emark: + return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)} + case tok == eof: + p.unscan() + reg, err := regexp.Compile(re) + + if err != nil { + return ColonReg{}, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component, %s`, err.Error())} + } + + return ColonReg{reg, negate}, nil + default: + p.unscan() + re += lit + } + } +} + +// parseColonDefault extract : statements +func (p *Parser) parseColonDefault() (Revisioner, error) { + var tok token + var lit string + var path string + var stage int + var err error + var n = -1 + + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + nextTok, _, err := p.scan() + + if err != nil { + return nil, err + } + + if tok == number && nextTok == colon { + n, _ = strconv.Atoi(lit) + } + + switch n { + case 0, 1, 2, 3: + stage = n + default: + path += lit + p.unscan() + } + + for { + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + switch { + case tok == eof && n == -1: + return ColonPath{path}, nil + case tok == eof: + return ColonStagePath{path, stage}, nil + default: + path += lit + } + } +} + +// parseRef extract reference name +func (p *Parser) parseRef() (Revisioner, error) { + var tok, prevTok token + var lit, buf string + var endOfRef bool + var err error + + for { + tok, lit, err = p.scan() + + if err != nil { + return nil, err + } + + switch tok { + case eof, at, colon, tilde, caret: + endOfRef = true + } + + err := p.checkRefFormat(tok, lit, prevTok, buf, endOfRef) + + if err != nil { + return "", err + } + + if endOfRef { + p.unscan() + return Ref(buf), nil + } + + buf += lit + prevTok = tok + } +} + +// checkRefFormat ensure reference name follow rules defined here : +// https://git-scm.com/docs/git-check-ref-format +func (p *Parser) checkRefFormat(token token, literal string, previousToken token, buffer string, endOfRef bool) error { + switch token { + case aslash, space, control, qmark, asterisk, obracket: + return &ErrInvalidRevision{fmt.Sprintf(`must not contains "%s"`, literal)} + } + + switch { + case (token == dot || token == slash) && buffer == "": + return &ErrInvalidRevision{fmt.Sprintf(`must not start with "%s"`, literal)} + case previousToken == slash && endOfRef: + return &ErrInvalidRevision{`must not end with "/"`} + case previousToken == dot && endOfRef: + return &ErrInvalidRevision{`must not end with "."`} + case token == dot && previousToken == slash: + return &ErrInvalidRevision{`must not contains "/."`} + case previousToken == dot && token == dot: + return &ErrInvalidRevision{`must not contains ".."`} + case previousToken == slash && token == slash: + return &ErrInvalidRevision{`must not contains consecutively "/"`} + case (token == slash || endOfRef) && len(buffer) > 4 && buffer[len(buffer)-5:] == ".lock": + return &ErrInvalidRevision{"cannot end with .lock"} + } + + return nil +} diff --git a/vendor/github.com/devtron-labs/go-git/internal/revision/scanner.go b/vendor/github.com/devtron-labs/go-git/internal/revision/scanner.go new file mode 100644 index 00000000..fb5f333f --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/internal/revision/scanner.go @@ -0,0 +1,117 @@ +package revision + +import ( + "bufio" + "io" + "unicode" +) + +// runeCategoryValidator takes a rune as input and +// validates it belongs to a rune category +type runeCategoryValidator func(r rune) bool + +// tokenizeExpression aggegates a series of runes matching check predicate into a single +// string and provides given tokenType as token type +func tokenizeExpression(ch rune, tokenType token, check runeCategoryValidator, r *bufio.Reader) (token, string, error) { + var data []rune + data = append(data, ch) + + for { + c, _, err := r.ReadRune() + + if c == zeroRune { + break + } + + if err != nil { + return tokenError, "", err + } + + if check(c) { + data = append(data, c) + } else { + err := r.UnreadRune() + + if err != nil { + return tokenError, "", err + } + + return tokenType, string(data), nil + } + } + + return tokenType, string(data), nil +} + +var zeroRune = rune(0) + +// scanner represents a lexical scanner. +type scanner struct { + r *bufio.Reader +} + +// newScanner returns a new instance of scanner. +func newScanner(r io.Reader) *scanner { + return &scanner{r: bufio.NewReader(r)} +} + +// Scan extracts tokens and their strings counterpart +// from the reader +func (s *scanner) scan() (token, string, error) { + ch, _, err := s.r.ReadRune() + + if err != nil && err != io.EOF { + return tokenError, "", err + } + + switch ch { + case zeroRune: + return eof, "", nil + case ':': + return colon, string(ch), nil + case '~': + return tilde, string(ch), nil + case '^': + return caret, string(ch), nil + case '.': + return dot, string(ch), nil + case '/': + return slash, string(ch), nil + case '{': + return obrace, string(ch), nil + case '}': + return cbrace, string(ch), nil + case '-': + return minus, string(ch), nil + case '@': + return at, string(ch), nil + case '\\': + return aslash, string(ch), nil + case '?': + return qmark, string(ch), nil + case '*': + return asterisk, string(ch), nil + case '[': + return obracket, string(ch), nil + case '!': + return emark, string(ch), nil + } + + if unicode.IsSpace(ch) { + return space, string(ch), nil + } + + if unicode.IsControl(ch) { + return control, string(ch), nil + } + + if unicode.IsLetter(ch) { + return tokenizeExpression(ch, word, unicode.IsLetter, s.r) + } + + if unicode.IsNumber(ch) { + return tokenizeExpression(ch, number, unicode.IsNumber, s.r) + } + + return tokenError, string(ch), nil +} diff --git a/vendor/github.com/devtron-labs/go-git/internal/revision/token.go b/vendor/github.com/devtron-labs/go-git/internal/revision/token.go new file mode 100644 index 00000000..abc40488 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/internal/revision/token.go @@ -0,0 +1,28 @@ +package revision + +// token represents a entity extracted from string parsing +type token int + +const ( + eof token = iota + + aslash + asterisk + at + caret + cbrace + colon + control + dot + emark + minus + number + obrace + obracket + qmark + slash + space + tilde + tokenError + word +) diff --git a/vendor/github.com/devtron-labs/go-git/options_test.go b/vendor/github.com/devtron-labs/go-git/options_test.go deleted file mode 100644 index eb0a0df0..00000000 --- a/vendor/github.com/devtron-labs/go-git/options_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package git - -import ( - "github.com/devtron-labs/go-git/plumbing/object" - . "gopkg.in/check.v1" -) - -type OptionsSuite struct { - BaseSuite -} - -var _ = Suite(&OptionsSuite{}) - -func (s *OptionsSuite) TestCommitOptionsParentsFromHEAD(c *C) { - o := CommitOptions{Author: &object.Signature{}} - err := o.Validate(s.Repository) - c.Assert(err, IsNil) - c.Assert(o.Parents, HasLen, 1) -} - -func (s *OptionsSuite) TestCommitOptionsMissingAuthor(c *C) { - o := CommitOptions{} - err := o.Validate(s.Repository) - c.Assert(err, Equals, ErrMissingAuthor) -} - -func (s *OptionsSuite) TestCommitOptionsCommitter(c *C) { - sig := &object.Signature{} - - o := CommitOptions{Author: sig} - err := o.Validate(s.Repository) - c.Assert(err, IsNil) - - c.Assert(o.Committer, Equals, o.Author) -} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/cache/buffer_lru.go b/vendor/github.com/devtron-labs/go-git/plumbing/cache/buffer_lru.go new file mode 100644 index 00000000..acaf1952 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/cache/buffer_lru.go @@ -0,0 +1,98 @@ +package cache + +import ( + "container/list" + "sync" +) + +// BufferLRU implements an object cache with an LRU eviction policy and a +// maximum size (measured in object size). +type BufferLRU struct { + MaxSize FileSize + + actualSize FileSize + ll *list.List + cache map[int64]*list.Element + mut sync.Mutex +} + +// NewBufferLRU creates a new BufferLRU with the given maximum size. The maximum +// size will never be exceeded. +func NewBufferLRU(maxSize FileSize) *BufferLRU { + return &BufferLRU{MaxSize: maxSize} +} + +// NewBufferLRUDefault creates a new BufferLRU with the default cache size. +func NewBufferLRUDefault() *BufferLRU { + return &BufferLRU{MaxSize: DefaultMaxSize} +} + +type buffer struct { + Key int64 + Slice []byte +} + +// Put puts a buffer into the cache. If the buffer is already in the cache, it +// will be marked as used. Otherwise, it will be inserted. A buffers might +// be evicted to make room for the new one. +func (c *BufferLRU) Put(key int64, slice []byte) { + c.mut.Lock() + defer c.mut.Unlock() + + if c.cache == nil { + c.actualSize = 0 + c.cache = make(map[int64]*list.Element, 1000) + c.ll = list.New() + } + + bufSize := FileSize(len(slice)) + if ee, ok := c.cache[key]; ok { + oldBuf := ee.Value.(buffer) + // in this case bufSize is a delta: new size - old size + bufSize -= FileSize(len(oldBuf.Slice)) + c.ll.MoveToFront(ee) + ee.Value = buffer{key, slice} + } else { + if bufSize > c.MaxSize { + return + } + ee := c.ll.PushFront(buffer{key, slice}) + c.cache[key] = ee + } + + c.actualSize += bufSize + for c.actualSize > c.MaxSize { + last := c.ll.Back() + lastObj := last.Value.(buffer) + lastSize := FileSize(len(lastObj.Slice)) + + c.ll.Remove(last) + delete(c.cache, lastObj.Key) + c.actualSize -= lastSize + } +} + +// Get returns a buffer by its key. It marks the buffer as used. If the buffer +// is not in the cache, (nil, false) will be returned. +func (c *BufferLRU) Get(key int64) ([]byte, bool) { + c.mut.Lock() + defer c.mut.Unlock() + + ee, ok := c.cache[key] + if !ok { + return nil, false + } + + c.ll.MoveToFront(ee) + return ee.Value.(buffer).Slice, true +} + +// Clear the content of this buffer cache. +func (c *BufferLRU) Clear() { + c.mut.Lock() + defer c.mut.Unlock() + + c.ll = nil + c.cache = nil + c.actualSize = 0 +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/cache/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/cache/common.go new file mode 100644 index 00000000..abf7a085 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/cache/common.go @@ -0,0 +1,39 @@ +package cache + +import "github.com/devtron-labs/go-git/plumbing" + +const ( + Byte FileSize = 1 << (iota * 10) + KiByte + MiByte + GiByte +) + +type FileSize int64 + +const DefaultMaxSize FileSize = 96 * MiByte + +// Object is an interface to a object cache. +type Object interface { + // Put puts the given object into the cache. Whether this object will + // actually be put into the cache or not is implementation specific. + Put(o plumbing.EncodedObject) + // Get gets an object from the cache given its hash. The second return value + // is true if the object was returned, and false otherwise. + Get(k plumbing.Hash) (plumbing.EncodedObject, bool) + // Clear clears every object from the cache. + Clear() +} + +// Buffer is an interface to a buffer cache. +type Buffer interface { + // Put puts a buffer into the cache. If the buffer is already in the cache, + // it will be marked as used. Otherwise, it will be inserted. Buffer might + // be evicted to make room for the new one. + Put(key int64, slice []byte) + // Get returns a buffer by its key. It marks the buffer as used. If the + // buffer is not in the cache, (nil, false) will be returned. + Get(key int64) ([]byte, bool) + // Clear clears every object from the cache. + Clear() +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/cache/object_lru.go b/vendor/github.com/devtron-labs/go-git/plumbing/cache/object_lru.go new file mode 100644 index 00000000..1efbe714 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/cache/object_lru.go @@ -0,0 +1,101 @@ +package cache + +import ( + "container/list" + "sync" + + "github.com/devtron-labs/go-git/plumbing" +) + +// ObjectLRU implements an object cache with an LRU eviction policy and a +// maximum size (measured in object size). +type ObjectLRU struct { + MaxSize FileSize + + actualSize FileSize + ll *list.List + cache map[interface{}]*list.Element + mut sync.Mutex +} + +// NewObjectLRU creates a new ObjectLRU with the given maximum size. The maximum +// size will never be exceeded. +func NewObjectLRU(maxSize FileSize) *ObjectLRU { + return &ObjectLRU{MaxSize: maxSize} +} + +// NewObjectLRUDefault creates a new ObjectLRU with the default cache size. +func NewObjectLRUDefault() *ObjectLRU { + return &ObjectLRU{MaxSize: DefaultMaxSize} +} + +// Put puts an object into the cache. If the object is already in the cache, it +// will be marked as used. Otherwise, it will be inserted. A single object might +// be evicted to make room for the new object. +func (c *ObjectLRU) Put(obj plumbing.EncodedObject) { + c.mut.Lock() + defer c.mut.Unlock() + + if c.cache == nil { + c.actualSize = 0 + c.cache = make(map[interface{}]*list.Element, 1000) + c.ll = list.New() + } + + objSize := FileSize(obj.Size()) + key := obj.Hash() + if ee, ok := c.cache[key]; ok { + oldObj := ee.Value.(plumbing.EncodedObject) + // in this case objSize is a delta: new size - old size + objSize -= FileSize(oldObj.Size()) + c.ll.MoveToFront(ee) + ee.Value = obj + } else { + if objSize > c.MaxSize { + return + } + ee := c.ll.PushFront(obj) + c.cache[key] = ee + } + + c.actualSize += objSize + for c.actualSize > c.MaxSize { + last := c.ll.Back() + if last == nil { + c.actualSize = 0 + break + } + + lastObj := last.Value.(plumbing.EncodedObject) + lastSize := FileSize(lastObj.Size()) + + c.ll.Remove(last) + delete(c.cache, lastObj.Hash()) + c.actualSize -= lastSize + } +} + +// Get returns an object by its hash. It marks the object as used. If the object +// is not in the cache, (nil, false) will be returned. +func (c *ObjectLRU) Get(k plumbing.Hash) (plumbing.EncodedObject, bool) { + c.mut.Lock() + defer c.mut.Unlock() + + ee, ok := c.cache[k] + if !ok { + return nil, false + } + + c.ll.MoveToFront(ee) + return ee.Value.(plumbing.EncodedObject), true +} + +// Clear the content of this object cache. +func (c *ObjectLRU) Clear() { + c.mut.Lock() + defer c.mut.Unlock() + + c.ll = nil + c.cache = nil + c.actualSize = 0 +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/dir.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/dir.go new file mode 100644 index 00000000..0792a0ed --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/dir.go @@ -0,0 +1,136 @@ +package gitignore + +import ( + "bytes" + "io/ioutil" + "os" + "os/user" + "strings" + + "github.com/devtron-labs/go-git/plumbing/format/config" + gioutil "github.com/devtron-labs/go-git/utils/ioutil" + "gopkg.in/src-d/go-billy.v4" +) + +const ( + commentPrefix = "#" + coreSection = "core" + eol = "\n" + excludesfile = "excludesfile" + gitDir = ".git" + gitignoreFile = ".gitignore" + gitconfigFile = ".gitconfig" + systemFile = "/etc/gitconfig" +) + +// readIgnoreFile reads a specific git ignore file. +func readIgnoreFile(fs billy.Filesystem, path []string, ignoreFile string) (ps []Pattern, err error) { + f, err := fs.Open(fs.Join(append(path, ignoreFile)...)) + if err == nil { + defer f.Close() + + if data, err := ioutil.ReadAll(f); err == nil { + for _, s := range strings.Split(string(data), eol) { + if !strings.HasPrefix(s, commentPrefix) && len(strings.TrimSpace(s)) > 0 { + ps = append(ps, ParsePattern(s, path)) + } + } + } + } else if !os.IsNotExist(err) { + return nil, err + } + + return +} + +// ReadPatterns reads gitignore patterns recursively traversing through the directory +// structure. The result is in the ascending order of priority (last higher). +func ReadPatterns(fs billy.Filesystem, path []string) (ps []Pattern, err error) { + ps, _ = readIgnoreFile(fs, path, gitignoreFile) + + var fis []os.FileInfo + fis, err = fs.ReadDir(fs.Join(path...)) + if err != nil { + return + } + + for _, fi := range fis { + if fi.IsDir() && fi.Name() != gitDir { + var subps []Pattern + subps, err = ReadPatterns(fs, append(path, fi.Name())) + if err != nil { + return + } + + if len(subps) > 0 { + ps = append(ps, subps...) + } + } + } + + return +} + +func loadPatterns(fs billy.Filesystem, path string) (ps []Pattern, err error) { + f, err := fs.Open(path) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + + defer gioutil.CheckClose(f, &err) + + b, err := ioutil.ReadAll(f) + if err != nil { + return + } + + d := config.NewDecoder(bytes.NewBuffer(b)) + + raw := config.New() + if err = d.Decode(raw); err != nil { + return + } + + s := raw.Section(coreSection) + efo := s.Options.Get(excludesfile) + if efo == "" { + return nil, nil + } + + ps, err = readIgnoreFile(fs, nil, efo) + if os.IsNotExist(err) { + return nil, nil + } + + return +} + +// LoadGlobalPatterns loads gitignore patterns from from the gitignore file +// declared in a user's ~/.gitconfig file. If the ~/.gitconfig file does not +// exist the function will return nil. If the core.excludesfile property +// is not declared, the function will return nil. If the file pointed to by +// the core.excludesfile property does not exist, the function will return nil. +// +// The function assumes fs is rooted at the root filesystem. +func LoadGlobalPatterns(fs billy.Filesystem) (ps []Pattern, err error) { + usr, err := user.Current() + if err != nil { + return + } + + return loadPatterns(fs, fs.Join(usr.HomeDir, gitconfigFile)) +} + +// LoadSystemPatterns loads gitignore patterns from from the gitignore file +// declared in a system's /etc/gitconfig file. If the ~/.gitconfig file does +// not exist the function will return nil. If the core.excludesfile property +// is not declared, the function will return nil. If the file pointed to by +// the core.excludesfile property does not exist, the function will return nil. +// +// The function assumes fs is rooted at the root filesystem. +func LoadSystemPatterns(fs billy.Filesystem) (ps []Pattern, err error) { + return loadPatterns(fs, systemFile) +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/doc.go new file mode 100644 index 00000000..eecd4bac --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/doc.go @@ -0,0 +1,70 @@ +// Package gitignore implements matching file system paths to gitignore patterns that +// can be automatically read from a git repository tree in the order of definition +// priorities. It support all pattern formats as specified in the original gitignore +// documentation, copied below: +// +// Pattern format +// ============== +// +// - A blank line matches no files, so it can serve as a separator for readability. +// +// - A line starting with # serves as a comment. Put a backslash ("\") in front of +// the first hash for patterns that begin with a hash. +// +// - Trailing spaces are ignored unless they are quoted with backslash ("\"). +// +// - An optional prefix "!" which negates the pattern; any matching file excluded +// by a previous pattern will become included again. It is not possible to +// re-include a file if a parent directory of that file is excluded. +// Git doesn’t list excluded directories for performance reasons, so +// any patterns on contained files have no effect, no matter where they are +// defined. Put a backslash ("\") in front of the first "!" for patterns +// that begin with a literal "!", for example, "\!important!.txt". +// +// - If the pattern ends with a slash, it is removed for the purpose of the +// following description, but it would only find a match with a directory. +// In other words, foo/ will match a directory foo and paths underneath it, +// but will not match a regular file or a symbolic link foo (this is consistent +// with the way how pathspec works in general in Git). +// +// - If the pattern does not contain a slash /, Git treats it as a shell glob +// pattern and checks for a match against the pathname relative to the location +// of the .gitignore file (relative to the toplevel of the work tree if not +// from a .gitignore file). +// +// - Otherwise, Git treats the pattern as a shell glob suitable for consumption +// by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will +// not match a / in the pathname. For example, "Documentation/*.html" matches +// "Documentation/git.html" but not "Documentation/ppc/ppc.html" or +// "tools/perf/Documentation/perf.html". +// +// - A leading slash matches the beginning of the pathname. For example, +// "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". +// +// Two consecutive asterisks ("**") in patterns matched against full pathname +// may have special meaning: +// +// - A leading "**" followed by a slash means match in all directories. +// For example, "**/foo" matches file or directory "foo" anywhere, the same as +// pattern "foo". "**/foo/bar" matches file or directory "bar" +// anywhere that is directly under directory "foo". +// +// - A trailing "/**" matches everything inside. For example, "abc/**" matches +// all files inside directory "abc", relative to the location of the +// .gitignore file, with infinite depth. +// +// - A slash followed by two consecutive asterisks then a slash matches +// zero or more directories. For example, "a/**/b" matches "a/b", "a/x/b", +// "a/x/y/b" and so on. +// +// - Other consecutive asterisks are considered invalid. +// +// Copyright and license +// ===================== +// +// Copyright (c) Oleg Sklyar, Silvertern and source{d} +// +// The package code was donated to source{d} to include, modify and develop +// further as a part of the `go-git` project, release it on the license of +// the whole project or delete it from the project. +package gitignore diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/matcher.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/matcher.go new file mode 100644 index 00000000..bd1e9e2d --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/matcher.go @@ -0,0 +1,30 @@ +package gitignore + +// Matcher defines a global multi-pattern matcher for gitignore patterns +type Matcher interface { + // Match matches patterns in the order of priorities. As soon as an inclusion or + // exclusion is found, not further matching is performed. + Match(path []string, isDir bool) bool +} + +// NewMatcher constructs a new global matcher. Patterns must be given in the order of +// increasing priority. That is most generic settings files first, then the content of +// the repo .gitignore, then content of .gitignore down the path or the repo and then +// the content command line arguments. +func NewMatcher(ps []Pattern) Matcher { + return &matcher{ps} +} + +type matcher struct { + patterns []Pattern +} + +func (m *matcher) Match(path []string, isDir bool) bool { + n := len(m.patterns) + for i := n - 1; i >= 0; i-- { + if match := m.patterns[i].Match(path, isDir); match > NoMatch { + return match == Exclude + } + } + return false +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/pattern.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/pattern.go new file mode 100644 index 00000000..098cb502 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/gitignore/pattern.go @@ -0,0 +1,153 @@ +package gitignore + +import ( + "path/filepath" + "strings" +) + +// MatchResult defines outcomes of a match, no match, exclusion or inclusion. +type MatchResult int + +const ( + // NoMatch defines the no match outcome of a match check + NoMatch MatchResult = iota + // Exclude defines an exclusion of a file as a result of a match check + Exclude + // Include defines an explicit inclusion of a file as a result of a match check + Include +) + +const ( + inclusionPrefix = "!" + zeroToManyDirs = "**" + patternDirSep = "/" +) + +// Pattern defines a single gitignore pattern. +type Pattern interface { + // Match matches the given path to the pattern. + Match(path []string, isDir bool) MatchResult +} + +type pattern struct { + domain []string + pattern []string + inclusion bool + dirOnly bool + isGlob bool +} + +// ParsePattern parses a gitignore pattern string into the Pattern structure. +func ParsePattern(p string, domain []string) Pattern { + res := pattern{domain: domain} + + if strings.HasPrefix(p, inclusionPrefix) { + res.inclusion = true + p = p[1:] + } + + if !strings.HasSuffix(p, "\\ ") { + p = strings.TrimRight(p, " ") + } + + if strings.HasSuffix(p, patternDirSep) { + res.dirOnly = true + p = p[:len(p)-1] + } + + if strings.Contains(p, patternDirSep) { + res.isGlob = true + } + + res.pattern = strings.Split(p, patternDirSep) + return &res +} + +func (p *pattern) Match(path []string, isDir bool) MatchResult { + if len(path) <= len(p.domain) { + return NoMatch + } + for i, e := range p.domain { + if path[i] != e { + return NoMatch + } + } + + path = path[len(p.domain):] + if p.isGlob && !p.globMatch(path, isDir) { + return NoMatch + } else if !p.isGlob && !p.simpleNameMatch(path, isDir) { + return NoMatch + } + + if p.inclusion { + return Include + } else { + return Exclude + } +} + +func (p *pattern) simpleNameMatch(path []string, isDir bool) bool { + for i, name := range path { + if match, err := filepath.Match(p.pattern[0], name); err != nil { + return false + } else if !match { + continue + } + if p.dirOnly && !isDir && i == len(path)-1 { + return false + } + return true + } + return false +} + +func (p *pattern) globMatch(path []string, isDir bool) bool { + matched := false + canTraverse := false + for i, pattern := range p.pattern { + if pattern == "" { + canTraverse = false + continue + } + if pattern == zeroToManyDirs { + if i == len(p.pattern)-1 { + break + } + canTraverse = true + continue + } + if strings.Contains(pattern, zeroToManyDirs) { + return false + } + if len(path) == 0 { + return false + } + if canTraverse { + canTraverse = false + for len(path) > 0 { + e := path[0] + path = path[1:] + if match, err := filepath.Match(pattern, e); err != nil { + return false + } else if match { + matched = true + break + } else if len(path) == 0 { + // if nothing left then fail + matched = false + } + } + } else { + if match, err := filepath.Match(pattern, path[0]); err != nil || !match { + return false + } + matched = true + path = path[1:] + } + } + if matched && p.dirOnly && !isDir && len(path) == 0 { + matched = false + } + return matched +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/decoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/decoder.go new file mode 100644 index 00000000..607fbec1 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/decoder.go @@ -0,0 +1,177 @@ +package idxfile + +import ( + "bufio" + "bytes" + "errors" + "io" + + "github.com/devtron-labs/go-git/utils/binary" +) + +var ( + // ErrUnsupportedVersion is returned by Decode when the idx file version + // is not supported. + ErrUnsupportedVersion = errors.New("Unsuported version") + // ErrMalformedIdxFile is returned by Decode when the idx file is corrupted. + ErrMalformedIdxFile = errors.New("Malformed IDX file") +) + +const ( + fanout = 256 + objectIDLength = 20 +) + +// Decoder reads and decodes idx files from an input stream. +type Decoder struct { + *bufio.Reader +} + +// NewDecoder builds a new idx stream decoder, that reads from r. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{bufio.NewReader(r)} +} + +// Decode reads from the stream and decode the content into the MemoryIndex struct. +func (d *Decoder) Decode(idx *MemoryIndex) error { + if err := validateHeader(d); err != nil { + return err + } + + flow := []func(*MemoryIndex, io.Reader) error{ + readVersion, + readFanout, + readObjectNames, + readCRC32, + readOffsets, + readChecksums, + } + + for _, f := range flow { + if err := f(idx, d); err != nil { + return err + } + } + + return nil +} + +func validateHeader(r io.Reader) error { + var h = make([]byte, 4) + if _, err := io.ReadFull(r, h); err != nil { + return err + } + + if !bytes.Equal(h, idxHeader) { + return ErrMalformedIdxFile + } + + return nil +} + +func readVersion(idx *MemoryIndex, r io.Reader) error { + v, err := binary.ReadUint32(r) + if err != nil { + return err + } + + if v > VersionSupported { + return ErrUnsupportedVersion + } + + idx.Version = v + return nil +} + +func readFanout(idx *MemoryIndex, r io.Reader) error { + for k := 0; k < fanout; k++ { + n, err := binary.ReadUint32(r) + if err != nil { + return err + } + + idx.Fanout[k] = n + idx.FanoutMapping[k] = noMapping + } + + return nil +} + +func readObjectNames(idx *MemoryIndex, r io.Reader) error { + for k := 0; k < fanout; k++ { + var buckets uint32 + if k == 0 { + buckets = idx.Fanout[k] + } else { + buckets = idx.Fanout[k] - idx.Fanout[k-1] + } + + if buckets == 0 { + continue + } + + idx.FanoutMapping[k] = len(idx.Names) + + nameLen := int(buckets * objectIDLength) + bin := make([]byte, nameLen) + if _, err := io.ReadFull(r, bin); err != nil { + return err + } + + idx.Names = append(idx.Names, bin) + idx.Offset32 = append(idx.Offset32, make([]byte, buckets*4)) + idx.CRC32 = append(idx.CRC32, make([]byte, buckets*4)) + } + + return nil +} + +func readCRC32(idx *MemoryIndex, r io.Reader) error { + for k := 0; k < fanout; k++ { + if pos := idx.FanoutMapping[k]; pos != noMapping { + if _, err := io.ReadFull(r, idx.CRC32[pos]); err != nil { + return err + } + } + } + + return nil +} + +func readOffsets(idx *MemoryIndex, r io.Reader) error { + var o64cnt int + for k := 0; k < fanout; k++ { + if pos := idx.FanoutMapping[k]; pos != noMapping { + if _, err := io.ReadFull(r, idx.Offset32[pos]); err != nil { + return err + } + + for p := 0; p < len(idx.Offset32[pos]); p += 4 { + if idx.Offset32[pos][p]&(byte(1)<<7) > 0 { + o64cnt++ + } + } + } + } + + if o64cnt > 0 { + idx.Offset64 = make([]byte, o64cnt*8) + if _, err := io.ReadFull(r, idx.Offset64); err != nil { + return err + } + } + + return nil +} + +func readChecksums(idx *MemoryIndex, r io.Reader) error { + if _, err := io.ReadFull(r, idx.PackfileChecksum[:]); err != nil { + return err + } + + if _, err := io.ReadFull(r, idx.IdxChecksum[:]); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/doc.go new file mode 100644 index 00000000..1e628ab4 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/doc.go @@ -0,0 +1,128 @@ +// Package idxfile implements encoding and decoding of packfile idx files. +// +// == Original (version 1) pack-*.idx files have the following format: +// +// - The header consists of 256 4-byte network byte order +// integers. N-th entry of this table records the number of +// objects in the corresponding pack, the first byte of whose +// object name is less than or equal to N. This is called the +// 'first-level fan-out' table. +// +// - The header is followed by sorted 24-byte entries, one entry +// per object in the pack. Each entry is: +// +// 4-byte network byte order integer, recording where the +// object is stored in the packfile as the offset from the +// beginning. +// +// 20-byte object name. +// +// - The file is concluded with a trailer: +// +// A copy of the 20-byte SHA1 checksum at the end of +// corresponding packfile. +// +// 20-byte SHA1-checksum of all of the above. +// +// Pack Idx file: +// +// -- +--------------------------------+ +// fanout | fanout[0] = 2 (for example) |-. +// table +--------------------------------+ | +// | fanout[1] | | +// +--------------------------------+ | +// | fanout[2] | | +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | +// | fanout[255] = total objects |---. +// -- +--------------------------------+ | | +// main | offset | | | +// index | object name 00XXXXXXXXXXXXXXXX | | | +// tab +--------------------------------+ | | +// | offset | | | +// | object name 00XXXXXXXXXXXXXXXX | | | +// +--------------------------------+<+ | +// .-| offset | | +// | | object name 01XXXXXXXXXXXXXXXX | | +// | +--------------------------------+ | +// | | offset | | +// | | object name 01XXXXXXXXXXXXXXXX | | +// | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | +// | | offset | | +// | | object name FFXXXXXXXXXXXXXXXX | | +// --| +--------------------------------+<--+ +// trailer | | packfile checksum | +// | +--------------------------------+ +// | | idxfile checksum | +// | +--------------------------------+ +// .---------. +// | +// Pack file entry: <+ +// +// packed object header: +// 1-byte size extension bit (MSB) +// type (next 3 bit) +// size0 (lower 4-bit) +// n-byte sizeN (as long as MSB is set, each 7-bit) +// size0..sizeN form 4+7+7+..+7 bit integer, size0 +// is the least significant part, and sizeN is the +// most significant part. +// packed object data: +// If it is not DELTA, then deflated bytes (the size above +// is the size before compression). +// If it is REF_DELTA, then +// 20-byte base object name SHA1 (the size above is the +// size of the delta data that follows). +// delta data, deflated. +// If it is OFS_DELTA, then +// n-byte offset (see below) interpreted as a negative +// offset from the type-byte of the header of the +// ofs-delta entry (the size above is the size of +// the delta data that follows). +// delta data, deflated. +// +// offset encoding: +// n bytes with MSB set in all but the last one. +// The offset is then the number constructed by +// concatenating the lower 7 bit of each byte, and +// for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1)) +// to the result. +// +// == Version 2 pack-*.idx files support packs larger than 4 GiB, and +// have some other reorganizations. They have the format: +// +// - A 4-byte magic number '\377tOc' which is an unreasonable +// fanout[0] value. +// +// - A 4-byte version number (= 2) +// +// - A 256-entry fan-out table just like v1. +// +// - A table of sorted 20-byte SHA1 object names. These are +// packed together without offset values to reduce the cache +// footprint of the binary search for a specific object name. +// +// - A table of 4-byte CRC32 values of the packed object data. +// This is new in v2 so compressed data can be copied directly +// from pack to pack during repacking without undetected +// data corruption. +// +// - A table of 4-byte offset values (in network byte order). +// These are usually 31-bit pack file offsets, but large +// offsets are encoded as an index into the next table with +// the msbit set. +// +// - A table of 8-byte offset entries (empty for pack files less +// than 2 GiB). Pack files are organized with heavily used +// objects toward the front, so most object references should +// not need to refer to this table. +// +// - The same trailer as a v1 pack file: +// +// A copy of the 20-byte SHA1 checksum at the end of +// corresponding packfile. +// +// 20-byte SHA1-checksum of all of the above. +// +// Source: +// https://www.kernel.org/pub/software/scm/git/docs/v1.7.5/technical/pack-format.txt +package idxfile diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/encoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/encoder.go new file mode 100644 index 00000000..0eecfa5f --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/encoder.go @@ -0,0 +1,142 @@ +package idxfile + +import ( + "crypto/sha1" + "hash" + "io" + + "github.com/devtron-labs/go-git/utils/binary" +) + +// Encoder writes MemoryIndex structs to an output stream. +type Encoder struct { + io.Writer + hash hash.Hash +} + +// NewEncoder returns a new stream encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + h := sha1.New() + mw := io.MultiWriter(w, h) + return &Encoder{mw, h} +} + +// Encode encodes an MemoryIndex to the encoder writer. +func (e *Encoder) Encode(idx *MemoryIndex) (int, error) { + flow := []func(*MemoryIndex) (int, error){ + e.encodeHeader, + e.encodeFanout, + e.encodeHashes, + e.encodeCRC32, + e.encodeOffsets, + e.encodeChecksums, + } + + sz := 0 + for _, f := range flow { + i, err := f(idx) + sz += i + + if err != nil { + return sz, err + } + } + + return sz, nil +} + +func (e *Encoder) encodeHeader(idx *MemoryIndex) (int, error) { + c, err := e.Write(idxHeader) + if err != nil { + return c, err + } + + return c + 4, binary.WriteUint32(e, idx.Version) +} + +func (e *Encoder) encodeFanout(idx *MemoryIndex) (int, error) { + for _, c := range idx.Fanout { + if err := binary.WriteUint32(e, c); err != nil { + return 0, err + } + } + + return fanout * 4, nil +} + +func (e *Encoder) encodeHashes(idx *MemoryIndex) (int, error) { + var size int + for k := 0; k < fanout; k++ { + pos := idx.FanoutMapping[k] + if pos == noMapping { + continue + } + + n, err := e.Write(idx.Names[pos]) + if err != nil { + return size, err + } + size += n + } + return size, nil +} + +func (e *Encoder) encodeCRC32(idx *MemoryIndex) (int, error) { + var size int + for k := 0; k < fanout; k++ { + pos := idx.FanoutMapping[k] + if pos == noMapping { + continue + } + + n, err := e.Write(idx.CRC32[pos]) + if err != nil { + return size, err + } + + size += n + } + + return size, nil +} + +func (e *Encoder) encodeOffsets(idx *MemoryIndex) (int, error) { + var size int + for k := 0; k < fanout; k++ { + pos := idx.FanoutMapping[k] + if pos == noMapping { + continue + } + + n, err := e.Write(idx.Offset32[pos]) + if err != nil { + return size, err + } + + size += n + } + + if len(idx.Offset64) > 0 { + n, err := e.Write(idx.Offset64) + if err != nil { + return size, err + } + + size += n + } + + return size, nil +} + +func (e *Encoder) encodeChecksums(idx *MemoryIndex) (int, error) { + if _, err := e.Write(idx.PackfileChecksum[:]); err != nil { + return 0, err + } + + copy(idx.IdxChecksum[:], e.hash.Sum(nil)[:20]) + if _, err := e.Write(idx.IdxChecksum[:]); err != nil { + return 0, err + } + + return 40, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/idxfile.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/idxfile.go new file mode 100644 index 00000000..4a75d872 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/idxfile.go @@ -0,0 +1,346 @@ +package idxfile + +import ( + "bytes" + "io" + "sort" + + encbin "encoding/binary" + + "github.com/devtron-labs/go-git/plumbing" +) + +const ( + // VersionSupported is the only idx version supported. + VersionSupported = 2 + + noMapping = -1 +) + +var ( + idxHeader = []byte{255, 't', 'O', 'c'} +) + +// Index represents an index of a packfile. +type Index interface { + // Contains checks whether the given hash is in the index. + Contains(h plumbing.Hash) (bool, error) + // FindOffset finds the offset in the packfile for the object with + // the given hash. + FindOffset(h plumbing.Hash) (int64, error) + // FindCRC32 finds the CRC32 of the object with the given hash. + FindCRC32(h plumbing.Hash) (uint32, error) + // FindHash finds the hash for the object with the given offset. + FindHash(o int64) (plumbing.Hash, error) + // Count returns the number of entries in the index. + Count() (int64, error) + // Entries returns an iterator to retrieve all index entries. + Entries() (EntryIter, error) + // EntriesByOffset returns an iterator to retrieve all index entries ordered + // by offset. + EntriesByOffset() (EntryIter, error) +} + +// MemoryIndex is the in memory representation of an idx file. +type MemoryIndex struct { + Version uint32 + Fanout [256]uint32 + // FanoutMapping maps the position in the fanout table to the position + // in the Names, Offset32 and CRC32 slices. This improves the memory + // usage by not needing an array with unnecessary empty slots. + FanoutMapping [256]int + Names [][]byte + Offset32 [][]byte + CRC32 [][]byte + Offset64 []byte + PackfileChecksum [20]byte + IdxChecksum [20]byte + + offsetHash map[int64]plumbing.Hash + offsetHashIsFull bool +} + +var _ Index = (*MemoryIndex)(nil) + +// NewMemoryIndex returns an instance of a new MemoryIndex. +func NewMemoryIndex() *MemoryIndex { + return &MemoryIndex{} +} + +func (idx *MemoryIndex) findHashIndex(h plumbing.Hash) (int, bool) { + k := idx.FanoutMapping[h[0]] + if k == noMapping { + return 0, false + } + + if len(idx.Names) <= k { + return 0, false + } + + data := idx.Names[k] + high := uint64(len(idx.Offset32[k])) >> 2 + if high == 0 { + return 0, false + } + + low := uint64(0) + for { + mid := (low + high) >> 1 + offset := mid * objectIDLength + + cmp := bytes.Compare(h[:], data[offset:offset+objectIDLength]) + if cmp < 0 { + high = mid + } else if cmp == 0 { + return int(mid), true + } else { + low = mid + 1 + } + + if low >= high { + break + } + } + + return 0, false +} + +// Contains implements the Index interface. +func (idx *MemoryIndex) Contains(h plumbing.Hash) (bool, error) { + _, ok := idx.findHashIndex(h) + return ok, nil +} + +// FindOffset implements the Index interface. +func (idx *MemoryIndex) FindOffset(h plumbing.Hash) (int64, error) { + if len(idx.FanoutMapping) <= int(h[0]) { + return 0, plumbing.ErrObjectNotFound + } + + k := idx.FanoutMapping[h[0]] + i, ok := idx.findHashIndex(h) + if !ok { + return 0, plumbing.ErrObjectNotFound + } + + offset := idx.getOffset(k, i) + + if !idx.offsetHashIsFull { + // Save the offset for reverse lookup + if idx.offsetHash == nil { + idx.offsetHash = make(map[int64]plumbing.Hash) + } + idx.offsetHash[int64(offset)] = h + } + + return int64(offset), nil +} + +const isO64Mask = uint64(1) << 31 + +func (idx *MemoryIndex) getOffset(firstLevel, secondLevel int) uint64 { + offset := secondLevel << 2 + ofs := encbin.BigEndian.Uint32(idx.Offset32[firstLevel][offset : offset+4]) + + if (uint64(ofs) & isO64Mask) != 0 { + offset := 8 * (uint64(ofs) & ^isO64Mask) + n := encbin.BigEndian.Uint64(idx.Offset64[offset : offset+8]) + return n + } + + return uint64(ofs) +} + +// FindCRC32 implements the Index interface. +func (idx *MemoryIndex) FindCRC32(h plumbing.Hash) (uint32, error) { + k := idx.FanoutMapping[h[0]] + i, ok := idx.findHashIndex(h) + if !ok { + return 0, plumbing.ErrObjectNotFound + } + + return idx.getCRC32(k, i), nil +} + +func (idx *MemoryIndex) getCRC32(firstLevel, secondLevel int) uint32 { + offset := secondLevel << 2 + return encbin.BigEndian.Uint32(idx.CRC32[firstLevel][offset : offset+4]) +} + +// FindHash implements the Index interface. +func (idx *MemoryIndex) FindHash(o int64) (plumbing.Hash, error) { + var hash plumbing.Hash + var ok bool + + if idx.offsetHash != nil { + if hash, ok = idx.offsetHash[o]; ok { + return hash, nil + } + } + + // Lazily generate the reverse offset/hash map if required. + if !idx.offsetHashIsFull || idx.offsetHash == nil { + if err := idx.genOffsetHash(); err != nil { + return plumbing.ZeroHash, err + } + + hash, ok = idx.offsetHash[o] + } + + if !ok { + return plumbing.ZeroHash, plumbing.ErrObjectNotFound + } + + return hash, nil +} + +// genOffsetHash generates the offset/hash mapping for reverse search. +func (idx *MemoryIndex) genOffsetHash() error { + count, err := idx.Count() + if err != nil { + return err + } + + idx.offsetHash = make(map[int64]plumbing.Hash, count) + idx.offsetHashIsFull = true + + var hash plumbing.Hash + i := uint32(0) + for firstLevel, fanoutValue := range idx.Fanout { + mappedFirstLevel := idx.FanoutMapping[firstLevel] + for secondLevel := uint32(0); i < fanoutValue; i++ { + copy(hash[:], idx.Names[mappedFirstLevel][secondLevel*objectIDLength:]) + offset := int64(idx.getOffset(mappedFirstLevel, int(secondLevel))) + idx.offsetHash[offset] = hash + secondLevel++ + } + } + + return nil +} + +// Count implements the Index interface. +func (idx *MemoryIndex) Count() (int64, error) { + return int64(idx.Fanout[fanout-1]), nil +} + +// Entries implements the Index interface. +func (idx *MemoryIndex) Entries() (EntryIter, error) { + return &idxfileEntryIter{idx, 0, 0, 0}, nil +} + +// EntriesByOffset implements the Index interface. +func (idx *MemoryIndex) EntriesByOffset() (EntryIter, error) { + count, err := idx.Count() + if err != nil { + return nil, err + } + + iter := &idxfileEntryOffsetIter{ + entries: make(entriesByOffset, count), + } + + entries, err := idx.Entries() + if err != nil { + return nil, err + } + + for pos := 0; int64(pos) < count; pos++ { + entry, err := entries.Next() + if err != nil { + return nil, err + } + + iter.entries[pos] = entry + } + + sort.Sort(iter.entries) + + return iter, nil +} + +// EntryIter is an iterator that will return the entries in a packfile index. +type EntryIter interface { + // Next returns the next entry in the packfile index. + Next() (*Entry, error) + // Close closes the iterator. + Close() error +} + +type idxfileEntryIter struct { + idx *MemoryIndex + total int + firstLevel, secondLevel int +} + +func (i *idxfileEntryIter) Next() (*Entry, error) { + for { + if i.firstLevel >= fanout { + return nil, io.EOF + } + + if i.total >= int(i.idx.Fanout[i.firstLevel]) { + i.firstLevel++ + i.secondLevel = 0 + continue + } + + mappedFirstLevel := i.idx.FanoutMapping[i.firstLevel] + entry := new(Entry) + copy(entry.Hash[:], i.idx.Names[mappedFirstLevel][i.secondLevel*objectIDLength:]) + entry.Offset = i.idx.getOffset(mappedFirstLevel, i.secondLevel) + entry.CRC32 = i.idx.getCRC32(mappedFirstLevel, i.secondLevel) + + i.secondLevel++ + i.total++ + + return entry, nil + } +} + +func (i *idxfileEntryIter) Close() error { + i.firstLevel = fanout + return nil +} + +// Entry is the in memory representation of an object entry in the idx file. +type Entry struct { + Hash plumbing.Hash + CRC32 uint32 + Offset uint64 +} + +type idxfileEntryOffsetIter struct { + entries entriesByOffset + pos int +} + +func (i *idxfileEntryOffsetIter) Next() (*Entry, error) { + if i.pos >= len(i.entries) { + return nil, io.EOF + } + + entry := i.entries[i.pos] + i.pos++ + + return entry, nil +} + +func (i *idxfileEntryOffsetIter) Close() error { + i.pos = len(i.entries) + 1 + return nil +} + +type entriesByOffset []*Entry + +func (o entriesByOffset) Len() int { + return len(o) +} + +func (o entriesByOffset) Less(i int, j int) bool { + return o[i].Offset < o[j].Offset +} + +func (o entriesByOffset) Swap(i int, j int) { + o[i], o[j] = o[j], o[i] +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/writer.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/writer.go new file mode 100644 index 00000000..f1ff02e8 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/idxfile/writer.go @@ -0,0 +1,186 @@ +package idxfile + +import ( + "bytes" + "fmt" + "math" + "sort" + "sync" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/utils/binary" +) + +// objects implements sort.Interface and uses hash as sorting key. +type objects []Entry + +// Writer implements a packfile Observer interface and is used to generate +// indexes. +type Writer struct { + m sync.Mutex + + count uint32 + checksum plumbing.Hash + objects objects + offset64 uint32 + finished bool + index *MemoryIndex + added map[plumbing.Hash]struct{} +} + +// Index returns a previously created MemoryIndex or creates a new one if +// needed. +func (w *Writer) Index() (*MemoryIndex, error) { + w.m.Lock() + defer w.m.Unlock() + + if w.index == nil { + return w.createIndex() + } + + return w.index, nil +} + +// Add appends new object data. +func (w *Writer) Add(h plumbing.Hash, pos uint64, crc uint32) { + w.m.Lock() + defer w.m.Unlock() + + if w.added == nil { + w.added = make(map[plumbing.Hash]struct{}) + } + + if _, ok := w.added[h]; !ok { + w.added[h] = struct{}{} + w.objects = append(w.objects, Entry{h, crc, pos}) + } + +} + +func (w *Writer) Finished() bool { + return w.finished +} + +// OnHeader implements packfile.Observer interface. +func (w *Writer) OnHeader(count uint32) error { + w.count = count + w.objects = make(objects, 0, count) + return nil +} + +// OnInflatedObjectHeader implements packfile.Observer interface. +func (w *Writer) OnInflatedObjectHeader(t plumbing.ObjectType, objSize int64, pos int64) error { + return nil +} + +// OnInflatedObjectContent implements packfile.Observer interface. +func (w *Writer) OnInflatedObjectContent(h plumbing.Hash, pos int64, crc uint32, _ []byte) error { + w.Add(h, uint64(pos), crc) + return nil +} + +// OnFooter implements packfile.Observer interface. +func (w *Writer) OnFooter(h plumbing.Hash) error { + w.checksum = h + w.finished = true + _, err := w.createIndex() + if err != nil { + return err + } + + return nil +} + +// creatIndex returns a filled MemoryIndex with the information filled by +// the observer callbacks. +func (w *Writer) createIndex() (*MemoryIndex, error) { + if !w.finished { + return nil, fmt.Errorf("the index still hasn't finished building") + } + + idx := new(MemoryIndex) + w.index = idx + + sort.Sort(w.objects) + + // unmap all fans by default + for i := range idx.FanoutMapping { + idx.FanoutMapping[i] = noMapping + } + + buf := new(bytes.Buffer) + + last := -1 + bucket := -1 + for i, o := range w.objects { + fan := o.Hash[0] + + // fill the gaps between fans + for j := last + 1; j < int(fan); j++ { + idx.Fanout[j] = uint32(i) + } + + // update the number of objects for this position + idx.Fanout[fan] = uint32(i + 1) + + // we move from one bucket to another, update counters and allocate + // memory + if last != int(fan) { + bucket++ + idx.FanoutMapping[fan] = bucket + last = int(fan) + + idx.Names = append(idx.Names, make([]byte, 0)) + idx.Offset32 = append(idx.Offset32, make([]byte, 0)) + idx.CRC32 = append(idx.CRC32, make([]byte, 0)) + } + + idx.Names[bucket] = append(idx.Names[bucket], o.Hash[:]...) + + offset := o.Offset + if offset > math.MaxInt32 { + offset = w.addOffset64(offset) + } + + buf.Truncate(0) + binary.WriteUint32(buf, uint32(offset)) + idx.Offset32[bucket] = append(idx.Offset32[bucket], buf.Bytes()...) + + buf.Truncate(0) + binary.WriteUint32(buf, o.CRC32) + idx.CRC32[bucket] = append(idx.CRC32[bucket], buf.Bytes()...) + } + + for j := last + 1; j < 256; j++ { + idx.Fanout[j] = uint32(len(w.objects)) + } + + idx.Version = VersionSupported + idx.PackfileChecksum = w.checksum + + return idx, nil +} + +func (w *Writer) addOffset64(pos uint64) uint64 { + buf := new(bytes.Buffer) + binary.WriteUint64(buf, pos) + w.index.Offset64 = append(w.index.Offset64, buf.Bytes()...) + + index := uint64(w.offset64 | (1 << 31)) + w.offset64++ + + return index +} + +func (o objects) Len() int { + return len(o) +} + +func (o objects) Less(i int, j int) bool { + cmp := bytes.Compare(o[i].Hash[:], o[j].Hash[:]) + return cmp < 0 +} + +func (o objects) Swap(i int, j int) { + o[i], o[j] = o[j], o[i] +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/doc.go new file mode 100644 index 00000000..a7145160 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/doc.go @@ -0,0 +1,2 @@ +// Package objfile implements encoding and decoding of object files. +package objfile diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/reader.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/reader.go new file mode 100644 index 00000000..ca8dfba6 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/reader.go @@ -0,0 +1,114 @@ +package objfile + +import ( + "compress/zlib" + "errors" + "io" + "strconv" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/packfile" +) + +var ( + ErrClosed = errors.New("objfile: already closed") + ErrHeader = errors.New("objfile: invalid header") + ErrNegativeSize = errors.New("objfile: negative object size") +) + +// Reader reads and decodes compressed objfile data from a provided io.Reader. +// Reader implements io.ReadCloser. Close should be called when finished with +// the Reader. Close will not close the underlying io.Reader. +type Reader struct { + multi io.Reader + zlib io.ReadCloser + hasher plumbing.Hasher +} + +// NewReader returns a new Reader reading from r. +func NewReader(r io.Reader) (*Reader, error) { + zlib, err := zlib.NewReader(r) + if err != nil { + return nil, packfile.ErrZLib.AddDetails(err.Error()) + } + + return &Reader{ + zlib: zlib, + }, nil +} + +// Header reads the type and the size of object, and prepares the reader for read +func (r *Reader) Header() (t plumbing.ObjectType, size int64, err error) { + var raw []byte + raw, err = r.readUntil(' ') + if err != nil { + return + } + + t, err = plumbing.ParseObjectType(string(raw)) + if err != nil { + return + } + + raw, err = r.readUntil(0) + if err != nil { + return + } + + size, err = strconv.ParseInt(string(raw), 10, 64) + if err != nil { + err = ErrHeader + return + } + + defer r.prepareForRead(t, size) + return +} + +// readSlice reads one byte at a time from r until it encounters delim or an +// error. +func (r *Reader) readUntil(delim byte) ([]byte, error) { + var buf [1]byte + value := make([]byte, 0, 16) + for { + if n, err := r.zlib.Read(buf[:]); err != nil && (err != io.EOF || n == 0) { + if err == io.EOF { + return nil, ErrHeader + } + return nil, err + } + + if buf[0] == delim { + return value, nil + } + + value = append(value, buf[0]) + } +} + +func (r *Reader) prepareForRead(t plumbing.ObjectType, size int64) { + r.hasher = plumbing.NewHasher(t, size) + r.multi = io.TeeReader(r.zlib, r.hasher) +} + +// Read reads len(p) bytes into p from the object data stream. It returns +// the number of bytes read (0 <= n <= len(p)) and any error encountered. Even +// if Read returns n < len(p), it may use all of p as scratch space during the +// call. +// +// If Read encounters the end of the data stream it will return err == io.EOF, +// either in the current call if n > 0 or in a subsequent call. +func (r *Reader) Read(p []byte) (n int, err error) { + return r.multi.Read(p) +} + +// Hash returns the hash of the object data stream that has been read so far. +func (r *Reader) Hash() plumbing.Hash { + return r.hasher.Sum() +} + +// Close releases any resources consumed by the Reader. Calling Close does not +// close the wrapped io.Reader originally passed to NewReader. +func (r *Reader) Close() error { + return r.zlib.Close() +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/writer.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/writer.go new file mode 100644 index 00000000..8904719c --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/objfile/writer.go @@ -0,0 +1,109 @@ +package objfile + +import ( + "compress/zlib" + "errors" + "io" + "strconv" + + "github.com/devtron-labs/go-git/plumbing" +) + +var ( + ErrOverflow = errors.New("objfile: declared data length exceeded (overflow)") +) + +// Writer writes and encodes data in compressed objfile format to a provided +// io.Writer. Close should be called when finished with the Writer. Close will +// not close the underlying io.Writer. +type Writer struct { + raw io.Writer + zlib io.WriteCloser + hasher plumbing.Hasher + multi io.Writer + + closed bool + pending int64 // number of unwritten bytes +} + +// NewWriter returns a new Writer writing to w. +// +// The returned Writer implements io.WriteCloser. Close should be called when +// finished with the Writer. Close will not close the underlying io.Writer. +func NewWriter(w io.Writer) *Writer { + return &Writer{ + raw: w, + zlib: zlib.NewWriter(w), + } +} + +// WriteHeader writes the type and the size and prepares to accept the object's +// contents. If an invalid t is provided, plumbing.ErrInvalidType is returned. If a +// negative size is provided, ErrNegativeSize is returned. +func (w *Writer) WriteHeader(t plumbing.ObjectType, size int64) error { + if !t.Valid() { + return plumbing.ErrInvalidType + } + if size < 0 { + return ErrNegativeSize + } + + b := t.Bytes() + b = append(b, ' ') + b = append(b, []byte(strconv.FormatInt(size, 10))...) + b = append(b, 0) + + defer w.prepareForWrite(t, size) + _, err := w.zlib.Write(b) + + return err +} + +func (w *Writer) prepareForWrite(t plumbing.ObjectType, size int64) { + w.pending = size + + w.hasher = plumbing.NewHasher(t, size) + w.multi = io.MultiWriter(w.zlib, w.hasher) +} + +// Write writes the object's contents. Write returns the error ErrOverflow if +// more than size bytes are written after WriteHeader. +func (w *Writer) Write(p []byte) (n int, err error) { + if w.closed { + return 0, ErrClosed + } + + overwrite := false + if int64(len(p)) > w.pending { + p = p[0:w.pending] + overwrite = true + } + + n, err = w.multi.Write(p) + w.pending -= int64(n) + if err == nil && overwrite { + err = ErrOverflow + return + } + + return +} + +// Hash returns the hash of the object data stream that has been written so far. +// It can be called before or after Close. +func (w *Writer) Hash() plumbing.Hash { + return w.hasher.Sum() // Not yet closed, return hash of data written so far +} + +// Close releases any resources consumed by the Writer. +// +// Calling Close does not close the wrapped io.Writer originally passed to +// NewWriter. +func (w *Writer) Close() error { + if err := w.zlib.Close(); err != nil { + return err + } + + w.closed = true + return nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/common.go new file mode 100644 index 00000000..b609f5f9 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/common.go @@ -0,0 +1,78 @@ +package packfile + +import ( + "bytes" + "compress/zlib" + "io" + "sync" + + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +var signature = []byte{'P', 'A', 'C', 'K'} + +const ( + // VersionSupported is the packfile version supported by this package + VersionSupported uint32 = 2 + + firstLengthBits = uint8(4) // the first byte into object header has 4 bits to store the length + lengthBits = uint8(7) // subsequent bytes has 7 bits to store the length + maskFirstLength = 15 // 0000 1111 + maskContinue = 0x80 // 1000 0000 + maskLength = uint8(127) // 0111 1111 + maskType = uint8(112) // 0111 0000 +) + +// UpdateObjectStorage updates the storer with the objects in the given +// packfile. +func UpdateObjectStorage(s storer.Storer, packfile io.Reader) error { + if pw, ok := s.(storer.PackfileWriter); ok { + return WritePackfileToObjectStorage(pw, packfile) + } + + p, err := NewParserWithStorage(NewScanner(packfile), s) + if err != nil { + return err + } + + _, err = p.Parse() + return err +} + +// WritePackfileToObjectStorage writes all the packfile objects into the given +// object storage. +func WritePackfileToObjectStorage( + sw storer.PackfileWriter, + packfile io.Reader, +) (err error) { + w, err := sw.PackfileWriter() + if err != nil { + return err + } + + defer ioutil.CheckClose(w, &err) + + var n int64 + n, err = io.Copy(w, packfile) + if err == nil && n == 0 { + return ErrEmptyPackfile + } + + return err +} + +var bufPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(nil) + }, +} + +var zlibInitBytes = []byte{0x78, 0x9c, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01} + +var zlibReaderPool = sync.Pool{ + New: func() interface{} { + r, _ := zlib.NewReader(bytes.NewReader(zlibInitBytes)) + return r + }, +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_index.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_index.go new file mode 100644 index 00000000..07a61120 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_index.go @@ -0,0 +1,297 @@ +package packfile + +const blksz = 16 +const maxChainLength = 64 + +// deltaIndex is a modified version of JGit's DeltaIndex adapted to our current +// design. +type deltaIndex struct { + table []int + entries []int + mask int +} + +func (idx *deltaIndex) init(buf []byte) { + scanner := newDeltaIndexScanner(buf, len(buf)) + idx.mask = scanner.mask + idx.table = scanner.table + idx.entries = make([]int, countEntries(scanner)+1) + idx.copyEntries(scanner) +} + +// findMatch returns the offset of src where the block starting at tgtOffset +// is and the length of the match. A length of 0 means there was no match. A +// length of -1 means the src length is lower than the blksz and whatever +// other positive length is the length of the match in bytes. +func (idx *deltaIndex) findMatch(src, tgt []byte, tgtOffset int) (srcOffset, l int) { + if len(tgt) < tgtOffset+s { + return 0, len(tgt) - tgtOffset + } + + if len(src) < blksz { + return 0, -1 + } + + if len(tgt) >= tgtOffset+s && len(src) >= blksz { + h := hashBlock(tgt, tgtOffset) + tIdx := h & idx.mask + eIdx := idx.table[tIdx] + if eIdx != 0 { + srcOffset = idx.entries[eIdx] + } else { + return + } + + l = matchLength(src, tgt, tgtOffset, srcOffset) + } + + return +} + +func matchLength(src, tgt []byte, otgt, osrc int) (l int) { + lensrc := len(src) + lentgt := len(tgt) + for (osrc < lensrc && otgt < lentgt) && src[osrc] == tgt[otgt] { + l++ + osrc++ + otgt++ + } + return +} + +func countEntries(scan *deltaIndexScanner) (cnt int) { + // Figure out exactly how many entries we need. As we do the + // enumeration truncate any delta chains longer than what we + // are willing to scan during encode. This keeps the encode + // logic linear in the size of the input rather than quadratic. + for i := 0; i < len(scan.table); i++ { + h := scan.table[i] + if h == 0 { + continue + } + + size := 0 + for { + size++ + if size == maxChainLength { + scan.next[h] = 0 + break + } + h = scan.next[h] + + if h == 0 { + break + } + } + cnt += size + } + + return +} + +func (idx *deltaIndex) copyEntries(scanner *deltaIndexScanner) { + // Rebuild the entries list from the scanner, positioning all + // blocks in the same hash chain next to each other. We can + // then later discard the next list, along with the scanner. + // + next := 1 + for i := 0; i < len(idx.table); i++ { + h := idx.table[i] + if h == 0 { + continue + } + + idx.table[i] = next + for { + idx.entries[next] = scanner.entries[h] + next++ + h = scanner.next[h] + + if h == 0 { + break + } + } + } +} + +type deltaIndexScanner struct { + table []int + entries []int + next []int + mask int + count int +} + +func newDeltaIndexScanner(buf []byte, size int) *deltaIndexScanner { + size -= size % blksz + worstCaseBlockCnt := size / blksz + if worstCaseBlockCnt < 1 { + return new(deltaIndexScanner) + } + + tableSize := tableSize(worstCaseBlockCnt) + scanner := &deltaIndexScanner{ + table: make([]int, tableSize), + mask: tableSize - 1, + entries: make([]int, worstCaseBlockCnt+1), + next: make([]int, worstCaseBlockCnt+1), + } + + scanner.scan(buf, size) + return scanner +} + +// slightly modified version of JGit's DeltaIndexScanner. We store the offset on the entries +// instead of the entries and the key, so we avoid operations to retrieve the offset later, as +// we don't use the key. +// See: https://github.com/eclipse/jgit/blob/005e5feb4ecd08c4e4d141a38b9e7942accb3212/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaIndexScanner.java +func (s *deltaIndexScanner) scan(buf []byte, end int) { + lastHash := 0 + ptr := end - blksz + + for { + key := hashBlock(buf, ptr) + tIdx := key & s.mask + head := s.table[tIdx] + if head != 0 && lastHash == key { + s.entries[head] = ptr + } else { + s.count++ + eIdx := s.count + s.entries[eIdx] = ptr + s.next[eIdx] = head + s.table[tIdx] = eIdx + } + + lastHash = key + ptr -= blksz + + if 0 > ptr { + break + } + } +} + +func tableSize(worstCaseBlockCnt int) int { + shift := 32 - leadingZeros(uint32(worstCaseBlockCnt)) + sz := 1 << uint(shift-1) + if sz < worstCaseBlockCnt { + sz <<= 1 + } + return sz +} + +// use https://golang.org/pkg/math/bits/#LeadingZeros32 in the future +func leadingZeros(x uint32) (n int) { + if x >= 1<<16 { + x >>= 16 + n = 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + n += int(len8tab[x]) + return 32 - n +} + +var len8tab = [256]uint8{ + 0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +} + +func hashBlock(raw []byte, ptr int) int { + // The first 4 steps collapse out into a 4 byte big-endian decode, + // with a larger right shift as we combined shift lefts together. + // + hash := ((uint32(raw[ptr]) & 0xff) << 24) | + ((uint32(raw[ptr+1]) & 0xff) << 16) | + ((uint32(raw[ptr+2]) & 0xff) << 8) | + (uint32(raw[ptr+3]) & 0xff) + hash ^= T[hash>>31] + + hash = ((hash << 8) | (uint32(raw[ptr+4]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+5]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+6]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+7]) & 0xff)) ^ T[hash>>23] + + hash = ((hash << 8) | (uint32(raw[ptr+8]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+9]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+10]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+11]) & 0xff)) ^ T[hash>>23] + + hash = ((hash << 8) | (uint32(raw[ptr+12]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+13]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+14]) & 0xff)) ^ T[hash>>23] + hash = ((hash << 8) | (uint32(raw[ptr+15]) & 0xff)) ^ T[hash>>23] + + return int(hash) +} + +var T = []uint32{0x00000000, 0xd4c6b32d, 0x7d4bd577, + 0xa98d665a, 0x2e5119c3, 0xfa97aaee, 0x531accb4, 0x87dc7f99, + 0x5ca23386, 0x886480ab, 0x21e9e6f1, 0xf52f55dc, 0x72f32a45, + 0xa6359968, 0x0fb8ff32, 0xdb7e4c1f, 0x6d82d421, 0xb944670c, + 0x10c90156, 0xc40fb27b, 0x43d3cde2, 0x97157ecf, 0x3e981895, + 0xea5eabb8, 0x3120e7a7, 0xe5e6548a, 0x4c6b32d0, 0x98ad81fd, + 0x1f71fe64, 0xcbb74d49, 0x623a2b13, 0xb6fc983e, 0x0fc31b6f, + 0xdb05a842, 0x7288ce18, 0xa64e7d35, 0x219202ac, 0xf554b181, + 0x5cd9d7db, 0x881f64f6, 0x536128e9, 0x87a79bc4, 0x2e2afd9e, + 0xfaec4eb3, 0x7d30312a, 0xa9f68207, 0x007be45d, 0xd4bd5770, + 0x6241cf4e, 0xb6877c63, 0x1f0a1a39, 0xcbcca914, 0x4c10d68d, + 0x98d665a0, 0x315b03fa, 0xe59db0d7, 0x3ee3fcc8, 0xea254fe5, + 0x43a829bf, 0x976e9a92, 0x10b2e50b, 0xc4745626, 0x6df9307c, + 0xb93f8351, 0x1f8636de, 0xcb4085f3, 0x62cde3a9, 0xb60b5084, + 0x31d72f1d, 0xe5119c30, 0x4c9cfa6a, 0x985a4947, 0x43240558, + 0x97e2b675, 0x3e6fd02f, 0xeaa96302, 0x6d751c9b, 0xb9b3afb6, + 0x103ec9ec, 0xc4f87ac1, 0x7204e2ff, 0xa6c251d2, 0x0f4f3788, + 0xdb8984a5, 0x5c55fb3c, 0x88934811, 0x211e2e4b, 0xf5d89d66, + 0x2ea6d179, 0xfa606254, 0x53ed040e, 0x872bb723, 0x00f7c8ba, + 0xd4317b97, 0x7dbc1dcd, 0xa97aaee0, 0x10452db1, 0xc4839e9c, + 0x6d0ef8c6, 0xb9c84beb, 0x3e143472, 0xead2875f, 0x435fe105, + 0x97995228, 0x4ce71e37, 0x9821ad1a, 0x31accb40, 0xe56a786d, + 0x62b607f4, 0xb670b4d9, 0x1ffdd283, 0xcb3b61ae, 0x7dc7f990, + 0xa9014abd, 0x008c2ce7, 0xd44a9fca, 0x5396e053, 0x8750537e, + 0x2edd3524, 0xfa1b8609, 0x2165ca16, 0xf5a3793b, 0x5c2e1f61, + 0x88e8ac4c, 0x0f34d3d5, 0xdbf260f8, 0x727f06a2, 0xa6b9b58f, + 0x3f0c6dbc, 0xebcade91, 0x4247b8cb, 0x96810be6, 0x115d747f, + 0xc59bc752, 0x6c16a108, 0xb8d01225, 0x63ae5e3a, 0xb768ed17, + 0x1ee58b4d, 0xca233860, 0x4dff47f9, 0x9939f4d4, 0x30b4928e, + 0xe47221a3, 0x528eb99d, 0x86480ab0, 0x2fc56cea, 0xfb03dfc7, + 0x7cdfa05e, 0xa8191373, 0x01947529, 0xd552c604, 0x0e2c8a1b, + 0xdaea3936, 0x73675f6c, 0xa7a1ec41, 0x207d93d8, 0xf4bb20f5, + 0x5d3646af, 0x89f0f582, 0x30cf76d3, 0xe409c5fe, 0x4d84a3a4, + 0x99421089, 0x1e9e6f10, 0xca58dc3d, 0x63d5ba67, 0xb713094a, + 0x6c6d4555, 0xb8abf678, 0x11269022, 0xc5e0230f, 0x423c5c96, + 0x96faefbb, 0x3f7789e1, 0xebb13acc, 0x5d4da2f2, 0x898b11df, + 0x20067785, 0xf4c0c4a8, 0x731cbb31, 0xa7da081c, 0x0e576e46, + 0xda91dd6b, 0x01ef9174, 0xd5292259, 0x7ca44403, 0xa862f72e, + 0x2fbe88b7, 0xfb783b9a, 0x52f55dc0, 0x8633eeed, 0x208a5b62, + 0xf44ce84f, 0x5dc18e15, 0x89073d38, 0x0edb42a1, 0xda1df18c, + 0x739097d6, 0xa75624fb, 0x7c2868e4, 0xa8eedbc9, 0x0163bd93, + 0xd5a50ebe, 0x52797127, 0x86bfc20a, 0x2f32a450, 0xfbf4177d, + 0x4d088f43, 0x99ce3c6e, 0x30435a34, 0xe485e919, 0x63599680, + 0xb79f25ad, 0x1e1243f7, 0xcad4f0da, 0x11aabcc5, 0xc56c0fe8, + 0x6ce169b2, 0xb827da9f, 0x3ffba506, 0xeb3d162b, 0x42b07071, + 0x9676c35c, 0x2f49400d, 0xfb8ff320, 0x5202957a, 0x86c42657, + 0x011859ce, 0xd5deeae3, 0x7c538cb9, 0xa8953f94, 0x73eb738b, + 0xa72dc0a6, 0x0ea0a6fc, 0xda6615d1, 0x5dba6a48, 0x897cd965, + 0x20f1bf3f, 0xf4370c12, 0x42cb942c, 0x960d2701, 0x3f80415b, + 0xeb46f276, 0x6c9a8def, 0xb85c3ec2, 0x11d15898, 0xc517ebb5, + 0x1e69a7aa, 0xcaaf1487, 0x632272dd, 0xb7e4c1f0, 0x3038be69, + 0xe4fe0d44, 0x4d736b1e, 0x99b5d833, +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_selector.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_selector.go new file mode 100644 index 00000000..225457b2 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/delta_selector.go @@ -0,0 +1,369 @@ +package packfile + +import ( + "sort" + "sync" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" +) + +const ( + // deltas based on deltas, how many steps we can do. + // 50 is the default value used in JGit + maxDepth = int64(50) +) + +// applyDelta is the set of object types that we should apply deltas +var applyDelta = map[plumbing.ObjectType]bool{ + plumbing.BlobObject: true, + plumbing.TreeObject: true, +} + +type deltaSelector struct { + storer storer.EncodedObjectStorer +} + +func newDeltaSelector(s storer.EncodedObjectStorer) *deltaSelector { + return &deltaSelector{s} +} + +// ObjectsToPack creates a list of ObjectToPack from the hashes +// provided, creating deltas if it's suitable, using an specific +// internal logic. `packWindow` specifies the size of the sliding +// window used to compare objects for delta compression; 0 turns off +// delta compression entirely. +func (dw *deltaSelector) ObjectsToPack( + hashes []plumbing.Hash, + packWindow uint, +) ([]*ObjectToPack, error) { + otp, err := dw.objectsToPack(hashes, packWindow) + if err != nil { + return nil, err + } + + if packWindow == 0 { + return otp, nil + } + + dw.sort(otp) + + var objectGroups [][]*ObjectToPack + var prev *ObjectToPack + i := -1 + for _, obj := range otp { + if prev == nil || prev.Type() != obj.Type() { + objectGroups = append(objectGroups, []*ObjectToPack{obj}) + i++ + prev = obj + } else { + objectGroups[i] = append(objectGroups[i], obj) + } + } + + var wg sync.WaitGroup + var once sync.Once + for _, objs := range objectGroups { + objs := objs + wg.Add(1) + go func() { + if walkErr := dw.walk(objs, packWindow); walkErr != nil { + once.Do(func() { + err = walkErr + }) + } + wg.Done() + }() + } + wg.Wait() + + if err != nil { + return nil, err + } + + return otp, nil +} + +func (dw *deltaSelector) objectsToPack( + hashes []plumbing.Hash, + packWindow uint, +) ([]*ObjectToPack, error) { + var objectsToPack []*ObjectToPack + for _, h := range hashes { + var o plumbing.EncodedObject + var err error + if packWindow == 0 { + o, err = dw.encodedObject(h) + } else { + o, err = dw.encodedDeltaObject(h) + } + if err != nil { + return nil, err + } + + otp := newObjectToPack(o) + if _, ok := o.(plumbing.DeltaObject); ok { + otp.CleanOriginal() + } + + objectsToPack = append(objectsToPack, otp) + } + + if packWindow == 0 { + return objectsToPack, nil + } + + if err := dw.fixAndBreakChains(objectsToPack); err != nil { + return nil, err + } + + return objectsToPack, nil +} + +func (dw *deltaSelector) encodedDeltaObject(h plumbing.Hash) (plumbing.EncodedObject, error) { + edos, ok := dw.storer.(storer.DeltaObjectStorer) + if !ok { + return dw.encodedObject(h) + } + + return edos.DeltaObject(plumbing.AnyObject, h) +} + +func (dw *deltaSelector) encodedObject(h plumbing.Hash) (plumbing.EncodedObject, error) { + return dw.storer.EncodedObject(plumbing.AnyObject, h) +} + +func (dw *deltaSelector) fixAndBreakChains(objectsToPack []*ObjectToPack) error { + m := make(map[plumbing.Hash]*ObjectToPack, len(objectsToPack)) + for _, otp := range objectsToPack { + m[otp.Hash()] = otp + } + + for _, otp := range objectsToPack { + if err := dw.fixAndBreakChainsOne(m, otp); err != nil { + return err + } + } + + return nil +} + +func (dw *deltaSelector) fixAndBreakChainsOne(objectsToPack map[plumbing.Hash]*ObjectToPack, otp *ObjectToPack) error { + if !otp.Object.Type().IsDelta() { + return nil + } + + // Initial ObjectToPack instances might have a delta assigned to Object + // but no actual base initially. Once Base is assigned to a delta, it means + // we already fixed it. + if otp.Base != nil { + return nil + } + + do, ok := otp.Object.(plumbing.DeltaObject) + if !ok { + // if this is not a DeltaObject, then we cannot retrieve its base, + // so we have to break the delta chain here. + return dw.undeltify(otp) + } + + base, ok := objectsToPack[do.BaseHash()] + if !ok { + // The base of the delta is not in our list of objects to pack, so + // we break the chain. + return dw.undeltify(otp) + } + + if err := dw.fixAndBreakChainsOne(objectsToPack, base); err != nil { + return err + } + + otp.SetDelta(base, otp.Object) + return nil +} + +func (dw *deltaSelector) restoreOriginal(otp *ObjectToPack) error { + if otp.Original != nil { + return nil + } + + if !otp.Object.Type().IsDelta() { + return nil + } + + obj, err := dw.encodedObject(otp.Hash()) + if err != nil { + return err + } + + otp.SetOriginal(obj) + + return nil +} + +// undeltify undeltifies an *ObjectToPack by retrieving the original object from +// the storer and resetting it. +func (dw *deltaSelector) undeltify(otp *ObjectToPack) error { + if err := dw.restoreOriginal(otp); err != nil { + return err + } + + otp.Object = otp.Original + otp.Depth = 0 + return nil +} + +func (dw *deltaSelector) sort(objectsToPack []*ObjectToPack) { + sort.Sort(byTypeAndSize(objectsToPack)) +} + +func (dw *deltaSelector) walk( + objectsToPack []*ObjectToPack, + packWindow uint, +) error { + indexMap := make(map[plumbing.Hash]*deltaIndex) + for i := 0; i < len(objectsToPack); i++ { + // Clean up the index map and reconstructed delta objects for anything + // outside our pack window, to save memory. + if i > int(packWindow) { + obj := objectsToPack[i-int(packWindow)] + + delete(indexMap, obj.Hash()) + + if obj.IsDelta() { + obj.SaveOriginalMetadata() + obj.CleanOriginal() + } + } + + target := objectsToPack[i] + + // If we already have a delta, we don't try to find a new one for this + // object. This happens when a delta is set to be reused from an existing + // packfile. + if target.IsDelta() { + continue + } + + // We only want to create deltas from specific types. + if !applyDelta[target.Type()] { + continue + } + + for j := i - 1; j >= 0 && i-j < int(packWindow); j-- { + base := objectsToPack[j] + // Objects must use only the same type as their delta base. + // Since objectsToPack is sorted by type and size, once we find + // a different type, we know we won't find more of them. + if base.Type() != target.Type() { + break + } + + if err := dw.tryToDeltify(indexMap, base, target); err != nil { + return err + } + } + } + + return nil +} + +func (dw *deltaSelector) tryToDeltify(indexMap map[plumbing.Hash]*deltaIndex, base, target *ObjectToPack) error { + // Original object might not be present if we're reusing a delta, so we + // ensure it is restored. + if err := dw.restoreOriginal(target); err != nil { + return err + } + + if err := dw.restoreOriginal(base); err != nil { + return err + } + + // If the sizes are radically different, this is a bad pairing. + if target.Size() < base.Size()>>4 { + return nil + } + + msz := dw.deltaSizeLimit( + target.Object.Size(), + base.Depth, + target.Depth, + target.IsDelta(), + ) + + // Nearly impossible to fit useful delta. + if msz <= 8 { + return nil + } + + // If we have to insert a lot to make this work, find another. + if base.Size()-target.Size() > msz { + return nil + } + + if _, ok := indexMap[base.Hash()]; !ok { + indexMap[base.Hash()] = new(deltaIndex) + } + + // Now we can generate the delta using originals + delta, err := getDelta(indexMap[base.Hash()], base.Original, target.Original) + if err != nil { + return err + } + + // if delta better than target + if delta.Size() < msz { + target.SetDelta(base, delta) + } + + return nil +} + +func (dw *deltaSelector) deltaSizeLimit(targetSize int64, baseDepth int, + targetDepth int, targetDelta bool) int64 { + if !targetDelta { + // Any delta should be no more than 50% of the original size + // (for text files deflate of whole form should shrink 50%). + n := targetSize >> 1 + + // Evenly distribute delta size limits over allowed depth. + // If src is non-delta (depth = 0), delta <= 50% of original. + // If src is almost at limit (9/10), delta <= 10% of original. + return n * (maxDepth - int64(baseDepth)) / maxDepth + } + + // With a delta base chosen any new delta must be "better". + // Retain the distribution described above. + d := int64(targetDepth) + n := targetSize + + // If target depth is bigger than maxDepth, this delta is not suitable to be used. + if d >= maxDepth { + return 0 + } + + // If src is whole (depth=0) and base is near limit (depth=9/10) + // any delta using src can be 10x larger and still be better. + // + // If src is near limit (depth=9/10) and base is whole (depth=0) + // a new delta dependent on src must be 1/10th the size. + return n * (maxDepth - int64(baseDepth)) / (maxDepth - d) +} + +type byTypeAndSize []*ObjectToPack + +func (a byTypeAndSize) Len() int { return len(a) } + +func (a byTypeAndSize) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func (a byTypeAndSize) Less(i, j int) bool { + if a[i].Type() < a[j].Type() { + return false + } + + if a[i].Type() > a[j].Type() { + return true + } + + return a[i].Size() > a[j].Size() +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/diff_delta.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/diff_delta.go new file mode 100644 index 00000000..6bc52030 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/diff_delta.go @@ -0,0 +1,200 @@ +package packfile + +import ( + "bytes" + + "github.com/devtron-labs/go-git/plumbing" +) + +// See https://github.com/jelmer/dulwich/blob/master/dulwich/pack.py and +// https://github.com/tarruda/node-git-core/blob/master/src/js/delta.js +// for more info + +const ( + // Standard chunk size used to generate fingerprints + s = 16 + + // https://github.com/git/git/blob/f7466e94375b3be27f229c78873f0acf8301c0a5/diff-delta.c#L428 + // Max size of a copy operation (64KB) + maxCopySize = 64 * 1024 +) + +// GetDelta returns an EncodedObject of type OFSDeltaObject. Base and Target object, +// will be loaded into memory to be able to create the delta object. +// To generate target again, you will need the obtained object and "base" one. +// Error will be returned if base or target object cannot be read. +func GetDelta(base, target plumbing.EncodedObject) (plumbing.EncodedObject, error) { + return getDelta(new(deltaIndex), base, target) +} + +func getDelta(index *deltaIndex, base, target plumbing.EncodedObject) (plumbing.EncodedObject, error) { + br, err := base.Reader() + if err != nil { + return nil, err + } + defer br.Close() + tr, err := target.Reader() + if err != nil { + return nil, err + } + defer tr.Close() + + bb := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(bb) + bb.Reset() + + _, err = bb.ReadFrom(br) + if err != nil { + return nil, err + } + + tb := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(tb) + tb.Reset() + + _, err = tb.ReadFrom(tr) + if err != nil { + return nil, err + } + + db := diffDelta(index, bb.Bytes(), tb.Bytes()) + delta := &plumbing.MemoryObject{} + _, err = delta.Write(db) + if err != nil { + return nil, err + } + + delta.SetSize(int64(len(db))) + delta.SetType(plumbing.OFSDeltaObject) + + return delta, nil +} + +// DiffDelta returns the delta that transforms src into tgt. +func DiffDelta(src, tgt []byte) []byte { + return diffDelta(new(deltaIndex), src, tgt) +} + +func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte { + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + buf.Write(deltaEncodeSize(len(src))) + buf.Write(deltaEncodeSize(len(tgt))) + + if len(index.entries) == 0 { + index.init(src) + } + + ibuf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(ibuf) + ibuf.Reset() + for i := 0; i < len(tgt); i++ { + offset, l := index.findMatch(src, tgt, i) + + if l == 0 { + // couldn't find a match, just write the current byte and continue + ibuf.WriteByte(tgt[i]) + } else if l < 0 { + // src is less than blksz, copy the rest of the target to avoid + // calls to findMatch + for ; i < len(tgt); i++ { + ibuf.WriteByte(tgt[i]) + } + } else if l < s { + // remaining target is less than blksz, copy what's left of it + // and avoid calls to findMatch + for j := i; j < i+l; j++ { + ibuf.WriteByte(tgt[j]) + } + i += l - 1 + } else { + encodeInsertOperation(ibuf, buf) + + rl := l + aOffset := offset + for rl > 0 { + if rl < maxCopySize { + buf.Write(encodeCopyOperation(aOffset, rl)) + break + } + + buf.Write(encodeCopyOperation(aOffset, maxCopySize)) + rl -= maxCopySize + aOffset += maxCopySize + } + + i += l - 1 + } + } + + encodeInsertOperation(ibuf, buf) + + // buf.Bytes() is only valid until the next modifying operation on the buffer. Copy it. + return append([]byte{}, buf.Bytes()...) +} + +func encodeInsertOperation(ibuf, buf *bytes.Buffer) { + if ibuf.Len() == 0 { + return + } + + b := ibuf.Bytes() + s := ibuf.Len() + o := 0 + for { + if s <= 127 { + break + } + buf.WriteByte(byte(127)) + buf.Write(b[o : o+127]) + s -= 127 + o += 127 + } + buf.WriteByte(byte(s)) + buf.Write(b[o : o+s]) + + ibuf.Reset() +} + +func deltaEncodeSize(size int) []byte { + var ret []byte + c := size & 0x7f + size >>= 7 + for { + if size == 0 { + break + } + + ret = append(ret, byte(c|0x80)) + c = size & 0x7f + size >>= 7 + } + ret = append(ret, byte(c)) + + return ret +} + +func encodeCopyOperation(offset, length int) []byte { + code := 0x80 + var opcodes []byte + + var i uint + for i = 0; i < 4; i++ { + f := 0xff << (i * 8) + if offset&f != 0 { + opcodes = append(opcodes, byte(offset&f>>(i*8))) + code |= 0x01 << i + } + } + + for i = 0; i < 3; i++ { + f := 0xff << (i * 8) + if length&f != 0 { + opcodes = append(opcodes, byte(length&f>>(i*8))) + code |= 0x10 << i + } + } + + return append([]byte{byte(code)}, opcodes...) +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/doc.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/doc.go new file mode 100644 index 00000000..2882a7f3 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/doc.go @@ -0,0 +1,39 @@ +// Package packfile implements encoding and decoding of packfile format. +// +// == pack-*.pack files have the following format: +// +// - A header appears at the beginning and consists of the following: +// +// 4-byte signature: +// The signature is: {'P', 'A', 'C', 'K'} +// +// 4-byte version number (network byte order): +// GIT currently accepts version number 2 or 3 but +// generates version 2 only. +// +// 4-byte number of objects contained in the pack (network byte order) +// +// Observation: we cannot have more than 4G versions ;-) and +// more than 4G objects in a pack. +// +// - The header is followed by number of object entries, each of +// which looks like this: +// +// (undeltified representation) +// n-byte type and length (3-bit type, (n-1)*7+4-bit length) +// compressed data +// +// (deltified representation) +// n-byte type and length (3-bit type, (n-1)*7+4-bit length) +// 20-byte base object name +// compressed delta data +// +// Observation: length of each object is encoded in a variable +// length format and is not constrained to 32-bit or anything. +// +// - The trailer records 20-byte SHA1 checksum of all of the above. +// +// +// Source: +// https://www.kernel.org/pub/software/scm/git/docs/v1.7.5/technical/pack-protocol.txt +package packfile diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/encoder.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/encoder.go new file mode 100644 index 00000000..0ba4063a --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/encoder.go @@ -0,0 +1,219 @@ +package packfile + +import ( + "compress/zlib" + "crypto/sha1" + "fmt" + "io" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/utils/binary" +) + +// Encoder gets the data from the storage and write it into the writer in PACK +// format +type Encoder struct { + selector *deltaSelector + w *offsetWriter + zw *zlib.Writer + hasher plumbing.Hasher + + useRefDeltas bool +} + +// NewEncoder creates a new packfile encoder using a specific Writer and +// EncodedObjectStorer. By default deltas used to generate the packfile will be +// OFSDeltaObject. To use Reference deltas, set useRefDeltas to true. +func NewEncoder(w io.Writer, s storer.EncodedObjectStorer, useRefDeltas bool) *Encoder { + h := plumbing.Hasher{ + Hash: sha1.New(), + } + mw := io.MultiWriter(w, h) + ow := newOffsetWriter(mw) + zw := zlib.NewWriter(mw) + return &Encoder{ + selector: newDeltaSelector(s), + w: ow, + zw: zw, + hasher: h, + useRefDeltas: useRefDeltas, + } +} + +// Encode creates a packfile containing all the objects referenced in +// hashes and writes it to the writer in the Encoder. `packWindow` +// specifies the size of the sliding window used to compare objects +// for delta compression; 0 turns off delta compression entirely. +func (e *Encoder) Encode( + hashes []plumbing.Hash, + packWindow uint, +) (plumbing.Hash, error) { + objects, err := e.selector.ObjectsToPack(hashes, packWindow) + if err != nil { + return plumbing.ZeroHash, err + } + + return e.encode(objects) +} + +func (e *Encoder) encode(objects []*ObjectToPack) (plumbing.Hash, error) { + if err := e.head(len(objects)); err != nil { + return plumbing.ZeroHash, err + } + + for _, o := range objects { + if err := e.entry(o); err != nil { + return plumbing.ZeroHash, err + } + } + + return e.footer() +} + +func (e *Encoder) head(numEntries int) error { + return binary.Write( + e.w, + signature, + int32(VersionSupported), + int32(numEntries), + ) +} + +func (e *Encoder) entry(o *ObjectToPack) error { + if o.WantWrite() { + // A cycle exists in this delta chain. This should only occur if a + // selected object representation disappeared during writing + // (for example due to a concurrent repack) and a different base + // was chosen, forcing a cycle. Select something other than a + // delta, and write this object. + e.selector.restoreOriginal(o) + o.BackToOriginal() + } + + if o.IsWritten() { + return nil + } + + o.MarkWantWrite() + + if err := e.writeBaseIfDelta(o); err != nil { + return err + } + + // We need to check if we already write that object due a cyclic delta chain + if o.IsWritten() { + return nil + } + + o.Offset = e.w.Offset() + + if o.IsDelta() { + if err := e.writeDeltaHeader(o); err != nil { + return err + } + } else { + if err := e.entryHead(o.Type(), o.Size()); err != nil { + return err + } + } + + e.zw.Reset(e.w) + or, err := o.Object.Reader() + if err != nil { + return err + } + + _, err = io.Copy(e.zw, or) + if err != nil { + return err + } + + return e.zw.Close() +} + +func (e *Encoder) writeBaseIfDelta(o *ObjectToPack) error { + if o.IsDelta() && !o.Base.IsWritten() { + // We must write base first + return e.entry(o.Base) + } + + return nil +} + +func (e *Encoder) writeDeltaHeader(o *ObjectToPack) error { + // Write offset deltas by default + t := plumbing.OFSDeltaObject + if e.useRefDeltas { + t = plumbing.REFDeltaObject + } + + if err := e.entryHead(t, o.Object.Size()); err != nil { + return err + } + + if e.useRefDeltas { + return e.writeRefDeltaHeader(o.Base.Hash()) + } else { + return e.writeOfsDeltaHeader(o) + } +} + +func (e *Encoder) writeRefDeltaHeader(base plumbing.Hash) error { + return binary.Write(e.w, base) +} + +func (e *Encoder) writeOfsDeltaHeader(o *ObjectToPack) error { + // for OFS_DELTA, offset of the base is interpreted as negative offset + // relative to the type-byte of the header of the ofs-delta entry. + relativeOffset := o.Offset - o.Base.Offset + if relativeOffset <= 0 { + return fmt.Errorf("bad offset for OFS_DELTA entry: %d", relativeOffset) + } + + return binary.WriteVariableWidthInt(e.w, relativeOffset) +} + +func (e *Encoder) entryHead(typeNum plumbing.ObjectType, size int64) error { + t := int64(typeNum) + header := []byte{} + c := (t << firstLengthBits) | (size & maskFirstLength) + size >>= firstLengthBits + for { + if size == 0 { + break + } + header = append(header, byte(c|maskContinue)) + c = size & int64(maskLength) + size >>= lengthBits + } + + header = append(header, byte(c)) + _, err := e.w.Write(header) + + return err +} + +func (e *Encoder) footer() (plumbing.Hash, error) { + h := e.hasher.Sum() + return h, binary.Write(e.w, h) +} + +type offsetWriter struct { + w io.Writer + offset int64 +} + +func newOffsetWriter(w io.Writer) *offsetWriter { + return &offsetWriter{w: w} +} + +func (ow *offsetWriter) Write(p []byte) (n int, err error) { + n, err = ow.w.Write(p) + ow.offset += int64(n) + return n, err +} + +func (ow *offsetWriter) Offset() int64 { + return ow.offset +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/error.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/error.go new file mode 100644 index 00000000..c0b91633 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/error.go @@ -0,0 +1,30 @@ +package packfile + +import "fmt" + +// Error specifies errors returned during packfile parsing. +type Error struct { + reason, details string +} + +// NewError returns a new error. +func NewError(reason string) *Error { + return &Error{reason: reason} +} + +// Error returns a text representation of the error. +func (e *Error) Error() string { + if e.details == "" { + return e.reason + } + + return fmt.Sprintf("%s: %s", e.reason, e.details) +} + +// AddDetails adds details to an error, with additional text. +func (e *Error) AddDetails(format string, args ...interface{}) *Error { + return &Error{ + reason: e.reason, + details: fmt.Sprintf(format, args...), + } +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/fsobject.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/fsobject.go new file mode 100644 index 00000000..a09bffd1 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/fsobject.go @@ -0,0 +1,116 @@ +package packfile + +import ( + "io" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/format/idxfile" + billy "gopkg.in/src-d/go-billy.v4" +) + +// FSObject is an object from the packfile on the filesystem. +type FSObject struct { + hash plumbing.Hash + h *ObjectHeader + offset int64 + size int64 + typ plumbing.ObjectType + index idxfile.Index + fs billy.Filesystem + path string + cache cache.Object +} + +// NewFSObject creates a new filesystem object. +func NewFSObject( + hash plumbing.Hash, + finalType plumbing.ObjectType, + offset int64, + contentSize int64, + index idxfile.Index, + fs billy.Filesystem, + path string, + cache cache.Object, +) *FSObject { + return &FSObject{ + hash: hash, + offset: offset, + size: contentSize, + typ: finalType, + index: index, + fs: fs, + path: path, + cache: cache, + } +} + +// Reader implements the plumbing.EncodedObject interface. +func (o *FSObject) Reader() (io.ReadCloser, error) { + obj, ok := o.cache.Get(o.hash) + if ok && obj != o { + reader, err := obj.Reader() + if err != nil { + return nil, err + } + + return reader, nil + } + + f, err := o.fs.Open(o.path) + if err != nil { + return nil, err + } + + p := NewPackfileWithCache(o.index, nil, f, o.cache) + r, err := p.getObjectContent(o.offset) + if err != nil { + _ = f.Close() + return nil, err + } + + if err := f.Close(); err != nil { + return nil, err + } + + return r, nil +} + +// SetSize implements the plumbing.EncodedObject interface. This method +// is a noop. +func (o *FSObject) SetSize(int64) {} + +// SetType implements the plumbing.EncodedObject interface. This method is +// a noop. +func (o *FSObject) SetType(plumbing.ObjectType) {} + +// Hash implements the plumbing.EncodedObject interface. +func (o *FSObject) Hash() plumbing.Hash { return o.hash } + +// Size implements the plumbing.EncodedObject interface. +func (o *FSObject) Size() int64 { return o.size } + +// Type implements the plumbing.EncodedObject interface. +func (o *FSObject) Type() plumbing.ObjectType { + return o.typ +} + +// Writer implements the plumbing.EncodedObject interface. This method always +// returns a nil writer. +func (o *FSObject) Writer() (io.WriteCloser, error) { + return nil, nil +} + +type objectReader struct { + io.ReadCloser + f billy.File +} + +func (r *objectReader) Close() error { + if err := r.ReadCloser.Close(); err != nil { + _ = r.f.Close() + return err + } + + return r.f.Close() +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/object_pack.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/object_pack.go new file mode 100644 index 00000000..062e1389 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/object_pack.go @@ -0,0 +1,164 @@ +package packfile + +import ( + "github.com/devtron-labs/go-git/plumbing" +) + +// ObjectToPack is a representation of an object that is going to be into a +// pack file. +type ObjectToPack struct { + // The main object to pack, it could be any object, including deltas + Object plumbing.EncodedObject + // Base is the object that a delta is based on (it could be also another delta). + // If the main object is not a delta, Base will be null + Base *ObjectToPack + // Original is the object that we can generate applying the delta to + // Base, or the same object as Object in the case of a non-delta + // object. + Original plumbing.EncodedObject + // Depth is the amount of deltas needed to resolve to obtain Original + // (delta based on delta based on ...) + Depth int + + // offset in pack when object has been already written, or 0 if it + // has not been written yet + Offset int64 + + // Information from the original object + resolvedOriginal bool + originalType plumbing.ObjectType + originalSize int64 + originalHash plumbing.Hash +} + +// newObjectToPack creates a correct ObjectToPack based on a non-delta object +func newObjectToPack(o plumbing.EncodedObject) *ObjectToPack { + return &ObjectToPack{ + Object: o, + Original: o, + } +} + +// newDeltaObjectToPack creates a correct ObjectToPack for a delta object, based on +// his base (could be another delta), the delta target (in this case called original), +// and the delta Object itself +func newDeltaObjectToPack(base *ObjectToPack, original, delta plumbing.EncodedObject) *ObjectToPack { + return &ObjectToPack{ + Object: delta, + Base: base, + Original: original, + Depth: base.Depth + 1, + } +} + +// BackToOriginal converts that ObjectToPack to a non-deltified object if it was one +func (o *ObjectToPack) BackToOriginal() { + if o.IsDelta() && o.Original != nil { + o.Object = o.Original + o.Base = nil + o.Depth = 0 + } +} + +// IsWritten returns if that ObjectToPack was +// already written into the packfile or not +func (o *ObjectToPack) IsWritten() bool { + return o.Offset > 1 +} + +// MarkWantWrite marks this ObjectToPack as WantWrite +// to avoid delta chain loops +func (o *ObjectToPack) MarkWantWrite() { + o.Offset = 1 +} + +// WantWrite checks if this ObjectToPack was marked as WantWrite before +func (o *ObjectToPack) WantWrite() bool { + return o.Offset == 1 +} + +// SetOriginal sets both Original and saves size, type and hash. If object +// is nil Original is set but previous resolved values are kept +func (o *ObjectToPack) SetOriginal(obj plumbing.EncodedObject) { + o.Original = obj + o.SaveOriginalMetadata() +} + +// SaveOriginalMetadata saves size, type and hash of Original object +func (o *ObjectToPack) SaveOriginalMetadata() { + if o.Original != nil { + o.originalSize = o.Original.Size() + o.originalType = o.Original.Type() + o.originalHash = o.Original.Hash() + o.resolvedOriginal = true + } +} + +// CleanOriginal sets Original to nil +func (o *ObjectToPack) CleanOriginal() { + o.Original = nil +} + +func (o *ObjectToPack) Type() plumbing.ObjectType { + if o.Original != nil { + return o.Original.Type() + } + + if o.resolvedOriginal { + return o.originalType + } + + if o.Base != nil { + return o.Base.Type() + } + + if o.Object != nil { + return o.Object.Type() + } + + panic("cannot get type") +} + +func (o *ObjectToPack) Hash() plumbing.Hash { + if o.Original != nil { + return o.Original.Hash() + } + + if o.resolvedOriginal { + return o.originalHash + } + + do, ok := o.Object.(plumbing.DeltaObject) + if ok { + return do.ActualHash() + } + + panic("cannot get hash") +} + +func (o *ObjectToPack) Size() int64 { + if o.Original != nil { + return o.Original.Size() + } + + if o.resolvedOriginal { + return o.originalSize + } + + do, ok := o.Object.(plumbing.DeltaObject) + if ok { + return do.ActualSize() + } + + panic("cannot get ObjectToPack size") +} + +func (o *ObjectToPack) IsDelta() bool { + return o.Base != nil +} + +func (o *ObjectToPack) SetDelta(base *ObjectToPack, delta plumbing.EncodedObject) { + o.Object = delta + o.Base = base + o.Depth = base.Depth + 1 +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/packfile.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/packfile.go new file mode 100644 index 00000000..d61ec7e3 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/packfile.go @@ -0,0 +1,562 @@ +package packfile + +import ( + "bytes" + "io" + "os" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/format/idxfile" + "github.com/devtron-labs/go-git/plumbing/storer" + billy "gopkg.in/src-d/go-billy.v4" +) + +var ( + // ErrInvalidObject is returned by Decode when an invalid object is + // found in the packfile. + ErrInvalidObject = NewError("invalid git object") + // ErrZLib is returned by Decode when there was an error unzipping + // the packfile contents. + ErrZLib = NewError("zlib reading error") +) + +// When reading small objects from packfile it is beneficial to do so at +// once to exploit the buffered I/O. In many cases the objects are so small +// that they were already loaded to memory when the object header was +// loaded from the packfile. Wrapping in FSObject would cause this buffered +// data to be thrown away and then re-read later, with the additional +// seeking causing reloads from disk. Objects smaller than this threshold +// are now always read into memory and stored in cache instead of being +// wrapped in FSObject. +const smallObjectThreshold = 16 * 1024 + +// Packfile allows retrieving information from inside a packfile. +type Packfile struct { + idxfile.Index + fs billy.Filesystem + file billy.File + s *Scanner + deltaBaseCache cache.Object + offsetToType map[int64]plumbing.ObjectType +} + +// NewPackfileWithCache creates a new Packfile with the given object cache. +// If the filesystem is provided, the packfile will return FSObjects, otherwise +// it will return MemoryObjects. +func NewPackfileWithCache( + index idxfile.Index, + fs billy.Filesystem, + file billy.File, + cache cache.Object, +) *Packfile { + s := NewScanner(file) + return &Packfile{ + index, + fs, + file, + s, + cache, + make(map[int64]plumbing.ObjectType), + } +} + +// NewPackfile returns a packfile representation for the given packfile file +// and packfile idx. +// If the filesystem is provided, the packfile will return FSObjects, otherwise +// it will return MemoryObjects. +func NewPackfile(index idxfile.Index, fs billy.Filesystem, file billy.File) *Packfile { + return NewPackfileWithCache(index, fs, file, cache.NewObjectLRUDefault()) +} + +// Get retrieves the encoded object in the packfile with the given hash. +func (p *Packfile) Get(h plumbing.Hash) (plumbing.EncodedObject, error) { + offset, err := p.FindOffset(h) + if err != nil { + return nil, err + } + + return p.objectAtOffset(offset, h) +} + +// GetByOffset retrieves the encoded object from the packfile at the given +// offset. +func (p *Packfile) GetByOffset(o int64) (plumbing.EncodedObject, error) { + hash, err := p.FindHash(o) + if err != nil { + return nil, err + } + + return p.objectAtOffset(o, hash) +} + +// GetSizeByOffset retrieves the size of the encoded object from the +// packfile with the given offset. +func (p *Packfile) GetSizeByOffset(o int64) (size int64, err error) { + if _, err := p.s.SeekFromStart(o); err != nil { + if err == io.EOF || isInvalid(err) { + return 0, plumbing.ErrObjectNotFound + } + + return 0, err + } + + h, err := p.nextObjectHeader() + if err != nil { + return 0, err + } + return p.getObjectSize(h) +} + +func (p *Packfile) objectHeaderAtOffset(offset int64) (*ObjectHeader, error) { + h, err := p.s.SeekObjectHeader(offset) + p.s.pendingObject = nil + return h, err +} + +func (p *Packfile) nextObjectHeader() (*ObjectHeader, error) { + h, err := p.s.NextObjectHeader() + p.s.pendingObject = nil + return h, err +} + +func (p *Packfile) getDeltaObjectSize(buf *bytes.Buffer) int64 { + delta := buf.Bytes() + _, delta = decodeLEB128(delta) // skip src size + sz, _ := decodeLEB128(delta) + return int64(sz) +} + +func (p *Packfile) getObjectSize(h *ObjectHeader) (int64, error) { + switch h.Type { + case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject: + return h.Length, nil + case plumbing.REFDeltaObject, plumbing.OFSDeltaObject: + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + + if _, _, err := p.s.NextObject(buf); err != nil { + return 0, err + } + + return p.getDeltaObjectSize(buf), nil + default: + return 0, ErrInvalidObject.AddDetails("type %q", h.Type) + } +} + +func (p *Packfile) getObjectType(h *ObjectHeader) (typ plumbing.ObjectType, err error) { + switch h.Type { + case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject: + return h.Type, nil + case plumbing.REFDeltaObject, plumbing.OFSDeltaObject: + var offset int64 + if h.Type == plumbing.REFDeltaObject { + offset, err = p.FindOffset(h.Reference) + if err != nil { + return + } + } else { + offset = h.OffsetReference + } + + if baseType, ok := p.offsetToType[offset]; ok { + typ = baseType + } else { + h, err = p.objectHeaderAtOffset(offset) + if err != nil { + return + } + + typ, err = p.getObjectType(h) + if err != nil { + return + } + } + default: + err = ErrInvalidObject.AddDetails("type %q", h.Type) + } + + p.offsetToType[h.Offset] = typ + + return +} + +func (p *Packfile) objectAtOffset(offset int64, hash plumbing.Hash) (plumbing.EncodedObject, error) { + if obj, ok := p.cacheGet(hash); ok { + return obj, nil + } + + h, err := p.objectHeaderAtOffset(offset) + if err != nil { + if err == io.EOF || isInvalid(err) { + return nil, plumbing.ErrObjectNotFound + } + return nil, err + } + + return p.getNextObject(h, hash) +} + +func (p *Packfile) getNextObject(h *ObjectHeader, hash plumbing.Hash) (plumbing.EncodedObject, error) { + var err error + + // If we have no filesystem, we will return a MemoryObject instead + // of an FSObject. + if p.fs == nil { + return p.getNextMemoryObject(h) + } + + // If the object is small enough then read it completely into memory now since + // it is already read from disk into buffer anyway. For delta objects we want + // to perform the optimization too, but we have to be careful about applying + // small deltas on big objects. + var size int64 + if h.Length <= smallObjectThreshold { + if h.Type != plumbing.OFSDeltaObject && h.Type != plumbing.REFDeltaObject { + return p.getNextMemoryObject(h) + } + + // For delta objects we read the delta data and apply the small object + // optimization only if the expanded version of the object still meets + // the small object threshold condition. + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + if _, _, err := p.s.NextObject(buf); err != nil { + return nil, err + } + + size = p.getDeltaObjectSize(buf) + if size <= smallObjectThreshold { + var obj = new(plumbing.MemoryObject) + obj.SetSize(size) + if h.Type == plumbing.REFDeltaObject { + err = p.fillREFDeltaObjectContentWithBuffer(obj, h.Reference, buf) + } else { + err = p.fillOFSDeltaObjectContentWithBuffer(obj, h.OffsetReference, buf) + } + return obj, err + } + } else { + size, err = p.getObjectSize(h) + if err != nil { + return nil, err + } + } + + typ, err := p.getObjectType(h) + if err != nil { + return nil, err + } + + p.offsetToType[h.Offset] = typ + + return NewFSObject( + hash, + typ, + h.Offset, + size, + p.Index, + p.fs, + p.file.Name(), + p.deltaBaseCache, + ), nil +} + +func (p *Packfile) getObjectContent(offset int64) (io.ReadCloser, error) { + h, err := p.objectHeaderAtOffset(offset) + if err != nil { + return nil, err + } + + // getObjectContent is called from FSObject, so we have to explicitly + // get memory object here to avoid recursive cycle + obj, err := p.getNextMemoryObject(h) + if err != nil { + return nil, err + } + + return obj.Reader() +} + +func (p *Packfile) getNextMemoryObject(h *ObjectHeader) (plumbing.EncodedObject, error) { + var obj = new(plumbing.MemoryObject) + obj.SetSize(h.Length) + obj.SetType(h.Type) + + var err error + switch h.Type { + case plumbing.CommitObject, plumbing.TreeObject, plumbing.BlobObject, plumbing.TagObject: + err = p.fillRegularObjectContent(obj) + case plumbing.REFDeltaObject: + err = p.fillREFDeltaObjectContent(obj, h.Reference) + case plumbing.OFSDeltaObject: + err = p.fillOFSDeltaObjectContent(obj, h.OffsetReference) + default: + err = ErrInvalidObject.AddDetails("type %q", h.Type) + } + + if err != nil { + return nil, err + } + + p.offsetToType[h.Offset] = obj.Type() + + return obj, nil +} + +func (p *Packfile) fillRegularObjectContent(obj plumbing.EncodedObject) error { + w, err := obj.Writer() + if err != nil { + return err + } + + _, _, err = p.s.NextObject(w) + p.cachePut(obj) + + return err +} + +func (p *Packfile) fillREFDeltaObjectContent(obj plumbing.EncodedObject, ref plumbing.Hash) error { + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + _, _, err := p.s.NextObject(buf) + if err != nil { + return err + } + + return p.fillREFDeltaObjectContentWithBuffer(obj, ref, buf) +} + +func (p *Packfile) fillREFDeltaObjectContentWithBuffer(obj plumbing.EncodedObject, ref plumbing.Hash, buf *bytes.Buffer) error { + var err error + + base, ok := p.cacheGet(ref) + if !ok { + base, err = p.Get(ref) + if err != nil { + return err + } + } + + obj.SetType(base.Type()) + err = ApplyDelta(obj, base, buf.Bytes()) + p.cachePut(obj) + + return err +} + +func (p *Packfile) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset int64) error { + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + _, _, err := p.s.NextObject(buf) + if err != nil { + return err + } + + return p.fillOFSDeltaObjectContentWithBuffer(obj, offset, buf) +} + +func (p *Packfile) fillOFSDeltaObjectContentWithBuffer(obj plumbing.EncodedObject, offset int64, buf *bytes.Buffer) error { + hash, err := p.FindHash(offset) + if err != nil { + return err + } + + base, err := p.objectAtOffset(offset, hash) + if err != nil { + return err + } + + obj.SetType(base.Type()) + err = ApplyDelta(obj, base, buf.Bytes()) + p.cachePut(obj) + + return err +} + +func (p *Packfile) cacheGet(h plumbing.Hash) (plumbing.EncodedObject, bool) { + if p.deltaBaseCache == nil { + return nil, false + } + + return p.deltaBaseCache.Get(h) +} + +func (p *Packfile) cachePut(obj plumbing.EncodedObject) { + if p.deltaBaseCache == nil { + return + } + + p.deltaBaseCache.Put(obj) +} + +// GetAll returns an iterator with all encoded objects in the packfile. +// The iterator returned is not thread-safe, it should be used in the same +// thread as the Packfile instance. +func (p *Packfile) GetAll() (storer.EncodedObjectIter, error) { + return p.GetByType(plumbing.AnyObject) +} + +// GetByType returns all the objects of the given type. +func (p *Packfile) GetByType(typ plumbing.ObjectType) (storer.EncodedObjectIter, error) { + switch typ { + case plumbing.AnyObject, + plumbing.BlobObject, + plumbing.TreeObject, + plumbing.CommitObject, + plumbing.TagObject: + entries, err := p.EntriesByOffset() + if err != nil { + return nil, err + } + + return &objectIter{ + // Easiest way to provide an object decoder is just to pass a Packfile + // instance. To not mess with the seeks, it's a new instance with a + // different scanner but the same cache and offset to hash map for + // reusing as much cache as possible. + p: p, + iter: entries, + typ: typ, + }, nil + default: + return nil, plumbing.ErrInvalidType + } +} + +// ID returns the ID of the packfile, which is the checksum at the end of it. +func (p *Packfile) ID() (plumbing.Hash, error) { + prev, err := p.file.Seek(-20, io.SeekEnd) + if err != nil { + return plumbing.ZeroHash, err + } + + var hash plumbing.Hash + if _, err := io.ReadFull(p.file, hash[:]); err != nil { + return plumbing.ZeroHash, err + } + + if _, err := p.file.Seek(prev, io.SeekStart); err != nil { + return plumbing.ZeroHash, err + } + + return hash, nil +} + +// Scanner returns the packfile's Scanner +func (p *Packfile) Scanner() *Scanner { + return p.s +} + +// Close the packfile and its resources. +func (p *Packfile) Close() error { + closer, ok := p.file.(io.Closer) + if !ok { + return nil + } + + return closer.Close() +} + +type objectIter struct { + p *Packfile + typ plumbing.ObjectType + iter idxfile.EntryIter +} + +func (i *objectIter) Next() (plumbing.EncodedObject, error) { + for { + e, err := i.iter.Next() + if err != nil { + return nil, err + } + + if i.typ != plumbing.AnyObject { + if typ, ok := i.p.offsetToType[int64(e.Offset)]; ok { + if typ != i.typ { + continue + } + } else if obj, ok := i.p.cacheGet(e.Hash); ok { + if obj.Type() != i.typ { + i.p.offsetToType[int64(e.Offset)] = obj.Type() + continue + } + return obj, nil + } else { + h, err := i.p.objectHeaderAtOffset(int64(e.Offset)) + if err != nil { + return nil, err + } + + if h.Type == plumbing.REFDeltaObject || h.Type == plumbing.OFSDeltaObject { + typ, err := i.p.getObjectType(h) + if err != nil { + return nil, err + } + if typ != i.typ { + i.p.offsetToType[int64(e.Offset)] = typ + continue + } + // getObjectType will seek in the file so we cannot use getNextObject safely + return i.p.objectAtOffset(int64(e.Offset), e.Hash) + } else { + if h.Type != i.typ { + i.p.offsetToType[int64(e.Offset)] = h.Type + continue + } + return i.p.getNextObject(h, e.Hash) + } + } + } + + obj, err := i.p.objectAtOffset(int64(e.Offset), e.Hash) + if err != nil { + return nil, err + } + + return obj, nil + } +} + +func (i *objectIter) ForEach(f func(plumbing.EncodedObject) error) error { + for { + o, err := i.Next() + if err != nil { + if err == io.EOF { + return nil + } + return err + } + + if err := f(o); err != nil { + return err + } + } +} + +func (i *objectIter) Close() { + i.iter.Close() +} + +// isInvalid checks whether an error is an os.PathError with an os.ErrInvalid +// error inside. It also checks for the windows error, which is different from +// os.ErrInvalid. +func isInvalid(err error) bool { + pe, ok := err.(*os.PathError) + if !ok { + return false + } + + errstr := pe.Err.Error() + return errstr == errInvalidUnix || errstr == errInvalidWindows +} + +// errInvalidWindows is the Windows equivalent to os.ErrInvalid +const errInvalidWindows = "The parameter is incorrect." + +var errInvalidUnix = os.ErrInvalid.Error() diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/parser.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/parser.go new file mode 100644 index 00000000..c17069c9 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/parser.go @@ -0,0 +1,483 @@ +package packfile + +import ( + "bytes" + "errors" + "io" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/storer" +) + +var ( + // ErrReferenceDeltaNotFound is returned when the reference delta is not + // found. + ErrReferenceDeltaNotFound = errors.New("reference delta not found") + + // ErrNotSeekableSource is returned when the source for the parser is not + // seekable and a storage was not provided, so it can't be parsed. + ErrNotSeekableSource = errors.New("parser source is not seekable and storage was not provided") + + // ErrDeltaNotCached is returned when the delta could not be found in cache. + ErrDeltaNotCached = errors.New("delta could not be found in cache") +) + +// Observer interface is implemented by index encoders. +type Observer interface { + // OnHeader is called when a new packfile is opened. + OnHeader(count uint32) error + // OnInflatedObjectHeader is called for each object header read. + OnInflatedObjectHeader(t plumbing.ObjectType, objSize int64, pos int64) error + // OnInflatedObjectContent is called for each decoded object. + OnInflatedObjectContent(h plumbing.Hash, pos int64, crc uint32, content []byte) error + // OnFooter is called when decoding is done. + OnFooter(h plumbing.Hash) error +} + +// Parser decodes a packfile and calls any observer associated to it. Is used +// to generate indexes. +type Parser struct { + storage storer.EncodedObjectStorer + scanner *Scanner + count uint32 + oi []*objectInfo + oiByHash map[plumbing.Hash]*objectInfo + oiByOffset map[int64]*objectInfo + hashOffset map[plumbing.Hash]int64 + checksum plumbing.Hash + + cache *cache.BufferLRU + // delta content by offset, only used if source is not seekable + deltas map[int64][]byte + + ob []Observer +} + +// NewParser creates a new Parser. The Scanner source must be seekable. +// If it's not, NewParserWithStorage should be used instead. +func NewParser(scanner *Scanner, ob ...Observer) (*Parser, error) { + return NewParserWithStorage(scanner, nil, ob...) +} + +// NewParserWithStorage creates a new Parser. The scanner source must either +// be seekable or a storage must be provided. +func NewParserWithStorage( + scanner *Scanner, + storage storer.EncodedObjectStorer, + ob ...Observer, +) (*Parser, error) { + if !scanner.IsSeekable && storage == nil { + return nil, ErrNotSeekableSource + } + + var deltas map[int64][]byte + if !scanner.IsSeekable { + deltas = make(map[int64][]byte) + } + + return &Parser{ + storage: storage, + scanner: scanner, + ob: ob, + count: 0, + cache: cache.NewBufferLRUDefault(), + deltas: deltas, + }, nil +} + +func (p *Parser) forEachObserver(f func(o Observer) error) error { + for _, o := range p.ob { + if err := f(o); err != nil { + return err + } + } + return nil +} + +func (p *Parser) onHeader(count uint32) error { + return p.forEachObserver(func(o Observer) error { + return o.OnHeader(count) + }) +} + +func (p *Parser) onInflatedObjectHeader( + t plumbing.ObjectType, + objSize int64, + pos int64, +) error { + return p.forEachObserver(func(o Observer) error { + return o.OnInflatedObjectHeader(t, objSize, pos) + }) +} + +func (p *Parser) onInflatedObjectContent( + h plumbing.Hash, + pos int64, + crc uint32, + content []byte, +) error { + return p.forEachObserver(func(o Observer) error { + return o.OnInflatedObjectContent(h, pos, crc, content) + }) +} + +func (p *Parser) onFooter(h plumbing.Hash) error { + return p.forEachObserver(func(o Observer) error { + return o.OnFooter(h) + }) +} + +// Parse start decoding phase of the packfile. +func (p *Parser) Parse() (plumbing.Hash, error) { + if err := p.init(); err != nil { + return plumbing.ZeroHash, err + } + + if err := p.indexObjects(); err != nil { + return plumbing.ZeroHash, err + } + + var err error + p.checksum, err = p.scanner.Checksum() + if err != nil && err != io.EOF { + return plumbing.ZeroHash, err + } + + if err := p.resolveDeltas(); err != nil { + return plumbing.ZeroHash, err + } + + if err := p.onFooter(p.checksum); err != nil { + return plumbing.ZeroHash, err + } + + return p.checksum, nil +} + +func (p *Parser) init() error { + _, c, err := p.scanner.Header() + if err != nil { + return err + } + + if err := p.onHeader(c); err != nil { + return err + } + + p.count = c + p.oiByHash = make(map[plumbing.Hash]*objectInfo, p.count) + p.oiByOffset = make(map[int64]*objectInfo, p.count) + p.oi = make([]*objectInfo, p.count) + + return nil +} + +func (p *Parser) indexObjects() error { + buf := new(bytes.Buffer) + + for i := uint32(0); i < p.count; i++ { + buf.Reset() + + oh, err := p.scanner.NextObjectHeader() + if err != nil { + return err + } + + delta := false + var ota *objectInfo + switch t := oh.Type; t { + case plumbing.OFSDeltaObject: + delta = true + + parent, ok := p.oiByOffset[oh.OffsetReference] + if !ok { + return plumbing.ErrObjectNotFound + } + + ota = newDeltaObject(oh.Offset, oh.Length, t, parent) + parent.Children = append(parent.Children, ota) + case plumbing.REFDeltaObject: + delta = true + parent, ok := p.oiByHash[oh.Reference] + if !ok { + // can't find referenced object in this pack file + // this must be a "thin" pack. + parent = &objectInfo{ //Placeholder parent + SHA1: oh.Reference, + ExternalRef: true, // mark as an external reference that must be resolved + Type: plumbing.AnyObject, + DiskType: plumbing.AnyObject, + } + p.oiByHash[oh.Reference] = parent + } + ota = newDeltaObject(oh.Offset, oh.Length, t, parent) + parent.Children = append(parent.Children, ota) + + default: + ota = newBaseObject(oh.Offset, oh.Length, t) + } + + _, crc, err := p.scanner.NextObject(buf) + if err != nil { + return err + } + + ota.Crc32 = crc + ota.Length = oh.Length + + data := buf.Bytes() + if !delta { + sha1, err := getSHA1(ota.Type, data) + if err != nil { + return err + } + + ota.SHA1 = sha1 + p.oiByHash[ota.SHA1] = ota + } + + if p.storage != nil && !delta { + obj := new(plumbing.MemoryObject) + obj.SetSize(oh.Length) + obj.SetType(oh.Type) + if _, err := obj.Write(data); err != nil { + return err + } + + if _, err := p.storage.SetEncodedObject(obj); err != nil { + return err + } + } + + if delta && !p.scanner.IsSeekable { + p.deltas[oh.Offset] = make([]byte, len(data)) + copy(p.deltas[oh.Offset], data) + } + + p.oiByOffset[oh.Offset] = ota + p.oi[i] = ota + } + + return nil +} + +func (p *Parser) resolveDeltas() error { + for _, obj := range p.oi { + content, err := p.get(obj) + if err != nil { + return err + } + + if err := p.onInflatedObjectHeader(obj.Type, obj.Length, obj.Offset); err != nil { + return err + } + + if err := p.onInflatedObjectContent(obj.SHA1, obj.Offset, obj.Crc32, content); err != nil { + return err + } + + if !obj.IsDelta() && len(obj.Children) > 0 { + for _, child := range obj.Children { + if _, err := p.resolveObject(child, content); err != nil { + return err + } + } + + // Remove the delta from the cache. + if obj.DiskType.IsDelta() && !p.scanner.IsSeekable { + delete(p.deltas, obj.Offset) + } + } + } + + return nil +} + +func (p *Parser) get(o *objectInfo) (b []byte, err error) { + var ok bool + if !o.ExternalRef { // skip cache check for placeholder parents + b, ok = p.cache.Get(o.Offset) + } + + // If it's not on the cache and is not a delta we can try to find it in the + // storage, if there's one. External refs must enter here. + if !ok && p.storage != nil && !o.Type.IsDelta() { + e, err := p.storage.EncodedObject(plumbing.AnyObject, o.SHA1) + if err != nil { + return nil, err + } + o.Type = e.Type() + + r, err := e.Reader() + if err != nil { + return nil, err + } + + b = make([]byte, e.Size()) + if _, err = r.Read(b); err != nil { + return nil, err + } + } + + if b != nil { + return b, nil + } + + if o.ExternalRef { + // we were not able to resolve a ref in a thin pack + return nil, ErrReferenceDeltaNotFound + } + + var data []byte + if o.DiskType.IsDelta() { + base, err := p.get(o.Parent) + if err != nil { + return nil, err + } + + data, err = p.resolveObject(o, base) + if err != nil { + return nil, err + } + } else { + data, err = p.readData(o) + if err != nil { + return nil, err + } + } + + if len(o.Children) > 0 { + p.cache.Put(o.Offset, data) + } + + return data, nil +} + +func (p *Parser) resolveObject( + o *objectInfo, + base []byte, +) ([]byte, error) { + if !o.DiskType.IsDelta() { + return nil, nil + } + + data, err := p.readData(o) + if err != nil { + return nil, err + } + + data, err = applyPatchBase(o, data, base) + if err != nil { + return nil, err + } + + if p.storage != nil { + obj := new(plumbing.MemoryObject) + obj.SetSize(o.Size()) + obj.SetType(o.Type) + if _, err := obj.Write(data); err != nil { + return nil, err + } + + if _, err := p.storage.SetEncodedObject(obj); err != nil { + return nil, err + } + } + + return data, nil +} + +func (p *Parser) readData(o *objectInfo) ([]byte, error) { + if !p.scanner.IsSeekable && o.DiskType.IsDelta() { + data, ok := p.deltas[o.Offset] + if !ok { + return nil, ErrDeltaNotCached + } + + return data, nil + } + + if _, err := p.scanner.SeekObjectHeader(o.Offset); err != nil { + return nil, err + } + + buf := new(bytes.Buffer) + if _, _, err := p.scanner.NextObject(buf); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func applyPatchBase(ota *objectInfo, data, base []byte) ([]byte, error) { + patched, err := PatchDelta(base, data) + if err != nil { + return nil, err + } + + if ota.SHA1 == plumbing.ZeroHash { + ota.Type = ota.Parent.Type + sha1, err := getSHA1(ota.Type, patched) + if err != nil { + return nil, err + } + + ota.SHA1 = sha1 + ota.Length = int64(len(patched)) + } + + return patched, nil +} + +func getSHA1(t plumbing.ObjectType, data []byte) (plumbing.Hash, error) { + hasher := plumbing.NewHasher(t, int64(len(data))) + if _, err := hasher.Write(data); err != nil { + return plumbing.ZeroHash, err + } + + return hasher.Sum(), nil +} + +type objectInfo struct { + Offset int64 + Length int64 + Type plumbing.ObjectType + DiskType plumbing.ObjectType + ExternalRef bool // indicates this is an external reference in a thin pack file + + Crc32 uint32 + + Parent *objectInfo + Children []*objectInfo + SHA1 plumbing.Hash +} + +func newBaseObject(offset, length int64, t plumbing.ObjectType) *objectInfo { + return newDeltaObject(offset, length, t, nil) +} + +func newDeltaObject( + offset, length int64, + t plumbing.ObjectType, + parent *objectInfo, +) *objectInfo { + obj := &objectInfo{ + Offset: offset, + Length: length, + Type: t, + DiskType: t, + Crc32: 0, + Parent: parent, + } + + return obj +} + +func (o *objectInfo) IsDelta() bool { + return o.Type.IsDelta() +} + +func (o *objectInfo) Size() int64 { + return o.Length +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/patch_delta.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/patch_delta.go new file mode 100644 index 00000000..885f70a4 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/patch_delta.go @@ -0,0 +1,229 @@ +package packfile + +import ( + "errors" + "io/ioutil" + + "github.com/devtron-labs/go-git/plumbing" +) + +// See https://github.com/git/git/blob/49fa3dc76179e04b0833542fa52d0f287a4955ac/delta.h +// https://github.com/git/git/blob/c2c5f6b1e479f2c38e0e01345350620944e3527f/patch-delta.c, +// and https://github.com/tarruda/node-git-core/blob/master/src/js/delta.js +// for details about the delta format. + +const deltaSizeMin = 4 + +// ApplyDelta writes to target the result of applying the modification deltas in delta to base. +func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error { + r, err := base.Reader() + if err != nil { + return err + } + + w, err := target.Writer() + if err != nil { + return err + } + + src, err := ioutil.ReadAll(r) + if err != nil { + return err + } + + dst, err := PatchDelta(src, delta) + if err != nil { + return err + } + + target.SetSize(int64(len(dst))) + + _, err = w.Write(dst) + return err +} + +var ( + ErrInvalidDelta = errors.New("invalid delta") + ErrDeltaCmd = errors.New("wrong delta command") +) + +// PatchDelta returns the result of applying the modification deltas in delta to src. +// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command +// is not copy from source or copy from delta (ErrDeltaCmd). +func PatchDelta(src, delta []byte) ([]byte, error) { + if len(delta) < deltaSizeMin { + return nil, ErrInvalidDelta + } + + srcSz, delta := decodeLEB128(delta) + if srcSz != uint(len(src)) { + return nil, ErrInvalidDelta + } + + targetSz, delta := decodeLEB128(delta) + remainingTargetSz := targetSz + + var cmd byte + dest := make([]byte, 0, targetSz) + for { + if len(delta) == 0 { + return nil, ErrInvalidDelta + } + + cmd = delta[0] + delta = delta[1:] + if isCopyFromSrc(cmd) { + var offset, sz uint + var err error + offset, delta, err = decodeOffset(cmd, delta) + if err != nil { + return nil, err + } + + sz, delta, err = decodeSize(cmd, delta) + if err != nil { + return nil, err + } + + if invalidSize(sz, targetSz) || + invalidOffsetSize(offset, sz, srcSz) { + break + } + dest = append(dest, src[offset:offset+sz]...) + remainingTargetSz -= sz + } else if isCopyFromDelta(cmd) { + sz := uint(cmd) // cmd is the size itself + if invalidSize(sz, targetSz) { + return nil, ErrInvalidDelta + } + + if uint(len(delta)) < sz { + return nil, ErrInvalidDelta + } + + dest = append(dest, delta[0:sz]...) + remainingTargetSz -= sz + delta = delta[sz:] + } else { + return nil, ErrDeltaCmd + } + + if remainingTargetSz <= 0 { + break + } + } + + return dest, nil +} + +// Decodes a number encoded as an unsigned LEB128 at the start of some +// binary data and returns the decoded number and the rest of the +// stream. +// +// This must be called twice on the delta data buffer, first to get the +// expected source buffer size, and again to get the target buffer size. +func decodeLEB128(input []byte) (uint, []byte) { + var num, sz uint + var b byte + for { + b = input[sz] + num |= (uint(b) & payload) << (sz * 7) // concats 7 bits chunks + sz++ + + if uint(b)&continuation == 0 || sz == uint(len(input)) { + break + } + } + + return num, input[sz:] +} + +const ( + payload = 0x7f // 0111 1111 + continuation = 0x80 // 1000 0000 +) + +func isCopyFromSrc(cmd byte) bool { + return (cmd & 0x80) != 0 +} + +func isCopyFromDelta(cmd byte) bool { + return (cmd&0x80) == 0 && cmd != 0 +} + +func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) { + var offset uint + if (cmd & 0x01) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + offset = uint(delta[0]) + delta = delta[1:] + } + if (cmd & 0x02) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + offset |= uint(delta[0]) << 8 + delta = delta[1:] + } + if (cmd & 0x04) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + offset |= uint(delta[0]) << 16 + delta = delta[1:] + } + if (cmd & 0x08) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + offset |= uint(delta[0]) << 24 + delta = delta[1:] + } + + return offset, delta, nil +} + +func decodeSize(cmd byte, delta []byte) (uint, []byte, error) { + var sz uint + if (cmd & 0x10) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + sz = uint(delta[0]) + delta = delta[1:] + } + if (cmd & 0x20) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + sz |= uint(delta[0]) << 8 + delta = delta[1:] + } + if (cmd & 0x40) != 0 { + if len(delta) == 0 { + return 0, nil, ErrInvalidDelta + } + sz |= uint(delta[0]) << 16 + delta = delta[1:] + } + if sz == 0 { + sz = 0x10000 + } + + return sz, delta, nil +} + +func invalidSize(sz, targetSz uint) bool { + return sz > targetSz +} + +func invalidOffsetSize(offset, sz, srcSz uint) bool { + return sumOverflows(offset, sz) || + offset+sz > srcSz +} + +func sumOverflows(a, b uint) bool { + return a+b < a +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/scanner.go b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/scanner.go new file mode 100644 index 00000000..04f728ec --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/format/packfile/scanner.go @@ -0,0 +1,466 @@ +package packfile + +import ( + "bufio" + "bytes" + "compress/zlib" + "fmt" + "hash" + "hash/crc32" + "io" + stdioutil "io/ioutil" + "sync" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/utils/binary" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +var ( + // ErrEmptyPackfile is returned by ReadHeader when no data is found in the packfile + ErrEmptyPackfile = NewError("empty packfile") + // ErrBadSignature is returned by ReadHeader when the signature in the packfile is incorrect. + ErrBadSignature = NewError("malformed pack file signature") + // ErrUnsupportedVersion is returned by ReadHeader when the packfile version is + // different than VersionSupported. + ErrUnsupportedVersion = NewError("unsupported packfile version") + // ErrSeekNotSupported returned if seek is not support + ErrSeekNotSupported = NewError("not seek support") +) + +// ObjectHeader contains the information related to the object, this information +// is collected from the previous bytes to the content of the object. +type ObjectHeader struct { + Type plumbing.ObjectType + Offset int64 + Length int64 + Reference plumbing.Hash + OffsetReference int64 +} + +type Scanner struct { + r *scannerReader + crc hash.Hash32 + + // pendingObject is used to detect if an object has been read, or still + // is waiting to be read + pendingObject *ObjectHeader + version, objects uint32 + + // lsSeekable says if this scanner can do Seek or not, to have a Scanner + // seekable a r implementing io.Seeker is required + IsSeekable bool +} + +// NewScanner returns a new Scanner based on a reader, if the given reader +// implements io.ReadSeeker the Scanner will be also Seekable +func NewScanner(r io.Reader) *Scanner { + _, ok := r.(io.ReadSeeker) + + crc := crc32.NewIEEE() + return &Scanner{ + r: newScannerReader(r, crc), + crc: crc, + IsSeekable: ok, + } +} + +func (s *Scanner) Reset(r io.Reader) { + _, ok := r.(io.ReadSeeker) + + s.r.Reset(r) + s.crc.Reset() + s.IsSeekable = ok + s.pendingObject = nil + s.version = 0 + s.objects = 0 +} + +// Header reads the whole packfile header (signature, version and object count). +// It returns the version and the object count and performs checks on the +// validity of the signature and the version fields. +func (s *Scanner) Header() (version, objects uint32, err error) { + if s.version != 0 { + return s.version, s.objects, nil + } + + sig, err := s.readSignature() + if err != nil { + if err == io.EOF { + err = ErrEmptyPackfile + } + + return + } + + if !s.isValidSignature(sig) { + err = ErrBadSignature + return + } + + version, err = s.readVersion() + s.version = version + if err != nil { + return + } + + if !s.isSupportedVersion(version) { + err = ErrUnsupportedVersion.AddDetails("%d", version) + return + } + + objects, err = s.readCount() + s.objects = objects + return +} + +// readSignature reads an returns the signature field in the packfile. +func (s *Scanner) readSignature() ([]byte, error) { + var sig = make([]byte, 4) + if _, err := io.ReadFull(s.r, sig); err != nil { + return []byte{}, err + } + + return sig, nil +} + +// isValidSignature returns if sig is a valid packfile signature. +func (s *Scanner) isValidSignature(sig []byte) bool { + return bytes.Equal(sig, signature) +} + +// readVersion reads and returns the version field of a packfile. +func (s *Scanner) readVersion() (uint32, error) { + return binary.ReadUint32(s.r) +} + +// isSupportedVersion returns whether version v is supported by the parser. +// The current supported version is VersionSupported, defined above. +func (s *Scanner) isSupportedVersion(v uint32) bool { + return v == VersionSupported +} + +// readCount reads and returns the count of objects field of a packfile. +func (s *Scanner) readCount() (uint32, error) { + return binary.ReadUint32(s.r) +} + +// SeekObjectHeader seeks to specified offset and returns the ObjectHeader +// for the next object in the reader +func (s *Scanner) SeekObjectHeader(offset int64) (*ObjectHeader, error) { + // if seeking we assume that you are not interested in the header + if s.version == 0 { + s.version = VersionSupported + } + + if _, err := s.r.Seek(offset, io.SeekStart); err != nil { + return nil, err + } + + h, err := s.nextObjectHeader() + if err != nil { + return nil, err + } + + h.Offset = offset + return h, nil +} + +// NextObjectHeader returns the ObjectHeader for the next object in the reader +func (s *Scanner) NextObjectHeader() (*ObjectHeader, error) { + if err := s.doPending(); err != nil { + return nil, err + } + + offset, err := s.r.Seek(0, io.SeekCurrent) + if err != nil { + return nil, err + } + + h, err := s.nextObjectHeader() + if err != nil { + return nil, err + } + + h.Offset = offset + return h, nil +} + +// nextObjectHeader returns the ObjectHeader for the next object in the reader +// without the Offset field +func (s *Scanner) nextObjectHeader() (*ObjectHeader, error) { + s.r.Flush() + s.crc.Reset() + + h := &ObjectHeader{} + s.pendingObject = h + + var err error + h.Offset, err = s.r.Seek(0, io.SeekCurrent) + if err != nil { + return nil, err + } + + h.Type, h.Length, err = s.readObjectTypeAndLength() + if err != nil { + return nil, err + } + + switch h.Type { + case plumbing.OFSDeltaObject: + no, err := binary.ReadVariableWidthInt(s.r) + if err != nil { + return nil, err + } + + h.OffsetReference = h.Offset - no + case plumbing.REFDeltaObject: + var err error + h.Reference, err = binary.ReadHash(s.r) + if err != nil { + return nil, err + } + } + + return h, nil +} + +func (s *Scanner) doPending() error { + if s.version == 0 { + var err error + s.version, s.objects, err = s.Header() + if err != nil { + return err + } + } + + return s.discardObjectIfNeeded() +} + +func (s *Scanner) discardObjectIfNeeded() error { + if s.pendingObject == nil { + return nil + } + + h := s.pendingObject + n, _, err := s.NextObject(stdioutil.Discard) + if err != nil { + return err + } + + if n != h.Length { + return fmt.Errorf( + "error discarding object, discarded %d, expected %d", + n, h.Length, + ) + } + + return nil +} + +// ReadObjectTypeAndLength reads and returns the object type and the +// length field from an object entry in a packfile. +func (s *Scanner) readObjectTypeAndLength() (plumbing.ObjectType, int64, error) { + t, c, err := s.readType() + if err != nil { + return t, 0, err + } + + l, err := s.readLength(c) + + return t, l, err +} + +func (s *Scanner) readType() (plumbing.ObjectType, byte, error) { + var c byte + var err error + if c, err = s.r.ReadByte(); err != nil { + return plumbing.ObjectType(0), 0, err + } + + typ := parseType(c) + + return typ, c, nil +} + +func parseType(b byte) plumbing.ObjectType { + return plumbing.ObjectType((b & maskType) >> firstLengthBits) +} + +// the length is codified in the last 4 bits of the first byte and in +// the last 7 bits of subsequent bytes. Last byte has a 0 MSB. +func (s *Scanner) readLength(first byte) (int64, error) { + length := int64(first & maskFirstLength) + + c := first + shift := firstLengthBits + var err error + for c&maskContinue > 0 { + if c, err = s.r.ReadByte(); err != nil { + return 0, err + } + + length += int64(c&maskLength) << shift + shift += lengthBits + } + + return length, nil +} + +// NextObject writes the content of the next object into the reader, returns +// the number of bytes written, the CRC32 of the content and an error, if any +func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err error) { + s.pendingObject = nil + written, err = s.copyObject(w) + + s.r.Flush() + crc32 = s.crc.Sum32() + s.crc.Reset() + + return +} + +// ReadRegularObject reads and write a non-deltified object +// from it zlib stream in an object entry in the packfile. +func (s *Scanner) copyObject(w io.Writer) (n int64, err error) { + zr := zlibReaderPool.Get().(io.ReadCloser) + defer zlibReaderPool.Put(zr) + + if err = zr.(zlib.Resetter).Reset(s.r, nil); err != nil { + return 0, fmt.Errorf("zlib reset error: %s", err) + } + + defer ioutil.CheckClose(zr, &err) + buf := byteSlicePool.Get().([]byte) + n, err = io.CopyBuffer(w, zr, buf) + byteSlicePool.Put(buf) + return +} + +var byteSlicePool = sync.Pool{ + New: func() interface{} { + return make([]byte, 32*1024) + }, +} + +// SeekFromStart sets a new offset from start, returns the old position before +// the change. +func (s *Scanner) SeekFromStart(offset int64) (previous int64, err error) { + // if seeking we assume that you are not interested in the header + if s.version == 0 { + s.version = VersionSupported + } + + previous, err = s.r.Seek(0, io.SeekCurrent) + if err != nil { + return -1, err + } + + _, err = s.r.Seek(offset, io.SeekStart) + return previous, err +} + +// Checksum returns the checksum of the packfile +func (s *Scanner) Checksum() (plumbing.Hash, error) { + err := s.discardObjectIfNeeded() + if err != nil { + return plumbing.ZeroHash, err + } + + return binary.ReadHash(s.r) +} + +// Close reads the reader until io.EOF +func (s *Scanner) Close() error { + buf := byteSlicePool.Get().([]byte) + _, err := io.CopyBuffer(stdioutil.Discard, s.r, buf) + byteSlicePool.Put(buf) + return err +} + +// Flush is a no-op (deprecated) +func (s *Scanner) Flush() error { + return nil +} + +// scannerReader has the following characteristics: +// - Provides an io.SeekReader impl for bufio.Reader, when the underlying +// reader supports it. +// - Keeps track of the current read position, for when the underlying reader +// isn't an io.SeekReader, but we still want to know the current offset. +// - Writes to the hash writer what it reads, with the aid of a smaller buffer. +// The buffer helps avoid a performance penality for performing small writes +// to the crc32 hash writer. +type scannerReader struct { + reader io.Reader + crc io.Writer + rbuf *bufio.Reader + wbuf *bufio.Writer + offset int64 +} + +func newScannerReader(r io.Reader, h io.Writer) *scannerReader { + sr := &scannerReader{ + rbuf: bufio.NewReader(nil), + wbuf: bufio.NewWriterSize(nil, 64), + crc: h, + } + sr.Reset(r) + + return sr +} + +func (r *scannerReader) Reset(reader io.Reader) { + r.reader = reader + r.rbuf.Reset(r.reader) + r.wbuf.Reset(r.crc) + + r.offset = 0 + if seeker, ok := r.reader.(io.ReadSeeker); ok { + r.offset, _ = seeker.Seek(0, io.SeekCurrent) + } +} + +func (r *scannerReader) Read(p []byte) (n int, err error) { + n, err = r.rbuf.Read(p) + + r.offset += int64(n) + if _, err := r.wbuf.Write(p[:n]); err != nil { + return n, err + } + return +} + +func (r *scannerReader) ReadByte() (b byte, err error) { + b, err = r.rbuf.ReadByte() + if err == nil { + r.offset++ + return b, r.wbuf.WriteByte(b) + } + return +} + +func (r *scannerReader) Flush() error { + return r.wbuf.Flush() +} + +// Seek seeks to a location. If the underlying reader is not an io.ReadSeeker, +// then only whence=io.SeekCurrent is supported, any other operation fails. +func (r *scannerReader) Seek(offset int64, whence int) (int64, error) { + var err error + + if seeker, ok := r.reader.(io.ReadSeeker); !ok { + if whence != io.SeekCurrent || offset != 0 { + return -1, ErrSeekNotSupported + } + } else { + if whence == io.SeekCurrent && offset == 0 { + return r.offset, nil + } + + r.offset, err = seeker.Seek(offset, whence) + r.rbuf.Reset(r.reader) + } + + return r.offset, err +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/revlist/revlist.go b/vendor/github.com/devtron-labs/go-git/plumbing/revlist/revlist.go new file mode 100644 index 00000000..70ebd600 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/revlist/revlist.go @@ -0,0 +1,230 @@ +// Package revlist provides support to access the ancestors of commits, in a +// similar way as the git-rev-list command. +package revlist + +import ( + "fmt" + "io" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/plumbing/object" + "github.com/devtron-labs/go-git/plumbing/storer" +) + +// Objects applies a complementary set. It gets all the hashes from all +// the reachable objects from the given objects. Ignore param are object hashes +// that we want to ignore on the result. All that objects must be accessible +// from the object storer. +func Objects( + s storer.EncodedObjectStorer, + objs, + ignore []plumbing.Hash, +) ([]plumbing.Hash, error) { + return ObjectsWithStorageForIgnores(s, s, objs, ignore) +} + +// ObjectsWithStorageForIgnores is the same as Objects, but a +// secondary storage layer can be provided, to be used to finding the +// full set of objects to be ignored while finding the reachable +// objects. This is useful when the main `s` storage layer is slow +// and/or remote, while the ignore list is available somewhere local. +func ObjectsWithStorageForIgnores( + s, ignoreStore storer.EncodedObjectStorer, + objs, + ignore []plumbing.Hash, +) ([]plumbing.Hash, error) { + ignore, err := objects(ignoreStore, ignore, nil, true) + if err != nil { + return nil, err + } + + return objects(s, objs, ignore, false) +} + +func objects( + s storer.EncodedObjectStorer, + objects, + ignore []plumbing.Hash, + allowMissingObjects bool, +) ([]plumbing.Hash, error) { + seen := hashListToSet(ignore) + result := make(map[plumbing.Hash]bool) + visited := make(map[plumbing.Hash]bool) + + walkerFunc := func(h plumbing.Hash) { + if !seen[h] { + result[h] = true + seen[h] = true + } + } + + for _, h := range objects { + if err := processObject(s, h, seen, visited, ignore, walkerFunc); err != nil { + if allowMissingObjects && err == plumbing.ErrObjectNotFound { + continue + } + + return nil, err + } + } + + return hashSetToList(result), nil +} + +// processObject obtains the object using the hash an process it depending of its type +func processObject( + s storer.EncodedObjectStorer, + h plumbing.Hash, + seen map[plumbing.Hash]bool, + visited map[plumbing.Hash]bool, + ignore []plumbing.Hash, + walkerFunc func(h plumbing.Hash), +) error { + if seen[h] { + return nil + } + + o, err := s.EncodedObject(plumbing.AnyObject, h) + if err != nil { + return err + } + + do, err := object.DecodeObject(s, o) + if err != nil { + return err + } + + switch do := do.(type) { + case *object.Commit: + return reachableObjects(do, seen, visited, ignore, walkerFunc) + case *object.Tree: + return iterateCommitTrees(seen, do, walkerFunc) + case *object.Tag: + walkerFunc(do.Hash) + return processObject(s, do.Target, seen, visited, ignore, walkerFunc) + case *object.Blob: + walkerFunc(do.Hash) + default: + return fmt.Errorf("object type not valid: %s. "+ + "Object reference: %s", o.Type(), o.Hash()) + } + + return nil +} + +// reachableObjects returns, using the callback function, all the reachable +// objects from the specified commit. To avoid to iterate over seen commits, +// if a commit hash is into the 'seen' set, we will not iterate all his trees +// and blobs objects. +func reachableObjects( + commit *object.Commit, + seen map[plumbing.Hash]bool, + visited map[plumbing.Hash]bool, + ignore []plumbing.Hash, + cb func(h plumbing.Hash), +) error { + i := object.NewCommitPreorderIter(commit, seen, ignore) + pending := make(map[plumbing.Hash]bool) + addPendingParents(pending, visited, commit) + for { + commit, err := i.Next() + if err == io.EOF { + break + } + + if err != nil { + return err + } + + if pending[commit.Hash] { + delete(pending, commit.Hash) + } + + addPendingParents(pending, visited, commit) + + if visited[commit.Hash] && len(pending) == 0 { + break + } + + if seen[commit.Hash] { + continue + } + + cb(commit.Hash) + + tree, err := commit.Tree() + if err != nil { + return err + } + + if err := iterateCommitTrees(seen, tree, cb); err != nil { + return err + } + } + + return nil +} + +func addPendingParents(pending, visited map[plumbing.Hash]bool, commit *object.Commit) { + for _, p := range commit.ParentHashes { + if !visited[p] { + pending[p] = true + } + } +} + +// iterateCommitTrees iterate all reachable trees from the given commit +func iterateCommitTrees( + seen map[plumbing.Hash]bool, + tree *object.Tree, + cb func(h plumbing.Hash), +) error { + if seen[tree.Hash] { + return nil + } + + cb(tree.Hash) + + treeWalker := object.NewTreeWalker(tree, true, seen) + + for { + _, e, err := treeWalker.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + + if e.Mode == filemode.Submodule { + continue + } + + if seen[e.Hash] { + continue + } + + cb(e.Hash) + } + + return nil +} + +func hashSetToList(hashes map[plumbing.Hash]bool) []plumbing.Hash { + var result []plumbing.Hash + for key := range hashes { + result = append(result, key) + } + + return result +} + +func hashListToSet(hashes []plumbing.Hash) map[plumbing.Hash]bool { + result := make(map[plumbing.Hash]bool) + for _, h := range hashes { + result[h] = true + } + + return result +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/client/client.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/client/client.go new file mode 100644 index 00000000..e2ccac94 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/client/client.go @@ -0,0 +1,48 @@ +// Package client contains helper function to deal with the different client +// protocols. +package client + +import ( + "fmt" + + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/file" + "github.com/devtron-labs/go-git/plumbing/transport/git" + "github.com/devtron-labs/go-git/plumbing/transport/http" + "github.com/devtron-labs/go-git/plumbing/transport/ssh" +) + +// Protocols are the protocols supported by default. +var Protocols = map[string]transport.Transport{ + "http": http.DefaultClient, + "https": http.DefaultClient, + "ssh": ssh.DefaultClient, + "git": git.DefaultClient, + "file": file.DefaultClient, +} + +// InstallProtocol adds or modifies an existing protocol. +func InstallProtocol(scheme string, c transport.Transport) { + if c == nil { + delete(Protocols, scheme) + return + } + + Protocols[scheme] = c +} + +// NewClient returns the appropriate client among of the set of known protocols: +// http://, https://, ssh:// and file://. +// See `InstallProtocol` to add or modify protocols. +func NewClient(endpoint *transport.Endpoint) (transport.Transport, error) { + f, ok := Protocols[endpoint.Protocol] + if !ok { + return nil, fmt.Errorf("unsupported scheme %q", endpoint.Protocol) + } + + if f == nil { + return nil, fmt.Errorf("malformed client for scheme %q, client is defined as nil", endpoint.Protocol) + } + + return f, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/file/client.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/file/client.go new file mode 100644 index 00000000..e22e47fe --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/file/client.go @@ -0,0 +1,156 @@ +// Package file implements the file transport protocol. +package file + +import ( + "bufio" + "errors" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/internal/common" +) + +// DefaultClient is the default local client. +var DefaultClient = NewClient( + transport.UploadPackServiceName, + transport.ReceivePackServiceName, +) + +type runner struct { + UploadPackBin string + ReceivePackBin string +} + +// NewClient returns a new local client using the given git-upload-pack and +// git-receive-pack binaries. +func NewClient(uploadPackBin, receivePackBin string) transport.Transport { + return common.NewClient(&runner{ + UploadPackBin: uploadPackBin, + ReceivePackBin: receivePackBin, + }) +} + +func prefixExecPath(cmd string) (string, error) { + // Use `git --exec-path` to find the exec path. + execCmd := exec.Command("git", "--exec-path") + + stdout, err := execCmd.StdoutPipe() + if err != nil { + return "", err + } + stdoutBuf := bufio.NewReader(stdout) + + err = execCmd.Start() + if err != nil { + return "", err + } + + execPathBytes, isPrefix, err := stdoutBuf.ReadLine() + if err != nil { + return "", err + } + if isPrefix { + return "", errors.New("Couldn't read exec-path line all at once") + } + + err = execCmd.Wait() + if err != nil { + return "", err + } + execPath := string(execPathBytes) + execPath = strings.TrimSpace(execPath) + cmd = filepath.Join(execPath, cmd) + + // Make sure it actually exists. + _, err = exec.LookPath(cmd) + if err != nil { + return "", err + } + return cmd, nil +} + +func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod, +) (common.Command, error) { + + switch cmd { + case transport.UploadPackServiceName: + cmd = r.UploadPackBin + case transport.ReceivePackServiceName: + cmd = r.ReceivePackBin + } + + _, err := exec.LookPath(cmd) + if err != nil { + if e, ok := err.(*exec.Error); ok && e.Err == exec.ErrNotFound { + cmd, err = prefixExecPath(cmd) + if err != nil { + return nil, err + } + } else { + return nil, err + } + } + + return &command{cmd: exec.Command(cmd, ep.Path)}, nil +} + +type command struct { + cmd *exec.Cmd + stderrCloser io.Closer + closed bool +} + +func (c *command) Start() error { + return c.cmd.Start() +} + +func (c *command) StderrPipe() (io.Reader, error) { + // Pipe returned by Command.StderrPipe has a race with Read + Command.Wait. + // We use an io.Pipe and close it after the command finishes. + r, w := io.Pipe() + c.cmd.Stderr = w + c.stderrCloser = r + return r, nil +} + +func (c *command) StdinPipe() (io.WriteCloser, error) { + return c.cmd.StdinPipe() +} + +func (c *command) StdoutPipe() (io.Reader, error) { + return c.cmd.StdoutPipe() +} + +func (c *command) Kill() error { + c.cmd.Process.Kill() + return c.Close() +} + +// Close waits for the command to exit. +func (c *command) Close() error { + if c.closed { + return nil + } + + defer func() { + c.closed = true + _ = c.stderrCloser.Close() + + }() + + err := c.cmd.Wait() + if _, ok := err.(*os.PathError); ok { + return nil + } + + // When a repository does not exist, the command exits with code 128. + if _, ok := err.(*exec.ExitError); ok { + return nil + } + + return err +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/file/server.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/file/server.go new file mode 100644 index 00000000..f64e14a9 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/file/server.go @@ -0,0 +1,53 @@ +package file + +import ( + "fmt" + "os" + + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/internal/common" + "github.com/devtron-labs/go-git/plumbing/transport/server" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +// ServeUploadPack serves a git-upload-pack request using standard output, input +// and error. This is meant to be used when implementing a git-upload-pack +// command. +func ServeUploadPack(path string) error { + ep, err := transport.NewEndpoint(path) + if err != nil { + return err + } + + // TODO: define and implement a server-side AuthMethod + s, err := server.DefaultServer.NewUploadPackSession(ep, nil) + if err != nil { + return fmt.Errorf("error creating session: %s", err) + } + + return common.ServeUploadPack(srvCmd, s) +} + +// ServeReceivePack serves a git-receive-pack request using standard output, +// input and error. This is meant to be used when implementing a +// git-receive-pack command. +func ServeReceivePack(path string) error { + ep, err := transport.NewEndpoint(path) + if err != nil { + return err + } + + // TODO: define and implement a server-side AuthMethod + s, err := server.DefaultServer.NewReceivePackSession(ep, nil) + if err != nil { + return fmt.Errorf("error creating session: %s", err) + } + + return common.ServeReceivePack(srvCmd, s) +} + +var srvCmd = common.ServerCommand{ + Stdin: os.Stdin, + Stdout: ioutil.WriteNopCloser(os.Stdout), + Stderr: os.Stderr, +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/git/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/git/common.go new file mode 100644 index 00000000..238daff2 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/git/common.go @@ -0,0 +1,109 @@ +// Package git implements the git transport protocol. +package git + +import ( + "fmt" + "io" + "net" + + "github.com/devtron-labs/go-git/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/internal/common" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +// DefaultClient is the default git client. +var DefaultClient = common.NewClient(&runner{}) + +const DefaultPort = 9418 + +type runner struct{} + +// Command returns a new Command for the given cmd in the given Endpoint +func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (common.Command, error) { + // auth not allowed since git protocol doesn't support authentication + if auth != nil { + return nil, transport.ErrInvalidAuthMethod + } + c := &command{command: cmd, endpoint: ep} + if err := c.connect(); err != nil { + return nil, err + } + return c, nil +} + +type command struct { + conn net.Conn + connected bool + command string + endpoint *transport.Endpoint +} + +// Start executes the command sending the required message to the TCP connection +func (c *command) Start() error { + cmd := endpointToCommand(c.command, c.endpoint) + + e := pktline.NewEncoder(c.conn) + return e.Encode([]byte(cmd)) +} + +func (c *command) connect() error { + if c.connected { + return transport.ErrAlreadyConnected + } + + var err error + c.conn, err = net.Dial("tcp", c.getHostWithPort()) + if err != nil { + return err + } + + c.connected = true + return nil +} + +func (c *command) getHostWithPort() string { + host := c.endpoint.Host + port := c.endpoint.Port + if port <= 0 { + port = DefaultPort + } + + return fmt.Sprintf("%s:%d", host, port) +} + +// StderrPipe git protocol doesn't have any dedicated error channel +func (c *command) StderrPipe() (io.Reader, error) { + return nil, nil +} + +// StdinPipe return the underlying connection as WriteCloser, wrapped to prevent +// call to the Close function from the connection, a command execution in git +// protocol can't be closed or killed +func (c *command) StdinPipe() (io.WriteCloser, error) { + return ioutil.WriteNopCloser(c.conn), nil +} + +// StdoutPipe return the underlying connection as Reader +func (c *command) StdoutPipe() (io.Reader, error) { + return c.conn, nil +} + +func endpointToCommand(cmd string, ep *transport.Endpoint) string { + host := ep.Host + if ep.Port != DefaultPort { + host = fmt.Sprintf("%s:%d", ep.Host, ep.Port) + } + + return fmt.Sprintf("%s %s%chost=%s%c", cmd, ep.Path, 0, host, 0) +} + +// Close closes the TCP connection and connection. +func (c *command) Close() error { + if !c.connected { + return nil + } + + c.connected = false + return c.conn.Close() +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/common.go new file mode 100644 index 00000000..18a96dbf --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/common.go @@ -0,0 +1,281 @@ +// Package http implements the HTTP transport protocol. +package http + +import ( + "bytes" + "fmt" + "net" + "net/http" + "strconv" + "strings" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +// it requires a bytes.Buffer, because we need to know the length +func applyHeadersToRequest(req *http.Request, content *bytes.Buffer, host string, requestType string) { + req.Header.Add("User-Agent", "git/1.0") + req.Header.Add("Host", host) // host:port + + if content == nil { + req.Header.Add("Accept", "*/*") + return + } + + req.Header.Add("Accept", fmt.Sprintf("application/x-%s-result", requestType)) + req.Header.Add("Content-Type", fmt.Sprintf("application/x-%s-request", requestType)) + req.Header.Add("Content-Length", strconv.Itoa(content.Len())) +} + +const infoRefsPath = "/info/refs" + +func advertisedReferences(s *session, serviceName string) (ref *packp.AdvRefs, err error) { + url := fmt.Sprintf( + "%s%s?service=%s", + s.endpoint.String(), infoRefsPath, serviceName, + ) + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + + s.ApplyAuthToRequest(req) + applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName) + res, err := s.client.Do(req) + if err != nil { + return nil, err + } + + s.ModifyEndpointIfRedirect(res) + defer ioutil.CheckClose(res.Body, &err) + + if err = NewErr(res); err != nil { + return nil, err + } + + ar := packp.NewAdvRefs() + if err = ar.Decode(res.Body); err != nil { + if err == packp.ErrEmptyAdvRefs { + err = transport.ErrEmptyRemoteRepository + } + + return nil, err + } + + transport.FilterUnsupportedCapabilities(ar.Capabilities) + s.advRefs = ar + + return ar, nil +} + +type client struct { + c *http.Client +} + +// DefaultClient is the default HTTP client, which uses `http.DefaultClient`. +var DefaultClient = NewClient(nil) + +// NewClient creates a new client with a custom net/http client. +// See `InstallProtocol` to install and override default http client. +// Unless a properly initialized client is given, it will fall back into +// `http.DefaultClient`. +// +// Note that for HTTP client cannot distinguist between private repositories and +// unexistent repositories on GitHub. So it returns `ErrAuthorizationRequired` +// for both. +func NewClient(c *http.Client) transport.Transport { + if c == nil { + return &client{http.DefaultClient} + } + + return &client{ + c: c, + } +} + +func (c *client) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( + transport.UploadPackSession, error) { + + return newUploadPackSession(c.c, ep, auth) +} + +func (c *client) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( + transport.ReceivePackSession, error) { + + return newReceivePackSession(c.c, ep, auth) +} + +type session struct { + auth AuthMethod + client *http.Client + endpoint *transport.Endpoint + advRefs *packp.AdvRefs +} + +func newSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (*session, error) { + s := &session{ + auth: basicAuthFromEndpoint(ep), + client: c, + endpoint: ep, + } + if auth != nil { + a, ok := auth.(AuthMethod) + if !ok { + return nil, transport.ErrInvalidAuthMethod + } + + s.auth = a + } + + return s, nil +} + +func (s *session) ApplyAuthToRequest(req *http.Request) { + if s.auth == nil { + return + } + + s.auth.SetAuth(req) +} + +func (s *session) ModifyEndpointIfRedirect(res *http.Response) { + if res.Request == nil { + return + } + + r := res.Request + if !strings.HasSuffix(r.URL.Path, infoRefsPath) { + return + } + + h, p, err := net.SplitHostPort(r.URL.Host) + if err != nil { + h = r.URL.Host + } + if p != "" { + port, err := strconv.Atoi(p) + if err == nil { + s.endpoint.Port = port + } + } + s.endpoint.Host = h + + s.endpoint.Protocol = r.URL.Scheme + s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)] +} + +func (*session) Close() error { + return nil +} + +// AuthMethod is concrete implementation of common.AuthMethod for HTTP services +type AuthMethod interface { + transport.AuthMethod + SetAuth(r *http.Request) +} + +func basicAuthFromEndpoint(ep *transport.Endpoint) *BasicAuth { + u := ep.User + if u == "" { + return nil + } + + return &BasicAuth{u, ep.Password} +} + +// BasicAuth represent a HTTP basic auth +type BasicAuth struct { + Username, Password string +} + +func (a *BasicAuth) SetAuth(r *http.Request) { + if a == nil { + return + } + + r.SetBasicAuth(a.Username, a.Password) +} + +// Name is name of the auth +func (a *BasicAuth) Name() string { + return "http-basic-auth" +} + +func (a *BasicAuth) String() string { + masked := "*******" + if a.Password == "" { + masked = "" + } + + return fmt.Sprintf("%s - %s:%s", a.Name(), a.Username, masked) +} + +// TokenAuth implements an http.AuthMethod that can be used with http transport +// to authenticate with HTTP token authentication (also known as bearer +// authentication). +// +// IMPORTANT: If you are looking to use OAuth tokens with popular servers (e.g. +// GitHub, Bitbucket, GitLab) you should use BasicAuth instead. These servers +// use basic HTTP authentication, with the OAuth token as user or password. +// Check the documentation of your git server for details. +type TokenAuth struct { + Token string +} + +func (a *TokenAuth) SetAuth(r *http.Request) { + if a == nil { + return + } + r.Header.Add("Authorization", fmt.Sprintf("Bearer %s", a.Token)) +} + +// Name is name of the auth +func (a *TokenAuth) Name() string { + return "http-token-auth" +} + +func (a *TokenAuth) String() string { + masked := "*******" + if a.Token == "" { + masked = "" + } + return fmt.Sprintf("%s - %s", a.Name(), masked) +} + +// Err is a dedicated error to return errors based on status code +type Err struct { + Response *http.Response +} + +// NewErr returns a new Err based on a http response +func NewErr(r *http.Response) error { + if r.StatusCode >= http.StatusOK && r.StatusCode < http.StatusMultipleChoices { + return nil + } + + switch r.StatusCode { + case http.StatusUnauthorized: + return transport.ErrAuthenticationRequired + case http.StatusForbidden: + return transport.ErrAuthorizationFailed + case http.StatusNotFound: + return transport.ErrRepositoryNotFound + } + + return plumbing.NewUnexpectedError(&Err{r}) +} + +// StatusCode returns the status code of the response +func (e *Err) StatusCode() int { + return e.Response.StatusCode +} + +func (e *Err) Error() string { + return fmt.Sprintf("unexpected requesting %q status code: %d", + e.Response.Request.URL, e.Response.StatusCode, + ) +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/receive_pack.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/receive_pack.go new file mode 100644 index 00000000..60cf48fc --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/receive_pack.go @@ -0,0 +1,106 @@ +package http + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +type rpSession struct { + *session +} + +func newReceivePackSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) { + s, err := newSession(c, ep, auth) + return &rpSession{s}, err +} + +func (s *rpSession) AdvertisedReferences() (*packp.AdvRefs, error) { + return advertisedReferences(s.session, transport.ReceivePackServiceName) +} + +func (s *rpSession) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateRequest) ( + *packp.ReportStatus, error) { + url := fmt.Sprintf( + "%s/%s", + s.endpoint.String(), transport.ReceivePackServiceName, + ) + + buf := bytes.NewBuffer(nil) + if err := req.Encode(buf); err != nil { + return nil, err + } + + res, err := s.doRequest(ctx, http.MethodPost, url, buf) + if err != nil { + return nil, err + } + + r, err := ioutil.NonEmptyReader(res.Body) + if err == ioutil.ErrEmptyReader { + return nil, nil + } + + if err != nil { + return nil, err + } + + var d *sideband.Demuxer + if req.Capabilities.Supports(capability.Sideband64k) { + d = sideband.NewDemuxer(sideband.Sideband64k, r) + } else if req.Capabilities.Supports(capability.Sideband) { + d = sideband.NewDemuxer(sideband.Sideband, r) + } + if d != nil { + d.Progress = req.Progress + r = d + } + + rc := ioutil.NewReadCloser(r, res.Body) + + report := packp.NewReportStatus() + if err := report.Decode(rc); err != nil { + return nil, err + } + + return report, report.Error() +} + +func (s *rpSession) doRequest( + ctx context.Context, method, url string, content *bytes.Buffer, +) (*http.Response, error) { + + var body io.Reader + if content != nil { + body = content + } + + req, err := http.NewRequest(method, url, body) + if err != nil { + return nil, plumbing.NewPermanentError(err) + } + + applyHeadersToRequest(req, content, s.endpoint.Host, transport.ReceivePackServiceName) + s.ApplyAuthToRequest(req) + + res, err := s.client.Do(req.WithContext(ctx)) + if err != nil { + return nil, plumbing.NewUnexpectedError(err) + } + + if err := NewErr(res); err != nil { + _ = res.Body.Close() + return nil, err + } + + return res, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/upload_pack.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/upload_pack.go new file mode 100644 index 00000000..a555916e --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/http/upload_pack.go @@ -0,0 +1,123 @@ +package http + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/internal/common" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +type upSession struct { + *session +} + +func newUploadPackSession(c *http.Client, ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) { + s, err := newSession(c, ep, auth) + return &upSession{s}, err +} + +func (s *upSession) AdvertisedReferences() (*packp.AdvRefs, error) { + return advertisedReferences(s.session, transport.UploadPackServiceName) +} + +func (s *upSession) UploadPack( + ctx context.Context, req *packp.UploadPackRequest, +) (*packp.UploadPackResponse, error) { + + if req.IsEmpty() { + return nil, transport.ErrEmptyUploadPackRequest + } + + if err := req.Validate(); err != nil { + return nil, err + } + + url := fmt.Sprintf( + "%s/%s", + s.endpoint.String(), transport.UploadPackServiceName, + ) + + content, err := uploadPackRequestToReader(req) + if err != nil { + return nil, err + } + + res, err := s.doRequest(ctx, http.MethodPost, url, content) + if err != nil { + return nil, err + } + + r, err := ioutil.NonEmptyReader(res.Body) + if err != nil { + if err == ioutil.ErrEmptyReader || err == io.ErrUnexpectedEOF { + return nil, transport.ErrEmptyUploadPackRequest + } + + return nil, err + } + + rc := ioutil.NewReadCloser(r, res.Body) + return common.DecodeUploadPackResponse(rc, req) +} + +// Close does nothing. +func (s *upSession) Close() error { + return nil +} + +func (s *upSession) doRequest( + ctx context.Context, method, url string, content *bytes.Buffer, +) (*http.Response, error) { + + var body io.Reader + if content != nil { + body = content + } + + req, err := http.NewRequest(method, url, body) + if err != nil { + return nil, plumbing.NewPermanentError(err) + } + + applyHeadersToRequest(req, content, s.endpoint.Host, transport.UploadPackServiceName) + s.ApplyAuthToRequest(req) + + res, err := s.client.Do(req.WithContext(ctx)) + if err != nil { + return nil, plumbing.NewUnexpectedError(err) + } + + if err := NewErr(res); err != nil { + _ = res.Body.Close() + return nil, err + } + + return res, nil +} + +func uploadPackRequestToReader(req *packp.UploadPackRequest) (*bytes.Buffer, error) { + buf := bytes.NewBuffer(nil) + e := pktline.NewEncoder(buf) + + if err := req.UploadRequest.Encode(buf); err != nil { + return nil, fmt.Errorf("sending upload-req message: %s", err) + } + + if err := req.UploadHaves.Encode(buf, false); err != nil { + return nil, fmt.Errorf("sending haves message: %s", err) + } + + if err := e.EncodeString("done\n"); err != nil { + return nil, err + } + + return buf, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/common.go new file mode 100644 index 00000000..022578c6 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/common.go @@ -0,0 +1,467 @@ +// Package common implements the git pack protocol with a pluggable transport. +// This is a low-level package to implement new transports. Use a concrete +// implementation instead (e.g. http, file, ssh). +// +// A simple example of usage can be found in the file package. +package common + +import ( + "bufio" + "context" + "errors" + "fmt" + "io" + stdioutil "io/ioutil" + "strings" + "time" + + "github.com/devtron-labs/go-git/plumbing/format/pktline" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +const ( + readErrorSecondsTimeout = 10 +) + +var ( + ErrTimeoutExceeded = errors.New("timeout exceeded") +) + +// Commander creates Command instances. This is the main entry point for +// transport implementations. +type Commander interface { + // Command creates a new Command for the given git command and + // endpoint. cmd can be git-upload-pack or git-receive-pack. An + // error should be returned if the endpoint is not supported or the + // command cannot be created (e.g. binary does not exist, connection + // cannot be established). + Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (Command, error) +} + +// Command is used for a single command execution. +// This interface is modeled after exec.Cmd and ssh.Session in the standard +// library. +type Command interface { + // StderrPipe returns a pipe that will be connected to the command's + // standard error when the command starts. It should not be called after + // Start. + StderrPipe() (io.Reader, error) + // StdinPipe returns a pipe that will be connected to the command's + // standard input when the command starts. It should not be called after + // Start. The pipe should be closed when no more input is expected. + StdinPipe() (io.WriteCloser, error) + // StdoutPipe returns a pipe that will be connected to the command's + // standard output when the command starts. It should not be called after + // Start. + StdoutPipe() (io.Reader, error) + // Start starts the specified command. It does not wait for it to + // complete. + Start() error + // Close closes the command and releases any resources used by it. It + // will block until the command exits. + Close() error +} + +// CommandKiller expands the Command interface, enableing it for being killed. +type CommandKiller interface { + // Kill and close the session whatever the state it is. It will block until + // the command is terminated. + Kill() error +} + +type client struct { + cmdr Commander +} + +// NewClient creates a new client using the given Commander. +func NewClient(runner Commander) transport.Transport { + return &client{runner} +} + +// NewUploadPackSession creates a new UploadPackSession. +func (c *client) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( + transport.UploadPackSession, error) { + + return c.newSession(transport.UploadPackServiceName, ep, auth) +} + +// NewReceivePackSession creates a new ReceivePackSession. +func (c *client) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) ( + transport.ReceivePackSession, error) { + + return c.newSession(transport.ReceivePackServiceName, ep, auth) +} + +type session struct { + Stdin io.WriteCloser + Stdout io.Reader + Command Command + + isReceivePack bool + advRefs *packp.AdvRefs + packRun bool + finished bool + firstErrLine chan string +} + +func (c *client) newSession(s string, ep *transport.Endpoint, auth transport.AuthMethod) (*session, error) { + cmd, err := c.cmdr.Command(s, ep, auth) + if err != nil { + return nil, err + } + + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + if err := cmd.Start(); err != nil { + return nil, err + } + + return &session{ + Stdin: stdin, + Stdout: stdout, + Command: cmd, + firstErrLine: c.listenFirstError(stderr), + isReceivePack: s == transport.ReceivePackServiceName, + }, nil +} + +func (c *client) listenFirstError(r io.Reader) chan string { + if r == nil { + return nil + } + + errLine := make(chan string, 1) + go func() { + s := bufio.NewScanner(r) + if s.Scan() { + errLine <- s.Text() + } else { + close(errLine) + } + + _, _ = io.Copy(stdioutil.Discard, r) + }() + + return errLine +} + +// AdvertisedReferences retrieves the advertised references from the server. +func (s *session) AdvertisedReferences() (*packp.AdvRefs, error) { + if s.advRefs != nil { + return s.advRefs, nil + } + + ar := packp.NewAdvRefs() + if err := ar.Decode(s.Stdout); err != nil { + if err := s.handleAdvRefDecodeError(err); err != nil { + return nil, err + } + } + + transport.FilterUnsupportedCapabilities(ar.Capabilities) + s.advRefs = ar + return ar, nil +} + +func (s *session) handleAdvRefDecodeError(err error) error { + // If repository is not found, we get empty stdout and server writes an + // error to stderr. + if err == packp.ErrEmptyInput { + s.finished = true + if err := s.checkNotFoundError(); err != nil { + return err + } + + return io.ErrUnexpectedEOF + } + + // For empty (but existing) repositories, we get empty advertised-references + // message. But valid. That is, it includes at least a flush. + if err == packp.ErrEmptyAdvRefs { + // Empty repositories are valid for git-receive-pack. + if s.isReceivePack { + return nil + } + + if err := s.finish(); err != nil { + return err + } + + return transport.ErrEmptyRemoteRepository + } + + // Some server sends the errors as normal content (git protocol), so when + // we try to decode it fails, we need to check the content of it, to detect + // not found errors + if uerr, ok := err.(*packp.ErrUnexpectedData); ok { + if isRepoNotFoundError(string(uerr.Data)) { + return transport.ErrRepositoryNotFound + } + } + + return err +} + +// UploadPack performs a request to the server to fetch a packfile. A reader is +// returned with the packfile content. The reader must be closed after reading. +func (s *session) UploadPack(ctx context.Context, req *packp.UploadPackRequest) (*packp.UploadPackResponse, error) { + if req.IsEmpty() { + return nil, transport.ErrEmptyUploadPackRequest + } + + if err := req.Validate(); err != nil { + return nil, err + } + + if _, err := s.AdvertisedReferences(); err != nil { + return nil, err + } + + s.packRun = true + + in := s.StdinContext(ctx) + out := s.StdoutContext(ctx) + + if err := uploadPack(in, out, req); err != nil { + return nil, err + } + + r, err := ioutil.NonEmptyReader(out) + if err == ioutil.ErrEmptyReader { + if c, ok := s.Stdout.(io.Closer); ok { + _ = c.Close() + } + + return nil, transport.ErrEmptyUploadPackRequest + } + + if err != nil { + return nil, err + } + + rc := ioutil.NewReadCloser(r, s) + return DecodeUploadPackResponse(rc, req) +} + +func (s *session) StdinContext(ctx context.Context) io.WriteCloser { + return ioutil.NewWriteCloserOnError( + ioutil.NewContextWriteCloser(ctx, s.Stdin), + s.onError, + ) +} + +func (s *session) StdoutContext(ctx context.Context) io.Reader { + return ioutil.NewReaderOnError( + ioutil.NewContextReader(ctx, s.Stdout), + s.onError, + ) +} + +func (s *session) onError(err error) { + if k, ok := s.Command.(CommandKiller); ok { + _ = k.Kill() + } + + _ = s.Close() +} + +func (s *session) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateRequest) (*packp.ReportStatus, error) { + if _, err := s.AdvertisedReferences(); err != nil { + return nil, err + } + + s.packRun = true + + w := s.StdinContext(ctx) + if err := req.Encode(w); err != nil { + return nil, err + } + + if err := w.Close(); err != nil { + return nil, err + } + + if !req.Capabilities.Supports(capability.ReportStatus) { + // If we don't have report-status, we can only + // check return value error. + return nil, s.Command.Close() + } + + r := s.StdoutContext(ctx) + + var d *sideband.Demuxer + if req.Capabilities.Supports(capability.Sideband64k) { + d = sideband.NewDemuxer(sideband.Sideband64k, r) + } else if req.Capabilities.Supports(capability.Sideband) { + d = sideband.NewDemuxer(sideband.Sideband, r) + } + if d != nil { + d.Progress = req.Progress + r = d + } + + report := packp.NewReportStatus() + if err := report.Decode(r); err != nil { + return nil, err + } + + if err := report.Error(); err != nil { + defer s.Close() + return report, err + } + + return report, s.Command.Close() +} + +func (s *session) finish() error { + if s.finished { + return nil + } + + s.finished = true + + // If we did not run a upload/receive-pack, we close the connection + // gracefully by sending a flush packet to the server. If the server + // operates correctly, it will exit with status 0. + if !s.packRun { + _, err := s.Stdin.Write(pktline.FlushPkt) + return err + } + + return nil +} + +func (s *session) Close() (err error) { + err = s.finish() + + defer ioutil.CheckClose(s.Command, &err) + return +} + +func (s *session) checkNotFoundError() error { + t := time.NewTicker(time.Second * readErrorSecondsTimeout) + defer t.Stop() + + select { + case <-t.C: + return ErrTimeoutExceeded + case line, ok := <-s.firstErrLine: + if !ok { + return nil + } + + if isRepoNotFoundError(line) { + return transport.ErrRepositoryNotFound + } + + return fmt.Errorf("unknown error: %s", line) + } +} + +var ( + githubRepoNotFoundErr = "ERROR: Repository not found." + bitbucketRepoNotFoundErr = "conq: repository does not exist." + localRepoNotFoundErr = "does not appear to be a git repository" + gitProtocolNotFoundErr = "ERR \n Repository not found." + gitProtocolNoSuchErr = "ERR no such repository" + gitProtocolAccessDeniedErr = "ERR access denied" + gogsAccessDeniedErr = "Gogs: Repository does not exist or you do not have access" +) + +func isRepoNotFoundError(s string) bool { + if strings.HasPrefix(s, githubRepoNotFoundErr) { + return true + } + + if strings.HasPrefix(s, bitbucketRepoNotFoundErr) { + return true + } + + if strings.HasSuffix(s, localRepoNotFoundErr) { + return true + } + + if strings.HasPrefix(s, gitProtocolNotFoundErr) { + return true + } + + if strings.HasPrefix(s, gitProtocolNoSuchErr) { + return true + } + + if strings.HasPrefix(s, gitProtocolAccessDeniedErr) { + return true + } + + if strings.HasPrefix(s, gogsAccessDeniedErr) { + return true + } + + return false +} + +var ( + nak = []byte("NAK") + eol = []byte("\n") +) + +// uploadPack implements the git-upload-pack protocol. +func uploadPack(w io.WriteCloser, r io.Reader, req *packp.UploadPackRequest) error { + // TODO support multi_ack mode + // TODO support multi_ack_detailed mode + // TODO support acks for common objects + // TODO build a proper state machine for all these processing options + + if err := req.UploadRequest.Encode(w); err != nil { + return fmt.Errorf("sending upload-req message: %s", err) + } + + if err := req.UploadHaves.Encode(w, true); err != nil { + return fmt.Errorf("sending haves message: %s", err) + } + + if err := sendDone(w); err != nil { + return fmt.Errorf("sending done message: %s", err) + } + + if err := w.Close(); err != nil { + return fmt.Errorf("closing input: %s", err) + } + + return nil +} + +func sendDone(w io.Writer) error { + e := pktline.NewEncoder(w) + + return e.Encodef("done\n") +} + +// DecodeUploadPackResponse decodes r into a new packp.UploadPackResponse +func DecodeUploadPackResponse(r io.ReadCloser, req *packp.UploadPackRequest) ( + *packp.UploadPackResponse, error, +) { + res := packp.NewUploadPackResponse(req) + if err := res.Decode(r); err != nil { + return nil, fmt.Errorf("error decoding upload-pack response: %s", err) + } + + return res, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/server.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/server.go new file mode 100644 index 00000000..d729eb26 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/internal/common/server.go @@ -0,0 +1,73 @@ +package common + +import ( + "context" + "fmt" + "io" + + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +// ServerCommand is used for a single server command execution. +type ServerCommand struct { + Stderr io.Writer + Stdout io.WriteCloser + Stdin io.Reader +} + +func ServeUploadPack(cmd ServerCommand, s transport.UploadPackSession) (err error) { + ioutil.CheckClose(cmd.Stdout, &err) + + ar, err := s.AdvertisedReferences() + if err != nil { + return err + } + + if err := ar.Encode(cmd.Stdout); err != nil { + return err + } + + req := packp.NewUploadPackRequest() + if err := req.Decode(cmd.Stdin); err != nil { + return err + } + + var resp *packp.UploadPackResponse + resp, err = s.UploadPack(context.TODO(), req) + if err != nil { + return err + } + + return resp.Encode(cmd.Stdout) +} + +func ServeReceivePack(cmd ServerCommand, s transport.ReceivePackSession) error { + ar, err := s.AdvertisedReferences() + if err != nil { + return fmt.Errorf("internal error in advertised references: %s", err) + } + + if err := ar.Encode(cmd.Stdout); err != nil { + return fmt.Errorf("error in advertised references encoding: %s", err) + } + + req := packp.NewReferenceUpdateRequest() + if err := req.Decode(cmd.Stdin); err != nil { + return fmt.Errorf("error decoding: %s", err) + } + + rs, err := s.ReceivePack(context.TODO(), req) + if rs != nil { + if err := rs.Encode(cmd.Stdout); err != nil { + return fmt.Errorf("error in encoding report status %s", err) + } + } + + if err != nil { + return fmt.Errorf("error in receive pack: %s", err) + } + + return nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/server/loader.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/server/loader.go new file mode 100644 index 00000000..c7168ba9 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/server/loader.go @@ -0,0 +1,64 @@ +package server + +import ( + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/storage/filesystem" + + "gopkg.in/src-d/go-billy.v4" + "gopkg.in/src-d/go-billy.v4/osfs" +) + +// DefaultLoader is a filesystem loader ignoring host and resolving paths to /. +var DefaultLoader = NewFilesystemLoader(osfs.New("")) + +// Loader loads repository's storer.Storer based on an optional host and a path. +type Loader interface { + // Load loads a storer.Storer given a transport.Endpoint. + // Returns transport.ErrRepositoryNotFound if the repository does not + // exist. + Load(ep *transport.Endpoint) (storer.Storer, error) +} + +type fsLoader struct { + base billy.Filesystem +} + +// NewFilesystemLoader creates a Loader that ignores host and resolves paths +// with a given base filesystem. +func NewFilesystemLoader(base billy.Filesystem) Loader { + return &fsLoader{base} +} + +// Load looks up the endpoint's path in the base file system and returns a +// storer for it. Returns transport.ErrRepositoryNotFound if a repository does +// not exist in the given path. +func (l *fsLoader) Load(ep *transport.Endpoint) (storer.Storer, error) { + fs, err := l.base.Chroot(ep.Path) + if err != nil { + return nil, err + } + + if _, err := fs.Stat("config"); err != nil { + return nil, transport.ErrRepositoryNotFound + } + + return filesystem.NewStorage(fs, cache.NewObjectLRUDefault()), nil +} + +// MapLoader is a Loader that uses a lookup map of storer.Storer by +// transport.Endpoint. +type MapLoader map[string]storer.Storer + +// Load returns a storer.Storer for given a transport.Endpoint by looking it up +// in the map. Returns transport.ErrRepositoryNotFound if the endpoint does not +// exist. +func (l MapLoader) Load(ep *transport.Endpoint) (storer.Storer, error) { + s, ok := l[ep.String()] + if !ok { + return nil, transport.ErrRepositoryNotFound + } + + return s, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/server/server.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/server/server.go new file mode 100644 index 00000000..eca51376 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/server/server.go @@ -0,0 +1,422 @@ +// Package server implements the git server protocol. For most use cases, the +// transport-specific implementations should be used. +package server + +import ( + "context" + "errors" + "fmt" + "io" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/packfile" + "github.com/devtron-labs/go-git/plumbing/protocol/packp" + "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" + "github.com/devtron-labs/go-git/plumbing/revlist" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +var DefaultServer = NewServer(DefaultLoader) + +type server struct { + loader Loader + handler *handler +} + +// NewServer returns a transport.Transport implementing a git server, +// independent of transport. Each transport must wrap this. +func NewServer(loader Loader) transport.Transport { + return &server{ + loader, + &handler{asClient: false}, + } +} + +// NewClient returns a transport.Transport implementing a client with an +// embedded server. +func NewClient(loader Loader) transport.Transport { + return &server{ + loader, + &handler{asClient: true}, + } +} + +func (s *server) NewUploadPackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.UploadPackSession, error) { + sto, err := s.loader.Load(ep) + if err != nil { + return nil, err + } + + return s.handler.NewUploadPackSession(sto) +} + +func (s *server) NewReceivePackSession(ep *transport.Endpoint, auth transport.AuthMethod) (transport.ReceivePackSession, error) { + sto, err := s.loader.Load(ep) + if err != nil { + return nil, err + } + + return s.handler.NewReceivePackSession(sto) +} + +type handler struct { + asClient bool +} + +func (h *handler) NewUploadPackSession(s storer.Storer) (transport.UploadPackSession, error) { + return &upSession{ + session: session{storer: s, asClient: h.asClient}, + }, nil +} + +func (h *handler) NewReceivePackSession(s storer.Storer) (transport.ReceivePackSession, error) { + return &rpSession{ + session: session{storer: s, asClient: h.asClient}, + cmdStatus: map[plumbing.ReferenceName]error{}, + }, nil +} + +type session struct { + storer storer.Storer + caps *capability.List + asClient bool +} + +func (s *session) Close() error { + return nil +} + +func (s *session) SetAuth(transport.AuthMethod) error { + //TODO: deprecate + return nil +} + +func (s *session) checkSupportedCapabilities(cl *capability.List) error { + for _, c := range cl.All() { + if !s.caps.Supports(c) { + return fmt.Errorf("unsupported capability: %s", c) + } + } + + return nil +} + +type upSession struct { + session +} + +func (s *upSession) AdvertisedReferences() (*packp.AdvRefs, error) { + ar := packp.NewAdvRefs() + + if err := s.setSupportedCapabilities(ar.Capabilities); err != nil { + return nil, err + } + + s.caps = ar.Capabilities + + if err := setReferences(s.storer, ar); err != nil { + return nil, err + } + + if err := setHEAD(s.storer, ar); err != nil { + return nil, err + } + + if s.asClient && len(ar.References) == 0 { + return nil, transport.ErrEmptyRemoteRepository + } + + return ar, nil +} + +func (s *upSession) UploadPack(ctx context.Context, req *packp.UploadPackRequest) (*packp.UploadPackResponse, error) { + if req.IsEmpty() { + return nil, transport.ErrEmptyUploadPackRequest + } + + if err := req.Validate(); err != nil { + return nil, err + } + + if s.caps == nil { + s.caps = capability.NewList() + if err := s.setSupportedCapabilities(s.caps); err != nil { + return nil, err + } + } + + if err := s.checkSupportedCapabilities(req.Capabilities); err != nil { + return nil, err + } + + s.caps = req.Capabilities + + if len(req.Shallows) > 0 { + return nil, fmt.Errorf("shallow not supported") + } + + objs, err := s.objectsToUpload(req) + if err != nil { + return nil, err + } + + pr, pw := io.Pipe() + e := packfile.NewEncoder(pw, s.storer, false) + go func() { + // TODO: plumb through a pack window. + _, err := e.Encode(objs, 10) + pw.CloseWithError(err) + }() + + return packp.NewUploadPackResponseWithPackfile(req, + ioutil.NewContextReadCloser(ctx, pr), + ), nil +} + +func (s *upSession) objectsToUpload(req *packp.UploadPackRequest) ([]plumbing.Hash, error) { + haves, err := revlist.Objects(s.storer, req.Haves, nil) + if err != nil { + return nil, err + } + + return revlist.Objects(s.storer, req.Wants, haves) +} + +func (*upSession) setSupportedCapabilities(c *capability.List) error { + if err := c.Set(capability.Agent, capability.DefaultAgent); err != nil { + return err + } + + if err := c.Set(capability.OFSDelta); err != nil { + return err + } + + return nil +} + +type rpSession struct { + session + cmdStatus map[plumbing.ReferenceName]error + firstErr error + unpackErr error +} + +func (s *rpSession) AdvertisedReferences() (*packp.AdvRefs, error) { + ar := packp.NewAdvRefs() + + if err := s.setSupportedCapabilities(ar.Capabilities); err != nil { + return nil, err + } + + s.caps = ar.Capabilities + + if err := setReferences(s.storer, ar); err != nil { + return nil, err + } + + if err := setHEAD(s.storer, ar); err != nil { + return nil, err + } + + return ar, nil +} + +var ( + ErrUpdateReference = errors.New("failed to update ref") +) + +func (s *rpSession) ReceivePack(ctx context.Context, req *packp.ReferenceUpdateRequest) (*packp.ReportStatus, error) { + if s.caps == nil { + s.caps = capability.NewList() + if err := s.setSupportedCapabilities(s.caps); err != nil { + return nil, err + } + } + + if err := s.checkSupportedCapabilities(req.Capabilities); err != nil { + return nil, err + } + + s.caps = req.Capabilities + + //TODO: Implement 'atomic' update of references. + + r := ioutil.NewContextReadCloser(ctx, req.Packfile) + if err := s.writePackfile(r); err != nil { + s.unpackErr = err + s.firstErr = err + return s.reportStatus(), err + } + + s.updateReferences(req) + return s.reportStatus(), s.firstErr +} + +func (s *rpSession) updateReferences(req *packp.ReferenceUpdateRequest) { + for _, cmd := range req.Commands { + exists, err := referenceExists(s.storer, cmd.Name) + if err != nil { + s.setStatus(cmd.Name, err) + continue + } + + switch cmd.Action() { + case packp.Create: + if exists { + s.setStatus(cmd.Name, ErrUpdateReference) + continue + } + + ref := plumbing.NewHashReference(cmd.Name, cmd.New) + err := s.storer.SetReference(ref) + s.setStatus(cmd.Name, err) + case packp.Delete: + if !exists { + s.setStatus(cmd.Name, ErrUpdateReference) + continue + } + + err := s.storer.RemoveReference(cmd.Name) + s.setStatus(cmd.Name, err) + case packp.Update: + if !exists { + s.setStatus(cmd.Name, ErrUpdateReference) + continue + } + + ref := plumbing.NewHashReference(cmd.Name, cmd.New) + err := s.storer.SetReference(ref) + s.setStatus(cmd.Name, err) + } + } +} + +func (s *rpSession) writePackfile(r io.ReadCloser) error { + if r == nil { + return nil + } + + if err := packfile.UpdateObjectStorage(s.storer, r); err != nil { + _ = r.Close() + return err + } + + return r.Close() +} + +func (s *rpSession) setStatus(ref plumbing.ReferenceName, err error) { + s.cmdStatus[ref] = err + if s.firstErr == nil && err != nil { + s.firstErr = err + } +} + +func (s *rpSession) reportStatus() *packp.ReportStatus { + if !s.caps.Supports(capability.ReportStatus) { + return nil + } + + rs := packp.NewReportStatus() + rs.UnpackStatus = "ok" + + if s.unpackErr != nil { + rs.UnpackStatus = s.unpackErr.Error() + } + + if s.cmdStatus == nil { + return rs + } + + for ref, err := range s.cmdStatus { + msg := "ok" + if err != nil { + msg = err.Error() + } + status := &packp.CommandStatus{ + ReferenceName: ref, + Status: msg, + } + rs.CommandStatuses = append(rs.CommandStatuses, status) + } + + return rs +} + +func (*rpSession) setSupportedCapabilities(c *capability.List) error { + if err := c.Set(capability.Agent, capability.DefaultAgent); err != nil { + return err + } + + if err := c.Set(capability.OFSDelta); err != nil { + return err + } + + if err := c.Set(capability.DeleteRefs); err != nil { + return err + } + + return c.Set(capability.ReportStatus) +} + +func setHEAD(s storer.Storer, ar *packp.AdvRefs) error { + ref, err := s.Reference(plumbing.HEAD) + if err == plumbing.ErrReferenceNotFound { + return nil + } + + if err != nil { + return err + } + + if ref.Type() == plumbing.SymbolicReference { + if err := ar.AddReference(ref); err != nil { + return nil + } + + ref, err = storer.ResolveReference(s, ref.Target()) + if err == plumbing.ErrReferenceNotFound { + return nil + } + + if err != nil { + return err + } + } + + if ref.Type() != plumbing.HashReference { + return plumbing.ErrInvalidType + } + + h := ref.Hash() + ar.Head = &h + + return nil +} + +func setReferences(s storer.Storer, ar *packp.AdvRefs) error { + //TODO: add peeled references. + iter, err := s.IterReferences() + if err != nil { + return err + } + + return iter.ForEach(func(ref *plumbing.Reference) error { + if ref.Type() != plumbing.HashReference { + return nil + } + + ar.References[ref.Name().String()] = ref.Hash() + return nil + }) +} + +func referenceExists(s storer.ReferenceStorer, n plumbing.ReferenceName) (bool, error) { + _, err := s.Reference(n) + if err == plumbing.ErrReferenceNotFound { + return false, nil + } + + return err == nil, err +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/auth_method.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/auth_method.go new file mode 100644 index 00000000..ec261fb7 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/auth_method.go @@ -0,0 +1,324 @@ +package ssh + +import ( + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "os" + "os/user" + "path/filepath" + + "github.com/devtron-labs/go-git/plumbing/transport" + + "github.com/mitchellh/go-homedir" + "github.com/xanzy/ssh-agent" + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/knownhosts" +) + +const DefaultUsername = "git" + +// AuthMethod is the interface all auth methods for the ssh client +// must implement. The clientConfig method returns the ssh client +// configuration needed to establish an ssh connection. +type AuthMethod interface { + transport.AuthMethod + // ClientConfig should return a valid ssh.ClientConfig to be used to create + // a connection to the SSH server. + ClientConfig() (*ssh.ClientConfig, error) +} + +// The names of the AuthMethod implementations. To be returned by the +// Name() method. Most git servers only allow PublicKeysName and +// PublicKeysCallbackName. +const ( + KeyboardInteractiveName = "ssh-keyboard-interactive" + PasswordName = "ssh-password" + PasswordCallbackName = "ssh-password-callback" + PublicKeysName = "ssh-public-keys" + PublicKeysCallbackName = "ssh-public-key-callback" +) + +// KeyboardInteractive implements AuthMethod by using a +// prompt/response sequence controlled by the server. +type KeyboardInteractive struct { + User string + Challenge ssh.KeyboardInteractiveChallenge + HostKeyCallbackHelper +} + +func (a *KeyboardInteractive) Name() string { + return KeyboardInteractiveName +} + +func (a *KeyboardInteractive) String() string { + return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) +} + +func (a *KeyboardInteractive) ClientConfig() (*ssh.ClientConfig, error) { + return a.SetHostKeyCallback(&ssh.ClientConfig{ + User: a.User, + Auth: []ssh.AuthMethod{ + a.Challenge, + }, + }) +} + +// Password implements AuthMethod by using the given password. +type Password struct { + User string + Password string + HostKeyCallbackHelper +} + +func (a *Password) Name() string { + return PasswordName +} + +func (a *Password) String() string { + return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) +} + +func (a *Password) ClientConfig() (*ssh.ClientConfig, error) { + return a.SetHostKeyCallback(&ssh.ClientConfig{ + User: a.User, + Auth: []ssh.AuthMethod{ssh.Password(a.Password)}, + }) +} + +// PasswordCallback implements AuthMethod by using a callback +// to fetch the password. +type PasswordCallback struct { + User string + Callback func() (pass string, err error) + HostKeyCallbackHelper +} + +func (a *PasswordCallback) Name() string { + return PasswordCallbackName +} + +func (a *PasswordCallback) String() string { + return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) +} + +func (a *PasswordCallback) ClientConfig() (*ssh.ClientConfig, error) { + return a.SetHostKeyCallback(&ssh.ClientConfig{ + User: a.User, + Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)}, + }) +} + +// PublicKeys implements AuthMethod by using the given key pairs. +type PublicKeys struct { + User string + Signer ssh.Signer + HostKeyCallbackHelper +} + +// NewPublicKeys returns a PublicKeys from a PEM encoded private key. An +// encryption password should be given if the pemBytes contains a password +// encrypted PEM block otherwise password should be empty. It supports RSA +// (PKCS#1), DSA (OpenSSL), and ECDSA private keys. +func NewPublicKeys(user string, pemBytes []byte, password string) (*PublicKeys, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("invalid PEM data") + } + if x509.IsEncryptedPEMBlock(block) { + key, err := x509.DecryptPEMBlock(block, []byte(password)) + if err != nil { + return nil, err + } + + block = &pem.Block{Type: block.Type, Bytes: key} + pemBytes = pem.EncodeToMemory(block) + } + + signer, err := ssh.ParsePrivateKey(pemBytes) + if err != nil { + return nil, err + } + + return &PublicKeys{User: user, Signer: signer}, nil +} + +// NewPublicKeysFromFile returns a PublicKeys from a file containing a PEM +// encoded private key. An encryption password should be given if the pemBytes +// contains a password encrypted PEM block otherwise password should be empty. +func NewPublicKeysFromFile(user, pemFile, password string) (*PublicKeys, error) { + bytes, err := ioutil.ReadFile(pemFile) + if err != nil { + return nil, err + } + + return NewPublicKeys(user, bytes, password) +} + +func (a *PublicKeys) Name() string { + return PublicKeysName +} + +func (a *PublicKeys) String() string { + return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) +} + +func (a *PublicKeys) ClientConfig() (*ssh.ClientConfig, error) { + return a.SetHostKeyCallback(&ssh.ClientConfig{ + User: a.User, + Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)}, + }) +} + +func username() (string, error) { + var username string + if user, err := user.Current(); err == nil { + username = user.Username + } else { + username = os.Getenv("USER") + } + + if username == "" { + return "", errors.New("failed to get username") + } + + return username, nil +} + +// PublicKeysCallback implements AuthMethod by asking a +// ssh.agent.Agent to act as a signer. +type PublicKeysCallback struct { + User string + Callback func() (signers []ssh.Signer, err error) + HostKeyCallbackHelper +} + +// NewSSHAgentAuth returns a PublicKeysCallback based on a SSH agent, it opens +// a pipe with the SSH agent and uses the pipe as the implementer of the public +// key callback function. +func NewSSHAgentAuth(u string) (*PublicKeysCallback, error) { + var err error + if u == "" { + u, err = username() + if err != nil { + return nil, err + } + } + + a, _, err := sshagent.New() + if err != nil { + return nil, fmt.Errorf("error creating SSH agent: %q", err) + } + + return &PublicKeysCallback{ + User: u, + Callback: a.Signers, + }, nil +} + +func (a *PublicKeysCallback) Name() string { + return PublicKeysCallbackName +} + +func (a *PublicKeysCallback) String() string { + return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) +} + +func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) { + return a.SetHostKeyCallback(&ssh.ClientConfig{ + User: a.User, + Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)}, + }) +} + +// NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a +// known_hosts file. http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT +// +// If list of files is empty, then it will be read from the SSH_KNOWN_HOSTS +// environment variable, example: +// +// /home/foo/custom_known_hosts_file:/etc/custom_known/hosts_file +// +// If SSH_KNOWN_HOSTS is not set the following file locations will be used: +// +// ~/.ssh/known_hosts +// /etc/ssh/ssh_known_hosts +func NewKnownHostsCallback(files ...string) (ssh.HostKeyCallback, error) { + var err error + + if len(files) == 0 { + if files, err = getDefaultKnownHostsFiles(); err != nil { + return nil, err + } + } + + if files, err = filterKnownHostsFiles(files...); err != nil { + return nil, err + } + + return knownhosts.New(files...) +} + +func getDefaultKnownHostsFiles() ([]string, error) { + files := filepath.SplitList(os.Getenv("SSH_KNOWN_HOSTS")) + if len(files) != 0 { + return files, nil + } + + homeDirPath, err := homedir.Dir() + if err != nil { + return nil, err + } + + return []string{ + filepath.Join(homeDirPath, "/.ssh/known_hosts"), + "/etc/ssh/ssh_known_hosts", + }, nil +} + +func filterKnownHostsFiles(files ...string) ([]string, error) { + var out []string + for _, file := range files { + _, err := os.Stat(file) + if err == nil { + out = append(out, file) + continue + } + + if !os.IsNotExist(err) { + return nil, err + } + } + + if len(out) == 0 { + return nil, fmt.Errorf("unable to find any valid known_hosts file, set SSH_KNOWN_HOSTS env variable") + } + + return out, nil +} + +// HostKeyCallbackHelper is a helper that provides common functionality to +// configure HostKeyCallback into a ssh.ClientConfig. +type HostKeyCallbackHelper struct { + // HostKeyCallback is the function type used for verifying server keys. + // If nil default callback will be create using NewKnownHostsCallback + // without argument. + HostKeyCallback ssh.HostKeyCallback +} + +// SetHostKeyCallback sets the field HostKeyCallback in the given cfg. If +// HostKeyCallback is empty a default callback is created using +// NewKnownHostsCallback. +func (m *HostKeyCallbackHelper) SetHostKeyCallback(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) { + var err error + if m.HostKeyCallback == nil { + if m.HostKeyCallback, err = NewKnownHostsCallback(); err != nil { + return cfg, err + } + } + + cfg.HostKeyCallback = m.HostKeyCallback + return cfg, nil +} diff --git a/vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/common.go b/vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/common.go new file mode 100644 index 00000000..f29cc1c0 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/plumbing/transport/ssh/common.go @@ -0,0 +1,228 @@ +// Package ssh implements the SSH transport protocol. +package ssh + +import ( + "context" + "fmt" + "reflect" + "strconv" + + "github.com/devtron-labs/go-git/plumbing/transport" + "github.com/devtron-labs/go-git/plumbing/transport/internal/common" + + "github.com/kevinburke/ssh_config" + "golang.org/x/crypto/ssh" + "golang.org/x/net/proxy" +) + +// DefaultClient is the default SSH client. +var DefaultClient = NewClient(nil) + +// DefaultSSHConfig is the reader used to access parameters stored in the +// system's ssh_config files. If nil all the ssh_config are ignored. +var DefaultSSHConfig sshConfig = ssh_config.DefaultUserSettings + +type sshConfig interface { + Get(alias, key string) string +} + +// NewClient creates a new SSH client with an optional *ssh.ClientConfig. +func NewClient(config *ssh.ClientConfig) transport.Transport { + return common.NewClient(&runner{config: config}) +} + +// DefaultAuthBuilder is the function used to create a default AuthMethod, when +// the user doesn't provide any. +var DefaultAuthBuilder = func(user string) (AuthMethod, error) { + return NewSSHAgentAuth(user) +} + +const DefaultPort = 22 + +type runner struct { + config *ssh.ClientConfig +} + +func (r *runner) Command(cmd string, ep *transport.Endpoint, auth transport.AuthMethod) (common.Command, error) { + c := &command{command: cmd, endpoint: ep, config: r.config} + if auth != nil { + c.setAuth(auth) + } + + if err := c.connect(); err != nil { + return nil, err + } + return c, nil +} + +type command struct { + *ssh.Session + connected bool + command string + endpoint *transport.Endpoint + client *ssh.Client + auth AuthMethod + config *ssh.ClientConfig +} + +func (c *command) setAuth(auth transport.AuthMethod) error { + a, ok := auth.(AuthMethod) + if !ok { + return transport.ErrInvalidAuthMethod + } + + c.auth = a + return nil +} + +func (c *command) Start() error { + return c.Session.Start(endpointToCommand(c.command, c.endpoint)) +} + +// Close closes the SSH session and connection. +func (c *command) Close() error { + if !c.connected { + return nil + } + + c.connected = false + + //XXX: If did read the full packfile, then the session might be already + // closed. + _ = c.Session.Close() + + return c.client.Close() +} + +// connect connects to the SSH server, unless a AuthMethod was set with +// SetAuth method, by default uses an auth method based on PublicKeysCallback, +// it connects to a SSH agent, using the address stored in the SSH_AUTH_SOCK +// environment var. +func (c *command) connect() error { + if c.connected { + return transport.ErrAlreadyConnected + } + + if c.auth == nil { + if err := c.setAuthFromEndpoint(); err != nil { + return err + } + } + + var err error + config, err := c.auth.ClientConfig() + if err != nil { + return err + } + + overrideConfig(c.config, config) + + c.client, err = dial("tcp", c.getHostWithPort(), config) + if err != nil { + return err + } + + c.Session, err = c.client.NewSession() + if err != nil { + _ = c.client.Close() + return err + } + + c.connected = true + return nil +} + +func dial(network, addr string, config *ssh.ClientConfig) (*ssh.Client, error) { + var ( + ctx = context.Background() + cancel context.CancelFunc + ) + if config.Timeout > 0 { + ctx, cancel = context.WithTimeout(ctx, config.Timeout) + } else { + ctx, cancel = context.WithCancel(ctx) + } + defer cancel() + + conn, err := proxy.Dial(ctx, network, addr) + if err != nil { + return nil, err + } + c, chans, reqs, err := ssh.NewClientConn(conn, addr, config) + if err != nil { + return nil, err + } + return ssh.NewClient(c, chans, reqs), nil +} + +func (c *command) getHostWithPort() string { + if addr, found := c.doGetHostWithPortFromSSHConfig(); found { + return addr + } + + host := c.endpoint.Host + port := c.endpoint.Port + if port <= 0 { + port = DefaultPort + } + + return fmt.Sprintf("%s:%d", host, port) +} + +func (c *command) doGetHostWithPortFromSSHConfig() (addr string, found bool) { + if DefaultSSHConfig == nil { + return + } + + host := c.endpoint.Host + port := c.endpoint.Port + + configHost := DefaultSSHConfig.Get(c.endpoint.Host, "Hostname") + if configHost != "" { + host = configHost + found = true + } + + if !found { + return + } + + configPort := DefaultSSHConfig.Get(c.endpoint.Host, "Port") + if configPort != "" { + if i, err := strconv.Atoi(configPort); err == nil { + port = i + } + } + + addr = fmt.Sprintf("%s:%d", host, port) + return +} + +func (c *command) setAuthFromEndpoint() error { + var err error + c.auth, err = DefaultAuthBuilder(c.endpoint.User) + return err +} + +func endpointToCommand(cmd string, ep *transport.Endpoint) string { + return fmt.Sprintf("%s '%s'", cmd, ep.Path) +} + +func overrideConfig(overrides *ssh.ClientConfig, c *ssh.ClientConfig) { + if overrides == nil { + return + } + + t := reflect.TypeOf(*c) + vc := reflect.ValueOf(c).Elem() + vo := reflect.ValueOf(overrides).Elem() + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + vcf := vc.FieldByName(f.Name) + vof := vo.FieldByName(f.Name) + vcf.Set(vof) + } + + *c = vc.Interface().(ssh.ClientConfig) +} diff --git a/vendor/github.com/devtron-labs/go-git/prune_test.go b/vendor/github.com/devtron-labs/go-git/prune_test.go deleted file mode 100644 index ea655c32..00000000 --- a/vendor/github.com/devtron-labs/go-git/prune_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package git - -import ( - "time" - - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/cache" - "github.com/devtron-labs/go-git/plumbing/storer" - "github.com/devtron-labs/go-git/storage" - "github.com/devtron-labs/go-git/storage/filesystem" - - "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" -) - -type PruneSuite struct { - BaseSuite -} - -var _ = Suite(&PruneSuite{}) - -func (s *PruneSuite) testPrune(c *C, deleteTime time.Time) { - srcFs := fixtures.ByTag("unpacked").One().DotGit() - var sto storage.Storer - var err error - sto = filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) - - los := sto.(storer.LooseObjectStorer) - c.Assert(los, NotNil) - - count := 0 - err = los.ForEachObjectHash(func(_ plumbing.Hash) error { - count++ - return nil - }) - c.Assert(err, IsNil) - - r, err := Open(sto, srcFs) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - // Remove a branch so we can prune some objects. - err = sto.RemoveReference(plumbing.ReferenceName("refs/heads/v4")) - c.Assert(err, IsNil) - err = sto.RemoveReference(plumbing.ReferenceName("refs/remotes/origin/v4")) - c.Assert(err, IsNil) - - err = r.Prune(PruneOptions{ - OnlyObjectsOlderThan: deleteTime, - Handler: r.DeleteObject, - }) - c.Assert(err, IsNil) - - newCount := 0 - err = los.ForEachObjectHash(func(_ plumbing.Hash) error { - newCount++ - return nil - }) - c.Assert(err, IsNil) - - if deleteTime.IsZero() { - c.Assert(newCount < count, Equals, true) - } else { - // Assume a delete time older than any of the objects was passed in. - c.Assert(newCount, Equals, count) - } -} - -func (s *PruneSuite) TestPrune(c *C) { - s.testPrune(c, time.Time{}) -} - -func (s *PruneSuite) TestPruneWithNoDelete(c *C) { - s.testPrune(c, time.Unix(0, 1)) -} diff --git a/vendor/github.com/devtron-labs/go-git/references_test.go b/vendor/github.com/devtron-labs/go-git/references_test.go deleted file mode 100644 index 4d9d3dc7..00000000 --- a/vendor/github.com/devtron-labs/go-git/references_test.go +++ /dev/null @@ -1,401 +0,0 @@ -package git - -import ( - "bytes" - "fmt" - - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/object" - "github.com/devtron-labs/go-git/storage/memory" - - "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" -) - -type ReferencesSuite struct { - BaseSuite -} - -var _ = Suite(&ReferencesSuite{}) - -var referencesTests = [...]struct { - // input data to revlist - repo string - commit string - path string - // expected output data form the revlist - revs []string -}{ - // Tyba git-fixture - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", []string{ - "35e85108805c84807bc66a02d91535e1e24b38b9", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", []string{ - "b8e471f58bcbca63b07bda20e428190409c2db47", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "go/example.go", []string{ - "918c48b83bd081e863dbe1b80f8998f058cd8294", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/long.json", []string{ - "af2d6a6954d532f8ffb47615169c8fdf9d383a1a", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "json/short.json", []string{ - "af2d6a6954d532f8ffb47615169c8fdf9d383a1a", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", []string{ - "b029517f6300c2da0f4b651b8642506cd6aaf45d", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "php/crappy.php", []string{ - "918c48b83bd081e863dbe1b80f8998f058cd8294", - }}, - {"https://github.com/git-fixtures/basic.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "vendor/foo.go", []string{ - "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }}, - {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "LICENSE", []string{ - "ffcda27c2de6768ee83f3f4a027fa4ab57d50f09", - }}, - {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "README.md", []string{ - "ffcda27c2de6768ee83f3f4a027fa4ab57d50f09", - "2e87a2dcc63a115f9a61bd969d1e85fb132a431b", - "215b0ac06225b0671bc3460d10da88c3406f796f", - "0260eb7a2623dd2309ab439f74e8681fccdc4285", - "d46b48933e94f30992486374fa9a6becfd28ea17", - "9cb4df2a88efee8836f9b8ad27ca2717f624164e", - "8c49acdec2ed441706d8799f8b17878aae4c1ffe", - "ebaca0c6f54c23193ee8175c3530e370cb2dabe3", - "77675f82039551a19de4fbccbe69366fe63680df", - "b9741594fb8ab7374f9be07d6a09a3bf96719816", - "04db6acd94de714ca48128c606b17ee1149a630e", - "ff737bd8a962a714a446d7592fae423a56e61e12", - "eadd03f7a1cc54810bd10eef6747ad9562ad246d", - "b5072ab5c1cf89191d71f1244eecc5d1f369ef7e", - "bfa6ebc9948f1939402b063c0a2a24bf2b1c1cc3", - "d9aef39828c670dfdb172502021a2ebcda8cf2fb", - "1a6b6e45c91e1831494eb139ee3f8e21649c7fb0", - "09fdbe4612066cf63ea46aee43c7cfaaff02ecfb", - "236f6526b1150cc1f1723566b4738f443fc70777", - "7862953f470b62397d22f6782a884f5bea6d760d", - "b0b0152d08c2333680266977a5bc9c4e50e1e968", - "13ce6c1c77c831f381974aa1c62008a414bd2b37", - "d3f3c8faca048d11709969fbfc0cdf2901b87578", - "8777dde1abe18c805d021366643218d3f3356dd9", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/reconfigure_spinnaker.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/validate_configuration.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", - "1e3d328a2cabda5d0aaddc5dec65271343e0dc37", - "b5d999e2986e190d81767cd3cfeda0260f9f6fb8", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/fetch.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pylib/spinnaker/yaml_util.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", - "b5d999e2986e190d81767cd3cfeda0260f9f6fb8", - "023d4fb17b76e0fe0764971df8b8538b735a1d67", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "dev/build_release.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", - "f42771ba298b93a7c4f5b16c5b30ab96c15305a8", - "dd52703a50e71891f63fcf05df1f69836f4e7056", - "0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", - "d375f1994ff4d0bdc32d614e698f1b50e1093f14", - "abad497f11a366548aa95303c8c2f165fe7ae918", - "6986d885626792dee4ef6b7474dfc9230c5bda54", - "5422a86a10a8c5a1ef6728f5fc8894d9a4c54cb9", - "09a4ea729b25714b6368959eea5113c99938f7b6", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "pkg_scripts/postUninstall.sh", []string{ - "ce9f123d790717599aaeb76bc62510de437761be", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/first_google_boot.sh", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - "de25f576b888569192e6442b0202d30ca7b2d8ec", - "a596972a661d9a7deca8abd18b52ce1a39516e89", - "9467ec579708b3c71dd9e5b3906772841c144a30", - "c4a9091e4076cb740fa46e790dd5b658e19012ad", - "6eb5d9c5225224bfe59c401182a2939d6c27fc00", - "495c7118e7cf757aa04eab410b64bfb5b5149ad2", - "dd2d03c19658ff96d371aef00e75e2e54702da0e", - "2a3b1d3b134e937c7bafdab6cc2950e264bf5dee", - "a57b08a9072f6a865f760551be2a4944f72f804a", - "0777fadf4ca6f458d7071de414f9bd5417911037", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.sh", []string{ - "0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_fake_openjdk8.sh", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/install_spinnaker.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - "37f94770d81232b1895fca447878f68d65aac652", - "46c9dcbb55ca3f4735e82ad006e8cae2fdd050d9", - "124a88cfda413cb7182ca9c739a284a9e50042a1", - "eb4faf67a8b775d7985d07a708e3ffeac4273580", - "0d9c9cef53af38cefcb6801bb492aaed3f2c9a42", - "01171a8a2e843bef3a574ba73b258ac29e5d5405", - "739d8c6fe16edcb6ef9185dc74197de561b84315", - "d33c2d1e350b03fb989eefc612e8c9d5fa7cadc2", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "install/__init__.py", []string{ - "a24001f6938d425d0e7504bdf5d27fc866a85c3d", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "experimental/docker-compose/docker-compose.yml", []string{ - "fda357835d889595dc39dfebc6181d863cce7d4f", - "57c59e7144354a76e1beba69ae2f85db6b1727af", - "7682dff881029c722d893a112a64fea6849a0428", - "66f1c938c380a4096674b27540086656076a597f", - "56dc238f6f397e93f1d1aad702976889c830e8bf", - "b95e442c064935709e789fa02126f17ddceef10b", - "f98965a8f42037bd038b86c3401da7e6dfbf4f2e", - "5344429749e8b68b168d2707b7903692436cc2ea", - "6a31f5d219766b0cec4ea4fbbbfe47bdcdb0ab8e", - "ddaae195b628150233b0a48f50a1674fd9d1a924", - "7119ad9cf7d4e4d8b059e5337374baae4adc7458", - }}, - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/validate_configuration_test.py", []string{ - "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", - "1e3d328a2cabda5d0aaddc5dec65271343e0dc37", - }}, - {"https://github.com/spinnaker/spinnaker.git", "f39d86f59a0781f130e8de6b2115329c1fbe9545", "README.adoc", []string{ - "638f61b3331695f46f1a88095e26dea0f09f176b", - "bd42370d3fe8d410e78acb96f81cb3d838ad1c21", - "d6905eab6fec1841c7cf8e4484499f5c8d7d423e", - "c0a70a0f5aa494f0ae01c55ba191f2325556489a", - "811795c8a185e88f5d269195cb68b29c8d0fe170", - "d6e6fe0194447cc280f942d6a2e0521b68ea7796", - "174bdbf9edfb0ca88415dd4a673852d5b22e7036", - "9944d6cf72b8f82d622d85dad7434472bc8f397d", - "e805183c72f0426fb073728c01901c2fd2db1da6", - "8ef83dd443a05e9122681950399edaa58a38d466", - "d73f9cee49a5ad27a42a6e18af7c49a8f28ad8a8", - }}, - // FAILS - /* - // this contains an empty move - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "google/dev/build_google_tarball.py", []string{ - "88e60ac93f832efc2616b3c165e99a8f2ffc3e0c", - "9e49443da49b8c862cc140b660744f84eebcfa51", - }}, - */ - /* - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/yaml_util_test.py", []string{ - "edf909edb9319c5e615e4ce73da47bbdca388ebe", - "023d4fb17b76e0fe0764971df8b8538b735a1d67", - }}, - */ - /* - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "unittest/configurator_test.py", []string{ - "1e14f94bcf82694fdc7e2dcbbfdbbed58db0f4d9", - "edf909edb9319c5e615e4ce73da47bbdca388ebe", - "d14f793a6cd7169ef708a4fc276ad876bd3edd4e", - "023d4fb17b76e0fe0764971df8b8538b735a1d67", - }}, - */ - /* - // this contains a cherry-pick at 094d0e7d5d691 (with 3f34438d) - {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "desk", []string{ - "ffcda27c2de6768ee83f3f4a027fa4ab57d50f09", - "a0c1e853158ccbaf95574220bbf3b54509034a9f", - "decfc524570c407d6bba0f217e534c8b47dbdbee", - "1413872d5b3af7cd674bbe0e1f23387cd5d940e6", - "40cd5a91d916e7b2f331e4e85fdc52636fd7cff7", - "8e07d73aa0e3780f8c7cf8ad1a6b263df26a0a52", - "19c56f95720ac3630efe9f29b1a252581d6cbc0c", - "9ea46ccc6d253cffb4b7b66e936987d87de136e4", - "094d0e7d5d69141c98a606910ba64786c5565da0", - "801e62706a9e4fef75fcaca9c78744de0bc36e6a", - "eddf335f31c73624ed3f40dc5fcad50136074b2b", - "c659093f06eb2bd68c6252caeab605e5cd8aa49e", - "d94b3fe8ce0e3a474874d742992d432cd040582f", - "93cddf036df2d8509f910063696acd556ca7600f", - "b3d4cb0c826b16b301f088581d681654d8de6c07", - "52d90f9b513dd3c5330663cba39396e6b8a3ba4e", - "15919e99ded03c6ceea9ff98558e77a322a4dadb", - "803bf37847633e2f685a46a27b11facf22efebec", - "c07ad524ee1e616c70bf2ea7a0ee4f4a01195d78", - "b91aff30f318fda461d009c308490613b394f3e2", - "67cec1e8a3f21c6eb11678e3f31ffd228b55b783", - "bbe404c78af7525fabc57b9e7aa7c100b0d39f7a", - "5dd078848786c2babc2511e9502fa98518cf3535", - "7970ae7cc165c5205945dfb704d67d53031f550a", - "33091ac904747747ff30f107d4d0f22fa872eccf", - "069f81cab12d185ba1b509be946c47897cd4fb1f", - "13ce6c1c77c831f381974aa1c62008a414bd2b37", - }}, - */ - /* - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "InstallSpinnaker.sh", []string{ - "ce9f123d790717599aaeb76bc62510de437761be", - "23673af3ad70b50bba7fdafadc2323302f5ba520", - "b7015a5d36990d69a054482556127b9c7404a24a", - "582da9622e3a72a19cd261a017276d72b5b0051a", - "0c5bb1e4392e751f884f3c57de5d4aee72c40031", - "c9c2a0ec03968ab17e8b16fdec9661eb1dbea173", - "a3cdf880826b4d9af42b93f4a2df29a91ab31d35", - "18526c447f5174d33c96aac6d6433318b0e2021c", - "2a6288be1c8ea160c443ca3cd0fe826ff2387d37", - "9e74d009894d73dd07773ea6b3bdd8323db980f7", - "d2f6214b625db706384b378a29cc4c22237db97a", - "202a9c720b3ba8106e022a0ad027ebe279040c78", - "791bcd1592828d9d5d16e83f3a825fb08b0ba22d", - "01e65d67eed8afcb67a6bdf1c962541f62b299c9", - "6328ee836affafc1b52127147b5ca07300ac78e6", - "3de4f77c105f700f50d9549d32b9a05a01b46c4b", - "8980daf661408a3faa1f22c225702a5c1d11d5c9", - "8eb116de9128c314ac8a6f5310ca500b8c74f5db", - "88e841aad37b71b78a8fb88bc75fe69499d527c7", - "370d61cdbc1f3c90db6759f1599ccbabd40ad6c1", - "505577dc87d300cf562dc4702a05a5615d90d855", - "b5c6053a46993b20d1b91e7b7206bffa54669ad7", - "ba486de7c025457963701114c683dcd4708e1dee", - "b41d7c0e5b20bbe7c8eb6606731a3ff68f4e3941", - "a47d0aaeda421f06df248ad65bd58230766bf118", - "495c7118e7cf757aa04eab410b64bfb5b5149ad2", - "46670eb6477c353d837dbaba3cf36c5f8b86f037", - "dd2d03c19658ff96d371aef00e75e2e54702da0e", - "4bbcad219ec55a465fb48ce236cb10ca52d43b1f", - "50d0556563599366f29cb286525780004fa5a317", - "9a06d3f20eabb254d0a1e2ff7735ef007ccd595e", - "d4b48a39aba7d3bd3e8abef2274a95b112d1ae73", - }}, - */ - /* - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/default-spinnaker-local.yml", []string{ - "ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", - "99534ecc895fe17a1d562bb3049d4168a04d0865", - "caf6d62e8285d4681514dd8027356fb019bc97ff", - "eaf7614cad81e8ab5c813dd4821129d0c04ea449", - "5a2a845bc08974a36d599a4a4b7e25be833823b0", - "41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", - "974b775a8978b120ff710cac93a21c7387b914c9", - "87e459a9a044b3109dfeb943cc82c627b61d84a6", - "5e09821cbd7d710405b61cab0a795c2982a71b9c", - "8cc2d4bdb0a15aafc7fe02cdcb03ab90c974cafa", - "3ce7b902a51bac2f10994f7d1f251b616c975e54", - "a596972a661d9a7deca8abd18b52ce1a39516e89", - "8980daf661408a3faa1f22c225702a5c1d11d5c9", - }}, - */ - /* - {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "config/spinnaker.yml", []string{ - "ae904e8d60228c21c47368f6a10f1cc9ca3aeebf", - "caf6d62e8285d4681514dd8027356fb019bc97ff", - "eaf7614cad81e8ab5c813dd4821129d0c04ea449", - "5a2a845bc08974a36d599a4a4b7e25be833823b0", - "41e96c54a478e5d09dd07ed7feb2d8d08d8c7e3c", - "974b775a8978b120ff710cac93a21c7387b914c9", - "ed887f6547d7cd2b2d741184a06f97a0a704152b", - "d4553dac205023fa77652308af1a2d1cf52138fb", - "a596972a661d9a7deca8abd18b52ce1a39516e89", - "66ac94f0b4442707fb6f695fbed91d62b3bd9d4a", - "079e42e7c979541b6fab7343838f7b9fd4a360cd", - }}, - */ -} - -func (s *ReferencesSuite) TestObjectNotFoundError(c *C) { - h1 := plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a") - hParent := plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea") - - url := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One().DotGit().Root() - storer := memory.NewStorage() - r, err := Clone(storer, nil, &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - delete(storer.Objects, hParent) - - commit, err := r.CommitObject(h1) - c.Assert(err, IsNil) - - _, err = references(commit, "LICENSE") - c.Assert(err, Equals, plumbing.ErrObjectNotFound) -} - -func (s *ReferencesSuite) TestRevList(c *C) { - for _, t := range referencesTests { - r := s.NewRepositoryFromPackfile(fixtures.ByURL(t.repo).One()) - - commit, err := r.CommitObject(plumbing.NewHash(t.commit)) - c.Assert(err, IsNil) - - revs, err := references(commit, t.path) - c.Assert(err, IsNil) - c.Assert(len(revs), Equals, len(t.revs)) - - for i := range revs { - if revs[i].Hash.String() != t.revs[i] { - commit, err := s.Repository.CommitObject(plumbing.NewHash(t.revs[i])) - c.Assert(err, IsNil) - equiv, err := equivalent(t.path, revs[i], commit) - c.Assert(err, IsNil) - if equiv { - fmt.Printf("cherry-pick detected: %s %s\n", revs[i].Hash.String(), t.revs[i]) - } else { - c.Fatalf("\nrepo=%s, commit=%s, path=%s, \n%s", - t.repo, t.commit, t.path, compareSideBySide(t.revs, revs)) - } - } - } - } -} - -// same length is assumed -func compareSideBySide(a []string, b []*object.Commit) string { - var buf bytes.Buffer - buf.WriteString("\t EXPECTED OBTAINED ") - var sep string - var obt string - for i := range a { - obt = b[i].Hash.String() - if a[i] != obt { - sep = "------" - } else { - sep = " " - } - buf.WriteString(fmt.Sprintf("\n%d", i+1)) - buf.WriteString(sep) - buf.WriteString(a[i]) - buf.WriteString(sep) - buf.WriteString(obt) - } - return buf.String() -} - -var cherryPicks = [...][]string{ - // repo, path, commit a, commit b - {"https://github.com/jamesob/desk.git", "desk", "094d0e7d5d69141c98a606910ba64786c5565da0", "3f34438d54f4a1ca86db8c0f03ed8eb38f20e22c"}, -} - -// should detect cherry picks -func (s *ReferencesSuite) TestEquivalent(c *C) { - for _, t := range cherryPicks { - cs := s.commits(c, t[0], t[2], t[3]) - equiv, err := equivalent(t[1], cs[0], cs[1]) - c.Assert(err, IsNil) - c.Assert(equiv, Equals, true, Commentf("repo=%s, file=%s, a=%s b=%s", t[0], t[1], t[2], t[3])) - } -} - -// returns the commits from a slice of hashes -func (s *ReferencesSuite) commits(c *C, repo string, hs ...string) []*object.Commit { - r := s.NewRepositoryFromPackfile(fixtures.ByURL(repo).One()) - - result := make([]*object.Commit, 0, len(hs)) - for _, h := range hs { - commit, err := r.CommitObject(plumbing.NewHash(h)) - c.Assert(err, IsNil) - - result = append(result, commit) - } - - return result -} diff --git a/vendor/github.com/devtron-labs/go-git/remote_test.go b/vendor/github.com/devtron-labs/go-git/remote_test.go deleted file mode 100644 index df632701..00000000 --- a/vendor/github.com/devtron-labs/go-git/remote_test.go +++ /dev/null @@ -1,889 +0,0 @@ -package git - -import ( - "bytes" - "context" - "io" - "io/ioutil" - "os" - "runtime" - "time" - - "github.com/devtron-labs/go-git/config" - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/cache" - "github.com/devtron-labs/go-git/plumbing/protocol/packp" - "github.com/devtron-labs/go-git/plumbing/protocol/packp/capability" - "github.com/devtron-labs/go-git/plumbing/storer" - "github.com/devtron-labs/go-git/storage" - "github.com/devtron-labs/go-git/storage/filesystem" - "github.com/devtron-labs/go-git/storage/memory" - - fixtures "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-billy.v4/osfs" -) - -type RemoteSuite struct { - BaseSuite -} - -var _ = Suite(&RemoteSuite{}) - -func (s *RemoteSuite) TestFetchInvalidEndpoint(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}}) - err := r.Fetch(&FetchOptions{RemoteName: "foo"}) - c.Assert(err, ErrorMatches, ".*invalid character.*") -} - -func (s *RemoteSuite) TestFetchNonExistentEndpoint(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}}) - err := r.Fetch(&FetchOptions{}) - c.Assert(err, NotNil) -} - -func (s *RemoteSuite) TestFetchInvalidSchemaEndpoint(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) - err := r.Fetch(&FetchOptions{}) - c.Assert(err, ErrorMatches, ".*unsupported scheme.*") -} - -func (s *RemoteSuite) TestFetchInvalidFetchOptions(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) - invalid := config.RefSpec("^*$ñ") - err := r.Fetch(&FetchOptions{RefSpecs: []config.RefSpec{invalid}}) - c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) -} - -func (s *RemoteSuite) TestFetchWildcard(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - s.testFetch(c, r, &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), - plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - }) -} - -func (s *RemoteSuite) TestFetchWildcardTags(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, - }) - - s.testFetch(c, r, &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), - plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"), - plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"), - plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"), - plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"), - plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), - }) -} - -func (s *RemoteSuite) TestFetch(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, - }) - - s.testFetch(c, r, &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), - }) -} - -func (s *RemoteSuite) TestFetchNonExistantReference(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, - }) - - err := r.Fetch(&FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/foo:refs/remotes/origin/foo"), - }, - }) - - c.Assert(err, ErrorMatches, "couldn't find remote ref.*") -} - -func (s *RemoteSuite) TestFetchContext(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, - }) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - err := r.FetchContext(ctx, &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), - }, - }) - c.Assert(err, NotNil) -} - -func (s *RemoteSuite) TestFetchWithAllTags(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, - }) - - s.testFetch(c, r, &FetchOptions{ - Tags: AllTags, - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), - plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"), - plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"), - plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"), - plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"), - plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), - }) -} - -func (s *RemoteSuite) TestFetchWithNoTags(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, - }) - - s.testFetch(c, r, &FetchOptions{ - Tags: NoTags, - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), - }) - -} - -func (s *RemoteSuite) TestFetchWithDepth(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - s.testFetch(c, r, &FetchOptions{ - Depth: 1, - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), - plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - }) - - c.Assert(r.s.(*memory.Storage).Objects, HasLen, 18) -} - -func (s *RemoteSuite) testFetch(c *C, r *Remote, o *FetchOptions, expected []*plumbing.Reference) { - err := r.Fetch(o) - c.Assert(err, IsNil) - - var refs int - l, err := r.s.IterReferences() - c.Assert(err, IsNil) - l.ForEach(func(r *plumbing.Reference) error { refs++; return nil }) - - c.Assert(refs, Equals, len(expected)) - - for _, exp := range expected { - r, err := r.s.Reference(exp.Name()) - c.Assert(err, IsNil) - c.Assert(exp.String(), Equals, r.String()) - } -} - -func (s *RemoteSuite) TestFetchWithProgress(c *C) { - url := s.GetBasicLocalRepositoryURL() - sto := memory.NewStorage() - buf := bytes.NewBuffer(nil) - - r := NewRemote(sto, &config.RemoteConfig{Name: "foo", URLs: []string{url}}) - - refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") - err := r.Fetch(&FetchOptions{ - RefSpecs: []config.RefSpec{refspec}, - Progress: buf, - }) - - c.Assert(err, IsNil) - c.Assert(sto.Objects, HasLen, 31) - - c.Assert(buf.Len(), Not(Equals), 0) -} - -type mockPackfileWriter struct { - storage.Storer - PackfileWriterCalled bool -} - -func (m *mockPackfileWriter) PackfileWriter() (io.WriteCloser, error) { - m.PackfileWriterCalled = true - return m.Storer.(storer.PackfileWriter).PackfileWriter() -} - -func (s *RemoteSuite) TestFetchWithPackfileWriter(c *C) { - dir, err := ioutil.TempDir("", "fetch") - c.Assert(err, IsNil) - - defer os.RemoveAll(dir) // clean up - - fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) - c.Assert(err, IsNil) - - mock := &mockPackfileWriter{Storer: fss} - - url := s.GetBasicLocalRepositoryURL() - r := NewRemote(mock, &config.RemoteConfig{Name: "foo", URLs: []string{url}}) - - refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") - err = r.Fetch(&FetchOptions{ - RefSpecs: []config.RefSpec{refspec}, - }) - - c.Assert(err, IsNil) - - var count int - iter, err := mock.IterEncodedObjects(plumbing.AnyObject) - c.Assert(err, IsNil) - - iter.ForEach(func(plumbing.EncodedObject) error { - count++ - return nil - }) - - c.Assert(count, Equals, 31) - c.Assert(mock.PackfileWriterCalled, Equals, true) -} - -func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) { - url := s.GetBasicLocalRepositoryURL() - s.doTestFetchNoErrAlreadyUpToDate(c, url) -} - -func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateButStillUpdateLocalRemoteRefs(c *C) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - o := &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), - }, - } - - err := r.Fetch(o) - c.Assert(err, IsNil) - - // Simulate an out of date remote ref even though we have the new commit locally - r.s.SetReference(plumbing.NewReferenceFromStrings( - "refs/remotes/origin/master", "918c48b83bd081e863dbe1b80f8998f058cd8294", - )) - - err = r.Fetch(o) - c.Assert(err, IsNil) - - exp := plumbing.NewReferenceFromStrings( - "refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - ) - - ref, err := r.s.Reference("refs/remotes/origin/master") - c.Assert(err, IsNil) - c.Assert(exp.String(), Equals, ref.String()) -} - -func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateWithNonCommitObjects(c *C) { - fixture := fixtures.ByTag("tags").One() - url := s.GetLocalRepositoryURL(fixture) - s.doTestFetchNoErrAlreadyUpToDate(c, url) -} - -func (s *RemoteSuite) doTestFetchNoErrAlreadyUpToDate(c *C, url string) { - r := NewRemote(memory.NewStorage(), &config.RemoteConfig{URLs: []string{url}}) - - o := &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), - }, - } - - err := r.Fetch(o) - c.Assert(err, IsNil) - err = r.Fetch(o) - c.Assert(err, Equals, NoErrAlreadyUpToDate) -} - -func (s *RemoteSuite) testFetchFastForward(c *C, sto storage.Storer) { - r := NewRemote(sto, &config.RemoteConfig{ - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - s.testFetch(c, r, &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/master:refs/heads/master"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - }) - - // First make sure that we error correctly when a force is required. - err := r.Fetch(&FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("refs/heads/branch:refs/heads/master"), - }, - }) - c.Assert(err, Equals, ErrForceNeeded) - - // And that forcing it fixes the problem. - err = r.Fetch(&FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/branch:refs/heads/master"), - }, - }) - c.Assert(err, IsNil) - - // Now test that a fast-forward, non-force fetch works. - r.s.SetReference(plumbing.NewReferenceFromStrings( - "refs/heads/master", "918c48b83bd081e863dbe1b80f8998f058cd8294", - )) - s.testFetch(c, r, &FetchOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("refs/heads/master:refs/heads/master"), - }, - }, []*plumbing.Reference{ - plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - }) -} - -func (s *RemoteSuite) TestFetchFastForwardMem(c *C) { - s.testFetchFastForward(c, memory.NewStorage()) -} - -func (s *RemoteSuite) TestFetchFastForwardFS(c *C) { - dir, err := ioutil.TempDir("", "fetch") - c.Assert(err, IsNil) - - defer os.RemoveAll(dir) // clean up - - fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) - - // This exercises `storage.filesystem.Storage.CheckAndSetReference()`. - s.testFetchFastForward(c, fss) -} - -func (s *RemoteSuite) TestString(c *C) { - r := NewRemote(nil, &config.RemoteConfig{ - Name: "foo", - URLs: []string{"https://github.com/git-fixtures/basic.git"}, - }) - - c.Assert(r.String(), Equals, ""+ - "foo\thttps://github.com/git-fixtures/basic.git (fetch)\n"+ - "foo\thttps://github.com/git-fixtures/basic.git (push)", - ) -} - -func (s *RemoteSuite) TestPushToEmptyRepository(c *C) { - url := c.MkDir() - server, err := PlainInit(url, true) - c.Assert(err, IsNil) - - srcFs := fixtures.Basic().One().DotGit() - sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) - - r := NewRemote(sto, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{url}, - }) - - rs := config.RefSpec("refs/heads/*:refs/heads/*") - err = r.Push(&PushOptions{ - RefSpecs: []config.RefSpec{rs}, - }) - c.Assert(err, IsNil) - - iter, err := r.s.IterReferences() - c.Assert(err, IsNil) - - expected := make(map[string]string) - iter.ForEach(func(ref *plumbing.Reference) error { - if !ref.Name().IsBranch() { - return nil - } - - expected[ref.Name().String()] = ref.Hash().String() - return nil - }) - c.Assert(err, IsNil) - - AssertReferences(c, server, expected) - -} - -func (s *RemoteSuite) TestPushContext(c *C) { - url := c.MkDir() - _, err := PlainInit(url, true) - c.Assert(err, IsNil) - - fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() - sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - r := NewRemote(sto, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{url}, - }) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - numGoroutines := runtime.NumGoroutine() - - err = r.PushContext(ctx, &PushOptions{ - RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}, - }) - c.Assert(err, NotNil) - - // let the goroutine from pushHashes finish and check that the number of - // goroutines is the same as before - time.Sleep(100 * time.Millisecond) - c.Assert(runtime.NumGoroutine(), Equals, numGoroutines) -} - -func (s *RemoteSuite) TestPushTags(c *C) { - url := c.MkDir() - server, err := PlainInit(url, true) - c.Assert(err, IsNil) - - fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() - sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - r := NewRemote(sto, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{url}, - }) - - err = r.Push(&PushOptions{ - RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}, - }) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/tags/lightweight-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", - "refs/tags/annotated-tag": "b742a2a9fa0afcfa9a6fad080980fbc26b007c69", - "refs/tags/commit-tag": "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc", - "refs/tags/blob-tag": "fe6cb94756faa81e5ed9240f9191b833db5f40ae", - "refs/tags/tree-tag": "152175bf7e5580299fa1f0ba41ef6474cc043b70", - }) -} - -func (s *RemoteSuite) TestPushNoErrAlreadyUpToDate(c *C) { - fs := fixtures.Basic().One().DotGit() - sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - r := NewRemote(sto, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{fs.Root()}, - }) - - err := r.Push(&PushOptions{ - RefSpecs: []config.RefSpec{"refs/heads/*:refs/heads/*"}, - }) - c.Assert(err, Equals, NoErrAlreadyUpToDate) -} - -func (s *RemoteSuite) TestPushDeleteReference(c *C) { - fs := fixtures.Basic().One().DotGit() - sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - r, err := PlainClone(c.MkDir(), true, &CloneOptions{ - URL: fs.Root(), - }) - c.Assert(err, IsNil) - - remote, err := r.Remote(DefaultRemoteName) - c.Assert(err, IsNil) - - err = remote.Push(&PushOptions{ - RefSpecs: []config.RefSpec{":refs/heads/branch"}, - }) - c.Assert(err, IsNil) - - _, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch")) - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) - - _, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) -} - -func (s *RemoteSuite) TestPushRejectNonFastForward(c *C) { - fs := fixtures.Basic().One().DotGit() - server := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - r, err := PlainClone(c.MkDir(), true, &CloneOptions{ - URL: fs.Root(), - }) - c.Assert(err, IsNil) - - remote, err := r.Remote(DefaultRemoteName) - c.Assert(err, IsNil) - - branch := plumbing.ReferenceName("refs/heads/branch") - oldRef, err := server.Reference(branch) - c.Assert(err, IsNil) - c.Assert(oldRef, NotNil) - - err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ - "refs/heads/master:refs/heads/branch", - }}) - c.Assert(err, ErrorMatches, "non-fast-forward update: refs/heads/branch") - - newRef, err := server.Reference(branch) - c.Assert(err, IsNil) - c.Assert(newRef, DeepEquals, oldRef) -} - -func (s *RemoteSuite) TestPushForce(c *C) { - f := fixtures.Basic().One() - sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) - - dstFs := f.DotGit() - dstSto := filesystem.NewStorage(dstFs, cache.NewObjectLRUDefault()) - - url := dstFs.Root() - r := NewRemote(sto, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{url}, - }) - - oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) - c.Assert(err, IsNil) - c.Assert(oldRef, NotNil) - - err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{ - config.RefSpec("+refs/heads/master:refs/heads/branch"), - }}) - c.Assert(err, IsNil) - - newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) - c.Assert(err, IsNil) - c.Assert(newRef, Not(DeepEquals), oldRef) -} - -func (s *RemoteSuite) TestPushPrune(c *C) { - fs := fixtures.Basic().One().DotGit() - url := c.MkDir() - server, err := PlainClone(url, true, &CloneOptions{ - URL: fs.Root(), - }) - c.Assert(err, IsNil) - - r, err := PlainClone(c.MkDir(), true, &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - tag, err := r.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true) - c.Assert(err, IsNil) - - err = r.DeleteTag("v1.0.0") - c.Assert(err, IsNil) - - remote, err := r.Remote(DefaultRemoteName) - c.Assert(err, IsNil) - - ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) - c.Assert(err, IsNil) - - err = remote.Push(&PushOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("refs/heads/*:refs/heads/*"), - }, - Prune: true, - }) - c.Assert(err, Equals, NoErrAlreadyUpToDate) - - AssertReferences(c, server, map[string]string{ - "refs/tags/v1.0.0": tag.Hash().String(), - }) - - err = remote.Push(&PushOptions{ - RefSpecs: []config.RefSpec{ - config.RefSpec("*:*"), - }, - Prune: true, - }) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/remotes/origin/master": ref.Hash().String(), - }) - - AssertReferences(c, server, map[string]string{ - "refs/remotes/origin/master": ref.Hash().String(), - }) - - ref, err = server.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true) - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) -} - -func (s *RemoteSuite) TestPushNewReference(c *C) { - fs := fixtures.Basic().One().DotGit() - url := c.MkDir() - server, err := PlainClone(url, true, &CloneOptions{ - URL: fs.Root(), - }) - c.Assert(err, IsNil) - - r, err := PlainClone(c.MkDir(), true, &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - remote, err := r.Remote(DefaultRemoteName) - c.Assert(err, IsNil) - - ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) - c.Assert(err, IsNil) - - err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ - "refs/heads/master:refs/heads/branch2", - }}) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/heads/branch2": ref.Hash().String(), - }) - - AssertReferences(c, r, map[string]string{ - "refs/remotes/origin/branch2": ref.Hash().String(), - }) -} - -func (s *RemoteSuite) TestPushNewReferenceAndDeleteInBatch(c *C) { - fs := fixtures.Basic().One().DotGit() - url := c.MkDir() - server, err := PlainClone(url, true, &CloneOptions{ - URL: fs.Root(), - }) - c.Assert(err, IsNil) - - r, err := PlainClone(c.MkDir(), true, &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - remote, err := r.Remote(DefaultRemoteName) - c.Assert(err, IsNil) - - ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) - c.Assert(err, IsNil) - - err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ - "refs/heads/master:refs/heads/branch2", - ":refs/heads/branch", - }}) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/heads/branch2": ref.Hash().String(), - }) - - AssertReferences(c, r, map[string]string{ - "refs/remotes/origin/branch2": ref.Hash().String(), - }) - - _, err = server.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) -} - -func (s *RemoteSuite) TestPushInvalidEndpoint(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}}) - err := r.Push(&PushOptions{RemoteName: "foo"}) - c.Assert(err, ErrorMatches, ".*invalid character.*") -} - -func (s *RemoteSuite) TestPushNonExistentEndpoint(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}}) - err := r.Push(&PushOptions{}) - c.Assert(err, NotNil) -} - -func (s *RemoteSuite) TestPushInvalidSchemaEndpoint(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "origin", URLs: []string{"qux://foo"}}) - err := r.Push(&PushOptions{}) - c.Assert(err, ErrorMatches, ".*unsupported scheme.*") -} - -func (s *RemoteSuite) TestPushInvalidFetchOptions(c *C) { - r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) - invalid := config.RefSpec("^*$ñ") - err := r.Push(&PushOptions{RefSpecs: []config.RefSpec{invalid}}) - c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) -} - -func (s *RemoteSuite) TestPushInvalidRefSpec(c *C) { - r := NewRemote(nil, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{"some-url"}, - }) - - rs := config.RefSpec("^*$**") - err := r.Push(&PushOptions{ - RefSpecs: []config.RefSpec{rs}, - }) - c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) -} - -func (s *RemoteSuite) TestPushWrongRemoteName(c *C) { - r := NewRemote(nil, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{"some-url"}, - }) - - err := r.Push(&PushOptions{ - RemoteName: "other-remote", - }) - c.Assert(err, ErrorMatches, ".*remote names don't match.*") -} - -func (s *RemoteSuite) TestGetHaves(c *C) { - f := fixtures.Basic().One() - sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) - - var localRefs = []*plumbing.Reference{ - plumbing.NewReferenceFromStrings( - "foo", - "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", - ), - plumbing.NewReferenceFromStrings( - "bar", - "fe6cb94756faa81e5ed9240f9191b833db5f40ae", - ), - plumbing.NewReferenceFromStrings( - "qux", - "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", - ), - } - - l, err := getHaves(localRefs, memory.NewStorage(), sto) - c.Assert(err, IsNil) - c.Assert(l, HasLen, 2) -} - -func (s *RemoteSuite) TestList(c *C) { - repo := fixtures.Basic().One() - remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{repo.URL}, - }) - - refs, err := remote.List(&ListOptions{}) - c.Assert(err, IsNil) - - expected := []*plumbing.Reference{ - plumbing.NewSymbolicReference("HEAD", "refs/heads/master"), - plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - plumbing.NewReferenceFromStrings("refs/heads/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), - plumbing.NewReferenceFromStrings("refs/pull/1/head", "b8e471f58bcbca63b07bda20e428190409c2db47"), - plumbing.NewReferenceFromStrings("refs/pull/2/head", "9632f02833b2f9613afb5e75682132b0b22e4a31"), - plumbing.NewReferenceFromStrings("refs/pull/2/merge", "c37f58a130ca555e42ff96a071cb9ccb3f437504"), - } - c.Assert(len(refs), Equals, len(expected)) - for _, e := range expected { - found := false - for _, r := range refs { - if r.Name() == e.Name() { - found = true - c.Assert(r, DeepEquals, e) - } - } - c.Assert(found, Equals, true) - } -} - -func (s *RemoteSuite) TestUpdateShallows(c *C) { - hashes := []plumbing.Hash{ - plumbing.NewHash("0000000000000000000000000000000000000001"), - plumbing.NewHash("0000000000000000000000000000000000000002"), - plumbing.NewHash("0000000000000000000000000000000000000003"), - plumbing.NewHash("0000000000000000000000000000000000000004"), - plumbing.NewHash("0000000000000000000000000000000000000005"), - plumbing.NewHash("0000000000000000000000000000000000000006"), - } - - tests := []struct { - hashes []plumbing.Hash - result []plumbing.Hash - }{ - // add to empty shallows - {hashes[0:2], hashes[0:2]}, - // add new hashes - {hashes[2:4], hashes[0:4]}, - // add some hashes already in shallow list - {hashes[2:6], hashes[0:6]}, - // add all hashes - {hashes[0:6], hashes[0:6]}, - // add empty list - {nil, hashes[0:6]}, - } - - remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{ - Name: DefaultRemoteName, - }) - - shallows, err := remote.s.Shallow() - c.Assert(err, IsNil) - c.Assert(len(shallows), Equals, 0) - - resp := new(packp.UploadPackResponse) - o := &FetchOptions{ - Depth: 1, - } - - for _, t := range tests { - resp.Shallows = t.hashes - err = remote.updateShallow(o, resp) - c.Assert(err, IsNil) - - shallow, err := remote.s.Shallow() - c.Assert(err, IsNil) - c.Assert(len(shallow), Equals, len(t.result)) - c.Assert(shallow, DeepEquals, t.result) - } -} - -func (s *RemoteSuite) TestUseRefDeltas(c *C) { - url := c.MkDir() - _, err := PlainInit(url, true) - c.Assert(err, IsNil) - - fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() - sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - r := NewRemote(sto, &config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{url}, - }) - - ar := packp.NewAdvRefs() - - ar.Capabilities.Add(capability.OFSDelta) - c.Assert(r.useRefDeltas(ar), Equals, false) - - ar.Capabilities.Delete(capability.OFSDelta) - c.Assert(r.useRefDeltas(ar), Equals, true) -} diff --git a/vendor/github.com/devtron-labs/go-git/repository_test.go b/vendor/github.com/devtron-labs/go-git/repository_test.go deleted file mode 100644 index 4c3f7c43..00000000 --- a/vendor/github.com/devtron-labs/go-git/repository_test.go +++ /dev/null @@ -1,2695 +0,0 @@ -package git - -import ( - "bytes" - "context" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "golang.org/x/crypto/openpgp" - "golang.org/x/crypto/openpgp/armor" - openpgperr "golang.org/x/crypto/openpgp/errors" - - "github.com/devtron-labs/go-git/config" - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/cache" - "github.com/devtron-labs/go-git/plumbing/object" - "github.com/devtron-labs/go-git/plumbing/storer" - "github.com/devtron-labs/go-git/plumbing/transport" - "github.com/devtron-labs/go-git/storage" - "github.com/devtron-labs/go-git/storage/filesystem" - "github.com/devtron-labs/go-git/storage/memory" - - "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-billy.v4/memfs" - "gopkg.in/src-d/go-billy.v4/osfs" - "gopkg.in/src-d/go-billy.v4/util" -) - -type RepositorySuite struct { - BaseSuite -} - -var _ = Suite(&RepositorySuite{}) - -func (s *RepositorySuite) TestInit(c *C) { - r, err := Init(memory.NewStorage(), memfs.New()) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Core.IsBare, Equals, false) -} - -func (s *RepositorySuite) TestInitNonStandardDotGit(c *C) { - dir, err := ioutil.TempDir("", "init-non-standard") - c.Assert(err, IsNil) - c.Assert(os.RemoveAll(dir), IsNil) - - fs := osfs.New(dir) - dot, _ := fs.Chroot("storage") - storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) - - wt, _ := fs.Chroot("worktree") - r, err := Init(storage, wt) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - f, err := fs.Open(fs.Join("worktree", ".git")) - c.Assert(err, IsNil) - - all, err := ioutil.ReadAll(f) - c.Assert(err, IsNil) - c.Assert(string(all), Equals, fmt.Sprintf("gitdir: %s\n", filepath.Join("..", "storage"))) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Core.Worktree, Equals, filepath.Join("..", "worktree")) -} - -func (s *RepositorySuite) TestInitStandardDotGit(c *C) { - dir, err := ioutil.TempDir("", "init-standard") - c.Assert(err, IsNil) - c.Assert(os.RemoveAll(dir), IsNil) - - fs := osfs.New(dir) - dot, _ := fs.Chroot(".git") - storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) - - r, err := Init(storage, fs) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - l, err := fs.ReadDir(".git") - c.Assert(err, IsNil) - c.Assert(len(l) > 0, Equals, true) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Core.Worktree, Equals, "") -} - -func (s *RepositorySuite) TestInitBare(c *C) { - r, err := Init(memory.NewStorage(), nil) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Core.IsBare, Equals, true) - -} - -func (s *RepositorySuite) TestInitAlreadyExists(c *C) { - st := memory.NewStorage() - - r, err := Init(st, nil) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = Init(st, nil) - c.Assert(err, Equals, ErrRepositoryAlreadyExists) - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestOpen(c *C) { - st := memory.NewStorage() - - r, err := Init(st, memfs.New()) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = Open(st, memfs.New()) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestOpenBare(c *C) { - st := memory.NewStorage() - - r, err := Init(st, nil) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = Open(st, nil) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestOpenBareMissingWorktree(c *C) { - st := memory.NewStorage() - - r, err := Init(st, memfs.New()) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = Open(st, nil) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestOpenNotExists(c *C) { - r, err := Open(memory.NewStorage(), nil) - c.Assert(err, Equals, ErrRepositoryNotExists) - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestClone(c *C) { - r, err := Clone(memory.NewStorage(), nil, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) -} - -func (s *RepositorySuite) TestCloneContext(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - r, err := CloneContext(ctx, memory.NewStorage(), nil, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(r, NotNil) - c.Assert(err, ErrorMatches, ".* context canceled") -} - -func (s *RepositorySuite) TestCloneWithTags(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, err := Clone(memory.NewStorage(), nil, &CloneOptions{URL: url, Tags: NoTags}) - c.Assert(err, IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) - - i, err := r.References() - c.Assert(err, IsNil) - - var count int - i.ForEach(func(r *plumbing.Reference) error { count++; return nil }) - - c.Assert(count, Equals, 3) -} - -func (s *RepositorySuite) TestCreateRemoteAndRemote(c *C) { - r, _ := Init(memory.NewStorage(), nil) - remote, err := r.CreateRemote(&config.RemoteConfig{ - Name: "foo", - URLs: []string{"http://foo/foo.git"}, - }) - - c.Assert(err, IsNil) - c.Assert(remote.Config().Name, Equals, "foo") - - alt, err := r.Remote("foo") - c.Assert(err, IsNil) - c.Assert(alt, Not(Equals), remote) - c.Assert(alt.Config().Name, Equals, "foo") -} - -func (s *RepositorySuite) TestCreateRemoteInvalid(c *C) { - r, _ := Init(memory.NewStorage(), nil) - remote, err := r.CreateRemote(&config.RemoteConfig{}) - - c.Assert(err, Equals, config.ErrRemoteConfigEmptyName) - c.Assert(remote, IsNil) -} - -func (s *RepositorySuite) TestCreateRemoteAnonymous(c *C) { - r, _ := Init(memory.NewStorage(), nil) - remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{ - Name: "anonymous", - URLs: []string{"http://foo/foo.git"}, - }) - - c.Assert(err, IsNil) - c.Assert(remote.Config().Name, Equals, "anonymous") -} - -func (s *RepositorySuite) TestCreateRemoteAnonymousInvalidName(c *C) { - r, _ := Init(memory.NewStorage(), nil) - remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{ - Name: "not_anonymous", - URLs: []string{"http://foo/foo.git"}, - }) - - c.Assert(err, Equals, ErrAnonymousRemoteName) - c.Assert(remote, IsNil) -} - -func (s *RepositorySuite) TestCreateRemoteAnonymousInvalid(c *C) { - r, _ := Init(memory.NewStorage(), nil) - remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{}) - - c.Assert(err, Equals, config.ErrRemoteConfigEmptyName) - c.Assert(remote, IsNil) -} - -func (s *RepositorySuite) TestDeleteRemote(c *C) { - r, _ := Init(memory.NewStorage(), nil) - _, err := r.CreateRemote(&config.RemoteConfig{ - Name: "foo", - URLs: []string{"http://foo/foo.git"}, - }) - - c.Assert(err, IsNil) - - err = r.DeleteRemote("foo") - c.Assert(err, IsNil) - - alt, err := r.Remote("foo") - c.Assert(err, Equals, ErrRemoteNotFound) - c.Assert(alt, IsNil) -} - -func (s *RepositorySuite) TestCreateBranchAndBranch(c *C) { - r, _ := Init(memory.NewStorage(), nil) - testBranch := &config.Branch{ - Name: "foo", - Remote: "origin", - Merge: "refs/heads/foo", - } - err := r.CreateBranch(testBranch) - - c.Assert(err, IsNil) - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(len(cfg.Branches), Equals, 1) - branch := cfg.Branches["foo"] - c.Assert(branch.Name, Equals, testBranch.Name) - c.Assert(branch.Remote, Equals, testBranch.Remote) - c.Assert(branch.Merge, Equals, testBranch.Merge) - - branch, err = r.Branch("foo") - c.Assert(err, IsNil) - c.Assert(branch.Name, Equals, testBranch.Name) - c.Assert(branch.Remote, Equals, testBranch.Remote) - c.Assert(branch.Merge, Equals, testBranch.Merge) -} - -func (s *RepositorySuite) TestCreateBranchUnmarshal(c *C) { - r, _ := Init(memory.NewStorage(), nil) - - expected := []byte(`[core] - bare = true -[remote "foo"] - url = http://foo/foo.git - fetch = +refs/heads/*:refs/remotes/foo/* -[branch "foo"] - remote = origin - merge = refs/heads/foo -[branch "master"] - remote = origin - merge = refs/heads/master -`) - - _, err := r.CreateRemote(&config.RemoteConfig{ - Name: "foo", - URLs: []string{"http://foo/foo.git"}, - }) - c.Assert(err, IsNil) - testBranch1 := &config.Branch{ - Name: "master", - Remote: "origin", - Merge: "refs/heads/master", - } - testBranch2 := &config.Branch{ - Name: "foo", - Remote: "origin", - Merge: "refs/heads/foo", - } - err = r.CreateBranch(testBranch1) - c.Assert(err, IsNil) - err = r.CreateBranch(testBranch2) - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - marshaled, err := cfg.Marshal() - c.Assert(err, IsNil) - c.Assert(string(expected), Equals, string(marshaled)) -} - -func (s *RepositorySuite) TestBranchInvalid(c *C) { - r, _ := Init(memory.NewStorage(), nil) - branch, err := r.Branch("foo") - - c.Assert(err, NotNil) - c.Assert(branch, IsNil) -} - -func (s *RepositorySuite) TestCreateBranchInvalid(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.CreateBranch(&config.Branch{}) - - c.Assert(err, NotNil) - - testBranch := &config.Branch{ - Name: "foo", - Remote: "origin", - Merge: "refs/heads/foo", - } - err = r.CreateBranch(testBranch) - c.Assert(err, IsNil) - err = r.CreateBranch(testBranch) - c.Assert(err, NotNil) -} - -func (s *RepositorySuite) TestDeleteBranch(c *C) { - r, _ := Init(memory.NewStorage(), nil) - testBranch := &config.Branch{ - Name: "foo", - Remote: "origin", - Merge: "refs/heads/foo", - } - err := r.CreateBranch(testBranch) - - c.Assert(err, IsNil) - - err = r.DeleteBranch("foo") - c.Assert(err, IsNil) - - b, err := r.Branch("foo") - c.Assert(err, Equals, ErrBranchNotFound) - c.Assert(b, IsNil) - - err = r.DeleteBranch("foo") - c.Assert(err, Equals, ErrBranchNotFound) -} - -func (s *RepositorySuite) TestPlainInit(c *C) { - dir, err := ioutil.TempDir("", "plain-init") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, true) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Core.IsBare, Equals, true) -} - -func (s *RepositorySuite) TestPlainInitAlreadyExists(c *C) { - dir, err := ioutil.TempDir("", "plain-init") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, true) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = PlainInit(dir, true) - c.Assert(err, Equals, ErrRepositoryAlreadyExists) - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestPlainOpen(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, false) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = PlainOpen(dir) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestPlainOpenBare(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, true) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = PlainOpen(dir) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestPlainOpenNotBare(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, false) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - r, err = PlainOpen(filepath.Join(dir, ".git")) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) testPlainOpenGitFile(c *C, f func(string, string) string) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, true) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - altDir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(altDir) - - err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(f(dir, altDir)), 0644) - c.Assert(err, IsNil) - - r, err = PlainOpen(altDir) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFile(c *C) { - s.testPlainOpenGitFile(c, func(dir, altDir string) string { - return fmt.Sprintf("gitdir: %s\n", dir) - }) -} - -func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFileNoEOL(c *C) { - s.testPlainOpenGitFile(c, func(dir, altDir string) string { - return fmt.Sprintf("gitdir: %s", dir) - }) -} - -func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFile(c *C) { - s.testPlainOpenGitFile(c, func(dir, altDir string) string { - dir, err := filepath.Rel(altDir, dir) - c.Assert(err, IsNil) - return fmt.Sprintf("gitdir: %s\n", dir) - }) -} - -func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileNoEOL(c *C) { - s.testPlainOpenGitFile(c, func(dir, altDir string) string { - dir, err := filepath.Rel(altDir, dir) - c.Assert(err, IsNil) - return fmt.Sprintf("gitdir: %s\n", dir) - }) -} - -func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileTrailingGarbage(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, true) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - altDir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("gitdir: %s\nTRAILING", altDir)), 0644) - c.Assert(err, IsNil) - - r, err = PlainOpen(altDir) - c.Assert(err, Equals, ErrRepositoryNotExists) - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileBadPrefix(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, true) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - altDir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("xgitdir: %s\n", dir)), 0644) - c.Assert(err, IsNil) - - r, err = PlainOpen(altDir) - c.Assert(err, ErrorMatches, ".*gitdir.*") - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestPlainOpenNotExists(c *C) { - r, err := PlainOpen("/not-exists/") - c.Assert(err, Equals, ErrRepositoryNotExists) - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestPlainOpenDetectDotGit(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - subdir := filepath.Join(dir, "a", "b") - err = os.MkdirAll(subdir, 0755) - c.Assert(err, IsNil) - - r, err := PlainInit(dir, false) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - opt := &PlainOpenOptions{DetectDotGit: true} - r, err = PlainOpenWithOptions(subdir, opt) - c.Assert(err, IsNil) - c.Assert(r, NotNil) -} - -func (s *RepositorySuite) TestPlainOpenNotExistsDetectDotGit(c *C) { - dir, err := ioutil.TempDir("", "plain-open") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - opt := &PlainOpenOptions{DetectDotGit: true} - r, err := PlainOpenWithOptions(dir, opt) - c.Assert(err, Equals, ErrRepositoryNotExists) - c.Assert(r, IsNil) -} - -func (s *RepositorySuite) TestPlainClone(c *C) { - r, err := PlainClone(c.MkDir(), false, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 1) - c.Assert(cfg.Branches["master"].Name, Equals, "master") -} - -func (s *RepositorySuite) TestPlainCloneWithRemoteName(c *C) { - r, err := PlainClone(c.MkDir(), false, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - RemoteName: "test", - }) - - c.Assert(err, IsNil) - - remote, err := r.Remote("test") - c.Assert(err, IsNil) - c.Assert(remote, NotNil) -} - -func (s *RepositorySuite) TestPlainCloneOverExistingGitDirectory(c *C) { - tmpDir := c.MkDir() - r, err := PlainInit(tmpDir, false) - c.Assert(r, NotNil) - c.Assert(err, IsNil) - - r, err = PlainClone(tmpDir, false, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(r, IsNil) - c.Assert(err, Equals, ErrRepositoryAlreadyExists) -} - -func (s *RepositorySuite) TestPlainCloneContextCancel(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - r, err := PlainCloneContext(ctx, c.MkDir(), false, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(r, NotNil) - c.Assert(err, ErrorMatches, ".* context canceled") -} - -func (s *RepositorySuite) TestPlainCloneContextNonExistentWithExistentDir(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - tmpDir := c.MkDir() - repoDir := tmpDir - - r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ - URL: "incorrectOnPurpose", - }) - c.Assert(r, NotNil) - c.Assert(err, Equals, transport.ErrRepositoryNotFound) - - _, err = os.Stat(repoDir) - c.Assert(os.IsNotExist(err), Equals, false) - - names, err := ioutil.ReadDir(repoDir) - c.Assert(err, IsNil) - c.Assert(names, HasLen, 0) -} - -func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNonExistentDir(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - tmpDir := c.MkDir() - repoDir := filepath.Join(tmpDir, "repoDir") - - r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ - URL: "incorrectOnPurpose", - }) - c.Assert(r, NotNil) - c.Assert(err, Equals, transport.ErrRepositoryNotFound) - - _, err = os.Stat(repoDir) - c.Assert(os.IsNotExist(err), Equals, true) -} - -func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotDir(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - tmpDir := c.MkDir() - repoDir := filepath.Join(tmpDir, "repoDir") - f, err := os.Create(repoDir) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ - URL: "incorrectOnPurpose", - }) - c.Assert(r, IsNil) - c.Assert(err, ErrorMatches, ".*not a directory.*") - - fi, err := os.Stat(repoDir) - c.Assert(err, IsNil) - c.Assert(fi.IsDir(), Equals, false) -} - -func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotEmptyDir(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - tmpDir := c.MkDir() - repoDirPath := filepath.Join(tmpDir, "repoDir") - err := os.Mkdir(repoDirPath, 0777) - c.Assert(err, IsNil) - - dummyFile := filepath.Join(repoDirPath, "dummyFile") - err = ioutil.WriteFile(dummyFile, []byte(fmt.Sprint("dummyContent")), 0644) - c.Assert(err, IsNil) - - r, err := PlainCloneContext(ctx, repoDirPath, false, &CloneOptions{ - URL: "incorrectOnPurpose", - }) - c.Assert(r, NotNil) - c.Assert(err, Equals, transport.ErrRepositoryNotFound) - - _, err = os.Stat(dummyFile) - c.Assert(err, IsNil) - -} - -func (s *RepositorySuite) TestPlainCloneContextNonExistingOverExistingGitDirectory(c *C) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - tmpDir := c.MkDir() - r, err := PlainInit(tmpDir, false) - c.Assert(r, NotNil) - c.Assert(err, IsNil) - - r, err = PlainCloneContext(ctx, tmpDir, false, &CloneOptions{ - URL: "incorrectOnPurpose", - }) - c.Assert(r, IsNil) - c.Assert(err, Equals, ErrRepositoryAlreadyExists) -} - -func (s *RepositorySuite) TestPlainCloneWithRecurseSubmodules(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - dir, err := ioutil.TempDir("", "plain-clone-submodule") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - path := fixtures.ByTag("submodule").One().Worktree().Root() - r, err := PlainClone(dir, false, &CloneOptions{ - URL: path, - RecurseSubmodules: DefaultSubmoduleRecursionDepth, - }) - - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Remotes, HasLen, 1) - c.Assert(cfg.Branches, HasLen, 1) - c.Assert(cfg.Submodules, HasLen, 2) -} - -func (s *RepositorySuite) TestPlainCloneNoCheckout(c *C) { - dir, err := ioutil.TempDir("", "plain-clone-no-checkout") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - path := fixtures.ByTag("submodule").One().Worktree().Root() - r, err := PlainClone(dir, false, &CloneOptions{ - URL: path, - NoCheckout: true, - RecurseSubmodules: DefaultSubmoduleRecursionDepth, - }) - c.Assert(err, IsNil) - - h, err := r.Head() - c.Assert(err, IsNil) - c.Assert(h.Hash().String(), Equals, "b685400c1f9316f350965a5993d350bc746b0bf4") - - fi, err := osfs.New(dir).ReadDir("") - c.Assert(err, IsNil) - c.Assert(fi, HasLen, 1) // .git -} - -func (s *RepositorySuite) TestFetch(c *C) { - r, _ := Init(memory.NewStorage(), nil) - _, err := r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - c.Assert(err, IsNil) - c.Assert(r.Fetch(&FetchOptions{}), IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) - - _, err = r.Head() - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) - - branch, err := r.Reference("refs/remotes/origin/master", false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Type(), Equals, plumbing.HashReference) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") -} - -func (s *RepositorySuite) TestFetchContext(c *C) { - r, _ := Init(memory.NewStorage(), nil) - _, err := r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - c.Assert(err, IsNil) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - c.Assert(r.FetchContext(ctx, &FetchOptions{}), NotNil) -} - -func (s *RepositorySuite) TestCloneWithProgress(c *C) { - fs := memfs.New() - - buf := bytes.NewBuffer(nil) - _, err := Clone(memory.NewStorage(), fs, &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - Progress: buf, - }) - - c.Assert(err, IsNil) - c.Assert(buf.Len(), Not(Equals), 0) -} - -func (s *RepositorySuite) TestCloneDeep(c *C) { - fs := memfs.New() - r, _ := Init(memory.NewStorage(), fs) - - head, err := r.Head() - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) - c.Assert(head, IsNil) - - err = r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) - - head, err = r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.SymbolicReference) - c.Assert(head.Target().String(), Equals, "refs/heads/master") - - branch, err := r.Reference(head.Target(), false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - branch, err = r.Reference("refs/remotes/origin/master", false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Type(), Equals, plumbing.HashReference) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - fi, err := fs.ReadDir("") - c.Assert(err, IsNil) - c.Assert(fi, HasLen, 8) -} - -func (s *RepositorySuite) TestCloneConfig(c *C) { - r, _ := Init(memory.NewStorage(), nil) - - head, err := r.Head() - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) - c.Assert(head, IsNil) - - err = r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - - c.Assert(cfg.Core.IsBare, Equals, true) - c.Assert(cfg.Remotes, HasLen, 1) - c.Assert(cfg.Remotes["origin"].Name, Equals, "origin") - c.Assert(cfg.Remotes["origin"].URLs, HasLen, 1) - c.Assert(cfg.Branches, HasLen, 1) - c.Assert(cfg.Branches["master"].Name, Equals, "master") -} - -func (s *RepositorySuite) TestCloneSingleBranchAndNonHEAD(c *C) { - r, _ := Init(memory.NewStorage(), nil) - - head, err := r.Head() - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) - c.Assert(head, IsNil) - - err = r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - ReferenceName: plumbing.ReferenceName("refs/heads/branch"), - SingleBranch: true, - }) - - c.Assert(err, IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 1) - c.Assert(cfg.Branches["branch"].Name, Equals, "branch") - c.Assert(cfg.Branches["branch"].Remote, Equals, "origin") - c.Assert(cfg.Branches["branch"].Merge, Equals, plumbing.ReferenceName("refs/heads/branch")) - - head, err = r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.SymbolicReference) - c.Assert(head.Target().String(), Equals, "refs/heads/branch") - - branch, err := r.Reference(head.Target(), false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881") - - branch, err = r.Reference("refs/remotes/origin/branch", false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Type(), Equals, plumbing.HashReference) - c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881") -} - -func (s *RepositorySuite) TestCloneSingleBranch(c *C) { - r, _ := Init(memory.NewStorage(), nil) - - head, err := r.Head() - c.Assert(err, Equals, plumbing.ErrReferenceNotFound) - c.Assert(head, IsNil) - - err = r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - SingleBranch: true, - }) - - c.Assert(err, IsNil) - - remotes, err := r.Remotes() - c.Assert(err, IsNil) - c.Assert(remotes, HasLen, 1) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 1) - c.Assert(cfg.Branches["master"].Name, Equals, "master") - c.Assert(cfg.Branches["master"].Remote, Equals, "origin") - c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master")) - - head, err = r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.SymbolicReference) - c.Assert(head.Target().String(), Equals, "refs/heads/master") - - branch, err := r.Reference(head.Target(), false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - branch, err = r.Reference("refs/remotes/origin/master", false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - c.Assert(branch.Type(), Equals, plumbing.HashReference) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") -} - -func (s *RepositorySuite) TestCloneSingleTag(c *C) { - r, _ := Init(memory.NewStorage(), nil) - - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - err := r.clone(context.Background(), &CloneOptions{ - URL: url, - SingleBranch: true, - ReferenceName: plumbing.ReferenceName("refs/tags/commit-tag"), - }) - c.Assert(err, IsNil) - - branch, err := r.Reference("refs/tags/commit-tag", false) - c.Assert(err, IsNil) - c.Assert(branch, NotNil) - - conf, err := r.Config() - c.Assert(err, IsNil) - originRemote := conf.Remotes["origin"] - c.Assert(originRemote, NotNil) - c.Assert(originRemote.Fetch, HasLen, 1) - c.Assert(originRemote.Fetch[0].String(), Equals, "+refs/tags/commit-tag:refs/tags/commit-tag") -} - -func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), - }) - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 0) - - head, err := r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.HashReference) - c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - count := 0 - objects, err := r.Objects() - c.Assert(err, IsNil) - objects.ForEach(func(object.Object) error { count++; return nil }) - c.Assert(count, Equals, 28) -} - -func (s *RepositorySuite) TestCloneDetachedHEADAndSingle(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), - SingleBranch: true, - }) - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 0) - - head, err := r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.HashReference) - c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - count := 0 - objects, err := r.Objects() - c.Assert(err, IsNil) - objects.ForEach(func(object.Object) error { count++; return nil }) - c.Assert(count, Equals, 28) -} - -func (s *RepositorySuite) TestCloneDetachedHEADAndShallow(c *C) { - r, _ := Init(memory.NewStorage(), memfs.New()) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), - Depth: 1, - }) - - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 0) - - head, err := r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.HashReference) - c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - count := 0 - objects, err := r.Objects() - c.Assert(err, IsNil) - objects.ForEach(func(object.Object) error { count++; return nil }) - c.Assert(count, Equals, 15) -} - -func (s *RepositorySuite) TestCloneDetachedHEADAnnotatedTag(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()), - ReferenceName: plumbing.ReferenceName("refs/tags/annotated-tag"), - }) - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Branches, HasLen, 0) - - head, err := r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(head, NotNil) - c.Assert(head.Type(), Equals, plumbing.HashReference) - c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") - - count := 0 - objects, err := r.Objects() - c.Assert(err, IsNil) - objects.ForEach(func(object.Object) error { count++; return nil }) - c.Assert(count, Equals, 7) -} - -func (s *RepositorySuite) TestPush(c *C) { - url := c.MkDir() - server, err := PlainInit(url, true) - c.Assert(err, IsNil) - - _, err = s.Repository.CreateRemote(&config.RemoteConfig{ - Name: "test", - URLs: []string{url}, - }) - c.Assert(err, IsNil) - - err = s.Repository.Push(&PushOptions{ - RemoteName: "test", - }) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", - }) - - AssertReferences(c, s.Repository, map[string]string{ - "refs/remotes/test/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "refs/remotes/test/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", - }) -} - -func (s *RepositorySuite) TestPushContext(c *C) { - url := c.MkDir() - _, err := PlainInit(url, true) - c.Assert(err, IsNil) - - _, err = s.Repository.CreateRemote(&config.RemoteConfig{ - Name: "foo", - URLs: []string{url}, - }) - c.Assert(err, IsNil) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - err = s.Repository.PushContext(ctx, &PushOptions{ - RemoteName: "foo", - }) - c.Assert(err, NotNil) -} - -// installPreReceiveHook installs a pre-receive hook in the .git -// directory at path which prints message m before exiting -// successfully. -func installPreReceiveHook(c *C, path, m string) { - hooks := filepath.Join(path, "hooks") - err := os.MkdirAll(hooks, 0777) - c.Assert(err, IsNil) - - err = ioutil.WriteFile(filepath.Join(hooks, "pre-receive"), preReceiveHook(m), 0777) - c.Assert(err, IsNil) -} - -func (s *RepositorySuite) TestPushWithProgress(c *C) { - url := c.MkDir() - server, err := PlainInit(url, true) - c.Assert(err, IsNil) - - m := "Receiving..." - installPreReceiveHook(c, url, m) - - _, err = s.Repository.CreateRemote(&config.RemoteConfig{ - Name: "bar", - URLs: []string{url}, - }) - c.Assert(err, IsNil) - - var p bytes.Buffer - err = s.Repository.Push(&PushOptions{ - RemoteName: "bar", - Progress: &p, - }) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", - }) - - c.Assert((&p).Bytes(), DeepEquals, []byte(m)) -} - -func (s *RepositorySuite) TestPushDepth(c *C) { - url := c.MkDir() - server, err := PlainClone(url, true, &CloneOptions{ - URL: fixtures.Basic().One().DotGit().Root(), - }) - - c.Assert(err, IsNil) - - r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ - URL: url, - Depth: 1, - }) - c.Assert(err, IsNil) - - err = util.WriteFile(r.wt, "foo", nil, 0755) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - _, err = w.Add("foo") - c.Assert(err, IsNil) - - hash, err := w.Commit("foo", &CommitOptions{ - Author: defaultSignature(), - Committer: defaultSignature(), - }) - c.Assert(err, IsNil) - - err = r.Push(&PushOptions{}) - c.Assert(err, IsNil) - - AssertReferences(c, server, map[string]string{ - "refs/heads/master": hash.String(), - }) - - AssertReferences(c, r, map[string]string{ - "refs/remotes/origin/master": hash.String(), - }) -} - -func (s *RepositorySuite) TestPushNonExistentRemote(c *C) { - srcFs := fixtures.Basic().One().DotGit() - sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) - - r, err := Open(sto, srcFs) - c.Assert(err, IsNil) - - err = r.Push(&PushOptions{RemoteName: "myremote"}) - c.Assert(err, ErrorMatches, ".*remote not found.*") -} - -func (s *RepositorySuite) TestLog(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - cIter, err := r.Log(&LogOptions{ - From: plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), - }) - - c.Assert(err, IsNil) - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), - plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), - } - - for _, o := range commitOrder { - commit, err := cIter.Next() - c.Assert(err, IsNil) - c.Assert(commit.Hash, Equals, o) - } - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) -} - -func (s *RepositorySuite) TestLogAll(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - - rIter, err := r.Storer.IterReferences() - c.Assert(err, IsNil) - - refCount := 0 - err = rIter.ForEach(func(ref *plumbing.Reference) error { - refCount++ - return nil - }) - c.Assert(err, IsNil) - c.Assert(refCount, Equals, 5) - - cIter, err := r.Log(&LogOptions{ - All: true, - }) - c.Assert(err, IsNil) - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), - plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), - plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), - plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), - plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), - plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), - plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), - } - - for _, o := range commitOrder { - commit, err := cIter.Next() - c.Assert(err, IsNil) - c.Assert(commit.Hash, Equals, o) - } - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) - cIter.Close() -} - -func (s *RepositorySuite) TestLogAllMissingReferences(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - err = r.Storer.RemoveReference(plumbing.HEAD) - c.Assert(err, IsNil) - - rIter, err := r.Storer.IterReferences() - c.Assert(err, IsNil) - - refCount := 0 - err = rIter.ForEach(func(ref *plumbing.Reference) error { - refCount++ - return nil - }) - c.Assert(err, IsNil) - c.Assert(refCount, Equals, 4) - - err = r.Storer.SetReference(plumbing.NewHashReference(plumbing.ReferenceName("DUMMY"), plumbing.NewHash("DUMMY"))) - c.Assert(err, IsNil) - - rIter, err = r.Storer.IterReferences() - c.Assert(err, IsNil) - - refCount = 0 - err = rIter.ForEach(func(ref *plumbing.Reference) error { - refCount++ - return nil - }) - c.Assert(err, IsNil) - c.Assert(refCount, Equals, 5) - - cIter, err := r.Log(&LogOptions{ - All: true, - }) - c.Assert(cIter, NotNil) - c.Assert(err, IsNil) - - cCount := 0 - cIter.ForEach(func(c *object.Commit) error { - cCount++ - return nil - }) - c.Assert(cCount, Equals, 9) - - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) - cIter.Close() -} - -func (s *RepositorySuite) TestLogAllOrderByTime(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - cIter, err := r.Log(&LogOptions{ - Order: LogOrderCommitterTime, - All: true, - }) - c.Assert(err, IsNil) - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), - plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), - plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), - plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), - plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), - plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), - plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), - } - - for _, o := range commitOrder { - commit, err := cIter.Next() - c.Assert(err, IsNil) - c.Assert(commit.Hash, Equals, o) - } - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) - cIter.Close() -} - -func (s *RepositorySuite) TestLogHead(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - cIter, err := r.Log(&LogOptions{}) - - c.Assert(err, IsNil) - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), - plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), - plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), - plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), - plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), - plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), - } - - for _, o := range commitOrder { - commit, err := cIter.Next() - c.Assert(err, IsNil) - c.Assert(commit.Hash, Equals, o) - } - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) -} - -func (s *RepositorySuite) TestLogError(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - _, err = r.Log(&LogOptions{ - From: plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), - }) - c.Assert(err, NotNil) -} - -func (s *RepositorySuite) TestLogFileNext(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - fileName := "vendor/foo.go" - cIter, err := r.Log(&LogOptions{FileName: &fileName}) - - c.Assert(err, IsNil) - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), - } - - for _, o := range commitOrder { - commit, err := cIter.Next() - c.Assert(err, IsNil) - c.Assert(commit.Hash, Equals, o) - } - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) -} - -func (s *RepositorySuite) TestLogFileForEach(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - fileName := "php/crappy.php" - cIter, err := r.Log(&LogOptions{FileName: &fileName}) - c.Assert(err, IsNil) - defer cIter.Close() - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), - } - - expectedIndex := 0 - cIter.ForEach(func(commit *object.Commit) error { - expectedCommitHash := commitOrder[expectedIndex] - c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) - expectedIndex++ - return nil - }) - c.Assert(expectedIndex, Equals, 1) -} - -func (s *RepositorySuite) TestLogNonHeadFile(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - fileName := "README" - cIter, err := r.Log(&LogOptions{FileName: &fileName}) - c.Assert(err, IsNil) - defer cIter.Close() - - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) -} - -func (s *RepositorySuite) TestLogAllFileForEach(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - fileName := "README" - cIter, err := r.Log(&LogOptions{FileName: &fileName, All: true}) - c.Assert(err, IsNil) - defer cIter.Close() - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), - } - - expectedIndex := 0 - cIter.ForEach(func(commit *object.Commit) error { - expectedCommitHash := commitOrder[expectedIndex] - c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) - expectedIndex++ - return nil - }) - c.Assert(expectedIndex, Equals, 1) -} - -func (s *RepositorySuite) TestLogInvalidFile(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - - // Throwing in a file that does not exist - fileName := "vendor/foo12.go" - cIter, err := r.Log(&LogOptions{FileName: &fileName}) - // Not raising an error since `git log -- vendor/foo12.go` responds silently - c.Assert(err, IsNil) - defer cIter.Close() - - _, err = cIter.Next() - c.Assert(err, Equals, io.EOF) -} - -func (s *RepositorySuite) TestLogFileInitialCommit(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - - fileName := "LICENSE" - cIter, err := r.Log(&LogOptions{ - Order: LogOrderCommitterTime, - FileName: &fileName, - }) - c.Assert(err, IsNil) - defer cIter.Close() - - commitOrder := []plumbing.Hash{ - plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), - } - - expectedIndex := 0 - cIter.ForEach(func(commit *object.Commit) error { - expectedCommitHash := commitOrder[expectedIndex] - c.Assert(commit.Hash.String(), Equals, expectedCommitHash.String()) - expectedIndex++ - return nil - }) - c.Assert(expectedIndex, Equals, 1) -} - -func (s *RepositorySuite) TestLogFileWithOtherParamsFail(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - - fileName := "vendor/foo.go" - cIter, err := r.Log(&LogOptions{ - Order: LogOrderCommitterTime, - FileName: &fileName, - From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - }) - c.Assert(err, IsNil) - defer cIter.Close() - - _, iterErr := cIter.Next() - c.Assert(iterErr, Equals, io.EOF) -} - -func (s *RepositorySuite) TestLogFileWithOtherParamsPass(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - - fileName := "LICENSE" - cIter, err := r.Log(&LogOptions{ - Order: LogOrderCommitterTime, - FileName: &fileName, - From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - }) - c.Assert(err, IsNil) - commitVal, iterErr := cIter.Next() - c.Assert(iterErr, Equals, nil) - c.Assert(commitVal.Hash.String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") - - _, iterErr = cIter.Next() - c.Assert(iterErr, Equals, io.EOF) -} - -func (s *RepositorySuite) TestCommit(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - hash := plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47") - commit, err := r.CommitObject(hash) - c.Assert(err, IsNil) - - c.Assert(commit.Hash.IsZero(), Equals, false) - c.Assert(commit.Hash, Equals, commit.ID()) - c.Assert(commit.Hash, Equals, hash) - c.Assert(commit.Type(), Equals, plumbing.CommitObject) - - tree, err := commit.Tree() - c.Assert(err, IsNil) - c.Assert(tree.Hash.IsZero(), Equals, false) - - c.Assert(commit.Author.Email, Equals, "daniel@lordran.local") -} - -func (s *RepositorySuite) TestCommits(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - count := 0 - commits, err := r.CommitObjects() - c.Assert(err, IsNil) - for { - commit, err := commits.Next() - if err != nil { - break - } - - count++ - c.Assert(commit.Hash.IsZero(), Equals, false) - c.Assert(commit.Hash, Equals, commit.ID()) - c.Assert(commit.Type(), Equals, plumbing.CommitObject) - } - - c.Assert(count, Equals, 9) -} - -func (s *RepositorySuite) TestBlob(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - - c.Assert(err, IsNil) - - blob, err := r.BlobObject(plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47")) - c.Assert(err, NotNil) - c.Assert(blob, IsNil) - - blobHash := plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492") - blob, err = r.BlobObject(blobHash) - c.Assert(err, IsNil) - - c.Assert(blob.Hash.IsZero(), Equals, false) - c.Assert(blob.Hash, Equals, blob.ID()) - c.Assert(blob.Hash, Equals, blobHash) - c.Assert(blob.Type(), Equals, plumbing.BlobObject) -} - -func (s *RepositorySuite) TestBlobs(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - count := 0 - blobs, err := r.BlobObjects() - c.Assert(err, IsNil) - for { - blob, err := blobs.Next() - if err != nil { - break - } - - count++ - c.Assert(blob.Hash.IsZero(), Equals, false) - c.Assert(blob.Hash, Equals, blob.ID()) - c.Assert(blob.Type(), Equals, plumbing.BlobObject) - } - - c.Assert(count, Equals, 10) -} - -func (s *RepositorySuite) TestTagObject(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - hash := plumbing.NewHash("ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc") - tag, err := r.TagObject(hash) - c.Assert(err, IsNil) - - c.Assert(tag.Hash.IsZero(), Equals, false) - c.Assert(tag.Hash, Equals, hash) - c.Assert(tag.Type(), Equals, plumbing.TagObject) -} - -func (s *RepositorySuite) TestTags(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - count := 0 - tags, err := r.Tags() - c.Assert(err, IsNil) - - tags.ForEach(func(tag *plumbing.Reference) error { - count++ - c.Assert(tag.Hash().IsZero(), Equals, false) - c.Assert(tag.Name().IsTag(), Equals, true) - return nil - }) - - c.Assert(count, Equals, 5) -} - -func (s *RepositorySuite) TestCreateTagLightweight(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - expected, err := r.Head() - c.Assert(err, IsNil) - - ref, err := r.CreateTag("foobar", expected.Hash(), nil) - c.Assert(err, IsNil) - c.Assert(ref, NotNil) - - actual, err := r.Tag("foobar") - c.Assert(err, IsNil) - - c.Assert(expected.Hash(), Equals, actual.Hash()) -} - -func (s *RepositorySuite) TestCreateTagLightweightExists(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - expected, err := r.Head() - c.Assert(err, IsNil) - - ref, err := r.CreateTag("lightweight-tag", expected.Hash(), nil) - c.Assert(ref, IsNil) - c.Assert(err, Equals, ErrTagExists) -} - -func (s *RepositorySuite) TestCreateTagAnnotated(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - h, err := r.Head() - c.Assert(err, IsNil) - - expectedHash := h.Hash() - - ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ - Tagger: defaultSignature(), - Message: "foo bar baz qux", - }) - c.Assert(err, IsNil) - - tag, err := r.Tag("foobar") - c.Assert(err, IsNil) - - obj, err := r.TagObject(tag.Hash()) - c.Assert(err, IsNil) - - c.Assert(ref, DeepEquals, tag) - c.Assert(obj.Hash, Equals, ref.Hash()) - c.Assert(obj.Type(), Equals, plumbing.TagObject) - c.Assert(obj.Target, Equals, expectedHash) -} - -func (s *RepositorySuite) TestCreateTagAnnotatedBadOpts(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - h, err := r.Head() - c.Assert(err, IsNil) - - expectedHash := h.Hash() - - ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ - Message: "foo bar baz qux", - }) - c.Assert(ref, IsNil) - c.Assert(err, Equals, ErrMissingTagger) - - ref, err = r.CreateTag("foobar", expectedHash, &CreateTagOptions{ - Tagger: defaultSignature(), - }) - c.Assert(ref, IsNil) - c.Assert(err, Equals, ErrMissingMessage) -} - -func (s *RepositorySuite) TestCreateTagAnnotatedBadHash(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - ref, err := r.CreateTag("foobar", plumbing.ZeroHash, &CreateTagOptions{ - Tagger: defaultSignature(), - Message: "foo bar baz qux", - }) - c.Assert(ref, IsNil) - c.Assert(err, Equals, plumbing.ErrObjectNotFound) -} - -func (s *RepositorySuite) TestCreateTagSigned(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - h, err := r.Head() - c.Assert(err, IsNil) - - key := commitSignKey(c, true) - _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ - Tagger: defaultSignature(), - Message: "foo bar baz qux", - SignKey: key, - }) - c.Assert(err, IsNil) - - tag, err := r.Tag("foobar") - c.Assert(err, IsNil) - - obj, err := r.TagObject(tag.Hash()) - c.Assert(err, IsNil) - - // Verify the tag. - pks := new(bytes.Buffer) - pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) - c.Assert(err, IsNil) - - err = key.Serialize(pkw) - c.Assert(err, IsNil) - err = pkw.Close() - c.Assert(err, IsNil) - - actual, err := obj.Verify(pks.String()) - c.Assert(err, IsNil) - c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) -} - -func (s *RepositorySuite) TestCreateTagSignedBadKey(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - h, err := r.Head() - c.Assert(err, IsNil) - - key := commitSignKey(c, false) - _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ - Tagger: defaultSignature(), - Message: "foo bar baz qux", - SignKey: key, - }) - c.Assert(err, Equals, openpgperr.InvalidArgumentError("signing key is encrypted")) -} - -func (s *RepositorySuite) TestCreateTagCanonicalize(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - h, err := r.Head() - c.Assert(err, IsNil) - - key := commitSignKey(c, true) - _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ - Tagger: defaultSignature(), - Message: "\n\nfoo bar baz qux\n\nsome message here", - SignKey: key, - }) - c.Assert(err, IsNil) - - tag, err := r.Tag("foobar") - c.Assert(err, IsNil) - - obj, err := r.TagObject(tag.Hash()) - c.Assert(err, IsNil) - - // Assert the new canonicalized message. - c.Assert(obj.Message, Equals, "foo bar baz qux\n\nsome message here\n") - - // Verify the tag. - pks := new(bytes.Buffer) - pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) - c.Assert(err, IsNil) - - err = key.Serialize(pkw) - c.Assert(err, IsNil) - err = pkw.Close() - c.Assert(err, IsNil) - - actual, err := obj.Verify(pks.String()) - c.Assert(err, IsNil) - c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) -} - -func (s *RepositorySuite) TestTagLightweight(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - expected := plumbing.NewHash("f7b877701fbf855b44c0a9e86f3fdce2c298b07f") - - tag, err := r.Tag("lightweight-tag") - c.Assert(err, IsNil) - - actual := tag.Hash() - c.Assert(expected, Equals, actual) -} - -func (s *RepositorySuite) TestTagLightweightMissingTag(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - tag, err := r.Tag("lightweight-tag-tag") - c.Assert(tag, IsNil) - c.Assert(err, Equals, ErrTagNotFound) -} - -func (s *RepositorySuite) TestDeleteTag(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - err = r.DeleteTag("lightweight-tag") - c.Assert(err, IsNil) - - _, err = r.Tag("lightweight-tag") - c.Assert(err, Equals, ErrTagNotFound) -} - -func (s *RepositorySuite) TestDeleteTagMissingTag(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - err = r.DeleteTag("lightweight-tag-tag") - c.Assert(err, Equals, ErrTagNotFound) -} - -func (s *RepositorySuite) TestDeleteTagAnnotated(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - dir, err := ioutil.TempDir("", "go-git-test-deletetag-annotated") - c.Assert(err, IsNil) - - defer os.RemoveAll(dir) // clean up - - fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) - - r, _ := Init(fss, nil) - err = r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - ref, err := r.Tag("annotated-tag") - c.Assert(ref, NotNil) - c.Assert(err, IsNil) - - obj, err := r.TagObject(ref.Hash()) - c.Assert(obj, NotNil) - c.Assert(err, IsNil) - - err = r.DeleteTag("annotated-tag") - c.Assert(err, IsNil) - - _, err = r.Tag("annotated-tag") - c.Assert(err, Equals, ErrTagNotFound) - - // Run a prune (and repack, to ensure that we are GCing everything regardless - // of the fixture in use) and try to get the tag object again. - // - // The repo needs to be re-opened after the repack. - err = r.Prune(PruneOptions{Handler: r.DeleteObject}) - c.Assert(err, IsNil) - - err = r.RepackObjects(&RepackConfig{}) - c.Assert(err, IsNil) - - r, err = PlainOpen(dir) - c.Assert(r, NotNil) - c.Assert(err, IsNil) - - // Now check to see if the GC was effective in removing the tag object. - obj, err = r.TagObject(ref.Hash()) - c.Assert(obj, IsNil) - c.Assert(err, Equals, plumbing.ErrObjectNotFound) -} - -func (s *RepositorySuite) TestDeleteTagAnnotatedUnpacked(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - dir, err := ioutil.TempDir("", "go-git-test-deletetag-annotated-unpacked") - c.Assert(err, IsNil) - - defer os.RemoveAll(dir) // clean up - - fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) - - r, _ := Init(fss, nil) - err = r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - // Create a tag for the deletion test. This ensures that the ultimate loose - // object will be unpacked (as we aren't doing anything that should pack it), - // so that we can effectively test that a prune deletes it, without having to - // resort to a repack. - h, err := r.Head() - c.Assert(err, IsNil) - - expectedHash := h.Hash() - - ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ - Tagger: defaultSignature(), - Message: "foo bar baz qux", - }) - c.Assert(err, IsNil) - - tag, err := r.Tag("foobar") - c.Assert(err, IsNil) - - obj, err := r.TagObject(tag.Hash()) - c.Assert(obj, NotNil) - c.Assert(err, IsNil) - - err = r.DeleteTag("foobar") - c.Assert(err, IsNil) - - _, err = r.Tag("foobar") - c.Assert(err, Equals, ErrTagNotFound) - - // As mentioned, only run a prune. We are not testing for packed objects - // here. - err = r.Prune(PruneOptions{Handler: r.DeleteObject}) - c.Assert(err, IsNil) - - // Now check to see if the GC was effective in removing the tag object. - obj, err = r.TagObject(ref.Hash()) - c.Assert(obj, IsNil) - c.Assert(err, Equals, plumbing.ErrObjectNotFound) -} - -func (s *RepositorySuite) TestBranches(c *C) { - f := fixtures.ByURL("https://github.com/git-fixtures/root-references.git").One() - sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) - r, err := Open(sto, f.DotGit()) - c.Assert(err, IsNil) - - count := 0 - branches, err := r.Branches() - c.Assert(err, IsNil) - - branches.ForEach(func(branch *plumbing.Reference) error { - count++ - c.Assert(branch.Hash().IsZero(), Equals, false) - c.Assert(branch.Name().IsBranch(), Equals, true) - return nil - }) - - c.Assert(count, Equals, 8) -} - -func (s *RepositorySuite) TestNotes(c *C) { - // TODO add fixture with Notes - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - count := 0 - notes, err := r.Notes() - c.Assert(err, IsNil) - - notes.ForEach(func(note *plumbing.Reference) error { - count++ - c.Assert(note.Hash().IsZero(), Equals, false) - c.Assert(note.Name().IsNote(), Equals, true) - return nil - }) - - c.Assert(count, Equals, 0) -} - -func (s *RepositorySuite) TestTree(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - }) - c.Assert(err, IsNil) - - invalidHash := plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") - tree, err := r.TreeObject(invalidHash) - c.Assert(tree, IsNil) - c.Assert(err, NotNil) - - hash := plumbing.NewHash("dbd3641b371024f44d0e469a9c8f5457b0660de1") - tree, err = r.TreeObject(hash) - c.Assert(err, IsNil) - - c.Assert(tree.Hash.IsZero(), Equals, false) - c.Assert(tree.Hash, Equals, tree.ID()) - c.Assert(tree.Hash, Equals, hash) - c.Assert(tree.Type(), Equals, plumbing.TreeObject) - c.Assert(len(tree.Entries), Not(Equals), 0) -} - -func (s *RepositorySuite) TestTrees(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - count := 0 - trees, err := r.TreeObjects() - c.Assert(err, IsNil) - for { - tree, err := trees.Next() - if err != nil { - break - } - - count++ - c.Assert(tree.Hash.IsZero(), Equals, false) - c.Assert(tree.Hash, Equals, tree.ID()) - c.Assert(tree.Type(), Equals, plumbing.TreeObject) - c.Assert(len(tree.Entries), Not(Equals), 0) - } - - c.Assert(count, Equals, 12) -} - -func (s *RepositorySuite) TestTagObjects(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - count := 0 - tags, err := r.TagObjects() - c.Assert(err, IsNil) - - tags.ForEach(func(tag *object.Tag) error { - count++ - - c.Assert(tag.Hash.IsZero(), Equals, false) - c.Assert(tag.Type(), Equals, plumbing.TagObject) - return nil - }) - - refs, _ := r.References() - refs.ForEach(func(ref *plumbing.Reference) error { - return nil - }) - - c.Assert(count, Equals, 4) -} - -func (s *RepositorySuite) TestCommitIterClosePanic(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - commits, err := r.CommitObjects() - c.Assert(err, IsNil) - commits.Close() -} - -func (s *RepositorySuite) TestRef(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - ref, err := r.Reference(plumbing.HEAD, false) - c.Assert(err, IsNil) - c.Assert(ref.Name(), Equals, plumbing.HEAD) - - ref, err = r.Reference(plumbing.HEAD, true) - c.Assert(err, IsNil) - c.Assert(ref.Name(), Equals, plumbing.ReferenceName("refs/heads/master")) -} - -func (s *RepositorySuite) TestRefs(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - c.Assert(err, IsNil) - - iter, err := r.References() - c.Assert(err, IsNil) - c.Assert(iter, NotNil) -} - -func (s *RepositorySuite) TestObject(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - hash := plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - o, err := r.Object(plumbing.CommitObject, hash) - c.Assert(err, IsNil) - - c.Assert(o.ID().IsZero(), Equals, false) - c.Assert(o.Type(), Equals, plumbing.CommitObject) -} - -func (s *RepositorySuite) TestObjects(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - count := 0 - objects, err := r.Objects() - c.Assert(err, IsNil) - for { - o, err := objects.Next() - if err != nil { - break - } - - count++ - c.Assert(o.ID().IsZero(), Equals, false) - c.Assert(o.Type(), Not(Equals), plumbing.AnyObject) - } - - c.Assert(count, Equals, 31) -} - -func (s *RepositorySuite) TestObjectNotFound(c *C) { - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) - c.Assert(err, IsNil) - - hash := plumbing.NewHash("0a3fb06ff80156fb153bcdcc58b5e16c2d27625c") - tag, err := r.Object(plumbing.TagObject, hash) - c.Assert(err, DeepEquals, plumbing.ErrObjectNotFound) - c.Assert(tag, IsNil) -} - -func (s *RepositorySuite) TestWorktree(c *C) { - def := memfs.New() - r, _ := Init(memory.NewStorage(), def) - w, err := r.Worktree() - c.Assert(err, IsNil) - c.Assert(w.Filesystem, Equals, def) -} - -func (s *RepositorySuite) TestWorktreeBare(c *C) { - r, _ := Init(memory.NewStorage(), nil) - w, err := r.Worktree() - c.Assert(err, Equals, ErrIsBareRepository) - c.Assert(w, IsNil) -} - -func (s *RepositorySuite) TestResolveRevision(c *C) { - f := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One() - sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) - r, err := Open(sto, f.DotGit()) - c.Assert(err, IsNil) - - datas := map[string]string{ - "HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "heads/master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", - "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d", - "refs/tags/v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "refs/remotes/origin/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "refs/remotes/origin/HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d", - "HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", - "HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", - "HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9", - "HEAD~^{/!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea", - "master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", - "v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - "branch~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", - "v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", - "master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", - "918c48b83bd081e863dbe1b80f8998f058cd8294": "918c48b83bd081e863dbe1b80f8998f058cd8294", - } - - for rev, hash := range datas { - h, err := r.ResolveRevision(plumbing.Revision(rev)) - - c.Assert(err, IsNil, Commentf("while checking %s", rev)) - c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev)) - } -} - -func (s *RepositorySuite) TestResolveRevisionAnnotated(c *C) { - f := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One() - sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) - r, err := Open(sto, f.DotGit()) - c.Assert(err, IsNil) - - datas := map[string]string{ - "refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", - "b742a2a9fa0afcfa9a6fad080980fbc26b007c69": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", - } - - for rev, hash := range datas { - h, err := r.ResolveRevision(plumbing.Revision(rev)) - - c.Assert(err, IsNil, Commentf("while checking %s", rev)) - c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev)) - } -} - -func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) { - url := s.GetLocalRepositoryURL( - fixtures.ByURL("https://github.com/git-fixtures/basic.git").One(), - ) - - r, _ := Init(memory.NewStorage(), nil) - err := r.clone(context.Background(), &CloneOptions{URL: url}) - c.Assert(err, IsNil) - - headRef, err := r.Head() - c.Assert(err, IsNil) - - ref := plumbing.NewHashReference("refs/heads/918c48b83bd081e863dbe1b80f8998f058cd8294", headRef.Hash()) - err = r.Storer.SetReference(ref) - c.Assert(err, IsNil) - - datas := map[string]string{ - "efs/heads/master~": "reference not found", - "HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`, - "HEAD^{/whatever}": `No commit message match regexp : "whatever"`, - "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83": "reference not found", - } - - for rev, rerr := range datas { - _, err := r.ResolveRevision(plumbing.Revision(rev)) - c.Assert(err, NotNil) - c.Assert(err.Error(), Equals, rerr) - } -} - -func (s *RepositorySuite) testRepackObjects( - c *C, deleteTime time.Time, expectedPacks int) { - srcFs := fixtures.ByTag("unpacked").One().DotGit() - var sto storage.Storer - var err error - sto = filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) - - los := sto.(storer.LooseObjectStorer) - c.Assert(los, NotNil) - - numLooseStart := 0 - err = los.ForEachObjectHash(func(_ plumbing.Hash) error { - numLooseStart++ - return nil - }) - c.Assert(err, IsNil) - c.Assert(numLooseStart > 0, Equals, true) - - pos := sto.(storer.PackedObjectStorer) - c.Assert(los, NotNil) - - packs, err := pos.ObjectPacks() - c.Assert(err, IsNil) - numPacksStart := len(packs) - c.Assert(numPacksStart > 1, Equals, true) - - r, err := Open(sto, srcFs) - c.Assert(err, IsNil) - c.Assert(r, NotNil) - - err = r.RepackObjects(&RepackConfig{ - OnlyDeletePacksOlderThan: deleteTime, - }) - c.Assert(err, IsNil) - - numLooseEnd := 0 - err = los.ForEachObjectHash(func(_ plumbing.Hash) error { - numLooseEnd++ - return nil - }) - c.Assert(err, IsNil) - c.Assert(numLooseEnd, Equals, 0) - - packs, err = pos.ObjectPacks() - c.Assert(err, IsNil) - numPacksEnd := len(packs) - c.Assert(numPacksEnd, Equals, expectedPacks) -} - -func (s *RepositorySuite) TestRepackObjects(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - s.testRepackObjects(c, time.Time{}, 1) -} - -func (s *RepositorySuite) TestRepackObjectsWithNoDelete(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - s.testRepackObjects(c, time.Unix(0, 1), 3) -} - -func ExecuteOnPath(c *C, path string, cmds ...string) error { - for _, cmd := range cmds { - err := executeOnPath(path, cmd) - c.Assert(err, IsNil) - } - - return nil -} - -func executeOnPath(path, cmd string) error { - args := strings.Split(cmd, " ") - c := exec.Command(args[0], args[1:]...) - c.Dir = path - c.Env = os.Environ() - - buf := bytes.NewBuffer(nil) - c.Stderr = buf - c.Stdout = buf - - return c.Run() -} - -func (s *RepositorySuite) TestBrokenMultipleShallowFetch(c *C) { - r, _ := Init(memory.NewStorage(), nil) - _, err := r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - c.Assert(err, IsNil) - - c.Assert(r.Fetch(&FetchOptions{ - Depth: 2, - RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/master:refs/heads/master")}, - }), IsNil) - - shallows, err := r.Storer.Shallow() - c.Assert(err, IsNil) - c.Assert(len(shallows), Equals, 1) - - ref, err := r.Reference("refs/heads/master", true) - c.Assert(err, IsNil) - cobj, err := r.CommitObject(ref.Hash()) - c.Assert(err, IsNil) - c.Assert(cobj, NotNil) - err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error { - for _, ph := range c.ParentHashes { - for _, h := range shallows { - if ph == h { - return storer.ErrStop - } - } - } - - return nil - }) - c.Assert(err, IsNil) - - c.Assert(r.Fetch(&FetchOptions{ - Depth: 5, - RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/*:refs/heads/*")}, - }), IsNil) - - shallows, err = r.Storer.Shallow() - c.Assert(err, IsNil) - c.Assert(len(shallows), Equals, 3) - - ref, err = r.Reference("refs/heads/master", true) - c.Assert(err, IsNil) - cobj, err = r.CommitObject(ref.Hash()) - c.Assert(err, IsNil) - c.Assert(cobj, NotNil) - err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error { - for _, ph := range c.ParentHashes { - for _, h := range shallows { - if ph == h { - return storer.ErrStop - } - } - } - - return nil - }) - c.Assert(err, IsNil) -} - -func BenchmarkObjects(b *testing.B) { - if err := fixtures.Init(); err != nil { - b.Fatal(err) - } - - defer func() { - if err := fixtures.Clean(); err != nil { - b.Fatal(err) - } - }() - - for _, f := range fixtures.ByTag("packfile") { - if f.DotGitHash == plumbing.ZeroHash { - continue - } - - b.Run(f.URL, func(b *testing.B) { - fs := f.DotGit() - storer := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - - worktree, err := fs.Chroot(filepath.Dir(fs.Root())) - if err != nil { - b.Fatal(err) - } - - repo, err := Open(storer, worktree) - if err != nil { - b.Fatal(err) - } - - for i := 0; i < b.N; i++ { - iter, err := repo.Objects() - if err != nil { - b.Fatal(err) - } - - for { - _, err := iter.Next() - if err == io.EOF { - break - } - - if err != nil { - b.Fatal(err) - } - } - - iter.Close() - } - }) - } -} - -func BenchmarkPlainClone(b *testing.B) { - for i := 0; i < b.N; i++ { - t, err := ioutil.TempDir("", "") - if err != nil { - b.Fatal(err) - } - _, err = PlainClone(t, false, &CloneOptions{ - URL: "https://github.com/knqyf263/vuln-list", - Depth: 1, - }) - if err != nil { - b.Error(err) - } - b.StopTimer() - os.RemoveAll(t) - b.StartTimer() - } -} diff --git a/vendor/github.com/devtron-labs/go-git/repository_unix_test.go b/vendor/github.com/devtron-labs/go-git/repository_unix_test.go deleted file mode 100644 index 75682ae7..00000000 --- a/vendor/github.com/devtron-labs/go-git/repository_unix_test.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !plan9,!windows - -package git - -import "fmt" - -// preReceiveHook returns the bytes of a pre-receive hook script -// that prints m before exiting successfully -func preReceiveHook(m string) []byte { - return []byte(fmt.Sprintf("#!/bin/sh\nprintf '%s'\n", m)) -} diff --git a/vendor/github.com/devtron-labs/go-git/repository_windows_test.go b/vendor/github.com/devtron-labs/go-git/repository_windows_test.go deleted file mode 100644 index bec0acdd..00000000 --- a/vendor/github.com/devtron-labs/go-git/repository_windows_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package git - -import "fmt" - -// preReceiveHook returns the bytes of a pre-receive hook script -// that prints m before exiting successfully -func preReceiveHook(m string) []byte { - return []byte(fmt.Sprintf("#!C:/Program\\ Files/Git/usr/bin/sh.exe\nprintf '%s'\n", m)) -} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/config.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/config.go new file mode 100644 index 00000000..12acf0d6 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/config.go @@ -0,0 +1,61 @@ +package filesystem + +import ( + stdioutil "io/ioutil" + "os" + + "github.com/devtron-labs/go-git/config" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +type ConfigStorage struct { + dir *dotgit.DotGit +} + +func (c *ConfigStorage) Config() (conf *config.Config, err error) { + cfg := config.NewConfig() + + f, err := c.dir.Config() + if err != nil { + if os.IsNotExist(err) { + return cfg, nil + } + + return nil, err + } + + defer ioutil.CheckClose(f, &err) + + b, err := stdioutil.ReadAll(f) + if err != nil { + return nil, err + } + + if err = cfg.Unmarshal(b); err != nil { + return nil, err + } + + return cfg, err +} + +func (c *ConfigStorage) SetConfig(cfg *config.Config) (err error) { + if err = cfg.Validate(); err != nil { + return err + } + + f, err := c.dir.ConfigWriter() + if err != nil { + return err + } + + defer ioutil.CheckClose(f, &err) + + b, err := cfg.Marshal() + if err != nil { + return err + } + + _, err = f.Write(b) + return err +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/deltaobject.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/deltaobject.go new file mode 100644 index 00000000..2e759598 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/deltaobject.go @@ -0,0 +1,37 @@ +package filesystem + +import ( + "github.com/devtron-labs/go-git/plumbing" +) + +type deltaObject struct { + plumbing.EncodedObject + base plumbing.Hash + hash plumbing.Hash + size int64 +} + +func newDeltaObject( + obj plumbing.EncodedObject, + hash plumbing.Hash, + base plumbing.Hash, + size int64) plumbing.DeltaObject { + return &deltaObject{ + EncodedObject: obj, + hash: hash, + base: base, + size: size, + } +} + +func (o *deltaObject) BaseHash() plumbing.Hash { + return o.base +} + +func (o *deltaObject) ActualSize() int64 { + return o.size +} + +func (o *deltaObject) ActualHash() plumbing.Hash { + return o.hash +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit.go new file mode 100644 index 00000000..dcd47284 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit.go @@ -0,0 +1,1100 @@ +// https://github.com/git/git/blob/master/Documentation/gitrepository-layout.txt +package dotgit + +import ( + "bufio" + "errors" + "fmt" + "io" + stdioutil "io/ioutil" + "os" + "path/filepath" + "strings" + "time" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/utils/ioutil" + "gopkg.in/src-d/go-billy.v4/osfs" + + "gopkg.in/src-d/go-billy.v4" +) + +const ( + suffix = ".git" + packedRefsPath = "packed-refs" + configPath = "config" + indexPath = "index" + shallowPath = "shallow" + modulePath = "modules" + objectsPath = "objects" + packPath = "pack" + refsPath = "refs" + + tmpPackedRefsPrefix = "._packed-refs" + + packExt = ".pack" + idxExt = ".idx" +) + +var ( + // ErrNotFound is returned by New when the path is not found. + ErrNotFound = errors.New("path not found") + // ErrIdxNotFound is returned by Idxfile when the idx file is not found + ErrIdxNotFound = errors.New("idx file not found") + // ErrPackfileNotFound is returned by Packfile when the packfile is not found + ErrPackfileNotFound = errors.New("packfile not found") + // ErrConfigNotFound is returned by Config when the config is not found + ErrConfigNotFound = errors.New("config file not found") + // ErrPackedRefsDuplicatedRef is returned when a duplicated reference is + // found in the packed-ref file. This is usually the case for corrupted git + // repositories. + ErrPackedRefsDuplicatedRef = errors.New("duplicated ref found in packed-ref file") + // ErrPackedRefsBadFormat is returned when the packed-ref file corrupt. + ErrPackedRefsBadFormat = errors.New("malformed packed-ref") + // ErrSymRefTargetNotFound is returned when a symbolic reference is + // targeting a non-existing object. This usually means the repository + // is corrupt. + ErrSymRefTargetNotFound = errors.New("symbolic reference target not found") +) + +// Options holds configuration for the storage. +type Options struct { + // ExclusiveAccess means that the filesystem is not modified externally + // while the repo is open. + ExclusiveAccess bool + // KeepDescriptors makes the file descriptors to be reused but they will + // need to be manually closed calling Close(). + KeepDescriptors bool +} + +// The DotGit type represents a local git repository on disk. This +// type is not zero-value-safe, use the New function to initialize it. +type DotGit struct { + options Options + fs billy.Filesystem + + // incoming object directory information + incomingChecked bool + incomingDirName string + + objectList []plumbing.Hash + objectMap map[plumbing.Hash]struct{} + packList []plumbing.Hash + packMap map[plumbing.Hash]struct{} + + files map[plumbing.Hash]billy.File +} + +// New returns a DotGit value ready to be used. The path argument must +// be the absolute path of a git repository directory (e.g. +// "/foo/bar/.git"). +func New(fs billy.Filesystem) *DotGit { + return NewWithOptions(fs, Options{}) +} + +// NewWithOptions sets non default configuration options. +// See New for complete help. +func NewWithOptions(fs billy.Filesystem, o Options) *DotGit { + return &DotGit{ + options: o, + fs: fs, + } +} + +// Initialize creates all the folder scaffolding. +func (d *DotGit) Initialize() error { + mustExists := []string{ + d.fs.Join("objects", "info"), + d.fs.Join("objects", "pack"), + d.fs.Join("refs", "heads"), + d.fs.Join("refs", "tags"), + } + + for _, path := range mustExists { + _, err := d.fs.Stat(path) + if err == nil { + continue + } + + if !os.IsNotExist(err) { + return err + } + + if err := d.fs.MkdirAll(path, os.ModeDir|os.ModePerm); err != nil { + return err + } + } + + return nil +} + +// Close closes all opened files. +func (d *DotGit) Close() error { + var firstError error + if d.files != nil { + for _, f := range d.files { + err := f.Close() + if err != nil && firstError == nil { + firstError = err + continue + } + } + + d.files = nil + } + + if firstError != nil { + return firstError + } + + return nil +} + +// ConfigWriter returns a file pointer for write to the config file +func (d *DotGit) ConfigWriter() (billy.File, error) { + return d.fs.Create(configPath) +} + +// Config returns a file pointer for read to the config file +func (d *DotGit) Config() (billy.File, error) { + return d.fs.Open(configPath) +} + +// IndexWriter returns a file pointer for write to the index file +func (d *DotGit) IndexWriter() (billy.File, error) { + return d.fs.Create(indexPath) +} + +// Index returns a file pointer for read to the index file +func (d *DotGit) Index() (billy.File, error) { + return d.fs.Open(indexPath) +} + +// ShallowWriter returns a file pointer for write to the shallow file +func (d *DotGit) ShallowWriter() (billy.File, error) { + return d.fs.Create(shallowPath) +} + +// Shallow returns a file pointer for read to the shallow file +func (d *DotGit) Shallow() (billy.File, error) { + f, err := d.fs.Open(shallowPath) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + + return nil, err + } + + return f, nil +} + +// NewObjectPack return a writer for a new packfile, it saves the packfile to +// disk and also generates and save the index for the given packfile. +func (d *DotGit) NewObjectPack() (*PackWriter, error) { + d.cleanPackList() + return newPackWrite(d.fs) +} + +// ObjectPacks returns the list of availables packfiles +func (d *DotGit) ObjectPacks() ([]plumbing.Hash, error) { + if !d.options.ExclusiveAccess { + return d.objectPacks() + } + + err := d.genPackList() + if err != nil { + return nil, err + } + + return d.packList, nil +} + +func (d *DotGit) objectPacks() ([]plumbing.Hash, error) { + packDir := d.fs.Join(objectsPath, packPath) + files, err := d.fs.ReadDir(packDir) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + + return nil, err + } + + var packs []plumbing.Hash + for _, f := range files { + if !strings.HasSuffix(f.Name(), packExt) { + continue + } + + n := f.Name() + h := plumbing.NewHash(n[5 : len(n)-5]) //pack-(hash).pack + if h.IsZero() { + // Ignore files with badly-formatted names. + continue + } + packs = append(packs, h) + } + + return packs, nil +} + +func (d *DotGit) objectPackPath(hash plumbing.Hash, extension string) string { + return d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.%s", hash.String(), extension)) +} + +func (d *DotGit) objectPackOpen(hash plumbing.Hash, extension string) (billy.File, error) { + if d.options.KeepDescriptors && extension == "pack" { + if d.files == nil { + d.files = make(map[plumbing.Hash]billy.File) + } + + f, ok := d.files[hash] + if ok { + return f, nil + } + } + + err := d.hasPack(hash) + if err != nil { + return nil, err + } + + path := d.objectPackPath(hash, extension) + pack, err := d.fs.Open(path) + if err != nil { + if os.IsNotExist(err) { + return nil, ErrPackfileNotFound + } + + return nil, err + } + + if d.options.KeepDescriptors && extension == "pack" { + d.files[hash] = pack + } + + return pack, nil +} + +// ObjectPack returns a fs.File of the given packfile +func (d *DotGit) ObjectPack(hash plumbing.Hash) (billy.File, error) { + err := d.hasPack(hash) + if err != nil { + return nil, err + } + + return d.objectPackOpen(hash, `pack`) +} + +// ObjectPackIdx returns a fs.File of the index file for a given packfile +func (d *DotGit) ObjectPackIdx(hash plumbing.Hash) (billy.File, error) { + err := d.hasPack(hash) + if err != nil { + return nil, err + } + + return d.objectPackOpen(hash, `idx`) +} + +func (d *DotGit) DeleteOldObjectPackAndIndex(hash plumbing.Hash, t time.Time) error { + d.cleanPackList() + + path := d.objectPackPath(hash, `pack`) + if !t.IsZero() { + fi, err := d.fs.Stat(path) + if err != nil { + return err + } + // too new, skip deletion. + if !fi.ModTime().Before(t) { + return nil + } + } + err := d.fs.Remove(path) + if err != nil { + return err + } + return d.fs.Remove(d.objectPackPath(hash, `idx`)) +} + +// NewObject return a writer for a new object file. +func (d *DotGit) NewObject() (*ObjectWriter, error) { + d.cleanObjectList() + + return newObjectWriter(d.fs) +} + +// Objects returns a slice with the hashes of objects found under the +// .git/objects/ directory. +func (d *DotGit) Objects() ([]plumbing.Hash, error) { + if d.options.ExclusiveAccess { + err := d.genObjectList() + if err != nil { + return nil, err + } + + return d.objectList, nil + } + + var objects []plumbing.Hash + err := d.ForEachObjectHash(func(hash plumbing.Hash) error { + objects = append(objects, hash) + return nil + }) + if err != nil { + return nil, err + } + return objects, nil +} + +// ForEachObjectHash iterates over the hashes of objects found under the +// .git/objects/ directory and executes the provided function. +func (d *DotGit) ForEachObjectHash(fun func(plumbing.Hash) error) error { + if !d.options.ExclusiveAccess { + return d.forEachObjectHash(fun) + } + + err := d.genObjectList() + if err != nil { + return err + } + + for _, h := range d.objectList { + err := fun(h) + if err != nil { + return err + } + } + + return nil +} + +func (d *DotGit) forEachObjectHash(fun func(plumbing.Hash) error) error { + files, err := d.fs.ReadDir(objectsPath) + if err != nil { + if os.IsNotExist(err) { + return nil + } + + return err + } + + for _, f := range files { + if f.IsDir() && len(f.Name()) == 2 && isHex(f.Name()) { + base := f.Name() + d, err := d.fs.ReadDir(d.fs.Join(objectsPath, base)) + if err != nil { + return err + } + + for _, o := range d { + h := plumbing.NewHash(base + o.Name()) + if h.IsZero() { + // Ignore files with badly-formatted names. + continue + } + err = fun(h) + if err != nil { + return err + } + } + } + } + + return nil +} + +func (d *DotGit) cleanObjectList() { + d.objectMap = nil + d.objectList = nil +} + +func (d *DotGit) genObjectList() error { + if d.objectMap != nil { + return nil + } + + d.objectMap = make(map[plumbing.Hash]struct{}) + return d.forEachObjectHash(func(h plumbing.Hash) error { + d.objectList = append(d.objectList, h) + d.objectMap[h] = struct{}{} + + return nil + }) +} + +func (d *DotGit) hasObject(h plumbing.Hash) error { + if !d.options.ExclusiveAccess { + return nil + } + + err := d.genObjectList() + if err != nil { + return err + } + + _, ok := d.objectMap[h] + if !ok { + return plumbing.ErrObjectNotFound + } + + return nil +} + +func (d *DotGit) cleanPackList() { + d.packMap = nil + d.packList = nil +} + +func (d *DotGit) genPackList() error { + if d.packMap != nil { + return nil + } + + op, err := d.objectPacks() + if err != nil { + return err + } + + d.packMap = make(map[plumbing.Hash]struct{}) + d.packList = nil + + for _, h := range op { + d.packList = append(d.packList, h) + d.packMap[h] = struct{}{} + } + + return nil +} + +func (d *DotGit) hasPack(h plumbing.Hash) error { + if !d.options.ExclusiveAccess { + return nil + } + + err := d.genPackList() + if err != nil { + return err + } + + _, ok := d.packMap[h] + if !ok { + return ErrPackfileNotFound + } + + return nil +} + +func (d *DotGit) objectPath(h plumbing.Hash) string { + hash := h.String() + return d.fs.Join(objectsPath, hash[0:2], hash[2:40]) +} + +// incomingObjectPath is intended to add support for a git pre-receive hook +// to be written it adds support for go-git to find objects in an "incoming" +// directory, so that the library can be used to write a pre-receive hook +// that deals with the incoming objects. +// +// More on git hooks found here : https://git-scm.com/docs/githooks +// More on 'quarantine'/incoming directory here: +// +// https://git-scm.com/docs/git-receive-pack +func (d *DotGit) incomingObjectPath(h plumbing.Hash) string { + hString := h.String() + + if d.incomingDirName == "" { + return d.fs.Join(objectsPath, hString[0:2], hString[2:40]) + } + + return d.fs.Join(objectsPath, d.incomingDirName, hString[0:2], hString[2:40]) +} + +// hasIncomingObjects searches for an incoming directory and keeps its name +// so it doesn't have to be found each time an object is accessed. +func (d *DotGit) hasIncomingObjects() bool { + if !d.incomingChecked { + directoryContents, err := d.fs.ReadDir(objectsPath) + if err == nil { + for _, file := range directoryContents { + if strings.HasPrefix(file.Name(), "incoming-") && file.IsDir() { + d.incomingDirName = file.Name() + } + } + } + + d.incomingChecked = true + } + + return d.incomingDirName != "" +} + +// Object returns a fs.File pointing the object file, if exists +func (d *DotGit) Object(h plumbing.Hash) (billy.File, error) { + err := d.hasObject(h) + if err != nil { + return nil, err + } + + obj1, err1 := d.fs.Open(d.objectPath(h)) + if os.IsNotExist(err1) && d.hasIncomingObjects() { + obj2, err2 := d.fs.Open(d.incomingObjectPath(h)) + if err2 != nil { + return obj1, err1 + } + return obj2, err2 + } + return obj1, err1 +} + +// ObjectStat returns a os.FileInfo pointing the object file, if exists +func (d *DotGit) ObjectStat(h plumbing.Hash) (os.FileInfo, error) { + err := d.hasObject(h) + if err != nil { + return nil, err + } + + obj1, err1 := d.fs.Stat(d.objectPath(h)) + if os.IsNotExist(err1) && d.hasIncomingObjects() { + obj2, err2 := d.fs.Stat(d.incomingObjectPath(h)) + if err2 != nil { + return obj1, err1 + } + return obj2, err2 + } + return obj1, err1 +} + +// ObjectDelete removes the object file, if exists +func (d *DotGit) ObjectDelete(h plumbing.Hash) error { + d.cleanObjectList() + + err1 := d.fs.Remove(d.objectPath(h)) + if os.IsNotExist(err1) && d.hasIncomingObjects() { + err2 := d.fs.Remove(d.incomingObjectPath(h)) + if err2 != nil { + return err1 + } + return err2 + } + return err1 +} + +func (d *DotGit) readReferenceFrom(rd io.Reader, name string) (ref *plumbing.Reference, err error) { + b, err := stdioutil.ReadAll(rd) + if err != nil { + return nil, err + } + + line := strings.TrimSpace(string(b)) + return plumbing.NewReferenceFromStrings(name, line), nil +} + +func (d *DotGit) checkReferenceAndTruncate(f billy.File, old *plumbing.Reference) error { + if old == nil { + return nil + } + ref, err := d.readReferenceFrom(f, old.Name().String()) + if err != nil { + return err + } + if ref.Hash() != old.Hash() { + return storage.ErrReferenceHasChanged + } + _, err = f.Seek(0, io.SeekStart) + if err != nil { + return err + } + return f.Truncate(0) +} + +func (d *DotGit) SetRef(r, old *plumbing.Reference) error { + var content string + switch r.Type() { + case plumbing.SymbolicReference: + content = fmt.Sprintf("ref: %s\n", r.Target()) + case plumbing.HashReference: + content = fmt.Sprintln(r.Hash().String()) + } + + fileName := r.Name().String() + + return d.setRef(fileName, content, old) +} + +// Refs scans the git directory collecting references, which it returns. +// Symbolic references are resolved and included in the output. +func (d *DotGit) Refs() ([]*plumbing.Reference, error) { + var refs []*plumbing.Reference + var seen = make(map[plumbing.ReferenceName]bool) + if err := d.addRefsFromRefDir(&refs, seen); err != nil { + return nil, err + } + + if err := d.addRefsFromPackedRefs(&refs, seen); err != nil { + return nil, err + } + + if err := d.addRefFromHEAD(&refs); err != nil { + return nil, err + } + + return refs, nil +} + +// Ref returns the reference for a given reference name. +func (d *DotGit) Ref(name plumbing.ReferenceName) (*plumbing.Reference, error) { + ref, err := d.readReferenceFile(".", name.String()) + if err == nil { + return ref, nil + } + + return d.packedRef(name) +} + +func (d *DotGit) findPackedRefsInFile(f billy.File) ([]*plumbing.Reference, error) { + s := bufio.NewScanner(f) + var refs []*plumbing.Reference + for s.Scan() { + ref, err := d.processLine(s.Text()) + if err != nil { + return nil, err + } + + if ref != nil { + refs = append(refs, ref) + } + } + + return refs, s.Err() +} + +func (d *DotGit) findPackedRefs() (r []*plumbing.Reference, err error) { + f, err := d.fs.Open(packedRefsPath) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + + defer ioutil.CheckClose(f, &err) + return d.findPackedRefsInFile(f) +} + +func (d *DotGit) packedRef(name plumbing.ReferenceName) (*plumbing.Reference, error) { + refs, err := d.findPackedRefs() + if err != nil { + return nil, err + } + + for _, ref := range refs { + if ref.Name() == name { + return ref, nil + } + } + + return nil, plumbing.ErrReferenceNotFound +} + +// RemoveRef removes a reference by name. +func (d *DotGit) RemoveRef(name plumbing.ReferenceName) error { + path := d.fs.Join(".", name.String()) + _, err := d.fs.Stat(path) + if err == nil { + err = d.fs.Remove(path) + // Drop down to remove it from the packed refs file, too. + } + + if err != nil && !os.IsNotExist(err) { + return err + } + + return d.rewritePackedRefsWithoutRef(name) +} + +func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference, seen map[plumbing.ReferenceName]bool) (err error) { + packedRefs, err := d.findPackedRefs() + if err != nil { + return err + } + + for _, ref := range packedRefs { + if !seen[ref.Name()] { + *refs = append(*refs, ref) + seen[ref.Name()] = true + } + } + return nil +} + +func (d *DotGit) addRefsFromPackedRefsFile(refs *[]*plumbing.Reference, f billy.File, seen map[plumbing.ReferenceName]bool) (err error) { + packedRefs, err := d.findPackedRefsInFile(f) + if err != nil { + return err + } + + for _, ref := range packedRefs { + if !seen[ref.Name()] { + *refs = append(*refs, ref) + seen[ref.Name()] = true + } + } + return nil +} + +func (d *DotGit) openAndLockPackedRefs(doCreate bool) ( + pr billy.File, err error) { + var f billy.File + defer func() { + if err != nil && f != nil { + ioutil.CheckClose(f, &err) + } + }() + + // File mode is retrieved from a constant defined in the target specific + // files (dotgit_rewrite_packed_refs_*). Some modes are not available + // in all filesystems. + openFlags := d.openAndLockPackedRefsMode() + if doCreate { + openFlags |= os.O_CREATE + } + + // Keep trying to open and lock the file until we're sure the file + // didn't change between the open and the lock. + for { + f, err = d.fs.OpenFile(packedRefsPath, openFlags, 0600) + if err != nil { + if os.IsNotExist(err) && !doCreate { + return nil, nil + } + + return nil, err + } + fi, err := d.fs.Stat(packedRefsPath) + if err != nil { + return nil, err + } + mtime := fi.ModTime() + + err = f.Lock() + if err != nil { + return nil, err + } + + fi, err = d.fs.Stat(packedRefsPath) + if err != nil { + return nil, err + } + if mtime.Equal(fi.ModTime()) { + break + } + // The file has changed since we opened it. Close and retry. + err = f.Close() + if err != nil { + return nil, err + } + } + return f, nil +} + +func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err error) { + pr, err := d.openAndLockPackedRefs(false) + if err != nil { + return err + } + if pr == nil { + return nil + } + defer ioutil.CheckClose(pr, &err) + + // Creating the temp file in the same directory as the target file + // improves our chances for rename operation to be atomic. + tmp, err := d.fs.TempFile("", tmpPackedRefsPrefix) + if err != nil { + return err + } + tmpName := tmp.Name() + defer func() { + ioutil.CheckClose(tmp, &err) + _ = d.fs.Remove(tmpName) // don't check err, we might have renamed it + }() + + s := bufio.NewScanner(pr) + found := false + for s.Scan() { + line := s.Text() + ref, err := d.processLine(line) + if err != nil { + return err + } + + if ref != nil && ref.Name() == name { + found = true + continue + } + + if _, err := fmt.Fprintln(tmp, line); err != nil { + return err + } + } + + if err := s.Err(); err != nil { + return err + } + + if !found { + return nil + } + + return d.rewritePackedRefsWhileLocked(tmp, pr) +} + +// process lines from a packed-refs file +func (d *DotGit) processLine(line string) (*plumbing.Reference, error) { + if len(line) == 0 { + return nil, nil + } + + switch line[0] { + case '#': // comment - ignore + return nil, nil + case '^': // annotated tag commit of the previous line - ignore + return nil, nil + default: + ws := strings.Split(line, " ") // hash then ref + if len(ws) != 2 { + return nil, ErrPackedRefsBadFormat + } + + return plumbing.NewReferenceFromStrings(ws[1], ws[0]), nil + } +} + +func (d *DotGit) addRefsFromRefDir(refs *[]*plumbing.Reference, seen map[plumbing.ReferenceName]bool) error { + return d.walkReferencesTree(refs, []string{refsPath}, seen) +} + +func (d *DotGit) walkReferencesTree(refs *[]*plumbing.Reference, relPath []string, seen map[plumbing.ReferenceName]bool) error { + files, err := d.fs.ReadDir(d.fs.Join(relPath...)) + if err != nil { + if os.IsNotExist(err) { + return nil + } + + return err + } + + for _, f := range files { + newRelPath := append(append([]string(nil), relPath...), f.Name()) + if f.IsDir() { + if err = d.walkReferencesTree(refs, newRelPath, seen); err != nil { + return err + } + + continue + } + + ref, err := d.readReferenceFile(".", strings.Join(newRelPath, "/")) + if err != nil { + return err + } + + if ref != nil && !seen[ref.Name()] { + *refs = append(*refs, ref) + seen[ref.Name()] = true + } + } + + return nil +} + +func (d *DotGit) addRefFromHEAD(refs *[]*plumbing.Reference) error { + ref, err := d.readReferenceFile(".", "HEAD") + if err != nil { + if os.IsNotExist(err) { + return nil + } + + return err + } + + *refs = append(*refs, ref) + return nil +} + +func (d *DotGit) readReferenceFile(path, name string) (ref *plumbing.Reference, err error) { + path = d.fs.Join(path, d.fs.Join(strings.Split(name, "/")...)) + f, err := d.fs.Open(path) + if err != nil { + return nil, err + } + defer ioutil.CheckClose(f, &err) + + return d.readReferenceFrom(f, name) +} + +func (d *DotGit) CountLooseRefs() (int, error) { + var refs []*plumbing.Reference + var seen = make(map[plumbing.ReferenceName]bool) + if err := d.addRefsFromRefDir(&refs, seen); err != nil { + return 0, err + } + + return len(refs), nil +} + +// PackRefs packs all loose refs into the packed-refs file. +// +// This implementation only works under the assumption that the view +// of the file system won't be updated during this operation. This +// strategy would not work on a general file system though, without +// locking each loose reference and checking it again before deleting +// the file, because otherwise an updated reference could sneak in and +// then be deleted by the packed-refs process. Alternatively, every +// ref update could also lock packed-refs, so only one lock is +// required during ref-packing. But that would worsen performance in +// the common case. +// +// TODO: add an "all" boolean like the `git pack-refs --all` flag. +// When `all` is false, it would only pack refs that have already been +// packed, plus all tags. +func (d *DotGit) PackRefs() (err error) { + // Lock packed-refs, and create it if it doesn't exist yet. + f, err := d.openAndLockPackedRefs(true) + if err != nil { + return err + } + defer ioutil.CheckClose(f, &err) + + // Gather all refs using addRefsFromRefDir and addRefsFromPackedRefs. + var refs []*plumbing.Reference + seen := make(map[plumbing.ReferenceName]bool) + if err = d.addRefsFromRefDir(&refs, seen); err != nil { + return err + } + if len(refs) == 0 { + // Nothing to do! + return nil + } + numLooseRefs := len(refs) + if err = d.addRefsFromPackedRefsFile(&refs, f, seen); err != nil { + return err + } + + // Write them all to a new temp packed-refs file. + tmp, err := d.fs.TempFile("", tmpPackedRefsPrefix) + if err != nil { + return err + } + tmpName := tmp.Name() + defer func() { + ioutil.CheckClose(tmp, &err) + _ = d.fs.Remove(tmpName) // don't check err, we might have renamed it + }() + + w := bufio.NewWriter(tmp) + for _, ref := range refs { + _, err = w.WriteString(ref.String() + "\n") + if err != nil { + return err + } + } + err = w.Flush() + if err != nil { + return err + } + + // Rename the temp packed-refs file. + err = d.rewritePackedRefsWhileLocked(tmp, f) + if err != nil { + return err + } + + // Delete all the loose refs, while still holding the packed-refs + // lock. + for _, ref := range refs[:numLooseRefs] { + path := d.fs.Join(".", ref.Name().String()) + err = d.fs.Remove(path) + if err != nil && !os.IsNotExist(err) { + return err + } + } + + return nil +} + +// Module return a billy.Filesystem pointing to the module folder +func (d *DotGit) Module(name string) (billy.Filesystem, error) { + return d.fs.Chroot(d.fs.Join(modulePath, name)) +} + +// Alternates returns DotGit(s) based off paths in objects/info/alternates if +// available. This can be used to checks if it's a shared repository. +func (d *DotGit) Alternates() ([]*DotGit, error) { + altpath := d.fs.Join("objects", "info", "alternates") + f, err := d.fs.Open(altpath) + if err != nil { + return nil, err + } + defer f.Close() + + var alternates []*DotGit + + // Read alternate paths line-by-line and create DotGit objects. + scanner := bufio.NewScanner(f) + for scanner.Scan() { + path := scanner.Text() + if !filepath.IsAbs(path) { + // For relative paths, we can perform an internal conversion to + // slash so that they work cross-platform. + slashPath := filepath.ToSlash(path) + // If the path is not absolute, it must be relative to object + // database (.git/objects/info). + // https://www.kernel.org/pub/software/scm/git/docs/gitrepository-layout.html + // Hence, derive a path relative to DotGit's root. + // "../../../reponame/.git/" -> "../../reponame/.git" + // Remove the first ../ + relpath := filepath.Join(strings.Split(slashPath, "/")[1:]...) + normalPath := filepath.FromSlash(relpath) + path = filepath.Join(d.fs.Root(), normalPath) + } + fs := osfs.New(filepath.Dir(path)) + alternates = append(alternates, New(fs)) + } + + if err = scanner.Err(); err != nil { + return nil, err + } + + return alternates, nil +} + +// Fs returns the underlying filesystem of the DotGit folder. +func (d *DotGit) Fs() billy.Filesystem { + return d.fs +} + +func isHex(s string) bool { + for _, b := range []byte(s) { + if isNum(b) { + continue + } + if isHexAlpha(b) { + continue + } + + return false + } + + return true +} + +func isNum(b byte) bool { + return b >= '0' && b <= '9' +} + +func isHexAlpha(b byte) bool { + return b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F' +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go new file mode 100644 index 00000000..dfb03bcd --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_rewrite_packed_refs.go @@ -0,0 +1,81 @@ +package dotgit + +import ( + "io" + "os" + "runtime" + + "github.com/devtron-labs/go-git/utils/ioutil" + "gopkg.in/src-d/go-billy.v4" +) + +func (d *DotGit) openAndLockPackedRefsMode() int { + if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) { + return os.O_RDWR + } + + return os.O_RDONLY +} + +func (d *DotGit) rewritePackedRefsWhileLocked( + tmp billy.File, pr billy.File) error { + // Try plain rename. If we aren't using the bare Windows filesystem as the + // storage layer, we might be able to get away with a rename over a locked + // file. + err := d.fs.Rename(tmp.Name(), pr.Name()) + if err == nil { + return nil + } + + // If we are in a filesystem that does not support rename (e.g. sivafs) + // a full copy is done. + if err == billy.ErrNotSupported { + return d.copyNewFile(tmp, pr) + } + + if runtime.GOOS != "windows" { + return err + } + + // Otherwise, Windows doesn't let us rename over a locked file, so + // we have to do a straight copy. Unfortunately this could result + // in a partially-written file if the process fails before the + // copy completes. + return d.copyToExistingFile(tmp, pr) +} + +func (d *DotGit) copyToExistingFile(tmp, pr billy.File) error { + _, err := pr.Seek(0, io.SeekStart) + if err != nil { + return err + } + err = pr.Truncate(0) + if err != nil { + return err + } + _, err = tmp.Seek(0, io.SeekStart) + if err != nil { + return err + } + _, err = io.Copy(pr, tmp) + + return err +} + +func (d *DotGit) copyNewFile(tmp billy.File, pr billy.File) (err error) { + prWrite, err := d.fs.Create(pr.Name()) + if err != nil { + return err + } + + defer ioutil.CheckClose(prWrite, &err) + + _, err = tmp.Seek(0, io.SeekStart) + if err != nil { + return err + } + + _, err = io.Copy(prWrite, tmp) + + return err +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_setref.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_setref.go new file mode 100644 index 00000000..23b018d9 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/dotgit_setref.go @@ -0,0 +1,90 @@ +package dotgit + +import ( + "fmt" + "os" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/utils/ioutil" + + "gopkg.in/src-d/go-billy.v4" +) + +func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err error) { + if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) { + return d.setRefRwfs(fileName, content, old) + } + + return d.setRefNorwfs(fileName, content, old) +} + +func (d *DotGit) setRefRwfs(fileName, content string, old *plumbing.Reference) (err error) { + // If we are not checking an old ref, just truncate the file. + mode := os.O_RDWR | os.O_CREATE + if old == nil { + mode |= os.O_TRUNC + } + + f, err := d.fs.OpenFile(fileName, mode, 0666) + if err != nil { + return err + } + + defer ioutil.CheckClose(f, &err) + + // Lock is unlocked by the deferred Close above. This is because Unlock + // does not imply a fsync and thus there would be a race between + // Unlock+Close and other concurrent writers. Adding Sync to go-billy + // could work, but this is better (and avoids superfluous syncs). + err = f.Lock() + if err != nil { + return err + } + + // this is a no-op to call even when old is nil. + err = d.checkReferenceAndTruncate(f, old) + if err != nil { + return err + } + + _, err = f.Write([]byte(content)) + return err +} + +// There are some filesystems that don't support opening files in RDWD mode. +// In these filesystems the standard SetRef function can not be used as it +// reads the reference file to check that it's not modified before updating it. +// +// This version of the function writes the reference without extra checks +// making it compatible with these simple filesystems. This is usually not +// a problem as they should be accessed by only one process at a time. +func (d *DotGit) setRefNorwfs(fileName, content string, old *plumbing.Reference) error { + _, err := d.fs.Stat(fileName) + if err == nil && old != nil { + fRead, err := d.fs.Open(fileName) + if err != nil { + return err + } + + ref, err := d.readReferenceFrom(fRead, old.Name().String()) + fRead.Close() + + if err != nil { + return err + } + + if ref.Hash() != old.Hash() { + return fmt.Errorf("reference has changed concurrently") + } + } + + f, err := d.fs.Create(fileName) + if err != nil { + return err + } + + defer f.Close() + + _, err = f.Write([]byte(content)) + return err +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/writers.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/writers.go new file mode 100644 index 00000000..0d26eff3 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/dotgit/writers.go @@ -0,0 +1,284 @@ +package dotgit + +import ( + "fmt" + "io" + "sync/atomic" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/format/idxfile" + "github.com/devtron-labs/go-git/plumbing/format/objfile" + "github.com/devtron-labs/go-git/plumbing/format/packfile" + + "gopkg.in/src-d/go-billy.v4" +) + +// PackWriter is a io.Writer that generates the packfile index simultaneously, +// a packfile.Decoder is used with a file reader to read the file being written +// this operation is synchronized with the write operations. +// The packfile is written in a temp file, when Close is called this file +// is renamed/moved (depends on the Filesystem implementation) to the final +// location, if the PackWriter is not used, nothing is written +type PackWriter struct { + Notify func(plumbing.Hash, *idxfile.Writer) + + fs billy.Filesystem + fr, fw billy.File + synced *syncedReader + checksum plumbing.Hash + parser *packfile.Parser + writer *idxfile.Writer + result chan error +} + +func newPackWrite(fs billy.Filesystem) (*PackWriter, error) { + fw, err := fs.TempFile(fs.Join(objectsPath, packPath), "tmp_pack_") + if err != nil { + return nil, err + } + + fr, err := fs.Open(fw.Name()) + if err != nil { + return nil, err + } + + writer := &PackWriter{ + fs: fs, + fw: fw, + fr: fr, + synced: newSyncedReader(fw, fr), + result: make(chan error), + } + + go writer.buildIndex() + return writer, nil +} + +func (w *PackWriter) buildIndex() { + s := packfile.NewScanner(w.synced) + w.writer = new(idxfile.Writer) + var err error + w.parser, err = packfile.NewParser(s, w.writer) + if err != nil { + w.result <- err + return + } + + checksum, err := w.parser.Parse() + if err != nil { + w.result <- err + return + } + + w.checksum = checksum + w.result <- err +} + +// waitBuildIndex waits until buildIndex function finishes, this can terminate +// with a packfile.ErrEmptyPackfile, this means that nothing was written so we +// ignore the error +func (w *PackWriter) waitBuildIndex() error { + err := <-w.result + if err == packfile.ErrEmptyPackfile { + return nil + } + + return err +} + +func (w *PackWriter) Write(p []byte) (int, error) { + return w.synced.Write(p) +} + +// Close closes all the file descriptors and save the final packfile, if nothing +// was written, the tempfiles are deleted without writing a packfile. +func (w *PackWriter) Close() error { + defer func() { + if w.Notify != nil && w.writer != nil && w.writer.Finished() { + w.Notify(w.checksum, w.writer) + } + + close(w.result) + }() + + if err := w.synced.Close(); err != nil { + return err + } + + if err := w.waitBuildIndex(); err != nil { + return err + } + + if err := w.fr.Close(); err != nil { + return err + } + + if err := w.fw.Close(); err != nil { + return err + } + + if w.writer == nil || !w.writer.Finished() { + return w.clean() + } + + return w.save() +} + +func (w *PackWriter) clean() error { + return w.fs.Remove(w.fw.Name()) +} + +func (w *PackWriter) save() error { + base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.checksum)) + idx, err := w.fs.Create(fmt.Sprintf("%s.idx", base)) + if err != nil { + return err + } + + if err := w.encodeIdx(idx); err != nil { + return err + } + + if err := idx.Close(); err != nil { + return err + } + + return w.fs.Rename(w.fw.Name(), fmt.Sprintf("%s.pack", base)) +} + +func (w *PackWriter) encodeIdx(writer io.Writer) error { + idx, err := w.writer.Index() + if err != nil { + return err + } + + e := idxfile.NewEncoder(writer) + _, err = e.Encode(idx) + return err +} + +type syncedReader struct { + w io.Writer + r io.ReadSeeker + + blocked, done uint32 + written, read uint64 + news chan bool +} + +func newSyncedReader(w io.Writer, r io.ReadSeeker) *syncedReader { + return &syncedReader{ + w: w, + r: r, + news: make(chan bool), + } +} + +func (s *syncedReader) Write(p []byte) (n int, err error) { + defer func() { + written := atomic.AddUint64(&s.written, uint64(n)) + read := atomic.LoadUint64(&s.read) + if written > read { + s.wake() + } + }() + + n, err = s.w.Write(p) + return +} + +func (s *syncedReader) Read(p []byte) (n int, err error) { + defer func() { atomic.AddUint64(&s.read, uint64(n)) }() + + for { + s.sleep() + n, err = s.r.Read(p) + if err == io.EOF && !s.isDone() && n == 0 { + continue + } + + break + } + + return +} + +func (s *syncedReader) isDone() bool { + return atomic.LoadUint32(&s.done) == 1 +} + +func (s *syncedReader) isBlocked() bool { + return atomic.LoadUint32(&s.blocked) == 1 +} + +func (s *syncedReader) wake() { + if s.isBlocked() { + atomic.StoreUint32(&s.blocked, 0) + s.news <- true + } +} + +func (s *syncedReader) sleep() { + read := atomic.LoadUint64(&s.read) + written := atomic.LoadUint64(&s.written) + if read >= written { + atomic.StoreUint32(&s.blocked, 1) + <-s.news + } + +} + +func (s *syncedReader) Seek(offset int64, whence int) (int64, error) { + if whence == io.SeekCurrent { + return s.r.Seek(offset, whence) + } + + p, err := s.r.Seek(offset, whence) + atomic.StoreUint64(&s.read, uint64(p)) + + return p, err +} + +func (s *syncedReader) Close() error { + atomic.StoreUint32(&s.done, 1) + close(s.news) + return nil +} + +type ObjectWriter struct { + objfile.Writer + fs billy.Filesystem + f billy.File +} + +func newObjectWriter(fs billy.Filesystem) (*ObjectWriter, error) { + f, err := fs.TempFile(fs.Join(objectsPath, packPath), "tmp_obj_") + if err != nil { + return nil, err + } + + return &ObjectWriter{ + Writer: (*objfile.NewWriter(f)), + fs: fs, + f: f, + }, nil +} + +func (w *ObjectWriter) Close() error { + if err := w.Writer.Close(); err != nil { + return err + } + + if err := w.f.Close(); err != nil { + return err + } + + return w.save() +} + +func (w *ObjectWriter) save() error { + hash := w.Hash().String() + file := w.fs.Join(objectsPath, hash[0:2], hash[2:40]) + + return w.fs.Rename(w.f.Name(), file) +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/index.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/index.go new file mode 100644 index 00000000..672d64da --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/index.go @@ -0,0 +1,54 @@ +package filesystem + +import ( + "bufio" + "os" + + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +type IndexStorage struct { + dir *dotgit.DotGit +} + +func (s *IndexStorage) SetIndex(idx *index.Index) (err error) { + f, err := s.dir.IndexWriter() + if err != nil { + return err + } + + defer ioutil.CheckClose(f, &err) + bw := bufio.NewWriter(f) + defer func() { + if e := bw.Flush(); err == nil && e != nil { + err = e + } + }() + + e := index.NewEncoder(bw) + err = e.Encode(idx) + return err +} + +func (s *IndexStorage) Index() (i *index.Index, err error) { + idx := &index.Index{ + Version: 2, + } + + f, err := s.dir.Index() + if err != nil { + if os.IsNotExist(err) { + return idx, nil + } + + return nil, err + } + + defer ioutil.CheckClose(f, &err) + + d := index.NewDecoder(bufio.NewReader(f)) + err = d.Decode(idx) + return idx, err +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/module.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/module.go new file mode 100644 index 00000000..3284939e --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/module.go @@ -0,0 +1,20 @@ +package filesystem + +import ( + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/storage" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" +) + +type ModuleStorage struct { + dir *dotgit.DotGit +} + +func (s *ModuleStorage) Module(name string) (storage.Storer, error) { + fs, err := s.dir.Module(name) + if err != nil { + return nil, err + } + + return NewStorage(fs, cache.NewObjectLRUDefault()), nil +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/object.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/object.go new file mode 100644 index 00000000..a5b9e155 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/object.go @@ -0,0 +1,815 @@ +package filesystem + +import ( + "io" + "os" + "time" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/plumbing/format/idxfile" + "github.com/devtron-labs/go-git/plumbing/format/objfile" + "github.com/devtron-labs/go-git/plumbing/format/packfile" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" + "github.com/devtron-labs/go-git/utils/ioutil" + + "gopkg.in/src-d/go-billy.v4" +) + +type ObjectStorage struct { + options Options + + // objectCache is an object cache uses to cache delta's bases and also recently + // loaded loose objects + objectCache cache.Object + + dir *dotgit.DotGit + index map[plumbing.Hash]idxfile.Index + + packList []plumbing.Hash + packListIdx int + packfiles map[plumbing.Hash]*packfile.Packfile +} + +// NewObjectStorage creates a new ObjectStorage with the given .git directory and cache. +func NewObjectStorage(dir *dotgit.DotGit, objectCache cache.Object) *ObjectStorage { + return NewObjectStorageWithOptions(dir, objectCache, Options{}) +} + +// NewObjectStorageWithOptions creates a new ObjectStorage with the given .git directory, cache and extra options +func NewObjectStorageWithOptions(dir *dotgit.DotGit, objectCache cache.Object, ops Options) *ObjectStorage { + return &ObjectStorage{ + options: ops, + objectCache: objectCache, + dir: dir, + } +} + +func (s *ObjectStorage) requireIndex() error { + if s.index != nil { + return nil + } + + s.index = make(map[plumbing.Hash]idxfile.Index) + packs, err := s.dir.ObjectPacks() + if err != nil { + return err + } + + for _, h := range packs { + if err := s.loadIdxFile(h); err != nil { + return err + } + } + + return nil +} + +// Reindex indexes again all packfiles. Useful if git changed packfiles externally +func (s *ObjectStorage) Reindex() { + s.index = nil +} + +func (s *ObjectStorage) loadIdxFile(h plumbing.Hash) (err error) { + f, err := s.dir.ObjectPackIdx(h) + if err != nil { + return err + } + + defer ioutil.CheckClose(f, &err) + + idxf := idxfile.NewMemoryIndex() + d := idxfile.NewDecoder(f) + if err = d.Decode(idxf); err != nil { + return err + } + + s.index[h] = idxf + return err +} + +func (s *ObjectStorage) NewEncodedObject() plumbing.EncodedObject { + return &plumbing.MemoryObject{} +} + +func (s *ObjectStorage) PackfileWriter() (io.WriteCloser, error) { + if err := s.requireIndex(); err != nil { + return nil, err + } + + w, err := s.dir.NewObjectPack() + if err != nil { + return nil, err + } + + w.Notify = func(h plumbing.Hash, writer *idxfile.Writer) { + index, err := writer.Index() + if err == nil { + s.index[h] = index + } + } + + return w, nil +} + +// SetEncodedObject adds a new object to the storage. +func (s *ObjectStorage) SetEncodedObject(o plumbing.EncodedObject) (h plumbing.Hash, err error) { + if o.Type() == plumbing.OFSDeltaObject || o.Type() == plumbing.REFDeltaObject { + return plumbing.ZeroHash, plumbing.ErrInvalidType + } + + ow, err := s.dir.NewObject() + if err != nil { + return plumbing.ZeroHash, err + } + + defer ioutil.CheckClose(ow, &err) + + or, err := o.Reader() + if err != nil { + return plumbing.ZeroHash, err + } + + defer ioutil.CheckClose(or, &err) + + if err = ow.WriteHeader(o.Type(), o.Size()); err != nil { + return plumbing.ZeroHash, err + } + + if _, err = io.Copy(ow, or); err != nil { + return plumbing.ZeroHash, err + } + + return o.Hash(), err +} + +// HasEncodedObject returns nil if the object exists, without actually +// reading the object data from storage. +func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) { + // Check unpacked objects + f, err := s.dir.Object(h) + if err != nil { + if !os.IsNotExist(err) { + return err + } + // Fall through to check packed objects. + } else { + defer ioutil.CheckClose(f, &err) + return nil + } + + // Check packed objects. + if err := s.requireIndex(); err != nil { + return err + } + _, _, offset := s.findObjectInPackfile(h) + if offset == -1 { + return plumbing.ErrObjectNotFound + } + return nil +} + +func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) ( + size int64, err error) { + f, err := s.dir.Object(h) + if err != nil { + if os.IsNotExist(err) { + return 0, plumbing.ErrObjectNotFound + } + + return 0, err + } + + r, err := objfile.NewReader(f) + if err != nil { + return 0, err + } + defer ioutil.CheckClose(r, &err) + + _, size, err = r.Header() + return size, err +} + +func (s *ObjectStorage) packfile(idx idxfile.Index, pack plumbing.Hash) (*packfile.Packfile, error) { + if p := s.packfileFromCache(pack); p != nil { + return p, nil + } + + f, err := s.dir.ObjectPack(pack) + if err != nil { + return nil, err + } + + var p *packfile.Packfile + if s.objectCache != nil { + p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache) + } else { + p = packfile.NewPackfile(idx, s.dir.Fs(), f) + } + + return p, s.storePackfileInCache(pack, p) +} + +func (s *ObjectStorage) packfileFromCache(hash plumbing.Hash) *packfile.Packfile { + if s.packfiles == nil { + if s.options.KeepDescriptors { + s.packfiles = make(map[plumbing.Hash]*packfile.Packfile) + } else if s.options.MaxOpenDescriptors > 0 { + s.packList = make([]plumbing.Hash, s.options.MaxOpenDescriptors) + s.packfiles = make(map[plumbing.Hash]*packfile.Packfile, s.options.MaxOpenDescriptors) + } + } + + return s.packfiles[hash] +} + +func (s *ObjectStorage) storePackfileInCache(hash plumbing.Hash, p *packfile.Packfile) error { + if s.options.KeepDescriptors { + s.packfiles[hash] = p + return nil + } + + if s.options.MaxOpenDescriptors <= 0 { + return nil + } + + // start over as the limit of packList is hit + if s.packListIdx >= len(s.packList) { + s.packListIdx = 0 + } + + // close the existing packfile if open + if next := s.packList[s.packListIdx]; !next.IsZero() { + open := s.packfiles[next] + delete(s.packfiles, next) + if open != nil { + if err := open.Close(); err != nil { + return err + } + } + } + + // cache newly open packfile + s.packList[s.packListIdx] = hash + s.packfiles[hash] = p + s.packListIdx++ + + return nil +} + +func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) ( + size int64, err error) { + if err := s.requireIndex(); err != nil { + return 0, err + } + + pack, _, offset := s.findObjectInPackfile(h) + if offset == -1 { + return 0, plumbing.ErrObjectNotFound + } + + idx := s.index[pack] + hash, err := idx.FindHash(offset) + if err == nil { + obj, ok := s.objectCache.Get(hash) + if ok { + return obj.Size(), nil + } + } else if err != nil && err != plumbing.ErrObjectNotFound { + return 0, err + } + + p, err := s.packfile(idx, pack) + if err != nil { + return 0, err + } + + if !s.options.KeepDescriptors && s.options.MaxOpenDescriptors == 0 { + defer ioutil.CheckClose(p, &err) + } + + return p.GetSizeByOffset(offset) +} + +// EncodedObjectSize returns the plaintext size of the given object, +// without actually reading the full object data from storage. +func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) ( + size int64, err error) { + size, err = s.encodedObjectSizeFromUnpacked(h) + if err != nil && err != plumbing.ErrObjectNotFound { + return 0, err + } else if err == nil { + return size, nil + } + + return s.encodedObjectSizeFromPackfile(h) +} + +// EncodedObject returns the object with the given hash, by searching for it in +// the packfile and the git object directories. +func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) { + var obj plumbing.EncodedObject + var err error + + if s.index != nil { + obj, err = s.getFromPackfile(h, false) + if err == plumbing.ErrObjectNotFound { + obj, err = s.getFromUnpacked(h) + } + } else { + obj, err = s.getFromUnpacked(h) + if err == plumbing.ErrObjectNotFound { + obj, err = s.getFromPackfile(h, false) + } + } + + // If the error is still object not found, check if it's a shared object + // repository. + if err == plumbing.ErrObjectNotFound { + dotgits, e := s.dir.Alternates() + if e == nil { + // Create a new object storage with the DotGit(s) and check for the + // required hash object. Skip when not found. + for _, dg := range dotgits { + o := NewObjectStorage(dg, s.objectCache) + enobj, enerr := o.EncodedObject(t, h) + if enerr != nil { + continue + } + return enobj, nil + } + } + } + + if err != nil { + return nil, err + } + + if plumbing.AnyObject != t && obj.Type() != t { + return nil, plumbing.ErrObjectNotFound + } + + return obj, nil +} + +// DeltaObject returns the object with the given hash, by searching for +// it in the packfile and the git object directories. +func (s *ObjectStorage) DeltaObject(t plumbing.ObjectType, + h plumbing.Hash) (plumbing.EncodedObject, error) { + obj, err := s.getFromUnpacked(h) + if err == plumbing.ErrObjectNotFound { + obj, err = s.getFromPackfile(h, true) + } + + if err != nil { + return nil, err + } + + if plumbing.AnyObject != t && obj.Type() != t { + return nil, plumbing.ErrObjectNotFound + } + + return obj, nil +} + +func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedObject, err error) { + f, err := s.dir.Object(h) + if err != nil { + if os.IsNotExist(err) { + return nil, plumbing.ErrObjectNotFound + } + + return nil, err + } + defer ioutil.CheckClose(f, &err) + + if cacheObj, found := s.objectCache.Get(h); found { + return cacheObj, nil + } + + obj = s.NewEncodedObject() + r, err := objfile.NewReader(f) + if err != nil { + return nil, err + } + + defer ioutil.CheckClose(r, &err) + + t, size, err := r.Header() + if err != nil { + return nil, err + } + + obj.SetType(t) + obj.SetSize(size) + w, err := obj.Writer() + if err != nil { + return nil, err + } + + s.objectCache.Put(obj) + + _, err = io.Copy(w, r) + return obj, err +} + +// Get returns the object with the given hash, by searching for it in +// the packfile. +func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) ( + plumbing.EncodedObject, error) { + + if err := s.requireIndex(); err != nil { + return nil, err + } + + pack, hash, offset := s.findObjectInPackfile(h) + if offset == -1 { + return nil, plumbing.ErrObjectNotFound + } + + idx := s.index[pack] + p, err := s.packfile(idx, pack) + if err != nil { + return nil, err + } + + if !s.options.KeepDescriptors && s.options.MaxOpenDescriptors == 0 { + defer ioutil.CheckClose(p, &err) + } + + if canBeDelta { + return s.decodeDeltaObjectAt(p, offset, hash) + } + + return s.decodeObjectAt(p, offset) +} + +func (s *ObjectStorage) decodeObjectAt( + p *packfile.Packfile, + offset int64, +) (plumbing.EncodedObject, error) { + hash, err := p.FindHash(offset) + if err == nil { + obj, ok := s.objectCache.Get(hash) + if ok { + return obj, nil + } + } + + if err != nil && err != plumbing.ErrObjectNotFound { + return nil, err + } + + return p.GetByOffset(offset) +} + +func (s *ObjectStorage) decodeDeltaObjectAt( + p *packfile.Packfile, + offset int64, + hash plumbing.Hash, +) (plumbing.EncodedObject, error) { + scan := p.Scanner() + header, err := scan.SeekObjectHeader(offset) + if err != nil { + return nil, err + } + + var ( + base plumbing.Hash + ) + + switch header.Type { + case plumbing.REFDeltaObject: + base = header.Reference + case plumbing.OFSDeltaObject: + base, err = p.FindHash(header.OffsetReference) + if err != nil { + return nil, err + } + default: + return s.decodeObjectAt(p, offset) + } + + obj := &plumbing.MemoryObject{} + obj.SetType(header.Type) + w, err := obj.Writer() + if err != nil { + return nil, err + } + + if _, _, err := scan.NextObject(w); err != nil { + return nil, err + } + + return newDeltaObject(obj, hash, base, header.Length), nil +} + +func (s *ObjectStorage) findObjectInPackfile(h plumbing.Hash) (plumbing.Hash, plumbing.Hash, int64) { + for packfile, index := range s.index { + offset, err := index.FindOffset(h) + if err == nil { + return packfile, h, offset + } + } + + return plumbing.ZeroHash, plumbing.ZeroHash, -1 +} + +// IterEncodedObjects returns an iterator for all the objects in the packfile +// with the given type. +func (s *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) { + objects, err := s.dir.Objects() + if err != nil { + return nil, err + } + + seen := make(map[plumbing.Hash]struct{}) + var iters []storer.EncodedObjectIter + if len(objects) != 0 { + iters = append(iters, &objectsIter{s: s, t: t, h: objects}) + seen = hashListAsMap(objects) + } + + packi, err := s.buildPackfileIters(t, seen) + if err != nil { + return nil, err + } + + iters = append(iters, packi) + return storer.NewMultiEncodedObjectIter(iters), nil +} + +func (s *ObjectStorage) buildPackfileIters( + t plumbing.ObjectType, + seen map[plumbing.Hash]struct{}, +) (storer.EncodedObjectIter, error) { + if err := s.requireIndex(); err != nil { + return nil, err + } + + packs, err := s.dir.ObjectPacks() + if err != nil { + return nil, err + } + return &lazyPackfilesIter{ + hashes: packs, + open: func(h plumbing.Hash) (storer.EncodedObjectIter, error) { + pack, err := s.dir.ObjectPack(h) + if err != nil { + return nil, err + } + return newPackfileIter( + s.dir.Fs(), pack, t, seen, s.index[h], + s.objectCache, s.options.KeepDescriptors, + ) + }, + }, nil +} + +// Close closes all opened files. +func (s *ObjectStorage) Close() error { + var firstError error + if s.options.KeepDescriptors || s.options.MaxOpenDescriptors > 0 { + for _, packfile := range s.packfiles { + err := packfile.Close() + if firstError == nil && err != nil { + firstError = err + } + } + } + + s.packfiles = nil + s.dir.Close() + + return firstError +} + +type lazyPackfilesIter struct { + hashes []plumbing.Hash + open func(h plumbing.Hash) (storer.EncodedObjectIter, error) + cur storer.EncodedObjectIter +} + +func (it *lazyPackfilesIter) Next() (plumbing.EncodedObject, error) { + for { + if it.cur == nil { + if len(it.hashes) == 0 { + return nil, io.EOF + } + h := it.hashes[0] + it.hashes = it.hashes[1:] + + sub, err := it.open(h) + if err == io.EOF { + continue + } else if err != nil { + return nil, err + } + it.cur = sub + } + ob, err := it.cur.Next() + if err == io.EOF { + it.cur.Close() + it.cur = nil + continue + } else if err != nil { + return nil, err + } + return ob, nil + } +} + +func (it *lazyPackfilesIter) ForEach(cb func(plumbing.EncodedObject) error) error { + return storer.ForEachIterator(it, cb) +} + +func (it *lazyPackfilesIter) Close() { + if it.cur != nil { + it.cur.Close() + it.cur = nil + } + it.hashes = nil +} + +type packfileIter struct { + pack billy.File + iter storer.EncodedObjectIter + seen map[plumbing.Hash]struct{} + + // tells whether the pack file should be left open after iteration or not + keepPack bool +} + +// NewPackfileIter returns a new EncodedObjectIter for the provided packfile +// and object type. Packfile and index file will be closed after they're +// used. If keepPack is true the packfile won't be closed after the iteration +// finished. +func NewPackfileIter( + fs billy.Filesystem, + f billy.File, + idxFile billy.File, + t plumbing.ObjectType, + keepPack bool, +) (storer.EncodedObjectIter, error) { + idx := idxfile.NewMemoryIndex() + if err := idxfile.NewDecoder(idxFile).Decode(idx); err != nil { + return nil, err + } + + if err := idxFile.Close(); err != nil { + return nil, err + } + + seen := make(map[plumbing.Hash]struct{}) + return newPackfileIter(fs, f, t, seen, idx, nil, keepPack) +} + +func newPackfileIter( + fs billy.Filesystem, + f billy.File, + t plumbing.ObjectType, + seen map[plumbing.Hash]struct{}, + index idxfile.Index, + cache cache.Object, + keepPack bool, +) (storer.EncodedObjectIter, error) { + var p *packfile.Packfile + if cache != nil { + p = packfile.NewPackfileWithCache(index, fs, f, cache) + } else { + p = packfile.NewPackfile(index, fs, f) + } + + iter, err := p.GetByType(t) + if err != nil { + return nil, err + } + + return &packfileIter{ + pack: f, + iter: iter, + seen: seen, + keepPack: keepPack, + }, nil +} + +func (iter *packfileIter) Next() (plumbing.EncodedObject, error) { + for { + obj, err := iter.iter.Next() + if err != nil { + return nil, err + } + + if _, ok := iter.seen[obj.Hash()]; ok { + continue + } + + return obj, nil + } +} + +func (iter *packfileIter) ForEach(cb func(plumbing.EncodedObject) error) error { + for { + o, err := iter.Next() + if err != nil { + if err == io.EOF { + iter.Close() + return nil + } + return err + } + + if err := cb(o); err != nil { + return err + } + } +} + +func (iter *packfileIter) Close() { + iter.iter.Close() + if !iter.keepPack { + _ = iter.pack.Close() + } +} + +type objectsIter struct { + s *ObjectStorage + t plumbing.ObjectType + h []plumbing.Hash +} + +func (iter *objectsIter) Next() (plumbing.EncodedObject, error) { + if len(iter.h) == 0 { + return nil, io.EOF + } + + obj, err := iter.s.getFromUnpacked(iter.h[0]) + iter.h = iter.h[1:] + + if err != nil { + return nil, err + } + + if iter.t != plumbing.AnyObject && iter.t != obj.Type() { + return iter.Next() + } + + return obj, err +} + +func (iter *objectsIter) ForEach(cb func(plumbing.EncodedObject) error) error { + for { + o, err := iter.Next() + if err != nil { + if err == io.EOF { + return nil + } + return err + } + + if err := cb(o); err != nil { + return err + } + } +} + +func (iter *objectsIter) Close() { + iter.h = []plumbing.Hash{} +} + +func hashListAsMap(l []plumbing.Hash) map[plumbing.Hash]struct{} { + m := make(map[plumbing.Hash]struct{}, len(l)) + for _, h := range l { + m[h] = struct{}{} + } + return m +} + +func (s *ObjectStorage) ForEachObjectHash(fun func(plumbing.Hash) error) error { + err := s.dir.ForEachObjectHash(fun) + if err == storer.ErrStop { + return nil + } + return err +} + +func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) { + fi, err := s.dir.ObjectStat(hash) + if err != nil { + return time.Time{}, err + } + return fi.ModTime(), nil +} + +func (s *ObjectStorage) DeleteLooseObject(hash plumbing.Hash) error { + return s.dir.ObjectDelete(hash) +} + +func (s *ObjectStorage) ObjectPacks() ([]plumbing.Hash, error) { + return s.dir.ObjectPacks() +} + +func (s *ObjectStorage) DeleteOldObjectPackAndIndex(h plumbing.Hash, t time.Time) error { + return s.dir.DeleteOldObjectPackAndIndex(h, t) +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/reference.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/reference.go new file mode 100644 index 00000000..eba06faf --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/reference.go @@ -0,0 +1,44 @@ +package filesystem + +import ( + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/storer" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" +) + +type ReferenceStorage struct { + dir *dotgit.DotGit +} + +func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error { + return r.dir.SetRef(ref, nil) +} + +func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error { + return r.dir.SetRef(ref, old) +} + +func (r *ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) { + return r.dir.Ref(n) +} + +func (r *ReferenceStorage) IterReferences() (storer.ReferenceIter, error) { + refs, err := r.dir.Refs() + if err != nil { + return nil, err + } + + return storer.NewReferenceSliceIter(refs), nil +} + +func (r *ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error { + return r.dir.RemoveRef(n) +} + +func (r *ReferenceStorage) CountLooseRefs() (int, error) { + return r.dir.CountLooseRefs() +} + +func (r *ReferenceStorage) PackRefs() error { + return r.dir.PackRefs() +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/shallow.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/shallow.go new file mode 100644 index 00000000..a7335d65 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/shallow.go @@ -0,0 +1,54 @@ +package filesystem + +import ( + "bufio" + "fmt" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" + "github.com/devtron-labs/go-git/utils/ioutil" +) + +// ShallowStorage where the shallow commits are stored, an internal to +// manipulate the shallow file +type ShallowStorage struct { + dir *dotgit.DotGit +} + +// SetShallow save the shallows in the shallow file in the .git folder as one +// commit per line represented by 40-byte hexadecimal object terminated by a +// newline. +func (s *ShallowStorage) SetShallow(commits []plumbing.Hash) error { + f, err := s.dir.ShallowWriter() + if err != nil { + return err + } + + defer ioutil.CheckClose(f, &err) + for _, h := range commits { + if _, err := fmt.Fprintf(f, "%s\n", h); err != nil { + return err + } + } + + return err +} + +// Shallow return the shallow commits reading from shallo file from .git +func (s *ShallowStorage) Shallow() ([]plumbing.Hash, error) { + f, err := s.dir.Shallow() + if f == nil || err != nil { + return nil, err + } + + defer ioutil.CheckClose(f, &err) + + var hash []plumbing.Hash + + scn := bufio.NewScanner(f) + for scn.Scan() { + hash = append(hash, plumbing.NewHash(scn.Text())) + } + + return hash, scn.Err() +} diff --git a/vendor/github.com/devtron-labs/go-git/storage/filesystem/storage.go b/vendor/github.com/devtron-labs/go-git/storage/filesystem/storage.go new file mode 100644 index 00000000..26a78d42 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/storage/filesystem/storage.go @@ -0,0 +1,73 @@ +// Package filesystem is a storage backend base on filesystems +package filesystem + +import ( + "github.com/devtron-labs/go-git/plumbing/cache" + "github.com/devtron-labs/go-git/storage/filesystem/dotgit" + + "gopkg.in/src-d/go-billy.v4" +) + +// Storage is an implementation of git.Storer that stores data on disk in the +// standard git format (this is, the .git directory). Zero values of this type +// are not safe to use, see the NewStorage function below. +type Storage struct { + fs billy.Filesystem + dir *dotgit.DotGit + + ObjectStorage + ReferenceStorage + IndexStorage + ShallowStorage + ConfigStorage + ModuleStorage +} + +// Options holds configuration for the storage. +type Options struct { + // ExclusiveAccess means that the filesystem is not modified externally + // while the repo is open. + ExclusiveAccess bool + // KeepDescriptors makes the file descriptors to be reused but they will + // need to be manually closed calling Close(). + KeepDescriptors bool + // MaxOpenDescriptors is the max number of file descriptors to keep + // open. If KeepDescriptors is true, all file descriptors will remain open. + MaxOpenDescriptors int +} + +// NewStorage returns a new Storage backed by a given `fs.Filesystem` and cache. +func NewStorage(fs billy.Filesystem, cache cache.Object) *Storage { + return NewStorageWithOptions(fs, cache, Options{}) +} + +// NewStorageWithOptions returns a new Storage with extra options, +// backed by a given `fs.Filesystem` and cache. +func NewStorageWithOptions(fs billy.Filesystem, cache cache.Object, ops Options) *Storage { + dirOps := dotgit.Options{ + ExclusiveAccess: ops.ExclusiveAccess, + } + dir := dotgit.NewWithOptions(fs, dirOps) + + return &Storage{ + fs: fs, + dir: dir, + + ObjectStorage: *NewObjectStorageWithOptions(dir, cache, ops), + ReferenceStorage: ReferenceStorage{dir: dir}, + IndexStorage: IndexStorage{dir: dir}, + ShallowStorage: ShallowStorage{dir: dir}, + ConfigStorage: ConfigStorage{dir: dir}, + ModuleStorage: ModuleStorage{dir: dir}, + } +} + +// Filesystem returns the underlying filesystem +func (s *Storage) Filesystem() billy.Filesystem { + return s.fs +} + +// Init initializes .git directory +func (s *Storage) Init() error { + return s.dir.Initialize() +} diff --git a/vendor/github.com/devtron-labs/go-git/submodule_test.go b/vendor/github.com/devtron-labs/go-git/submodule_test.go deleted file mode 100644 index c73ae6ee..00000000 --- a/vendor/github.com/devtron-labs/go-git/submodule_test.go +++ /dev/null @@ -1,236 +0,0 @@ -package git - -import ( - "context" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/devtron-labs/go-git/plumbing" - - "github.com/devtron-labs/go-git-fixtures" - . "gopkg.in/check.v1" -) - -type SubmoduleSuite struct { - BaseSuite - Worktree *Worktree - path string -} - -var _ = Suite(&SubmoduleSuite{}) - -func (s *SubmoduleSuite) SetUpTest(c *C) { - path := fixtures.ByTag("submodule").One().Worktree().Root() - - dir, err := ioutil.TempDir("", "submodule") - c.Assert(err, IsNil) - - r, err := PlainClone(filepath.Join(dir, "worktree"), false, &CloneOptions{ - URL: path, - }) - - c.Assert(err, IsNil) - - s.Repository = r - s.Worktree, err = r.Worktree() - c.Assert(err, IsNil) - - s.path = dir -} - -func (s *SubmoduleSuite) TearDownTest(c *C) { - err := os.RemoveAll(s.path) - c.Assert(err, IsNil) -} - -func (s *SubmoduleSuite) TestInit(c *C) { - sm, err := s.Worktree.Submodule("basic") - c.Assert(err, IsNil) - - c.Assert(sm.initialized, Equals, false) - err = sm.Init() - c.Assert(err, IsNil) - - c.Assert(sm.initialized, Equals, true) - - cfg, err := s.Repository.Config() - c.Assert(err, IsNil) - - c.Assert(cfg.Submodules, HasLen, 1) - c.Assert(cfg.Submodules["basic"], NotNil) - - status, err := sm.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, false) -} - -func (s *SubmoduleSuite) TestUpdate(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - sm, err := s.Worktree.Submodule("basic") - c.Assert(err, IsNil) - - err = sm.Update(&SubmoduleUpdateOptions{ - Init: true, - }) - - c.Assert(err, IsNil) - - r, err := sm.Repository() - c.Assert(err, IsNil) - - ref, err := r.Reference(plumbing.HEAD, true) - c.Assert(err, IsNil) - c.Assert(ref.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - status, err := sm.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *SubmoduleSuite) TestRepositoryWithoutInit(c *C) { - sm, err := s.Worktree.Submodule("basic") - c.Assert(err, IsNil) - - r, err := sm.Repository() - c.Assert(err, Equals, ErrSubmoduleNotInitialized) - c.Assert(r, IsNil) -} - -func (s *SubmoduleSuite) TestUpdateWithoutInit(c *C) { - sm, err := s.Worktree.Submodule("basic") - c.Assert(err, IsNil) - - err = sm.Update(&SubmoduleUpdateOptions{}) - c.Assert(err, Equals, ErrSubmoduleNotInitialized) -} - -func (s *SubmoduleSuite) TestUpdateWithNotFetch(c *C) { - sm, err := s.Worktree.Submodule("basic") - c.Assert(err, IsNil) - - err = sm.Update(&SubmoduleUpdateOptions{ - Init: true, - NoFetch: true, - }) - - // Since we are not fetching, the object is not there - c.Assert(err, Equals, plumbing.ErrObjectNotFound) -} - -func (s *SubmoduleSuite) TestUpdateWithRecursion(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - sm, err := s.Worktree.Submodule("itself") - c.Assert(err, IsNil) - - err = sm.Update(&SubmoduleUpdateOptions{ - Init: true, - RecurseSubmodules: 2, - }) - - c.Assert(err, IsNil) - - fs := s.Worktree.Filesystem - _, err = fs.Stat(fs.Join("itself", "basic", "LICENSE")) - c.Assert(err, IsNil) -} - -func (s *SubmoduleSuite) TestUpdateWithInitAndUpdate(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - sm, err := s.Worktree.Submodule("basic") - c.Assert(err, IsNil) - - err = sm.Update(&SubmoduleUpdateOptions{ - Init: true, - }) - c.Assert(err, IsNil) - - idx, err := s.Repository.Storer.Index() - c.Assert(err, IsNil) - - for i, e := range idx.Entries { - if e.Name == "basic" { - e.Hash = plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d") - } - - idx.Entries[i] = e - } - - err = s.Repository.Storer.SetIndex(idx) - c.Assert(err, IsNil) - - err = sm.Update(&SubmoduleUpdateOptions{}) - c.Assert(err, IsNil) - - r, err := sm.Repository() - c.Assert(err, IsNil) - - ref, err := r.Reference(plumbing.HEAD, true) - c.Assert(err, IsNil) - c.Assert(ref.Hash().String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d") - -} - -func (s *SubmoduleSuite) TestSubmodulesInit(c *C) { - sm, err := s.Worktree.Submodules() - c.Assert(err, IsNil) - - err = sm.Init() - c.Assert(err, IsNil) - - sm, err = s.Worktree.Submodules() - c.Assert(err, IsNil) - - for _, m := range sm { - c.Assert(m.initialized, Equals, true) - } -} - -func (s *SubmoduleSuite) TestGitSubmodulesSymlink(c *C) { - f, err := s.Worktree.Filesystem.Create("badfile") - c.Assert(err, IsNil) - defer f.Close() - - err = s.Worktree.Filesystem.Remove(gitmodulesFile) - c.Assert(err, IsNil) - - err = s.Worktree.Filesystem.Symlink("badfile", gitmodulesFile) - c.Assert(err, IsNil) - - _, err = s.Worktree.Submodules() - c.Assert(err, Equals, ErrGitModulesSymlink) -} - -func (s *SubmoduleSuite) TestSubmodulesStatus(c *C) { - sm, err := s.Worktree.Submodules() - c.Assert(err, IsNil) - - status, err := sm.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 2) -} - -func (s *SubmoduleSuite) TestSubmodulesUpdateContext(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - sm, err := s.Worktree.Submodules() - c.Assert(err, IsNil) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - err = sm.UpdateContext(ctx, &SubmoduleUpdateOptions{Init: true}) - c.Assert(err, NotNil) -} diff --git a/vendor/github.com/devtron-labs/go-git/utils/merkletrie/filesystem/node.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/filesystem/node.go new file mode 100644 index 00000000..eb3492c8 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/filesystem/node.go @@ -0,0 +1,196 @@ +package filesystem + +import ( + "io" + "os" + "path" + + "github.com/devtron-labs/go-git/plumbing" + "github.com/devtron-labs/go-git/plumbing/filemode" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" + + "gopkg.in/src-d/go-billy.v4" +) + +var ignore = map[string]bool{ + ".git": true, +} + +// The node represents a file or a directory in a billy.Filesystem. It +// implements the interface noder.Noder of merkletrie package. +// +// This implementation implements a "standard" hash method being able to be +// compared with any other noder.Noder implementation inside of go-git. +type node struct { + fs billy.Filesystem + submodules map[string]plumbing.Hash + + path string + hash []byte + children []noder.Noder + isDir bool +} + +// NewRootNode returns the root node based on a given billy.Filesystem. +// +// In order to provide the submodule hash status, a map[string]plumbing.Hash +// should be provided where the key is the path of the submodule and the commit +// of the submodule HEAD +func NewRootNode( + fs billy.Filesystem, + submodules map[string]plumbing.Hash, +) noder.Noder { + return &node{fs: fs, submodules: submodules, isDir: true} +} + +// Hash the hash of a filesystem is the result of concatenating the computed +// plumbing.Hash of the file as a Blob and its plumbing.FileMode; that way the +// difftree algorithm will detect changes in the contents of files and also in +// their mode. +// +// The hash of a directory is always a 24-bytes slice of zero values +func (n *node) Hash() []byte { + return n.hash +} + +func (n *node) Name() string { + return path.Base(n.path) +} + +func (n *node) IsDir() bool { + return n.isDir +} + +func (n *node) Children() ([]noder.Noder, error) { + if err := n.calculateChildren(); err != nil { + return nil, err + } + + return n.children, nil +} + +func (n *node) NumChildren() (int, error) { + if err := n.calculateChildren(); err != nil { + return -1, err + } + + return len(n.children), nil +} + +func (n *node) calculateChildren() error { + if !n.IsDir() { + return nil + } + + if len(n.children) != 0 { + return nil + } + + files, err := n.fs.ReadDir(n.path) + if err != nil { + if os.IsNotExist(err) { + return nil + } + + return nil + } + + for _, file := range files { + if _, ok := ignore[file.Name()]; ok { + continue + } + + c, err := n.newChildNode(file) + if err != nil { + return err + } + + n.children = append(n.children, c) + } + + return nil +} + +func (n *node) newChildNode(file os.FileInfo) (*node, error) { + path := path.Join(n.path, file.Name()) + + hash, err := n.calculateHash(path, file) + if err != nil { + return nil, err + } + + node := &node{ + fs: n.fs, + submodules: n.submodules, + + path: path, + hash: hash, + isDir: file.IsDir(), + } + + if hash, isSubmodule := n.submodules[path]; isSubmodule { + node.hash = append(hash[:], filemode.Submodule.Bytes()...) + node.isDir = false + } + + return node, nil +} + +func (n *node) calculateHash(path string, file os.FileInfo) ([]byte, error) { + if file.IsDir() { + return make([]byte, 24), nil + } + + var hash plumbing.Hash + var err error + if file.Mode()&os.ModeSymlink != 0 { + hash, err = n.doCalculateHashForSymlink(path, file) + } else { + hash, err = n.doCalculateHashForRegular(path, file) + } + + if err != nil { + return nil, err + } + + mode, err := filemode.NewFromOSFileMode(file.Mode()) + if err != nil { + return nil, err + } + + return append(hash[:], mode.Bytes()...), nil +} + +func (n *node) doCalculateHashForRegular(path string, file os.FileInfo) (plumbing.Hash, error) { + f, err := n.fs.Open(path) + if err != nil { + return plumbing.ZeroHash, err + } + + defer f.Close() + + h := plumbing.NewHasher(plumbing.BlobObject, file.Size()) + if _, err := io.Copy(h, f); err != nil { + return plumbing.ZeroHash, err + } + + return h.Sum(), nil +} + +func (n *node) doCalculateHashForSymlink(path string, file os.FileInfo) (plumbing.Hash, error) { + target, err := n.fs.Readlink(path) + if err != nil { + return plumbing.ZeroHash, err + } + + h := plumbing.NewHasher(plumbing.BlobObject, file.Size()) + if _, err := h.Write([]byte(target)); err != nil { + return plumbing.ZeroHash, err + } + + return h.Sum(), nil +} + +func (n *node) String() string { + return n.path +} diff --git a/vendor/github.com/devtron-labs/go-git/utils/merkletrie/index/node.go b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/index/node.go new file mode 100644 index 00000000..4d4ce343 --- /dev/null +++ b/vendor/github.com/devtron-labs/go-git/utils/merkletrie/index/node.go @@ -0,0 +1,90 @@ +package index + +import ( + "path" + "strings" + + "github.com/devtron-labs/go-git/plumbing/format/index" + "github.com/devtron-labs/go-git/utils/merkletrie/noder" +) + +// The node represents a index.Entry or a directory inferred from the path +// of all entries. It implements the interface noder.Noder of merkletrie +// package. +// +// This implementation implements a "standard" hash method being able to be +// compared with any other noder.Noder implementation inside of go-git +type node struct { + path string + entry *index.Entry + children []noder.Noder + isDir bool +} + +// NewRootNode returns the root node of a computed tree from a index.Index, +func NewRootNode(idx *index.Index) noder.Noder { + const rootNode = "" + + m := map[string]*node{rootNode: {isDir: true}} + + for _, e := range idx.Entries { + parts := strings.Split(e.Name, string("/")) + + var fullpath string + for _, part := range parts { + parent := fullpath + fullpath = path.Join(fullpath, part) + + if _, ok := m[fullpath]; ok { + continue + } + + n := &node{path: fullpath} + if fullpath == e.Name { + n.entry = e + } else { + n.isDir = true + } + + m[n.path] = n + m[parent].children = append(m[parent].children, n) + } + } + + return m[rootNode] +} + +func (n *node) String() string { + return n.path +} + +// Hash the hash of a filesystem is a 24-byte slice, is the result of +// concatenating the computed plumbing.Hash of the file as a Blob and its +// plumbing.FileMode; that way the difftree algorithm will detect changes in the +// contents of files and also in their mode. +// +// If the node is computed and not based on a index.Entry the hash is equals +// to a 24-bytes slices of zero values. +func (n *node) Hash() []byte { + if n.entry == nil { + return make([]byte, 24) + } + + return append(n.entry.Hash[:], n.entry.Mode.Bytes()...) +} + +func (n *node) Name() string { + return path.Base(n.path) +} + +func (n *node) IsDir() bool { + return n.isDir +} + +func (n *node) Children() ([]noder.Noder, error) { + return n.children, nil +} + +func (n *node) NumChildren() (int, error) { + return len(n.children), nil +} diff --git a/vendor/github.com/devtron-labs/go-git/worktree_commit_test.go b/vendor/github.com/devtron-labs/go-git/worktree_commit_test.go deleted file mode 100644 index 5be5c649..00000000 --- a/vendor/github.com/devtron-labs/go-git/worktree_commit_test.go +++ /dev/null @@ -1,369 +0,0 @@ -package git - -import ( - "bytes" - "io/ioutil" - "os" - "os/exec" - "strings" - "time" - - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/cache" - "github.com/devtron-labs/go-git/plumbing/object" - "github.com/devtron-labs/go-git/plumbing/storer" - "github.com/devtron-labs/go-git/storage/filesystem" - "github.com/devtron-labs/go-git/storage/memory" - - "golang.org/x/crypto/openpgp" - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-billy.v4/memfs" - "gopkg.in/src-d/go-billy.v4/osfs" - "gopkg.in/src-d/go-billy.v4/util" -) - -func (s *WorktreeSuite) TestCommitInvalidOptions(c *C) { - r, err := Init(memory.NewStorage(), memfs.New()) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - hash, err := w.Commit("", &CommitOptions{}) - c.Assert(err, Equals, ErrMissingAuthor) - c.Assert(hash.IsZero(), Equals, true) -} - -func (s *WorktreeSuite) TestCommitInitial(c *C) { - expected := plumbing.NewHash("98c4ac7c29c913f7461eae06e024dc18e80d23a4") - - fs := memfs.New() - storage := memory.NewStorage() - - r, err := Init(storage, fs) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - util.WriteFile(fs, "foo", []byte("foo"), 0644) - - _, err = w.Add("foo") - c.Assert(err, IsNil) - - hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) - c.Assert(hash, Equals, expected) - c.Assert(err, IsNil) - - assertStorageStatus(c, r, 1, 1, 1, expected) -} - -func (s *WorktreeSuite) TestCommitParent(c *C) { - expected := plumbing.NewHash("ef3ca05477530b37f48564be33ddd48063fc7a22") - - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - util.WriteFile(fs, "foo", []byte("foo"), 0644) - - _, err = w.Add("foo") - c.Assert(err, IsNil) - - hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) - c.Assert(hash, Equals, expected) - c.Assert(err, IsNil) - - assertStorageStatus(c, s.Repository, 13, 11, 10, expected) -} - -func (s *WorktreeSuite) TestCommitAll(c *C) { - expected := plumbing.NewHash("aede6f8c9c1c7ec9ca8d287c64b8ed151276fa28") - - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - util.WriteFile(fs, "LICENSE", []byte("foo"), 0644) - util.WriteFile(fs, "foo", []byte("foo"), 0644) - - hash, err := w.Commit("foo\n", &CommitOptions{ - All: true, - Author: defaultSignature(), - }) - - c.Assert(hash, Equals, expected) - c.Assert(err, IsNil) - - assertStorageStatus(c, s.Repository, 13, 11, 10, expected) -} - -func (s *WorktreeSuite) TestRemoveAndCommitAll(c *C) { - expected := plumbing.NewHash("907cd576c6ced2ecd3dab34a72bf9cf65944b9a9") - - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - util.WriteFile(fs, "foo", []byte("foo"), 0644) - _, err = w.Add("foo") - c.Assert(err, IsNil) - - _, errFirst := w.Commit("Add in Repo\n", &CommitOptions{ - Author: defaultSignature(), - }) - c.Assert(errFirst, IsNil) - - errRemove := fs.Remove("foo") - c.Assert(errRemove, IsNil) - - hash, errSecond := w.Commit("Remove foo\n", &CommitOptions{ - All: true, - Author: defaultSignature(), - }) - c.Assert(errSecond, IsNil) - - c.Assert(hash, Equals, expected) - c.Assert(err, IsNil) - - assertStorageStatus(c, s.Repository, 13, 11, 11, expected) -} - -func (s *WorktreeSuite) TestCommitSign(c *C) { - fs := memfs.New() - storage := memory.NewStorage() - - r, err := Init(storage, fs) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - util.WriteFile(fs, "foo", []byte("foo"), 0644) - - _, err = w.Add("foo") - c.Assert(err, IsNil) - - key := commitSignKey(c, true) - hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) - c.Assert(err, IsNil) - - // Verify the commit. - pks := new(bytes.Buffer) - pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) - c.Assert(err, IsNil) - - err = key.Serialize(pkw) - c.Assert(err, IsNil) - err = pkw.Close() - c.Assert(err, IsNil) - - expectedCommit, err := r.CommitObject(hash) - c.Assert(err, IsNil) - actual, err := expectedCommit.Verify(pks.String()) - c.Assert(err, IsNil) - c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) -} - -func (s *WorktreeSuite) TestCommitSignBadKey(c *C) { - fs := memfs.New() - storage := memory.NewStorage() - - r, err := Init(storage, fs) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - util.WriteFile(fs, "foo", []byte("foo"), 0644) - - _, err = w.Add("foo") - c.Assert(err, IsNil) - - key := commitSignKey(c, false) - _, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) - c.Assert(err, Equals, errors.InvalidArgumentError("signing key is encrypted")) -} - -func (s *WorktreeSuite) TestCommitTreeSort(c *C) { - path, err := ioutil.TempDir(os.TempDir(), "test-commit-tree-sort") - c.Assert(err, IsNil) - fs := osfs.New(path) - st := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) - r, err := Init(st, nil) - c.Assert(err, IsNil) - - r, _ = Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ - URL: path, - }) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - mfs := w.Filesystem - - err = mfs.MkdirAll("delta", 0755) - c.Assert(err, IsNil) - - for _, p := range []string{"delta_last", "Gamma", "delta/middle", "Beta", "delta-first", "alpha"} { - util.WriteFile(mfs, p, []byte("foo"), 0644) - _, err = w.Add(p) - c.Assert(err, IsNil) - } - - _, err = w.Commit("foo\n", &CommitOptions{ - All: true, - Author: defaultSignature(), - }) - c.Assert(err, IsNil) - - err = r.Push(&PushOptions{}) - c.Assert(err, IsNil) - - cmd := exec.Command("git", "fsck") - cmd.Dir = path - cmd.Env = os.Environ() - buf := &bytes.Buffer{} - cmd.Stderr = buf - cmd.Stdout = buf - - err = cmd.Run() - - c.Assert(err, IsNil, Commentf("%s", buf.Bytes())) -} - -func assertStorageStatus( - c *C, r *Repository, - treesCount, blobCount, commitCount int, head plumbing.Hash, -) { - trees, err := r.Storer.IterEncodedObjects(plumbing.TreeObject) - c.Assert(err, IsNil) - blobs, err := r.Storer.IterEncodedObjects(plumbing.BlobObject) - c.Assert(err, IsNil) - commits, err := r.Storer.IterEncodedObjects(plumbing.CommitObject) - c.Assert(err, IsNil) - - c.Assert(lenIterEncodedObjects(trees), Equals, treesCount) - c.Assert(lenIterEncodedObjects(blobs), Equals, blobCount) - c.Assert(lenIterEncodedObjects(commits), Equals, commitCount) - - ref, err := r.Head() - c.Assert(err, IsNil) - c.Assert(ref.Hash(), Equals, head) -} - -func lenIterEncodedObjects(iter storer.EncodedObjectIter) int { - count := 0 - iter.ForEach(func(plumbing.EncodedObject) error { - count++ - return nil - }) - - return count -} - -func defaultSignature() *object.Signature { - when, _ := time.Parse(object.DateFormat, "Thu May 04 00:03:43 2017 +0200") - return &object.Signature{ - Name: "foo", - Email: "foo@foo.foo", - When: when, - } -} - -func commitSignKey(c *C, decrypt bool) *openpgp.Entity { - s := strings.NewReader(armoredKeyRing) - es, err := openpgp.ReadArmoredKeyRing(s) - c.Assert(err, IsNil) - - c.Assert(es, HasLen, 1) - c.Assert(es[0].Identities, HasLen, 1) - _, ok := es[0].Identities["foo bar "] - c.Assert(ok, Equals, true) - - key := es[0] - if decrypt { - err = key.PrivateKey.Decrypt([]byte(keyPassphrase)) - c.Assert(err, IsNil) - } - - return key -} - -const armoredKeyRing = ` ------BEGIN PGP PRIVATE KEY BLOCK----- - -lQdGBFt89QIBEAC8du0Purt9yeFuLlBYHcexnZvcbaci2pY+Ejn1VnxM7caFxRX/ -b2weZi9E6+I0F+K/hKIaidPdcbK92UCL0Vp6F3izjqategZ7o44vlK/HfWFME4wv -sou6lnig9ovA73HRyzngi3CmqWxSdg8lL0kIJLNzlvCFEd4Z34BnEkagklQJRymo -0WnmLJjSnZFT5Nk7q5jrcR7ApbD98cakvgivDlUBPJCk2JFPWheCkouWPHMvLXQz -bZXW5RFz4lJsMUWa/S3ofvIOnjG5Etnil3IA4uksS8fSDkGus998mBvUwzqX7xBh -dK17ZEbxDdO4PuVJDkjvq618rMu8FVk5yVd59rUketSnGrehd/+vdh6qtgQC4tu1 -RldbUVAuKZGg79H61nWnvrDZmbw4eoqCEuv1+aZsM9ElSC5Ps2J0rtpHRyBndKn+ -8Jlc/KTH04/O+FAhEv0IgMTFEm3iAq8udBhRBgu6Y4gJyn4tqy6+6ZjPUNos8GOG -+ZJPdrgHHHfQged1ygeceN6W2AwQRet/B3/rieHf2V93uHJy/DjYUEuBhPm9nxqi -R6ILUr97Sj2EsvLyfQO9pFpIctoNKEJmDx/C9tkFMNNlQhpsBitSdR2/wancw9ND -iWV/J9roUdC0qns7eNSbiFe3Len8Xir7srnjAFgbGvOu9jDBUuiKGT5F3wARAQAB -/gcDAl+0SktmjrUW8uwpvru6GeIeo5kc4rXuD7iIxH6nDl3nmjZMX7qWvp+pRTHH -0hEDH44899PDvzclBN3ouehfFUbJ+DBy8umBiLqF8Mu2PrKjdmyv3BvnbTkqPM3m -2Su7WmUDBhG00X07lfl8fTpZJG80onEGzGynryP/xVm4ymzoHyYGksntXLYr2HJ5 -aV6L7sL2/STsaaOVHoa/oEmVBo1+NRsTxRRUcFVLs3g0OIi6ZCeSevBdavMwf9Iv -b5Bs/e0+GLpP71XzFpdrGcL6oGjZH/dgdeypzbGA+FHtQJqynN3qEE9eCc9cfTGL -2zN2OtnMA28NtPVN4SnSxQIDvycWx68NZjfwLOK+gswfKpimp+6xMWSnNIRDyU9M -w0hdNPMK9JAxm/MlnkR7x6ysX/8vrVVFl9gWOmxzJ5L4kvfMsHcV5ZFRP8OnVA6a -NFBWIBGXF1uQC4qrXup/xKyWJOoH++cMo2cjPT3+3oifZgdBydVfHXjS9aQ/S3Sa -A6henWyx/qeBGPVRuXWdXIOKDboOPK8JwQaGd6yazKkH9c5tDohmQHzZ6ho0gyAt -dh+g9ZyiZVpjc6excfK/DP/RdUOYKw3Ur9652hKephvYZzHvPjTbqVkhS7JjZkVY -rukQ64d5T0pE1B4y+If4hLFXMNQtfo0TIsATNA69jop+KFnJpLzAB+Ee33EA/HUl -YC5EJCJaXt6kdtYFac0HvVWiz5ZuMhdtzpJfvOe+Olp/xR9nIPW3XZojQoHIZKwu -gXeZeVMvfeoq+ymKAKNH5Np4WaUDF7Wh9VLl045jGyF5viyy61ivC0eyAzp5W1uy -gJBZwafVma5MhmZUS2dFs0hBwBrKRzZZhN65VvfSYw6CnXp83ryUjReDvrLmqZDM -FNpSMDKRk1+k9Wwi3m+fzLAvlxoHscJ5Any7ApsvBRbyehP8MAAG7UV3jImugTLi -yN6FKVwziQXiC4/97oKbA1YYNjTT7Qw9gWTXvLRspn4f9997brcA9dm0M0seTjLa -lc5hTJwJQdvPPI2klf+YgPvsD6nrP1moeWBb8irICqG1/BoE0JHPS+bqJ1J+m1iV -kRV/+4pV2bLlXKqg1LEvqANW+1P1eM2nbbVB7EQn8ZOPIKMoCLoC1QWUPNfnemsW -U5ynAbhsbm16PDJql0ApEgUCEDfsXTu1ui6SIO3bs/gWyD9HEmnfaYMYDKF+j+0r -jXd4GnCxb+Yu3wV5WyewOHouzC+++h/3WcDLkOYZ9pcIbA86qT+v6b9MuTAU0D3c -wlDv8r5J59zOcXl4HpMb2BY5F9dZn8hjgeVJRhJdij9x1TQ8qlVasSi4Eq8SiPmZ -PZz33Pk6yn2caQ6wd47A79LXCbFQqJqA5aA6oS4DOpENGS5fh7WUZq/MTcmm9GsG -w2gHxocASK9RCUYgZFWVYgLDuviMMWvc/2TJcTMxdF0Amu3erYAD90smFs0g/6fZ -4pRLnKFuifwAMGMOx7jbW5tmOaSPx6XkuYvkDJeLMHoN3z/8bZEG5VpayypwFGyV -bk/YIUWg/KM/43juDPdTvab9tZzYIjxC6on7dtYIAGjZis97XZou3KYKTaMe1VY6 -IhrnVzJ0JAHpd1prf9NUz96e1vjGdn3I61JgjNp5sWklIJEZzvaD28Eovf/LH1BO -gYFFCvsWXaRoPHNQ5a9m7CROkLeHUFgRu5uriqHxxQHgogDznc8/3fnvDAHNpNb6 -Jnk4zaeVR3tTyIjiNM+wxUFPDNFpJWmQbSDCcPVYTbpznzVRnhqrw7q0FWZvbyBi -YXIgPGZvb0Bmb28uZm9vPokCVAQTAQgAPgIbAwULCQgHAgYVCAkKCwIEFgIDAQIe -AQIXgBYhBJOhf/AeVDKFRgh8jgKTlUAu/M1TBQJbfPU4BQkSzAM2AAoJEAKTlUAu -/M1TVTIQALA6ocNc2fXz1loLykMxlfnX/XxiyNDOUPDZkrZtscqqWPYaWvJK3OiD -32bdVEbftnAiFvJYkinrCXLEmwwf5wyOxKFmCHwwKhH0UYt60yF4WwlOVNstGSAy -RkPMEEmVfMXS9K1nzKv/9A5YsqMQob7sN5CMN66Vrm0RKSvOF/NhhM9v8fC0QSU2 -GZNO0tnRfaS4wMnFr5L4FuDST+14F5sJT7ZEJz7HfbxXKLvvWbvqLlCYHJOdz56s -X/eKde8eT9/LSzcmgsd7rGS2np5901kubww5jllUl1CFnk3Mdg9FTJl5u9Epuhnn -823Jpdy1ZNbyLqZ266Z/q2HepDA7P/GqIXgWdHjwG2y1YAC4JIkA4RBbesQwqAXs -6cX5gqRFRl5iDGEP5zclS0y5mWi/J8bLYxMYfqxs9EZtHd9DumWISi87804TEzYa -WDijMlW7PR8QRW0vdmtYOhJZOlTnomLQx2v27iqpVXRh12J1aYVBFC+IvG1vhCf9 -FL3LzAHHEGlIoDaKJMd+Wg/Lm/f1PqqQx3lWIh9hhKh5Qx6hcuJH669JOWuEdxfo -1so50aItG+tdDKqXflmOi7grrUURchYYKteaW2fC2SQgzDClprALI7aj9s/lDrEN -CgLH6twOqdSFWqB/4ASDMsNeLeKX3WOYKYYMlE01cj3T1m6dpRUO -=gIM9 ------END PGP PRIVATE KEY BLOCK----- -` - -const keyPassphrase = "abcdef0123456789" diff --git a/vendor/github.com/devtron-labs/go-git/worktree_test.go b/vendor/github.com/devtron-labs/go-git/worktree_test.go deleted file mode 100644 index b4da7b75..00000000 --- a/vendor/github.com/devtron-labs/go-git/worktree_test.go +++ /dev/null @@ -1,2008 +0,0 @@ -package git - -import ( - "bytes" - "context" - "errors" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "runtime" - "testing" - "time" - - "github.com/devtron-labs/go-git/config" - "github.com/devtron-labs/go-git/plumbing" - "github.com/devtron-labs/go-git/plumbing/filemode" - "github.com/devtron-labs/go-git/plumbing/format/gitignore" - "github.com/devtron-labs/go-git/plumbing/format/index" - "github.com/devtron-labs/go-git/plumbing/object" - "github.com/devtron-labs/go-git/storage/memory" - - "github.com/devtron-labs/go-git-fixtures" - "golang.org/x/text/unicode/norm" - . "gopkg.in/check.v1" - "gopkg.in/src-d/go-billy.v4/memfs" - "gopkg.in/src-d/go-billy.v4/osfs" - "gopkg.in/src-d/go-billy.v4/util" -) - -type WorktreeSuite struct { - BaseSuite -} - -var _ = Suite(&WorktreeSuite{}) - -func (s *WorktreeSuite) SetUpTest(c *C) { - f := fixtures.Basic().One() - s.Repository = s.NewRepositoryWithEmptyWorktree(f) -} - -func (s *WorktreeSuite) TestPullCheckout(c *C) { - fs := memfs.New() - r, _ := Init(memory.NewStorage(), fs) - r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{}) - c.Assert(err, IsNil) - - fi, err := fs.ReadDir("") - c.Assert(err, IsNil) - c.Assert(fi, HasLen, 8) -} - -func (s *WorktreeSuite) TestPullFastForward(c *C) { - url := c.MkDir() - path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() - - server, err := PlainClone(url, false, &CloneOptions{ - URL: path, - }) - c.Assert(err, IsNil) - - r, err := PlainClone(c.MkDir(), false, &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - w, err := server.Worktree() - c.Assert(err, IsNil) - err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) - c.Assert(err, IsNil) - hash, err := w.Commit("foo", &CommitOptions{Author: defaultSignature()}) - c.Assert(err, IsNil) - - w, err = r.Worktree() - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{}) - c.Assert(err, IsNil) - - head, err := r.Head() - c.Assert(err, IsNil) - c.Assert(head.Hash(), Equals, hash) -} - -func (s *WorktreeSuite) TestPullNonFastForward(c *C) { - url := c.MkDir() - path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() - - server, err := PlainClone(url, false, &CloneOptions{ - URL: path, - }) - c.Assert(err, IsNil) - - r, err := PlainClone(c.MkDir(), false, &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - w, err := server.Worktree() - c.Assert(err, IsNil) - err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) - c.Assert(err, IsNil) - _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) - c.Assert(err, IsNil) - - w, err = r.Worktree() - c.Assert(err, IsNil) - err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755) - c.Assert(err, IsNil) - _, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()}) - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{}) - c.Assert(err, Equals, ErrNonFastForwardUpdate) -} - -func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) { - r, _ := Init(memory.NewStorage(), memfs.New()) - r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - err := r.Fetch(&FetchOptions{}) - c.Assert(err, IsNil) - - _, err = r.Reference("refs/heads/master", false) - c.Assert(err, NotNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{}) - c.Assert(err, IsNil) - - head, err := r.Reference(plumbing.HEAD, true) - c.Assert(err, IsNil) - c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - branch, err := r.Reference("refs/heads/master", false) - c.Assert(err, IsNil) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - err = w.Pull(&PullOptions{}) - c.Assert(err, Equals, NoErrAlreadyUpToDate) -} - -func (s *WorktreeSuite) TestPullInSingleBranch(c *C) { - r, _ := Init(memory.NewStorage(), memfs.New()) - err := r.clone(context.Background(), &CloneOptions{ - URL: s.GetBasicLocalRepositoryURL(), - SingleBranch: true, - }) - - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{}) - c.Assert(err, Equals, NoErrAlreadyUpToDate) - - branch, err := r.Reference("refs/heads/master", false) - c.Assert(err, IsNil) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - branch, err = r.Reference("refs/remotes/foo/branch", false) - c.Assert(err, NotNil) - - storage := r.Storer.(*memory.Storage) - c.Assert(storage.Objects, HasLen, 28) -} - -func (s *WorktreeSuite) TestPullProgress(c *C) { - r, _ := Init(memory.NewStorage(), memfs.New()) - - r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{s.GetBasicLocalRepositoryURL()}, - }) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - buf := bytes.NewBuffer(nil) - err = w.Pull(&PullOptions{ - Progress: buf, - }) - - c.Assert(err, IsNil) - c.Assert(buf.Len(), Not(Equals), 0) -} - -func (s *WorktreeSuite) TestPullProgressWithRecursion(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - path := fixtures.ByTag("submodule").One().Worktree().Root() - - dir, err := ioutil.TempDir("", "plain-clone-submodule") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, _ := PlainInit(dir, false) - r.CreateRemote(&config.RemoteConfig{ - Name: DefaultRemoteName, - URLs: []string{path}, - }) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{ - RecurseSubmodules: DefaultSubmoduleRecursionDepth, - }) - c.Assert(err, IsNil) - - cfg, err := r.Config() - c.Assert(err, IsNil) - c.Assert(cfg.Submodules, HasLen, 2) -} - -func (s *RepositorySuite) TestPullAdd(c *C) { - path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() - - r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ - URL: filepath.Join(path, ".git"), - }) - - c.Assert(err, IsNil) - - storage := r.Storer.(*memory.Storage) - c.Assert(storage.Objects, HasLen, 28) - - branch, err := r.Reference("refs/heads/master", false) - c.Assert(err, IsNil) - c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") - - ExecuteOnPath(c, path, - "touch foo", - "git add foo", - "git commit -m foo foo", - ) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Pull(&PullOptions{RemoteName: "origin"}) - c.Assert(err, IsNil) - - // the commit command has introduced a new commit, tree and blob - c.Assert(storage.Objects, HasLen, 31) - - branch, err = r.Reference("refs/heads/master", false) - c.Assert(err, IsNil) - c.Assert(branch.Hash().String(), Not(Equals), "6ecf0ef2c2dffb796033e5a02219af86ec6584e5") -} - -func (s *WorktreeSuite) TestCheckout(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{ - Force: true, - }) - c.Assert(err, IsNil) - - entries, err := fs.ReadDir("/") - c.Assert(err, IsNil) - - c.Assert(entries, HasLen, 8) - ch, err := fs.Open("CHANGELOG") - c.Assert(err, IsNil) - - content, err := ioutil.ReadAll(ch) - c.Assert(err, IsNil) - c.Assert(string(content), Equals, "Initial changelog\n") - - idx, err := s.Repository.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) -} - -func (s *WorktreeSuite) TestCheckoutForce(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - w.Filesystem = memfs.New() - - err = w.Checkout(&CheckoutOptions{ - Force: true, - }) - c.Assert(err, IsNil) - - entries, err := w.Filesystem.ReadDir("/") - c.Assert(err, IsNil) - c.Assert(entries, HasLen, 8) -} - -func (s *WorktreeSuite) TestCheckoutKeep(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{ - Force: true, - }) - c.Assert(err, IsNil) - - // Create a new branch and create a new file. - err = w.Checkout(&CheckoutOptions{ - Branch: plumbing.NewBranchReferenceName("new-branch"), - Create: true, - }) - c.Assert(err, IsNil) - - w.Filesystem = memfs.New() - f, err := w.Filesystem.Create("new-file.txt") - c.Assert(err, IsNil) - _, err = f.Write([]byte("DUMMY")) - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - // Add the file to staging. - _, err = w.Add("new-file.txt") - c.Assert(err, IsNil) - - // Switch branch to master, and verify that the new file was kept in staging. - err = w.Checkout(&CheckoutOptions{ - Keep: true, - }) - c.Assert(err, IsNil) - - fi, err := w.Filesystem.Stat("new-file.txt") - c.Assert(err, IsNil) - c.Assert(fi.Size(), Equals, int64(5)) -} - -func (s *WorktreeSuite) TestCheckoutSymlink(c *C) { - if runtime.GOOS == "windows" { - c.Skip("git doesn't support symlinks by default in windows") - } - - dir, err := ioutil.TempDir("", "checkout") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, false) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - w.Filesystem.Symlink("not-exists", "bar") - w.Add("bar") - w.Commit("foo", &CommitOptions{Author: defaultSignature()}) - - r.Storer.SetIndex(&index.Index{Version: 2}) - w.Filesystem = osfs.New(filepath.Join(dir, "worktree-empty")) - - err = w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) - - target, err := w.Filesystem.Readlink("bar") - c.Assert(target, Equals, "not-exists") - c.Assert(err, IsNil) -} - -func (s *WorktreeSuite) TestFilenameNormalization(c *C) { - if runtime.GOOS == "windows" { - c.Skip("windows paths may contain non utf-8 sequences") - } - - url := c.MkDir() - path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() - - server, err := PlainClone(url, false, &CloneOptions{ - URL: path, - }) - c.Assert(err, IsNil) - - filename := "페" - - w, err := server.Worktree() - c.Assert(err, IsNil) - - writeFile := func(path string) { - err := util.WriteFile(w.Filesystem, path, []byte("foo"), 0755) - c.Assert(err, IsNil) - } - - writeFile(filename) - origHash, err := w.Add(filename) - c.Assert(err, IsNil) - _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) - c.Assert(err, IsNil) - - r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ - URL: url, - }) - c.Assert(err, IsNil) - - w, err = r.Worktree() - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) - - err = w.Filesystem.Remove(filename) - c.Assert(err, IsNil) - - modFilename := norm.NFKD.String(filename) - writeFile(modFilename) - - _, err = w.Add(filename) - c.Assert(err, IsNil) - modHash, err := w.Add(modFilename) - c.Assert(err, IsNil) - // At this point we've got two files with the same content. - // Hence their hashes must be the same. - c.Assert(origHash == modHash, Equals, true) - - status, err = w.Status() - c.Assert(err, IsNil) - // However, their names are different and the work tree is still dirty. - c.Assert(status.IsClean(), Equals, false) - - // Revert back the deletion of the first file. - writeFile(filename) - _, err = w.Add(filename) - c.Assert(err, IsNil) - - status, err = w.Status() - c.Assert(err, IsNil) - // Still dirty - the second file is added. - c.Assert(status.IsClean(), Equals, false) - - _, err = w.Remove(modFilename) - c.Assert(err, IsNil) - - status, err = w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestCheckoutSubmodule(c *C) { - url := "https://github.com/git-fixtures/submodule.git" - r := s.NewRepositoryWithEmptyWorktree(fixtures.ByURL(url).One()) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestCheckoutSubmoduleInitialized(c *C) { - url := "https://github.com/git-fixtures/submodule.git" - r := s.NewRepository(fixtures.ByURL(url).One()) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - sub, err := w.Submodules() - c.Assert(err, IsNil) - - err = sub.Update(&SubmoduleUpdateOptions{Init: true}) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestCheckoutIndexMem(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - idx, err := s.Repository.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88") - c.Assert(idx.Entries[0].Name, Equals, ".gitignore") - c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular) - c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false) - c.Assert(idx.Entries[0].Size, Equals, uint32(189)) - - // ctime, dev, inode, uid and gid are not supported on memfs fs - c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, true) - c.Assert(idx.Entries[0].Dev, Equals, uint32(0)) - c.Assert(idx.Entries[0].Inode, Equals, uint32(0)) - c.Assert(idx.Entries[0].UID, Equals, uint32(0)) - c.Assert(idx.Entries[0].GID, Equals, uint32(0)) -} - -func (s *WorktreeSuite) TestCheckoutIndexOS(c *C) { - dir, err := ioutil.TempDir("", "checkout") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - fs := osfs.New(filepath.Join(dir, "worktree")) - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err = w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - idx, err := s.Repository.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - c.Assert(idx.Entries[0].Hash.String(), Equals, "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88") - c.Assert(idx.Entries[0].Name, Equals, ".gitignore") - c.Assert(idx.Entries[0].Mode, Equals, filemode.Regular) - c.Assert(idx.Entries[0].ModifiedAt.IsZero(), Equals, false) - c.Assert(idx.Entries[0].Size, Equals, uint32(189)) - - c.Assert(idx.Entries[0].CreatedAt.IsZero(), Equals, false) - if runtime.GOOS != "windows" { - c.Assert(idx.Entries[0].Dev, Not(Equals), uint32(0)) - c.Assert(idx.Entries[0].Inode, Not(Equals), uint32(0)) - c.Assert(idx.Entries[0].UID, Not(Equals), uint32(0)) - c.Assert(idx.Entries[0].GID, Not(Equals), uint32(0)) - } -} - -func (s *WorktreeSuite) TestCheckoutBranch(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{ - Branch: "refs/heads/branch", - }) - c.Assert(err, IsNil) - - head, err := w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "refs/heads/branch") - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestCheckoutCreateWithHash(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{ - Create: true, - Branch: "refs/heads/foo", - Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - }) - c.Assert(err, IsNil) - - head, err := w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "refs/heads/foo") - c.Assert(head.Hash(), Equals, plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9")) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestCheckoutCreate(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{ - Create: true, - Branch: "refs/heads/foo", - }) - c.Assert(err, IsNil) - - head, err := w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "refs/heads/foo") - c.Assert(head.Hash(), Equals, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5")) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestCheckoutBranchAndHash(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{ - Branch: "refs/heads/foo", - Hash: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), - }) - - c.Assert(err, Equals, ErrBranchHashExclusive) -} - -func (s *WorktreeSuite) TestCheckoutCreateMissingBranch(c *C) { - w := &Worktree{ - r: s.Repository, - Filesystem: memfs.New(), - } - - err := w.Checkout(&CheckoutOptions{ - Create: true, - }) - - c.Assert(err, Equals, ErrCreateRequiresBranch) -} - -func (s *WorktreeSuite) TestCheckoutTag(c *C) { - f := fixtures.ByTag("tags").One() - r := s.NewRepositoryWithEmptyWorktree(f) - w, err := r.Worktree() - c.Assert(err, IsNil) - - err = w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - head, err := w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "refs/heads/master") - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) - - err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/lightweight-tag"}) - c.Assert(err, IsNil) - head, err = w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "HEAD") - c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") - - err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/commit-tag"}) - c.Assert(err, IsNil) - head, err = w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "HEAD") - c.Assert(head.Hash().String(), Equals, "f7b877701fbf855b44c0a9e86f3fdce2c298b07f") - - err = w.Checkout(&CheckoutOptions{Branch: "refs/tags/tree-tag"}) - c.Assert(err, NotNil) - head, err = w.r.Head() - c.Assert(err, IsNil) - c.Assert(head.Name().String(), Equals, "HEAD") -} - -func (s *WorktreeSuite) TestCheckoutBisect(c *C) { - if testing.Short() { - c.Skip("skipping test in short mode.") - } - - s.testCheckoutBisect(c, "https://github.com/src-d/go-git.git") -} - -func (s *WorktreeSuite) TestCheckoutBisectSubmodules(c *C) { - s.testCheckoutBisect(c, "https://github.com/git-fixtures/submodule.git") -} - -// TestCheckoutBisect simulates a git bisect going through the git history and -// checking every commit over the previous commit -func (s *WorktreeSuite) testCheckoutBisect(c *C, url string) { - f := fixtures.ByURL(url).One() - r := s.NewRepositoryWithEmptyWorktree(f) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - iter, err := w.r.Log(&LogOptions{}) - c.Assert(err, IsNil) - - iter.ForEach(func(commit *object.Commit) error { - err := w.Checkout(&CheckoutOptions{Hash: commit.Hash}) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) - - return nil - }) -} - -func (s *WorktreeSuite) TestStatus(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - status, err := w.Status() - c.Assert(err, IsNil) - - c.Assert(status.IsClean(), Equals, false) - c.Assert(status, HasLen, 9) -} - -func (s *WorktreeSuite) TestStatusEmpty(c *C) { - fs := memfs.New() - storage := memory.NewStorage() - - r, err := Init(storage, fs) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) - c.Assert(status, NotNil) -} - -func (s *WorktreeSuite) TestStatusEmptyDirty(c *C) { - fs := memfs.New() - err := util.WriteFile(fs, "foo", []byte("foo"), 0755) - c.Assert(err, IsNil) - - storage := memory.NewStorage() - - r, err := Init(storage, fs) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, false) - c.Assert(status, HasLen, 1) -} - -func (s *WorktreeSuite) TestReset(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - branch, err := w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Not(Equals), commit) - - err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit}) - c.Assert(err, IsNil) - - branch, err = w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Equals, commit) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestResetWithUntracked(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - err = util.WriteFile(fs, "foo", nil, 0755) - c.Assert(err, IsNil) - - err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commit}) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) -} - -func (s *WorktreeSuite) TestResetSoft(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - err = w.Reset(&ResetOptions{Mode: SoftReset, Commit: commit}) - c.Assert(err, IsNil) - - branch, err := w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Equals, commit) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, false) - c.Assert(status.File("CHANGELOG").Staging, Equals, Added) -} - -func (s *WorktreeSuite) TestResetMixed(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - err = w.Reset(&ResetOptions{Mode: MixedReset, Commit: commit}) - c.Assert(err, IsNil) - - branch, err := w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Equals, commit) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, false) - c.Assert(status.File("CHANGELOG").Staging, Equals, Untracked) -} - -func (s *WorktreeSuite) TestResetMerge(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - commitA := plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294") - commitB := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitA}) - c.Assert(err, IsNil) - - branch, err := w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Equals, commitA) - - f, err := fs.Create(".gitignore") - c.Assert(err, IsNil) - _, err = f.Write([]byte("foo")) - c.Assert(err, IsNil) - err = f.Close() - c.Assert(err, IsNil) - - err = w.Reset(&ResetOptions{Mode: MergeReset, Commit: commitB}) - c.Assert(err, Equals, ErrUnstagedChanges) - - branch, err = w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Equals, commitA) -} - -func (s *WorktreeSuite) TestResetHard(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - commit := plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9") - - err := w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - f, err := fs.Create(".gitignore") - c.Assert(err, IsNil) - _, err = f.Write([]byte("foo")) - c.Assert(err, IsNil) - err = f.Close() - c.Assert(err, IsNil) - - err = w.Reset(&ResetOptions{Mode: HardReset, Commit: commit}) - c.Assert(err, IsNil) - - branch, err := w.r.Reference(plumbing.Master, false) - c.Assert(err, IsNil) - c.Assert(branch.Hash(), Equals, commit) -} - -func (s *WorktreeSuite) TestStatusAfterCheckout(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, true) - -} - -func (s *WorktreeSuite) TestStatusModified(c *C) { - dir, err := ioutil.TempDir("", "status") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - fs := osfs.New(filepath.Join(dir, "worktree")) - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err = w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - f, err := fs.Create(".gitignore") - c.Assert(err, IsNil) - _, err = f.Write([]byte("foo")) - c.Assert(err, IsNil) - err = f.Close() - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, false) - c.Assert(status.File(".gitignore").Worktree, Equals, Modified) -} - -func (s *WorktreeSuite) TestStatusIgnored(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - w.Checkout(&CheckoutOptions{}) - - fs.MkdirAll("another", os.ModePerm) - f, _ := fs.Create("another/file") - f.Close() - fs.MkdirAll("vendor/github.com", os.ModePerm) - f, _ = fs.Create("vendor/github.com/file") - f.Close() - fs.MkdirAll("vendor/gopkg.in", os.ModePerm) - f, _ = fs.Create("vendor/gopkg.in/file") - f.Close() - - status, _ := w.Status() - c.Assert(len(status), Equals, 3) - _, ok := status["another/file"] - c.Assert(ok, Equals, true) - _, ok = status["vendor/github.com/file"] - c.Assert(ok, Equals, true) - _, ok = status["vendor/gopkg.in/file"] - c.Assert(ok, Equals, true) - - f, _ = fs.Create(".gitignore") - f.Write([]byte("vendor/g*/")) - f.Close() - f, _ = fs.Create("vendor/.gitignore") - f.Write([]byte("!github.com/\n")) - f.Close() - - status, _ = w.Status() - c.Assert(len(status), Equals, 4) - _, ok = status[".gitignore"] - c.Assert(ok, Equals, true) - _, ok = status["another/file"] - c.Assert(ok, Equals, true) - _, ok = status["vendor/.gitignore"] - c.Assert(ok, Equals, true) - _, ok = status["vendor/github.com/file"] - c.Assert(ok, Equals, true) -} - -func (s *WorktreeSuite) TestStatusUntracked(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - f, err := w.Filesystem.Create("foo") - c.Assert(err, IsNil) - c.Assert(f.Close(), IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.File("foo").Staging, Equals, Untracked) - c.Assert(status.File("foo").Worktree, Equals, Untracked) -} - -func (s *WorktreeSuite) TestStatusDeleted(c *C) { - dir, err := ioutil.TempDir("", "status") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - fs := osfs.New(filepath.Join(dir, "worktree")) - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err = w.Checkout(&CheckoutOptions{}) - c.Assert(err, IsNil) - - err = fs.Remove(".gitignore") - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status.IsClean(), Equals, false) - c.Assert(status.File(".gitignore").Worktree, Equals, Deleted) -} - -func (s *WorktreeSuite) TestSubmodule(c *C) { - path := fixtures.ByTag("submodule").One().Worktree().Root() - r, err := PlainOpen(path) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - m, err := w.Submodule("basic") - c.Assert(err, IsNil) - - c.Assert(m.Config().Name, Equals, "basic") -} - -func (s *WorktreeSuite) TestSubmodules(c *C) { - path := fixtures.ByTag("submodule").One().Worktree().Root() - r, err := PlainOpen(path) - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - - l, err := w.Submodules() - c.Assert(err, IsNil) - - c.Assert(l, HasLen, 2) -} - -func (s *WorktreeSuite) TestAddUntracked(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - idx, err := w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) - c.Assert(err, IsNil) - - hash, err := w.Add("foo") - c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5") - c.Assert(err, IsNil) - - idx, err = w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 10) - - e, err := idx.Entry("foo") - c.Assert(err, IsNil) - c.Assert(e.Hash, Equals, hash) - c.Assert(e.Mode, Equals, filemode.Executable) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 1) - - file := status.File("foo") - c.Assert(file.Staging, Equals, Added) - c.Assert(file.Worktree, Equals, Unmodified) - - obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, hash) - c.Assert(err, IsNil) - c.Assert(obj, NotNil) - c.Assert(obj.Size(), Equals, int64(3)) -} - -func (s *WorktreeSuite) TestIgnored(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - w.Excludes = make([]gitignore.Pattern, 0) - w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil)) - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - idx, err := w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 0) - - file := status.File("foo") - c.Assert(file.Staging, Equals, Untracked) - c.Assert(file.Worktree, Equals, Untracked) -} - -func (s *WorktreeSuite) TestExcludedNoGitignore(c *C) { - f := fixtures.ByTag("empty").One() - r := s.NewRepository(f) - - fs := memfs.New() - w := &Worktree{ - r: r, - Filesystem: fs, - } - - _, err := fs.Open(".gitignore") - c.Assert(err, Equals, os.ErrNotExist) - - w.Excludes = make([]gitignore.Pattern, 0) - w.Excludes = append(w.Excludes, gitignore.ParsePattern("foo", nil)) - - err = util.WriteFile(w.Filesystem, "foo", []byte("FOO"), 0755) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 0) - - file := status.File("foo") - c.Assert(file.Staging, Equals, Untracked) - c.Assert(file.Worktree, Equals, Untracked) -} - -func (s *WorktreeSuite) TestAddModified(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - idx, err := w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - err = util.WriteFile(w.Filesystem, "LICENSE", []byte("FOO"), 0644) - c.Assert(err, IsNil) - - hash, err := w.Add("LICENSE") - c.Assert(err, IsNil) - c.Assert(hash.String(), Equals, "d96c7efbfec2814ae0301ad054dc8d9fc416c9b5") - - idx, err = w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - e, err := idx.Entry("LICENSE") - c.Assert(err, IsNil) - c.Assert(e.Hash, Equals, hash) - c.Assert(e.Mode, Equals, filemode.Regular) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 1) - - file := status.File("LICENSE") - c.Assert(file.Staging, Equals, Modified) - c.Assert(file.Worktree, Equals, Unmodified) -} - -func (s *WorktreeSuite) TestAddUnmodified(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Add("LICENSE") - c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") - c.Assert(err, IsNil) -} - -func (s *WorktreeSuite) TestAddRemoved(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - idx, err := w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - err = w.Filesystem.Remove("LICENSE") - c.Assert(err, IsNil) - - hash, err := w.Add("LICENSE") - c.Assert(err, IsNil) - c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") - - e, err := idx.Entry("LICENSE") - c.Assert(err, IsNil) - c.Assert(e.Hash, Equals, hash) - c.Assert(e.Mode, Equals, filemode.Regular) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 1) - - file := status.File("LICENSE") - c.Assert(file.Staging, Equals, Deleted) -} - -func (s *WorktreeSuite) TestAddSymlink(c *C) { - dir, err := ioutil.TempDir("", "checkout") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - r, err := PlainInit(dir, false) - c.Assert(err, IsNil) - err = util.WriteFile(r.wt, "foo", []byte("qux"), 0644) - c.Assert(err, IsNil) - err = r.wt.Symlink("foo", "bar") - c.Assert(err, IsNil) - - w, err := r.Worktree() - c.Assert(err, IsNil) - h, err := w.Add("foo") - c.Assert(err, IsNil) - c.Assert(h, Not(Equals), plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c")) - - h, err = w.Add("bar") - c.Assert(err, IsNil) - c.Assert(h, Equals, plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c")) - - obj, err := w.r.Storer.EncodedObject(plumbing.BlobObject, h) - c.Assert(err, IsNil) - c.Assert(obj, NotNil) - c.Assert(obj.Size(), Equals, int64(3)) -} - -func (s *WorktreeSuite) TestAddDirectory(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - idx, err := w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - err = util.WriteFile(w.Filesystem, "qux/foo", []byte("FOO"), 0755) - c.Assert(err, IsNil) - err = util.WriteFile(w.Filesystem, "qux/baz/bar", []byte("BAR"), 0755) - c.Assert(err, IsNil) - - h, err := w.Add("qux") - c.Assert(err, IsNil) - c.Assert(h.IsZero(), Equals, true) - - idx, err = w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 11) - - e, err := idx.Entry("qux/foo") - c.Assert(err, IsNil) - c.Assert(e.Mode, Equals, filemode.Executable) - - e, err = idx.Entry("qux/baz/bar") - c.Assert(err, IsNil) - c.Assert(e.Mode, Equals, filemode.Executable) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 2) - - file := status.File("qux/foo") - c.Assert(file.Staging, Equals, Added) - c.Assert(file.Worktree, Equals, Unmodified) - - file = status.File("qux/baz/bar") - c.Assert(file.Staging, Equals, Added) - c.Assert(file.Worktree, Equals, Unmodified) -} - -func (s *WorktreeSuite) TestAddDirectoryErrorNotFound(c *C) { - r, _ := Init(memory.NewStorage(), memfs.New()) - w, _ := r.Worktree() - - h, err := w.Add("foo") - c.Assert(err, NotNil) - c.Assert(h.IsZero(), Equals, true) -} - -func (s *WorktreeSuite) TestAddGlob(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - idx, err := w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 9) - - err = util.WriteFile(w.Filesystem, "qux/qux", []byte("QUX"), 0755) - c.Assert(err, IsNil) - err = util.WriteFile(w.Filesystem, "qux/baz", []byte("BAZ"), 0755) - c.Assert(err, IsNil) - err = util.WriteFile(w.Filesystem, "qux/bar/baz", []byte("BAZ"), 0755) - c.Assert(err, IsNil) - - err = w.AddGlob(w.Filesystem.Join("qux", "b*")) - c.Assert(err, IsNil) - - idx, err = w.r.Storer.Index() - c.Assert(err, IsNil) - c.Assert(idx.Entries, HasLen, 11) - - e, err := idx.Entry("qux/baz") - c.Assert(err, IsNil) - c.Assert(e.Mode, Equals, filemode.Executable) - - e, err = idx.Entry("qux/bar/baz") - c.Assert(err, IsNil) - c.Assert(e.Mode, Equals, filemode.Executable) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 3) - - file := status.File("qux/qux") - c.Assert(file.Staging, Equals, Untracked) - c.Assert(file.Worktree, Equals, Untracked) - - file = status.File("qux/baz") - c.Assert(file.Staging, Equals, Added) - c.Assert(file.Worktree, Equals, Unmodified) - - file = status.File("qux/bar/baz") - c.Assert(file.Staging, Equals, Added) - c.Assert(file.Worktree, Equals, Unmodified) -} - -func (s *WorktreeSuite) TestAddGlobErrorNoMatches(c *C) { - r, _ := Init(memory.NewStorage(), memfs.New()) - w, _ := r.Worktree() - - err := w.AddGlob("foo") - c.Assert(err, Equals, ErrGlobNoMatches) -} - -func (s *WorktreeSuite) TestRemove(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Remove("LICENSE") - c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 1) - c.Assert(status.File("LICENSE").Staging, Equals, Deleted) -} - -func (s *WorktreeSuite) TestRemoveNotExistentEntry(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Remove("not-exists") - c.Assert(hash.IsZero(), Equals, true) - c.Assert(err, NotNil) -} - -func (s *WorktreeSuite) TestRemoveDirectory(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Remove("json") - c.Assert(hash.IsZero(), Equals, true) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 2) - c.Assert(status.File("json/long.json").Staging, Equals, Deleted) - c.Assert(status.File("json/short.json").Staging, Equals, Deleted) - - _, err = w.Filesystem.Stat("json") - c.Assert(os.IsNotExist(err), Equals, true) -} - -func (s *WorktreeSuite) TestRemoveDirectoryUntracked(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755) - c.Assert(err, IsNil) - - hash, err := w.Remove("json") - c.Assert(hash.IsZero(), Equals, true) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 3) - c.Assert(status.File("json/long.json").Staging, Equals, Deleted) - c.Assert(status.File("json/short.json").Staging, Equals, Deleted) - c.Assert(status.File("json/foo").Staging, Equals, Untracked) - - _, err = w.Filesystem.Stat("json") - c.Assert(err, IsNil) -} - -func (s *WorktreeSuite) TestRemoveDeletedFromWorktree(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - err = fs.Remove("LICENSE") - c.Assert(err, IsNil) - - hash, err := w.Remove("LICENSE") - c.Assert(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 1) - c.Assert(status.File("LICENSE").Staging, Equals, Deleted) -} - -func (s *WorktreeSuite) TestRemoveGlob(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - err = w.RemoveGlob(w.Filesystem.Join("json", "l*")) - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 1) - c.Assert(status.File("json/long.json").Staging, Equals, Deleted) -} - -func (s *WorktreeSuite) TestRemoveGlobDirectory(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - err = w.RemoveGlob("js*") - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 2) - c.Assert(status.File("json/short.json").Staging, Equals, Deleted) - c.Assert(status.File("json/long.json").Staging, Equals, Deleted) - - _, err = w.Filesystem.Stat("json") - c.Assert(os.IsNotExist(err), Equals, true) -} - -func (s *WorktreeSuite) TestRemoveGlobDirectoryDeleted(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - err = fs.Remove("json/short.json") - c.Assert(err, IsNil) - - err = util.WriteFile(w.Filesystem, "json/foo", []byte("FOO"), 0755) - c.Assert(err, IsNil) - - err = w.RemoveGlob("js*") - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 3) - c.Assert(status.File("json/short.json").Staging, Equals, Deleted) - c.Assert(status.File("json/long.json").Staging, Equals, Deleted) -} - -func (s *WorktreeSuite) TestMove(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Move("LICENSE", "foo") - c.Check(hash.String(), Equals, "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f") - c.Assert(err, IsNil) - - status, err := w.Status() - c.Assert(err, IsNil) - c.Assert(status, HasLen, 2) - c.Assert(status.File("LICENSE").Staging, Equals, Deleted) - c.Assert(status.File("foo").Staging, Equals, Added) - -} - -func (s *WorktreeSuite) TestMoveNotExistentEntry(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Move("not-exists", "foo") - c.Assert(hash.IsZero(), Equals, true) - c.Assert(err, NotNil) -} - -func (s *WorktreeSuite) TestMoveToExistent(c *C) { - fs := memfs.New() - w := &Worktree{ - r: s.Repository, - Filesystem: fs, - } - - err := w.Checkout(&CheckoutOptions{Force: true}) - c.Assert(err, IsNil) - - hash, err := w.Move(".gitignore", "LICENSE") - c.Assert(hash.IsZero(), Equals, true) - c.Assert(err, Equals, ErrDestinationExists) -} - -func (s *WorktreeSuite) TestClean(c *C) { - fs := fixtures.ByTag("dirty").One().Worktree() - - // Open the repo. - fs, err := fs.Chroot("repo") - c.Assert(err, IsNil) - r, err := PlainOpen(fs.Root()) - c.Assert(err, IsNil) - - wt, err := r.Worktree() - c.Assert(err, IsNil) - - // Status before cleaning. - status, err := wt.Status() - c.Assert(err, IsNil) - c.Assert(len(status), Equals, 2) - - err = wt.Clean(&CleanOptions{}) - c.Assert(err, IsNil) - - // Status after cleaning. - status, err = wt.Status() - c.Assert(err, IsNil) - - c.Assert(len(status), Equals, 1) - - fi, err := fs.Lstat("pkgA") - c.Assert(err, IsNil) - c.Assert(fi.IsDir(), Equals, true) - - // Clean with Dir: true. - err = wt.Clean(&CleanOptions{Dir: true}) - c.Assert(err, IsNil) - - status, err = wt.Status() - c.Assert(err, IsNil) - - c.Assert(len(status), Equals, 0) - - // An empty dir should be deleted, as well. - _, err = fs.Lstat("pkgA") - c.Assert(err, ErrorMatches, ".*(no such file or directory.*|.*file does not exist)*.") - -} - -func (s *WorktreeSuite) TestAlternatesRepo(c *C) { - fs := fixtures.ByTag("alternates").One().Worktree() - - // Open 1st repo. - rep1fs, err := fs.Chroot("rep1") - c.Assert(err, IsNil) - rep1, err := PlainOpen(rep1fs.Root()) - c.Assert(err, IsNil) - - // Open 2nd repo. - rep2fs, err := fs.Chroot("rep2") - c.Assert(err, IsNil) - rep2, err := PlainOpen(rep2fs.Root()) - c.Assert(err, IsNil) - - // Get the HEAD commit from the main repo. - h, err := rep1.Head() - c.Assert(err, IsNil) - commit1, err := rep1.CommitObject(h.Hash()) - c.Assert(err, IsNil) - - // Get the HEAD commit from the shared repo. - h, err = rep2.Head() - c.Assert(err, IsNil) - commit2, err := rep2.CommitObject(h.Hash()) - c.Assert(err, IsNil) - - c.Assert(commit1.String(), Equals, commit2.String()) -} - -func (s *WorktreeSuite) TestGrep(c *C) { - cases := []struct { - name string - options GrepOptions - wantResult []GrepResult - dontWantResult []GrepResult - wantError error - }{ - { - name: "basic word match", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, - }, - wantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - { - FileName: "vendor/foo.go", - LineNumber: 3, - Content: "import \"fmt\"", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, { - name: "case insensitive match", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile(`(?i)IMport`)}, - }, - wantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - { - FileName: "vendor/foo.go", - LineNumber: 3, - Content: "import \"fmt\"", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, { - name: "invert match", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, - InvertMatch: true, - }, - dontWantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - { - FileName: "vendor/foo.go", - LineNumber: 3, - Content: "import \"fmt\"", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, { - name: "match at a given commit hash", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("The MIT License")}, - CommitHash: plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), - }, - wantResult: []GrepResult{ - { - FileName: "LICENSE", - LineNumber: 1, - Content: "The MIT License (MIT)", - TreeName: "b029517f6300c2da0f4b651b8642506cd6aaf45d", - }, - }, - dontWantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, { - name: "match for a given pathspec", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, - PathSpecs: []*regexp.Regexp{regexp.MustCompile("go/")}, - }, - wantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - dontWantResult: []GrepResult{ - { - FileName: "vendor/foo.go", - LineNumber: 3, - Content: "import \"fmt\"", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, { - name: "match at a given reference name", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, - ReferenceName: "refs/heads/master", - }, - wantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "refs/heads/master", - }, - }, - }, { - name: "ambiguous options", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, - CommitHash: plumbing.NewHash("2d55a722f3c3ecc36da919dfd8b6de38352f3507"), - ReferenceName: "somereferencename", - }, - wantError: ErrHashOrReference, - }, { - name: "multiple patterns", - options: GrepOptions{ - Patterns: []*regexp.Regexp{ - regexp.MustCompile("import"), - regexp.MustCompile("License"), - }, - }, - wantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - { - FileName: "vendor/foo.go", - LineNumber: 3, - Content: "import \"fmt\"", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - { - FileName: "LICENSE", - LineNumber: 1, - Content: "The MIT License (MIT)", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, { - name: "multiple pathspecs", - options: GrepOptions{ - Patterns: []*regexp.Regexp{regexp.MustCompile("import")}, - PathSpecs: []*regexp.Regexp{ - regexp.MustCompile("go/"), - regexp.MustCompile("vendor/"), - }, - }, - wantResult: []GrepResult{ - { - FileName: "go/example.go", - LineNumber: 3, - Content: "import (", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - { - FileName: "vendor/foo.go", - LineNumber: 3, - Content: "import \"fmt\"", - TreeName: "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", - }, - }, - }, - } - - path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() - server, err := PlainClone(c.MkDir(), false, &CloneOptions{ - URL: path, - }) - c.Assert(err, IsNil) - - w, err := server.Worktree() - c.Assert(err, IsNil) - - for _, tc := range cases { - gr, err := w.Grep(&tc.options) - if tc.wantError != nil { - c.Assert(err, Equals, tc.wantError) - } else { - c.Assert(err, IsNil) - } - - // Iterate through the results and check if the wanted result is present - // in the got result. - for _, wantResult := range tc.wantResult { - found := false - for _, gotResult := range gr { - if wantResult == gotResult { - found = true - break - } - } - if !found { - c.Errorf("unexpected grep results for %q, expected result to contain: %v", tc.name, wantResult) - } - } - - // Iterate through the results and check if the not wanted result is - // present in the got result. - for _, dontWantResult := range tc.dontWantResult { - found := false - for _, gotResult := range gr { - if dontWantResult == gotResult { - found = true - break - } - } - if found { - c.Errorf("unexpected grep results for %q, expected result to NOT contain: %v", tc.name, dontWantResult) - } - } - } -} - -func (s *WorktreeSuite) TestAddAndCommit(c *C) { - dir, err := ioutil.TempDir("", "plain-repo") - c.Assert(err, IsNil) - defer os.RemoveAll(dir) - - repo, err := PlainInit(dir, false) - c.Assert(err, IsNil) - - w, err := repo.Worktree() - c.Assert(err, IsNil) - - _, err = w.Add(".") - c.Assert(err, IsNil) - - w.Commit("Test Add And Commit", &CommitOptions{Author: &object.Signature{ - Name: "foo", - Email: "foo@foo.foo", - When: time.Now(), - }}) - - iter, err := w.r.Log(&LogOptions{}) - c.Assert(err, IsNil) - err = iter.ForEach(func(c *object.Commit) error { - files, err := c.Files() - if err != nil { - return err - } - - err = files.ForEach(func(f *object.File) error { - return errors.New("Expected no files, got at least 1") - }) - return err - }) - c.Assert(err, IsNil) -} diff --git a/vendor/github.com/kevinburke/ssh_config/.gitattributes b/vendor/github.com/kevinburke/ssh_config/.gitattributes new file mode 100644 index 00000000..44db5818 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/.gitattributes @@ -0,0 +1 @@ +testdata/dos-lines eol=crlf diff --git a/vendor/github.com/kevinburke/ssh_config/.gitignore b/vendor/github.com/kevinburke/ssh_config/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/vendor/github.com/kevinburke/ssh_config/.mailmap b/vendor/github.com/kevinburke/ssh_config/.mailmap new file mode 100644 index 00000000..253406b1 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/.mailmap @@ -0,0 +1 @@ +Kevin Burke Kevin Burke diff --git a/vendor/github.com/kevinburke/ssh_config/.travis.yml b/vendor/github.com/kevinburke/ssh_config/.travis.yml new file mode 100644 index 00000000..4306f30f --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/.travis.yml @@ -0,0 +1,14 @@ +go_import_path: github.com/kevinburke/ssh_config + +language: go + +go: + - 1.11.x + - 1.12.x + - master + +before_script: + - go get -u ./... + +script: + - make race-test diff --git a/vendor/github.com/kevinburke/ssh_config/AUTHORS.txt b/vendor/github.com/kevinburke/ssh_config/AUTHORS.txt new file mode 100644 index 00000000..cd337940 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/AUTHORS.txt @@ -0,0 +1,5 @@ +Eugene Terentev +Kevin Burke +Mark Nevill +Sergey Lukjanov +Wayne Ashley Berry diff --git a/vendor/github.com/kevinburke/ssh_config/LICENSE b/vendor/github.com/kevinburke/ssh_config/LICENSE new file mode 100644 index 00000000..b9a770ac --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/LICENSE @@ -0,0 +1,49 @@ +Copyright (c) 2017 Kevin Burke. + +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. + +=================== + +The lexer and parser borrow heavily from github.com/pelletier/go-toml. The +license for that project is copied below. + +The MIT License (MIT) + +Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/kevinburke/ssh_config/Makefile b/vendor/github.com/kevinburke/ssh_config/Makefile new file mode 100644 index 00000000..a1880d18 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/Makefile @@ -0,0 +1,30 @@ +BUMP_VERSION := $(GOPATH)/bin/bump_version +STATICCHECK := $(GOPATH)/bin/staticcheck +WRITE_MAILMAP := $(GOPATH)/bin/write_mailmap + +$(STATICCHECK): + go get honnef.co/go/tools/cmd/staticcheck + +lint: $(STATICCHECK) + go vet ./... + $(STATICCHECK) + +test: lint + @# the timeout helps guard against infinite recursion + go test -timeout=250ms ./... + +race-test: lint + go test -timeout=500ms -race ./... + +$(BUMP_VERSION): + go get -u github.com/kevinburke/bump_version + +release: test | $(BUMP_VERSION) + $(BUMP_VERSION) minor config.go + +force: ; + +AUTHORS.txt: force | $(WRITE_MAILMAP) + $(WRITE_MAILMAP) > AUTHORS.txt + +authors: AUTHORS.txt diff --git a/vendor/github.com/kevinburke/ssh_config/README.md b/vendor/github.com/kevinburke/ssh_config/README.md new file mode 100644 index 00000000..52cc1eac --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/README.md @@ -0,0 +1,81 @@ +# ssh_config + +This is a Go parser for `ssh_config` files. Importantly, this parser attempts +to preserve comments in a given file, so you can manipulate a `ssh_config` file +from a program, if your heart desires. + +It's designed to be used with the excellent +[x/crypto/ssh](https://golang.org/x/crypto/ssh) package, which handles SSH +negotiation but isn't very easy to configure. + +The `ssh_config` `Get()` and `GetStrict()` functions will attempt to read values +from `$HOME/.ssh/config` and fall back to `/etc/ssh/ssh_config`. The first +argument is the host name to match on, and the second argument is the key you +want to retrieve. + +```go +port := ssh_config.Get("myhost", "Port") +``` + +You can also load a config file and read values from it. + +```go +var config = ` +Host *.test + Compression yes +` + +cfg, err := ssh_config.Decode(strings.NewReader(config)) +fmt.Println(cfg.Get("example.test", "Port")) +``` + +Some SSH arguments have default values - for example, the default value for +`KeyboardAuthentication` is `"yes"`. If you call Get(), and no value for the +given Host/keyword pair exists in the config, we'll return a default for the +keyword if one exists. + +### Manipulating SSH config files + +Here's how you can manipulate an SSH config file, and then write it back to +disk. + +```go +f, _ := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config")) +cfg, _ := ssh_config.Decode(f) +for _, host := range cfg.Hosts { + fmt.Println("patterns:", host.Patterns) + for _, node := range host.Nodes { + // Manipulate the nodes as you see fit, or use a type switch to + // distinguish between Empty, KV, and Include nodes. + fmt.Println(node.String()) + } +} + +// Print the config to stdout: +fmt.Println(cfg.String()) +``` + +## Spec compliance + +Wherever possible we try to implement the specification as documented in +the `ssh_config` manpage. Unimplemented features should be present in the +[issues][issues] list. + +Notably, the `Match` directive is currently unsupported. + +[issues]: https://github.com/kevinburke/ssh_config/issues + +## Errata + +This is the second [comment-preserving configuration parser][blog] I've written, after +[an /etc/hosts parser][hostsfile]. Eventually, I will write one for every Linux +file format. + +[blog]: https://kev.inburke.com/kevin/more-comment-preserving-configuration-parsers/ +[hostsfile]: https://github.com/kevinburke/hostsfile + +## Donating + +Donations free up time to make improvements to the library, and respond to +bug reports. You can send donations via Paypal's "Send Money" feature to +kev@inburke.com. Donations are not tax deductible in the USA. diff --git a/vendor/github.com/kevinburke/ssh_config/config.go b/vendor/github.com/kevinburke/ssh_config/config.go new file mode 100644 index 00000000..136f0c35 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/config.go @@ -0,0 +1,649 @@ +// Package ssh_config provides tools for manipulating SSH config files. +// +// Importantly, this parser attempts to preserve comments in a given file, so +// you can manipulate a `ssh_config` file from a program, if your heart desires. +// +// The Get() and GetStrict() functions will attempt to read values from +// $HOME/.ssh/config, falling back to /etc/ssh/ssh_config. The first argument is +// the host name to match on ("example.com"), and the second argument is the key +// you want to retrieve ("Port"). The keywords are case insensitive. +// +// port := ssh_config.Get("myhost", "Port") +// +// You can also manipulate an SSH config file and then print it or write it back +// to disk. +// +// f, _ := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config")) +// cfg, _ := ssh_config.Decode(f) +// for _, host := range cfg.Hosts { +// fmt.Println("patterns:", host.Patterns) +// for _, node := range host.Nodes { +// fmt.Println(node.String()) +// } +// } +// +// // Write the cfg back to disk: +// fmt.Println(cfg.String()) +// +// BUG: the Match directive is currently unsupported; parsing a config with +// a Match directive will trigger an error. +package ssh_config + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + osuser "os/user" + "path/filepath" + "regexp" + "runtime" + "strings" + "sync" +) + +const version = "1.0" + +var _ = version + +type configFinder func() string + +// UserSettings checks ~/.ssh and /etc/ssh for configuration files. The config +// files are parsed and cached the first time Get() or GetStrict() is called. +type UserSettings struct { + IgnoreErrors bool + systemConfig *Config + systemConfigFinder configFinder + userConfig *Config + userConfigFinder configFinder + loadConfigs sync.Once + onceErr error +} + +func homedir() string { + user, err := osuser.Current() + if err == nil { + return user.HomeDir + } else { + return os.Getenv("HOME") + } +} + +func userConfigFinder() string { + return filepath.Join(homedir(), ".ssh", "config") +} + +// DefaultUserSettings is the default UserSettings and is used by Get and +// GetStrict. It checks both $HOME/.ssh/config and /etc/ssh/ssh_config for keys, +// and it will return parse errors (if any) instead of swallowing them. +var DefaultUserSettings = &UserSettings{ + IgnoreErrors: false, + systemConfigFinder: systemConfigFinder, + userConfigFinder: userConfigFinder, +} + +func systemConfigFinder() string { + return filepath.Join("/", "etc", "ssh", "ssh_config") +} + +func findVal(c *Config, alias, key string) (string, error) { + if c == nil { + return "", nil + } + val, err := c.Get(alias, key) + if err != nil || val == "" { + return "", err + } + if err := validate(key, val); err != nil { + return "", err + } + return val, nil +} + +// Get finds the first value for key within a declaration that matches the +// alias. Get returns the empty string if no value was found, or if IgnoreErrors +// is false and we could not parse the configuration file. Use GetStrict to +// disambiguate the latter cases. +// +// The match for key is case insensitive. +// +// Get is a wrapper around DefaultUserSettings.Get. +func Get(alias, key string) string { + return DefaultUserSettings.Get(alias, key) +} + +// GetStrict finds the first value for key within a declaration that matches the +// alias. If key has a default value and no matching configuration is found, the +// default will be returned. For more information on default values and the way +// patterns are matched, see the manpage for ssh_config. +// +// error will be non-nil if and only if a user's configuration file or the +// system configuration file could not be parsed, and u.IgnoreErrors is false. +// +// GetStrict is a wrapper around DefaultUserSettings.GetStrict. +func GetStrict(alias, key string) (string, error) { + return DefaultUserSettings.GetStrict(alias, key) +} + +// Get finds the first value for key within a declaration that matches the +// alias. Get returns the empty string if no value was found, or if IgnoreErrors +// is false and we could not parse the configuration file. Use GetStrict to +// disambiguate the latter cases. +// +// The match for key is case insensitive. +func (u *UserSettings) Get(alias, key string) string { + val, err := u.GetStrict(alias, key) + if err != nil { + return "" + } + return val +} + +// GetStrict finds the first value for key within a declaration that matches the +// alias. If key has a default value and no matching configuration is found, the +// default will be returned. For more information on default values and the way +// patterns are matched, see the manpage for ssh_config. +// +// error will be non-nil if and only if a user's configuration file or the +// system configuration file could not be parsed, and u.IgnoreErrors is false. +func (u *UserSettings) GetStrict(alias, key string) (string, error) { + u.loadConfigs.Do(func() { + // can't parse user file, that's ok. + var filename string + if u.userConfigFinder == nil { + filename = userConfigFinder() + } else { + filename = u.userConfigFinder() + } + var err error + u.userConfig, err = parseFile(filename) + //lint:ignore S1002 I prefer it this way + if err != nil && os.IsNotExist(err) == false { + u.onceErr = err + return + } + if u.systemConfigFinder == nil { + filename = systemConfigFinder() + } else { + filename = u.systemConfigFinder() + } + u.systemConfig, err = parseFile(filename) + //lint:ignore S1002 I prefer it this way + if err != nil && os.IsNotExist(err) == false { + u.onceErr = err + return + } + }) + //lint:ignore S1002 I prefer it this way + if u.onceErr != nil && u.IgnoreErrors == false { + return "", u.onceErr + } + val, err := findVal(u.userConfig, alias, key) + if err != nil || val != "" { + return val, err + } + val2, err2 := findVal(u.systemConfig, alias, key) + if err2 != nil || val2 != "" { + return val2, err2 + } + return Default(key), nil +} + +func parseFile(filename string) (*Config, error) { + return parseWithDepth(filename, 0) +} + +func parseWithDepth(filename string, depth uint8) (*Config, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return decodeBytes(b, isSystem(filename), depth) +} + +func isSystem(filename string) bool { + // TODO: not sure this is the best way to detect a system repo + return strings.HasPrefix(filepath.Clean(filename), "/etc/ssh") +} + +// Decode reads r into a Config, or returns an error if r could not be parsed as +// an SSH config file. +func Decode(r io.Reader) (*Config, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return decodeBytes(b, false, 0) +} + +func decodeBytes(b []byte, system bool, depth uint8) (c *Config, err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + if e, ok := r.(error); ok && e == ErrDepthExceeded { + err = e + return + } + err = errors.New(r.(string)) + } + }() + + c = parseSSH(lexSSH(b), system, depth) + return c, err +} + +// Config represents an SSH config file. +type Config struct { + // A list of hosts to match against. The file begins with an implicit + // "Host *" declaration matching all hosts. + Hosts []*Host + depth uint8 + position Position +} + +// Get finds the first value in the configuration that matches the alias and +// contains key. Get returns the empty string if no value was found, or if the +// Config contains an invalid conditional Include value. +// +// The match for key is case insensitive. +func (c *Config) Get(alias, key string) (string, error) { + lowerKey := strings.ToLower(key) + for _, host := range c.Hosts { + if !host.Matches(alias) { + continue + } + for _, node := range host.Nodes { + switch t := node.(type) { + case *Empty: + continue + case *KV: + // "keys are case insensitive" per the spec + lkey := strings.ToLower(t.Key) + if lkey == "match" { + panic("can't handle Match directives") + } + if lkey == lowerKey { + return t.Value, nil + } + case *Include: + val := t.Get(alias, key) + if val != "" { + return val, nil + } + default: + return "", fmt.Errorf("unknown Node type %v", t) + } + } + } + return "", nil +} + +// String returns a string representation of the Config file. +func (c Config) String() string { + return marshal(c).String() +} + +func (c Config) MarshalText() ([]byte, error) { + return marshal(c).Bytes(), nil +} + +func marshal(c Config) *bytes.Buffer { + var buf bytes.Buffer + for i := range c.Hosts { + buf.WriteString(c.Hosts[i].String()) + } + return &buf +} + +// Pattern is a pattern in a Host declaration. Patterns are read-only values; +// create a new one with NewPattern(). +type Pattern struct { + str string // Its appearance in the file, not the value that gets compiled. + regex *regexp.Regexp + not bool // True if this is a negated match +} + +// String prints the string representation of the pattern. +func (p Pattern) String() string { + return p.str +} + +// Copied from regexp.go with * and ? removed. +var specialBytes = []byte(`\.+()|[]{}^$`) + +func special(b byte) bool { + return bytes.IndexByte(specialBytes, b) >= 0 +} + +// NewPattern creates a new Pattern for matching hosts. NewPattern("*") creates +// a Pattern that matches all hosts. +// +// From the manpage, a pattern consists of zero or more non-whitespace +// characters, `*' (a wildcard that matches zero or more characters), or `?' (a +// wildcard that matches exactly one character). For example, to specify a set +// of declarations for any host in the ".co.uk" set of domains, the following +// pattern could be used: +// +// Host *.co.uk +// +// The following pattern would match any host in the 192.168.0.[0-9] network range: +// +// Host 192.168.0.? +func NewPattern(s string) (*Pattern, error) { + if s == "" { + return nil, errors.New("ssh_config: empty pattern") + } + negated := false + if s[0] == '!' { + negated = true + s = s[1:] + } + var buf bytes.Buffer + buf.WriteByte('^') + for i := 0; i < len(s); i++ { + // A byte loop is correct because all metacharacters are ASCII. + switch b := s[i]; b { + case '*': + buf.WriteString(".*") + case '?': + buf.WriteString(".?") + default: + // borrowing from QuoteMeta here. + if special(b) { + buf.WriteByte('\\') + } + buf.WriteByte(b) + } + } + buf.WriteByte('$') + r, err := regexp.Compile(buf.String()) + if err != nil { + return nil, err + } + return &Pattern{str: s, regex: r, not: negated}, nil +} + +// Host describes a Host directive and the keywords that follow it. +type Host struct { + // A list of host patterns that should match this host. + Patterns []*Pattern + // A Node is either a key/value pair or a comment line. + Nodes []Node + // EOLComment is the comment (if any) terminating the Host line. + EOLComment string + hasEquals bool + leadingSpace int // TODO: handle spaces vs tabs here. + // The file starts with an implicit "Host *" declaration. + implicit bool +} + +// Matches returns true if the Host matches for the given alias. For +// a description of the rules that provide a match, see the manpage for +// ssh_config. +func (h *Host) Matches(alias string) bool { + found := false + for i := range h.Patterns { + if h.Patterns[i].regex.MatchString(alias) { + if h.Patterns[i].not { + // Negated match. "A pattern entry may be negated by prefixing + // it with an exclamation mark (`!'). If a negated entry is + // matched, then the Host entry is ignored, regardless of + // whether any other patterns on the line match. Negated matches + // are therefore useful to provide exceptions for wildcard + // matches." + return false + } + found = true + } + } + return found +} + +// String prints h as it would appear in a config file. Minor tweaks may be +// present in the whitespace in the printed file. +func (h *Host) String() string { + var buf bytes.Buffer + //lint:ignore S1002 I prefer to write it this way + if h.implicit == false { + buf.WriteString(strings.Repeat(" ", int(h.leadingSpace))) + buf.WriteString("Host") + if h.hasEquals { + buf.WriteString(" = ") + } else { + buf.WriteString(" ") + } + for i, pat := range h.Patterns { + buf.WriteString(pat.String()) + if i < len(h.Patterns)-1 { + buf.WriteString(" ") + } + } + if h.EOLComment != "" { + buf.WriteString(" #") + buf.WriteString(h.EOLComment) + } + buf.WriteByte('\n') + } + for i := range h.Nodes { + buf.WriteString(h.Nodes[i].String()) + buf.WriteByte('\n') + } + return buf.String() +} + +// Node represents a line in a Config. +type Node interface { + Pos() Position + String() string +} + +// KV is a line in the config file that contains a key, a value, and possibly +// a comment. +type KV struct { + Key string + Value string + Comment string + hasEquals bool + leadingSpace int // Space before the key. TODO handle spaces vs tabs. + position Position +} + +// Pos returns k's Position. +func (k *KV) Pos() Position { + return k.position +} + +// String prints k as it was parsed in the config file. There may be slight +// changes to the whitespace between values. +func (k *KV) String() string { + if k == nil { + return "" + } + equals := " " + if k.hasEquals { + equals = " = " + } + line := fmt.Sprintf("%s%s%s%s", strings.Repeat(" ", int(k.leadingSpace)), k.Key, equals, k.Value) + if k.Comment != "" { + line += " #" + k.Comment + } + return line +} + +// Empty is a line in the config file that contains only whitespace or comments. +type Empty struct { + Comment string + leadingSpace int // TODO handle spaces vs tabs. + position Position +} + +// Pos returns e's Position. +func (e *Empty) Pos() Position { + return e.position +} + +// String prints e as it was parsed in the config file. +func (e *Empty) String() string { + if e == nil { + return "" + } + if e.Comment == "" { + return "" + } + return fmt.Sprintf("%s#%s", strings.Repeat(" ", int(e.leadingSpace)), e.Comment) +} + +// Include holds the result of an Include directive, including the config files +// that have been parsed as part of that directive. At most 5 levels of Include +// statements will be parsed. +type Include struct { + // Comment is the contents of any comment at the end of the Include + // statement. + Comment string + // an include directive can include several different files, and wildcards + directives []string + + mu sync.Mutex + // 1:1 mapping between matches and keys in files array; matches preserves + // ordering + matches []string + // actual filenames are listed here + files map[string]*Config + leadingSpace int + position Position + depth uint8 + hasEquals bool +} + +const maxRecurseDepth = 5 + +// ErrDepthExceeded is returned if too many Include directives are parsed. +// Usually this indicates a recursive loop (an Include directive pointing to the +// file it contains). +var ErrDepthExceeded = errors.New("ssh_config: max recurse depth exceeded") + +func removeDups(arr []string) []string { + // Use map to record duplicates as we find them. + encountered := make(map[string]bool, len(arr)) + result := make([]string, 0) + + for v := range arr { + //lint:ignore S1002 I prefer it this way + if encountered[arr[v]] == false { + encountered[arr[v]] = true + result = append(result, arr[v]) + } + } + return result +} + +// NewInclude creates a new Include with a list of file globs to include. +// Configuration files are parsed greedily (e.g. as soon as this function runs). +// Any error encountered while parsing nested configuration files will be +// returned. +func NewInclude(directives []string, hasEquals bool, pos Position, comment string, system bool, depth uint8) (*Include, error) { + if depth > maxRecurseDepth { + return nil, ErrDepthExceeded + } + inc := &Include{ + Comment: comment, + directives: directives, + files: make(map[string]*Config), + position: pos, + leadingSpace: pos.Col - 1, + depth: depth, + hasEquals: hasEquals, + } + // no need for inc.mu.Lock() since nothing else can access this inc + matches := make([]string, 0) + for i := range directives { + var path string + if filepath.IsAbs(directives[i]) { + path = directives[i] + } else if system { + path = filepath.Join("/etc/ssh", directives[i]) + } else { + path = filepath.Join(homedir(), ".ssh", directives[i]) + } + theseMatches, err := filepath.Glob(path) + if err != nil { + return nil, err + } + matches = append(matches, theseMatches...) + } + matches = removeDups(matches) + inc.matches = matches + for i := range matches { + config, err := parseWithDepth(matches[i], depth) + if err != nil { + return nil, err + } + inc.files[matches[i]] = config + } + return inc, nil +} + +// Pos returns the position of the Include directive in the larger file. +func (i *Include) Pos() Position { + return i.position +} + +// Get finds the first value in the Include statement matching the alias and the +// given key. +func (inc *Include) Get(alias, key string) string { + inc.mu.Lock() + defer inc.mu.Unlock() + // TODO: we search files in any order which is not correct + for i := range inc.matches { + cfg := inc.files[inc.matches[i]] + if cfg == nil { + panic("nil cfg") + } + val, err := cfg.Get(alias, key) + if err == nil && val != "" { + return val + } + } + return "" +} + +// String prints out a string representation of this Include directive. Note +// included Config files are not printed as part of this representation. +func (inc *Include) String() string { + equals := " " + if inc.hasEquals { + equals = " = " + } + line := fmt.Sprintf("%sInclude%s%s", strings.Repeat(" ", int(inc.leadingSpace)), equals, strings.Join(inc.directives, " ")) + if inc.Comment != "" { + line += " #" + inc.Comment + } + return line +} + +var matchAll *Pattern + +func init() { + var err error + matchAll, err = NewPattern("*") + if err != nil { + panic(err) + } +} + +func newConfig() *Config { + return &Config{ + Hosts: []*Host{ + &Host{ + implicit: true, + Patterns: []*Pattern{matchAll}, + Nodes: make([]Node, 0), + }, + }, + depth: 0, + } +} diff --git a/vendor/github.com/kevinburke/ssh_config/lexer.go b/vendor/github.com/kevinburke/ssh_config/lexer.go new file mode 100644 index 00000000..11680b4c --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/lexer.go @@ -0,0 +1,240 @@ +package ssh_config + +import ( + "bytes" +) + +// Define state functions +type sshLexStateFn func() sshLexStateFn + +type sshLexer struct { + inputIdx int + input []rune // Textual source + + buffer []rune // Runes composing the current token + tokens chan token + line int + col int + endbufferLine int + endbufferCol int +} + +func (s *sshLexer) lexComment(previousState sshLexStateFn) sshLexStateFn { + return func() sshLexStateFn { + growingString := "" + for next := s.peek(); next != '\n' && next != eof; next = s.peek() { + if next == '\r' && s.follow("\r\n") { + break + } + growingString += string(next) + s.next() + } + s.emitWithValue(tokenComment, growingString) + s.skip() + return previousState + } +} + +// lex the space after an equals sign in a function +func (s *sshLexer) lexRspace() sshLexStateFn { + for { + next := s.peek() + if !isSpace(next) { + break + } + s.skip() + } + return s.lexRvalue +} + +func (s *sshLexer) lexEquals() sshLexStateFn { + for { + next := s.peek() + if next == '=' { + s.emit(tokenEquals) + s.skip() + return s.lexRspace + } + // TODO error handling here; newline eof etc. + if !isSpace(next) { + break + } + s.skip() + } + return s.lexRvalue +} + +func (s *sshLexer) lexKey() sshLexStateFn { + growingString := "" + + for r := s.peek(); isKeyChar(r); r = s.peek() { + // simplified a lot here + if isSpace(r) || r == '=' { + s.emitWithValue(tokenKey, growingString) + s.skip() + return s.lexEquals + } + growingString += string(r) + s.next() + } + s.emitWithValue(tokenKey, growingString) + return s.lexEquals +} + +func (s *sshLexer) lexRvalue() sshLexStateFn { + growingString := "" + for { + next := s.peek() + switch next { + case '\r': + if s.follow("\r\n") { + s.emitWithValue(tokenString, growingString) + s.skip() + return s.lexVoid + } + case '\n': + s.emitWithValue(tokenString, growingString) + s.skip() + return s.lexVoid + case '#': + s.emitWithValue(tokenString, growingString) + s.skip() + return s.lexComment(s.lexVoid) + case eof: + s.next() + } + if next == eof { + break + } + growingString += string(next) + s.next() + } + s.emit(tokenEOF) + return nil +} + +func (s *sshLexer) read() rune { + r := s.peek() + if r == '\n' { + s.endbufferLine++ + s.endbufferCol = 1 + } else { + s.endbufferCol++ + } + s.inputIdx++ + return r +} + +func (s *sshLexer) next() rune { + r := s.read() + + if r != eof { + s.buffer = append(s.buffer, r) + } + return r +} + +func (s *sshLexer) lexVoid() sshLexStateFn { + for { + next := s.peek() + switch next { + case '#': + s.skip() + return s.lexComment(s.lexVoid) + case '\r': + fallthrough + case '\n': + s.emit(tokenEmptyLine) + s.skip() + continue + } + + if isSpace(next) { + s.skip() + } + + if isKeyStartChar(next) { + return s.lexKey + } + + // removed IsKeyStartChar and lexKey. probably will need to readd + + if next == eof { + s.next() + break + } + } + + s.emit(tokenEOF) + return nil +} + +func (s *sshLexer) ignore() { + s.buffer = make([]rune, 0) + s.line = s.endbufferLine + s.col = s.endbufferCol +} + +func (s *sshLexer) skip() { + s.next() + s.ignore() +} + +func (s *sshLexer) emit(t tokenType) { + s.emitWithValue(t, string(s.buffer)) +} + +func (s *sshLexer) emitWithValue(t tokenType, value string) { + tok := token{ + Position: Position{s.line, s.col}, + typ: t, + val: value, + } + s.tokens <- tok + s.ignore() +} + +func (s *sshLexer) peek() rune { + if s.inputIdx >= len(s.input) { + return eof + } + + r := s.input[s.inputIdx] + return r +} + +func (s *sshLexer) follow(next string) bool { + inputIdx := s.inputIdx + for _, expectedRune := range next { + if inputIdx >= len(s.input) { + return false + } + r := s.input[inputIdx] + inputIdx++ + if expectedRune != r { + return false + } + } + return true +} + +func (s *sshLexer) run() { + for state := s.lexVoid; state != nil; { + state = state() + } + close(s.tokens) +} + +func lexSSH(input []byte) chan token { + runes := bytes.Runes(input) + l := &sshLexer{ + input: runes, + tokens: make(chan token), + line: 1, + col: 1, + endbufferLine: 1, + endbufferCol: 1, + } + go l.run() + return l.tokens +} diff --git a/vendor/github.com/kevinburke/ssh_config/parser.go b/vendor/github.com/kevinburke/ssh_config/parser.go new file mode 100644 index 00000000..36c42055 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/parser.go @@ -0,0 +1,191 @@ +package ssh_config + +import ( + "fmt" + "strings" +) + +type sshParser struct { + flow chan token + config *Config + tokensBuffer []token + currentTable []string + seenTableKeys []string + // /etc/ssh parser or local parser - used to find the default for relative + // filepaths in the Include directive + system bool + depth uint8 +} + +type sshParserStateFn func() sshParserStateFn + +// Formats and panics an error message based on a token +func (p *sshParser) raiseErrorf(tok *token, msg string, args ...interface{}) { + // TODO this format is ugly + panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...)) +} + +func (p *sshParser) raiseError(tok *token, err error) { + if err == ErrDepthExceeded { + panic(err) + } + // TODO this format is ugly + panic(tok.Position.String() + ": " + err.Error()) +} + +func (p *sshParser) run() { + for state := p.parseStart; state != nil; { + state = state() + } +} + +func (p *sshParser) peek() *token { + if len(p.tokensBuffer) != 0 { + return &(p.tokensBuffer[0]) + } + + tok, ok := <-p.flow + if !ok { + return nil + } + p.tokensBuffer = append(p.tokensBuffer, tok) + return &tok +} + +func (p *sshParser) getToken() *token { + if len(p.tokensBuffer) != 0 { + tok := p.tokensBuffer[0] + p.tokensBuffer = p.tokensBuffer[1:] + return &tok + } + tok, ok := <-p.flow + if !ok { + return nil + } + return &tok +} + +func (p *sshParser) parseStart() sshParserStateFn { + tok := p.peek() + + // end of stream, parsing is finished + if tok == nil { + return nil + } + + switch tok.typ { + case tokenComment, tokenEmptyLine: + return p.parseComment + case tokenKey: + return p.parseKV + case tokenEOF: + return nil + default: + p.raiseErrorf(tok, fmt.Sprintf("unexpected token %q\n", tok)) + } + return nil +} + +func (p *sshParser) parseKV() sshParserStateFn { + key := p.getToken() + hasEquals := false + val := p.getToken() + if val.typ == tokenEquals { + hasEquals = true + val = p.getToken() + } + comment := "" + tok := p.peek() + if tok == nil { + tok = &token{typ: tokenEOF} + } + if tok.typ == tokenComment && tok.Position.Line == val.Position.Line { + tok = p.getToken() + comment = tok.val + } + if strings.ToLower(key.val) == "match" { + // https://github.com/kevinburke/ssh_config/issues/6 + p.raiseErrorf(val, "ssh_config: Match directive parsing is unsupported") + return nil + } + if strings.ToLower(key.val) == "host" { + strPatterns := strings.Split(val.val, " ") + patterns := make([]*Pattern, 0) + for i := range strPatterns { + if strPatterns[i] == "" { + continue + } + pat, err := NewPattern(strPatterns[i]) + if err != nil { + p.raiseErrorf(val, "Invalid host pattern: %v", err) + return nil + } + patterns = append(patterns, pat) + } + p.config.Hosts = append(p.config.Hosts, &Host{ + Patterns: patterns, + Nodes: make([]Node, 0), + EOLComment: comment, + hasEquals: hasEquals, + }) + return p.parseStart + } + lastHost := p.config.Hosts[len(p.config.Hosts)-1] + if strings.ToLower(key.val) == "include" { + inc, err := NewInclude(strings.Split(val.val, " "), hasEquals, key.Position, comment, p.system, p.depth+1) + if err == ErrDepthExceeded { + p.raiseError(val, err) + return nil + } + if err != nil { + p.raiseErrorf(val, "Error parsing Include directive: %v", err) + return nil + } + lastHost.Nodes = append(lastHost.Nodes, inc) + return p.parseStart + } + kv := &KV{ + Key: key.val, + Value: val.val, + Comment: comment, + hasEquals: hasEquals, + leadingSpace: key.Position.Col - 1, + position: key.Position, + } + lastHost.Nodes = append(lastHost.Nodes, kv) + return p.parseStart +} + +func (p *sshParser) parseComment() sshParserStateFn { + comment := p.getToken() + lastHost := p.config.Hosts[len(p.config.Hosts)-1] + lastHost.Nodes = append(lastHost.Nodes, &Empty{ + Comment: comment.val, + // account for the "#" as well + leadingSpace: comment.Position.Col - 2, + position: comment.Position, + }) + return p.parseStart +} + +func parseSSH(flow chan token, system bool, depth uint8) *Config { + // Ensure we consume tokens to completion even if parser exits early + defer func() { + for range flow { + } + }() + + result := newConfig() + result.position = Position{1, 1} + parser := &sshParser{ + flow: flow, + config: result, + tokensBuffer: make([]token, 0), + currentTable: make([]string, 0), + seenTableKeys: make([]string, 0), + system: system, + depth: depth, + } + parser.run() + return result +} diff --git a/vendor/github.com/kevinburke/ssh_config/position.go b/vendor/github.com/kevinburke/ssh_config/position.go new file mode 100644 index 00000000..e0b5e3fb --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/position.go @@ -0,0 +1,25 @@ +package ssh_config + +import "fmt" + +// Position of a document element within a SSH document. +// +// Line and Col are both 1-indexed positions for the element's line number and +// column number, respectively. Values of zero or less will cause Invalid(), +// to return true. +type Position struct { + Line int // line within the document + Col int // column within the line +} + +// String representation of the position. +// Displays 1-indexed line and column numbers. +func (p Position) String() string { + return fmt.Sprintf("(%d, %d)", p.Line, p.Col) +} + +// Invalid returns whether or not the position is valid (i.e. with negative or +// null values) +func (p Position) Invalid() bool { + return p.Line <= 0 || p.Col <= 0 +} diff --git a/vendor/github.com/kevinburke/ssh_config/token.go b/vendor/github.com/kevinburke/ssh_config/token.go new file mode 100644 index 00000000..a0ecbb2b --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/token.go @@ -0,0 +1,49 @@ +package ssh_config + +import "fmt" + +type token struct { + Position + typ tokenType + val string +} + +func (t token) String() string { + switch t.typ { + case tokenEOF: + return "EOF" + } + return fmt.Sprintf("%q", t.val) +} + +type tokenType int + +const ( + eof = -(iota + 1) +) + +const ( + tokenError tokenType = iota + tokenEOF + tokenEmptyLine + tokenComment + tokenKey + tokenEquals + tokenString +) + +func isSpace(r rune) bool { + return r == ' ' || r == '\t' +} + +func isKeyStartChar(r rune) bool { + return !(isSpace(r) || r == '\r' || r == '\n' || r == eof) +} + +// I'm not sure that this is correct +func isKeyChar(r rune) bool { + // Keys start with the first character that isn't whitespace or [ and end + // with the last non-whitespace character before the equals sign. Keys + // cannot contain a # character." + return !(r == '\r' || r == '\n' || r == eof || r == '=') +} diff --git a/vendor/github.com/kevinburke/ssh_config/validators.go b/vendor/github.com/kevinburke/ssh_config/validators.go new file mode 100644 index 00000000..29fab6a9 --- /dev/null +++ b/vendor/github.com/kevinburke/ssh_config/validators.go @@ -0,0 +1,162 @@ +package ssh_config + +import ( + "fmt" + "strconv" + "strings" +) + +// Default returns the default value for the given keyword, for example "22" if +// the keyword is "Port". Default returns the empty string if the keyword has no +// default, or if the keyword is unknown. Keyword matching is case-insensitive. +// +// Default values are provided by OpenSSH_7.4p1 on a Mac. +func Default(keyword string) string { + return defaults[strings.ToLower(keyword)] +} + +// Arguments where the value must be "yes" or "no" and *only* yes or no. +var yesnos = map[string]bool{ + strings.ToLower("BatchMode"): true, + strings.ToLower("CanonicalizeFallbackLocal"): true, + strings.ToLower("ChallengeResponseAuthentication"): true, + strings.ToLower("CheckHostIP"): true, + strings.ToLower("ClearAllForwardings"): true, + strings.ToLower("Compression"): true, + strings.ToLower("EnableSSHKeysign"): true, + strings.ToLower("ExitOnForwardFailure"): true, + strings.ToLower("ForwardAgent"): true, + strings.ToLower("ForwardX11"): true, + strings.ToLower("ForwardX11Trusted"): true, + strings.ToLower("GatewayPorts"): true, + strings.ToLower("GSSAPIAuthentication"): true, + strings.ToLower("GSSAPIDelegateCredentials"): true, + strings.ToLower("HostbasedAuthentication"): true, + strings.ToLower("IdentitiesOnly"): true, + strings.ToLower("KbdInteractiveAuthentication"): true, + strings.ToLower("NoHostAuthenticationForLocalhost"): true, + strings.ToLower("PasswordAuthentication"): true, + strings.ToLower("PermitLocalCommand"): true, + strings.ToLower("PubkeyAuthentication"): true, + strings.ToLower("RhostsRSAAuthentication"): true, + strings.ToLower("RSAAuthentication"): true, + strings.ToLower("StreamLocalBindUnlink"): true, + strings.ToLower("TCPKeepAlive"): true, + strings.ToLower("UseKeychain"): true, + strings.ToLower("UsePrivilegedPort"): true, + strings.ToLower("VisualHostKey"): true, +} + +var uints = map[string]bool{ + strings.ToLower("CanonicalizeMaxDots"): true, + strings.ToLower("CompressionLevel"): true, // 1 to 9 + strings.ToLower("ConnectionAttempts"): true, + strings.ToLower("ConnectTimeout"): true, + strings.ToLower("NumberOfPasswordPrompts"): true, + strings.ToLower("Port"): true, + strings.ToLower("ServerAliveCountMax"): true, + strings.ToLower("ServerAliveInterval"): true, +} + +func mustBeYesOrNo(lkey string) bool { + return yesnos[lkey] +} + +func mustBeUint(lkey string) bool { + return uints[lkey] +} + +func validate(key, val string) error { + lkey := strings.ToLower(key) + if mustBeYesOrNo(lkey) && (val != "yes" && val != "no") { + return fmt.Errorf("ssh_config: value for key %q must be 'yes' or 'no', got %q", key, val) + } + if mustBeUint(lkey) { + _, err := strconv.ParseUint(val, 10, 64) + if err != nil { + return fmt.Errorf("ssh_config: %v", err) + } + } + return nil +} + +var defaults = map[string]string{ + strings.ToLower("AddKeysToAgent"): "no", + strings.ToLower("AddressFamily"): "any", + strings.ToLower("BatchMode"): "no", + strings.ToLower("CanonicalizeFallbackLocal"): "yes", + strings.ToLower("CanonicalizeHostname"): "no", + strings.ToLower("CanonicalizeMaxDots"): "1", + strings.ToLower("ChallengeResponseAuthentication"): "yes", + strings.ToLower("CheckHostIP"): "yes", + // TODO is this still the correct cipher + strings.ToLower("Cipher"): "3des", + strings.ToLower("Ciphers"): "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc", + strings.ToLower("ClearAllForwardings"): "no", + strings.ToLower("Compression"): "no", + strings.ToLower("CompressionLevel"): "6", + strings.ToLower("ConnectionAttempts"): "1", + strings.ToLower("ControlMaster"): "no", + strings.ToLower("EnableSSHKeysign"): "no", + strings.ToLower("EscapeChar"): "~", + strings.ToLower("ExitOnForwardFailure"): "no", + strings.ToLower("FingerprintHash"): "sha256", + strings.ToLower("ForwardAgent"): "no", + strings.ToLower("ForwardX11"): "no", + strings.ToLower("ForwardX11Timeout"): "20m", + strings.ToLower("ForwardX11Trusted"): "no", + strings.ToLower("GatewayPorts"): "no", + strings.ToLower("GlobalKnownHostsFile"): "/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2", + strings.ToLower("GSSAPIAuthentication"): "no", + strings.ToLower("GSSAPIDelegateCredentials"): "no", + strings.ToLower("HashKnownHosts"): "no", + strings.ToLower("HostbasedAuthentication"): "no", + + strings.ToLower("HostbasedKeyTypes"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa", + strings.ToLower("HostKeyAlgorithms"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa", + // HostName has a dynamic default (the value passed at the command line). + + strings.ToLower("IdentitiesOnly"): "no", + strings.ToLower("IdentityFile"): "~/.ssh/identity", + + // IPQoS has a dynamic default based on interactive or non-interactive + // sessions. + + strings.ToLower("KbdInteractiveAuthentication"): "yes", + + strings.ToLower("KexAlgorithms"): "curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1", + strings.ToLower("LogLevel"): "INFO", + strings.ToLower("MACs"): "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1", + + strings.ToLower("NoHostAuthenticationForLocalhost"): "no", + strings.ToLower("NumberOfPasswordPrompts"): "3", + strings.ToLower("PasswordAuthentication"): "yes", + strings.ToLower("PermitLocalCommand"): "no", + strings.ToLower("Port"): "22", + + strings.ToLower("PreferredAuthentications"): "gssapi-with-mic,hostbased,publickey,keyboard-interactive,password", + strings.ToLower("Protocol"): "2", + strings.ToLower("ProxyUseFdpass"): "no", + strings.ToLower("PubkeyAcceptedKeyTypes"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa", + strings.ToLower("PubkeyAuthentication"): "yes", + strings.ToLower("RekeyLimit"): "default none", + strings.ToLower("RhostsRSAAuthentication"): "no", + strings.ToLower("RSAAuthentication"): "yes", + + strings.ToLower("ServerAliveCountMax"): "3", + strings.ToLower("ServerAliveInterval"): "0", + strings.ToLower("StreamLocalBindMask"): "0177", + strings.ToLower("StreamLocalBindUnlink"): "no", + strings.ToLower("StrictHostKeyChecking"): "ask", + strings.ToLower("TCPKeepAlive"): "yes", + strings.ToLower("Tunnel"): "no", + strings.ToLower("TunnelDevice"): "any:any", + strings.ToLower("UpdateHostKeys"): "no", + strings.ToLower("UseKeychain"): "no", + strings.ToLower("UsePrivilegedPort"): "no", + + strings.ToLower("UserKnownHostsFile"): "~/.ssh/known_hosts ~/.ssh/known_hosts2", + strings.ToLower("VerifyHostKeyDNS"): "no", + strings.ToLower("VisualHostKey"): "no", + strings.ToLower("XAuthLocation"): "/usr/X11R6/bin/xauth", +} diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE new file mode 100644 index 00000000..f9c841a5 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-homedir/README.md b/vendor/github.com/mitchellh/go-homedir/README.md new file mode 100644 index 00000000..d70706d5 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/README.md @@ -0,0 +1,14 @@ +# go-homedir + +This is a Go library for detecting the user's home directory without +the use of cgo, so the library can be used in cross-compilation environments. + +Usage is incredibly simple, just call `homedir.Dir()` to get the home directory +for a user, and `homedir.Expand()` to expand the `~` in a path to the home +directory. + +**Why not just use `os/user`?** The built-in `os/user` package requires +cgo on Darwin systems. This means that any Go code that uses that package +cannot cross compile. But 99% of the time the use for `os/user` is just to +retrieve the home directory, which we can do for the current user without +cgo. This library does that, enabling cross-compilation. diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go new file mode 100644 index 00000000..25378537 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go @@ -0,0 +1,167 @@ +package homedir + +import ( + "bytes" + "errors" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" +) + +// DisableCache will disable caching of the home directory. Caching is enabled +// by default. +var DisableCache bool + +var homedirCache string +var cacheLock sync.RWMutex + +// Dir returns the home directory for the executing user. +// +// This uses an OS-specific method for discovering the home directory. +// An error is returned if a home directory cannot be detected. +func Dir() (string, error) { + if !DisableCache { + cacheLock.RLock() + cached := homedirCache + cacheLock.RUnlock() + if cached != "" { + return cached, nil + } + } + + cacheLock.Lock() + defer cacheLock.Unlock() + + var result string + var err error + if runtime.GOOS == "windows" { + result, err = dirWindows() + } else { + // Unix-like system, so just assume Unix + result, err = dirUnix() + } + + if err != nil { + return "", err + } + homedirCache = result + return result, nil +} + +// Expand expands the path to include the home directory if the path +// is prefixed with `~`. If it isn't prefixed with `~`, the path is +// returned as-is. +func Expand(path string) (string, error) { + if len(path) == 0 { + return path, nil + } + + if path[0] != '~' { + return path, nil + } + + if len(path) > 1 && path[1] != '/' && path[1] != '\\' { + return "", errors.New("cannot expand user-specific home dir") + } + + dir, err := Dir() + if err != nil { + return "", err + } + + return filepath.Join(dir, path[1:]), nil +} + +// Reset clears the cache, forcing the next call to Dir to re-detect +// the home directory. This generally never has to be called, but can be +// useful in tests if you're modifying the home directory via the HOME +// env var or something. +func Reset() { + cacheLock.Lock() + defer cacheLock.Unlock() + homedirCache = "" +} + +func dirUnix() (string, error) { + homeEnv := "HOME" + if runtime.GOOS == "plan9" { + // On plan9, env vars are lowercase. + homeEnv = "home" + } + + // First prefer the HOME environmental variable + if home := os.Getenv(homeEnv); home != "" { + return home, nil + } + + var stdout bytes.Buffer + + // If that fails, try OS specific commands + if runtime.GOOS == "darwin" { + cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + result := strings.TrimSpace(stdout.String()) + if result != "" { + return result, nil + } + } + } else { + cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + // If the error is ErrNotFound, we ignore it. Otherwise, return it. + if err != exec.ErrNotFound { + return "", err + } + } else { + if passwd := strings.TrimSpace(stdout.String()); passwd != "" { + // username:password:uid:gid:gecos:home:shell + passwdParts := strings.SplitN(passwd, ":", 7) + if len(passwdParts) > 5 { + return passwdParts[5], nil + } + } + } + } + + // If all else fails, try the shell + stdout.Reset() + cmd := exec.Command("sh", "-c", "cd && pwd") + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return "", err + } + + result := strings.TrimSpace(stdout.String()) + if result == "" { + return "", errors.New("blank output when reading home directory") + } + + return result, nil +} + +func dirWindows() (string, error) { + // First prefer the HOME environmental variable + if home := os.Getenv("HOME"); home != "" { + return home, nil + } + + // Prefer standard environment variable USERPROFILE + if home := os.Getenv("USERPROFILE"); home != "" { + return home, nil + } + + drive := os.Getenv("HOMEDRIVE") + path := os.Getenv("HOMEPATH") + home := drive + path + if drive == "" || path == "" { + return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") + } + + return home, nil +} diff --git a/vendor/github.com/xanzy/ssh-agent/.gitignore b/vendor/github.com/xanzy/ssh-agent/.gitignore new file mode 100644 index 00000000..daf913b1 --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/xanzy/ssh-agent/LICENSE b/vendor/github.com/xanzy/ssh-agent/LICENSE new file mode 100644 index 00000000..8f71f43f --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/xanzy/ssh-agent/README.md b/vendor/github.com/xanzy/ssh-agent/README.md new file mode 100644 index 00000000..d93af40a --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/README.md @@ -0,0 +1,23 @@ +# ssh-agent + +Create a new [agent.Agent](https://godoc.org/golang.org/x/crypto/ssh/agent#Agent) on any type of OS (so including Windows) from any [Go](https://golang.org) application. + +## Limitations + +When compiled for Windows, it will only support [Pageant](http://the.earth.li/~sgtatham/putty/0.66/htmldoc/Chapter9.html#pageant) as the SSH authentication agent. + +## Credits + +Big thanks to [Давид Мзареулян (David Mzareulyan)](https://github.com/davidmz) for creating the [go-pageant](https://github.com/davidmz/go-pageant) package! + +## Issues + +If you have an issue: report it on the [issue tracker](https://github.com/xanzy/ssh-agent/issues) + +## Author + +Sander van Harmelen () + +## License + +The files `pageant_windows.go` and `sshagent_windows.go` have their own license (see file headers). The rest of this package is 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 diff --git a/vendor/github.com/xanzy/ssh-agent/pageant_windows.go b/vendor/github.com/xanzy/ssh-agent/pageant_windows.go new file mode 100644 index 00000000..62956079 --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/pageant_windows.go @@ -0,0 +1,146 @@ +// +// Copyright (c) 2014 David Mzareulyan +// +// 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. +// + +// +build windows + +package sshagent + +// see https://github.com/Yasushi/putty/blob/master/windows/winpgntc.c#L155 +// see https://github.com/paramiko/paramiko/blob/master/paramiko/win_pageant.py + +import ( + "encoding/binary" + "errors" + "fmt" + "sync" + "syscall" + "unsafe" +) + +// Maximum size of message can be sent to pageant +const MaxMessageLen = 8192 + +var ( + ErrPageantNotFound = errors.New("pageant process not found") + ErrSendMessage = errors.New("error sending message") + + ErrMessageTooLong = errors.New("message too long") + ErrInvalidMessageFormat = errors.New("invalid message format") + ErrResponseTooLong = errors.New("response too long") +) + +const ( + agentCopydataID = 0x804e50ba + wmCopydata = 74 +) + +type copyData struct { + dwData uintptr + cbData uint32 + lpData unsafe.Pointer +} + +var ( + lock sync.Mutex + + winFindWindow = winAPI("user32.dll", "FindWindowW") + winGetCurrentThreadID = winAPI("kernel32.dll", "GetCurrentThreadId") + winSendMessage = winAPI("user32.dll", "SendMessageW") +) + +func winAPI(dllName, funcName string) func(...uintptr) (uintptr, uintptr, error) { + proc := syscall.MustLoadDLL(dllName).MustFindProc(funcName) + return func(a ...uintptr) (uintptr, uintptr, error) { return proc.Call(a...) } +} + +// Available returns true if Pageant is running +func Available() bool { return pageantWindow() != 0 } + +// Query sends message msg to Pageant and returns response or error. +// 'msg' is raw agent request with length prefix +// Response is raw agent response with length prefix +func query(msg []byte) ([]byte, error) { + if len(msg) > MaxMessageLen { + return nil, ErrMessageTooLong + } + + msgLen := binary.BigEndian.Uint32(msg[:4]) + if len(msg) != int(msgLen)+4 { + return nil, ErrInvalidMessageFormat + } + + lock.Lock() + defer lock.Unlock() + + paWin := pageantWindow() + + if paWin == 0 { + return nil, ErrPageantNotFound + } + + thID, _, _ := winGetCurrentThreadID() + mapName := fmt.Sprintf("PageantRequest%08x", thID) + pMapName, _ := syscall.UTF16PtrFromString(mapName) + + mmap, err := syscall.CreateFileMapping(syscall.InvalidHandle, nil, syscall.PAGE_READWRITE, 0, MaxMessageLen+4, pMapName) + if err != nil { + return nil, err + } + defer syscall.CloseHandle(mmap) + + ptr, err := syscall.MapViewOfFile(mmap, syscall.FILE_MAP_WRITE, 0, 0, 0) + if err != nil { + return nil, err + } + defer syscall.UnmapViewOfFile(ptr) + + mmSlice := (*(*[MaxMessageLen]byte)(unsafe.Pointer(ptr)))[:] + + copy(mmSlice, msg) + + mapNameBytesZ := append([]byte(mapName), 0) + + cds := copyData{ + dwData: agentCopydataID, + cbData: uint32(len(mapNameBytesZ)), + lpData: unsafe.Pointer(&(mapNameBytesZ[0])), + } + + resp, _, _ := winSendMessage(paWin, wmCopydata, 0, uintptr(unsafe.Pointer(&cds))) + + if resp == 0 { + return nil, ErrSendMessage + } + + respLen := binary.BigEndian.Uint32(mmSlice[:4]) + if respLen > MaxMessageLen-4 { + return nil, ErrResponseTooLong + } + + respData := make([]byte, respLen+4) + copy(respData, mmSlice) + + return respData, nil +} + +func pageantWindow() uintptr { + nameP, _ := syscall.UTF16PtrFromString("Pageant") + h, _, _ := winFindWindow(uintptr(unsafe.Pointer(nameP)), uintptr(unsafe.Pointer(nameP))) + return h +} diff --git a/vendor/github.com/xanzy/ssh-agent/sshagent.go b/vendor/github.com/xanzy/ssh-agent/sshagent.go new file mode 100644 index 00000000..259fea2b --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/sshagent.go @@ -0,0 +1,49 @@ +// +// Copyright 2015, Sander van Harmelen +// +// 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. +// + +// +build !windows + +package sshagent + +import ( + "errors" + "fmt" + "net" + "os" + + "golang.org/x/crypto/ssh/agent" +) + +// New returns a new agent.Agent that uses a unix socket +func New() (agent.Agent, net.Conn, error) { + if !Available() { + return nil, nil, errors.New("SSH agent requested but SSH_AUTH_SOCK not-specified") + } + + sshAuthSock := os.Getenv("SSH_AUTH_SOCK") + + conn, err := net.Dial("unix", sshAuthSock) + if err != nil { + return nil, nil, fmt.Errorf("Error connecting to SSH_AUTH_SOCK: %v", err) + } + + return agent.NewClient(conn), conn, nil +} + +// Available returns true is a auth socket is defined +func Available() bool { + return os.Getenv("SSH_AUTH_SOCK") != "" +} diff --git a/vendor/github.com/xanzy/ssh-agent/sshagent_windows.go b/vendor/github.com/xanzy/ssh-agent/sshagent_windows.go new file mode 100644 index 00000000..c46710e8 --- /dev/null +++ b/vendor/github.com/xanzy/ssh-agent/sshagent_windows.go @@ -0,0 +1,80 @@ +// +// Copyright (c) 2014 David Mzareulyan +// +// 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. +// + +// +build windows + +package sshagent + +import ( + "errors" + "io" + "net" + "sync" + + "golang.org/x/crypto/ssh/agent" +) + +// New returns a new agent.Agent and the (custom) connection it uses +// to communicate with a running pagent.exe instance (see README.md) +func New() (agent.Agent, net.Conn, error) { + if !Available() { + return nil, nil, errors.New("SSH agent requested but Pageant not running") + } + + return agent.NewClient(&conn{}), nil, nil +} + +type conn struct { + sync.Mutex + buf []byte +} + +func (c *conn) Close() { + c.Lock() + defer c.Unlock() + c.buf = nil +} + +func (c *conn) Write(p []byte) (int, error) { + c.Lock() + defer c.Unlock() + + resp, err := query(p) + if err != nil { + return 0, err + } + + c.buf = append(c.buf, resp...) + + return len(p), nil +} + +func (c *conn) Read(p []byte) (int, error) { + c.Lock() + defer c.Unlock() + + if len(c.buf) == 0 { + return 0, io.EOF + } + + n := copy(p, c.buf) + c.buf = c.buf[n:] + + return n, nil +} diff --git a/vendor/golang.org/x/crypto/blowfish/block.go b/vendor/golang.org/x/crypto/blowfish/block.go new file mode 100644 index 00000000..9d80f195 --- /dev/null +++ b/vendor/golang.org/x/crypto/blowfish/block.go @@ -0,0 +1,159 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blowfish + +// getNextWord returns the next big-endian uint32 value from the byte slice +// at the given position in a circular manner, updating the position. +func getNextWord(b []byte, pos *int) uint32 { + var w uint32 + j := *pos + for i := 0; i < 4; i++ { + w = w<<8 | uint32(b[j]) + j++ + if j >= len(b) { + j = 0 + } + } + *pos = j + return w +} + +// ExpandKey performs a key expansion on the given *Cipher. Specifically, it +// performs the Blowfish algorithm's key schedule which sets up the *Cipher's +// pi and substitution tables for calls to Encrypt. This is used, primarily, +// by the bcrypt package to reuse the Blowfish key schedule during its +// set up. It's unlikely that you need to use this directly. +func ExpandKey(key []byte, c *Cipher) { + j := 0 + for i := 0; i < 18; i++ { + // Using inlined getNextWord for performance. + var d uint32 + for k := 0; k < 4; k++ { + d = d<<8 | uint32(key[j]) + j++ + if j >= len(key) { + j = 0 + } + } + c.p[i] ^= d + } + + var l, r uint32 + for i := 0; i < 18; i += 2 { + l, r = encryptBlock(l, r, c) + c.p[i], c.p[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s0[i], c.s0[i+1] = l, r + } + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s1[i], c.s1[i+1] = l, r + } + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s2[i], c.s2[i+1] = l, r + } + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s3[i], c.s3[i+1] = l, r + } +} + +// This is similar to ExpandKey, but folds the salt during the key +// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero +// salt passed in, reusing ExpandKey turns out to be a place of inefficiency +// and specializing it here is useful. +func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) { + j := 0 + for i := 0; i < 18; i++ { + c.p[i] ^= getNextWord(key, &j) + } + + j = 0 + var l, r uint32 + for i := 0; i < 18; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.p[i], c.p[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s0[i], c.s0[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s1[i], c.s1[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s2[i], c.s2[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s3[i], c.s3[i+1] = l, r + } +} + +func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { + xl, xr := l, r + xl ^= c.p[0] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16] + xr ^= c.p[17] + return xr, xl +} + +func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { + xl, xr := l, r + xl ^= c.p[17] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1] + xr ^= c.p[0] + return xr, xl +} diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go new file mode 100644 index 00000000..213bf204 --- /dev/null +++ b/vendor/golang.org/x/crypto/blowfish/cipher.go @@ -0,0 +1,99 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. +// +// Blowfish is a legacy cipher and its short block size makes it vulnerable to +// birthday bound attacks (see https://sweet32.info). It should only be used +// where compatibility with legacy systems, not security, is the goal. +// +// Deprecated: any new system should use AES (from crypto/aes, if necessary in +// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from +// golang.org/x/crypto/chacha20poly1305). +package blowfish // import "golang.org/x/crypto/blowfish" + +// The code is a port of Bruce Schneier's C implementation. +// See https://www.schneier.com/blowfish.html. + +import "strconv" + +// The Blowfish block size in bytes. +const BlockSize = 8 + +// A Cipher is an instance of Blowfish encryption using a particular key. +type Cipher struct { + p [18]uint32 + s0, s1, s2, s3 [256]uint32 +} + +type KeySizeError int + +func (k KeySizeError) Error() string { + return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k)) +} + +// NewCipher creates and returns a Cipher. +// The key argument should be the Blowfish key, from 1 to 56 bytes. +func NewCipher(key []byte) (*Cipher, error) { + var result Cipher + if k := len(key); k < 1 || k > 56 { + return nil, KeySizeError(k) + } + initCipher(&result) + ExpandKey(key, &result) + return &result, nil +} + +// NewSaltedCipher creates a returns a Cipher that folds a salt into its key +// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is +// sufficient and desirable. For bcrypt compatibility, the key can be over 56 +// bytes. +func NewSaltedCipher(key, salt []byte) (*Cipher, error) { + if len(salt) == 0 { + return NewCipher(key) + } + var result Cipher + if k := len(key); k < 1 { + return nil, KeySizeError(k) + } + initCipher(&result) + expandKeyWithSalt(key, salt, &result) + return &result, nil +} + +// BlockSize returns the Blowfish block size, 8 bytes. +// It is necessary to satisfy the Block interface in the +// package "crypto/cipher". +func (c *Cipher) BlockSize() int { return BlockSize } + +// Encrypt encrypts the 8-byte buffer src using the key k +// and stores the result in dst. +// Note that for amounts of data larger than a block, +// it is not safe to just call Encrypt on successive blocks; +// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). +func (c *Cipher) Encrypt(dst, src []byte) { + l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + l, r = encryptBlock(l, r, c) + dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) + dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) +} + +// Decrypt decrypts the 8-byte buffer src using the key k +// and stores the result in dst. +func (c *Cipher) Decrypt(dst, src []byte) { + l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + l, r = decryptBlock(l, r, c) + dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) + dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) +} + +func initCipher(c *Cipher) { + copy(c.p[0:], p[0:]) + copy(c.s0[0:], s0[0:]) + copy(c.s1[0:], s1[0:]) + copy(c.s2[0:], s2[0:]) + copy(c.s3[0:], s3[0:]) +} diff --git a/vendor/golang.org/x/crypto/blowfish/const.go b/vendor/golang.org/x/crypto/blowfish/const.go new file mode 100644 index 00000000..d0407759 --- /dev/null +++ b/vendor/golang.org/x/crypto/blowfish/const.go @@ -0,0 +1,199 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The startup permutation array and substitution boxes. +// They are the hexadecimal digits of PI; see: +// https://www.schneier.com/code/constants.txt. + +package blowfish + +var s0 = [256]uint32{ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, + 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, + 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, + 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, + 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, + 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, + 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, + 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, + 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, + 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, + 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, + 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, + 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, + 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, + 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, + 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, + 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, + 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, + 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, + 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, + 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, + 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, +} + +var s1 = [256]uint32{ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, +} + +var s2 = [256]uint32{ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, +} + +var s3 = [256]uint32{ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, +} + +var p = [18]uint32{ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b, +} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go new file mode 100644 index 00000000..94c71ac1 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go @@ -0,0 +1,17 @@ +// Copyright 2018 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. + +//go:build go1.11 && gc && !purego +// +build go1.11,gc,!purego + +package chacha20 + +const bufSize = 256 + +//go:noescape +func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) + +func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { + xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) +} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s new file mode 100644 index 00000000..63cae9e6 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s @@ -0,0 +1,308 @@ +// Copyright 2018 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. + +//go:build go1.11 && gc && !purego +// +build go1.11,gc,!purego + +#include "textflag.h" + +#define NUM_ROUNDS 10 + +// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) +TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 + MOVD dst+0(FP), R1 + MOVD src+24(FP), R2 + MOVD src_len+32(FP), R3 + MOVD key+48(FP), R4 + MOVD nonce+56(FP), R6 + MOVD counter+64(FP), R7 + + MOVD $·constants(SB), R10 + MOVD $·incRotMatrix(SB), R11 + + MOVW (R7), R20 + + AND $~255, R3, R13 + ADD R2, R13, R12 // R12 for block end + AND $255, R3, R13 +loop: + MOVD $NUM_ROUNDS, R21 + VLD1 (R11), [V30.S4, V31.S4] + + // load contants + // VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4] + WORD $0x4D60E940 + + // load keys + // VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4] + WORD $0x4DFFE884 + // VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4] + WORD $0x4DFFE888 + SUB $32, R4 + + // load counter + nonce + // VLD1R (R7), [V12.S4] + WORD $0x4D40C8EC + + // VLD3R (R6), [V13.S4, V14.S4, V15.S4] + WORD $0x4D40E8CD + + // update counter + VADD V30.S4, V12.S4, V12.S4 + +chacha: + // V0..V3 += V4..V7 + // V12..V15 <<<= ((V12..V15 XOR V0..V3), 16) + VADD V0.S4, V4.S4, V0.S4 + VADD V1.S4, V5.S4, V1.S4 + VADD V2.S4, V6.S4, V2.S4 + VADD V3.S4, V7.S4, V3.S4 + VEOR V12.B16, V0.B16, V12.B16 + VEOR V13.B16, V1.B16, V13.B16 + VEOR V14.B16, V2.B16, V14.B16 + VEOR V15.B16, V3.B16, V15.B16 + VREV32 V12.H8, V12.H8 + VREV32 V13.H8, V13.H8 + VREV32 V14.H8, V14.H8 + VREV32 V15.H8, V15.H8 + // V8..V11 += V12..V15 + // V4..V7 <<<= ((V4..V7 XOR V8..V11), 12) + VADD V8.S4, V12.S4, V8.S4 + VADD V9.S4, V13.S4, V9.S4 + VADD V10.S4, V14.S4, V10.S4 + VADD V11.S4, V15.S4, V11.S4 + VEOR V8.B16, V4.B16, V16.B16 + VEOR V9.B16, V5.B16, V17.B16 + VEOR V10.B16, V6.B16, V18.B16 + VEOR V11.B16, V7.B16, V19.B16 + VSHL $12, V16.S4, V4.S4 + VSHL $12, V17.S4, V5.S4 + VSHL $12, V18.S4, V6.S4 + VSHL $12, V19.S4, V7.S4 + VSRI $20, V16.S4, V4.S4 + VSRI $20, V17.S4, V5.S4 + VSRI $20, V18.S4, V6.S4 + VSRI $20, V19.S4, V7.S4 + + // V0..V3 += V4..V7 + // V12..V15 <<<= ((V12..V15 XOR V0..V3), 8) + VADD V0.S4, V4.S4, V0.S4 + VADD V1.S4, V5.S4, V1.S4 + VADD V2.S4, V6.S4, V2.S4 + VADD V3.S4, V7.S4, V3.S4 + VEOR V12.B16, V0.B16, V12.B16 + VEOR V13.B16, V1.B16, V13.B16 + VEOR V14.B16, V2.B16, V14.B16 + VEOR V15.B16, V3.B16, V15.B16 + VTBL V31.B16, [V12.B16], V12.B16 + VTBL V31.B16, [V13.B16], V13.B16 + VTBL V31.B16, [V14.B16], V14.B16 + VTBL V31.B16, [V15.B16], V15.B16 + + // V8..V11 += V12..V15 + // V4..V7 <<<= ((V4..V7 XOR V8..V11), 7) + VADD V12.S4, V8.S4, V8.S4 + VADD V13.S4, V9.S4, V9.S4 + VADD V14.S4, V10.S4, V10.S4 + VADD V15.S4, V11.S4, V11.S4 + VEOR V8.B16, V4.B16, V16.B16 + VEOR V9.B16, V5.B16, V17.B16 + VEOR V10.B16, V6.B16, V18.B16 + VEOR V11.B16, V7.B16, V19.B16 + VSHL $7, V16.S4, V4.S4 + VSHL $7, V17.S4, V5.S4 + VSHL $7, V18.S4, V6.S4 + VSHL $7, V19.S4, V7.S4 + VSRI $25, V16.S4, V4.S4 + VSRI $25, V17.S4, V5.S4 + VSRI $25, V18.S4, V6.S4 + VSRI $25, V19.S4, V7.S4 + + // V0..V3 += V5..V7, V4 + // V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16) + VADD V0.S4, V5.S4, V0.S4 + VADD V1.S4, V6.S4, V1.S4 + VADD V2.S4, V7.S4, V2.S4 + VADD V3.S4, V4.S4, V3.S4 + VEOR V15.B16, V0.B16, V15.B16 + VEOR V12.B16, V1.B16, V12.B16 + VEOR V13.B16, V2.B16, V13.B16 + VEOR V14.B16, V3.B16, V14.B16 + VREV32 V12.H8, V12.H8 + VREV32 V13.H8, V13.H8 + VREV32 V14.H8, V14.H8 + VREV32 V15.H8, V15.H8 + + // V10 += V15; V5 <<<= ((V10 XOR V5), 12) + // ... + VADD V15.S4, V10.S4, V10.S4 + VADD V12.S4, V11.S4, V11.S4 + VADD V13.S4, V8.S4, V8.S4 + VADD V14.S4, V9.S4, V9.S4 + VEOR V10.B16, V5.B16, V16.B16 + VEOR V11.B16, V6.B16, V17.B16 + VEOR V8.B16, V7.B16, V18.B16 + VEOR V9.B16, V4.B16, V19.B16 + VSHL $12, V16.S4, V5.S4 + VSHL $12, V17.S4, V6.S4 + VSHL $12, V18.S4, V7.S4 + VSHL $12, V19.S4, V4.S4 + VSRI $20, V16.S4, V5.S4 + VSRI $20, V17.S4, V6.S4 + VSRI $20, V18.S4, V7.S4 + VSRI $20, V19.S4, V4.S4 + + // V0 += V5; V15 <<<= ((V0 XOR V15), 8) + // ... + VADD V5.S4, V0.S4, V0.S4 + VADD V6.S4, V1.S4, V1.S4 + VADD V7.S4, V2.S4, V2.S4 + VADD V4.S4, V3.S4, V3.S4 + VEOR V0.B16, V15.B16, V15.B16 + VEOR V1.B16, V12.B16, V12.B16 + VEOR V2.B16, V13.B16, V13.B16 + VEOR V3.B16, V14.B16, V14.B16 + VTBL V31.B16, [V12.B16], V12.B16 + VTBL V31.B16, [V13.B16], V13.B16 + VTBL V31.B16, [V14.B16], V14.B16 + VTBL V31.B16, [V15.B16], V15.B16 + + // V10 += V15; V5 <<<= ((V10 XOR V5), 7) + // ... + VADD V15.S4, V10.S4, V10.S4 + VADD V12.S4, V11.S4, V11.S4 + VADD V13.S4, V8.S4, V8.S4 + VADD V14.S4, V9.S4, V9.S4 + VEOR V10.B16, V5.B16, V16.B16 + VEOR V11.B16, V6.B16, V17.B16 + VEOR V8.B16, V7.B16, V18.B16 + VEOR V9.B16, V4.B16, V19.B16 + VSHL $7, V16.S4, V5.S4 + VSHL $7, V17.S4, V6.S4 + VSHL $7, V18.S4, V7.S4 + VSHL $7, V19.S4, V4.S4 + VSRI $25, V16.S4, V5.S4 + VSRI $25, V17.S4, V6.S4 + VSRI $25, V18.S4, V7.S4 + VSRI $25, V19.S4, V4.S4 + + SUB $1, R21 + CBNZ R21, chacha + + // VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4] + WORD $0x4D60E950 + + // VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4] + WORD $0x4DFFE894 + VADD V30.S4, V12.S4, V12.S4 + VADD V16.S4, V0.S4, V0.S4 + VADD V17.S4, V1.S4, V1.S4 + VADD V18.S4, V2.S4, V2.S4 + VADD V19.S4, V3.S4, V3.S4 + // VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4] + WORD $0x4DFFE898 + // restore R4 + SUB $32, R4 + + // load counter + nonce + // VLD1R (R7), [V28.S4] + WORD $0x4D40C8FC + // VLD3R (R6), [V29.S4, V30.S4, V31.S4] + WORD $0x4D40E8DD + + VADD V20.S4, V4.S4, V4.S4 + VADD V21.S4, V5.S4, V5.S4 + VADD V22.S4, V6.S4, V6.S4 + VADD V23.S4, V7.S4, V7.S4 + VADD V24.S4, V8.S4, V8.S4 + VADD V25.S4, V9.S4, V9.S4 + VADD V26.S4, V10.S4, V10.S4 + VADD V27.S4, V11.S4, V11.S4 + VADD V28.S4, V12.S4, V12.S4 + VADD V29.S4, V13.S4, V13.S4 + VADD V30.S4, V14.S4, V14.S4 + VADD V31.S4, V15.S4, V15.S4 + + VZIP1 V1.S4, V0.S4, V16.S4 + VZIP2 V1.S4, V0.S4, V17.S4 + VZIP1 V3.S4, V2.S4, V18.S4 + VZIP2 V3.S4, V2.S4, V19.S4 + VZIP1 V5.S4, V4.S4, V20.S4 + VZIP2 V5.S4, V4.S4, V21.S4 + VZIP1 V7.S4, V6.S4, V22.S4 + VZIP2 V7.S4, V6.S4, V23.S4 + VZIP1 V9.S4, V8.S4, V24.S4 + VZIP2 V9.S4, V8.S4, V25.S4 + VZIP1 V11.S4, V10.S4, V26.S4 + VZIP2 V11.S4, V10.S4, V27.S4 + VZIP1 V13.S4, V12.S4, V28.S4 + VZIP2 V13.S4, V12.S4, V29.S4 + VZIP1 V15.S4, V14.S4, V30.S4 + VZIP2 V15.S4, V14.S4, V31.S4 + VZIP1 V18.D2, V16.D2, V0.D2 + VZIP2 V18.D2, V16.D2, V4.D2 + VZIP1 V19.D2, V17.D2, V8.D2 + VZIP2 V19.D2, V17.D2, V12.D2 + VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16] + + VZIP1 V22.D2, V20.D2, V1.D2 + VZIP2 V22.D2, V20.D2, V5.D2 + VZIP1 V23.D2, V21.D2, V9.D2 + VZIP2 V23.D2, V21.D2, V13.D2 + VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16] + VZIP1 V26.D2, V24.D2, V2.D2 + VZIP2 V26.D2, V24.D2, V6.D2 + VZIP1 V27.D2, V25.D2, V10.D2 + VZIP2 V27.D2, V25.D2, V14.D2 + VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16] + VZIP1 V30.D2, V28.D2, V3.D2 + VZIP2 V30.D2, V28.D2, V7.D2 + VZIP1 V31.D2, V29.D2, V11.D2 + VZIP2 V31.D2, V29.D2, V15.D2 + VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16] + VEOR V0.B16, V16.B16, V16.B16 + VEOR V1.B16, V17.B16, V17.B16 + VEOR V2.B16, V18.B16, V18.B16 + VEOR V3.B16, V19.B16, V19.B16 + VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1) + VEOR V4.B16, V20.B16, V20.B16 + VEOR V5.B16, V21.B16, V21.B16 + VEOR V6.B16, V22.B16, V22.B16 + VEOR V7.B16, V23.B16, V23.B16 + VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1) + VEOR V8.B16, V24.B16, V24.B16 + VEOR V9.B16, V25.B16, V25.B16 + VEOR V10.B16, V26.B16, V26.B16 + VEOR V11.B16, V27.B16, V27.B16 + VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1) + VEOR V12.B16, V28.B16, V28.B16 + VEOR V13.B16, V29.B16, V29.B16 + VEOR V14.B16, V30.B16, V30.B16 + VEOR V15.B16, V31.B16, V31.B16 + VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1) + + ADD $4, R20 + MOVW R20, (R7) // update counter + + CMP R2, R12 + BGT loop + + RET + + +DATA ·constants+0x00(SB)/4, $0x61707865 +DATA ·constants+0x04(SB)/4, $0x3320646e +DATA ·constants+0x08(SB)/4, $0x79622d32 +DATA ·constants+0x0c(SB)/4, $0x6b206574 +GLOBL ·constants(SB), NOPTR|RODATA, $32 + +DATA ·incRotMatrix+0x00(SB)/4, $0x00000000 +DATA ·incRotMatrix+0x04(SB)/4, $0x00000001 +DATA ·incRotMatrix+0x08(SB)/4, $0x00000002 +DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003 +DATA ·incRotMatrix+0x10(SB)/4, $0x02010003 +DATA ·incRotMatrix+0x14(SB)/4, $0x06050407 +DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B +DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F +GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/chacha20/chacha_generic.go new file mode 100644 index 00000000..a2ecf5c3 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_generic.go @@ -0,0 +1,398 @@ +// 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 chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms +// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01. +package chacha20 + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + "math/bits" + + "golang.org/x/crypto/internal/subtle" +) + +const ( + // KeySize is the size of the key used by this cipher, in bytes. + KeySize = 32 + + // NonceSize is the size of the nonce used with the standard variant of this + // cipher, in bytes. + // + // Note that this is too short to be safely generated at random if the same + // key is reused more than 2³² times. + NonceSize = 12 + + // NonceSizeX is the size of the nonce used with the XChaCha20 variant of + // this cipher, in bytes. + NonceSizeX = 24 +) + +// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key +// and nonce. A *Cipher implements the cipher.Stream interface. +type Cipher struct { + // The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter + // (incremented after each block), and 3 of nonce. + key [8]uint32 + counter uint32 + nonce [3]uint32 + + // The last len bytes of buf are leftover key stream bytes from the previous + // XORKeyStream invocation. The size of buf depends on how many blocks are + // computed at a time by xorKeyStreamBlocks. + buf [bufSize]byte + len int + + // overflow is set when the counter overflowed, no more blocks can be + // generated, and the next XORKeyStream call should panic. + overflow bool + + // The counter-independent results of the first round are cached after they + // are computed the first time. + precompDone bool + p1, p5, p9, p13 uint32 + p2, p6, p10, p14 uint32 + p3, p7, p11, p15 uint32 +} + +var _ cipher.Stream = (*Cipher)(nil) + +// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given +// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided, +// the XChaCha20 construction will be used. It returns an error if key or nonce +// have any other length. +// +// Note that ChaCha20, like all stream ciphers, is not authenticated and allows +// attackers to silently tamper with the plaintext. For this reason, it is more +// appropriate as a building block than as a standalone encryption mechanism. +// Instead, consider using package golang.org/x/crypto/chacha20poly1305. +func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) { + // This function is split into a wrapper so that the Cipher allocation will + // be inlined, and depending on how the caller uses the return value, won't + // escape to the heap. + c := &Cipher{} + return newUnauthenticatedCipher(c, key, nonce) +} + +func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) { + if len(key) != KeySize { + return nil, errors.New("chacha20: wrong key size") + } + if len(nonce) == NonceSizeX { + // XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a + // derived key, allowing it to operate on a nonce of 24 bytes. See + // draft-irtf-cfrg-xchacha-01, Section 2.3. + key, _ = HChaCha20(key, nonce[0:16]) + cNonce := make([]byte, NonceSize) + copy(cNonce[4:12], nonce[16:24]) + nonce = cNonce + } else if len(nonce) != NonceSize { + return nil, errors.New("chacha20: wrong nonce size") + } + + key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint + c.key = [8]uint32{ + binary.LittleEndian.Uint32(key[0:4]), + binary.LittleEndian.Uint32(key[4:8]), + binary.LittleEndian.Uint32(key[8:12]), + binary.LittleEndian.Uint32(key[12:16]), + binary.LittleEndian.Uint32(key[16:20]), + binary.LittleEndian.Uint32(key[20:24]), + binary.LittleEndian.Uint32(key[24:28]), + binary.LittleEndian.Uint32(key[28:32]), + } + c.nonce = [3]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + } + return c, nil +} + +// The constant first 4 words of the ChaCha20 state. +const ( + j0 uint32 = 0x61707865 // expa + j1 uint32 = 0x3320646e // nd 3 + j2 uint32 = 0x79622d32 // 2-by + j3 uint32 = 0x6b206574 // te k +) + +const blockSize = 64 + +// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words. +// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16 +// words each round, in columnar or diagonal groups of 4 at a time. +func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { + a += b + d ^= a + d = bits.RotateLeft32(d, 16) + c += d + b ^= c + b = bits.RotateLeft32(b, 12) + a += b + d ^= a + d = bits.RotateLeft32(d, 8) + c += d + b ^= c + b = bits.RotateLeft32(b, 7) + return a, b, c, d +} + +// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will +// behave as if (64 * counter) bytes had been encrypted so far. +// +// To prevent accidental counter reuse, SetCounter panics if counter is less +// than the current value. +// +// Note that the execution time of XORKeyStream is not independent of the +// counter value. +func (s *Cipher) SetCounter(counter uint32) { + // Internally, s may buffer multiple blocks, which complicates this + // implementation slightly. When checking whether the counter has rolled + // back, we must use both s.counter and s.len to determine how many blocks + // we have already output. + outputCounter := s.counter - uint32(s.len)/blockSize + if s.overflow || counter < outputCounter { + panic("chacha20: SetCounter attempted to rollback counter") + } + + // In the general case, we set the new counter value and reset s.len to 0, + // causing the next call to XORKeyStream to refill the buffer. However, if + // we're advancing within the existing buffer, we can save work by simply + // setting s.len. + if counter < s.counter { + s.len = int(s.counter-counter) * blockSize + } else { + s.counter = counter + s.len = 0 + } +} + +// XORKeyStream XORs each byte in the given slice with a byte from the +// cipher's key stream. Dst and src must overlap entirely or not at all. +// +// If len(dst) < len(src), XORKeyStream will panic. It is acceptable +// to pass a dst bigger than src, and in that case, XORKeyStream will +// only update dst[:len(src)] and will not touch the rest of dst. +// +// Multiple calls to XORKeyStream behave as if the concatenation of +// the src buffers was passed in a single run. That is, Cipher +// maintains state and does not reset at each XORKeyStream call. +func (s *Cipher) XORKeyStream(dst, src []byte) { + if len(src) == 0 { + return + } + if len(dst) < len(src) { + panic("chacha20: output smaller than input") + } + dst = dst[:len(src)] + if subtle.InexactOverlap(dst, src) { + panic("chacha20: invalid buffer overlap") + } + + // First, drain any remaining key stream from a previous XORKeyStream. + if s.len != 0 { + keyStream := s.buf[bufSize-s.len:] + if len(src) < len(keyStream) { + keyStream = keyStream[:len(src)] + } + _ = src[len(keyStream)-1] // bounds check elimination hint + for i, b := range keyStream { + dst[i] = src[i] ^ b + } + s.len -= len(keyStream) + dst, src = dst[len(keyStream):], src[len(keyStream):] + } + if len(src) == 0 { + return + } + + // If we'd need to let the counter overflow and keep generating output, + // panic immediately. If instead we'd only reach the last block, remember + // not to generate any more output after the buffer is drained. + numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize + if s.overflow || uint64(s.counter)+numBlocks > 1<<32 { + panic("chacha20: counter overflow") + } else if uint64(s.counter)+numBlocks == 1<<32 { + s.overflow = true + } + + // xorKeyStreamBlocks implementations expect input lengths that are a + // multiple of bufSize. Platform-specific ones process multiple blocks at a + // time, so have bufSizes that are a multiple of blockSize. + + full := len(src) - len(src)%bufSize + if full > 0 { + s.xorKeyStreamBlocks(dst[:full], src[:full]) + } + dst, src = dst[full:], src[full:] + + // If using a multi-block xorKeyStreamBlocks would overflow, use the generic + // one that does one block at a time. + const blocksPerBuf = bufSize / blockSize + if uint64(s.counter)+blocksPerBuf > 1<<32 { + s.buf = [bufSize]byte{} + numBlocks := (len(src) + blockSize - 1) / blockSize + buf := s.buf[bufSize-numBlocks*blockSize:] + copy(buf, src) + s.xorKeyStreamBlocksGeneric(buf, buf) + s.len = len(buf) - copy(dst, buf) + return + } + + // If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and + // keep the leftover keystream for the next XORKeyStream invocation. + if len(src) > 0 { + s.buf = [bufSize]byte{} + copy(s.buf[:], src) + s.xorKeyStreamBlocks(s.buf[:], s.buf[:]) + s.len = bufSize - copy(dst, s.buf[:]) + } +} + +func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) { + if len(dst) != len(src) || len(dst)%blockSize != 0 { + panic("chacha20: internal error: wrong dst and/or src length") + } + + // To generate each block of key stream, the initial cipher state + // (represented below) is passed through 20 rounds of shuffling, + // alternatively applying quarterRounds by columns (like 1, 5, 9, 13) + // or by diagonals (like 1, 6, 11, 12). + // + // 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc + // 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk + // 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk + // 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn + // + // c=constant k=key b=blockcount n=nonce + var ( + c0, c1, c2, c3 = j0, j1, j2, j3 + c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3] + c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7] + _, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2] + ) + + // Three quarters of the first round don't depend on the counter, so we can + // calculate them here, and reuse them for multiple blocks in the loop, and + // for future XORKeyStream invocations. + if !s.precompDone { + s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13) + s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14) + s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15) + s.precompDone = true + } + + // A condition of len(src) > 0 would be sufficient, but this also + // acts as a bounds check elimination hint. + for len(src) >= 64 && len(dst) >= 64 { + // The remainder of the first column round. + fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter) + + // The second diagonal round. + x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15) + x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12) + x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13) + x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14) + + // The remaining 18 rounds. + for i := 0; i < 9; i++ { + // Column round. + x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) + x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) + x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) + x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) + + // Diagonal round. + x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) + x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) + x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) + x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) + } + + // Add back the initial state to generate the key stream, then + // XOR the key stream with the source and write out the result. + addXor(dst[0:4], src[0:4], x0, c0) + addXor(dst[4:8], src[4:8], x1, c1) + addXor(dst[8:12], src[8:12], x2, c2) + addXor(dst[12:16], src[12:16], x3, c3) + addXor(dst[16:20], src[16:20], x4, c4) + addXor(dst[20:24], src[20:24], x5, c5) + addXor(dst[24:28], src[24:28], x6, c6) + addXor(dst[28:32], src[28:32], x7, c7) + addXor(dst[32:36], src[32:36], x8, c8) + addXor(dst[36:40], src[36:40], x9, c9) + addXor(dst[40:44], src[40:44], x10, c10) + addXor(dst[44:48], src[44:48], x11, c11) + addXor(dst[48:52], src[48:52], x12, s.counter) + addXor(dst[52:56], src[52:56], x13, c13) + addXor(dst[56:60], src[56:60], x14, c14) + addXor(dst[60:64], src[60:64], x15, c15) + + s.counter += 1 + + src, dst = src[blockSize:], dst[blockSize:] + } +} + +// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes +// key and a 16 bytes nonce. It returns an error if key or nonce have any other +// length. It is used as part of the XChaCha20 construction. +func HChaCha20(key, nonce []byte) ([]byte, error) { + // This function is split into a wrapper so that the slice allocation will + // be inlined, and depending on how the caller uses the return value, won't + // escape to the heap. + out := make([]byte, 32) + return hChaCha20(out, key, nonce) +} + +func hChaCha20(out, key, nonce []byte) ([]byte, error) { + if len(key) != KeySize { + return nil, errors.New("chacha20: wrong HChaCha20 key size") + } + if len(nonce) != 16 { + return nil, errors.New("chacha20: wrong HChaCha20 nonce size") + } + + x0, x1, x2, x3 := j0, j1, j2, j3 + x4 := binary.LittleEndian.Uint32(key[0:4]) + x5 := binary.LittleEndian.Uint32(key[4:8]) + x6 := binary.LittleEndian.Uint32(key[8:12]) + x7 := binary.LittleEndian.Uint32(key[12:16]) + x8 := binary.LittleEndian.Uint32(key[16:20]) + x9 := binary.LittleEndian.Uint32(key[20:24]) + x10 := binary.LittleEndian.Uint32(key[24:28]) + x11 := binary.LittleEndian.Uint32(key[28:32]) + x12 := binary.LittleEndian.Uint32(nonce[0:4]) + x13 := binary.LittleEndian.Uint32(nonce[4:8]) + x14 := binary.LittleEndian.Uint32(nonce[8:12]) + x15 := binary.LittleEndian.Uint32(nonce[12:16]) + + for i := 0; i < 10; i++ { + // Diagonal round. + x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) + x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) + x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) + x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) + + // Column round. + x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) + x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) + x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) + x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) + } + + _ = out[31] // bounds check elimination hint + binary.LittleEndian.PutUint32(out[0:4], x0) + binary.LittleEndian.PutUint32(out[4:8], x1) + binary.LittleEndian.PutUint32(out[8:12], x2) + binary.LittleEndian.PutUint32(out[12:16], x3) + binary.LittleEndian.PutUint32(out[16:20], x12) + binary.LittleEndian.PutUint32(out[20:24], x13) + binary.LittleEndian.PutUint32(out[24:28], x14) + binary.LittleEndian.PutUint32(out[28:32], x15) + return out, nil +} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go new file mode 100644 index 00000000..025b4989 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go @@ -0,0 +1,14 @@ +// Copyright 2018 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. + +//go:build (!arm64 && !s390x && !ppc64le) || (arm64 && !go1.11) || !gc || purego +// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego + +package chacha20 + +const bufSize = blockSize + +func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) { + s.xorKeyStreamBlocksGeneric(dst, src) +} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go new file mode 100644 index 00000000..da420b2e --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go @@ -0,0 +1,17 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego +// +build gc,!purego + +package chacha20 + +const bufSize = 256 + +//go:noescape +func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) + +func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { + chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter) +} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s new file mode 100644 index 00000000..5c0fed26 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s @@ -0,0 +1,450 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Based on CRYPTOGAMS code with the following comment: +// # ==================================================================== +// # Written by Andy Polyakov for the OpenSSL +// # project. The module is, however, dual licensed under OpenSSL and +// # CRYPTOGAMS licenses depending on where you obtain it. For further +// # details see http://www.openssl.org/~appro/cryptogams/. +// # ==================================================================== + +// Code for the perl script that generates the ppc64 assembler +// can be found in the cryptogams repository at the link below. It is based on +// the original from openssl. + +// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91 + +// The differences in this and the original implementation are +// due to the calling conventions and initialization of constants. + +//go:build gc && !purego +// +build gc,!purego + +#include "textflag.h" + +#define OUT R3 +#define INP R4 +#define LEN R5 +#define KEY R6 +#define CNT R7 +#define TMP R15 + +#define CONSTBASE R16 +#define BLOCKS R17 + +DATA consts<>+0x00(SB)/8, $0x3320646e61707865 +DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 +DATA consts<>+0x10(SB)/8, $0x0000000000000001 +DATA consts<>+0x18(SB)/8, $0x0000000000000000 +DATA consts<>+0x20(SB)/8, $0x0000000000000004 +DATA consts<>+0x28(SB)/8, $0x0000000000000000 +DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d +DATA consts<>+0x38(SB)/8, $0x0203000106070405 +DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c +DATA consts<>+0x48(SB)/8, $0x0102030005060704 +DATA consts<>+0x50(SB)/8, $0x6170786561707865 +DATA consts<>+0x58(SB)/8, $0x6170786561707865 +DATA consts<>+0x60(SB)/8, $0x3320646e3320646e +DATA consts<>+0x68(SB)/8, $0x3320646e3320646e +DATA consts<>+0x70(SB)/8, $0x79622d3279622d32 +DATA consts<>+0x78(SB)/8, $0x79622d3279622d32 +DATA consts<>+0x80(SB)/8, $0x6b2065746b206574 +DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 +DATA consts<>+0x90(SB)/8, $0x0000000100000000 +DATA consts<>+0x98(SB)/8, $0x0000000300000002 +GLOBL consts<>(SB), RODATA, $0xa0 + +//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) +TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 + MOVD out+0(FP), OUT + MOVD inp+8(FP), INP + MOVD len+16(FP), LEN + MOVD key+24(FP), KEY + MOVD counter+32(FP), CNT + + // Addressing for constants + MOVD $consts<>+0x00(SB), CONSTBASE + MOVD $16, R8 + MOVD $32, R9 + MOVD $48, R10 + MOVD $64, R11 + SRD $6, LEN, BLOCKS + // V16 + LXVW4X (CONSTBASE)(R0), VS48 + ADD $80,CONSTBASE + + // Load key into V17,V18 + LXVW4X (KEY)(R0), VS49 + LXVW4X (KEY)(R8), VS50 + + // Load CNT, NONCE into V19 + LXVW4X (CNT)(R0), VS51 + + // Clear V27 + VXOR V27, V27, V27 + + // V28 + LXVW4X (CONSTBASE)(R11), VS60 + + // splat slot from V19 -> V26 + VSPLTW $0, V19, V26 + + VSLDOI $4, V19, V27, V19 + VSLDOI $12, V27, V19, V19 + + VADDUWM V26, V28, V26 + + MOVD $10, R14 + MOVD R14, CTR + +loop_outer_vsx: + // V0, V1, V2, V3 + LXVW4X (R0)(CONSTBASE), VS32 + LXVW4X (R8)(CONSTBASE), VS33 + LXVW4X (R9)(CONSTBASE), VS34 + LXVW4X (R10)(CONSTBASE), VS35 + + // splat values from V17, V18 into V4-V11 + VSPLTW $0, V17, V4 + VSPLTW $1, V17, V5 + VSPLTW $2, V17, V6 + VSPLTW $3, V17, V7 + VSPLTW $0, V18, V8 + VSPLTW $1, V18, V9 + VSPLTW $2, V18, V10 + VSPLTW $3, V18, V11 + + // VOR + VOR V26, V26, V12 + + // splat values from V19 -> V13, V14, V15 + VSPLTW $1, V19, V13 + VSPLTW $2, V19, V14 + VSPLTW $3, V19, V15 + + // splat const values + VSPLTISW $-16, V27 + VSPLTISW $12, V28 + VSPLTISW $8, V29 + VSPLTISW $7, V30 + +loop_vsx: + VADDUWM V0, V4, V0 + VADDUWM V1, V5, V1 + VADDUWM V2, V6, V2 + VADDUWM V3, V7, V3 + + VXOR V12, V0, V12 + VXOR V13, V1, V13 + VXOR V14, V2, V14 + VXOR V15, V3, V15 + + VRLW V12, V27, V12 + VRLW V13, V27, V13 + VRLW V14, V27, V14 + VRLW V15, V27, V15 + + VADDUWM V8, V12, V8 + VADDUWM V9, V13, V9 + VADDUWM V10, V14, V10 + VADDUWM V11, V15, V11 + + VXOR V4, V8, V4 + VXOR V5, V9, V5 + VXOR V6, V10, V6 + VXOR V7, V11, V7 + + VRLW V4, V28, V4 + VRLW V5, V28, V5 + VRLW V6, V28, V6 + VRLW V7, V28, V7 + + VADDUWM V0, V4, V0 + VADDUWM V1, V5, V1 + VADDUWM V2, V6, V2 + VADDUWM V3, V7, V3 + + VXOR V12, V0, V12 + VXOR V13, V1, V13 + VXOR V14, V2, V14 + VXOR V15, V3, V15 + + VRLW V12, V29, V12 + VRLW V13, V29, V13 + VRLW V14, V29, V14 + VRLW V15, V29, V15 + + VADDUWM V8, V12, V8 + VADDUWM V9, V13, V9 + VADDUWM V10, V14, V10 + VADDUWM V11, V15, V11 + + VXOR V4, V8, V4 + VXOR V5, V9, V5 + VXOR V6, V10, V6 + VXOR V7, V11, V7 + + VRLW V4, V30, V4 + VRLW V5, V30, V5 + VRLW V6, V30, V6 + VRLW V7, V30, V7 + + VADDUWM V0, V5, V0 + VADDUWM V1, V6, V1 + VADDUWM V2, V7, V2 + VADDUWM V3, V4, V3 + + VXOR V15, V0, V15 + VXOR V12, V1, V12 + VXOR V13, V2, V13 + VXOR V14, V3, V14 + + VRLW V15, V27, V15 + VRLW V12, V27, V12 + VRLW V13, V27, V13 + VRLW V14, V27, V14 + + VADDUWM V10, V15, V10 + VADDUWM V11, V12, V11 + VADDUWM V8, V13, V8 + VADDUWM V9, V14, V9 + + VXOR V5, V10, V5 + VXOR V6, V11, V6 + VXOR V7, V8, V7 + VXOR V4, V9, V4 + + VRLW V5, V28, V5 + VRLW V6, V28, V6 + VRLW V7, V28, V7 + VRLW V4, V28, V4 + + VADDUWM V0, V5, V0 + VADDUWM V1, V6, V1 + VADDUWM V2, V7, V2 + VADDUWM V3, V4, V3 + + VXOR V15, V0, V15 + VXOR V12, V1, V12 + VXOR V13, V2, V13 + VXOR V14, V3, V14 + + VRLW V15, V29, V15 + VRLW V12, V29, V12 + VRLW V13, V29, V13 + VRLW V14, V29, V14 + + VADDUWM V10, V15, V10 + VADDUWM V11, V12, V11 + VADDUWM V8, V13, V8 + VADDUWM V9, V14, V9 + + VXOR V5, V10, V5 + VXOR V6, V11, V6 + VXOR V7, V8, V7 + VXOR V4, V9, V4 + + VRLW V5, V30, V5 + VRLW V6, V30, V6 + VRLW V7, V30, V7 + VRLW V4, V30, V4 + BC 16, LT, loop_vsx + + VADDUWM V12, V26, V12 + + WORD $0x13600F8C // VMRGEW V0, V1, V27 + WORD $0x13821F8C // VMRGEW V2, V3, V28 + + WORD $0x10000E8C // VMRGOW V0, V1, V0 + WORD $0x10421E8C // VMRGOW V2, V3, V2 + + WORD $0x13A42F8C // VMRGEW V4, V5, V29 + WORD $0x13C63F8C // VMRGEW V6, V7, V30 + + XXPERMDI VS32, VS34, $0, VS33 + XXPERMDI VS32, VS34, $3, VS35 + XXPERMDI VS59, VS60, $0, VS32 + XXPERMDI VS59, VS60, $3, VS34 + + WORD $0x10842E8C // VMRGOW V4, V5, V4 + WORD $0x10C63E8C // VMRGOW V6, V7, V6 + + WORD $0x13684F8C // VMRGEW V8, V9, V27 + WORD $0x138A5F8C // VMRGEW V10, V11, V28 + + XXPERMDI VS36, VS38, $0, VS37 + XXPERMDI VS36, VS38, $3, VS39 + XXPERMDI VS61, VS62, $0, VS36 + XXPERMDI VS61, VS62, $3, VS38 + + WORD $0x11084E8C // VMRGOW V8, V9, V8 + WORD $0x114A5E8C // VMRGOW V10, V11, V10 + + WORD $0x13AC6F8C // VMRGEW V12, V13, V29 + WORD $0x13CE7F8C // VMRGEW V14, V15, V30 + + XXPERMDI VS40, VS42, $0, VS41 + XXPERMDI VS40, VS42, $3, VS43 + XXPERMDI VS59, VS60, $0, VS40 + XXPERMDI VS59, VS60, $3, VS42 + + WORD $0x118C6E8C // VMRGOW V12, V13, V12 + WORD $0x11CE7E8C // VMRGOW V14, V15, V14 + + VSPLTISW $4, V27 + VADDUWM V26, V27, V26 + + XXPERMDI VS44, VS46, $0, VS45 + XXPERMDI VS44, VS46, $3, VS47 + XXPERMDI VS61, VS62, $0, VS44 + XXPERMDI VS61, VS62, $3, VS46 + + VADDUWM V0, V16, V0 + VADDUWM V4, V17, V4 + VADDUWM V8, V18, V8 + VADDUWM V12, V19, V12 + + CMPU LEN, $64 + BLT tail_vsx + + // Bottom of loop + LXVW4X (INP)(R0), VS59 + LXVW4X (INP)(R8), VS60 + LXVW4X (INP)(R9), VS61 + LXVW4X (INP)(R10), VS62 + + VXOR V27, V0, V27 + VXOR V28, V4, V28 + VXOR V29, V8, V29 + VXOR V30, V12, V30 + + STXVW4X VS59, (OUT)(R0) + STXVW4X VS60, (OUT)(R8) + ADD $64, INP + STXVW4X VS61, (OUT)(R9) + ADD $-64, LEN + STXVW4X VS62, (OUT)(R10) + ADD $64, OUT + BEQ done_vsx + + VADDUWM V1, V16, V0 + VADDUWM V5, V17, V4 + VADDUWM V9, V18, V8 + VADDUWM V13, V19, V12 + + CMPU LEN, $64 + BLT tail_vsx + + LXVW4X (INP)(R0), VS59 + LXVW4X (INP)(R8), VS60 + LXVW4X (INP)(R9), VS61 + LXVW4X (INP)(R10), VS62 + VXOR V27, V0, V27 + + VXOR V28, V4, V28 + VXOR V29, V8, V29 + VXOR V30, V12, V30 + + STXVW4X VS59, (OUT)(R0) + STXVW4X VS60, (OUT)(R8) + ADD $64, INP + STXVW4X VS61, (OUT)(R9) + ADD $-64, LEN + STXVW4X VS62, (OUT)(V10) + ADD $64, OUT + BEQ done_vsx + + VADDUWM V2, V16, V0 + VADDUWM V6, V17, V4 + VADDUWM V10, V18, V8 + VADDUWM V14, V19, V12 + + CMPU LEN, $64 + BLT tail_vsx + + LXVW4X (INP)(R0), VS59 + LXVW4X (INP)(R8), VS60 + LXVW4X (INP)(R9), VS61 + LXVW4X (INP)(R10), VS62 + + VXOR V27, V0, V27 + VXOR V28, V4, V28 + VXOR V29, V8, V29 + VXOR V30, V12, V30 + + STXVW4X VS59, (OUT)(R0) + STXVW4X VS60, (OUT)(R8) + ADD $64, INP + STXVW4X VS61, (OUT)(R9) + ADD $-64, LEN + STXVW4X VS62, (OUT)(R10) + ADD $64, OUT + BEQ done_vsx + + VADDUWM V3, V16, V0 + VADDUWM V7, V17, V4 + VADDUWM V11, V18, V8 + VADDUWM V15, V19, V12 + + CMPU LEN, $64 + BLT tail_vsx + + LXVW4X (INP)(R0), VS59 + LXVW4X (INP)(R8), VS60 + LXVW4X (INP)(R9), VS61 + LXVW4X (INP)(R10), VS62 + + VXOR V27, V0, V27 + VXOR V28, V4, V28 + VXOR V29, V8, V29 + VXOR V30, V12, V30 + + STXVW4X VS59, (OUT)(R0) + STXVW4X VS60, (OUT)(R8) + ADD $64, INP + STXVW4X VS61, (OUT)(R9) + ADD $-64, LEN + STXVW4X VS62, (OUT)(R10) + ADD $64, OUT + + MOVD $10, R14 + MOVD R14, CTR + BNE loop_outer_vsx + +done_vsx: + // Increment counter by number of 64 byte blocks + MOVD (CNT), R14 + ADD BLOCKS, R14 + MOVD R14, (CNT) + RET + +tail_vsx: + ADD $32, R1, R11 + MOVD LEN, CTR + + // Save values on stack to copy from + STXVW4X VS32, (R11)(R0) + STXVW4X VS36, (R11)(R8) + STXVW4X VS40, (R11)(R9) + STXVW4X VS44, (R11)(R10) + ADD $-1, R11, R12 + ADD $-1, INP + ADD $-1, OUT + +looptail_vsx: + // Copying the result to OUT + // in bytes. + MOVBZU 1(R12), KEY + MOVBZU 1(INP), TMP + XOR KEY, TMP, KEY + MOVBU KEY, 1(OUT) + BC 16, LT, looptail_vsx + + // Clear the stack values + STXVW4X VS48, (R11)(R0) + STXVW4X VS48, (R11)(R8) + STXVW4X VS48, (R11)(R9) + STXVW4X VS48, (R11)(R10) + BR done_vsx diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go new file mode 100644 index 00000000..4652247b --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go @@ -0,0 +1,28 @@ +// Copyright 2018 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. + +//go:build gc && !purego +// +build gc,!purego + +package chacha20 + +import "golang.org/x/sys/cpu" + +var haveAsm = cpu.S390X.HasVX + +const bufSize = 256 + +// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only +// be called when the vector facility is available. Implementation in asm_s390x.s. +// +//go:noescape +func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) + +func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) { + if cpu.S390X.HasVX { + xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) + } else { + c.xorKeyStreamBlocksGeneric(dst, src) + } +} diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s new file mode 100644 index 00000000..f3ef5a01 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s @@ -0,0 +1,225 @@ +// Copyright 2018 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. + +//go:build gc && !purego +// +build gc,!purego + +#include "go_asm.h" +#include "textflag.h" + +// This is an implementation of the ChaCha20 encryption algorithm as +// specified in RFC 7539. It uses vector instructions to compute +// 4 keystream blocks in parallel (256 bytes) which are then XORed +// with the bytes in the input slice. + +GLOBL ·constants<>(SB), RODATA|NOPTR, $32 +// BSWAP: swap bytes in each 4-byte element +DATA ·constants<>+0x00(SB)/4, $0x03020100 +DATA ·constants<>+0x04(SB)/4, $0x07060504 +DATA ·constants<>+0x08(SB)/4, $0x0b0a0908 +DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c +// J0: [j0, j1, j2, j3] +DATA ·constants<>+0x10(SB)/4, $0x61707865 +DATA ·constants<>+0x14(SB)/4, $0x3320646e +DATA ·constants<>+0x18(SB)/4, $0x79622d32 +DATA ·constants<>+0x1c(SB)/4, $0x6b206574 + +#define BSWAP V5 +#define J0 V6 +#define KEY0 V7 +#define KEY1 V8 +#define NONCE V9 +#define CTR V10 +#define M0 V11 +#define M1 V12 +#define M2 V13 +#define M3 V14 +#define INC V15 +#define X0 V16 +#define X1 V17 +#define X2 V18 +#define X3 V19 +#define X4 V20 +#define X5 V21 +#define X6 V22 +#define X7 V23 +#define X8 V24 +#define X9 V25 +#define X10 V26 +#define X11 V27 +#define X12 V28 +#define X13 V29 +#define X14 V30 +#define X15 V31 + +#define NUM_ROUNDS 20 + +#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \ + VAF a1, a0, a0 \ + VAF b1, b0, b0 \ + VAF c1, c0, c0 \ + VAF d1, d0, d0 \ + VX a0, a2, a2 \ + VX b0, b2, b2 \ + VX c0, c2, c2 \ + VX d0, d2, d2 \ + VERLLF $16, a2, a2 \ + VERLLF $16, b2, b2 \ + VERLLF $16, c2, c2 \ + VERLLF $16, d2, d2 \ + VAF a2, a3, a3 \ + VAF b2, b3, b3 \ + VAF c2, c3, c3 \ + VAF d2, d3, d3 \ + VX a3, a1, a1 \ + VX b3, b1, b1 \ + VX c3, c1, c1 \ + VX d3, d1, d1 \ + VERLLF $12, a1, a1 \ + VERLLF $12, b1, b1 \ + VERLLF $12, c1, c1 \ + VERLLF $12, d1, d1 \ + VAF a1, a0, a0 \ + VAF b1, b0, b0 \ + VAF c1, c0, c0 \ + VAF d1, d0, d0 \ + VX a0, a2, a2 \ + VX b0, b2, b2 \ + VX c0, c2, c2 \ + VX d0, d2, d2 \ + VERLLF $8, a2, a2 \ + VERLLF $8, b2, b2 \ + VERLLF $8, c2, c2 \ + VERLLF $8, d2, d2 \ + VAF a2, a3, a3 \ + VAF b2, b3, b3 \ + VAF c2, c3, c3 \ + VAF d2, d3, d3 \ + VX a3, a1, a1 \ + VX b3, b1, b1 \ + VX c3, c1, c1 \ + VX d3, d1, d1 \ + VERLLF $7, a1, a1 \ + VERLLF $7, b1, b1 \ + VERLLF $7, c1, c1 \ + VERLLF $7, d1, d1 + +#define PERMUTE(mask, v0, v1, v2, v3) \ + VPERM v0, v0, mask, v0 \ + VPERM v1, v1, mask, v1 \ + VPERM v2, v2, mask, v2 \ + VPERM v3, v3, mask, v3 + +#define ADDV(x, v0, v1, v2, v3) \ + VAF x, v0, v0 \ + VAF x, v1, v1 \ + VAF x, v2, v2 \ + VAF x, v3, v3 + +#define XORV(off, dst, src, v0, v1, v2, v3) \ + VLM off(src), M0, M3 \ + PERMUTE(BSWAP, v0, v1, v2, v3) \ + VX v0, M0, M0 \ + VX v1, M1, M1 \ + VX v2, M2, M2 \ + VX v3, M3, M3 \ + VSTM M0, M3, off(dst) + +#define SHUFFLE(a, b, c, d, t, u, v, w) \ + VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]} + VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]} + VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]} + VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]} + VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]} + VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]} + VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]} + VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]} + +// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) +TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 + MOVD $·constants<>(SB), R1 + MOVD dst+0(FP), R2 // R2=&dst[0] + LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src) + MOVD key+48(FP), R5 // R5=key + MOVD nonce+56(FP), R6 // R6=nonce + MOVD counter+64(FP), R7 // R7=counter + + // load BSWAP and J0 + VLM (R1), BSWAP, J0 + + // setup + MOVD $95, R0 + VLM (R5), KEY0, KEY1 + VLL R0, (R6), NONCE + VZERO M0 + VLEIB $7, $32, M0 + VSRLB M0, NONCE, NONCE + + // initialize counter values + VLREPF (R7), CTR + VZERO INC + VLEIF $1, $1, INC + VLEIF $2, $2, INC + VLEIF $3, $3, INC + VAF INC, CTR, CTR + VREPIF $4, INC + +chacha: + VREPF $0, J0, X0 + VREPF $1, J0, X1 + VREPF $2, J0, X2 + VREPF $3, J0, X3 + VREPF $0, KEY0, X4 + VREPF $1, KEY0, X5 + VREPF $2, KEY0, X6 + VREPF $3, KEY0, X7 + VREPF $0, KEY1, X8 + VREPF $1, KEY1, X9 + VREPF $2, KEY1, X10 + VREPF $3, KEY1, X11 + VLR CTR, X12 + VREPF $1, NONCE, X13 + VREPF $2, NONCE, X14 + VREPF $3, NONCE, X15 + + MOVD $(NUM_ROUNDS/2), R1 + +loop: + ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11) + ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9) + + ADD $-1, R1 + BNE loop + + // decrement length + ADD $-256, R4 + + // rearrange vectors + SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3) + ADDV(J0, X0, X1, X2, X3) + SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3) + ADDV(KEY0, X4, X5, X6, X7) + SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3) + ADDV(KEY1, X8, X9, X10, X11) + VAF CTR, X12, X12 + SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3) + ADDV(NONCE, X12, X13, X14, X15) + + // increment counters + VAF INC, CTR, CTR + + // xor keystream with plaintext + XORV(0*64, R2, R3, X0, X4, X8, X12) + XORV(1*64, R2, R3, X1, X5, X9, X13) + XORV(2*64, R2, R3, X2, X6, X10, X14) + XORV(3*64, R2, R3, X3, X7, X11, X15) + + // increment pointers + MOVD $256(R2), R2 + MOVD $256(R3), R3 + + CMPBNE R4, $0, chacha + + VSTEF $0, CTR, (R7) + RET diff --git a/vendor/golang.org/x/crypto/chacha20/xor.go b/vendor/golang.org/x/crypto/chacha20/xor.go new file mode 100644 index 00000000..c2d04851 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20/xor.go @@ -0,0 +1,42 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found src the LICENSE file. + +package chacha20 + +import "runtime" + +// Platforms that have fast unaligned 32-bit little endian accesses. +const unaligned = runtime.GOARCH == "386" || + runtime.GOARCH == "amd64" || + runtime.GOARCH == "arm64" || + runtime.GOARCH == "ppc64le" || + runtime.GOARCH == "s390x" + +// addXor reads a little endian uint32 from src, XORs it with (a + b) and +// places the result in little endian byte order in dst. +func addXor(dst, src []byte, a, b uint32) { + _, _ = src[3], dst[3] // bounds check elimination hint + if unaligned { + // The compiler should optimize this code into + // 32-bit unaligned little endian loads and stores. + // TODO: delete once the compiler does a reliably + // good job with the generic code below. + // See issue #25111 for more details. + v := uint32(src[0]) + v |= uint32(src[1]) << 8 + v |= uint32(src[2]) << 16 + v |= uint32(src[3]) << 24 + v ^= a + b + dst[0] = byte(v) + dst[1] = byte(v >> 8) + dst[2] = byte(v >> 16) + dst[3] = byte(v >> 24) + } else { + a += b + dst[0] = src[0] ^ byte(a) + dst[1] = src[1] ^ byte(a>>8) + dst[2] = src[2] ^ byte(a>>16) + dst[3] = src[3] ^ byte(a>>24) + } +} diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go new file mode 100644 index 00000000..bc62161d --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go @@ -0,0 +1,146 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package curve25519 provides an implementation of the X25519 function, which +// performs scalar multiplication on the elliptic curve known as Curve25519. +// See RFC 7748. +package curve25519 // import "golang.org/x/crypto/curve25519" + +import ( + "crypto/subtle" + "errors" + "strconv" + + "golang.org/x/crypto/curve25519/internal/field" +) + +// ScalarMult sets dst to the product scalar * point. +// +// Deprecated: when provided a low-order point, ScalarMult will set dst to all +// zeroes, irrespective of the scalar. Instead, use the X25519 function, which +// will return an error. +func ScalarMult(dst, scalar, point *[32]byte) { + var e [32]byte + + copy(e[:], scalar[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element + x1.SetBytes(point[:]) + x2.One() + x3.Set(&x1) + z3.One() + + swap := 0 + for pos := 254; pos >= 0; pos-- { + b := e[pos/8] >> uint(pos&7) + b &= 1 + swap ^= int(b) + x2.Swap(&x3, swap) + z2.Swap(&z3, swap) + swap = int(b) + + tmp0.Subtract(&x3, &z3) + tmp1.Subtract(&x2, &z2) + x2.Add(&x2, &z2) + z2.Add(&x3, &z3) + z3.Multiply(&tmp0, &x2) + z2.Multiply(&z2, &tmp1) + tmp0.Square(&tmp1) + tmp1.Square(&x2) + x3.Add(&z3, &z2) + z2.Subtract(&z3, &z2) + x2.Multiply(&tmp1, &tmp0) + tmp1.Subtract(&tmp1, &tmp0) + z2.Square(&z2) + + z3.Mult32(&tmp1, 121666) + x3.Square(&x3) + tmp0.Add(&tmp0, &z3) + z3.Multiply(&x1, &z2) + z2.Multiply(&tmp1, &tmp0) + } + + x2.Swap(&x3, swap) + z2.Swap(&z3, swap) + + z2.Invert(&z2) + x2.Multiply(&x2, &z2) + copy(dst[:], x2.Bytes()) +} + +// ScalarBaseMult sets dst to the product scalar * base where base is the +// standard generator. +// +// It is recommended to use the X25519 function with Basepoint instead, as +// copying into fixed size arrays can lead to unexpected bugs. +func ScalarBaseMult(dst, scalar *[32]byte) { + ScalarMult(dst, scalar, &basePoint) +} + +const ( + // ScalarSize is the size of the scalar input to X25519. + ScalarSize = 32 + // PointSize is the size of the point input to X25519. + PointSize = 32 +) + +// Basepoint is the canonical Curve25519 generator. +var Basepoint []byte + +var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +func init() { Basepoint = basePoint[:] } + +func checkBasepoint() { + if subtle.ConstantTimeCompare(Basepoint, []byte{ + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }) != 1 { + panic("curve25519: global Basepoint value was modified") + } +} + +// X25519 returns the result of the scalar multiplication (scalar * point), +// according to RFC 7748, Section 5. scalar, point and the return value are +// slices of 32 bytes. +// +// scalar can be generated at random, for example with crypto/rand. point should +// be either Basepoint or the output of another X25519 call. +// +// If point is Basepoint (but not if it's a different slice with the same +// contents) a precomputed implementation might be used for performance. +func X25519(scalar, point []byte) ([]byte, error) { + // Outline the body of function, to let the allocation be inlined in the + // caller, and possibly avoid escaping to the heap. + var dst [32]byte + return x25519(&dst, scalar, point) +} + +func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) { + var in [32]byte + if l := len(scalar); l != 32 { + return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32") + } + if l := len(point); l != 32 { + return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32") + } + copy(in[:], scalar) + if &point[0] == &Basepoint[0] { + checkBasepoint() + ScalarBaseMult(dst, &in) + } else { + var base, zero [32]byte + copy(base[:], point) + ScalarMult(dst, &in, &base) + if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 { + return nil, errors.New("bad input point: low order point") + } + } + return dst[:], nil +} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/README b/vendor/golang.org/x/crypto/curve25519/internal/field/README new file mode 100644 index 00000000..e25bca7d --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/README @@ -0,0 +1,7 @@ +This package is kept in sync with crypto/ed25519/internal/edwards25519/field in +the standard library. + +If there are any changes in the standard library that need to be synced to this +package, run sync.sh. It will not overwrite any local changes made since the +previous sync, so it's ok to land changes in this package first, and then sync +to the standard library later. diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go new file mode 100644 index 00000000..ca841ad9 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go @@ -0,0 +1,416 @@ +// Copyright (c) 2017 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 field implements fast arithmetic modulo 2^255-19. +package field + +import ( + "crypto/subtle" + "encoding/binary" + "math/bits" +) + +// Element represents an element of the field GF(2^255-19). Note that this +// is not a cryptographically secure group, and should only be used to interact +// with edwards25519.Point coordinates. +// +// This type works similarly to math/big.Int, and all arguments and receivers +// are allowed to alias. +// +// The zero value is a valid zero element. +type Element struct { + // An element t represents the integer + // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204 + // + // Between operations, all limbs are expected to be lower than 2^52. + l0 uint64 + l1 uint64 + l2 uint64 + l3 uint64 + l4 uint64 +} + +const maskLow51Bits uint64 = (1 << 51) - 1 + +var feZero = &Element{0, 0, 0, 0, 0} + +// Zero sets v = 0, and returns v. +func (v *Element) Zero() *Element { + *v = *feZero + return v +} + +var feOne = &Element{1, 0, 0, 0, 0} + +// One sets v = 1, and returns v. +func (v *Element) One() *Element { + *v = *feOne + return v +} + +// reduce reduces v modulo 2^255 - 19 and returns it. +func (v *Element) reduce() *Element { + v.carryPropagate() + + // After the light reduction we now have a field element representation + // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19. + + // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1, + // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise. + c := (v.l0 + 19) >> 51 + c = (v.l1 + c) >> 51 + c = (v.l2 + c) >> 51 + c = (v.l3 + c) >> 51 + c = (v.l4 + c) >> 51 + + // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's + // effectively applying the reduction identity to the carry. + v.l0 += 19 * c + + v.l1 += v.l0 >> 51 + v.l0 = v.l0 & maskLow51Bits + v.l2 += v.l1 >> 51 + v.l1 = v.l1 & maskLow51Bits + v.l3 += v.l2 >> 51 + v.l2 = v.l2 & maskLow51Bits + v.l4 += v.l3 >> 51 + v.l3 = v.l3 & maskLow51Bits + // no additional carry + v.l4 = v.l4 & maskLow51Bits + + return v +} + +// Add sets v = a + b, and returns v. +func (v *Element) Add(a, b *Element) *Element { + v.l0 = a.l0 + b.l0 + v.l1 = a.l1 + b.l1 + v.l2 = a.l2 + b.l2 + v.l3 = a.l3 + b.l3 + v.l4 = a.l4 + b.l4 + // Using the generic implementation here is actually faster than the + // assembly. Probably because the body of this function is so simple that + // the compiler can figure out better optimizations by inlining the carry + // propagation. TODO + return v.carryPropagateGeneric() +} + +// Subtract sets v = a - b, and returns v. +func (v *Element) Subtract(a, b *Element) *Element { + // We first add 2 * p, to guarantee the subtraction won't underflow, and + // then subtract b (which can be up to 2^255 + 2^13 * 19). + v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0 + v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1 + v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2 + v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3 + v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4 + return v.carryPropagate() +} + +// Negate sets v = -a, and returns v. +func (v *Element) Negate(a *Element) *Element { + return v.Subtract(feZero, a) +} + +// Invert sets v = 1/z mod p, and returns v. +// +// If z == 0, Invert returns v = 0. +func (v *Element) Invert(z *Element) *Element { + // Inversion is implemented as exponentiation with exponent p − 2. It uses the + // same sequence of 255 squarings and 11 multiplications as [Curve25519]. + var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element + + z2.Square(z) // 2 + t.Square(&z2) // 4 + t.Square(&t) // 8 + z9.Multiply(&t, z) // 9 + z11.Multiply(&z9, &z2) // 11 + t.Square(&z11) // 22 + z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 + + t.Square(&z2_5_0) // 2^6 - 2^1 + for i := 0; i < 4; i++ { + t.Square(&t) // 2^10 - 2^5 + } + z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 + + t.Square(&z2_10_0) // 2^11 - 2^1 + for i := 0; i < 9; i++ { + t.Square(&t) // 2^20 - 2^10 + } + z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 + + t.Square(&z2_20_0) // 2^21 - 2^1 + for i := 0; i < 19; i++ { + t.Square(&t) // 2^40 - 2^20 + } + t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 + + t.Square(&t) // 2^41 - 2^1 + for i := 0; i < 9; i++ { + t.Square(&t) // 2^50 - 2^10 + } + z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 + + t.Square(&z2_50_0) // 2^51 - 2^1 + for i := 0; i < 49; i++ { + t.Square(&t) // 2^100 - 2^50 + } + z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 + + t.Square(&z2_100_0) // 2^101 - 2^1 + for i := 0; i < 99; i++ { + t.Square(&t) // 2^200 - 2^100 + } + t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 + + t.Square(&t) // 2^201 - 2^1 + for i := 0; i < 49; i++ { + t.Square(&t) // 2^250 - 2^50 + } + t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 + + t.Square(&t) // 2^251 - 2^1 + t.Square(&t) // 2^252 - 2^2 + t.Square(&t) // 2^253 - 2^3 + t.Square(&t) // 2^254 - 2^4 + t.Square(&t) // 2^255 - 2^5 + + return v.Multiply(&t, &z11) // 2^255 - 21 +} + +// Set sets v = a, and returns v. +func (v *Element) Set(a *Element) *Element { + *v = *a + return v +} + +// SetBytes sets v to x, which must be a 32-byte little-endian encoding. +// +// Consistent with RFC 7748, the most significant bit (the high bit of the +// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1) +// are accepted. Note that this is laxer than specified by RFC 8032. +func (v *Element) SetBytes(x []byte) *Element { + if len(x) != 32 { + panic("edwards25519: invalid field element input size") + } + + // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). + v.l0 = binary.LittleEndian.Uint64(x[0:8]) + v.l0 &= maskLow51Bits + // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). + v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 + v.l1 &= maskLow51Bits + // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). + v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 + v.l2 &= maskLow51Bits + // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). + v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 + v.l3 &= maskLow51Bits + // Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51). + // Note: not bytes 25:33, shift 4, to avoid overread. + v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 + v.l4 &= maskLow51Bits + + return v +} + +// Bytes returns the canonical 32-byte little-endian encoding of v. +func (v *Element) Bytes() []byte { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. + var out [32]byte + return v.bytes(&out) +} + +func (v *Element) bytes(out *[32]byte) []byte { + t := *v + t.reduce() + + var buf [8]byte + for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { + bitsOffset := i * 51 + binary.LittleEndian.PutUint64(buf[:], l<= len(out) { + break + } + out[off] |= bb + } + } + + return out[:] +} + +// Equal returns 1 if v and u are equal, and 0 otherwise. +func (v *Element) Equal(u *Element) int { + sa, sv := u.Bytes(), v.Bytes() + return subtle.ConstantTimeCompare(sa, sv) +} + +// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise. +func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) } + +// Select sets v to a if cond == 1, and to b if cond == 0. +func (v *Element) Select(a, b *Element, cond int) *Element { + m := mask64Bits(cond) + v.l0 = (m & a.l0) | (^m & b.l0) + v.l1 = (m & a.l1) | (^m & b.l1) + v.l2 = (m & a.l2) | (^m & b.l2) + v.l3 = (m & a.l3) | (^m & b.l3) + v.l4 = (m & a.l4) | (^m & b.l4) + return v +} + +// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v. +func (v *Element) Swap(u *Element, cond int) { + m := mask64Bits(cond) + t := m & (v.l0 ^ u.l0) + v.l0 ^= t + u.l0 ^= t + t = m & (v.l1 ^ u.l1) + v.l1 ^= t + u.l1 ^= t + t = m & (v.l2 ^ u.l2) + v.l2 ^= t + u.l2 ^= t + t = m & (v.l3 ^ u.l3) + v.l3 ^= t + u.l3 ^= t + t = m & (v.l4 ^ u.l4) + v.l4 ^= t + u.l4 ^= t +} + +// IsNegative returns 1 if v is negative, and 0 otherwise. +func (v *Element) IsNegative() int { + return int(v.Bytes()[0] & 1) +} + +// Absolute sets v to |u|, and returns v. +func (v *Element) Absolute(u *Element) *Element { + return v.Select(new(Element).Negate(u), u, u.IsNegative()) +} + +// Multiply sets v = x * y, and returns v. +func (v *Element) Multiply(x, y *Element) *Element { + feMul(v, x, y) + return v +} + +// Square sets v = x * x, and returns v. +func (v *Element) Square(x *Element) *Element { + feSquare(v, x) + return v +} + +// Mult32 sets v = x * y, and returns v. +func (v *Element) Mult32(x *Element, y uint32) *Element { + x0lo, x0hi := mul51(x.l0, y) + x1lo, x1hi := mul51(x.l1, y) + x2lo, x2hi := mul51(x.l2, y) + x3lo, x3hi := mul51(x.l3, y) + x4lo, x4hi := mul51(x.l4, y) + v.l0 = x0lo + 19*x4hi // carried over per the reduction identity + v.l1 = x1lo + x0hi + v.l2 = x2lo + x1hi + v.l3 = x3lo + x2hi + v.l4 = x4lo + x3hi + // The hi portions are going to be only 32 bits, plus any previous excess, + // so we can skip the carry propagation. + return v +} + +// mul51 returns lo + hi * 2⁵¹ = a * b. +func mul51(a uint64, b uint32) (lo uint64, hi uint64) { + mh, ml := bits.Mul64(a, uint64(b)) + lo = ml & maskLow51Bits + hi = (mh << 13) | (ml >> 51) + return +} + +// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3. +func (v *Element) Pow22523(x *Element) *Element { + var t0, t1, t2 Element + + t0.Square(x) // x^2 + t1.Square(&t0) // x^4 + t1.Square(&t1) // x^8 + t1.Multiply(x, &t1) // x^9 + t0.Multiply(&t0, &t1) // x^11 + t0.Square(&t0) // x^22 + t0.Multiply(&t1, &t0) // x^31 + t1.Square(&t0) // x^62 + for i := 1; i < 5; i++ { // x^992 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 + t1.Square(&t0) // 2^11 - 2 + for i := 1; i < 10; i++ { // 2^20 - 2^10 + t1.Square(&t1) + } + t1.Multiply(&t1, &t0) // 2^20 - 1 + t2.Square(&t1) // 2^21 - 2 + for i := 1; i < 20; i++ { // 2^40 - 2^20 + t2.Square(&t2) + } + t1.Multiply(&t2, &t1) // 2^40 - 1 + t1.Square(&t1) // 2^41 - 2 + for i := 1; i < 10; i++ { // 2^50 - 2^10 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // 2^50 - 1 + t1.Square(&t0) // 2^51 - 2 + for i := 1; i < 50; i++ { // 2^100 - 2^50 + t1.Square(&t1) + } + t1.Multiply(&t1, &t0) // 2^100 - 1 + t2.Square(&t1) // 2^101 - 2 + for i := 1; i < 100; i++ { // 2^200 - 2^100 + t2.Square(&t2) + } + t1.Multiply(&t2, &t1) // 2^200 - 1 + t1.Square(&t1) // 2^201 - 2 + for i := 1; i < 50; i++ { // 2^250 - 2^50 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // 2^250 - 1 + t0.Square(&t0) // 2^251 - 2 + t0.Square(&t0) // 2^252 - 4 + return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) +} + +// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. +var sqrtM1 = &Element{1718705420411056, 234908883556509, + 2233514472574048, 2117202627021982, 765476049583133} + +// SqrtRatio sets r to the non-negative square root of the ratio of u and v. +// +// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio +// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, +// and returns r and 0. +func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) { + var a, b Element + + // r = (u * v3) * (u * v7)^((p-5)/8) + v2 := a.Square(v) + uv3 := b.Multiply(u, b.Multiply(v2, v)) + uv7 := a.Multiply(uv3, a.Square(v2)) + r.Multiply(uv3, r.Pow22523(uv7)) + + check := a.Multiply(v, a.Square(r)) // check = v * r^2 + + uNeg := b.Negate(u) + correctSignSqrt := check.Equal(u) + flippedSignSqrt := check.Equal(uNeg) + flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1)) + + rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r + // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) + r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI) + + r.Absolute(r) // Choose the nonnegative square root. + return r, correctSignSqrt | flippedSignSqrt +} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go new file mode 100644 index 00000000..edcf163c --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go @@ -0,0 +1,16 @@ +// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. + +//go:build amd64 && gc && !purego +// +build amd64,gc,!purego + +package field + +// feMul sets out = a * b. It works like feMulGeneric. +// +//go:noescape +func feMul(out *Element, a *Element, b *Element) + +// feSquare sets out = a * a. It works like feSquareGeneric. +// +//go:noescape +func feSquare(out *Element, a *Element) diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s new file mode 100644 index 00000000..293f013c --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s @@ -0,0 +1,379 @@ +// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. + +//go:build amd64 && gc && !purego +// +build amd64,gc,!purego + +#include "textflag.h" + +// func feMul(out *Element, a *Element, b *Element) +TEXT ·feMul(SB), NOSPLIT, $0-24 + MOVQ a+8(FP), CX + MOVQ b+16(FP), BX + + // r0 = a0×b0 + MOVQ (CX), AX + MULQ (BX) + MOVQ AX, DI + MOVQ DX, SI + + // r0 += 19×a1×b4 + MOVQ 8(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r0 += 19×a2×b3 + MOVQ 16(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r0 += 19×a3×b2 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 16(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r0 += 19×a4×b1 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 8(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r1 = a0×b1 + MOVQ (CX), AX + MULQ 8(BX) + MOVQ AX, R9 + MOVQ DX, R8 + + // r1 += a1×b0 + MOVQ 8(CX), AX + MULQ (BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r1 += 19×a2×b4 + MOVQ 16(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r1 += 19×a3×b3 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r1 += 19×a4×b2 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 16(BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r2 = a0×b2 + MOVQ (CX), AX + MULQ 16(BX) + MOVQ AX, R11 + MOVQ DX, R10 + + // r2 += a1×b1 + MOVQ 8(CX), AX + MULQ 8(BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r2 += a2×b0 + MOVQ 16(CX), AX + MULQ (BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r2 += 19×a3×b4 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r2 += 19×a4×b3 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r3 = a0×b3 + MOVQ (CX), AX + MULQ 24(BX) + MOVQ AX, R13 + MOVQ DX, R12 + + // r3 += a1×b2 + MOVQ 8(CX), AX + MULQ 16(BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r3 += a2×b1 + MOVQ 16(CX), AX + MULQ 8(BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r3 += a3×b0 + MOVQ 24(CX), AX + MULQ (BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r3 += 19×a4×b4 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r4 = a0×b4 + MOVQ (CX), AX + MULQ 32(BX) + MOVQ AX, R15 + MOVQ DX, R14 + + // r4 += a1×b3 + MOVQ 8(CX), AX + MULQ 24(BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // r4 += a2×b2 + MOVQ 16(CX), AX + MULQ 16(BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // r4 += a3×b1 + MOVQ 24(CX), AX + MULQ 8(BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // r4 += a4×b0 + MOVQ 32(CX), AX + MULQ (BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // First reduction chain + MOVQ $0x0007ffffffffffff, AX + SHLQ $0x0d, DI, SI + SHLQ $0x0d, R9, R8 + SHLQ $0x0d, R11, R10 + SHLQ $0x0d, R13, R12 + SHLQ $0x0d, R15, R14 + ANDQ AX, DI + IMUL3Q $0x13, R14, R14 + ADDQ R14, DI + ANDQ AX, R9 + ADDQ SI, R9 + ANDQ AX, R11 + ADDQ R8, R11 + ANDQ AX, R13 + ADDQ R10, R13 + ANDQ AX, R15 + ADDQ R12, R15 + + // Second reduction chain (carryPropagate) + MOVQ DI, SI + SHRQ $0x33, SI + MOVQ R9, R8 + SHRQ $0x33, R8 + MOVQ R11, R10 + SHRQ $0x33, R10 + MOVQ R13, R12 + SHRQ $0x33, R12 + MOVQ R15, R14 + SHRQ $0x33, R14 + ANDQ AX, DI + IMUL3Q $0x13, R14, R14 + ADDQ R14, DI + ANDQ AX, R9 + ADDQ SI, R9 + ANDQ AX, R11 + ADDQ R8, R11 + ANDQ AX, R13 + ADDQ R10, R13 + ANDQ AX, R15 + ADDQ R12, R15 + + // Store output + MOVQ out+0(FP), AX + MOVQ DI, (AX) + MOVQ R9, 8(AX) + MOVQ R11, 16(AX) + MOVQ R13, 24(AX) + MOVQ R15, 32(AX) + RET + +// func feSquare(out *Element, a *Element) +TEXT ·feSquare(SB), NOSPLIT, $0-16 + MOVQ a+8(FP), CX + + // r0 = l0×l0 + MOVQ (CX), AX + MULQ (CX) + MOVQ AX, SI + MOVQ DX, BX + + // r0 += 38×l1×l4 + MOVQ 8(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 32(CX) + ADDQ AX, SI + ADCQ DX, BX + + // r0 += 38×l2×l3 + MOVQ 16(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 24(CX) + ADDQ AX, SI + ADCQ DX, BX + + // r1 = 2×l0×l1 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 8(CX) + MOVQ AX, R8 + MOVQ DX, DI + + // r1 += 38×l2×l4 + MOVQ 16(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 32(CX) + ADDQ AX, R8 + ADCQ DX, DI + + // r1 += 19×l3×l3 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(CX) + ADDQ AX, R8 + ADCQ DX, DI + + // r2 = 2×l0×l2 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 16(CX) + MOVQ AX, R10 + MOVQ DX, R9 + + // r2 += l1×l1 + MOVQ 8(CX), AX + MULQ 8(CX) + ADDQ AX, R10 + ADCQ DX, R9 + + // r2 += 38×l3×l4 + MOVQ 24(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 32(CX) + ADDQ AX, R10 + ADCQ DX, R9 + + // r3 = 2×l0×l3 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 24(CX) + MOVQ AX, R12 + MOVQ DX, R11 + + // r3 += 2×l1×l2 + MOVQ 8(CX), AX + IMUL3Q $0x02, AX, AX + MULQ 16(CX) + ADDQ AX, R12 + ADCQ DX, R11 + + // r3 += 19×l4×l4 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(CX) + ADDQ AX, R12 + ADCQ DX, R11 + + // r4 = 2×l0×l4 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 32(CX) + MOVQ AX, R14 + MOVQ DX, R13 + + // r4 += 2×l1×l3 + MOVQ 8(CX), AX + IMUL3Q $0x02, AX, AX + MULQ 24(CX) + ADDQ AX, R14 + ADCQ DX, R13 + + // r4 += l2×l2 + MOVQ 16(CX), AX + MULQ 16(CX) + ADDQ AX, R14 + ADCQ DX, R13 + + // First reduction chain + MOVQ $0x0007ffffffffffff, AX + SHLQ $0x0d, SI, BX + SHLQ $0x0d, R8, DI + SHLQ $0x0d, R10, R9 + SHLQ $0x0d, R12, R11 + SHLQ $0x0d, R14, R13 + ANDQ AX, SI + IMUL3Q $0x13, R13, R13 + ADDQ R13, SI + ANDQ AX, R8 + ADDQ BX, R8 + ANDQ AX, R10 + ADDQ DI, R10 + ANDQ AX, R12 + ADDQ R9, R12 + ANDQ AX, R14 + ADDQ R11, R14 + + // Second reduction chain (carryPropagate) + MOVQ SI, BX + SHRQ $0x33, BX + MOVQ R8, DI + SHRQ $0x33, DI + MOVQ R10, R9 + SHRQ $0x33, R9 + MOVQ R12, R11 + SHRQ $0x33, R11 + MOVQ R14, R13 + SHRQ $0x33, R13 + ANDQ AX, SI + IMUL3Q $0x13, R13, R13 + ADDQ R13, SI + ANDQ AX, R8 + ADDQ BX, R8 + ANDQ AX, R10 + ADDQ DI, R10 + ANDQ AX, R12 + ADDQ R9, R12 + ANDQ AX, R14 + ADDQ R11, R14 + + // Store output + MOVQ out+0(FP), AX + MOVQ SI, (AX) + MOVQ R8, 8(AX) + MOVQ R10, 16(AX) + MOVQ R12, 24(AX) + MOVQ R14, 32(AX) + RET diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go new file mode 100644 index 00000000..ddb6c9b8 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go @@ -0,0 +1,12 @@ +// Copyright (c) 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || !gc || purego +// +build !amd64 !gc purego + +package field + +func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } + +func feSquare(v, x *Element) { feSquareGeneric(v, x) } diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go new file mode 100644 index 00000000..af459ef5 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go @@ -0,0 +1,16 @@ +// Copyright (c) 2020 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. + +//go:build arm64 && gc && !purego +// +build arm64,gc,!purego + +package field + +//go:noescape +func carryPropagate(v *Element) + +func (v *Element) carryPropagate() *Element { + carryPropagate(v) + return v +} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s new file mode 100644 index 00000000..5c91e458 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s @@ -0,0 +1,43 @@ +// Copyright (c) 2020 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. + +//go:build arm64 && gc && !purego +// +build arm64,gc,!purego + +#include "textflag.h" + +// carryPropagate works exactly like carryPropagateGeneric and uses the +// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but +// avoids loading R0-R4 twice and uses LDP and STP. +// +// See https://golang.org/issues/43145 for the main compiler issue. +// +// func carryPropagate(v *Element) +TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8 + MOVD v+0(FP), R20 + + LDP 0(R20), (R0, R1) + LDP 16(R20), (R2, R3) + MOVD 32(R20), R4 + + AND $0x7ffffffffffff, R0, R10 + AND $0x7ffffffffffff, R1, R11 + AND $0x7ffffffffffff, R2, R12 + AND $0x7ffffffffffff, R3, R13 + AND $0x7ffffffffffff, R4, R14 + + ADD R0>>51, R11, R11 + ADD R1>>51, R12, R12 + ADD R2>>51, R13, R13 + ADD R3>>51, R14, R14 + // R4>>51 * 19 + R10 -> R10 + LSR $51, R4, R21 + MOVD $19, R22 + MADD R22, R10, R21, R10 + + STP (R10, R11), 0(R20) + STP (R12, R13), 16(R20) + MOVD R14, 32(R20) + + RET diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go new file mode 100644 index 00000000..234a5b2e --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go @@ -0,0 +1,12 @@ +// Copyright (c) 2021 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. + +//go:build !arm64 || !gc || purego +// +build !arm64 !gc purego + +package field + +func (v *Element) carryPropagate() *Element { + return v.carryPropagateGeneric() +} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go new file mode 100644 index 00000000..7b5b78cb --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go @@ -0,0 +1,264 @@ +// Copyright (c) 2017 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 field + +import "math/bits" + +// uint128 holds a 128-bit number as two 64-bit limbs, for use with the +// bits.Mul64 and bits.Add64 intrinsics. +type uint128 struct { + lo, hi uint64 +} + +// mul64 returns a * b. +func mul64(a, b uint64) uint128 { + hi, lo := bits.Mul64(a, b) + return uint128{lo, hi} +} + +// addMul64 returns v + a * b. +func addMul64(v uint128, a, b uint64) uint128 { + hi, lo := bits.Mul64(a, b) + lo, c := bits.Add64(lo, v.lo, 0) + hi, _ = bits.Add64(hi, v.hi, c) + return uint128{lo, hi} +} + +// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. +func shiftRightBy51(a uint128) uint64 { + return (a.hi << (64 - 51)) | (a.lo >> 51) +} + +func feMulGeneric(v, a, b *Element) { + a0 := a.l0 + a1 := a.l1 + a2 := a.l2 + a3 := a.l3 + a4 := a.l4 + + b0 := b.l0 + b1 := b.l1 + b2 := b.l2 + b3 := b.l3 + b4 := b.l4 + + // Limb multiplication works like pen-and-paper columnar multiplication, but + // with 51-bit limbs instead of digits. + // + // a4 a3 a2 a1 a0 x + // b4 b3 b2 b1 b0 = + // ------------------------ + // a4b0 a3b0 a2b0 a1b0 a0b0 + + // a4b1 a3b1 a2b1 a1b1 a0b1 + + // a4b2 a3b2 a2b2 a1b2 a0b2 + + // a4b3 a3b3 a2b3 a1b3 a0b3 + + // a4b4 a3b4 a2b4 a1b4 a0b4 = + // ---------------------------------------------- + // r8 r7 r6 r5 r4 r3 r2 r1 r0 + // + // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to + // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5, + // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc. + // + // Reduction can be carried out simultaneously to multiplication. For + // example, we do not compute r5: whenever the result of a multiplication + // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0. + // + // a4b0 a3b0 a2b0 a1b0 a0b0 + + // a3b1 a2b1 a1b1 a0b1 19×a4b1 + + // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 + + // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 + + // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 = + // -------------------------------------- + // r4 r3 r2 r1 r0 + // + // Finally we add up the columns into wide, overlapping limbs. + + a1_19 := a1 * 19 + a2_19 := a2 * 19 + a3_19 := a3 * 19 + a4_19 := a4 * 19 + + // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) + r0 := mul64(a0, b0) + r0 = addMul64(r0, a1_19, b4) + r0 = addMul64(r0, a2_19, b3) + r0 = addMul64(r0, a3_19, b2) + r0 = addMul64(r0, a4_19, b1) + + // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2) + r1 := mul64(a0, b1) + r1 = addMul64(r1, a1, b0) + r1 = addMul64(r1, a2_19, b4) + r1 = addMul64(r1, a3_19, b3) + r1 = addMul64(r1, a4_19, b2) + + // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3) + r2 := mul64(a0, b2) + r2 = addMul64(r2, a1, b1) + r2 = addMul64(r2, a2, b0) + r2 = addMul64(r2, a3_19, b4) + r2 = addMul64(r2, a4_19, b3) + + // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4 + r3 := mul64(a0, b3) + r3 = addMul64(r3, a1, b2) + r3 = addMul64(r3, a2, b1) + r3 = addMul64(r3, a3, b0) + r3 = addMul64(r3, a4_19, b4) + + // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 + r4 := mul64(a0, b4) + r4 = addMul64(r4, a1, b3) + r4 = addMul64(r4, a2, b2) + r4 = addMul64(r4, a3, b1) + r4 = addMul64(r4, a4, b0) + + // After the multiplication, we need to reduce (carry) the five coefficients + // to obtain a result with limbs that are at most slightly larger than 2⁵¹, + // to respect the Element invariant. + // + // Overall, the reduction works the same as carryPropagate, except with + // wider inputs: we take the carry for each coefficient by shifting it right + // by 51, and add it to the limb above it. The top carry is multiplied by 19 + // according to the reduction identity and added to the lowest limb. + // + // The largest coefficient (r0) will be at most 111 bits, which guarantees + // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64. + // + // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) + // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²) + // r0 < (1 + 19 × 4) × 2⁵² × 2⁵² + // r0 < 2⁷ × 2⁵² × 2⁵² + // r0 < 2¹¹¹ + // + // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most + // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and + // allows us to easily apply the reduction identity. + // + // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 + // r4 < 5 × 2⁵² × 2⁵² + // r4 < 2¹⁰⁷ + // + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + c4*19 + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + // Now all coefficients fit into 64-bit registers but are still too large to + // be passed around as a Element. We therefore do one last carry chain, + // where the carries will be small enough to fit in the wiggle room above 2⁵¹. + *v = Element{rr0, rr1, rr2, rr3, rr4} + v.carryPropagate() +} + +func feSquareGeneric(v, a *Element) { + l0 := a.l0 + l1 := a.l1 + l2 := a.l2 + l3 := a.l3 + l4 := a.l4 + + // Squaring works precisely like multiplication above, but thanks to its + // symmetry we get to group a few terms together. + // + // l4 l3 l2 l1 l0 x + // l4 l3 l2 l1 l0 = + // ------------------------ + // l4l0 l3l0 l2l0 l1l0 l0l0 + + // l4l1 l3l1 l2l1 l1l1 l0l1 + + // l4l2 l3l2 l2l2 l1l2 l0l2 + + // l4l3 l3l3 l2l3 l1l3 l0l3 + + // l4l4 l3l4 l2l4 l1l4 l0l4 = + // ---------------------------------------------- + // r8 r7 r6 r5 r4 r3 r2 r1 r0 + // + // l4l0 l3l0 l2l0 l1l0 l0l0 + + // l3l1 l2l1 l1l1 l0l1 19×l4l1 + + // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 + + // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 + + // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 = + // -------------------------------------- + // r4 r3 r2 r1 r0 + // + // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with + // only three Mul64 and four Add64, instead of five and eight. + + l0_2 := l0 * 2 + l1_2 := l1 * 2 + + l1_38 := l1 * 38 + l2_38 := l2 * 38 + l3_38 := l3 * 38 + + l3_19 := l3 * 19 + l4_19 := l4 * 19 + + // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3) + r0 := mul64(l0, l0) + r0 = addMul64(r0, l1_38, l4) + r0 = addMul64(r0, l2_38, l3) + + // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 + r1 := mul64(l0_2, l1) + r1 = addMul64(r1, l2_38, l4) + r1 = addMul64(r1, l3_19, l3) + + // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4 + r2 := mul64(l0_2, l2) + r2 = addMul64(r2, l1, l1) + r2 = addMul64(r2, l3_38, l4) + + // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 + r3 := mul64(l0_2, l3) + r3 = addMul64(r3, l1_2, l2) + r3 = addMul64(r3, l4_19, l4) + + // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2 + r4 := mul64(l0_2, l4) + r4 = addMul64(r4, l1_2, l3) + r4 = addMul64(r4, l2, l2) + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + c4*19 + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + *v = Element{rr0, rr1, rr2, rr3, rr4} + v.carryPropagate() +} + +// carryPropagate brings the limbs below 52 bits by applying the reduction +// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. TODO inline +func (v *Element) carryPropagateGeneric() *Element { + c0 := v.l0 >> 51 + c1 := v.l1 >> 51 + c2 := v.l2 >> 51 + c3 := v.l3 >> 51 + c4 := v.l4 >> 51 + + v.l0 = v.l0&maskLow51Bits + c4*19 + v.l1 = v.l1&maskLow51Bits + c0 + v.l2 = v.l2&maskLow51Bits + c1 + v.l3 = v.l3&maskLow51Bits + c2 + v.l4 = v.l4&maskLow51Bits + c3 + + return v +} diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint b/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint new file mode 100644 index 00000000..e3685f95 --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint @@ -0,0 +1 @@ +b0c49ae9f59d233526f8934262c5bbbe14d4358d diff --git a/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh b/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh new file mode 100644 index 00000000..1ba22a8b --- /dev/null +++ b/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh @@ -0,0 +1,19 @@ +#! /bin/bash +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +STD_PATH=src/crypto/ed25519/internal/edwards25519/field +LOCAL_PATH=curve25519/internal/field +LAST_SYNC_REF=$(cat $LOCAL_PATH/sync.checkpoint) + +git fetch https://go.googlesource.com/go master + +if git diff --quiet $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH; then + echo "No changes." +else + NEW_REF=$(git rev-parse FETCH_HEAD | tee $LOCAL_PATH/sync.checkpoint) + echo "Applying changes from $LAST_SYNC_REF to $NEW_REF..." + git diff $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH | \ + git apply -3 --directory=$LOCAL_PATH +fi diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go new file mode 100644 index 00000000..45b5c966 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go @@ -0,0 +1,40 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.13 +// +build !go1.13 + +package poly1305 + +// Generic fallbacks for the math/bits intrinsics, copied from +// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had +// variable time fallbacks until Go 1.13. + +func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { + sum = x + y + carry + carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 + return +} + +func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { + diff = x - y - borrow + borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 + return +} + +func bitsMul64(x, y uint64) (hi, lo uint64) { + const mask32 = 1<<32 - 1 + x0 := x & mask32 + x1 := x >> 32 + y0 := y & mask32 + y1 := y >> 32 + w0 := x0 * y0 + t := x1*y0 + w0>>32 + w1 := t & mask32 + w2 := t >> 32 + w1 += x0 * y1 + hi = x1*y1 + w2 + w1>>32 + lo = x * y + return +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go new file mode 100644 index 00000000..ed52b341 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go @@ -0,0 +1,22 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.13 +// +build go1.13 + +package poly1305 + +import "math/bits" + +func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { + return bits.Add64(x, y, carry) +} + +func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { + return bits.Sub64(x, y, borrow) +} + +func bitsMul64(x, y uint64) (hi, lo uint64) { + return bits.Mul64(x, y) +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go new file mode 100644 index 00000000..f184b67d --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go @@ -0,0 +1,10 @@ +// Copyright 2018 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. + +//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego +// +build !amd64,!ppc64le,!s390x !gc purego + +package poly1305 + +type mac struct{ macGeneric } diff --git a/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go b/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go new file mode 100644 index 00000000..4aaea810 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go @@ -0,0 +1,99 @@ +// 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 poly1305 implements Poly1305 one-time message authentication code as +// specified in https://cr.yp.to/mac/poly1305-20050329.pdf. +// +// Poly1305 is a fast, one-time authentication function. It is infeasible for an +// attacker to generate an authenticator for a message without the key. However, a +// key must only be used for a single message. Authenticating two different +// messages with the same key allows an attacker to forge authenticators for other +// messages with the same key. +// +// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was +// used with a fixed key in order to generate one-time keys from an nonce. +// However, in this package AES isn't used and the one-time key is specified +// directly. +package poly1305 + +import "crypto/subtle" + +// TagSize is the size, in bytes, of a poly1305 authenticator. +const TagSize = 16 + +// Sum generates an authenticator for msg using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[16]byte, m []byte, key *[32]byte) { + h := New(key) + h.Write(m) + h.Sum(out[:0]) +} + +// Verify returns true if mac is a valid authenticator for m with the given key. +func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { + var tmp [16]byte + Sum(&tmp, m, key) + return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 +} + +// New returns a new MAC computing an authentication +// tag of all data written to it with the given key. +// This allows writing the message progressively instead +// of passing it as a single slice. Common users should use +// the Sum function instead. +// +// The key must be unique for each message, as authenticating +// two different messages with the same key allows an attacker +// to forge messages at will. +func New(key *[32]byte) *MAC { + m := &MAC{} + initialize(key, &m.macState) + return m +} + +// MAC is an io.Writer computing an authentication tag +// of the data written to it. +// +// MAC cannot be used like common hash.Hash implementations, +// because using a poly1305 key twice breaks its security. +// Therefore writing data to a running MAC after calling +// Sum or Verify causes it to panic. +type MAC struct { + mac // platform-dependent implementation + + finalized bool +} + +// Size returns the number of bytes Sum will return. +func (h *MAC) Size() int { return TagSize } + +// Write adds more data to the running message authentication code. +// It never returns an error. +// +// It must not be called after the first call of Sum or Verify. +func (h *MAC) Write(p []byte) (n int, err error) { + if h.finalized { + panic("poly1305: write to MAC after Sum or Verify") + } + return h.mac.Write(p) +} + +// Sum computes the authenticator of all data written to the +// message authentication code. +func (h *MAC) Sum(b []byte) []byte { + var mac [TagSize]byte + h.mac.Sum(&mac) + h.finalized = true + return append(b, mac[:]...) +} + +// Verify returns whether the authenticator of all data written to +// the message authentication code matches the expected value. +func (h *MAC) Verify(expected []byte) bool { + var mac [TagSize]byte + h.mac.Sum(&mac) + h.finalized = true + return subtle.ConstantTimeCompare(expected, mac[:]) == 1 +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go new file mode 100644 index 00000000..6d522333 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go @@ -0,0 +1,48 @@ +// 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. + +//go:build gc && !purego +// +build gc,!purego + +package poly1305 + +//go:noescape +func update(state *macState, msg []byte) + +// mac is a wrapper for macGeneric that redirects calls that would have gone to +// updateGeneric to update. +// +// Its Write and Sum methods are otherwise identical to the macGeneric ones, but +// using function pointers would carry a major performance cost. +type mac struct{ macGeneric } + +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < TagSize { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + update(&h.macState, h.buffer[:]) + } + if n := len(p) - (len(p) % TagSize); n > 0 { + update(&h.macState, p[:n]) + p = p[n:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return nn, nil +} + +func (h *mac) Sum(out *[16]byte) { + state := h.macState + if h.offset > 0 { + update(&state, h.buffer[:h.offset]) + } + finalize(out, &state.h, &state.s) +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s new file mode 100644 index 00000000..1d74f0f8 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s @@ -0,0 +1,109 @@ +// 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. + +//go:build gc && !purego +// +build gc,!purego + +#include "textflag.h" + +#define POLY1305_ADD(msg, h0, h1, h2) \ + ADDQ 0(msg), h0; \ + ADCQ 8(msg), h1; \ + ADCQ $1, h2; \ + LEAQ 16(msg), msg + +#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \ + MOVQ r0, AX; \ + MULQ h0; \ + MOVQ AX, t0; \ + MOVQ DX, t1; \ + MOVQ r0, AX; \ + MULQ h1; \ + ADDQ AX, t1; \ + ADCQ $0, DX; \ + MOVQ r0, t2; \ + IMULQ h2, t2; \ + ADDQ DX, t2; \ + \ + MOVQ r1, AX; \ + MULQ h0; \ + ADDQ AX, t1; \ + ADCQ $0, DX; \ + MOVQ DX, h0; \ + MOVQ r1, t3; \ + IMULQ h2, t3; \ + MOVQ r1, AX; \ + MULQ h1; \ + ADDQ AX, t2; \ + ADCQ DX, t3; \ + ADDQ h0, t2; \ + ADCQ $0, t3; \ + \ + MOVQ t0, h0; \ + MOVQ t1, h1; \ + MOVQ t2, h2; \ + ANDQ $3, h2; \ + MOVQ t2, t0; \ + ANDQ $0xFFFFFFFFFFFFFFFC, t0; \ + ADDQ t0, h0; \ + ADCQ t3, h1; \ + ADCQ $0, h2; \ + SHRQ $2, t3, t2; \ + SHRQ $2, t3; \ + ADDQ t2, h0; \ + ADCQ t3, h1; \ + ADCQ $0, h2 + +// func update(state *[7]uint64, msg []byte) +TEXT ·update(SB), $0-32 + MOVQ state+0(FP), DI + MOVQ msg_base+8(FP), SI + MOVQ msg_len+16(FP), R15 + + MOVQ 0(DI), R8 // h0 + MOVQ 8(DI), R9 // h1 + MOVQ 16(DI), R10 // h2 + MOVQ 24(DI), R11 // r0 + MOVQ 32(DI), R12 // r1 + + CMPQ R15, $16 + JB bytes_between_0_and_15 + +loop: + POLY1305_ADD(SI, R8, R9, R10) + +multiply: + POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) + SUBQ $16, R15 + CMPQ R15, $16 + JAE loop + +bytes_between_0_and_15: + TESTQ R15, R15 + JZ done + MOVQ $1, BX + XORQ CX, CX + XORQ R13, R13 + ADDQ R15, SI + +flush_buffer: + SHLQ $8, BX, CX + SHLQ $8, BX + MOVB -1(SI), R13 + XORQ R13, BX + DECQ SI + DECQ R15 + JNZ flush_buffer + + ADDQ BX, R8 + ADCQ CX, R9 + ADCQ $0, R10 + MOVQ $16, R15 + JMP multiply + +done: + MOVQ R8, 0(DI) + MOVQ R9, 8(DI) + MOVQ R10, 16(DI) + RET diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go new file mode 100644 index 00000000..e041da5e --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go @@ -0,0 +1,309 @@ +// Copyright 2018 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. + +// This file provides the generic implementation of Sum and MAC. Other files +// might provide optimized assembly implementations of some of this code. + +package poly1305 + +import "encoding/binary" + +// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag +// for a 64 bytes message is approximately +// +// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5 +// +// for some secret r and s. It can be computed sequentially like +// +// for len(msg) > 0: +// h += read(msg, 16) +// h *= r +// h %= 2¹³⁰ - 5 +// return h + s +// +// All the complexity is about doing performant constant-time math on numbers +// larger than any available numeric type. + +func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { + h := newMACGeneric(key) + h.Write(msg) + h.Sum(out) +} + +func newMACGeneric(key *[32]byte) macGeneric { + m := macGeneric{} + initialize(key, &m.macState) + return m +} + +// macState holds numbers in saturated 64-bit little-endian limbs. That is, +// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸. +type macState struct { + // h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but + // can grow larger during and after rounds. It must, however, remain below + // 2 * (2¹³⁰ - 5). + h [3]uint64 + // r and s are the private key components. + r [2]uint64 + s [2]uint64 +} + +type macGeneric struct { + macState + + buffer [TagSize]byte + offset int +} + +// Write splits the incoming message into TagSize chunks, and passes them to +// update. It buffers incomplete chunks. +func (h *macGeneric) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < TagSize { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + updateGeneric(&h.macState, h.buffer[:]) + } + if n := len(p) - (len(p) % TagSize); n > 0 { + updateGeneric(&h.macState, p[:n]) + p = p[n:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return nn, nil +} + +// Sum flushes the last incomplete chunk from the buffer, if any, and generates +// the MAC output. It does not modify its state, in order to allow for multiple +// calls to Sum, even if no Write is allowed after Sum. +func (h *macGeneric) Sum(out *[TagSize]byte) { + state := h.macState + if h.offset > 0 { + updateGeneric(&state, h.buffer[:h.offset]) + } + finalize(out, &state.h, &state.s) +} + +// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It +// clears some bits of the secret coefficient to make it possible to implement +// multiplication more efficiently. +const ( + rMask0 = 0x0FFFFFFC0FFFFFFF + rMask1 = 0x0FFFFFFC0FFFFFFC +) + +// initialize loads the 256-bit key into the two 128-bit secret values r and s. +func initialize(key *[32]byte, m *macState) { + m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 + m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 + m.s[0] = binary.LittleEndian.Uint64(key[16:24]) + m.s[1] = binary.LittleEndian.Uint64(key[24:32]) +} + +// uint128 holds a 128-bit number as two 64-bit limbs, for use with the +// bits.Mul64 and bits.Add64 intrinsics. +type uint128 struct { + lo, hi uint64 +} + +func mul64(a, b uint64) uint128 { + hi, lo := bitsMul64(a, b) + return uint128{lo, hi} +} + +func add128(a, b uint128) uint128 { + lo, c := bitsAdd64(a.lo, b.lo, 0) + hi, c := bitsAdd64(a.hi, b.hi, c) + if c != 0 { + panic("poly1305: unexpected overflow") + } + return uint128{lo, hi} +} + +func shiftRightBy2(a uint128) uint128 { + a.lo = a.lo>>2 | (a.hi&3)<<62 + a.hi = a.hi >> 2 + return a +} + +// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of +// 128 bits of message, it computes +// +// h₊ = (h + m) * r mod 2¹³⁰ - 5 +// +// If the msg length is not a multiple of TagSize, it assumes the last +// incomplete chunk is the final one. +func updateGeneric(state *macState, msg []byte) { + h0, h1, h2 := state.h[0], state.h[1], state.h[2] + r0, r1 := state.r[0], state.r[1] + + for len(msg) > 0 { + var c uint64 + + // For the first step, h + m, we use a chain of bits.Add64 intrinsics. + // The resulting value of h might exceed 2¹³⁰ - 5, but will be partially + // reduced at the end of the multiplication below. + // + // The spec requires us to set a bit just above the message size, not to + // hide leading zeroes. For full chunks, that's 1 << 128, so we can just + // add 1 to the most significant (2¹²⁸) limb, h2. + if len(msg) >= TagSize { + h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) + h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) + h2 += c + 1 + + msg = msg[TagSize:] + } else { + var buf [TagSize]byte + copy(buf[:], msg) + buf[len(msg)] = 1 + + h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) + h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) + h2 += c + + msg = nil + } + + // Multiplication of big number limbs is similar to elementary school + // columnar multiplication. Instead of digits, there are 64-bit limbs. + // + // We are multiplying a 3 limbs number, h, by a 2 limbs number, r. + // + // h2 h1 h0 x + // r1 r0 = + // ---------------- + // h2r0 h1r0 h0r0 <-- individual 128-bit products + // + h2r1 h1r1 h0r1 + // ------------------------ + // m3 m2 m1 m0 <-- result in 128-bit overlapping limbs + // ------------------------ + // m3.hi m2.hi m1.hi m0.hi <-- carry propagation + // + m3.lo m2.lo m1.lo m0.lo + // ------------------------------- + // t4 t3 t2 t1 t0 <-- final result in 64-bit limbs + // + // The main difference from pen-and-paper multiplication is that we do + // carry propagation in a separate step, as if we wrote two digit sums + // at first (the 128-bit limbs), and then carried the tens all at once. + + h0r0 := mul64(h0, r0) + h1r0 := mul64(h1, r0) + h2r0 := mul64(h2, r0) + h0r1 := mul64(h0, r1) + h1r1 := mul64(h1, r1) + h2r1 := mul64(h2, r1) + + // Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their + // top 4 bits cleared by rMask{0,1}, we know that their product is not going + // to overflow 64 bits, so we can ignore the high part of the products. + // + // This also means that the product doesn't have a fifth limb (t4). + if h2r0.hi != 0 { + panic("poly1305: unexpected overflow") + } + if h2r1.hi != 0 { + panic("poly1305: unexpected overflow") + } + + m0 := h0r0 + m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again + m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1. + m3 := h2r1 + + t0 := m0.lo + t1, c := bitsAdd64(m1.lo, m0.hi, 0) + t2, c := bitsAdd64(m2.lo, m1.hi, c) + t3, _ := bitsAdd64(m3.lo, m2.hi, c) + + // Now we have the result as 4 64-bit limbs, and we need to reduce it + // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do + // a cheap partial reduction according to the reduction identity + // + // c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5 + // + // because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is + // likely to be larger than 2¹³⁰ - 5, but still small enough to fit the + // assumptions we make about h in the rest of the code. + // + // See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23 + + // We split the final result at the 2¹³⁰ mark into h and cc, the carry. + // Note that the carry bits are effectively shifted left by 2, in other + // words, cc = c * 4 for the c in the reduction identity. + h0, h1, h2 = t0, t1, t2&maskLow2Bits + cc := uint128{t2 & maskNotLow2Bits, t3} + + // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. + + h0, c = bitsAdd64(h0, cc.lo, 0) + h1, c = bitsAdd64(h1, cc.hi, c) + h2 += c + + cc = shiftRightBy2(cc) + + h0, c = bitsAdd64(h0, cc.lo, 0) + h1, c = bitsAdd64(h1, cc.hi, c) + h2 += c + + // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most + // + // 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1 + } + + state.h[0], state.h[1], state.h[2] = h0, h1, h2 +} + +const ( + maskLow2Bits uint64 = 0x0000000000000003 + maskNotLow2Bits uint64 = ^maskLow2Bits +) + +// select64 returns x if v == 1 and y if v == 0, in constant time. +func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y } + +// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order. +const ( + p0 = 0xFFFFFFFFFFFFFFFB + p1 = 0xFFFFFFFFFFFFFFFF + p2 = 0x0000000000000003 +) + +// finalize completes the modular reduction of h and computes +// +// out = h + s mod 2¹²⁸ +func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { + h0, h1, h2 := h[0], h[1], h[2] + + // After the partial reduction in updateGeneric, h might be more than + // 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction + // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the + // result if the subtraction underflows, and t otherwise. + + hMinusP0, b := bitsSub64(h0, p0, 0) + hMinusP1, b := bitsSub64(h1, p1, b) + _, b = bitsSub64(h2, p2, b) + + // h = h if h < p else h - p + h0 = select64(b, h0, hMinusP0) + h1 = select64(b, h1, hMinusP1) + + // Finally, we compute the last Poly1305 step + // + // tag = h + s mod 2¹²⁸ + // + // by just doing a wide addition with the 128 low bits of h and discarding + // the overflow. + h0, c := bitsAdd64(h0, s[0], 0) + h1, _ = bitsAdd64(h1, s[1], c) + + binary.LittleEndian.PutUint64(out[0:8], h0) + binary.LittleEndian.PutUint64(out[8:16], h1) +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go new file mode 100644 index 00000000..4a069941 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go @@ -0,0 +1,48 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego +// +build gc,!purego + +package poly1305 + +//go:noescape +func update(state *macState, msg []byte) + +// mac is a wrapper for macGeneric that redirects calls that would have gone to +// updateGeneric to update. +// +// Its Write and Sum methods are otherwise identical to the macGeneric ones, but +// using function pointers would carry a major performance cost. +type mac struct{ macGeneric } + +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < TagSize { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + update(&h.macState, h.buffer[:]) + } + if n := len(p) - (len(p) % TagSize); n > 0 { + update(&h.macState, p[:n]) + p = p[n:] + } + if len(p) > 0 { + h.offset += copy(h.buffer[h.offset:], p) + } + return nn, nil +} + +func (h *mac) Sum(out *[16]byte) { + state := h.macState + if h.offset > 0 { + update(&state, h.buffer[:h.offset]) + } + finalize(out, &state.h, &state.s) +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s new file mode 100644 index 00000000..58422aad --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s @@ -0,0 +1,182 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego +// +build gc,!purego + +#include "textflag.h" + +// This was ported from the amd64 implementation. + +#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \ + MOVD (msg), t0; \ + MOVD 8(msg), t1; \ + MOVD $1, t2; \ + ADDC t0, h0, h0; \ + ADDE t1, h1, h1; \ + ADDE t2, h2; \ + ADD $16, msg + +#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ + MULLD r0, h0, t0; \ + MULLD r0, h1, t4; \ + MULHDU r0, h0, t1; \ + MULHDU r0, h1, t5; \ + ADDC t4, t1, t1; \ + MULLD r0, h2, t2; \ + ADDZE t5; \ + MULHDU r1, h0, t4; \ + MULLD r1, h0, h0; \ + ADD t5, t2, t2; \ + ADDC h0, t1, t1; \ + MULLD h2, r1, t3; \ + ADDZE t4, h0; \ + MULHDU r1, h1, t5; \ + MULLD r1, h1, t4; \ + ADDC t4, t2, t2; \ + ADDE t5, t3, t3; \ + ADDC h0, t2, t2; \ + MOVD $-4, t4; \ + MOVD t0, h0; \ + MOVD t1, h1; \ + ADDZE t3; \ + ANDCC $3, t2, h2; \ + AND t2, t4, t0; \ + ADDC t0, h0, h0; \ + ADDE t3, h1, h1; \ + SLD $62, t3, t4; \ + SRD $2, t2; \ + ADDZE h2; \ + OR t4, t2, t2; \ + SRD $2, t3; \ + ADDC t2, h0, h0; \ + ADDE t3, h1, h1; \ + ADDZE h2 + +DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF +DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC +GLOBL ·poly1305Mask<>(SB), RODATA, $16 + +// func update(state *[7]uint64, msg []byte) +TEXT ·update(SB), $0-32 + MOVD state+0(FP), R3 + MOVD msg_base+8(FP), R4 + MOVD msg_len+16(FP), R5 + + MOVD 0(R3), R8 // h0 + MOVD 8(R3), R9 // h1 + MOVD 16(R3), R10 // h2 + MOVD 24(R3), R11 // r0 + MOVD 32(R3), R12 // r1 + + CMP R5, $16 + BLT bytes_between_0_and_15 + +loop: + POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) + +multiply: + POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) + ADD $-16, R5 + CMP R5, $16 + BGE loop + +bytes_between_0_and_15: + CMP R5, $0 + BEQ done + MOVD $0, R16 // h0 + MOVD $0, R17 // h1 + +flush_buffer: + CMP R5, $8 + BLE just1 + + MOVD $8, R21 + SUB R21, R5, R21 + + // Greater than 8 -- load the rightmost remaining bytes in msg + // and put into R17 (h1) + MOVD (R4)(R21), R17 + MOVD $16, R22 + + // Find the offset to those bytes + SUB R5, R22, R22 + SLD $3, R22 + + // Shift to get only the bytes in msg + SRD R22, R17, R17 + + // Put 1 at high end + MOVD $1, R23 + SLD $3, R21 + SLD R21, R23, R23 + OR R23, R17, R17 + + // Remainder is 8 + MOVD $8, R5 + +just1: + CMP R5, $8 + BLT less8 + + // Exactly 8 + MOVD (R4), R16 + + CMP R17, $0 + + // Check if we've already set R17; if not + // set 1 to indicate end of msg. + BNE carry + MOVD $1, R17 + BR carry + +less8: + MOVD $0, R16 // h0 + MOVD $0, R22 // shift count + CMP R5, $4 + BLT less4 + MOVWZ (R4), R16 + ADD $4, R4 + ADD $-4, R5 + MOVD $32, R22 + +less4: + CMP R5, $2 + BLT less2 + MOVHZ (R4), R21 + SLD R22, R21, R21 + OR R16, R21, R16 + ADD $16, R22 + ADD $-2, R5 + ADD $2, R4 + +less2: + CMP R5, $0 + BEQ insert1 + MOVBZ (R4), R21 + SLD R22, R21, R21 + OR R16, R21, R16 + ADD $8, R22 + +insert1: + // Insert 1 at end of msg + MOVD $1, R21 + SLD R22, R21, R21 + OR R16, R21, R16 + +carry: + // Add new values to h0, h1, h2 + ADDC R16, R8 + ADDE R17, R9 + ADDZE R10, R10 + MOVD $16, R5 + ADD R5, R4 + BR multiply + +done: + // Save h0, h1, h2 in state + MOVD R8, 0(R3) + MOVD R9, 8(R3) + MOVD R10, 16(R3) + RET diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go new file mode 100644 index 00000000..ec959668 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go @@ -0,0 +1,77 @@ +// Copyright 2018 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. + +//go:build gc && !purego +// +build gc,!purego + +package poly1305 + +import ( + "golang.org/x/sys/cpu" +) + +// updateVX is an assembly implementation of Poly1305 that uses vector +// instructions. It must only be called if the vector facility (vx) is +// available. +// +//go:noescape +func updateVX(state *macState, msg []byte) + +// mac is a replacement for macGeneric that uses a larger buffer and redirects +// calls that would have gone to updateGeneric to updateVX if the vector +// facility is installed. +// +// A larger buffer is required for good performance because the vector +// implementation has a higher fixed cost per call than the generic +// implementation. +type mac struct { + macState + + buffer [16 * TagSize]byte // size must be a multiple of block size (16) + offset int +} + +func (h *mac) Write(p []byte) (int, error) { + nn := len(p) + if h.offset > 0 { + n := copy(h.buffer[h.offset:], p) + if h.offset+n < len(h.buffer) { + h.offset += n + return nn, nil + } + p = p[n:] + h.offset = 0 + if cpu.S390X.HasVX { + updateVX(&h.macState, h.buffer[:]) + } else { + updateGeneric(&h.macState, h.buffer[:]) + } + } + + tail := len(p) % len(h.buffer) // number of bytes to copy into buffer + body := len(p) - tail // number of bytes to process now + if body > 0 { + if cpu.S390X.HasVX { + updateVX(&h.macState, p[:body]) + } else { + updateGeneric(&h.macState, p[:body]) + } + } + h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0 + return nn, nil +} + +func (h *mac) Sum(out *[TagSize]byte) { + state := h.macState + remainder := h.buffer[:h.offset] + + // Use the generic implementation if we have 2 or fewer blocks left + // to sum. The vector implementation has a higher startup time. + if cpu.S390X.HasVX && len(remainder) > 2*TagSize { + updateVX(&state, remainder) + } else if len(remainder) > 0 { + updateGeneric(&state, remainder) + } + finalize(out, &state.h, &state.s) +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s new file mode 100644 index 00000000..aa9e0494 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s @@ -0,0 +1,504 @@ +// Copyright 2018 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. + +//go:build gc && !purego +// +build gc,!purego + +#include "textflag.h" + +// This implementation of Poly1305 uses the vector facility (vx) +// to process up to 2 blocks (32 bytes) per iteration using an +// algorithm based on the one described in: +// +// NEON crypto, Daniel J. Bernstein & Peter Schwabe +// https://cryptojedi.org/papers/neoncrypto-20120320.pdf +// +// This algorithm uses 5 26-bit limbs to represent a 130-bit +// value. These limbs are, for the most part, zero extended and +// placed into 64-bit vector register elements. Each vector +// register is 128-bits wide and so holds 2 of these elements. +// Using 26-bit limbs allows us plenty of headroom to accommodate +// accumulations before and after multiplication without +// overflowing either 32-bits (before multiplication) or 64-bits +// (after multiplication). +// +// In order to parallelise the operations required to calculate +// the sum we use two separate accumulators and then sum those +// in an extra final step. For compatibility with the generic +// implementation we perform this summation at the end of every +// updateVX call. +// +// To use two accumulators we must multiply the message blocks +// by r² rather than r. Only the final message block should be +// multiplied by r. +// +// Example: +// +// We want to calculate the sum (h) for a 64 byte message (m): +// +// h = m[0:16]r⁴ + m[16:32]r³ + m[32:48]r² + m[48:64]r +// +// To do this we split the calculation into the even indices +// and odd indices of the message. These form our SIMD 'lanes': +// +// h = m[ 0:16]r⁴ + m[32:48]r² + <- lane 0 +// m[16:32]r³ + m[48:64]r <- lane 1 +// +// To calculate this iteratively we refactor so that both lanes +// are written in terms of r² and r: +// +// h = (m[ 0:16]r² + m[32:48])r² + <- lane 0 +// (m[16:32]r² + m[48:64])r <- lane 1 +// ^ ^ +// | coefficients for second iteration +// coefficients for first iteration +// +// So in this case we would have two iterations. In the first +// both lanes are multiplied by r². In the second only the +// first lane is multiplied by r² and the second lane is +// instead multiplied by r. This gives use the odd and even +// powers of r that we need from the original equation. +// +// Notation: +// +// h - accumulator +// r - key +// m - message +// +// [a, b] - SIMD register holding two 64-bit values +// [a, b, c, d] - SIMD register holding four 32-bit values +// xᵢ[n] - limb n of variable x with bit width i +// +// Limbs are expressed in little endian order, so for 26-bit +// limbs x₂₆[4] will be the most significant limb and x₂₆[0] +// will be the least significant limb. + +// masking constants +#define MOD24 V0 // [0x0000000000ffffff, 0x0000000000ffffff] - mask low 24-bits +#define MOD26 V1 // [0x0000000003ffffff, 0x0000000003ffffff] - mask low 26-bits + +// expansion constants (see EXPAND macro) +#define EX0 V2 +#define EX1 V3 +#define EX2 V4 + +// key (r², r or 1 depending on context) +#define R_0 V5 +#define R_1 V6 +#define R_2 V7 +#define R_3 V8 +#define R_4 V9 + +// precalculated coefficients (5r², 5r or 0 depending on context) +#define R5_1 V10 +#define R5_2 V11 +#define R5_3 V12 +#define R5_4 V13 + +// message block (m) +#define M_0 V14 +#define M_1 V15 +#define M_2 V16 +#define M_3 V17 +#define M_4 V18 + +// accumulator (h) +#define H_0 V19 +#define H_1 V20 +#define H_2 V21 +#define H_3 V22 +#define H_4 V23 + +// temporary registers (for short-lived values) +#define T_0 V24 +#define T_1 V25 +#define T_2 V26 +#define T_3 V27 +#define T_4 V28 + +GLOBL ·constants<>(SB), RODATA, $0x30 +// EX0 +DATA ·constants<>+0x00(SB)/8, $0x0006050403020100 +DATA ·constants<>+0x08(SB)/8, $0x1016151413121110 +// EX1 +DATA ·constants<>+0x10(SB)/8, $0x060c0b0a09080706 +DATA ·constants<>+0x18(SB)/8, $0x161c1b1a19181716 +// EX2 +DATA ·constants<>+0x20(SB)/8, $0x0d0d0d0d0d0f0e0d +DATA ·constants<>+0x28(SB)/8, $0x1d1d1d1d1d1f1e1d + +// MULTIPLY multiplies each lane of f and g, partially reduced +// modulo 2¹³⁰ - 5. The result, h, consists of partial products +// in each lane that need to be reduced further to produce the +// final result. +// +// h₁₃₀ = (f₁₃₀g₁₃₀) % 2¹³⁰ + (5f₁₃₀g₁₃₀) / 2¹³⁰ +// +// Note that the multiplication by 5 of the high bits is +// achieved by precalculating the multiplication of four of the +// g coefficients by 5. These are g51-g54. +#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ + VMLOF f0, g0, h0 \ + VMLOF f0, g3, h3 \ + VMLOF f0, g1, h1 \ + VMLOF f0, g4, h4 \ + VMLOF f0, g2, h2 \ + VMLOF f1, g54, T_0 \ + VMLOF f1, g2, T_3 \ + VMLOF f1, g0, T_1 \ + VMLOF f1, g3, T_4 \ + VMLOF f1, g1, T_2 \ + VMALOF f2, g53, h0, h0 \ + VMALOF f2, g1, h3, h3 \ + VMALOF f2, g54, h1, h1 \ + VMALOF f2, g2, h4, h4 \ + VMALOF f2, g0, h2, h2 \ + VMALOF f3, g52, T_0, T_0 \ + VMALOF f3, g0, T_3, T_3 \ + VMALOF f3, g53, T_1, T_1 \ + VMALOF f3, g1, T_4, T_4 \ + VMALOF f3, g54, T_2, T_2 \ + VMALOF f4, g51, h0, h0 \ + VMALOF f4, g54, h3, h3 \ + VMALOF f4, g52, h1, h1 \ + VMALOF f4, g0, h4, h4 \ + VMALOF f4, g53, h2, h2 \ + VAG T_0, h0, h0 \ + VAG T_3, h3, h3 \ + VAG T_1, h1, h1 \ + VAG T_4, h4, h4 \ + VAG T_2, h2, h2 + +// REDUCE performs the following carry operations in four +// stages, as specified in Bernstein & Schwabe: +// +// 1: h₂₆[0]->h₂₆[1] h₂₆[3]->h₂₆[4] +// 2: h₂₆[1]->h₂₆[2] h₂₆[4]->h₂₆[0] +// 3: h₂₆[0]->h₂₆[1] h₂₆[2]->h₂₆[3] +// 4: h₂₆[3]->h₂₆[4] +// +// The result is that all of the limbs are limited to 26-bits +// except for h₂₆[1] and h₂₆[4] which are limited to 27-bits. +// +// Note that although each limb is aligned at 26-bit intervals +// they may contain values that exceed 2²⁶ - 1, hence the need +// to carry the excess bits in each limb. +#define REDUCE(h0, h1, h2, h3, h4) \ + VESRLG $26, h0, T_0 \ + VESRLG $26, h3, T_1 \ + VN MOD26, h0, h0 \ + VN MOD26, h3, h3 \ + VAG T_0, h1, h1 \ + VAG T_1, h4, h4 \ + VESRLG $26, h1, T_2 \ + VESRLG $26, h4, T_3 \ + VN MOD26, h1, h1 \ + VN MOD26, h4, h4 \ + VESLG $2, T_3, T_4 \ + VAG T_3, T_4, T_4 \ + VAG T_2, h2, h2 \ + VAG T_4, h0, h0 \ + VESRLG $26, h2, T_0 \ + VESRLG $26, h0, T_1 \ + VN MOD26, h2, h2 \ + VN MOD26, h0, h0 \ + VAG T_0, h3, h3 \ + VAG T_1, h1, h1 \ + VESRLG $26, h3, T_2 \ + VN MOD26, h3, h3 \ + VAG T_2, h4, h4 + +// EXPAND splits the 128-bit little-endian values in0 and in1 +// into 26-bit big-endian limbs and places the results into +// the first and second lane of d₂₆[0:4] respectively. +// +// The EX0, EX1 and EX2 constants are arrays of byte indices +// for permutation. The permutation both reverses the bytes +// in the input and ensures the bytes are copied into the +// destination limb ready to be shifted into their final +// position. +#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ + VPERM in0, in1, EX0, d0 \ + VPERM in0, in1, EX1, d2 \ + VPERM in0, in1, EX2, d4 \ + VESRLG $26, d0, d1 \ + VESRLG $30, d2, d3 \ + VESRLG $4, d2, d2 \ + VN MOD26, d0, d0 \ // [in0₂₆[0], in1₂₆[0]] + VN MOD26, d3, d3 \ // [in0₂₆[3], in1₂₆[3]] + VN MOD26, d1, d1 \ // [in0₂₆[1], in1₂₆[1]] + VN MOD24, d4, d4 \ // [in0₂₆[4], in1₂₆[4]] + VN MOD26, d2, d2 // [in0₂₆[2], in1₂₆[2]] + +// func updateVX(state *macState, msg []byte) +TEXT ·updateVX(SB), NOSPLIT, $0 + MOVD state+0(FP), R1 + LMG msg+8(FP), R2, R3 // R2=msg_base, R3=msg_len + + // load EX0, EX1 and EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 + + // generate masks + VGMG $(64-24), $63, MOD24 // [0x00ffffff, 0x00ffffff] + VGMG $(64-26), $63, MOD26 // [0x03ffffff, 0x03ffffff] + + // load h (accumulator) and r (key) from state + VZERO T_1 // [0, 0] + VL 0(R1), T_0 // [h₆₄[0], h₆₄[1]] + VLEG $0, 16(R1), T_1 // [h₆₄[2], 0] + VL 24(R1), T_2 // [r₆₄[0], r₆₄[1]] + VPDI $0, T_0, T_2, T_3 // [h₆₄[0], r₆₄[0]] + VPDI $5, T_0, T_2, T_4 // [h₆₄[1], r₆₄[1]] + + // unpack h and r into 26-bit limbs + // note: h₆₄[2] may have the low 3 bits set, so h₂₆[4] is a 27-bit value + VN MOD26, T_3, H_0 // [h₂₆[0], r₂₆[0]] + VZERO H_1 // [0, 0] + VZERO H_3 // [0, 0] + VGMG $(64-12-14), $(63-12), T_0 // [0x03fff000, 0x03fff000] - 26-bit mask with low 12 bits masked out + VESLG $24, T_1, T_1 // [h₆₄[2]<<24, 0] + VERIMG $-26&63, T_3, MOD26, H_1 // [h₂₆[1], r₂₆[1]] + VESRLG $+52&63, T_3, H_2 // [h₂₆[2], r₂₆[2]] - low 12 bits only + VERIMG $-14&63, T_4, MOD26, H_3 // [h₂₆[1], r₂₆[1]] + VESRLG $40, T_4, H_4 // [h₂₆[4], r₂₆[4]] - low 24 bits only + VERIMG $+12&63, T_4, T_0, H_2 // [h₂₆[2], r₂₆[2]] - complete + VO T_1, H_4, H_4 // [h₂₆[4], r₂₆[4]] - complete + + // replicate r across all 4 vector elements + VREPF $3, H_0, R_0 // [r₂₆[0], r₂₆[0], r₂₆[0], r₂₆[0]] + VREPF $3, H_1, R_1 // [r₂₆[1], r₂₆[1], r₂₆[1], r₂₆[1]] + VREPF $3, H_2, R_2 // [r₂₆[2], r₂₆[2], r₂₆[2], r₂₆[2]] + VREPF $3, H_3, R_3 // [r₂₆[3], r₂₆[3], r₂₆[3], r₂₆[3]] + VREPF $3, H_4, R_4 // [r₂₆[4], r₂₆[4], r₂₆[4], r₂₆[4]] + + // zero out lane 1 of h + VLEIG $1, $0, H_0 // [h₂₆[0], 0] + VLEIG $1, $0, H_1 // [h₂₆[1], 0] + VLEIG $1, $0, H_2 // [h₂₆[2], 0] + VLEIG $1, $0, H_3 // [h₂₆[3], 0] + VLEIG $1, $0, H_4 // [h₂₆[4], 0] + + // calculate 5r (ignore least significant limb) + VREPIF $5, T_0 + VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r₂₆[1], 5r₂₆[1], 5r₂₆[1]] + VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r₂₆[2], 5r₂₆[2], 5r₂₆[2]] + VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r₂₆[3], 5r₂₆[3], 5r₂₆[3]] + VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r₂₆[4], 5r₂₆[4], 5r₂₆[4]] + + // skip r² calculation if we are only calculating one block + CMPBLE R3, $16, skip + + // calculate r² + MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, M_0, M_1, M_2, M_3, M_4) + REDUCE(M_0, M_1, M_2, M_3, M_4) + VGBM $0x0f0f, T_0 + VERIMG $0, M_0, T_0, R_0 // [r₂₆[0], r²₂₆[0], r₂₆[0], r²₂₆[0]] + VERIMG $0, M_1, T_0, R_1 // [r₂₆[1], r²₂₆[1], r₂₆[1], r²₂₆[1]] + VERIMG $0, M_2, T_0, R_2 // [r₂₆[2], r²₂₆[2], r₂₆[2], r²₂₆[2]] + VERIMG $0, M_3, T_0, R_3 // [r₂₆[3], r²₂₆[3], r₂₆[3], r²₂₆[3]] + VERIMG $0, M_4, T_0, R_4 // [r₂₆[4], r²₂₆[4], r₂₆[4], r²₂₆[4]] + + // calculate 5r² (ignore least significant limb) + VREPIF $5, T_0 + VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r²₂₆[1], 5r₂₆[1], 5r²₂₆[1]] + VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r²₂₆[2], 5r₂₆[2], 5r²₂₆[2]] + VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r²₂₆[3], 5r₂₆[3], 5r²₂₆[3]] + VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r²₂₆[4], 5r₂₆[4], 5r²₂₆[4]] + +loop: + CMPBLE R3, $32, b2 // 2 or fewer blocks remaining, need to change key coefficients + + // load next 2 blocks from message + VLM (R2), T_0, T_1 + + // update message slice + SUB $32, R3 + MOVD $32(R2), R2 + + // unpack message blocks into 26-bit big-endian limbs + EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) + + // add 2¹²⁸ to each message block value + VLEIB $4, $1, M_4 + VLEIB $12, $1, M_4 + +multiply: + // accumulate the incoming message + VAG H_0, M_0, M_0 + VAG H_3, M_3, M_3 + VAG H_1, M_1, M_1 + VAG H_4, M_4, M_4 + VAG H_2, M_2, M_2 + + // multiply the accumulator by the key coefficient + MULTIPLY(M_0, M_1, M_2, M_3, M_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) + + // carry and partially reduce the partial products + REDUCE(H_0, H_1, H_2, H_3, H_4) + + CMPBNE R3, $0, loop + +finish: + // sum lane 0 and lane 1 and put the result in lane 1 + VZERO T_0 + VSUMQG H_0, T_0, H_0 + VSUMQG H_3, T_0, H_3 + VSUMQG H_1, T_0, H_1 + VSUMQG H_4, T_0, H_4 + VSUMQG H_2, T_0, H_2 + + // reduce again after summation + // TODO(mundaym): there might be a more efficient way to do this + // now that we only have 1 active lane. For example, we could + // simultaneously pack the values as we reduce them. + REDUCE(H_0, H_1, H_2, H_3, H_4) + + // carry h[1] through to h[4] so that only h[4] can exceed 2²⁶ - 1 + // TODO(mundaym): in testing this final carry was unnecessary. + // Needs a proof before it can be removed though. + VESRLG $26, H_1, T_1 + VN MOD26, H_1, H_1 + VAQ T_1, H_2, H_2 + VESRLG $26, H_2, T_2 + VN MOD26, H_2, H_2 + VAQ T_2, H_3, H_3 + VESRLG $26, H_3, T_3 + VN MOD26, H_3, H_3 + VAQ T_3, H_4, H_4 + + // h is now < 2(2¹³⁰ - 5) + // Pack each lane in h₂₆[0:4] into h₁₂₈[0:1]. + VESLG $26, H_1, H_1 + VESLG $26, H_3, H_3 + VO H_0, H_1, H_0 + VO H_2, H_3, H_2 + VESLG $4, H_2, H_2 + VLEIB $7, $48, H_1 + VSLB H_1, H_2, H_2 + VO H_0, H_2, H_0 + VLEIB $7, $104, H_1 + VSLB H_1, H_4, H_3 + VO H_3, H_0, H_0 + VLEIB $7, $24, H_1 + VSRLB H_1, H_4, H_1 + + // update state + VSTEG $1, H_0, 0(R1) + VSTEG $0, H_0, 8(R1) + VSTEG $1, H_1, 16(R1) + RET + +b2: // 2 or fewer blocks remaining + CMPBLE R3, $16, b1 + + // Load the 2 remaining blocks (17-32 bytes remaining). + MOVD $-17(R3), R0 // index of final byte to load modulo 16 + VL (R2), T_0 // load full 16 byte block + VLL R0, 16(R2), T_1 // load final (possibly partial) block and pad with zeros to 16 bytes + + // The Poly1305 algorithm requires that a 1 bit be appended to + // each message block. If the final block is less than 16 bytes + // long then it is easiest to insert the 1 before the message + // block is split into 26-bit limbs. If, on the other hand, the + // final message block is 16 bytes long then we append the 1 bit + // after expansion as normal. + MOVBZ $1, R0 + MOVD $-16(R3), R3 // index of byte in last block to insert 1 at (could be 16) + CMPBEQ R3, $16, 2(PC) // skip the insertion if the final block is 16 bytes long + VLVGB R3, R0, T_1 // insert 1 into the byte at index R3 + + // Split both blocks into 26-bit limbs in the appropriate lanes. + EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) + + // Append a 1 byte to the end of the second to last block. + VLEIB $4, $1, M_4 + + // Append a 1 byte to the end of the last block only if it is a + // full 16 byte block. + CMPBNE R3, $16, 2(PC) + VLEIB $12, $1, M_4 + + // Finally, set up the coefficients for the final multiplication. + // We have previously saved r and 5r in the 32-bit even indexes + // of the R_[0-4] and R5_[1-4] coefficient registers. + // + // We want lane 0 to be multiplied by r² so that can be kept the + // same. We want lane 1 to be multiplied by r so we need to move + // the saved r value into the 32-bit odd index in lane 1 by + // rotating the 64-bit lane by 32. + VGBM $0x00ff, T_0 // [0, 0xffffffffffffffff] - mask lane 1 only + VERIMG $32, R_0, T_0, R_0 // [_, r²₂₆[0], _, r₂₆[0]] + VERIMG $32, R_1, T_0, R_1 // [_, r²₂₆[1], _, r₂₆[1]] + VERIMG $32, R_2, T_0, R_2 // [_, r²₂₆[2], _, r₂₆[2]] + VERIMG $32, R_3, T_0, R_3 // [_, r²₂₆[3], _, r₂₆[3]] + VERIMG $32, R_4, T_0, R_4 // [_, r²₂₆[4], _, r₂₆[4]] + VERIMG $32, R5_1, T_0, R5_1 // [_, 5r²₂₆[1], _, 5r₂₆[1]] + VERIMG $32, R5_2, T_0, R5_2 // [_, 5r²₂₆[2], _, 5r₂₆[2]] + VERIMG $32, R5_3, T_0, R5_3 // [_, 5r²₂₆[3], _, 5r₂₆[3]] + VERIMG $32, R5_4, T_0, R5_4 // [_, 5r²₂₆[4], _, 5r₂₆[4]] + + MOVD $0, R3 + BR multiply + +skip: + CMPBEQ R3, $0, finish + +b1: // 1 block remaining + + // Load the final block (1-16 bytes). This will be placed into + // lane 0. + MOVD $-1(R3), R0 + VLL R0, (R2), T_0 // pad to 16 bytes with zeros + + // The Poly1305 algorithm requires that a 1 bit be appended to + // each message block. If the final block is less than 16 bytes + // long then it is easiest to insert the 1 before the message + // block is split into 26-bit limbs. If, on the other hand, the + // final message block is 16 bytes long then we append the 1 bit + // after expansion as normal. + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, T_0 + + // Set the message block in lane 1 to the value 0 so that it + // can be accumulated without affecting the final result. + VZERO T_1 + + // Split the final message block into 26-bit limbs in lane 0. + // Lane 1 will be contain 0. + EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) + + // Append a 1 byte to the end of the last block only if it is a + // full 16 byte block. + CMPBNE R3, $16, 2(PC) + VLEIB $4, $1, M_4 + + // We have previously saved r and 5r in the 32-bit even indexes + // of the R_[0-4] and R5_[1-4] coefficient registers. + // + // We want lane 0 to be multiplied by r so we need to move the + // saved r value into the 32-bit odd index in lane 0. We want + // lane 1 to be set to the value 1. This makes multiplication + // a no-op. We do this by setting lane 1 in every register to 0 + // and then just setting the 32-bit index 3 in R_0 to 1. + VZERO T_0 + MOVD $0, R0 + MOVD $0x10111213, R12 + VLVGP R12, R0, T_1 // [_, 0x10111213, _, 0x00000000] + VPERM T_0, R_0, T_1, R_0 // [_, r₂₆[0], _, 0] + VPERM T_0, R_1, T_1, R_1 // [_, r₂₆[1], _, 0] + VPERM T_0, R_2, T_1, R_2 // [_, r₂₆[2], _, 0] + VPERM T_0, R_3, T_1, R_3 // [_, r₂₆[3], _, 0] + VPERM T_0, R_4, T_1, R_4 // [_, r₂₆[4], _, 0] + VPERM T_0, R5_1, T_1, R5_1 // [_, 5r₂₆[1], _, 0] + VPERM T_0, R5_2, T_1, R5_2 // [_, 5r₂₆[2], _, 0] + VPERM T_0, R5_3, T_1, R5_3 // [_, 5r₂₆[3], _, 0] + VPERM T_0, R5_4, T_1, R5_4 // [_, 5r₂₆[4], _, 0] + + // Set the value of lane 1 to be 1. + VLEIF $3, $1, R_0 // [_, r₂₆[0], _, 1] + + MOVD $0, R3 + BR multiply diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go new file mode 100644 index 00000000..4fad24f8 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +//go:build !purego +// +build !purego + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go new file mode 100644 index 00000000..80ccbed2 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go @@ -0,0 +1,36 @@ +// Copyright 2018 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. + +//go:build purego +// +build purego + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +// This is the Google App Engine standard variant based on reflect +// because the unsafe package and cgo are disallowed. + +import "reflect" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && + reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go new file mode 100644 index 00000000..3c4d18a1 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -0,0 +1,847 @@ +// 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 agent implements the ssh-agent protocol, and provides both +// a client and a server. The client can talk to a standard ssh-agent +// that uses UNIX sockets, and one could implement an alternative +// ssh-agent process using the sample server. +// +// References: +// +// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00 +package agent // import "golang.org/x/crypto/ssh/agent" + +import ( + "bytes" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rsa" + "encoding/base64" + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + "sync" + + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ssh" +) + +// SignatureFlags represent additional flags that can be passed to the signature +// requests an defined in [PROTOCOL.agent] section 4.5.1. +type SignatureFlags uint32 + +// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. +const ( + SignatureFlagReserved SignatureFlags = 1 << iota + SignatureFlagRsaSha256 + SignatureFlagRsaSha512 +) + +// Agent represents the capabilities of an ssh-agent. +type Agent interface { + // List returns the identities known to the agent. + List() ([]*Key, error) + + // Sign has the agent sign the data using a protocol 2 key as defined + // in [PROTOCOL.agent] section 2.6.2. + Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) + + // Add adds a private key to the agent. + Add(key AddedKey) error + + // Remove removes all identities with the given public key. + Remove(key ssh.PublicKey) error + + // RemoveAll removes all identities. + RemoveAll() error + + // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. + Lock(passphrase []byte) error + + // Unlock undoes the effect of Lock + Unlock(passphrase []byte) error + + // Signers returns signers for all the known keys. + Signers() ([]ssh.Signer, error) +} + +type ExtendedAgent interface { + Agent + + // SignWithFlags signs like Sign, but allows for additional flags to be sent/received + SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) + + // Extension processes a custom extension request. Standard-compliant agents are not + // required to support any extensions, but this method allows agents to implement + // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. + // If agent extensions are unsupported entirely this method MUST return an + // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in + // the request is unsupported by the agent then ErrExtensionUnsupported MUST be + // returned. + // + // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents + // of the response are unspecified (including the type of the message), the complete + // response will be returned as a []byte slice, including the "type" byte of the message. + Extension(extensionType string, contents []byte) ([]byte, error) +} + +// ConstraintExtension describes an optional constraint defined by users. +type ConstraintExtension struct { + // ExtensionName consist of a UTF-8 string suffixed by the + // implementation domain following the naming scheme defined + // in Section 4.2 of [RFC4251], e.g. "foo@example.com". + ExtensionName string + // ExtensionDetails contains the actual content of the extended + // constraint. + ExtensionDetails []byte +} + +// AddedKey describes an SSH key to be added to an Agent. +type AddedKey struct { + // PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey, + // ed25519.PrivateKey or *ecdsa.PrivateKey, which will be inserted into the + // agent. + PrivateKey interface{} + // Certificate, if not nil, is communicated to the agent and will be + // stored with the key. + Certificate *ssh.Certificate + // Comment is an optional, free-form string. + Comment string + // LifetimeSecs, if not zero, is the number of seconds that the + // agent will store the key for. + LifetimeSecs uint32 + // ConfirmBeforeUse, if true, requests that the agent confirm with the + // user before each use of this key. + ConfirmBeforeUse bool + // ConstraintExtensions are the experimental or private-use constraints + // defined by users. + ConstraintExtensions []ConstraintExtension +} + +// See [PROTOCOL.agent], section 3. +const ( + agentRequestV1Identities = 1 + agentRemoveAllV1Identities = 9 + + // 3.2 Requests from client to agent for protocol 2 key operations + agentAddIdentity = 17 + agentRemoveIdentity = 18 + agentRemoveAllIdentities = 19 + agentAddIDConstrained = 25 + + // 3.3 Key-type independent requests from client to agent + agentAddSmartcardKey = 20 + agentRemoveSmartcardKey = 21 + agentLock = 22 + agentUnlock = 23 + agentAddSmartcardKeyConstrained = 26 + + // 3.7 Key constraint identifiers + agentConstrainLifetime = 1 + agentConstrainConfirm = 2 + agentConstrainExtension = 3 +) + +// maxAgentResponseBytes is the maximum agent reply size that is accepted. This +// is a sanity check, not a limit in the spec. +const maxAgentResponseBytes = 16 << 20 + +// Agent messages: +// These structures mirror the wire format of the corresponding ssh agent +// messages found in [PROTOCOL.agent]. + +// 3.4 Generic replies from agent to client +const agentFailure = 5 + +type failureAgentMsg struct{} + +const agentSuccess = 6 + +type successAgentMsg struct{} + +// See [PROTOCOL.agent], section 2.5.2. +const agentRequestIdentities = 11 + +type requestIdentitiesAgentMsg struct{} + +// See [PROTOCOL.agent], section 2.5.2. +const agentIdentitiesAnswer = 12 + +type identitiesAnswerAgentMsg struct { + NumKeys uint32 `sshtype:"12"` + Keys []byte `ssh:"rest"` +} + +// See [PROTOCOL.agent], section 2.6.2. +const agentSignRequest = 13 + +type signRequestAgentMsg struct { + KeyBlob []byte `sshtype:"13"` + Data []byte + Flags uint32 +} + +// See [PROTOCOL.agent], section 2.6.2. + +// 3.6 Replies from agent to client for protocol 2 key operations +const agentSignResponse = 14 + +type signResponseAgentMsg struct { + SigBlob []byte `sshtype:"14"` +} + +type publicKey struct { + Format string + Rest []byte `ssh:"rest"` +} + +// 3.7 Key constraint identifiers +type constrainLifetimeAgentMsg struct { + LifetimeSecs uint32 `sshtype:"1"` +} + +type constrainExtensionAgentMsg struct { + ExtensionName string `sshtype:"3"` + ExtensionDetails []byte + + // Rest is a field used for parsing, not part of message + Rest []byte `ssh:"rest"` +} + +// See [PROTOCOL.agent], section 4.7 +const agentExtension = 27 +const agentExtensionFailure = 28 + +// ErrExtensionUnsupported indicates that an extension defined in +// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this +// error indicates that the agent returned a standard SSH_AGENT_FAILURE message +// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol +// specification (and therefore this error) does not distinguish between a +// specific extension being unsupported and extensions being unsupported entirely. +var ErrExtensionUnsupported = errors.New("agent: extension unsupported") + +type extensionAgentMsg struct { + ExtensionType string `sshtype:"27"` + Contents []byte +} + +// Key represents a protocol 2 public key as defined in +// [PROTOCOL.agent], section 2.5.2. +type Key struct { + Format string + Blob []byte + Comment string +} + +func clientErr(err error) error { + return fmt.Errorf("agent: client error: %v", err) +} + +// String returns the storage form of an agent key with the format, base64 +// encoded serialized key, and the comment if it is not empty. +func (k *Key) String() string { + s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob) + + if k.Comment != "" { + s += " " + k.Comment + } + + return s +} + +// Type returns the public key type. +func (k *Key) Type() string { + return k.Format +} + +// Marshal returns key blob to satisfy the ssh.PublicKey interface. +func (k *Key) Marshal() []byte { + return k.Blob +} + +// Verify satisfies the ssh.PublicKey interface. +func (k *Key) Verify(data []byte, sig *ssh.Signature) error { + pubKey, err := ssh.ParsePublicKey(k.Blob) + if err != nil { + return fmt.Errorf("agent: bad public key: %v", err) + } + return pubKey.Verify(data, sig) +} + +type wireKey struct { + Format string + Rest []byte `ssh:"rest"` +} + +func parseKey(in []byte) (out *Key, rest []byte, err error) { + var record struct { + Blob []byte + Comment string + Rest []byte `ssh:"rest"` + } + + if err := ssh.Unmarshal(in, &record); err != nil { + return nil, nil, err + } + + var wk wireKey + if err := ssh.Unmarshal(record.Blob, &wk); err != nil { + return nil, nil, err + } + + return &Key{ + Format: wk.Format, + Blob: record.Blob, + Comment: record.Comment, + }, record.Rest, nil +} + +// client is a client for an ssh-agent process. +type client struct { + // conn is typically a *net.UnixConn + conn io.ReadWriter + // mu is used to prevent concurrent access to the agent + mu sync.Mutex +} + +// NewClient returns an Agent that talks to an ssh-agent process over +// the given connection. +func NewClient(rw io.ReadWriter) ExtendedAgent { + return &client{conn: rw} +} + +// call sends an RPC to the agent. On success, the reply is +// unmarshaled into reply and replyType is set to the first byte of +// the reply, which contains the type of the message. +func (c *client) call(req []byte) (reply interface{}, err error) { + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + reply, err = unmarshal(buf) + if err != nil { + return nil, clientErr(err) + } + return reply, nil +} + +// callRaw sends an RPC to the agent. On success, the raw +// bytes of the response are returned; no unmarshalling is +// performed on the response. +func (c *client) callRaw(req []byte) (reply []byte, err error) { + c.mu.Lock() + defer c.mu.Unlock() + + msg := make([]byte, 4+len(req)) + binary.BigEndian.PutUint32(msg, uint32(len(req))) + copy(msg[4:], req) + if _, err = c.conn.Write(msg); err != nil { + return nil, clientErr(err) + } + + var respSizeBuf [4]byte + if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil { + return nil, clientErr(err) + } + respSize := binary.BigEndian.Uint32(respSizeBuf[:]) + if respSize > maxAgentResponseBytes { + return nil, clientErr(errors.New("response too large")) + } + + buf := make([]byte, respSize) + if _, err = io.ReadFull(c.conn, buf); err != nil { + return nil, clientErr(err) + } + return buf, nil +} + +func (c *client) simpleCall(req []byte) error { + resp, err := c.call(req) + if err != nil { + return err + } + if _, ok := resp.(*successAgentMsg); ok { + return nil + } + return errors.New("agent: failure") +} + +func (c *client) RemoveAll() error { + return c.simpleCall([]byte{agentRemoveAllIdentities}) +} + +func (c *client) Remove(key ssh.PublicKey) error { + req := ssh.Marshal(&agentRemoveIdentityMsg{ + KeyBlob: key.Marshal(), + }) + return c.simpleCall(req) +} + +func (c *client) Lock(passphrase []byte) error { + req := ssh.Marshal(&agentLockMsg{ + Passphrase: passphrase, + }) + return c.simpleCall(req) +} + +func (c *client) Unlock(passphrase []byte) error { + req := ssh.Marshal(&agentUnlockMsg{ + Passphrase: passphrase, + }) + return c.simpleCall(req) +} + +// List returns the identities known to the agent. +func (c *client) List() ([]*Key, error) { + // see [PROTOCOL.agent] section 2.5.2. + req := []byte{agentRequestIdentities} + + msg, err := c.call(req) + if err != nil { + return nil, err + } + + switch msg := msg.(type) { + case *identitiesAnswerAgentMsg: + if msg.NumKeys > maxAgentResponseBytes/8 { + return nil, errors.New("agent: too many keys in agent reply") + } + keys := make([]*Key, msg.NumKeys) + data := msg.Keys + for i := uint32(0); i < msg.NumKeys; i++ { + var key *Key + var err error + if key, data, err = parseKey(data); err != nil { + return nil, err + } + keys[i] = key + } + return keys, nil + case *failureAgentMsg: + return nil, errors.New("agent: failed to list keys") + } + panic("unreachable") +} + +// Sign has the agent sign the data using a protocol 2 key as defined +// in [PROTOCOL.agent] section 2.6.2. +func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return c.SignWithFlags(key, data, 0) +} + +func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { + req := ssh.Marshal(signRequestAgentMsg{ + KeyBlob: key.Marshal(), + Data: data, + Flags: uint32(flags), + }) + + msg, err := c.call(req) + if err != nil { + return nil, err + } + + switch msg := msg.(type) { + case *signResponseAgentMsg: + var sig ssh.Signature + if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil { + return nil, err + } + + return &sig, nil + case *failureAgentMsg: + return nil, errors.New("agent: failed to sign challenge") + } + panic("unreachable") +} + +// unmarshal parses an agent message in packet, returning the parsed +// form and the message type of packet. +func unmarshal(packet []byte) (interface{}, error) { + if len(packet) < 1 { + return nil, errors.New("agent: empty packet") + } + var msg interface{} + switch packet[0] { + case agentFailure: + return new(failureAgentMsg), nil + case agentSuccess: + return new(successAgentMsg), nil + case agentIdentitiesAnswer: + msg = new(identitiesAnswerAgentMsg) + case agentSignResponse: + msg = new(signResponseAgentMsg) + case agentV1IdentitiesAnswer: + msg = new(agentV1IdentityMsg) + default: + return nil, fmt.Errorf("agent: unknown type tag %d", packet[0]) + } + if err := ssh.Unmarshal(packet, msg); err != nil { + return nil, err + } + return msg, nil +} + +type rsaKeyMsg struct { + Type string `sshtype:"17|25"` + N *big.Int + E *big.Int + D *big.Int + Iqmp *big.Int // IQMP = Inverse Q Mod P + P *big.Int + Q *big.Int + Comments string + Constraints []byte `ssh:"rest"` +} + +type dsaKeyMsg struct { + Type string `sshtype:"17|25"` + P *big.Int + Q *big.Int + G *big.Int + Y *big.Int + X *big.Int + Comments string + Constraints []byte `ssh:"rest"` +} + +type ecdsaKeyMsg struct { + Type string `sshtype:"17|25"` + Curve string + KeyBytes []byte + D *big.Int + Comments string + Constraints []byte `ssh:"rest"` +} + +type ed25519KeyMsg struct { + Type string `sshtype:"17|25"` + Pub []byte + Priv []byte + Comments string + Constraints []byte `ssh:"rest"` +} + +// Insert adds a private key to the agent. +func (c *client) insertKey(s interface{}, comment string, constraints []byte) error { + var req []byte + switch k := s.(type) { + case *rsa.PrivateKey: + if len(k.Primes) != 2 { + return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) + } + k.Precompute() + req = ssh.Marshal(rsaKeyMsg{ + Type: ssh.KeyAlgoRSA, + N: k.N, + E: big.NewInt(int64(k.E)), + D: k.D, + Iqmp: k.Precomputed.Qinv, + P: k.Primes[0], + Q: k.Primes[1], + Comments: comment, + Constraints: constraints, + }) + case *dsa.PrivateKey: + req = ssh.Marshal(dsaKeyMsg{ + Type: ssh.KeyAlgoDSA, + P: k.P, + Q: k.Q, + G: k.G, + Y: k.Y, + X: k.X, + Comments: comment, + Constraints: constraints, + }) + case *ecdsa.PrivateKey: + nistID := fmt.Sprintf("nistp%d", k.Params().BitSize) + req = ssh.Marshal(ecdsaKeyMsg{ + Type: "ecdsa-sha2-" + nistID, + Curve: nistID, + KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y), + D: k.D, + Comments: comment, + Constraints: constraints, + }) + case ed25519.PrivateKey: + req = ssh.Marshal(ed25519KeyMsg{ + Type: ssh.KeyAlgoED25519, + Pub: []byte(k)[32:], + Priv: []byte(k), + Comments: comment, + Constraints: constraints, + }) + // This function originally supported only *ed25519.PrivateKey, however the + // general idiom is to pass ed25519.PrivateKey by value, not by pointer. + // We still support the pointer variant for backwards compatibility. + case *ed25519.PrivateKey: + req = ssh.Marshal(ed25519KeyMsg{ + Type: ssh.KeyAlgoED25519, + Pub: []byte(*k)[32:], + Priv: []byte(*k), + Comments: comment, + Constraints: constraints, + }) + default: + return fmt.Errorf("agent: unsupported key type %T", s) + } + + // if constraints are present then the message type needs to be changed. + if len(constraints) != 0 { + req[0] = agentAddIDConstrained + } + + resp, err := c.call(req) + if err != nil { + return err + } + if _, ok := resp.(*successAgentMsg); ok { + return nil + } + return errors.New("agent: failure") +} + +type rsaCertMsg struct { + Type string `sshtype:"17|25"` + CertBytes []byte + D *big.Int + Iqmp *big.Int // IQMP = Inverse Q Mod P + P *big.Int + Q *big.Int + Comments string + Constraints []byte `ssh:"rest"` +} + +type dsaCertMsg struct { + Type string `sshtype:"17|25"` + CertBytes []byte + X *big.Int + Comments string + Constraints []byte `ssh:"rest"` +} + +type ecdsaCertMsg struct { + Type string `sshtype:"17|25"` + CertBytes []byte + D *big.Int + Comments string + Constraints []byte `ssh:"rest"` +} + +type ed25519CertMsg struct { + Type string `sshtype:"17|25"` + CertBytes []byte + Pub []byte + Priv []byte + Comments string + Constraints []byte `ssh:"rest"` +} + +// Add adds a private key to the agent. If a certificate is given, +// that certificate is added instead as public key. +func (c *client) Add(key AddedKey) error { + var constraints []byte + + if secs := key.LifetimeSecs; secs != 0 { + constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...) + } + + if key.ConfirmBeforeUse { + constraints = append(constraints, agentConstrainConfirm) + } + + cert := key.Certificate + if cert == nil { + return c.insertKey(key.PrivateKey, key.Comment, constraints) + } + return c.insertCert(key.PrivateKey, cert, key.Comment, constraints) +} + +func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error { + var req []byte + switch k := s.(type) { + case *rsa.PrivateKey: + if len(k.Primes) != 2 { + return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) + } + k.Precompute() + req = ssh.Marshal(rsaCertMsg{ + Type: cert.Type(), + CertBytes: cert.Marshal(), + D: k.D, + Iqmp: k.Precomputed.Qinv, + P: k.Primes[0], + Q: k.Primes[1], + Comments: comment, + Constraints: constraints, + }) + case *dsa.PrivateKey: + req = ssh.Marshal(dsaCertMsg{ + Type: cert.Type(), + CertBytes: cert.Marshal(), + X: k.X, + Comments: comment, + Constraints: constraints, + }) + case *ecdsa.PrivateKey: + req = ssh.Marshal(ecdsaCertMsg{ + Type: cert.Type(), + CertBytes: cert.Marshal(), + D: k.D, + Comments: comment, + Constraints: constraints, + }) + case ed25519.PrivateKey: + req = ssh.Marshal(ed25519CertMsg{ + Type: cert.Type(), + CertBytes: cert.Marshal(), + Pub: []byte(k)[32:], + Priv: []byte(k), + Comments: comment, + Constraints: constraints, + }) + // This function originally supported only *ed25519.PrivateKey, however the + // general idiom is to pass ed25519.PrivateKey by value, not by pointer. + // We still support the pointer variant for backwards compatibility. + case *ed25519.PrivateKey: + req = ssh.Marshal(ed25519CertMsg{ + Type: cert.Type(), + CertBytes: cert.Marshal(), + Pub: []byte(*k)[32:], + Priv: []byte(*k), + Comments: comment, + Constraints: constraints, + }) + default: + return fmt.Errorf("agent: unsupported key type %T", s) + } + + // if constraints are present then the message type needs to be changed. + if len(constraints) != 0 { + req[0] = agentAddIDConstrained + } + + signer, err := ssh.NewSignerFromKey(s) + if err != nil { + return err + } + if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { + return errors.New("agent: signer and cert have different public key") + } + + resp, err := c.call(req) + if err != nil { + return err + } + if _, ok := resp.(*successAgentMsg); ok { + return nil + } + return errors.New("agent: failure") +} + +// Signers provides a callback for client authentication. +func (c *client) Signers() ([]ssh.Signer, error) { + keys, err := c.List() + if err != nil { + return nil, err + } + + var result []ssh.Signer + for _, k := range keys { + result = append(result, &agentKeyringSigner{c, k}) + } + return result, nil +} + +type agentKeyringSigner struct { + agent *client + pub ssh.PublicKey +} + +func (s *agentKeyringSigner) PublicKey() ssh.PublicKey { + return s.pub +} + +func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) { + // The agent has its own entropy source, so the rand argument is ignored. + return s.agent.Sign(s.pub, data) +} + +func (s *agentKeyringSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*ssh.Signature, error) { + if algorithm == "" || algorithm == underlyingAlgo(s.pub.Type()) { + return s.Sign(rand, data) + } + + var flags SignatureFlags + switch algorithm { + case ssh.KeyAlgoRSASHA256: + flags = SignatureFlagRsaSha256 + case ssh.KeyAlgoRSASHA512: + flags = SignatureFlagRsaSha512 + default: + return nil, fmt.Errorf("agent: unsupported algorithm %q", algorithm) + } + + return s.agent.SignWithFlags(s.pub, data, flags) +} + +var _ ssh.AlgorithmSigner = &agentKeyringSigner{} + +// certKeyAlgoNames is a mapping from known certificate algorithm names to the +// corresponding public key signature algorithm. +// +// This map must be kept in sync with the one in certs.go. +var certKeyAlgoNames = map[string]string{ + ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA, + ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256, + ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512, + ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA, + ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256, + ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384, + ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521, + ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256, + ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519, + ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519, +} + +// underlyingAlgo returns the signature algorithm associated with algo (which is +// an advertised or negotiated public key or host key algorithm). These are +// usually the same, except for certificate algorithms. +func underlyingAlgo(algo string) string { + if a, ok := certKeyAlgoNames[algo]; ok { + return a + } + return algo +} + +// Calls an extension method. It is up to the agent implementation as to whether or not +// any particular extension is supported and may always return an error. Because the +// type of the response is up to the implementation, this returns the bytes of the +// response and does not attempt any type of unmarshalling. +func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { + req := ssh.Marshal(extensionAgentMsg{ + ExtensionType: extensionType, + Contents: contents, + }) + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + if len(buf) == 0 { + return nil, errors.New("agent: failure; empty response") + } + // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message + // represents an agent that does not support the extension + if buf[0] == agentFailure { + return nil, ErrExtensionUnsupported + } + if buf[0] == agentExtensionFailure { + return nil, errors.New("agent: generic extension failure") + } + + return buf, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/forward.go b/vendor/golang.org/x/crypto/ssh/agent/forward.go new file mode 100644 index 00000000..fd24ba90 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/agent/forward.go @@ -0,0 +1,103 @@ +// Copyright 2014 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 agent + +import ( + "errors" + "io" + "net" + "sync" + + "golang.org/x/crypto/ssh" +) + +// RequestAgentForwarding sets up agent forwarding for the session. +// ForwardToAgent or ForwardToRemote should be called to route +// the authentication requests. +func RequestAgentForwarding(session *ssh.Session) error { + ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil) + if err != nil { + return err + } + if !ok { + return errors.New("forwarding request denied") + } + return nil +} + +// ForwardToAgent routes authentication requests to the given keyring. +func ForwardToAgent(client *ssh.Client, keyring Agent) error { + channels := client.HandleChannelOpen(channelType) + if channels == nil { + return errors.New("agent: already have handler for " + channelType) + } + + go func() { + for ch := range channels { + channel, reqs, err := ch.Accept() + if err != nil { + continue + } + go ssh.DiscardRequests(reqs) + go func() { + ServeAgent(keyring, channel) + channel.Close() + }() + } + }() + return nil +} + +const channelType = "auth-agent@openssh.com" + +// ForwardToRemote routes authentication requests to the ssh-agent +// process serving on the given unix socket. +func ForwardToRemote(client *ssh.Client, addr string) error { + channels := client.HandleChannelOpen(channelType) + if channels == nil { + return errors.New("agent: already have handler for " + channelType) + } + conn, err := net.Dial("unix", addr) + if err != nil { + return err + } + conn.Close() + + go func() { + for ch := range channels { + channel, reqs, err := ch.Accept() + if err != nil { + continue + } + go ssh.DiscardRequests(reqs) + go forwardUnixSocket(channel, addr) + } + }() + return nil +} + +func forwardUnixSocket(channel ssh.Channel, addr string) { + conn, err := net.Dial("unix", addr) + if err != nil { + return + } + + var wg sync.WaitGroup + wg.Add(2) + go func() { + io.Copy(conn, channel) + conn.(*net.UnixConn).CloseWrite() + wg.Done() + }() + go func() { + io.Copy(channel, conn) + channel.CloseWrite() + wg.Done() + }() + + wg.Wait() + conn.Close() + channel.Close() +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go new file mode 100644 index 00000000..21bfa870 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go @@ -0,0 +1,241 @@ +// Copyright 2014 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 agent + +import ( + "bytes" + "crypto/rand" + "crypto/subtle" + "errors" + "fmt" + "sync" + "time" + + "golang.org/x/crypto/ssh" +) + +type privKey struct { + signer ssh.Signer + comment string + expire *time.Time +} + +type keyring struct { + mu sync.Mutex + keys []privKey + + locked bool + passphrase []byte +} + +var errLocked = errors.New("agent: locked") + +// NewKeyring returns an Agent that holds keys in memory. It is safe +// for concurrent use by multiple goroutines. +func NewKeyring() Agent { + return &keyring{} +} + +// RemoveAll removes all identities. +func (r *keyring) RemoveAll() error { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + return errLocked + } + + r.keys = nil + return nil +} + +// removeLocked does the actual key removal. The caller must already be holding the +// keyring mutex. +func (r *keyring) removeLocked(want []byte) error { + found := false + for i := 0; i < len(r.keys); { + if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { + found = true + r.keys[i] = r.keys[len(r.keys)-1] + r.keys = r.keys[:len(r.keys)-1] + continue + } else { + i++ + } + } + + if !found { + return errors.New("agent: key not found") + } + return nil +} + +// Remove removes all identities with the given public key. +func (r *keyring) Remove(key ssh.PublicKey) error { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + return errLocked + } + + return r.removeLocked(key.Marshal()) +} + +// Lock locks the agent. Sign and Remove will fail, and List will return an empty list. +func (r *keyring) Lock(passphrase []byte) error { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + return errLocked + } + + r.locked = true + r.passphrase = passphrase + return nil +} + +// Unlock undoes the effect of Lock +func (r *keyring) Unlock(passphrase []byte) error { + r.mu.Lock() + defer r.mu.Unlock() + if !r.locked { + return errors.New("agent: not locked") + } + if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { + return fmt.Errorf("agent: incorrect passphrase") + } + + r.locked = false + r.passphrase = nil + return nil +} + +// expireKeysLocked removes expired keys from the keyring. If a key was added +// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have +// elapsed, it is removed. The caller *must* be holding the keyring mutex. +func (r *keyring) expireKeysLocked() { + for _, k := range r.keys { + if k.expire != nil && time.Now().After(*k.expire) { + r.removeLocked(k.signer.PublicKey().Marshal()) + } + } +} + +// List returns the identities known to the agent. +func (r *keyring) List() ([]*Key, error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + // section 2.7: locked agents return empty. + return nil, nil + } + + r.expireKeysLocked() + var ids []*Key + for _, k := range r.keys { + pub := k.signer.PublicKey() + ids = append(ids, &Key{ + Format: pub.Type(), + Blob: pub.Marshal(), + Comment: k.comment}) + } + return ids, nil +} + +// Insert adds a private key to the keyring. If a certificate +// is given, that certificate is added as public key. Note that +// any constraints given are ignored. +func (r *keyring) Add(key AddedKey) error { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + return errLocked + } + signer, err := ssh.NewSignerFromKey(key.PrivateKey) + + if err != nil { + return err + } + + if cert := key.Certificate; cert != nil { + signer, err = ssh.NewCertSigner(cert, signer) + if err != nil { + return err + } + } + + p := privKey{ + signer: signer, + comment: key.Comment, + } + + if key.LifetimeSecs > 0 { + t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second) + p.expire = &t + } + + r.keys = append(r.keys, p) + + return nil +} + +// Sign returns a signature for the data. +func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return r.SignWithFlags(key, data, 0) +} + +func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + return nil, errLocked + } + + r.expireKeysLocked() + wanted := key.Marshal() + for _, k := range r.keys { + if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { + if flags == 0 { + return k.signer.Sign(rand.Reader, data) + } else { + if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { + return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) + } else { + var algorithm string + switch flags { + case SignatureFlagRsaSha256: + algorithm = ssh.KeyAlgoRSASHA256 + case SignatureFlagRsaSha512: + algorithm = ssh.KeyAlgoRSASHA512 + default: + return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) + } + return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + } + } + } + } + return nil, errors.New("not found") +} + +// Signers returns signers for all the known keys. +func (r *keyring) Signers() ([]ssh.Signer, error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.locked { + return nil, errLocked + } + + r.expireKeysLocked() + s := make([]ssh.Signer, 0, len(r.keys)) + for _, k := range r.keys { + s = append(s, k.signer) + } + return s, nil +} + +// The keyring does not support any extensions +func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { + return nil, ErrExtensionUnsupported +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go new file mode 100644 index 00000000..6e7a1e02 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -0,0 +1,570 @@ +// 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 agent + +import ( + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rsa" + "encoding/binary" + "errors" + "fmt" + "io" + "log" + "math/big" + + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ssh" +) + +// Server wraps an Agent and uses it to implement the agent side of +// the SSH-agent, wire protocol. +type server struct { + agent Agent +} + +func (s *server) processRequestBytes(reqData []byte) []byte { + rep, err := s.processRequest(reqData) + if err != nil { + if err != errLocked { + // TODO(hanwen): provide better logging interface? + log.Printf("agent %d: %v", reqData[0], err) + } + return []byte{agentFailure} + } + + if err == nil && rep == nil { + return []byte{agentSuccess} + } + + return ssh.Marshal(rep) +} + +func marshalKey(k *Key) []byte { + var record struct { + Blob []byte + Comment string + } + record.Blob = k.Marshal() + record.Comment = k.Comment + + return ssh.Marshal(&record) +} + +// See [PROTOCOL.agent], section 2.5.1. +const agentV1IdentitiesAnswer = 2 + +type agentV1IdentityMsg struct { + Numkeys uint32 `sshtype:"2"` +} + +type agentRemoveIdentityMsg struct { + KeyBlob []byte `sshtype:"18"` +} + +type agentLockMsg struct { + Passphrase []byte `sshtype:"22"` +} + +type agentUnlockMsg struct { + Passphrase []byte `sshtype:"23"` +} + +func (s *server) processRequest(data []byte) (interface{}, error) { + switch data[0] { + case agentRequestV1Identities: + return &agentV1IdentityMsg{0}, nil + + case agentRemoveAllV1Identities: + return nil, nil + + case agentRemoveIdentity: + var req agentRemoveIdentityMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + + var wk wireKey + if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { + return nil, err + } + + return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) + + case agentRemoveAllIdentities: + return nil, s.agent.RemoveAll() + + case agentLock: + var req agentLockMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + + return nil, s.agent.Lock(req.Passphrase) + + case agentUnlock: + var req agentUnlockMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + return nil, s.agent.Unlock(req.Passphrase) + + case agentSignRequest: + var req signRequestAgentMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + + var wk wireKey + if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { + return nil, err + } + + k := &Key{ + Format: wk.Format, + Blob: req.KeyBlob, + } + + var sig *ssh.Signature + var err error + if extendedAgent, ok := s.agent.(ExtendedAgent); ok { + sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) + } else { + sig, err = s.agent.Sign(k, req.Data) + } + + if err != nil { + return nil, err + } + return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil + + case agentRequestIdentities: + keys, err := s.agent.List() + if err != nil { + return nil, err + } + + rep := identitiesAnswerAgentMsg{ + NumKeys: uint32(len(keys)), + } + for _, k := range keys { + rep.Keys = append(rep.Keys, marshalKey(k)...) + } + return rep, nil + + case agentAddIDConstrained, agentAddIdentity: + return nil, s.insertIdentity(data) + + case agentExtension: + // Return a stub object where the whole contents of the response gets marshaled. + var responseStub struct { + Rest []byte `ssh:"rest"` + } + + if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { + // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 + // requires that we return a standard SSH_AGENT_FAILURE message. + responseStub.Rest = []byte{agentFailure} + } else { + var req extensionAgentMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) + if err != nil { + // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE + // message as required by [PROTOCOL.agent] section 4.7. + if err == ErrExtensionUnsupported { + responseStub.Rest = []byte{agentFailure} + } else { + // As the result of any other error processing an extension request, + // [PROTOCOL.agent] section 4.7 requires that we return a + // SSH_AGENT_EXTENSION_FAILURE code. + responseStub.Rest = []byte{agentExtensionFailure} + } + } else { + if len(res) == 0 { + return nil, nil + } + responseStub.Rest = res + } + } + + return responseStub, nil + } + + return nil, fmt.Errorf("unknown opcode %d", data[0]) +} + +func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) { + for len(constraints) != 0 { + switch constraints[0] { + case agentConstrainLifetime: + lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5]) + constraints = constraints[5:] + case agentConstrainConfirm: + confirmBeforeUse = true + constraints = constraints[1:] + case agentConstrainExtension: + var msg constrainExtensionAgentMsg + if err = ssh.Unmarshal(constraints, &msg); err != nil { + return 0, false, nil, err + } + extensions = append(extensions, ConstraintExtension{ + ExtensionName: msg.ExtensionName, + ExtensionDetails: msg.ExtensionDetails, + }) + constraints = msg.Rest + default: + return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0]) + } + } + return +} + +func setConstraints(key *AddedKey, constraintBytes []byte) error { + lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes) + if err != nil { + return err + } + + key.LifetimeSecs = lifetimeSecs + key.ConfirmBeforeUse = confirmBeforeUse + key.ConstraintExtensions = constraintExtensions + return nil +} + +func parseRSAKey(req []byte) (*AddedKey, error) { + var k rsaKeyMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + if k.E.BitLen() > 30 { + return nil, errors.New("agent: RSA public exponent too large") + } + priv := &rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + E: int(k.E.Int64()), + N: k.N, + }, + D: k.D, + Primes: []*big.Int{k.P, k.Q}, + } + priv.Precompute() + + addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func parseEd25519Key(req []byte) (*AddedKey, error) { + var k ed25519KeyMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + priv := ed25519.PrivateKey(k.Priv) + + addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func parseDSAKey(req []byte) (*AddedKey, error) { + var k dsaKeyMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + priv := &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: k.P, + Q: k.Q, + G: k.G, + }, + Y: k.Y, + }, + X: k.X, + } + + addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) { + priv = &ecdsa.PrivateKey{ + D: privScalar, + } + + switch curveName { + case "nistp256": + priv.Curve = elliptic.P256() + case "nistp384": + priv.Curve = elliptic.P384() + case "nistp521": + priv.Curve = elliptic.P521() + default: + return nil, fmt.Errorf("agent: unknown curve %q", curveName) + } + + priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes) + if priv.X == nil || priv.Y == nil { + return nil, errors.New("agent: point not on curve") + } + + return priv, nil +} + +func parseEd25519Cert(req []byte) (*AddedKey, error) { + var k ed25519CertMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + pubKey, err := ssh.ParsePublicKey(k.CertBytes) + if err != nil { + return nil, err + } + priv := ed25519.PrivateKey(k.Priv) + cert, ok := pubKey.(*ssh.Certificate) + if !ok { + return nil, errors.New("agent: bad ED25519 certificate") + } + + addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func parseECDSAKey(req []byte) (*AddedKey, error) { + var k ecdsaKeyMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + + priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D) + if err != nil { + return nil, err + } + + addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func parseRSACert(req []byte) (*AddedKey, error) { + var k rsaCertMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + + pubKey, err := ssh.ParsePublicKey(k.CertBytes) + if err != nil { + return nil, err + } + + cert, ok := pubKey.(*ssh.Certificate) + if !ok { + return nil, errors.New("agent: bad RSA certificate") + } + + // An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go + var rsaPub struct { + Name string + E *big.Int + N *big.Int + } + if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil { + return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) + } + + if rsaPub.E.BitLen() > 30 { + return nil, errors.New("agent: RSA public exponent too large") + } + + priv := rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + E: int(rsaPub.E.Int64()), + N: rsaPub.N, + }, + D: k.D, + Primes: []*big.Int{k.Q, k.P}, + } + priv.Precompute() + + addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func parseDSACert(req []byte) (*AddedKey, error) { + var k dsaCertMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + pubKey, err := ssh.ParsePublicKey(k.CertBytes) + if err != nil { + return nil, err + } + cert, ok := pubKey.(*ssh.Certificate) + if !ok { + return nil, errors.New("agent: bad DSA certificate") + } + + // A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go + var w struct { + Name string + P, Q, G, Y *big.Int + } + if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil { + return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) + } + + priv := &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: w.P, + Q: w.Q, + G: w.G, + }, + Y: w.Y, + }, + X: k.X, + } + + addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func parseECDSACert(req []byte) (*AddedKey, error) { + var k ecdsaCertMsg + if err := ssh.Unmarshal(req, &k); err != nil { + return nil, err + } + + pubKey, err := ssh.ParsePublicKey(k.CertBytes) + if err != nil { + return nil, err + } + cert, ok := pubKey.(*ssh.Certificate) + if !ok { + return nil, errors.New("agent: bad ECDSA certificate") + } + + // An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go + var ecdsaPub struct { + Name string + ID string + Key []byte + } + if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil { + return nil, err + } + + priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D) + if err != nil { + return nil, err + } + + addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil +} + +func (s *server) insertIdentity(req []byte) error { + var record struct { + Type string `sshtype:"17|25"` + Rest []byte `ssh:"rest"` + } + + if err := ssh.Unmarshal(req, &record); err != nil { + return err + } + + var addedKey *AddedKey + var err error + + switch record.Type { + case ssh.KeyAlgoRSA: + addedKey, err = parseRSAKey(req) + case ssh.KeyAlgoDSA: + addedKey, err = parseDSAKey(req) + case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: + addedKey, err = parseECDSAKey(req) + case ssh.KeyAlgoED25519: + addedKey, err = parseEd25519Key(req) + case ssh.CertAlgoRSAv01: + addedKey, err = parseRSACert(req) + case ssh.CertAlgoDSAv01: + addedKey, err = parseDSACert(req) + case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01: + addedKey, err = parseECDSACert(req) + case ssh.CertAlgoED25519v01: + addedKey, err = parseEd25519Cert(req) + default: + return fmt.Errorf("agent: not implemented: %q", record.Type) + } + + if err != nil { + return err + } + return s.agent.Add(*addedKey) +} + +// ServeAgent serves the agent protocol on the given connection. It +// returns when an I/O error occurs. +func ServeAgent(agent Agent, c io.ReadWriter) error { + s := &server{agent} + + var length [4]byte + for { + if _, err := io.ReadFull(c, length[:]); err != nil { + return err + } + l := binary.BigEndian.Uint32(length[:]) + if l == 0 { + return fmt.Errorf("agent: request size is 0") + } + if l > maxAgentResponseBytes { + // We also cap requests. + return fmt.Errorf("agent: request too large: %d", l) + } + + req := make([]byte, l) + if _, err := io.ReadFull(c, req); err != nil { + return err + } + + repData := s.processRequestBytes(req) + if len(repData) > maxAgentResponseBytes { + return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) + } + + binary.BigEndian.PutUint32(length[:], uint32(len(repData))) + if _, err := c.Write(length[:]); err != nil { + return err + } + if _, err := c.Write(repData); err != nil { + return err + } + } +} diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go new file mode 100644 index 00000000..1ab07d07 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/buffer.go @@ -0,0 +1,97 @@ +// 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 ssh + +import ( + "io" + "sync" +) + +// buffer provides a linked list buffer for data exchange +// between producer and consumer. Theoretically the buffer is +// of unlimited capacity as it does no allocation of its own. +type buffer struct { + // protects concurrent access to head, tail and closed + *sync.Cond + + head *element // the buffer that will be read first + tail *element // the buffer that will be read last + + closed bool +} + +// An element represents a single link in a linked list. +type element struct { + buf []byte + next *element +} + +// newBuffer returns an empty buffer that is not closed. +func newBuffer() *buffer { + e := new(element) + b := &buffer{ + Cond: newCond(), + head: e, + tail: e, + } + return b +} + +// write makes buf available for Read to receive. +// buf must not be modified after the call to write. +func (b *buffer) write(buf []byte) { + b.Cond.L.Lock() + e := &element{buf: buf} + b.tail.next = e + b.tail = e + b.Cond.Signal() + b.Cond.L.Unlock() +} + +// eof closes the buffer. Reads from the buffer once all +// the data has been consumed will receive io.EOF. +func (b *buffer) eof() { + b.Cond.L.Lock() + b.closed = true + b.Cond.Signal() + b.Cond.L.Unlock() +} + +// Read reads data from the internal buffer in buf. Reads will block +// if no data is available, or until the buffer is closed. +func (b *buffer) Read(buf []byte) (n int, err error) { + b.Cond.L.Lock() + defer b.Cond.L.Unlock() + + for len(buf) > 0 { + // if there is data in b.head, copy it + if len(b.head.buf) > 0 { + r := copy(buf, b.head.buf) + buf, b.head.buf = buf[r:], b.head.buf[r:] + n += r + continue + } + // if there is a next buffer, make it the head + if len(b.head.buf) == 0 && b.head != b.tail { + b.head = b.head.next + continue + } + + // if at least one byte has been copied, return + if n > 0 { + break + } + + // if nothing was read, and there is nothing outstanding + // check to see if the buffer is closed. + if b.closed { + err = io.EOF + break + } + // out of buffers, wait for producer + b.Cond.Wait() + } + return +} diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go new file mode 100644 index 00000000..4600c207 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -0,0 +1,589 @@ +// 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 ssh + +import ( + "bytes" + "errors" + "fmt" + "io" + "net" + "sort" + "time" +) + +// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear +// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms. +// Unlike key algorithm names, these are not passed to AlgorithmSigner and don't +// appear in the Signature.Format field. +const ( + CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" + CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" + CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" + CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" + CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" + CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" + CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com" + CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com" + + // CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a + // Certificate.Type (or PublicKey.Type), but only in + // ClientConfig.HostKeyAlgorithms. + CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com" + CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com" +) + +const ( + // Deprecated: use CertAlgoRSAv01. + CertSigAlgoRSAv01 = CertAlgoRSAv01 + // Deprecated: use CertAlgoRSASHA256v01. + CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01 + // Deprecated: use CertAlgoRSASHA512v01. + CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01 +) + +// Certificate types distinguish between host and user +// certificates. The values can be set in the CertType field of +// Certificate. +const ( + UserCert = 1 + HostCert = 2 +) + +// Signature represents a cryptographic signature. +type Signature struct { + Format string + Blob []byte + Rest []byte `ssh:"rest"` +} + +// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that +// a certificate does not expire. +const CertTimeInfinity = 1<<64 - 1 + +// An Certificate represents an OpenSSH certificate as defined in +// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the +// PublicKey interface, so it can be unmarshaled using +// ParsePublicKey. +type Certificate struct { + Nonce []byte + Key PublicKey + Serial uint64 + CertType uint32 + KeyId string + ValidPrincipals []string + ValidAfter uint64 + ValidBefore uint64 + Permissions + Reserved []byte + SignatureKey PublicKey + Signature *Signature +} + +// genericCertData holds the key-independent part of the certificate data. +// Overall, certificates contain an nonce, public key fields and +// key-independent fields. +type genericCertData struct { + Serial uint64 + CertType uint32 + KeyId string + ValidPrincipals []byte + ValidAfter uint64 + ValidBefore uint64 + CriticalOptions []byte + Extensions []byte + Reserved []byte + SignatureKey []byte + Signature []byte +} + +func marshalStringList(namelist []string) []byte { + var to []byte + for _, name := range namelist { + s := struct{ N string }{name} + to = append(to, Marshal(&s)...) + } + return to +} + +type optionsTuple struct { + Key string + Value []byte +} + +type optionsTupleValue struct { + Value string +} + +// serialize a map of critical options or extensions +// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, +// we need two length prefixes for a non-empty string value +func marshalTuples(tups map[string]string) []byte { + keys := make([]string, 0, len(tups)) + for key := range tups { + keys = append(keys, key) + } + sort.Strings(keys) + + var ret []byte + for _, key := range keys { + s := optionsTuple{Key: key} + if value := tups[key]; len(value) > 0 { + s.Value = Marshal(&optionsTupleValue{value}) + } + ret = append(ret, Marshal(&s)...) + } + return ret +} + +// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, +// we need two length prefixes for a non-empty option value +func parseTuples(in []byte) (map[string]string, error) { + tups := map[string]string{} + var lastKey string + var haveLastKey bool + + for len(in) > 0 { + var key, val, extra []byte + var ok bool + + if key, in, ok = parseString(in); !ok { + return nil, errShortRead + } + keyStr := string(key) + // according to [PROTOCOL.certkeys], the names must be in + // lexical order. + if haveLastKey && keyStr <= lastKey { + return nil, fmt.Errorf("ssh: certificate options are not in lexical order") + } + lastKey, haveLastKey = keyStr, true + // the next field is a data field, which if non-empty has a string embedded + if val, in, ok = parseString(in); !ok { + return nil, errShortRead + } + if len(val) > 0 { + val, extra, ok = parseString(val) + if !ok { + return nil, errShortRead + } + if len(extra) > 0 { + return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") + } + tups[keyStr] = string(val) + } else { + tups[keyStr] = "" + } + } + return tups, nil +} + +func parseCert(in []byte, privAlgo string) (*Certificate, error) { + nonce, rest, ok := parseString(in) + if !ok { + return nil, errShortRead + } + + key, rest, err := parsePubKey(rest, privAlgo) + if err != nil { + return nil, err + } + + var g genericCertData + if err := Unmarshal(rest, &g); err != nil { + return nil, err + } + + c := &Certificate{ + Nonce: nonce, + Key: key, + Serial: g.Serial, + CertType: g.CertType, + KeyId: g.KeyId, + ValidAfter: g.ValidAfter, + ValidBefore: g.ValidBefore, + } + + for principals := g.ValidPrincipals; len(principals) > 0; { + principal, rest, ok := parseString(principals) + if !ok { + return nil, errShortRead + } + c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) + principals = rest + } + + c.CriticalOptions, err = parseTuples(g.CriticalOptions) + if err != nil { + return nil, err + } + c.Extensions, err = parseTuples(g.Extensions) + if err != nil { + return nil, err + } + c.Reserved = g.Reserved + k, err := ParsePublicKey(g.SignatureKey) + if err != nil { + return nil, err + } + + c.SignatureKey = k + c.Signature, rest, ok = parseSignatureBody(g.Signature) + if !ok || len(rest) > 0 { + return nil, errors.New("ssh: signature parse error") + } + + return c, nil +} + +type openSSHCertSigner struct { + pub *Certificate + signer Signer +} + +type algorithmOpenSSHCertSigner struct { + *openSSHCertSigner + algorithmSigner AlgorithmSigner +} + +// NewCertSigner returns a Signer that signs with the given Certificate, whose +// private key is held by signer. It returns an error if the public key in cert +// doesn't match the key used by signer. +func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { + if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { + return nil, errors.New("ssh: signer and cert have different public key") + } + + if algorithmSigner, ok := signer.(AlgorithmSigner); ok { + return &algorithmOpenSSHCertSigner{ + &openSSHCertSigner{cert, signer}, algorithmSigner}, nil + } else { + return &openSSHCertSigner{cert, signer}, nil + } +} + +func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.signer.Sign(rand, data) +} + +func (s *openSSHCertSigner) PublicKey() PublicKey { + return s.pub +} + +func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) +} + +const sourceAddressCriticalOption = "source-address" + +// CertChecker does the work of verifying a certificate. Its methods +// can be plugged into ClientConfig.HostKeyCallback and +// ServerConfig.PublicKeyCallback. For the CertChecker to work, +// minimally, the IsAuthority callback should be set. +type CertChecker struct { + // SupportedCriticalOptions lists the CriticalOptions that the + // server application layer understands. These are only used + // for user certificates. + SupportedCriticalOptions []string + + // IsUserAuthority should return true if the key is recognized as an + // authority for the given user certificate. This allows for + // certificates to be signed by other certificates. This must be set + // if this CertChecker will be checking user certificates. + IsUserAuthority func(auth PublicKey) bool + + // IsHostAuthority should report whether the key is recognized as + // an authority for this host. This allows for certificates to be + // signed by other keys, and for those other keys to only be valid + // signers for particular hostnames. This must be set if this + // CertChecker will be checking host certificates. + IsHostAuthority func(auth PublicKey, address string) bool + + // Clock is used for verifying time stamps. If nil, time.Now + // is used. + Clock func() time.Time + + // UserKeyFallback is called when CertChecker.Authenticate encounters a + // public key that is not a certificate. It must implement validation + // of user keys or else, if nil, all such keys are rejected. + UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) + + // HostKeyFallback is called when CertChecker.CheckHostKey encounters a + // public key that is not a certificate. It must implement host key + // validation or else, if nil, all such keys are rejected. + HostKeyFallback HostKeyCallback + + // IsRevoked is called for each certificate so that revocation checking + // can be implemented. It should return true if the given certificate + // is revoked and false otherwise. If nil, no certificates are + // considered to have been revoked. + IsRevoked func(cert *Certificate) bool +} + +// CheckHostKey checks a host key certificate. This method can be +// plugged into ClientConfig.HostKeyCallback. +func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { + cert, ok := key.(*Certificate) + if !ok { + if c.HostKeyFallback != nil { + return c.HostKeyFallback(addr, remote, key) + } + return errors.New("ssh: non-certificate host key") + } + if cert.CertType != HostCert { + return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) + } + if !c.IsHostAuthority(cert.SignatureKey, addr) { + return fmt.Errorf("ssh: no authorities for hostname: %v", addr) + } + + hostname, _, err := net.SplitHostPort(addr) + if err != nil { + return err + } + + // Pass hostname only as principal for host certificates (consistent with OpenSSH) + return c.CheckCert(hostname, cert) +} + +// Authenticate checks a user certificate. Authenticate can be used as +// a value for ServerConfig.PublicKeyCallback. +func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { + cert, ok := pubKey.(*Certificate) + if !ok { + if c.UserKeyFallback != nil { + return c.UserKeyFallback(conn, pubKey) + } + return nil, errors.New("ssh: normal key pairs not accepted") + } + + if cert.CertType != UserCert { + return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) + } + if !c.IsUserAuthority(cert.SignatureKey) { + return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") + } + + if err := c.CheckCert(conn.User(), cert); err != nil { + return nil, err + } + + return &cert.Permissions, nil +} + +// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and +// the signature of the certificate. +func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { + if c.IsRevoked != nil && c.IsRevoked(cert) { + return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial) + } + + for opt := range cert.CriticalOptions { + // sourceAddressCriticalOption will be enforced by + // serverAuthenticate + if opt == sourceAddressCriticalOption { + continue + } + + found := false + for _, supp := range c.SupportedCriticalOptions { + if supp == opt { + found = true + break + } + } + if !found { + return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) + } + } + + if len(cert.ValidPrincipals) > 0 { + // By default, certs are valid for all users/hosts. + found := false + for _, p := range cert.ValidPrincipals { + if p == principal { + found = true + break + } + } + if !found { + return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) + } + } + + clock := c.Clock + if clock == nil { + clock = time.Now + } + + unixNow := clock().Unix() + if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { + return fmt.Errorf("ssh: cert is not yet valid") + } + if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { + return fmt.Errorf("ssh: cert has expired") + } + if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { + return fmt.Errorf("ssh: certificate signature does not verify") + } + + return nil +} + +// SignCert signs the certificate with an authority, setting the Nonce, +// SignatureKey, and Signature fields. +func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { + c.Nonce = make([]byte, 32) + if _, err := io.ReadFull(rand, c.Nonce); err != nil { + return err + } + c.SignatureKey = authority.PublicKey() + + // Default to KeyAlgoRSASHA512 for ssh-rsa signers. + if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA { + sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512) + if err != nil { + return err + } + c.Signature = sig + return nil + } + + sig, err := authority.Sign(rand, c.bytesForSigning()) + if err != nil { + return err + } + c.Signature = sig + return nil +} + +// certKeyAlgoNames is a mapping from known certificate algorithm names to the +// corresponding public key signature algorithm. +// +// This map must be kept in sync with the one in agent/client.go. +var certKeyAlgoNames = map[string]string{ + CertAlgoRSAv01: KeyAlgoRSA, + CertAlgoRSASHA256v01: KeyAlgoRSASHA256, + CertAlgoRSASHA512v01: KeyAlgoRSASHA512, + CertAlgoDSAv01: KeyAlgoDSA, + CertAlgoECDSA256v01: KeyAlgoECDSA256, + CertAlgoECDSA384v01: KeyAlgoECDSA384, + CertAlgoECDSA521v01: KeyAlgoECDSA521, + CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256, + CertAlgoED25519v01: KeyAlgoED25519, + CertAlgoSKED25519v01: KeyAlgoSKED25519, +} + +// underlyingAlgo returns the signature algorithm associated with algo (which is +// an advertised or negotiated public key or host key algorithm). These are +// usually the same, except for certificate algorithms. +func underlyingAlgo(algo string) string { + if a, ok := certKeyAlgoNames[algo]; ok { + return a + } + return algo +} + +// certificateAlgo returns the certificate algorithms that uses the provided +// underlying signature algorithm. +func certificateAlgo(algo string) (certAlgo string, ok bool) { + for certName, algoName := range certKeyAlgoNames { + if algoName == algo { + return certName, true + } + } + return "", false +} + +func (cert *Certificate) bytesForSigning() []byte { + c2 := *cert + c2.Signature = nil + out := c2.Marshal() + // Drop trailing signature length. + return out[:len(out)-4] +} + +// Marshal serializes c into OpenSSH's wire format. It is part of the +// PublicKey interface. +func (c *Certificate) Marshal() []byte { + generic := genericCertData{ + Serial: c.Serial, + CertType: c.CertType, + KeyId: c.KeyId, + ValidPrincipals: marshalStringList(c.ValidPrincipals), + ValidAfter: uint64(c.ValidAfter), + ValidBefore: uint64(c.ValidBefore), + CriticalOptions: marshalTuples(c.CriticalOptions), + Extensions: marshalTuples(c.Extensions), + Reserved: c.Reserved, + SignatureKey: c.SignatureKey.Marshal(), + } + if c.Signature != nil { + generic.Signature = Marshal(c.Signature) + } + genericBytes := Marshal(&generic) + keyBytes := c.Key.Marshal() + _, keyBytes, _ = parseString(keyBytes) + prefix := Marshal(&struct { + Name string + Nonce []byte + Key []byte `ssh:"rest"` + }{c.Type(), c.Nonce, keyBytes}) + + result := make([]byte, 0, len(prefix)+len(genericBytes)) + result = append(result, prefix...) + result = append(result, genericBytes...) + return result +} + +// Type returns the certificate algorithm name. It is part of the PublicKey interface. +func (c *Certificate) Type() string { + certName, ok := certificateAlgo(c.Key.Type()) + if !ok { + panic("unknown certificate type for key type " + c.Key.Type()) + } + return certName +} + +// Verify verifies a signature against the certificate's public +// key. It is part of the PublicKey interface. +func (c *Certificate) Verify(data []byte, sig *Signature) error { + return c.Key.Verify(data, sig) +} + +func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { + format, in, ok := parseString(in) + if !ok { + return + } + + out = &Signature{ + Format: string(format), + } + + if out.Blob, in, ok = parseString(in); !ok { + return + } + + switch out.Format { + case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01: + out.Rest = in + return out, nil, ok + } + + return out, in, ok +} + +func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { + sigBytes, rest, ok := parseString(in) + if !ok { + return + } + + out, trailing, ok := parseSignatureBody(sigBytes) + if !ok || len(trailing) > 0 { + return nil, nil, false + } + return +} diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go new file mode 100644 index 00000000..c0834c00 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/channel.go @@ -0,0 +1,633 @@ +// 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 ssh + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "log" + "sync" +) + +const ( + minPacketLength = 9 + // channelMaxPacket contains the maximum number of bytes that will be + // sent in a single packet. As per RFC 4253, section 6.1, 32k is also + // the minimum. + channelMaxPacket = 1 << 15 + // We follow OpenSSH here. + channelWindowSize = 64 * channelMaxPacket +) + +// NewChannel represents an incoming request to a channel. It must either be +// accepted for use by calling Accept, or rejected by calling Reject. +type NewChannel interface { + // Accept accepts the channel creation request. It returns the Channel + // and a Go channel containing SSH requests. The Go channel must be + // serviced otherwise the Channel will hang. + Accept() (Channel, <-chan *Request, error) + + // Reject rejects the channel creation request. After calling + // this, no other methods on the Channel may be called. + Reject(reason RejectionReason, message string) error + + // ChannelType returns the type of the channel, as supplied by the + // client. + ChannelType() string + + // ExtraData returns the arbitrary payload for this channel, as supplied + // by the client. This data is specific to the channel type. + ExtraData() []byte +} + +// A Channel is an ordered, reliable, flow-controlled, duplex stream +// that is multiplexed over an SSH connection. +type Channel interface { + // Read reads up to len(data) bytes from the channel. + Read(data []byte) (int, error) + + // Write writes len(data) bytes to the channel. + Write(data []byte) (int, error) + + // Close signals end of channel use. No data may be sent after this + // call. + Close() error + + // CloseWrite signals the end of sending in-band + // data. Requests may still be sent, and the other side may + // still send data + CloseWrite() error + + // SendRequest sends a channel request. If wantReply is true, + // it will wait for a reply and return the result as a + // boolean, otherwise the return value will be false. Channel + // requests are out-of-band messages so they may be sent even + // if the data stream is closed or blocked by flow control. + // If the channel is closed before a reply is returned, io.EOF + // is returned. + SendRequest(name string, wantReply bool, payload []byte) (bool, error) + + // Stderr returns an io.ReadWriter that writes to this channel + // with the extended data type set to stderr. Stderr may + // safely be read and written from a different goroutine than + // Read and Write respectively. + Stderr() io.ReadWriter +} + +// Request is a request sent outside of the normal stream of +// data. Requests can either be specific to an SSH channel, or they +// can be global. +type Request struct { + Type string + WantReply bool + Payload []byte + + ch *channel + mux *mux +} + +// Reply sends a response to a request. It must be called for all requests +// where WantReply is true and is a no-op otherwise. The payload argument is +// ignored for replies to channel-specific requests. +func (r *Request) Reply(ok bool, payload []byte) error { + if !r.WantReply { + return nil + } + + if r.ch == nil { + return r.mux.ackRequest(ok, payload) + } + + return r.ch.ackRequest(ok) +} + +// RejectionReason is an enumeration used when rejecting channel creation +// requests. See RFC 4254, section 5.1. +type RejectionReason uint32 + +const ( + Prohibited RejectionReason = iota + 1 + ConnectionFailed + UnknownChannelType + ResourceShortage +) + +// String converts the rejection reason to human readable form. +func (r RejectionReason) String() string { + switch r { + case Prohibited: + return "administratively prohibited" + case ConnectionFailed: + return "connect failed" + case UnknownChannelType: + return "unknown channel type" + case ResourceShortage: + return "resource shortage" + } + return fmt.Sprintf("unknown reason %d", int(r)) +} + +func min(a uint32, b int) uint32 { + if a < uint32(b) { + return a + } + return uint32(b) +} + +type channelDirection uint8 + +const ( + channelInbound channelDirection = iota + channelOutbound +) + +// channel is an implementation of the Channel interface that works +// with the mux class. +type channel struct { + // R/O after creation + chanType string + extraData []byte + localId, remoteId uint32 + + // maxIncomingPayload and maxRemotePayload are the maximum + // payload sizes of normal and extended data packets for + // receiving and sending, respectively. The wire packet will + // be 9 or 13 bytes larger (excluding encryption overhead). + maxIncomingPayload uint32 + maxRemotePayload uint32 + + mux *mux + + // decided is set to true if an accept or reject message has been sent + // (for outbound channels) or received (for inbound channels). + decided bool + + // direction contains either channelOutbound, for channels created + // locally, or channelInbound, for channels created by the peer. + direction channelDirection + + // Pending internal channel messages. + msg chan interface{} + + // Since requests have no ID, there can be only one request + // with WantReply=true outstanding. This lock is held by a + // goroutine that has such an outgoing request pending. + sentRequestMu sync.Mutex + + incomingRequests chan *Request + + sentEOF bool + + // thread-safe data + remoteWin window + pending *buffer + extPending *buffer + + // windowMu protects myWindow, the flow-control window. + windowMu sync.Mutex + myWindow uint32 + + // writeMu serializes calls to mux.conn.writePacket() and + // protects sentClose and packetPool. This mutex must be + // different from windowMu, as writePacket can block if there + // is a key exchange pending. + writeMu sync.Mutex + sentClose bool + + // packetPool has a buffer for each extended channel ID to + // save allocations during writes. + packetPool map[uint32][]byte +} + +// writePacket sends a packet. If the packet is a channel close, it updates +// sentClose. This method takes the lock c.writeMu. +func (ch *channel) writePacket(packet []byte) error { + ch.writeMu.Lock() + if ch.sentClose { + ch.writeMu.Unlock() + return io.EOF + } + ch.sentClose = (packet[0] == msgChannelClose) + err := ch.mux.conn.writePacket(packet) + ch.writeMu.Unlock() + return err +} + +func (ch *channel) sendMessage(msg interface{}) error { + if debugMux { + log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg) + } + + p := Marshal(msg) + binary.BigEndian.PutUint32(p[1:], ch.remoteId) + return ch.writePacket(p) +} + +// WriteExtended writes data to a specific extended stream. These streams are +// used, for example, for stderr. +func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { + if ch.sentEOF { + return 0, io.EOF + } + // 1 byte message type, 4 bytes remoteId, 4 bytes data length + opCode := byte(msgChannelData) + headerLength := uint32(9) + if extendedCode > 0 { + headerLength += 4 + opCode = msgChannelExtendedData + } + + ch.writeMu.Lock() + packet := ch.packetPool[extendedCode] + // We don't remove the buffer from packetPool, so + // WriteExtended calls from different goroutines will be + // flagged as errors by the race detector. + ch.writeMu.Unlock() + + for len(data) > 0 { + space := min(ch.maxRemotePayload, len(data)) + if space, err = ch.remoteWin.reserve(space); err != nil { + return n, err + } + if want := headerLength + space; uint32(cap(packet)) < want { + packet = make([]byte, want) + } else { + packet = packet[:want] + } + + todo := data[:space] + + packet[0] = opCode + binary.BigEndian.PutUint32(packet[1:], ch.remoteId) + if extendedCode > 0 { + binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) + } + binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) + copy(packet[headerLength:], todo) + if err = ch.writePacket(packet); err != nil { + return n, err + } + + n += len(todo) + data = data[len(todo):] + } + + ch.writeMu.Lock() + ch.packetPool[extendedCode] = packet + ch.writeMu.Unlock() + + return n, err +} + +func (ch *channel) handleData(packet []byte) error { + headerLen := 9 + isExtendedData := packet[0] == msgChannelExtendedData + if isExtendedData { + headerLen = 13 + } + if len(packet) < headerLen { + // malformed data packet + return parseError(packet[0]) + } + + var extended uint32 + if isExtendedData { + extended = binary.BigEndian.Uint32(packet[5:]) + } + + length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) + if length == 0 { + return nil + } + if length > ch.maxIncomingPayload { + // TODO(hanwen): should send Disconnect? + return errors.New("ssh: incoming packet exceeds maximum payload size") + } + + data := packet[headerLen:] + if length != uint32(len(data)) { + return errors.New("ssh: wrong packet length") + } + + ch.windowMu.Lock() + if ch.myWindow < length { + ch.windowMu.Unlock() + // TODO(hanwen): should send Disconnect with reason? + return errors.New("ssh: remote side wrote too much") + } + ch.myWindow -= length + ch.windowMu.Unlock() + + if extended == 1 { + ch.extPending.write(data) + } else if extended > 0 { + // discard other extended data. + } else { + ch.pending.write(data) + } + return nil +} + +func (c *channel) adjustWindow(n uint32) error { + c.windowMu.Lock() + // Since myWindow is managed on our side, and can never exceed + // the initial window setting, we don't worry about overflow. + c.myWindow += uint32(n) + c.windowMu.Unlock() + return c.sendMessage(windowAdjustMsg{ + AdditionalBytes: uint32(n), + }) +} + +func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { + switch extended { + case 1: + n, err = c.extPending.Read(data) + case 0: + n, err = c.pending.Read(data) + default: + return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) + } + + if n > 0 { + err = c.adjustWindow(uint32(n)) + // sendWindowAdjust can return io.EOF if the remote + // peer has closed the connection, however we want to + // defer forwarding io.EOF to the caller of Read until + // the buffer has been drained. + if n > 0 && err == io.EOF { + err = nil + } + } + + return n, err +} + +func (c *channel) close() { + c.pending.eof() + c.extPending.eof() + close(c.msg) + close(c.incomingRequests) + c.writeMu.Lock() + // This is not necessary for a normal channel teardown, but if + // there was another error, it is. + c.sentClose = true + c.writeMu.Unlock() + // Unblock writers. + c.remoteWin.close() +} + +// responseMessageReceived is called when a success or failure message is +// received on a channel to check that such a message is reasonable for the +// given channel. +func (ch *channel) responseMessageReceived() error { + if ch.direction == channelInbound { + return errors.New("ssh: channel response message received on inbound channel") + } + if ch.decided { + return errors.New("ssh: duplicate response received for channel") + } + ch.decided = true + return nil +} + +func (ch *channel) handlePacket(packet []byte) error { + switch packet[0] { + case msgChannelData, msgChannelExtendedData: + return ch.handleData(packet) + case msgChannelClose: + ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId}) + ch.mux.chanList.remove(ch.localId) + ch.close() + return nil + case msgChannelEOF: + // RFC 4254 is mute on how EOF affects dataExt messages but + // it is logical to signal EOF at the same time. + ch.extPending.eof() + ch.pending.eof() + return nil + } + + decoded, err := decode(packet) + if err != nil { + return err + } + + switch msg := decoded.(type) { + case *channelOpenFailureMsg: + if err := ch.responseMessageReceived(); err != nil { + return err + } + ch.mux.chanList.remove(msg.PeersID) + ch.msg <- msg + case *channelOpenConfirmMsg: + if err := ch.responseMessageReceived(); err != nil { + return err + } + if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { + return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) + } + ch.remoteId = msg.MyID + ch.maxRemotePayload = msg.MaxPacketSize + ch.remoteWin.add(msg.MyWindow) + ch.msg <- msg + case *windowAdjustMsg: + if !ch.remoteWin.add(msg.AdditionalBytes) { + return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) + } + case *channelRequestMsg: + req := Request{ + Type: msg.Request, + WantReply: msg.WantReply, + Payload: msg.RequestSpecificData, + ch: ch, + } + + ch.incomingRequests <- &req + default: + ch.msg <- msg + } + return nil +} + +func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { + ch := &channel{ + remoteWin: window{Cond: newCond()}, + myWindow: channelWindowSize, + pending: newBuffer(), + extPending: newBuffer(), + direction: direction, + incomingRequests: make(chan *Request, chanSize), + msg: make(chan interface{}, chanSize), + chanType: chanType, + extraData: extraData, + mux: m, + packetPool: make(map[uint32][]byte), + } + ch.localId = m.chanList.add(ch) + return ch +} + +var errUndecided = errors.New("ssh: must Accept or Reject channel") +var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") + +type extChannel struct { + code uint32 + ch *channel +} + +func (e *extChannel) Write(data []byte) (n int, err error) { + return e.ch.WriteExtended(data, e.code) +} + +func (e *extChannel) Read(data []byte) (n int, err error) { + return e.ch.ReadExtended(data, e.code) +} + +func (ch *channel) Accept() (Channel, <-chan *Request, error) { + if ch.decided { + return nil, nil, errDecidedAlready + } + ch.maxIncomingPayload = channelMaxPacket + confirm := channelOpenConfirmMsg{ + PeersID: ch.remoteId, + MyID: ch.localId, + MyWindow: ch.myWindow, + MaxPacketSize: ch.maxIncomingPayload, + } + ch.decided = true + if err := ch.sendMessage(confirm); err != nil { + return nil, nil, err + } + + return ch, ch.incomingRequests, nil +} + +func (ch *channel) Reject(reason RejectionReason, message string) error { + if ch.decided { + return errDecidedAlready + } + reject := channelOpenFailureMsg{ + PeersID: ch.remoteId, + Reason: reason, + Message: message, + Language: "en", + } + ch.decided = true + return ch.sendMessage(reject) +} + +func (ch *channel) Read(data []byte) (int, error) { + if !ch.decided { + return 0, errUndecided + } + return ch.ReadExtended(data, 0) +} + +func (ch *channel) Write(data []byte) (int, error) { + if !ch.decided { + return 0, errUndecided + } + return ch.WriteExtended(data, 0) +} + +func (ch *channel) CloseWrite() error { + if !ch.decided { + return errUndecided + } + ch.sentEOF = true + return ch.sendMessage(channelEOFMsg{ + PeersID: ch.remoteId}) +} + +func (ch *channel) Close() error { + if !ch.decided { + return errUndecided + } + + return ch.sendMessage(channelCloseMsg{ + PeersID: ch.remoteId}) +} + +// Extended returns an io.ReadWriter that sends and receives data on the given, +// SSH extended stream. Such streams are used, for example, for stderr. +func (ch *channel) Extended(code uint32) io.ReadWriter { + if !ch.decided { + return nil + } + return &extChannel{code, ch} +} + +func (ch *channel) Stderr() io.ReadWriter { + return ch.Extended(1) +} + +func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { + if !ch.decided { + return false, errUndecided + } + + if wantReply { + ch.sentRequestMu.Lock() + defer ch.sentRequestMu.Unlock() + } + + msg := channelRequestMsg{ + PeersID: ch.remoteId, + Request: name, + WantReply: wantReply, + RequestSpecificData: payload, + } + + if err := ch.sendMessage(msg); err != nil { + return false, err + } + + if wantReply { + m, ok := (<-ch.msg) + if !ok { + return false, io.EOF + } + switch m.(type) { + case *channelRequestFailureMsg: + return false, nil + case *channelRequestSuccessMsg: + return true, nil + default: + return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) + } + } + + return false, nil +} + +// ackRequest either sends an ack or nack to the channel request. +func (ch *channel) ackRequest(ok bool) error { + if !ch.decided { + return errUndecided + } + + var msg interface{} + if !ok { + msg = channelRequestFailureMsg{ + PeersID: ch.remoteId, + } + } else { + msg = channelRequestSuccessMsg{ + PeersID: ch.remoteId, + } + } + return ch.sendMessage(msg) +} + +func (ch *channel) ChannelType() string { + return ch.chanType +} + +func (ch *channel) ExtraData() []byte { + return ch.extraData +} diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go new file mode 100644 index 00000000..770e8a66 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/cipher.go @@ -0,0 +1,789 @@ +// 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 ssh + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/rc4" + "crypto/subtle" + "encoding/binary" + "errors" + "fmt" + "hash" + "io" + "io/ioutil" + + "golang.org/x/crypto/chacha20" + "golang.org/x/crypto/internal/poly1305" +) + +const ( + packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. + + // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations + // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC + // indicates implementations SHOULD be able to handle larger packet sizes, but then + // waffles on about reasonable limits. + // + // OpenSSH caps their maxPacket at 256kB so we choose to do + // the same. maxPacket is also used to ensure that uint32 + // length fields do not overflow, so it should remain well + // below 4G. + maxPacket = 256 * 1024 +) + +// noneCipher implements cipher.Stream and provides no encryption. It is used +// by the transport before the first key-exchange. +type noneCipher struct{} + +func (c noneCipher) XORKeyStream(dst, src []byte) { + copy(dst, src) +} + +func newAESCTR(key, iv []byte) (cipher.Stream, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + return cipher.NewCTR(c, iv), nil +} + +func newRC4(key, iv []byte) (cipher.Stream, error) { + return rc4.NewCipher(key) +} + +type cipherMode struct { + keySize int + ivSize int + create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) +} + +func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + stream, err := createFunc(key, iv) + if err != nil { + return nil, err + } + + var streamDump []byte + if skip > 0 { + streamDump = make([]byte, 512) + } + + for remainingToDump := skip; remainingToDump > 0; { + dumpThisTime := remainingToDump + if dumpThisTime > len(streamDump) { + dumpThisTime = len(streamDump) + } + stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) + remainingToDump -= dumpThisTime + } + + mac := macModes[algs.MAC].new(macKey) + return &streamPacketCipher{ + mac: mac, + etm: macModes[algs.MAC].etm, + macResult: make([]byte, mac.Size()), + cipher: stream, + }, nil + } +} + +// cipherModes documents properties of supported ciphers. Ciphers not included +// are not supported and will not be negotiated, even if explicitly requested in +// ClientConfig.Crypto.Ciphers. +var cipherModes = map[string]*cipherMode{ + // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms + // are defined in the order specified in the RFC. + "aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + "aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + "aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + + // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. + // They are defined in the order specified in the RFC. + "arcfour128": {16, 0, streamCipherMode(1536, newRC4)}, + "arcfour256": {32, 0, streamCipherMode(1536, newRC4)}, + + // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. + // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and + // RC4) has problems with weak keys, and should be used with caution." + // RFC4345 introduces improved versions of Arcfour. + "arcfour": {16, 0, streamCipherMode(0, newRC4)}, + + // AEAD ciphers + gcmCipherID: {16, 12, newGCMCipher}, + chacha20Poly1305ID: {64, 0, newChaCha20Cipher}, + + // CBC mode is insecure and so is not included in the default config. + // (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely + // needed, it's possible to specify a custom Config to enable it. + // You should expect that an active attacker can recover plaintext if + // you do. + aes128cbcID: {16, aes.BlockSize, newAESCBCCipher}, + + // 3des-cbc is insecure and is not included in the default + // config. + tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher}, +} + +// prefixLen is the length of the packet prefix that contains the packet length +// and number of padding bytes. +const prefixLen = 5 + +// streamPacketCipher is a packetCipher using a stream cipher. +type streamPacketCipher struct { + mac hash.Hash + cipher cipher.Stream + etm bool + + // The following members are to avoid per-packet allocations. + prefix [prefixLen]byte + seqNumBytes [4]byte + padding [2 * packetSizeMultiple]byte + packetData []byte + macResult []byte +} + +// readCipherPacket reads and decrypt a single packet from the reader argument. +func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { + if _, err := io.ReadFull(r, s.prefix[:]); err != nil { + return nil, err + } + + var encryptedPaddingLength [1]byte + if s.mac != nil && s.etm { + copy(encryptedPaddingLength[:], s.prefix[4:5]) + s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) + } else { + s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + } + + length := binary.BigEndian.Uint32(s.prefix[0:4]) + paddingLength := uint32(s.prefix[4]) + + var macSize uint32 + if s.mac != nil { + s.mac.Reset() + binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) + s.mac.Write(s.seqNumBytes[:]) + if s.etm { + s.mac.Write(s.prefix[:4]) + s.mac.Write(encryptedPaddingLength[:]) + } else { + s.mac.Write(s.prefix[:]) + } + macSize = uint32(s.mac.Size()) + } + + if length <= paddingLength+1 { + return nil, errors.New("ssh: invalid packet length, packet too small") + } + + if length > maxPacket { + return nil, errors.New("ssh: invalid packet length, packet too large") + } + + // the maxPacket check above ensures that length-1+macSize + // does not overflow. + if uint32(cap(s.packetData)) < length-1+macSize { + s.packetData = make([]byte, length-1+macSize) + } else { + s.packetData = s.packetData[:length-1+macSize] + } + + if _, err := io.ReadFull(r, s.packetData); err != nil { + return nil, err + } + mac := s.packetData[length-1:] + data := s.packetData[:length-1] + + if s.mac != nil && s.etm { + s.mac.Write(data) + } + + s.cipher.XORKeyStream(data, data) + + if s.mac != nil { + if !s.etm { + s.mac.Write(data) + } + s.macResult = s.mac.Sum(s.macResult[:0]) + if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { + return nil, errors.New("ssh: MAC failure") + } + } + + return s.packetData[:length-paddingLength-1], nil +} + +// writeCipherPacket encrypts and sends a packet of data to the writer argument +func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { + if len(packet) > maxPacket { + return errors.New("ssh: packet too large") + } + + aadlen := 0 + if s.mac != nil && s.etm { + // packet length is not encrypted for EtM modes + aadlen = 4 + } + + paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple + if paddingLength < 4 { + paddingLength += packetSizeMultiple + } + + length := len(packet) + 1 + paddingLength + binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) + s.prefix[4] = byte(paddingLength) + padding := s.padding[:paddingLength] + if _, err := io.ReadFull(rand, padding); err != nil { + return err + } + + if s.mac != nil { + s.mac.Reset() + binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) + s.mac.Write(s.seqNumBytes[:]) + + if s.etm { + // For EtM algorithms, the packet length must stay unencrypted, + // but the following data (padding length) must be encrypted + s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) + } + + s.mac.Write(s.prefix[:]) + + if !s.etm { + // For non-EtM algorithms, the algorithm is applied on unencrypted data + s.mac.Write(packet) + s.mac.Write(padding) + } + } + + if !(s.mac != nil && s.etm) { + // For EtM algorithms, the padding length has already been encrypted + // and the packet length must remain unencrypted + s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + } + + s.cipher.XORKeyStream(packet, packet) + s.cipher.XORKeyStream(padding, padding) + + if s.mac != nil && s.etm { + // For EtM algorithms, packet and padding must be encrypted + s.mac.Write(packet) + s.mac.Write(padding) + } + + if _, err := w.Write(s.prefix[:]); err != nil { + return err + } + if _, err := w.Write(packet); err != nil { + return err + } + if _, err := w.Write(padding); err != nil { + return err + } + + if s.mac != nil { + s.macResult = s.mac.Sum(s.macResult[:0]) + if _, err := w.Write(s.macResult); err != nil { + return err + } + } + + return nil +} + +type gcmCipher struct { + aead cipher.AEAD + prefix [4]byte + iv []byte + buf []byte +} + +func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aead, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + return &gcmCipher{ + aead: aead, + iv: iv, + }, nil +} + +const gcmTagSize = 16 + +func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { + // Pad out to multiple of 16 bytes. This is different from the + // stream cipher because that encrypts the length too. + padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) + if padding < 4 { + padding += packetSizeMultiple + } + + length := uint32(len(packet) + int(padding) + 1) + binary.BigEndian.PutUint32(c.prefix[:], length) + if _, err := w.Write(c.prefix[:]); err != nil { + return err + } + + if cap(c.buf) < int(length) { + c.buf = make([]byte, length) + } else { + c.buf = c.buf[:length] + } + + c.buf[0] = padding + copy(c.buf[1:], packet) + if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { + return err + } + c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) + if _, err := w.Write(c.buf); err != nil { + return err + } + c.incIV() + + return nil +} + +func (c *gcmCipher) incIV() { + for i := 4 + 7; i >= 4; i-- { + c.iv[i]++ + if c.iv[i] != 0 { + break + } + } +} + +func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { + if _, err := io.ReadFull(r, c.prefix[:]); err != nil { + return nil, err + } + length := binary.BigEndian.Uint32(c.prefix[:]) + if length > maxPacket { + return nil, errors.New("ssh: max packet length exceeded") + } + + if cap(c.buf) < int(length+gcmTagSize) { + c.buf = make([]byte, length+gcmTagSize) + } else { + c.buf = c.buf[:length+gcmTagSize] + } + + if _, err := io.ReadFull(r, c.buf); err != nil { + return nil, err + } + + plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) + if err != nil { + return nil, err + } + c.incIV() + + if len(plain) == 0 { + return nil, errors.New("ssh: empty packet") + } + + padding := plain[0] + if padding < 4 { + // padding is a byte, so it automatically satisfies + // the maximum size, which is 255. + return nil, fmt.Errorf("ssh: illegal padding %d", padding) + } + + if int(padding+1) >= len(plain) { + return nil, fmt.Errorf("ssh: padding %d too large", padding) + } + plain = plain[1 : length-uint32(padding)] + return plain, nil +} + +// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 +type cbcCipher struct { + mac hash.Hash + macSize uint32 + decrypter cipher.BlockMode + encrypter cipher.BlockMode + + // The following members are to avoid per-packet allocations. + seqNumBytes [4]byte + packetData []byte + macResult []byte + + // Amount of data we should still read to hide which + // verification error triggered. + oracleCamouflage uint32 +} + +func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + cbc := &cbcCipher{ + mac: macModes[algs.MAC].new(macKey), + decrypter: cipher.NewCBCDecrypter(c, iv), + encrypter: cipher.NewCBCEncrypter(c, iv), + packetData: make([]byte, 1024), + } + if cbc.mac != nil { + cbc.macSize = uint32(cbc.mac.Size()) + } + + return cbc, nil +} + +func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + cbc, err := newCBCCipher(c, key, iv, macKey, algs) + if err != nil { + return nil, err + } + + return cbc, nil +} + +func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + c, err := des.NewTripleDESCipher(key) + if err != nil { + return nil, err + } + + cbc, err := newCBCCipher(c, key, iv, macKey, algs) + if err != nil { + return nil, err + } + + return cbc, nil +} + +func maxUInt32(a, b int) uint32 { + if a > b { + return uint32(a) + } + return uint32(b) +} + +const ( + cbcMinPacketSizeMultiple = 8 + cbcMinPacketSize = 16 + cbcMinPaddingSize = 4 +) + +// cbcError represents a verification error that may leak information. +type cbcError string + +func (e cbcError) Error() string { return string(e) } + +func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { + p, err := c.readCipherPacketLeaky(seqNum, r) + if err != nil { + if _, ok := err.(cbcError); ok { + // Verification error: read a fixed amount of + // data, to make distinguishing between + // failing MAC and failing length check more + // difficult. + io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) + } + } + return p, err +} + +func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { + blockSize := c.decrypter.BlockSize() + + // Read the header, which will include some of the subsequent data in the + // case of block ciphers - this is copied back to the payload later. + // How many bytes of payload/padding will be read with this first read. + firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) + firstBlock := c.packetData[:firstBlockLength] + if _, err := io.ReadFull(r, firstBlock); err != nil { + return nil, err + } + + c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength + + c.decrypter.CryptBlocks(firstBlock, firstBlock) + length := binary.BigEndian.Uint32(firstBlock[:4]) + if length > maxPacket { + return nil, cbcError("ssh: packet too large") + } + if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { + // The minimum size of a packet is 16 (or the cipher block size, whichever + // is larger) bytes. + return nil, cbcError("ssh: packet too small") + } + // The length of the packet (including the length field but not the MAC) must + // be a multiple of the block size or 8, whichever is larger. + if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { + return nil, cbcError("ssh: invalid packet length multiple") + } + + paddingLength := uint32(firstBlock[4]) + if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { + return nil, cbcError("ssh: invalid packet length") + } + + // Positions within the c.packetData buffer: + macStart := 4 + length + paddingStart := macStart - paddingLength + + // Entire packet size, starting before length, ending at end of mac. + entirePacketSize := macStart + c.macSize + + // Ensure c.packetData is large enough for the entire packet data. + if uint32(cap(c.packetData)) < entirePacketSize { + // Still need to upsize and copy, but this should be rare at runtime, only + // on upsizing the packetData buffer. + c.packetData = make([]byte, entirePacketSize) + copy(c.packetData, firstBlock) + } else { + c.packetData = c.packetData[:entirePacketSize] + } + + n, err := io.ReadFull(r, c.packetData[firstBlockLength:]) + if err != nil { + return nil, err + } + c.oracleCamouflage -= uint32(n) + + remainingCrypted := c.packetData[firstBlockLength:macStart] + c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) + + mac := c.packetData[macStart:] + if c.mac != nil { + c.mac.Reset() + binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) + c.mac.Write(c.seqNumBytes[:]) + c.mac.Write(c.packetData[:macStart]) + c.macResult = c.mac.Sum(c.macResult[:0]) + if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { + return nil, cbcError("ssh: MAC failure") + } + } + + return c.packetData[prefixLen:paddingStart], nil +} + +func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { + effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) + + // Length of encrypted portion of the packet (header, payload, padding). + // Enforce minimum padding and packet size. + encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) + // Enforce block size. + encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize + + length := encLength - 4 + paddingLength := int(length) - (1 + len(packet)) + + // Overall buffer contains: header, payload, padding, mac. + // Space for the MAC is reserved in the capacity but not the slice length. + bufferSize := encLength + c.macSize + if uint32(cap(c.packetData)) < bufferSize { + c.packetData = make([]byte, encLength, bufferSize) + } else { + c.packetData = c.packetData[:encLength] + } + + p := c.packetData + + // Packet header. + binary.BigEndian.PutUint32(p, length) + p = p[4:] + p[0] = byte(paddingLength) + + // Payload. + p = p[1:] + copy(p, packet) + + // Padding. + p = p[len(packet):] + if _, err := io.ReadFull(rand, p); err != nil { + return err + } + + if c.mac != nil { + c.mac.Reset() + binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) + c.mac.Write(c.seqNumBytes[:]) + c.mac.Write(c.packetData) + // The MAC is now appended into the capacity reserved for it earlier. + c.packetData = c.mac.Sum(c.packetData) + } + + c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) + + if _, err := w.Write(c.packetData); err != nil { + return err + } + + return nil +} + +const chacha20Poly1305ID = "chacha20-poly1305@openssh.com" + +// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com +// AEAD, which is described here: +// +// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 +// +// the methods here also implement padding, which RFC4253 Section 6 +// also requires of stream ciphers. +type chacha20Poly1305Cipher struct { + lengthKey [32]byte + contentKey [32]byte + buf []byte +} + +func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { + if len(key) != 64 { + panic(len(key)) + } + + c := &chacha20Poly1305Cipher{ + buf: make([]byte, 256), + } + + copy(c.contentKey[:], key[:32]) + copy(c.lengthKey[:], key[32:]) + return c, nil +} + +func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { + nonce := make([]byte, 12) + binary.BigEndian.PutUint32(nonce[8:], seqNum) + s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce) + if err != nil { + return nil, err + } + var polyKey, discardBuf [32]byte + s.XORKeyStream(polyKey[:], polyKey[:]) + s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes + + encryptedLength := c.buf[:4] + if _, err := io.ReadFull(r, encryptedLength); err != nil { + return nil, err + } + + var lenBytes [4]byte + ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce) + if err != nil { + return nil, err + } + ls.XORKeyStream(lenBytes[:], encryptedLength) + + length := binary.BigEndian.Uint32(lenBytes[:]) + if length > maxPacket { + return nil, errors.New("ssh: invalid packet length, packet too large") + } + + contentEnd := 4 + length + packetEnd := contentEnd + poly1305.TagSize + if uint32(cap(c.buf)) < packetEnd { + c.buf = make([]byte, packetEnd) + copy(c.buf[:], encryptedLength) + } else { + c.buf = c.buf[:packetEnd] + } + + if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil { + return nil, err + } + + var mac [poly1305.TagSize]byte + copy(mac[:], c.buf[contentEnd:packetEnd]) + if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) { + return nil, errors.New("ssh: MAC failure") + } + + plain := c.buf[4:contentEnd] + s.XORKeyStream(plain, plain) + + if len(plain) == 0 { + return nil, errors.New("ssh: empty packet") + } + + padding := plain[0] + if padding < 4 { + // padding is a byte, so it automatically satisfies + // the maximum size, which is 255. + return nil, fmt.Errorf("ssh: illegal padding %d", padding) + } + + if int(padding)+1 >= len(plain) { + return nil, fmt.Errorf("ssh: padding %d too large", padding) + } + + plain = plain[1 : len(plain)-int(padding)] + + return plain, nil +} + +func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { + nonce := make([]byte, 12) + binary.BigEndian.PutUint32(nonce[8:], seqNum) + s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce) + if err != nil { + return err + } + var polyKey, discardBuf [32]byte + s.XORKeyStream(polyKey[:], polyKey[:]) + s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes + + // There is no blocksize, so fall back to multiple of 8 byte + // padding, as described in RFC 4253, Sec 6. + const packetSizeMultiple = 8 + + padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple + if padding < 4 { + padding += packetSizeMultiple + } + + // size (4 bytes), padding (1), payload, padding, tag. + totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize + if cap(c.buf) < totalLength { + c.buf = make([]byte, totalLength) + } else { + c.buf = c.buf[:totalLength] + } + + binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) + ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce) + if err != nil { + return err + } + ls.XORKeyStream(c.buf, c.buf[:4]) + c.buf[4] = byte(padding) + copy(c.buf[5:], payload) + packetEnd := 5 + len(payload) + padding + if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil { + return err + } + + s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) + + var mac [poly1305.TagSize]byte + poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) + + copy(c.buf[packetEnd:], mac[:]) + + if _, err := w.Write(c.buf); err != nil { + return err + } + return nil +} diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go new file mode 100644 index 00000000..bdc356cb --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -0,0 +1,282 @@ +// 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 ssh + +import ( + "bytes" + "errors" + "fmt" + "net" + "os" + "sync" + "time" +) + +// Client implements a traditional SSH client that supports shells, +// subprocesses, TCP port/streamlocal forwarding and tunneled dialing. +type Client struct { + Conn + + handleForwardsOnce sync.Once // guards calling (*Client).handleForwards + + forwards forwardList // forwarded tcpip connections from the remote side + mu sync.Mutex + channelHandlers map[string]chan NewChannel +} + +// HandleChannelOpen returns a channel on which NewChannel requests +// for the given type are sent. If the type already is being handled, +// nil is returned. The channel is closed when the connection is closed. +func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { + c.mu.Lock() + defer c.mu.Unlock() + if c.channelHandlers == nil { + // The SSH channel has been closed. + c := make(chan NewChannel) + close(c) + return c + } + + ch := c.channelHandlers[channelType] + if ch != nil { + return nil + } + + ch = make(chan NewChannel, chanSize) + c.channelHandlers[channelType] = ch + return ch +} + +// NewClient creates a Client on top of the given connection. +func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { + conn := &Client{ + Conn: c, + channelHandlers: make(map[string]chan NewChannel, 1), + } + + go conn.handleGlobalRequests(reqs) + go conn.handleChannelOpens(chans) + go func() { + conn.Wait() + conn.forwards.closeAll() + }() + return conn +} + +// NewClientConn establishes an authenticated SSH connection using c +// as the underlying transport. The Request and NewChannel channels +// must be serviced or the connection will hang. +func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { + fullConf := *config + fullConf.SetDefaults() + if fullConf.HostKeyCallback == nil { + c.Close() + return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback") + } + + conn := &connection{ + sshConn: sshConn{conn: c, user: fullConf.User}, + } + + if err := conn.clientHandshake(addr, &fullConf); err != nil { + c.Close() + return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) + } + conn.mux = newMux(conn.transport) + return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil +} + +// clientHandshake performs the client side key exchange. See RFC 4253 Section +// 7. +func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { + if config.ClientVersion != "" { + c.clientVersion = []byte(config.ClientVersion) + } else { + c.clientVersion = []byte(packageVersion) + } + var err error + c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) + if err != nil { + return err + } + + c.transport = newClientTransport( + newTransport(c.sshConn.conn, config.Rand, true /* is client */), + c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) + if err := c.transport.waitSession(); err != nil { + return err + } + + c.sessionID = c.transport.getSessionID() + return c.clientAuthenticate(config) +} + +// verifyHostKeySignature verifies the host key obtained in the key exchange. +// algo is the negotiated algorithm, and may be a certificate type. +func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error { + sig, rest, ok := parseSignatureBody(result.Signature) + if len(rest) > 0 || !ok { + return errors.New("ssh: signature parse error") + } + + if a := underlyingAlgo(algo); sig.Format != a { + return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, a) + } + + return hostKey.Verify(result.H, sig) +} + +// NewSession opens a new Session for this client. (A session is a remote +// execution of a program.) +func (c *Client) NewSession() (*Session, error) { + ch, in, err := c.OpenChannel("session", nil) + if err != nil { + return nil, err + } + return newSession(ch, in) +} + +func (c *Client) handleGlobalRequests(incoming <-chan *Request) { + for r := range incoming { + // This handles keepalive messages and matches + // the behaviour of OpenSSH. + r.Reply(false, nil) + } +} + +// handleChannelOpens channel open messages from the remote side. +func (c *Client) handleChannelOpens(in <-chan NewChannel) { + for ch := range in { + c.mu.Lock() + handler := c.channelHandlers[ch.ChannelType()] + c.mu.Unlock() + + if handler != nil { + handler <- ch + } else { + ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) + } + } + + c.mu.Lock() + for _, ch := range c.channelHandlers { + close(ch) + } + c.channelHandlers = nil + c.mu.Unlock() +} + +// Dial starts a client connection to the given SSH server. It is a +// convenience function that connects to the given network address, +// initiates the SSH handshake, and then sets up a Client. For access +// to incoming channels and requests, use net.Dial with NewClientConn +// instead. +func Dial(network, addr string, config *ClientConfig) (*Client, error) { + conn, err := net.DialTimeout(network, addr, config.Timeout) + if err != nil { + return nil, err + } + c, chans, reqs, err := NewClientConn(conn, addr, config) + if err != nil { + return nil, err + } + return NewClient(c, chans, reqs), nil +} + +// HostKeyCallback is the function type used for verifying server +// keys. A HostKeyCallback must return nil if the host key is OK, or +// an error to reject it. It receives the hostname as passed to Dial +// or NewClientConn. The remote address is the RemoteAddr of the +// net.Conn underlying the SSH connection. +type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error + +// BannerCallback is the function type used for treat the banner sent by +// the server. A BannerCallback receives the message sent by the remote server. +type BannerCallback func(message string) error + +// A ClientConfig structure is used to configure a Client. It must not be +// modified after having been passed to an SSH function. +type ClientConfig struct { + // Config contains configuration that is shared between clients and + // servers. + Config + + // User contains the username to authenticate as. + User string + + // Auth contains possible authentication methods to use with the + // server. Only the first instance of a particular RFC 4252 method will + // be used during authentication. + Auth []AuthMethod + + // HostKeyCallback is called during the cryptographic + // handshake to validate the server's host key. The client + // configuration must supply this callback for the connection + // to succeed. The functions InsecureIgnoreHostKey or + // FixedHostKey can be used for simplistic host key checks. + HostKeyCallback HostKeyCallback + + // BannerCallback is called during the SSH dance to display a custom + // server's message. The client configuration can supply this callback to + // handle it as wished. The function BannerDisplayStderr can be used for + // simplistic display on Stderr. + BannerCallback BannerCallback + + // ClientVersion contains the version identification string that will + // be used for the connection. If empty, a reasonable default is used. + ClientVersion string + + // HostKeyAlgorithms lists the public key algorithms that the client will + // accept from the server for host key authentication, in order of + // preference. If empty, a reasonable default is used. Any + // string returned from a PublicKey.Type method may be used, or + // any of the CertAlgo and KeyAlgo constants. + HostKeyAlgorithms []string + + // Timeout is the maximum amount of time for the TCP connection to establish. + // + // A Timeout of zero means no timeout. + Timeout time.Duration +} + +// InsecureIgnoreHostKey returns a function that can be used for +// ClientConfig.HostKeyCallback to accept any host key. It should +// not be used for production code. +func InsecureIgnoreHostKey() HostKeyCallback { + return func(hostname string, remote net.Addr, key PublicKey) error { + return nil + } +} + +type fixedHostKey struct { + key PublicKey +} + +func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error { + if f.key == nil { + return fmt.Errorf("ssh: required host key was nil") + } + if !bytes.Equal(key.Marshal(), f.key.Marshal()) { + return fmt.Errorf("ssh: host key mismatch") + } + return nil +} + +// FixedHostKey returns a function for use in +// ClientConfig.HostKeyCallback to accept only a specific host key. +func FixedHostKey(key PublicKey) HostKeyCallback { + hk := &fixedHostKey{key} + return hk.check +} + +// BannerDisplayStderr returns a function that can be used for +// ClientConfig.BannerCallback to display banners on os.Stderr. +func BannerDisplayStderr() BannerCallback { + return func(banner string) error { + _, err := os.Stderr.WriteString(banner) + + return err + } +} diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go new file mode 100644 index 00000000..409b5ea1 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -0,0 +1,725 @@ +// 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 ssh + +import ( + "bytes" + "errors" + "fmt" + "io" + "strings" +) + +type authResult int + +const ( + authFailure authResult = iota + authPartialSuccess + authSuccess +) + +// clientAuthenticate authenticates with the remote server. See RFC 4252. +func (c *connection) clientAuthenticate(config *ClientConfig) error { + // initiate user auth session + if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { + return err + } + packet, err := c.transport.readPacket() + if err != nil { + return err + } + // The server may choose to send a SSH_MSG_EXT_INFO at this point (if we + // advertised willingness to receive one, which we always do) or not. See + // RFC 8308, Section 2.4. + extensions := make(map[string][]byte) + if len(packet) > 0 && packet[0] == msgExtInfo { + var extInfo extInfoMsg + if err := Unmarshal(packet, &extInfo); err != nil { + return err + } + payload := extInfo.Payload + for i := uint32(0); i < extInfo.NumExtensions; i++ { + name, rest, ok := parseString(payload) + if !ok { + return parseError(msgExtInfo) + } + value, rest, ok := parseString(rest) + if !ok { + return parseError(msgExtInfo) + } + extensions[string(name)] = value + payload = rest + } + packet, err = c.transport.readPacket() + if err != nil { + return err + } + } + var serviceAccept serviceAcceptMsg + if err := Unmarshal(packet, &serviceAccept); err != nil { + return err + } + + // during the authentication phase the client first attempts the "none" method + // then any untried methods suggested by the server. + var tried []string + var lastMethods []string + + sessionID := c.transport.getSessionID() + for auth := AuthMethod(new(noneAuth)); auth != nil; { + ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions) + if err != nil { + return err + } + if ok == authSuccess { + // success + return nil + } else if ok == authFailure { + if m := auth.method(); !contains(tried, m) { + tried = append(tried, m) + } + } + if methods == nil { + methods = lastMethods + } + lastMethods = methods + + auth = nil + + findNext: + for _, a := range config.Auth { + candidateMethod := a.method() + if contains(tried, candidateMethod) { + continue + } + for _, meth := range methods { + if meth == candidateMethod { + auth = a + break findNext + } + } + } + } + return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried) +} + +func contains(list []string, e string) bool { + for _, s := range list { + if s == e { + return true + } + } + return false +} + +// An AuthMethod represents an instance of an RFC 4252 authentication method. +type AuthMethod interface { + // auth authenticates user over transport t. + // Returns true if authentication is successful. + // If authentication is not successful, a []string of alternative + // method names is returned. If the slice is nil, it will be ignored + // and the previous set of possible methods will be reused. + auth(session []byte, user string, p packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) + + // method returns the RFC 4252 method name. + method() string +} + +// "none" authentication, RFC 4252 section 5.2. +type noneAuth int + +func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { + if err := c.writePacket(Marshal(&userAuthRequestMsg{ + User: user, + Service: serviceSSH, + Method: "none", + })); err != nil { + return authFailure, nil, err + } + + return handleAuthResponse(c) +} + +func (n *noneAuth) method() string { + return "none" +} + +// passwordCallback is an AuthMethod that fetches the password through +// a function call, e.g. by prompting the user. +type passwordCallback func() (password string, err error) + +func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { + type passwordAuthMsg struct { + User string `sshtype:"50"` + Service string + Method string + Reply bool + Password string + } + + pw, err := cb() + // REVIEW NOTE: is there a need to support skipping a password attempt? + // The program may only find out that the user doesn't have a password + // when prompting. + if err != nil { + return authFailure, nil, err + } + + if err := c.writePacket(Marshal(&passwordAuthMsg{ + User: user, + Service: serviceSSH, + Method: cb.method(), + Reply: false, + Password: pw, + })); err != nil { + return authFailure, nil, err + } + + return handleAuthResponse(c) +} + +func (cb passwordCallback) method() string { + return "password" +} + +// Password returns an AuthMethod using the given password. +func Password(secret string) AuthMethod { + return passwordCallback(func() (string, error) { return secret, nil }) +} + +// PasswordCallback returns an AuthMethod that uses a callback for +// fetching a password. +func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { + return passwordCallback(prompt) +} + +type publickeyAuthMsg struct { + User string `sshtype:"50"` + Service string + Method string + // HasSig indicates to the receiver packet that the auth request is signed and + // should be used for authentication of the request. + HasSig bool + Algoname string + PubKey []byte + // Sig is tagged with "rest" so Marshal will exclude it during + // validateKey + Sig []byte `ssh:"rest"` +} + +// publicKeyCallback is an AuthMethod that uses a set of key +// pairs for authentication. +type publicKeyCallback func() ([]Signer, error) + +func (cb publicKeyCallback) method() string { + return "publickey" +} + +func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) { + keyFormat := signer.PublicKey().Type() + + // Like in sendKexInit, if the public key implements AlgorithmSigner we + // assume it supports all algorithms, otherwise only the key format one. + as, ok := signer.(AlgorithmSigner) + if !ok { + return algorithmSignerWrapper{signer}, keyFormat + } + + extPayload, ok := extensions["server-sig-algs"] + if !ok { + // If there is no "server-sig-algs" extension, fall back to the key + // format algorithm. + return as, keyFormat + } + + // The server-sig-algs extension only carries underlying signature + // algorithm, but we are trying to select a protocol-level public key + // algorithm, which might be a certificate type. Extend the list of server + // supported algorithms to include the corresponding certificate algorithms. + serverAlgos := strings.Split(string(extPayload), ",") + for _, algo := range serverAlgos { + if certAlgo, ok := certificateAlgo(algo); ok { + serverAlgos = append(serverAlgos, certAlgo) + } + } + + keyAlgos := algorithmsForKeyFormat(keyFormat) + algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos) + if err != nil { + // If there is no overlap, try the key anyway with the key format + // algorithm, to support servers that fail to list all supported + // algorithms. + return as, keyFormat + } + return as, algo +} + +func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) { + // Authentication is performed by sending an enquiry to test if a key is + // acceptable to the remote. If the key is acceptable, the client will + // attempt to authenticate with the valid key. If not the client will repeat + // the process with the remaining keys. + + signers, err := cb() + if err != nil { + return authFailure, nil, err + } + var methods []string + for _, signer := range signers { + pub := signer.PublicKey() + as, algo := pickSignatureAlgorithm(signer, extensions) + + ok, err := validateKey(pub, algo, user, c) + if err != nil { + return authFailure, nil, err + } + if !ok { + continue + } + + pubKey := pub.Marshal() + data := buildDataSignedForAuth(session, userAuthRequestMsg{ + User: user, + Service: serviceSSH, + Method: cb.method(), + }, algo, pubKey) + sign, err := as.SignWithAlgorithm(rand, data, underlyingAlgo(algo)) + if err != nil { + return authFailure, nil, err + } + + // manually wrap the serialized signature in a string + s := Marshal(sign) + sig := make([]byte, stringLength(len(s))) + marshalString(sig, s) + msg := publickeyAuthMsg{ + User: user, + Service: serviceSSH, + Method: cb.method(), + HasSig: true, + Algoname: algo, + PubKey: pubKey, + Sig: sig, + } + p := Marshal(&msg) + if err := c.writePacket(p); err != nil { + return authFailure, nil, err + } + var success authResult + success, methods, err = handleAuthResponse(c) + if err != nil { + return authFailure, nil, err + } + + // If authentication succeeds or the list of available methods does not + // contain the "publickey" method, do not attempt to authenticate with any + // other keys. According to RFC 4252 Section 7, the latter can occur when + // additional authentication methods are required. + if success == authSuccess || !containsMethod(methods, cb.method()) { + return success, methods, err + } + } + + return authFailure, methods, nil +} + +func containsMethod(methods []string, method string) bool { + for _, m := range methods { + if m == method { + return true + } + } + + return false +} + +// validateKey validates the key provided is acceptable to the server. +func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, error) { + pubKey := key.Marshal() + msg := publickeyAuthMsg{ + User: user, + Service: serviceSSH, + Method: "publickey", + HasSig: false, + Algoname: algo, + PubKey: pubKey, + } + if err := c.writePacket(Marshal(&msg)); err != nil { + return false, err + } + + return confirmKeyAck(key, algo, c) +} + +func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) { + pubKey := key.Marshal() + + for { + packet, err := c.readPacket() + if err != nil { + return false, err + } + switch packet[0] { + case msgUserAuthBanner: + if err := handleBannerResponse(c, packet); err != nil { + return false, err + } + case msgUserAuthPubKeyOk: + var msg userAuthPubKeyOkMsg + if err := Unmarshal(packet, &msg); err != nil { + return false, err + } + if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) { + return false, nil + } + return true, nil + case msgUserAuthFailure: + return false, nil + default: + return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0]) + } + } +} + +// PublicKeys returns an AuthMethod that uses the given key +// pairs. +func PublicKeys(signers ...Signer) AuthMethod { + return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) +} + +// PublicKeysCallback returns an AuthMethod that runs the given +// function to obtain a list of key pairs. +func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { + return publicKeyCallback(getSigners) +} + +// handleAuthResponse returns whether the preceding authentication request succeeded +// along with a list of remaining authentication methods to try next and +// an error if an unexpected response was received. +func handleAuthResponse(c packetConn) (authResult, []string, error) { + gotMsgExtInfo := false + for { + packet, err := c.readPacket() + if err != nil { + return authFailure, nil, err + } + + switch packet[0] { + case msgUserAuthBanner: + if err := handleBannerResponse(c, packet); err != nil { + return authFailure, nil, err + } + case msgExtInfo: + // Ignore post-authentication RFC 8308 extensions, once. + if gotMsgExtInfo { + return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) + } + gotMsgExtInfo = true + case msgUserAuthFailure: + var msg userAuthFailureMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil + case msgUserAuthSuccess: + return authSuccess, nil, nil + default: + return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) + } + } +} + +func handleBannerResponse(c packetConn, packet []byte) error { + var msg userAuthBannerMsg + if err := Unmarshal(packet, &msg); err != nil { + return err + } + + transport, ok := c.(*handshakeTransport) + if !ok { + return nil + } + + if transport.bannerCallback != nil { + return transport.bannerCallback(msg.Message) + } + + return nil +} + +// KeyboardInteractiveChallenge should print questions, optionally +// disabling echoing (e.g. for passwords), and return all the answers. +// Challenge may be called multiple times in a single session. After +// successful authentication, the server may send a challenge with no +// questions, for which the name and instruction messages should be +// printed. RFC 4256 section 3.3 details how the UI should behave for +// both CLI and GUI environments. +type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error) + +// KeyboardInteractive returns an AuthMethod using a prompt/response +// sequence controlled by the server. +func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { + return challenge +} + +func (cb KeyboardInteractiveChallenge) method() string { + return "keyboard-interactive" +} + +func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { + type initiateMsg struct { + User string `sshtype:"50"` + Service string + Method string + Language string + Submethods string + } + + if err := c.writePacket(Marshal(&initiateMsg{ + User: user, + Service: serviceSSH, + Method: "keyboard-interactive", + })); err != nil { + return authFailure, nil, err + } + + gotMsgExtInfo := false + for { + packet, err := c.readPacket() + if err != nil { + return authFailure, nil, err + } + + // like handleAuthResponse, but with less options. + switch packet[0] { + case msgUserAuthBanner: + if err := handleBannerResponse(c, packet); err != nil { + return authFailure, nil, err + } + continue + case msgExtInfo: + // Ignore post-authentication RFC 8308 extensions, once. + if gotMsgExtInfo { + return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) + } + gotMsgExtInfo = true + continue + case msgUserAuthInfoRequest: + // OK + case msgUserAuthFailure: + var msg userAuthFailureMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil + case msgUserAuthSuccess: + return authSuccess, nil, nil + default: + return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) + } + + var msg userAuthInfoRequestMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + + // Manually unpack the prompt/echo pairs. + rest := msg.Prompts + var prompts []string + var echos []bool + for i := 0; i < int(msg.NumPrompts); i++ { + prompt, r, ok := parseString(rest) + if !ok || len(r) == 0 { + return authFailure, nil, errors.New("ssh: prompt format error") + } + prompts = append(prompts, string(prompt)) + echos = append(echos, r[0] != 0) + rest = r[1:] + } + + if len(rest) != 0 { + return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") + } + + answers, err := cb(msg.Name, msg.Instruction, prompts, echos) + if err != nil { + return authFailure, nil, err + } + + if len(answers) != len(prompts) { + return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(answers), len(prompts)) + } + responseLength := 1 + 4 + for _, a := range answers { + responseLength += stringLength(len(a)) + } + serialized := make([]byte, responseLength) + p := serialized + p[0] = msgUserAuthInfoResponse + p = p[1:] + p = marshalUint32(p, uint32(len(answers))) + for _, a := range answers { + p = marshalString(p, []byte(a)) + } + + if err := c.writePacket(serialized); err != nil { + return authFailure, nil, err + } + } +} + +type retryableAuthMethod struct { + authMethod AuthMethod + maxTries int +} + +func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (ok authResult, methods []string, err error) { + for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { + ok, methods, err = r.authMethod.auth(session, user, c, rand, extensions) + if ok != authFailure || err != nil { // either success, partial success or error terminate + return ok, methods, err + } + } + return ok, methods, err +} + +func (r *retryableAuthMethod) method() string { + return r.authMethod.method() +} + +// RetryableAuthMethod is a decorator for other auth methods enabling them to +// be retried up to maxTries before considering that AuthMethod itself failed. +// If maxTries is <= 0, will retry indefinitely +// +// This is useful for interactive clients using challenge/response type +// authentication (e.g. Keyboard-Interactive, Password, etc) where the user +// could mistype their response resulting in the server issuing a +// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 +// [keyboard-interactive]); Without this decorator, the non-retryable +// AuthMethod would be removed from future consideration, and never tried again +// (and so the user would never be able to retry their entry). +func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { + return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} +} + +// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication. +// See RFC 4462 section 3 +// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details. +// target is the server host you want to log in to. +func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod { + if gssAPIClient == nil { + panic("gss-api client must be not nil with enable gssapi-with-mic") + } + return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target} +} + +type gssAPIWithMICCallback struct { + gssAPIClient GSSAPIClient + target string +} + +func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) { + m := &userAuthRequestMsg{ + User: user, + Service: serviceSSH, + Method: g.method(), + } + // The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST. + // See RFC 4462 section 3.2. + m.Payload = appendU32(m.Payload, 1) + m.Payload = appendString(m.Payload, string(krb5OID)) + if err := c.writePacket(Marshal(m)); err != nil { + return authFailure, nil, err + } + // The server responds to the SSH_MSG_USERAUTH_REQUEST with either an + // SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or + // with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE. + // See RFC 4462 section 3.3. + // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check + // selected mech if it is valid. + packet, err := c.readPacket() + if err != nil { + return authFailure, nil, err + } + userAuthGSSAPIResp := &userAuthGSSAPIResponse{} + if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil { + return authFailure, nil, err + } + // Start the loop into the exchange token. + // See RFC 4462 section 3.4. + var token []byte + defer g.gssAPIClient.DeleteSecContext() + for { + // Initiates the establishment of a security context between the application and a remote peer. + nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false) + if err != nil { + return authFailure, nil, err + } + if len(nextToken) > 0 { + if err := c.writePacket(Marshal(&userAuthGSSAPIToken{ + Token: nextToken, + })); err != nil { + return authFailure, nil, err + } + } + if !needContinue { + break + } + packet, err = c.readPacket() + if err != nil { + return authFailure, nil, err + } + switch packet[0] { + case msgUserAuthFailure: + var msg userAuthFailureMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil + case msgUserAuthGSSAPIError: + userAuthGSSAPIErrorResp := &userAuthGSSAPIError{} + if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil { + return authFailure, nil, err + } + return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+ + "Major Status: %d\n"+ + "Minor Status: %d\n"+ + "Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus, + userAuthGSSAPIErrorResp.Message) + case msgUserAuthGSSAPIToken: + userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} + if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { + return authFailure, nil, err + } + token = userAuthGSSAPITokenReq.Token + } + } + // Binding Encryption Keys. + // See RFC 4462 section 3.5. + micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic") + micToken, err := g.gssAPIClient.GetMIC(micField) + if err != nil { + return authFailure, nil, err + } + if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{ + MIC: micToken, + })); err != nil { + return authFailure, nil, err + } + return handleAuthResponse(c) +} + +func (g *gssAPIWithMICCallback) method() string { + return "gssapi-with-mic" +} diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go new file mode 100644 index 00000000..2a47a61d --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -0,0 +1,430 @@ +// 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 ssh + +import ( + "crypto" + "crypto/rand" + "fmt" + "io" + "math" + "sync" + + _ "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" +) + +// These are string constants in the SSH protocol. +const ( + compressionNone = "none" + serviceUserAuth = "ssh-userauth" + serviceSSH = "ssh-connection" +) + +// supportedCiphers lists ciphers we support but might not recommend. +var supportedCiphers = []string{ + "aes128-ctr", "aes192-ctr", "aes256-ctr", + "aes128-gcm@openssh.com", + chacha20Poly1305ID, + "arcfour256", "arcfour128", "arcfour", + aes128cbcID, + tripledescbcID, +} + +// preferredCiphers specifies the default preference for ciphers. +var preferredCiphers = []string{ + "aes128-gcm@openssh.com", + chacha20Poly1305ID, + "aes128-ctr", "aes192-ctr", "aes256-ctr", +} + +// supportedKexAlgos specifies the supported key-exchange algorithms in +// preference order. +var supportedKexAlgos = []string{ + kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH, + // P384 and P521 are not constant-time yet, but since we don't + // reuse ephemeral keys, using them for ECDH should be OK. + kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, + kexAlgoDH14SHA256, kexAlgoDH14SHA1, kexAlgoDH1SHA1, +} + +// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden +// for the server half. +var serverForbiddenKexAlgos = map[string]struct{}{ + kexAlgoDHGEXSHA1: {}, // server half implementation is only minimal to satisfy the automated tests + kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests +} + +// preferredKexAlgos specifies the default preference for key-exchange algorithms +// in preference order. +var preferredKexAlgos = []string{ + kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH, + kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, + kexAlgoDH14SHA256, kexAlgoDH14SHA1, +} + +// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods +// of authenticating servers) in preference order. +var supportedHostKeyAlgos = []string{ + CertAlgoRSASHA512v01, CertAlgoRSASHA256v01, + CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, + CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, + + KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, + KeyAlgoRSASHA512, KeyAlgoRSASHA256, + KeyAlgoRSA, KeyAlgoDSA, + + KeyAlgoED25519, +} + +// supportedMACs specifies a default set of MAC algorithms in preference order. +// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed +// because they have reached the end of their useful life. +var supportedMACs = []string{ + "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", +} + +var supportedCompressions = []string{compressionNone} + +// hashFuncs keeps the mapping of supported signature algorithms to their +// respective hashes needed for signing and verification. +var hashFuncs = map[string]crypto.Hash{ + KeyAlgoRSA: crypto.SHA1, + KeyAlgoRSASHA256: crypto.SHA256, + KeyAlgoRSASHA512: crypto.SHA512, + KeyAlgoDSA: crypto.SHA1, + KeyAlgoECDSA256: crypto.SHA256, + KeyAlgoECDSA384: crypto.SHA384, + KeyAlgoECDSA521: crypto.SHA512, + // KeyAlgoED25519 doesn't pre-hash. + KeyAlgoSKECDSA256: crypto.SHA256, + KeyAlgoSKED25519: crypto.SHA256, +} + +// algorithmsForKeyFormat returns the supported signature algorithms for a given +// public key format (PublicKey.Type), in order of preference. See RFC 8332, +// Section 2. See also the note in sendKexInit on backwards compatibility. +func algorithmsForKeyFormat(keyFormat string) []string { + switch keyFormat { + case KeyAlgoRSA: + return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA} + case CertAlgoRSAv01: + return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01} + default: + return []string{keyFormat} + } +} + +// unexpectedMessageError results when the SSH message that we received didn't +// match what we wanted. +func unexpectedMessageError(expected, got uint8) error { + return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) +} + +// parseError results from a malformed SSH message. +func parseError(tag uint8) error { + return fmt.Errorf("ssh: parse error in message type %d", tag) +} + +func findCommon(what string, client []string, server []string) (common string, err error) { + for _, c := range client { + for _, s := range server { + if c == s { + return c, nil + } + } + } + return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) +} + +// directionAlgorithms records algorithm choices in one direction (either read or write) +type directionAlgorithms struct { + Cipher string + MAC string + Compression string +} + +// rekeyBytes returns a rekeying intervals in bytes. +func (a *directionAlgorithms) rekeyBytes() int64 { + // According to RFC4344 block ciphers should rekey after + // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is + // 128. + switch a.Cipher { + case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID: + return 16 * (1 << 32) + + } + + // For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. + return 1 << 30 +} + +var aeadCiphers = map[string]bool{ + gcmCipherID: true, + chacha20Poly1305ID: true, +} + +type algorithms struct { + kex string + hostKey string + w directionAlgorithms + r directionAlgorithms +} + +func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { + result := &algorithms{} + + result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) + if err != nil { + return + } + + result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) + if err != nil { + return + } + + stoc, ctos := &result.w, &result.r + if isClient { + ctos, stoc = stoc, ctos + } + + ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) + if err != nil { + return + } + + stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) + if err != nil { + return + } + + if !aeadCiphers[ctos.Cipher] { + ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) + if err != nil { + return + } + } + + if !aeadCiphers[stoc.Cipher] { + stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) + if err != nil { + return + } + } + + ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) + if err != nil { + return + } + + stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) + if err != nil { + return + } + + return result, nil +} + +// If rekeythreshold is too small, we can't make any progress sending +// stuff. +const minRekeyThreshold uint64 = 256 + +// Config contains configuration data common to both ServerConfig and +// ClientConfig. +type Config struct { + // Rand provides the source of entropy for cryptographic + // primitives. If Rand is nil, the cryptographic random reader + // in package crypto/rand will be used. + Rand io.Reader + + // The maximum number of bytes sent or received after which a + // new key is negotiated. It must be at least 256. If + // unspecified, a size suitable for the chosen cipher is used. + RekeyThreshold uint64 + + // The allowed key exchanges algorithms. If unspecified then a + // default set of algorithms is used. + KeyExchanges []string + + // The allowed cipher algorithms. If unspecified then a sensible + // default is used. + Ciphers []string + + // The allowed MAC algorithms. If unspecified then a sensible default + // is used. + MACs []string +} + +// SetDefaults sets sensible values for unset fields in config. This is +// exported for testing: Configs passed to SSH functions are copied and have +// default values set automatically. +func (c *Config) SetDefaults() { + if c.Rand == nil { + c.Rand = rand.Reader + } + if c.Ciphers == nil { + c.Ciphers = preferredCiphers + } + var ciphers []string + for _, c := range c.Ciphers { + if cipherModes[c] != nil { + // reject the cipher if we have no cipherModes definition + ciphers = append(ciphers, c) + } + } + c.Ciphers = ciphers + + if c.KeyExchanges == nil { + c.KeyExchanges = preferredKexAlgos + } + + if c.MACs == nil { + c.MACs = supportedMACs + } + + if c.RekeyThreshold == 0 { + // cipher specific default + } else if c.RekeyThreshold < minRekeyThreshold { + c.RekeyThreshold = minRekeyThreshold + } else if c.RekeyThreshold >= math.MaxInt64 { + // Avoid weirdness if somebody uses -1 as a threshold. + c.RekeyThreshold = math.MaxInt64 + } +} + +// buildDataSignedForAuth returns the data that is signed in order to prove +// possession of a private key. See RFC 4252, section 7. algo is the advertised +// algorithm, and may be a certificate type. +func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte { + data := struct { + Session []byte + Type byte + User string + Service string + Method string + Sign bool + Algo string + PubKey []byte + }{ + sessionID, + msgUserAuthRequest, + req.User, + req.Service, + req.Method, + true, + algo, + pubKey, + } + return Marshal(data) +} + +func appendU16(buf []byte, n uint16) []byte { + return append(buf, byte(n>>8), byte(n)) +} + +func appendU32(buf []byte, n uint32) []byte { + return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) +} + +func appendU64(buf []byte, n uint64) []byte { + return append(buf, + byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), + byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) +} + +func appendInt(buf []byte, n int) []byte { + return appendU32(buf, uint32(n)) +} + +func appendString(buf []byte, s string) []byte { + buf = appendU32(buf, uint32(len(s))) + buf = append(buf, s...) + return buf +} + +func appendBool(buf []byte, b bool) []byte { + if b { + return append(buf, 1) + } + return append(buf, 0) +} + +// newCond is a helper to hide the fact that there is no usable zero +// value for sync.Cond. +func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } + +// window represents the buffer available to clients +// wishing to write to a channel. +type window struct { + *sync.Cond + win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 + writeWaiters int + closed bool +} + +// add adds win to the amount of window available +// for consumers. +func (w *window) add(win uint32) bool { + // a zero sized window adjust is a noop. + if win == 0 { + return true + } + w.L.Lock() + if w.win+win < win { + w.L.Unlock() + return false + } + w.win += win + // It is unusual that multiple goroutines would be attempting to reserve + // window space, but not guaranteed. Use broadcast to notify all waiters + // that additional window is available. + w.Broadcast() + w.L.Unlock() + return true +} + +// close sets the window to closed, so all reservations fail +// immediately. +func (w *window) close() { + w.L.Lock() + w.closed = true + w.Broadcast() + w.L.Unlock() +} + +// reserve reserves win from the available window capacity. +// If no capacity remains, reserve will block. reserve may +// return less than requested. +func (w *window) reserve(win uint32) (uint32, error) { + var err error + w.L.Lock() + w.writeWaiters++ + w.Broadcast() + for w.win == 0 && !w.closed { + w.Wait() + } + w.writeWaiters-- + if w.win < win { + win = w.win + } + w.win -= win + if w.closed { + err = io.EOF + } + w.L.Unlock() + return win, err +} + +// waitWriterBlocked waits until some goroutine is blocked for further +// writes. It is used in tests only. +func (w *window) waitWriterBlocked() { + w.Cond.L.Lock() + for w.writeWaiters == 0 { + w.Cond.Wait() + } + w.Cond.L.Unlock() +} diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go new file mode 100644 index 00000000..fd6b0681 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/connection.go @@ -0,0 +1,143 @@ +// 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 ssh + +import ( + "fmt" + "net" +) + +// OpenChannelError is returned if the other side rejects an +// OpenChannel request. +type OpenChannelError struct { + Reason RejectionReason + Message string +} + +func (e *OpenChannelError) Error() string { + return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) +} + +// ConnMetadata holds metadata for the connection. +type ConnMetadata interface { + // User returns the user ID for this connection. + User() string + + // SessionID returns the session hash, also denoted by H. + SessionID() []byte + + // ClientVersion returns the client's version string as hashed + // into the session ID. + ClientVersion() []byte + + // ServerVersion returns the server's version string as hashed + // into the session ID. + ServerVersion() []byte + + // RemoteAddr returns the remote address for this connection. + RemoteAddr() net.Addr + + // LocalAddr returns the local address for this connection. + LocalAddr() net.Addr +} + +// Conn represents an SSH connection for both server and client roles. +// Conn is the basis for implementing an application layer, such +// as ClientConn, which implements the traditional shell access for +// clients. +type Conn interface { + ConnMetadata + + // SendRequest sends a global request, and returns the + // reply. If wantReply is true, it returns the response status + // and payload. See also RFC4254, section 4. + SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) + + // OpenChannel tries to open an channel. If the request is + // rejected, it returns *OpenChannelError. On success it returns + // the SSH Channel and a Go channel for incoming, out-of-band + // requests. The Go channel must be serviced, or the + // connection will hang. + OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) + + // Close closes the underlying network connection + Close() error + + // Wait blocks until the connection has shut down, and returns the + // error causing the shutdown. + Wait() error + + // TODO(hanwen): consider exposing: + // RequestKeyChange + // Disconnect +} + +// DiscardRequests consumes and rejects all requests from the +// passed-in channel. +func DiscardRequests(in <-chan *Request) { + for req := range in { + if req.WantReply { + req.Reply(false, nil) + } + } +} + +// A connection represents an incoming connection. +type connection struct { + transport *handshakeTransport + sshConn + + // The connection protocol. + *mux +} + +func (c *connection) Close() error { + return c.sshConn.conn.Close() +} + +// sshconn provides net.Conn metadata, but disallows direct reads and +// writes. +type sshConn struct { + conn net.Conn + + user string + sessionID []byte + clientVersion []byte + serverVersion []byte +} + +func dup(src []byte) []byte { + dst := make([]byte, len(src)) + copy(dst, src) + return dst +} + +func (c *sshConn) User() string { + return c.user +} + +func (c *sshConn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +func (c *sshConn) Close() error { + return c.conn.Close() +} + +func (c *sshConn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +func (c *sshConn) SessionID() []byte { + return dup(c.sessionID) +} + +func (c *sshConn) ClientVersion() []byte { + return dup(c.clientVersion) +} + +func (c *sshConn) ServerVersion() []byte { + return dup(c.serverVersion) +} diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go new file mode 100644 index 00000000..f6bff60d --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/doc.go @@ -0,0 +1,22 @@ +// 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 ssh implements an SSH client and server. + +SSH is a transport security protocol, an authentication protocol and a +family of application protocols. The most typical application level +protocol is a remote shell and this is specifically implemented. However, +the multiplexed nature of SSH is exposed to users that wish to support +others. + +References: + + [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD + [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 + +This package does not fall under the stability promise of the Go language itself, +so its API may be changed when pressing needs arise. +*/ +package ssh // import "golang.org/x/crypto/ssh" diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go new file mode 100644 index 00000000..653dc4d2 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/handshake.go @@ -0,0 +1,704 @@ +// 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 ssh + +import ( + "crypto/rand" + "errors" + "fmt" + "io" + "log" + "net" + "sync" +) + +// debugHandshake, if set, prints messages sent and received. Key +// exchange messages are printed as if DH were used, so the debug +// messages are wrong when using ECDH. +const debugHandshake = false + +// chanSize sets the amount of buffering SSH connections. This is +// primarily for testing: setting chanSize=0 uncovers deadlocks more +// quickly. +const chanSize = 16 + +// keyingTransport is a packet based transport that supports key +// changes. It need not be thread-safe. It should pass through +// msgNewKeys in both directions. +type keyingTransport interface { + packetConn + + // prepareKeyChange sets up a key change. The key change for a + // direction will be effected if a msgNewKeys message is sent + // or received. + prepareKeyChange(*algorithms, *kexResult) error +} + +// handshakeTransport implements rekeying on top of a keyingTransport +// and offers a thread-safe writePacket() interface. +type handshakeTransport struct { + conn keyingTransport + config *Config + + serverVersion []byte + clientVersion []byte + + // hostKeys is non-empty if we are the server. In that case, + // it contains all host keys that can be used to sign the + // connection. + hostKeys []Signer + + // hostKeyAlgorithms is non-empty if we are the client. In that case, + // we accept these key types from the server as host key. + hostKeyAlgorithms []string + + // On read error, incoming is closed, and readError is set. + incoming chan []byte + readError error + + mu sync.Mutex + writeError error + sentInitPacket []byte + sentInitMsg *kexInitMsg + pendingPackets [][]byte // Used when a key exchange is in progress. + + // If the read loop wants to schedule a kex, it pings this + // channel, and the write loop will send out a kex + // message. + requestKex chan struct{} + + // If the other side requests or confirms a kex, its kexInit + // packet is sent here for the write loop to find it. + startKex chan *pendingKex + + // data for host key checking + hostKeyCallback HostKeyCallback + dialAddress string + remoteAddr net.Addr + + // bannerCallback is non-empty if we are the client and it has been set in + // ClientConfig. In that case it is called during the user authentication + // dance to handle a custom server's message. + bannerCallback BannerCallback + + // Algorithms agreed in the last key exchange. + algorithms *algorithms + + readPacketsLeft uint32 + readBytesLeft int64 + + writePacketsLeft uint32 + writeBytesLeft int64 + + // The session ID or nil if first kex did not complete yet. + sessionID []byte +} + +type pendingKex struct { + otherInit []byte + done chan error +} + +func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { + t := &handshakeTransport{ + conn: conn, + serverVersion: serverVersion, + clientVersion: clientVersion, + incoming: make(chan []byte, chanSize), + requestKex: make(chan struct{}, 1), + startKex: make(chan *pendingKex, 1), + + config: config, + } + t.resetReadThresholds() + t.resetWriteThresholds() + + // We always start with a mandatory key exchange. + t.requestKex <- struct{}{} + return t +} + +func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { + t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) + t.dialAddress = dialAddr + t.remoteAddr = addr + t.hostKeyCallback = config.HostKeyCallback + t.bannerCallback = config.BannerCallback + if config.HostKeyAlgorithms != nil { + t.hostKeyAlgorithms = config.HostKeyAlgorithms + } else { + t.hostKeyAlgorithms = supportedHostKeyAlgos + } + go t.readLoop() + go t.kexLoop() + return t +} + +func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { + t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) + t.hostKeys = config.hostKeys + go t.readLoop() + go t.kexLoop() + return t +} + +func (t *handshakeTransport) getSessionID() []byte { + return t.sessionID +} + +// waitSession waits for the session to be established. This should be +// the first thing to call after instantiating handshakeTransport. +func (t *handshakeTransport) waitSession() error { + p, err := t.readPacket() + if err != nil { + return err + } + if p[0] != msgNewKeys { + return fmt.Errorf("ssh: first packet should be msgNewKeys") + } + + return nil +} + +func (t *handshakeTransport) id() string { + if len(t.hostKeys) > 0 { + return "server" + } + return "client" +} + +func (t *handshakeTransport) printPacket(p []byte, write bool) { + action := "got" + if write { + action = "sent" + } + + if p[0] == msgChannelData || p[0] == msgChannelExtendedData { + log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) + } else { + msg, err := decode(p) + log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) + } +} + +func (t *handshakeTransport) readPacket() ([]byte, error) { + p, ok := <-t.incoming + if !ok { + return nil, t.readError + } + return p, nil +} + +func (t *handshakeTransport) readLoop() { + first := true + for { + p, err := t.readOnePacket(first) + first = false + if err != nil { + t.readError = err + close(t.incoming) + break + } + if p[0] == msgIgnore || p[0] == msgDebug { + continue + } + t.incoming <- p + } + + // Stop writers too. + t.recordWriteError(t.readError) + + // Unblock the writer should it wait for this. + close(t.startKex) + + // Don't close t.requestKex; it's also written to from writePacket. +} + +func (t *handshakeTransport) pushPacket(p []byte) error { + if debugHandshake { + t.printPacket(p, true) + } + return t.conn.writePacket(p) +} + +func (t *handshakeTransport) getWriteError() error { + t.mu.Lock() + defer t.mu.Unlock() + return t.writeError +} + +func (t *handshakeTransport) recordWriteError(err error) { + t.mu.Lock() + defer t.mu.Unlock() + if t.writeError == nil && err != nil { + t.writeError = err + } +} + +func (t *handshakeTransport) requestKeyExchange() { + select { + case t.requestKex <- struct{}{}: + default: + // something already requested a kex, so do nothing. + } +} + +func (t *handshakeTransport) resetWriteThresholds() { + t.writePacketsLeft = packetRekeyThreshold + if t.config.RekeyThreshold > 0 { + t.writeBytesLeft = int64(t.config.RekeyThreshold) + } else if t.algorithms != nil { + t.writeBytesLeft = t.algorithms.w.rekeyBytes() + } else { + t.writeBytesLeft = 1 << 30 + } +} + +func (t *handshakeTransport) kexLoop() { + +write: + for t.getWriteError() == nil { + var request *pendingKex + var sent bool + + for request == nil || !sent { + var ok bool + select { + case request, ok = <-t.startKex: + if !ok { + break write + } + case <-t.requestKex: + break + } + + if !sent { + if err := t.sendKexInit(); err != nil { + t.recordWriteError(err) + break + } + sent = true + } + } + + if err := t.getWriteError(); err != nil { + if request != nil { + request.done <- err + } + break + } + + // We're not servicing t.requestKex, but that is OK: + // we never block on sending to t.requestKex. + + // We're not servicing t.startKex, but the remote end + // has just sent us a kexInitMsg, so it can't send + // another key change request, until we close the done + // channel on the pendingKex request. + + err := t.enterKeyExchange(request.otherInit) + + t.mu.Lock() + t.writeError = err + t.sentInitPacket = nil + t.sentInitMsg = nil + + t.resetWriteThresholds() + + // we have completed the key exchange. Since the + // reader is still blocked, it is safe to clear out + // the requestKex channel. This avoids the situation + // where: 1) we consumed our own request for the + // initial kex, and 2) the kex from the remote side + // caused another send on the requestKex channel, + clear: + for { + select { + case <-t.requestKex: + // + default: + break clear + } + } + + request.done <- t.writeError + + // kex finished. Push packets that we received while + // the kex was in progress. Don't look at t.startKex + // and don't increment writtenSinceKex: if we trigger + // another kex while we are still busy with the last + // one, things will become very confusing. + for _, p := range t.pendingPackets { + t.writeError = t.pushPacket(p) + if t.writeError != nil { + break + } + } + t.pendingPackets = t.pendingPackets[:0] + t.mu.Unlock() + } + + // drain startKex channel. We don't service t.requestKex + // because nobody does blocking sends there. + go func() { + for init := range t.startKex { + init.done <- t.writeError + } + }() + + // Unblock reader. + t.conn.Close() +} + +// The protocol uses uint32 for packet counters, so we can't let them +// reach 1<<32. We will actually read and write more packets than +// this, though: the other side may send more packets, and after we +// hit this limit on writing we will send a few more packets for the +// key exchange itself. +const packetRekeyThreshold = (1 << 31) + +func (t *handshakeTransport) resetReadThresholds() { + t.readPacketsLeft = packetRekeyThreshold + if t.config.RekeyThreshold > 0 { + t.readBytesLeft = int64(t.config.RekeyThreshold) + } else if t.algorithms != nil { + t.readBytesLeft = t.algorithms.r.rekeyBytes() + } else { + t.readBytesLeft = 1 << 30 + } +} + +func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { + p, err := t.conn.readPacket() + if err != nil { + return nil, err + } + + if t.readPacketsLeft > 0 { + t.readPacketsLeft-- + } else { + t.requestKeyExchange() + } + + if t.readBytesLeft > 0 { + t.readBytesLeft -= int64(len(p)) + } else { + t.requestKeyExchange() + } + + if debugHandshake { + t.printPacket(p, false) + } + + if first && p[0] != msgKexInit { + return nil, fmt.Errorf("ssh: first packet should be msgKexInit") + } + + if p[0] != msgKexInit { + return p, nil + } + + firstKex := t.sessionID == nil + + kex := pendingKex{ + done: make(chan error, 1), + otherInit: p, + } + t.startKex <- &kex + err = <-kex.done + + if debugHandshake { + log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) + } + + if err != nil { + return nil, err + } + + t.resetReadThresholds() + + // By default, a key exchange is hidden from higher layers by + // translating it into msgIgnore. + successPacket := []byte{msgIgnore} + if firstKex { + // sendKexInit() for the first kex waits for + // msgNewKeys so the authentication process is + // guaranteed to happen over an encrypted transport. + successPacket = []byte{msgNewKeys} + } + + return successPacket, nil +} + +// sendKexInit sends a key change message. +func (t *handshakeTransport) sendKexInit() error { + t.mu.Lock() + defer t.mu.Unlock() + if t.sentInitMsg != nil { + // kexInits may be sent either in response to the other side, + // or because our side wants to initiate a key change, so we + // may have already sent a kexInit. In that case, don't send a + // second kexInit. + return nil + } + + msg := &kexInitMsg{ + KexAlgos: t.config.KeyExchanges, + CiphersClientServer: t.config.Ciphers, + CiphersServerClient: t.config.Ciphers, + MACsClientServer: t.config.MACs, + MACsServerClient: t.config.MACs, + CompressionClientServer: supportedCompressions, + CompressionServerClient: supportedCompressions, + } + io.ReadFull(rand.Reader, msg.Cookie[:]) + + isServer := len(t.hostKeys) > 0 + if isServer { + for _, k := range t.hostKeys { + // If k is an AlgorithmSigner, presume it supports all signature algorithms + // associated with the key format. (Ideally AlgorithmSigner would have a + // method to advertise supported algorithms, but it doesn't. This means that + // adding support for a new algorithm is a breaking change, as we will + // immediately negotiate it even if existing implementations don't support + // it. If that ever happens, we'll have to figure something out.) + // If k is not an AlgorithmSigner, we can only assume it only supports the + // algorithms that matches the key format. (This means that Sign can't pick + // a different default.) + keyFormat := k.PublicKey().Type() + if _, ok := k.(AlgorithmSigner); ok { + msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...) + } else { + msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat) + } + } + } else { + msg.ServerHostKeyAlgos = t.hostKeyAlgorithms + + // As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what + // algorithms the server supports for public key authentication. See RFC + // 8308, Section 2.1. + if firstKeyExchange := t.sessionID == nil; firstKeyExchange { + msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1) + msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...) + msg.KexAlgos = append(msg.KexAlgos, "ext-info-c") + } + } + + packet := Marshal(msg) + + // writePacket destroys the contents, so save a copy. + packetCopy := make([]byte, len(packet)) + copy(packetCopy, packet) + + if err := t.pushPacket(packetCopy); err != nil { + return err + } + + t.sentInitMsg = msg + t.sentInitPacket = packet + + return nil +} + +func (t *handshakeTransport) writePacket(p []byte) error { + switch p[0] { + case msgKexInit: + return errors.New("ssh: only handshakeTransport can send kexInit") + case msgNewKeys: + return errors.New("ssh: only handshakeTransport can send newKeys") + } + + t.mu.Lock() + defer t.mu.Unlock() + if t.writeError != nil { + return t.writeError + } + + if t.sentInitMsg != nil { + // Copy the packet so the writer can reuse the buffer. + cp := make([]byte, len(p)) + copy(cp, p) + t.pendingPackets = append(t.pendingPackets, cp) + return nil + } + + if t.writeBytesLeft > 0 { + t.writeBytesLeft -= int64(len(p)) + } else { + t.requestKeyExchange() + } + + if t.writePacketsLeft > 0 { + t.writePacketsLeft-- + } else { + t.requestKeyExchange() + } + + if err := t.pushPacket(p); err != nil { + t.writeError = err + } + + return nil +} + +func (t *handshakeTransport) Close() error { + return t.conn.Close() +} + +func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { + if debugHandshake { + log.Printf("%s entered key exchange", t.id()) + } + + otherInit := &kexInitMsg{} + if err := Unmarshal(otherInitPacket, otherInit); err != nil { + return err + } + + magics := handshakeMagics{ + clientVersion: t.clientVersion, + serverVersion: t.serverVersion, + clientKexInit: otherInitPacket, + serverKexInit: t.sentInitPacket, + } + + clientInit := otherInit + serverInit := t.sentInitMsg + isClient := len(t.hostKeys) == 0 + if isClient { + clientInit, serverInit = serverInit, clientInit + + magics.clientKexInit = t.sentInitPacket + magics.serverKexInit = otherInitPacket + } + + var err error + t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit) + if err != nil { + return err + } + + // We don't send FirstKexFollows, but we handle receiving it. + // + // RFC 4253 section 7 defines the kex and the agreement method for + // first_kex_packet_follows. It states that the guessed packet + // should be ignored if the "kex algorithm and/or the host + // key algorithm is guessed wrong (server and client have + // different preferred algorithm), or if any of the other + // algorithms cannot be agreed upon". The other algorithms have + // already been checked above so the kex algorithm and host key + // algorithm are checked here. + if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) { + // other side sent a kex message for the wrong algorithm, + // which we have to ignore. + if _, err := t.conn.readPacket(); err != nil { + return err + } + } + + kex, ok := kexAlgoMap[t.algorithms.kex] + if !ok { + return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) + } + + var result *kexResult + if len(t.hostKeys) > 0 { + result, err = t.server(kex, &magics) + } else { + result, err = t.client(kex, &magics) + } + + if err != nil { + return err + } + + if t.sessionID == nil { + t.sessionID = result.H + } + result.SessionID = t.sessionID + + if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil { + return err + } + if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { + return err + } + if packet, err := t.conn.readPacket(); err != nil { + return err + } else if packet[0] != msgNewKeys { + return unexpectedMessageError(msgNewKeys, packet[0]) + } + + return nil +} + +// algorithmSignerWrapper is an AlgorithmSigner that only supports the default +// key format algorithm. +// +// This is technically a violation of the AlgorithmSigner interface, but it +// should be unreachable given where we use this. Anyway, at least it returns an +// error instead of panicing or producing an incorrect signature. +type algorithmSignerWrapper struct { + Signer +} + +func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm != underlyingAlgo(a.PublicKey().Type()) { + return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm") + } + return a.Sign(rand, data) +} + +func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner { + for _, k := range hostKeys { + if algo == k.PublicKey().Type() { + return algorithmSignerWrapper{k} + } + k, ok := k.(AlgorithmSigner) + if !ok { + continue + } + for _, a := range algorithmsForKeyFormat(k.PublicKey().Type()) { + if algo == a { + return k + } + } + } + return nil +} + +func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) { + hostKey := pickHostKey(t.hostKeys, t.algorithms.hostKey) + if hostKey == nil { + return nil, errors.New("ssh: internal error: negotiated unsupported signature type") + } + + r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.hostKey) + return r, err +} + +func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) { + result, err := kex.Client(t.conn, t.config.Rand, magics) + if err != nil { + return nil, err + } + + hostKey, err := ParsePublicKey(result.HostKey) + if err != nil { + return nil, err + } + + if err := verifyHostKeySignature(hostKey, t.algorithms.hostKey, result); err != nil { + return nil, err + } + + err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go b/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go new file mode 100644 index 00000000..af81d266 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go @@ -0,0 +1,93 @@ +// Copyright 2014 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 bcrypt_pbkdf implements bcrypt_pbkdf(3) from OpenBSD. +// +// See https://flak.tedunangst.com/post/bcrypt-pbkdf and +// https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libutil/bcrypt_pbkdf.c. +package bcrypt_pbkdf + +import ( + "crypto/sha512" + "errors" + "golang.org/x/crypto/blowfish" +) + +const blockSize = 32 + +// Key derives a key from the password, salt and rounds count, returning a +// []byte of length keyLen that can be used as cryptographic key. +func Key(password, salt []byte, rounds, keyLen int) ([]byte, error) { + if rounds < 1 { + return nil, errors.New("bcrypt_pbkdf: number of rounds is too small") + } + if len(password) == 0 { + return nil, errors.New("bcrypt_pbkdf: empty password") + } + if len(salt) == 0 || len(salt) > 1<<20 { + return nil, errors.New("bcrypt_pbkdf: bad salt length") + } + if keyLen > 1024 { + return nil, errors.New("bcrypt_pbkdf: keyLen is too large") + } + + numBlocks := (keyLen + blockSize - 1) / blockSize + key := make([]byte, numBlocks*blockSize) + + h := sha512.New() + h.Write(password) + shapass := h.Sum(nil) + + shasalt := make([]byte, 0, sha512.Size) + cnt, tmp := make([]byte, 4), make([]byte, blockSize) + for block := 1; block <= numBlocks; block++ { + h.Reset() + h.Write(salt) + cnt[0] = byte(block >> 24) + cnt[1] = byte(block >> 16) + cnt[2] = byte(block >> 8) + cnt[3] = byte(block) + h.Write(cnt) + bcryptHash(tmp, shapass, h.Sum(shasalt)) + + out := make([]byte, blockSize) + copy(out, tmp) + for i := 2; i <= rounds; i++ { + h.Reset() + h.Write(tmp) + bcryptHash(tmp, shapass, h.Sum(shasalt)) + for j := 0; j < len(out); j++ { + out[j] ^= tmp[j] + } + } + + for i, v := range out { + key[i*numBlocks+(block-1)] = v + } + } + return key[:keyLen], nil +} + +var magic = []byte("OxychromaticBlowfishSwatDynamite") + +func bcryptHash(out, shapass, shasalt []byte) { + c, err := blowfish.NewSaltedCipher(shapass, shasalt) + if err != nil { + panic(err) + } + for i := 0; i < 64; i++ { + blowfish.ExpandKey(shasalt, c) + blowfish.ExpandKey(shapass, c) + } + copy(out, magic) + for i := 0; i < 32; i += 8 { + for j := 0; j < 64; j++ { + c.Encrypt(out[i:i+8], out[i:i+8]) + } + } + // Swap bytes due to different endianness. + for i := 0; i < 32; i += 4 { + out[i+3], out[i+2], out[i+1], out[i] = out[i], out[i+1], out[i+2], out[i+3] + } +} diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go new file mode 100644 index 00000000..927a90cd --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/kex.go @@ -0,0 +1,774 @@ +// 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 ssh + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/subtle" + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + + "golang.org/x/crypto/curve25519" +) + +const ( + kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" + kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" + kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256" + kexAlgoECDH256 = "ecdh-sha2-nistp256" + kexAlgoECDH384 = "ecdh-sha2-nistp384" + kexAlgoECDH521 = "ecdh-sha2-nistp521" + kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org" + kexAlgoCurve25519SHA256 = "curve25519-sha256" + + // For the following kex only the client half contains a production + // ready implementation. The server half only consists of a minimal + // implementation to satisfy the automated tests. + kexAlgoDHGEXSHA1 = "diffie-hellman-group-exchange-sha1" + kexAlgoDHGEXSHA256 = "diffie-hellman-group-exchange-sha256" +) + +// kexResult captures the outcome of a key exchange. +type kexResult struct { + // Session hash. See also RFC 4253, section 8. + H []byte + + // Shared secret. See also RFC 4253, section 8. + K []byte + + // Host key as hashed into H. + HostKey []byte + + // Signature of H. + Signature []byte + + // A cryptographic hash function that matches the security + // level of the key exchange algorithm. It is used for + // calculating H, and for deriving keys from H and K. + Hash crypto.Hash + + // The session ID, which is the first H computed. This is used + // to derive key material inside the transport. + SessionID []byte +} + +// handshakeMagics contains data that is always included in the +// session hash. +type handshakeMagics struct { + clientVersion, serverVersion []byte + clientKexInit, serverKexInit []byte +} + +func (m *handshakeMagics) write(w io.Writer) { + writeString(w, m.clientVersion) + writeString(w, m.serverVersion) + writeString(w, m.clientKexInit) + writeString(w, m.serverKexInit) +} + +// kexAlgorithm abstracts different key exchange algorithms. +type kexAlgorithm interface { + // Server runs server-side key agreement, signing the result + // with a hostkey. algo is the negotiated algorithm, and may + // be a certificate type. + Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error) + + // Client runs the client-side key agreement. Caller is + // responsible for verifying the host key signature. + Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) +} + +// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. +type dhGroup struct { + g, p, pMinus1 *big.Int + hashFunc crypto.Hash +} + +func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { + if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { + return nil, errors.New("ssh: DH parameter out of bounds") + } + return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil +} + +func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { + var x *big.Int + for { + var err error + if x, err = rand.Int(randSource, group.pMinus1); err != nil { + return nil, err + } + if x.Sign() > 0 { + break + } + } + + X := new(big.Int).Exp(group.g, x, group.p) + kexDHInit := kexDHInitMsg{ + X: X, + } + if err := c.writePacket(Marshal(&kexDHInit)); err != nil { + return nil, err + } + + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var kexDHReply kexDHReplyMsg + if err = Unmarshal(packet, &kexDHReply); err != nil { + return nil, err + } + + ki, err := group.diffieHellman(kexDHReply.Y, x) + if err != nil { + return nil, err + } + + h := group.hashFunc.New() + magics.write(h) + writeString(h, kexDHReply.HostKey) + writeInt(h, X) + writeInt(h, kexDHReply.Y) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: kexDHReply.HostKey, + Signature: kexDHReply.Signature, + Hash: group.hashFunc, + }, nil +} + +func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { + packet, err := c.readPacket() + if err != nil { + return + } + var kexDHInit kexDHInitMsg + if err = Unmarshal(packet, &kexDHInit); err != nil { + return + } + + var y *big.Int + for { + if y, err = rand.Int(randSource, group.pMinus1); err != nil { + return + } + if y.Sign() > 0 { + break + } + } + + Y := new(big.Int).Exp(group.g, y, group.p) + ki, err := group.diffieHellman(kexDHInit.X, y) + if err != nil { + return nil, err + } + + hostKeyBytes := priv.PublicKey().Marshal() + + h := group.hashFunc.New() + magics.write(h) + writeString(h, hostKeyBytes) + writeInt(h, kexDHInit.X) + writeInt(h, Y) + + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + H := h.Sum(nil) + + // H is already a hash, but the hostkey signing will apply its + // own key-specific hash algorithm. + sig, err := signAndMarshal(priv, randSource, H, algo) + if err != nil { + return nil, err + } + + kexDHReply := kexDHReplyMsg{ + HostKey: hostKeyBytes, + Y: Y, + Signature: sig, + } + packet = Marshal(&kexDHReply) + + err = c.writePacket(packet) + return &kexResult{ + H: H, + K: K, + HostKey: hostKeyBytes, + Signature: sig, + Hash: group.hashFunc, + }, err +} + +// ecdh performs Elliptic Curve Diffie-Hellman key exchange as +// described in RFC 5656, section 4. +type ecdh struct { + curve elliptic.Curve +} + +func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { + ephKey, err := ecdsa.GenerateKey(kex.curve, rand) + if err != nil { + return nil, err + } + + kexInit := kexECDHInitMsg{ + ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), + } + + serialized := Marshal(&kexInit) + if err := c.writePacket(serialized); err != nil { + return nil, err + } + + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var reply kexECDHReplyMsg + if err = Unmarshal(packet, &reply); err != nil { + return nil, err + } + + x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) + if err != nil { + return nil, err + } + + // generate shared secret + secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) + + h := ecHash(kex.curve).New() + magics.write(h) + writeString(h, reply.HostKey) + writeString(h, kexInit.ClientPubKey) + writeString(h, reply.EphemeralPubKey) + K := make([]byte, intLength(secret)) + marshalInt(K, secret) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: reply.HostKey, + Signature: reply.Signature, + Hash: ecHash(kex.curve), + }, nil +} + +// unmarshalECKey parses and checks an EC key. +func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { + x, y = elliptic.Unmarshal(curve, pubkey) + if x == nil { + return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") + } + if !validateECPublicKey(curve, x, y) { + return nil, nil, errors.New("ssh: public key not on curve") + } + return x, y, nil +} + +// validateECPublicKey checks that the point is a valid public key for +// the given curve. See [SEC1], 3.2.2 +func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { + if x.Sign() == 0 && y.Sign() == 0 { + return false + } + + if x.Cmp(curve.Params().P) >= 0 { + return false + } + + if y.Cmp(curve.Params().P) >= 0 { + return false + } + + if !curve.IsOnCurve(x, y) { + return false + } + + // We don't check if N * PubKey == 0, since + // + // - the NIST curves have cofactor = 1, so this is implicit. + // (We don't foresee an implementation that supports non NIST + // curves) + // + // - for ephemeral keys, we don't need to worry about small + // subgroup attacks. + return true +} + +func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var kexECDHInit kexECDHInitMsg + if err = Unmarshal(packet, &kexECDHInit); err != nil { + return nil, err + } + + clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) + if err != nil { + return nil, err + } + + // We could cache this key across multiple users/multiple + // connection attempts, but the benefit is small. OpenSSH + // generates a new key for each incoming connection. + ephKey, err := ecdsa.GenerateKey(kex.curve, rand) + if err != nil { + return nil, err + } + + hostKeyBytes := priv.PublicKey().Marshal() + + serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) + + // generate shared secret + secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) + + h := ecHash(kex.curve).New() + magics.write(h) + writeString(h, hostKeyBytes) + writeString(h, kexECDHInit.ClientPubKey) + writeString(h, serializedEphKey) + + K := make([]byte, intLength(secret)) + marshalInt(K, secret) + h.Write(K) + + H := h.Sum(nil) + + // H is already a hash, but the hostkey signing will apply its + // own key-specific hash algorithm. + sig, err := signAndMarshal(priv, rand, H, algo) + if err != nil { + return nil, err + } + + reply := kexECDHReplyMsg{ + EphemeralPubKey: serializedEphKey, + HostKey: hostKeyBytes, + Signature: sig, + } + + serialized := Marshal(&reply) + if err := c.writePacket(serialized); err != nil { + return nil, err + } + + return &kexResult{ + H: H, + K: K, + HostKey: reply.HostKey, + Signature: sig, + Hash: ecHash(kex.curve), + }, nil +} + +// ecHash returns the hash to match the given elliptic curve, see RFC +// 5656, section 6.2.1 +func ecHash(curve elliptic.Curve) crypto.Hash { + bitSize := curve.Params().BitSize + switch { + case bitSize <= 256: + return crypto.SHA256 + case bitSize <= 384: + return crypto.SHA384 + } + return crypto.SHA512 +} + +var kexAlgoMap = map[string]kexAlgorithm{} + +func init() { + // This is the group called diffie-hellman-group1-sha1 in + // RFC 4253 and Oakley Group 2 in RFC 2409. + p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) + kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ + g: new(big.Int).SetInt64(2), + p: p, + pMinus1: new(big.Int).Sub(p, bigOne), + hashFunc: crypto.SHA1, + } + + // This are the groups called diffie-hellman-group14-sha1 and + // diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268, + // and Oakley Group 14 in RFC 3526. + p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) + group14 := &dhGroup{ + g: new(big.Int).SetInt64(2), + p: p, + pMinus1: new(big.Int).Sub(p, bigOne), + } + + kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ + g: group14.g, p: group14.p, pMinus1: group14.pMinus1, + hashFunc: crypto.SHA1, + } + kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{ + g: group14.g, p: group14.p, pMinus1: group14.pMinus1, + hashFunc: crypto.SHA256, + } + + kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} + kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} + kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} + kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} + kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{} + kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} + kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} +} + +// curve25519sha256 implements the curve25519-sha256 (formerly known as +// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731. +type curve25519sha256 struct{} + +type curve25519KeyPair struct { + priv [32]byte + pub [32]byte +} + +func (kp *curve25519KeyPair) generate(rand io.Reader) error { + if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { + return err + } + curve25519.ScalarBaseMult(&kp.pub, &kp.priv) + return nil +} + +// curve25519Zeros is just an array of 32 zero bytes so that we have something +// convenient to compare against in order to reject curve25519 points with the +// wrong order. +var curve25519Zeros [32]byte + +func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { + var kp curve25519KeyPair + if err := kp.generate(rand); err != nil { + return nil, err + } + if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { + return nil, err + } + + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var reply kexECDHReplyMsg + if err = Unmarshal(packet, &reply); err != nil { + return nil, err + } + if len(reply.EphemeralPubKey) != 32 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong length") + } + + var servPub, secret [32]byte + copy(servPub[:], reply.EphemeralPubKey) + curve25519.ScalarMult(&secret, &kp.priv, &servPub) + if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + } + + h := crypto.SHA256.New() + magics.write(h) + writeString(h, reply.HostKey) + writeString(h, kp.pub[:]) + writeString(h, reply.EphemeralPubKey) + + ki := new(big.Int).SetBytes(secret[:]) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: reply.HostKey, + Signature: reply.Signature, + Hash: crypto.SHA256, + }, nil +} + +func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { + packet, err := c.readPacket() + if err != nil { + return + } + var kexInit kexECDHInitMsg + if err = Unmarshal(packet, &kexInit); err != nil { + return + } + + if len(kexInit.ClientPubKey) != 32 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong length") + } + + var kp curve25519KeyPair + if err := kp.generate(rand); err != nil { + return nil, err + } + + var clientPub, secret [32]byte + copy(clientPub[:], kexInit.ClientPubKey) + curve25519.ScalarMult(&secret, &kp.priv, &clientPub) + if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + } + + hostKeyBytes := priv.PublicKey().Marshal() + + h := crypto.SHA256.New() + magics.write(h) + writeString(h, hostKeyBytes) + writeString(h, kexInit.ClientPubKey) + writeString(h, kp.pub[:]) + + ki := new(big.Int).SetBytes(secret[:]) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + H := h.Sum(nil) + + sig, err := signAndMarshal(priv, rand, H, algo) + if err != nil { + return nil, err + } + + reply := kexECDHReplyMsg{ + EphemeralPubKey: kp.pub[:], + HostKey: hostKeyBytes, + Signature: sig, + } + if err := c.writePacket(Marshal(&reply)); err != nil { + return nil, err + } + return &kexResult{ + H: H, + K: K, + HostKey: hostKeyBytes, + Signature: sig, + Hash: crypto.SHA256, + }, nil +} + +// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and +// diffie-hellman-group-exchange-sha256 key agreement protocols, +// as described in RFC 4419 +type dhGEXSHA struct { + hashFunc crypto.Hash +} + +const ( + dhGroupExchangeMinimumBits = 2048 + dhGroupExchangePreferredBits = 2048 + dhGroupExchangeMaximumBits = 8192 +) + +func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { + // Send GexRequest + kexDHGexRequest := kexDHGexRequestMsg{ + MinBits: dhGroupExchangeMinimumBits, + PreferedBits: dhGroupExchangePreferredBits, + MaxBits: dhGroupExchangeMaximumBits, + } + if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil { + return nil, err + } + + // Receive GexGroup + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var msg kexDHGexGroupMsg + if err = Unmarshal(packet, &msg); err != nil { + return nil, err + } + + // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits + if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits { + return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen()) + } + + // Check if g is safe by verifying that 1 < g < p-1 + pMinusOne := new(big.Int).Sub(msg.P, bigOne) + if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 { + return nil, fmt.Errorf("ssh: server provided gex g is not safe") + } + + // Send GexInit + pHalf := new(big.Int).Rsh(msg.P, 1) + x, err := rand.Int(randSource, pHalf) + if err != nil { + return nil, err + } + X := new(big.Int).Exp(msg.G, x, msg.P) + kexDHGexInit := kexDHGexInitMsg{ + X: X, + } + if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil { + return nil, err + } + + // Receive GexReply + packet, err = c.readPacket() + if err != nil { + return nil, err + } + + var kexDHGexReply kexDHGexReplyMsg + if err = Unmarshal(packet, &kexDHGexReply); err != nil { + return nil, err + } + + if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 { + return nil, errors.New("ssh: DH parameter out of bounds") + } + kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P) + + // Check if k is safe by verifying that k > 1 and k < p - 1 + if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 { + return nil, fmt.Errorf("ssh: derived k is not safe") + } + + h := gex.hashFunc.New() + magics.write(h) + writeString(h, kexDHGexReply.HostKey) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) + writeInt(h, msg.P) + writeInt(h, msg.G) + writeInt(h, X) + writeInt(h, kexDHGexReply.Y) + K := make([]byte, intLength(kInt)) + marshalInt(K, kInt) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: kexDHGexReply.HostKey, + Signature: kexDHGexReply.Signature, + Hash: gex.hashFunc, + }, nil +} + +// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. +// +// This is a minimal implementation to satisfy the automated tests. +func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) { + // Receive GexRequest + packet, err := c.readPacket() + if err != nil { + return + } + var kexDHGexRequest kexDHGexRequestMsg + if err = Unmarshal(packet, &kexDHGexRequest); err != nil { + return + } + + // Send GexGroup + // This is the group called diffie-hellman-group14-sha1 in RFC + // 4253 and Oakley Group 14 in RFC 3526. + p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) + g := big.NewInt(2) + + msg := &kexDHGexGroupMsg{ + P: p, + G: g, + } + if err := c.writePacket(Marshal(msg)); err != nil { + return nil, err + } + + // Receive GexInit + packet, err = c.readPacket() + if err != nil { + return + } + var kexDHGexInit kexDHGexInitMsg + if err = Unmarshal(packet, &kexDHGexInit); err != nil { + return + } + + pHalf := new(big.Int).Rsh(p, 1) + + y, err := rand.Int(randSource, pHalf) + if err != nil { + return + } + Y := new(big.Int).Exp(g, y, p) + + pMinusOne := new(big.Int).Sub(p, bigOne) + if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 { + return nil, errors.New("ssh: DH parameter out of bounds") + } + kInt := new(big.Int).Exp(kexDHGexInit.X, y, p) + + hostKeyBytes := priv.PublicKey().Marshal() + + h := gex.hashFunc.New() + magics.write(h) + writeString(h, hostKeyBytes) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) + binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) + writeInt(h, p) + writeInt(h, g) + writeInt(h, kexDHGexInit.X) + writeInt(h, Y) + + K := make([]byte, intLength(kInt)) + marshalInt(K, kInt) + h.Write(K) + + H := h.Sum(nil) + + // H is already a hash, but the hostkey signing will apply its + // own key-specific hash algorithm. + sig, err := signAndMarshal(priv, randSource, H, algo) + if err != nil { + return nil, err + } + + kexDHGexReply := kexDHGexReplyMsg{ + HostKey: hostKeyBytes, + Y: Y, + Signature: sig, + } + packet = Marshal(&kexDHGexReply) + + err = c.writePacket(packet) + + return &kexResult{ + H: H, + K: K, + HostKey: hostKeyBytes, + Signature: sig, + Hash: gex.hashFunc, + }, err +} diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go new file mode 100644 index 00000000..1c7de1a6 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -0,0 +1,1447 @@ +// 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 ssh + +import ( + "bytes" + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/md5" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/asn1" + "encoding/base64" + "encoding/hex" + "encoding/pem" + "errors" + "fmt" + "io" + "math/big" + "strings" + + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ssh/internal/bcrypt_pbkdf" +) + +// Public key algorithms names. These values can appear in PublicKey.Type, +// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner +// arguments. +const ( + KeyAlgoRSA = "ssh-rsa" + KeyAlgoDSA = "ssh-dss" + KeyAlgoECDSA256 = "ecdsa-sha2-nistp256" + KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com" + KeyAlgoECDSA384 = "ecdsa-sha2-nistp384" + KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" + KeyAlgoED25519 = "ssh-ed25519" + KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com" + + // KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not + // public key formats, so they can't appear as a PublicKey.Type. The + // corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2. + KeyAlgoRSASHA256 = "rsa-sha2-256" + KeyAlgoRSASHA512 = "rsa-sha2-512" +) + +const ( + // Deprecated: use KeyAlgoRSA. + SigAlgoRSA = KeyAlgoRSA + // Deprecated: use KeyAlgoRSASHA256. + SigAlgoRSASHA2256 = KeyAlgoRSASHA256 + // Deprecated: use KeyAlgoRSASHA512. + SigAlgoRSASHA2512 = KeyAlgoRSASHA512 +) + +// parsePubKey parses a public key of the given algorithm. +// Use ParsePublicKey for keys with prepended algorithm. +func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { + switch algo { + case KeyAlgoRSA: + return parseRSA(in) + case KeyAlgoDSA: + return parseDSA(in) + case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: + return parseECDSA(in) + case KeyAlgoSKECDSA256: + return parseSKECDSA(in) + case KeyAlgoED25519: + return parseED25519(in) + case KeyAlgoSKED25519: + return parseSKEd25519(in) + case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: + cert, err := parseCert(in, certKeyAlgoNames[algo]) + if err != nil { + return nil, nil, err + } + return cert, nil, nil + } + return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) +} + +// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format +// (see sshd(8) manual page) once the options and key type fields have been +// removed. +func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) { + in = bytes.TrimSpace(in) + + i := bytes.IndexAny(in, " \t") + if i == -1 { + i = len(in) + } + base64Key := in[:i] + + key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key))) + n, err := base64.StdEncoding.Decode(key, base64Key) + if err != nil { + return nil, "", err + } + key = key[:n] + out, err = ParsePublicKey(key) + if err != nil { + return nil, "", err + } + comment = string(bytes.TrimSpace(in[i:])) + return out, comment, nil +} + +// ParseKnownHosts parses an entry in the format of the known_hosts file. +// +// The known_hosts format is documented in the sshd(8) manual page. This +// function will parse a single entry from in. On successful return, marker +// will contain the optional marker value (i.e. "cert-authority" or "revoked") +// or else be empty, hosts will contain the hosts that this entry matches, +// pubKey will contain the public key and comment will contain any trailing +// comment at the end of the line. See the sshd(8) manual page for the various +// forms that a host string can take. +// +// The unparsed remainder of the input will be returned in rest. This function +// can be called repeatedly to parse multiple entries. +// +// If no entries were found in the input then err will be io.EOF. Otherwise a +// non-nil err value indicates a parse error. +func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) { + for len(in) > 0 { + end := bytes.IndexByte(in, '\n') + if end != -1 { + rest = in[end+1:] + in = in[:end] + } else { + rest = nil + } + + end = bytes.IndexByte(in, '\r') + if end != -1 { + in = in[:end] + } + + in = bytes.TrimSpace(in) + if len(in) == 0 || in[0] == '#' { + in = rest + continue + } + + i := bytes.IndexAny(in, " \t") + if i == -1 { + in = rest + continue + } + + // Strip out the beginning of the known_host key. + // This is either an optional marker or a (set of) hostname(s). + keyFields := bytes.Fields(in) + if len(keyFields) < 3 || len(keyFields) > 5 { + return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data") + } + + // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated + // list of hosts + marker := "" + if keyFields[0][0] == '@' { + marker = string(keyFields[0][1:]) + keyFields = keyFields[1:] + } + + hosts := string(keyFields[0]) + // keyFields[1] contains the key type (e.g. “ssh-rsa”). + // However, that information is duplicated inside the + // base64-encoded key and so is ignored here. + + key := bytes.Join(keyFields[2:], []byte(" ")) + if pubKey, comment, err = parseAuthorizedKey(key); err != nil { + return "", nil, nil, "", nil, err + } + + return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil + } + + return "", nil, nil, "", nil, io.EOF +} + +// ParseAuthorizedKeys parses a public key from an authorized_keys +// file used in OpenSSH according to the sshd(8) manual page. +func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { + for len(in) > 0 { + end := bytes.IndexByte(in, '\n') + if end != -1 { + rest = in[end+1:] + in = in[:end] + } else { + rest = nil + } + + end = bytes.IndexByte(in, '\r') + if end != -1 { + in = in[:end] + } + + in = bytes.TrimSpace(in) + if len(in) == 0 || in[0] == '#' { + in = rest + continue + } + + i := bytes.IndexAny(in, " \t") + if i == -1 { + in = rest + continue + } + + if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { + return out, comment, options, rest, nil + } + + // No key type recognised. Maybe there's an options field at + // the beginning. + var b byte + inQuote := false + var candidateOptions []string + optionStart := 0 + for i, b = range in { + isEnd := !inQuote && (b == ' ' || b == '\t') + if (b == ',' && !inQuote) || isEnd { + if i-optionStart > 0 { + candidateOptions = append(candidateOptions, string(in[optionStart:i])) + } + optionStart = i + 1 + } + if isEnd { + break + } + if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) { + inQuote = !inQuote + } + } + for i < len(in) && (in[i] == ' ' || in[i] == '\t') { + i++ + } + if i == len(in) { + // Invalid line: unmatched quote + in = rest + continue + } + + in = in[i:] + i = bytes.IndexAny(in, " \t") + if i == -1 { + in = rest + continue + } + + if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { + options = candidateOptions + return out, comment, options, rest, nil + } + + in = rest + continue + } + + return nil, "", nil, nil, errors.New("ssh: no key found") +} + +// ParsePublicKey parses an SSH public key formatted for use in +// the SSH wire protocol according to RFC 4253, section 6.6. +func ParsePublicKey(in []byte) (out PublicKey, err error) { + algo, in, ok := parseString(in) + if !ok { + return nil, errShortRead + } + var rest []byte + out, rest, err = parsePubKey(in, string(algo)) + if len(rest) > 0 { + return nil, errors.New("ssh: trailing junk in public key") + } + + return out, err +} + +// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH +// authorized_keys file. The return value ends with newline. +func MarshalAuthorizedKey(key PublicKey) []byte { + b := &bytes.Buffer{} + b.WriteString(key.Type()) + b.WriteByte(' ') + e := base64.NewEncoder(base64.StdEncoding, b) + e.Write(key.Marshal()) + e.Close() + b.WriteByte('\n') + return b.Bytes() +} + +// PublicKey represents a public key using an unspecified algorithm. +// +// Some PublicKeys provided by this package also implement CryptoPublicKey. +type PublicKey interface { + // Type returns the key format name, e.g. "ssh-rsa". + Type() string + + // Marshal returns the serialized key data in SSH wire format, with the name + // prefix. To unmarshal the returned data, use the ParsePublicKey function. + Marshal() []byte + + // Verify that sig is a signature on the given data using this key. This + // method will hash the data appropriately first. sig.Format is allowed to + // be any signature algorithm compatible with the key type, the caller + // should check if it has more stringent requirements. + Verify(data []byte, sig *Signature) error +} + +// CryptoPublicKey, if implemented by a PublicKey, +// returns the underlying crypto.PublicKey form of the key. +type CryptoPublicKey interface { + CryptoPublicKey() crypto.PublicKey +} + +// A Signer can create signatures that verify against a public key. +// +// Some Signers provided by this package also implement AlgorithmSigner. +type Signer interface { + // PublicKey returns the associated PublicKey. + PublicKey() PublicKey + + // Sign returns a signature for the given data. This method will hash the + // data appropriately first. The signature algorithm is expected to match + // the key format returned by the PublicKey.Type method (and not to be any + // alternative algorithm supported by the key format). + Sign(rand io.Reader, data []byte) (*Signature, error) +} + +// An AlgorithmSigner is a Signer that also supports specifying an algorithm to +// use for signing. +// +// An AlgorithmSigner can't advertise the algorithms it supports, so it should +// be prepared to be invoked with every algorithm supported by the public key +// format. +type AlgorithmSigner interface { + Signer + + // SignWithAlgorithm is like Signer.Sign, but allows specifying a desired + // signing algorithm. Callers may pass an empty string for the algorithm in + // which case the AlgorithmSigner will use a default algorithm. This default + // doesn't currently control any behavior in this package. + SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) +} + +type rsaPublicKey rsa.PublicKey + +func (r *rsaPublicKey) Type() string { + return "ssh-rsa" +} + +// parseRSA parses an RSA key according to RFC 4253, section 6.6. +func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + E *big.Int + N *big.Int + Rest []byte `ssh:"rest"` + } + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + if w.E.BitLen() > 24 { + return nil, nil, errors.New("ssh: exponent too large") + } + e := w.E.Int64() + if e < 3 || e&1 == 0 { + return nil, nil, errors.New("ssh: incorrect exponent") + } + + var key rsa.PublicKey + key.E = int(e) + key.N = w.N + return (*rsaPublicKey)(&key), w.Rest, nil +} + +func (r *rsaPublicKey) Marshal() []byte { + e := new(big.Int).SetInt64(int64(r.E)) + // RSA publickey struct layout should match the struct used by + // parseRSACert in the x/crypto/ssh/agent package. + wirekey := struct { + Name string + E *big.Int + N *big.Int + }{ + KeyAlgoRSA, + e, + r.N, + } + return Marshal(&wirekey) +} + +func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { + supportedAlgos := algorithmsForKeyFormat(r.Type()) + if !contains(supportedAlgos, sig.Format) { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) + } + hash := hashFuncs[sig.Format] + h := hash.New() + h.Write(data) + digest := h.Sum(nil) + return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) +} + +func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { + return (*rsa.PublicKey)(r) +} + +type dsaPublicKey dsa.PublicKey + +func (k *dsaPublicKey) Type() string { + return "ssh-dss" +} + +func checkDSAParams(param *dsa.Parameters) error { + // SSH specifies FIPS 186-2, which only provided a single size + // (1024 bits) DSA key. FIPS 186-3 allows for larger key + // sizes, which would confuse SSH. + if l := param.P.BitLen(); l != 1024 { + return fmt.Errorf("ssh: unsupported DSA key size %d", l) + } + + return nil +} + +// parseDSA parses an DSA key according to RFC 4253, section 6.6. +func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + P, Q, G, Y *big.Int + Rest []byte `ssh:"rest"` + } + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + param := dsa.Parameters{ + P: w.P, + Q: w.Q, + G: w.G, + } + if err := checkDSAParams(¶m); err != nil { + return nil, nil, err + } + + key := &dsaPublicKey{ + Parameters: param, + Y: w.Y, + } + return key, w.Rest, nil +} + +func (k *dsaPublicKey) Marshal() []byte { + // DSA publickey struct layout should match the struct used by + // parseDSACert in the x/crypto/ssh/agent package. + w := struct { + Name string + P, Q, G, Y *big.Int + }{ + k.Type(), + k.P, + k.Q, + k.G, + k.Y, + } + + return Marshal(&w) +} + +func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + h := hashFuncs[sig.Format].New() + h.Write(data) + digest := h.Sum(nil) + + // Per RFC 4253, section 6.6, + // The value for 'dss_signature_blob' is encoded as a string containing + // r, followed by s (which are 160-bit integers, without lengths or + // padding, unsigned, and in network byte order). + // For DSS purposes, sig.Blob should be exactly 40 bytes in length. + if len(sig.Blob) != 40 { + return errors.New("ssh: DSA signature parse error") + } + r := new(big.Int).SetBytes(sig.Blob[:20]) + s := new(big.Int).SetBytes(sig.Blob[20:]) + if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) { + return nil + } + return errors.New("ssh: signature did not verify") +} + +func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { + return (*dsa.PublicKey)(k) +} + +type dsaPrivateKey struct { + *dsa.PrivateKey +} + +func (k *dsaPrivateKey) PublicKey() PublicKey { + return (*dsaPublicKey)(&k.PrivateKey.PublicKey) +} + +func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { + return k.SignWithAlgorithm(rand, data, k.PublicKey().Type()) +} + +func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm != "" && algorithm != k.PublicKey().Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + + h := hashFuncs[k.PublicKey().Type()].New() + h.Write(data) + digest := h.Sum(nil) + r, s, err := dsa.Sign(rand, k.PrivateKey, digest) + if err != nil { + return nil, err + } + + sig := make([]byte, 40) + rb := r.Bytes() + sb := s.Bytes() + + copy(sig[20-len(rb):20], rb) + copy(sig[40-len(sb):], sb) + + return &Signature{ + Format: k.PublicKey().Type(), + Blob: sig, + }, nil +} + +type ecdsaPublicKey ecdsa.PublicKey + +func (k *ecdsaPublicKey) Type() string { + return "ecdsa-sha2-" + k.nistID() +} + +func (k *ecdsaPublicKey) nistID() string { + switch k.Params().BitSize { + case 256: + return "nistp256" + case 384: + return "nistp384" + case 521: + return "nistp521" + } + panic("ssh: unsupported ecdsa key size") +} + +type ed25519PublicKey ed25519.PublicKey + +func (k ed25519PublicKey) Type() string { + return KeyAlgoED25519 +} + +func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + KeyBytes []byte + Rest []byte `ssh:"rest"` + } + + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + if l := len(w.KeyBytes); l != ed25519.PublicKeySize { + return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l) + } + + return ed25519PublicKey(w.KeyBytes), w.Rest, nil +} + +func (k ed25519PublicKey) Marshal() []byte { + w := struct { + Name string + KeyBytes []byte + }{ + KeyAlgoED25519, + []byte(k), + } + return Marshal(&w) +} + +func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + if l := len(k); l != ed25519.PublicKeySize { + return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l) + } + + if ok := ed25519.Verify(ed25519.PublicKey(k), b, sig.Blob); !ok { + return errors.New("ssh: signature did not verify") + } + + return nil +} + +func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { + return ed25519.PublicKey(k) +} + +func supportedEllipticCurve(curve elliptic.Curve) bool { + return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() +} + +// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. +func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + Curve string + KeyBytes []byte + Rest []byte `ssh:"rest"` + } + + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + key := new(ecdsa.PublicKey) + + switch w.Curve { + case "nistp256": + key.Curve = elliptic.P256() + case "nistp384": + key.Curve = elliptic.P384() + case "nistp521": + key.Curve = elliptic.P521() + default: + return nil, nil, errors.New("ssh: unsupported curve") + } + + key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) + if key.X == nil || key.Y == nil { + return nil, nil, errors.New("ssh: invalid curve point") + } + return (*ecdsaPublicKey)(key), w.Rest, nil +} + +func (k *ecdsaPublicKey) Marshal() []byte { + // See RFC 5656, section 3.1. + keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) + // ECDSA publickey struct layout should match the struct used by + // parseECDSACert in the x/crypto/ssh/agent package. + w := struct { + Name string + ID string + Key []byte + }{ + k.Type(), + k.nistID(), + keyBytes, + } + + return Marshal(&w) +} + +func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + + h := hashFuncs[sig.Format].New() + h.Write(data) + digest := h.Sum(nil) + + // Per RFC 5656, section 3.1.2, + // The ecdsa_signature_blob value has the following specific encoding: + // mpint r + // mpint s + var ecSig struct { + R *big.Int + S *big.Int + } + + if err := Unmarshal(sig.Blob, &ecSig); err != nil { + return err + } + + if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) { + return nil + } + return errors.New("ssh: signature did not verify") +} + +func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { + return (*ecdsa.PublicKey)(k) +} + +// skFields holds the additional fields present in U2F/FIDO2 signatures. +// See openssh/PROTOCOL.u2f 'SSH U2F Signatures' for details. +type skFields struct { + // Flags contains U2F/FIDO2 flags such as 'user present' + Flags byte + // Counter is a monotonic signature counter which can be + // used to detect concurrent use of a private key, should + // it be extracted from hardware. + Counter uint32 +} + +type skECDSAPublicKey struct { + // application is a URL-like string, typically "ssh:" for SSH. + // see openssh/PROTOCOL.u2f for details. + application string + ecdsa.PublicKey +} + +func (k *skECDSAPublicKey) Type() string { + return KeyAlgoSKECDSA256 +} + +func (k *skECDSAPublicKey) nistID() string { + return "nistp256" +} + +func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + Curve string + KeyBytes []byte + Application string + Rest []byte `ssh:"rest"` + } + + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + key := new(skECDSAPublicKey) + key.application = w.Application + + if w.Curve != "nistp256" { + return nil, nil, errors.New("ssh: unsupported curve") + } + key.Curve = elliptic.P256() + + key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) + if key.X == nil || key.Y == nil { + return nil, nil, errors.New("ssh: invalid curve point") + } + + return key, w.Rest, nil +} + +func (k *skECDSAPublicKey) Marshal() []byte { + // See RFC 5656, section 3.1. + keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) + w := struct { + Name string + ID string + Key []byte + Application string + }{ + k.Type(), + k.nistID(), + keyBytes, + k.application, + } + + return Marshal(&w) +} + +func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + + h := hashFuncs[sig.Format].New() + h.Write([]byte(k.application)) + appDigest := h.Sum(nil) + + h.Reset() + h.Write(data) + dataDigest := h.Sum(nil) + + var ecSig struct { + R *big.Int + S *big.Int + } + if err := Unmarshal(sig.Blob, &ecSig); err != nil { + return err + } + + var skf skFields + if err := Unmarshal(sig.Rest, &skf); err != nil { + return err + } + + blob := struct { + ApplicationDigest []byte `ssh:"rest"` + Flags byte + Counter uint32 + MessageDigest []byte `ssh:"rest"` + }{ + appDigest, + skf.Flags, + skf.Counter, + dataDigest, + } + + original := Marshal(blob) + + h.Reset() + h.Write(original) + digest := h.Sum(nil) + + if ecdsa.Verify((*ecdsa.PublicKey)(&k.PublicKey), digest, ecSig.R, ecSig.S) { + return nil + } + return errors.New("ssh: signature did not verify") +} + +type skEd25519PublicKey struct { + // application is a URL-like string, typically "ssh:" for SSH. + // see openssh/PROTOCOL.u2f for details. + application string + ed25519.PublicKey +} + +func (k *skEd25519PublicKey) Type() string { + return KeyAlgoSKED25519 +} + +func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + KeyBytes []byte + Application string + Rest []byte `ssh:"rest"` + } + + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + if l := len(w.KeyBytes); l != ed25519.PublicKeySize { + return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l) + } + + key := new(skEd25519PublicKey) + key.application = w.Application + key.PublicKey = ed25519.PublicKey(w.KeyBytes) + + return key, w.Rest, nil +} + +func (k *skEd25519PublicKey) Marshal() []byte { + w := struct { + Name string + KeyBytes []byte + Application string + }{ + KeyAlgoSKED25519, + []byte(k.PublicKey), + k.application, + } + return Marshal(&w) +} + +func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + if l := len(k.PublicKey); l != ed25519.PublicKeySize { + return fmt.Errorf("invalid size %d for Ed25519 public key", l) + } + + h := hashFuncs[sig.Format].New() + h.Write([]byte(k.application)) + appDigest := h.Sum(nil) + + h.Reset() + h.Write(data) + dataDigest := h.Sum(nil) + + var edSig struct { + Signature []byte `ssh:"rest"` + } + + if err := Unmarshal(sig.Blob, &edSig); err != nil { + return err + } + + var skf skFields + if err := Unmarshal(sig.Rest, &skf); err != nil { + return err + } + + blob := struct { + ApplicationDigest []byte `ssh:"rest"` + Flags byte + Counter uint32 + MessageDigest []byte `ssh:"rest"` + }{ + appDigest, + skf.Flags, + skf.Counter, + dataDigest, + } + + original := Marshal(blob) + + if ok := ed25519.Verify(k.PublicKey, original, edSig.Signature); !ok { + return errors.New("ssh: signature did not verify") + } + + return nil +} + +// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, +// *ecdsa.PrivateKey or any other crypto.Signer and returns a +// corresponding Signer instance. ECDSA keys must use P-256, P-384 or +// P-521. DSA keys must use parameter size L1024N160. +func NewSignerFromKey(key interface{}) (Signer, error) { + switch key := key.(type) { + case crypto.Signer: + return NewSignerFromSigner(key) + case *dsa.PrivateKey: + return newDSAPrivateKey(key) + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } +} + +func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) { + if err := checkDSAParams(&key.PublicKey.Parameters); err != nil { + return nil, err + } + + return &dsaPrivateKey{key}, nil +} + +type wrappedSigner struct { + signer crypto.Signer + pubKey PublicKey +} + +// NewSignerFromSigner takes any crypto.Signer implementation and +// returns a corresponding Signer interface. This can be used, for +// example, with keys kept in hardware modules. +func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { + pubKey, err := NewPublicKey(signer.Public()) + if err != nil { + return nil, err + } + + return &wrappedSigner{signer, pubKey}, nil +} + +func (s *wrappedSigner) PublicKey() PublicKey { + return s.pubKey +} + +func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.SignWithAlgorithm(rand, data, s.pubKey.Type()) +} + +func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm == "" { + algorithm = s.pubKey.Type() + } + + supportedAlgos := algorithmsForKeyFormat(s.pubKey.Type()) + if !contains(supportedAlgos, algorithm) { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type()) + } + + hashFunc := hashFuncs[algorithm] + var digest []byte + if hashFunc != 0 { + h := hashFunc.New() + h.Write(data) + digest = h.Sum(nil) + } else { + digest = data + } + + signature, err := s.signer.Sign(rand, digest, hashFunc) + if err != nil { + return nil, err + } + + // crypto.Signer.Sign is expected to return an ASN.1-encoded signature + // for ECDSA and DSA, but that's not the encoding expected by SSH, so + // re-encode. + switch s.pubKey.(type) { + case *ecdsaPublicKey, *dsaPublicKey: + type asn1Signature struct { + R, S *big.Int + } + asn1Sig := new(asn1Signature) + _, err := asn1.Unmarshal(signature, asn1Sig) + if err != nil { + return nil, err + } + + switch s.pubKey.(type) { + case *ecdsaPublicKey: + signature = Marshal(asn1Sig) + + case *dsaPublicKey: + signature = make([]byte, 40) + r := asn1Sig.R.Bytes() + s := asn1Sig.S.Bytes() + copy(signature[20-len(r):20], r) + copy(signature[40-len(s):40], s) + } + } + + return &Signature{ + Format: algorithm, + Blob: signature, + }, nil +} + +// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, +// or ed25519.PublicKey returns a corresponding PublicKey instance. +// ECDSA keys must use P-256, P-384 or P-521. +func NewPublicKey(key interface{}) (PublicKey, error) { + switch key := key.(type) { + case *rsa.PublicKey: + return (*rsaPublicKey)(key), nil + case *ecdsa.PublicKey: + if !supportedEllipticCurve(key.Curve) { + return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported") + } + return (*ecdsaPublicKey)(key), nil + case *dsa.PublicKey: + return (*dsaPublicKey)(key), nil + case ed25519.PublicKey: + if l := len(key); l != ed25519.PublicKeySize { + return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l) + } + return ed25519PublicKey(key), nil + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } +} + +// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports +// the same keys as ParseRawPrivateKey. If the private key is encrypted, it +// will return a PassphraseMissingError. +func ParsePrivateKey(pemBytes []byte) (Signer, error) { + key, err := ParseRawPrivateKey(pemBytes) + if err != nil { + return nil, err + } + + return NewSignerFromKey(key) +} + +// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private +// key and passphrase. It supports the same keys as +// ParseRawPrivateKeyWithPassphrase. +func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error) { + key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase) + if err != nil { + return nil, err + } + + return NewSignerFromKey(key) +} + +// encryptedBlock tells whether a private key is +// encrypted by examining its Proc-Type header +// for a mention of ENCRYPTED +// according to RFC 1421 Section 4.6.1.1. +func encryptedBlock(block *pem.Block) bool { + return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") +} + +// A PassphraseMissingError indicates that parsing this private key requires a +// passphrase. Use ParsePrivateKeyWithPassphrase. +type PassphraseMissingError struct { + // PublicKey will be set if the private key format includes an unencrypted + // public key along with the encrypted private key. + PublicKey PublicKey +} + +func (*PassphraseMissingError) Error() string { + return "ssh: this private key is passphrase protected" +} + +// ParseRawPrivateKey returns a private key from a PEM encoded private key. It +// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. If the +// private key is encrypted, it will return a PassphraseMissingError. +func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("ssh: no key found") + } + + if encryptedBlock(block) { + return nil, &PassphraseMissingError{} + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + // RFC5208 - https://tools.ietf.org/html/rfc5208 + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + case "DSA PRIVATE KEY": + return ParseDSAPrivateKey(block.Bytes) + case "OPENSSH PRIVATE KEY": + return parseOpenSSHPrivateKey(block.Bytes, unencryptedOpenSSHKey) + default: + return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) + } +} + +// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with +// passphrase from a PEM encoded private key. If the passphrase is wrong, it +// will return x509.IncorrectPasswordError. +func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("ssh: no key found") + } + + if block.Type == "OPENSSH PRIVATE KEY" { + return parseOpenSSHPrivateKey(block.Bytes, passphraseProtectedOpenSSHKey(passphrase)) + } + + if !encryptedBlock(block) || !x509.IsEncryptedPEMBlock(block) { + return nil, errors.New("ssh: not an encrypted key") + } + + buf, err := x509.DecryptPEMBlock(block, passphrase) + if err != nil { + if err == x509.IncorrectPasswordError { + return nil, err + } + return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err) + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(buf) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(buf) + case "DSA PRIVATE KEY": + return ParseDSAPrivateKey(buf) + default: + return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) + } +} + +// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as +// specified by the OpenSSL DSA man page. +func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { + var k struct { + Version int + P *big.Int + Q *big.Int + G *big.Int + Pub *big.Int + Priv *big.Int + } + rest, err := asn1.Unmarshal(der, &k) + if err != nil { + return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) + } + if len(rest) > 0 { + return nil, errors.New("ssh: garbage after DSA key") + } + + return &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: k.P, + Q: k.Q, + G: k.G, + }, + Y: k.Pub, + }, + X: k.Priv, + }, nil +} + +func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) { + if kdfName != "none" || cipherName != "none" { + return nil, &PassphraseMissingError{} + } + if kdfOpts != "" { + return nil, errors.New("ssh: invalid openssh private key") + } + return privKeyBlock, nil +} + +func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc { + return func(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) { + if kdfName == "none" || cipherName == "none" { + return nil, errors.New("ssh: key is not password protected") + } + if kdfName != "bcrypt" { + return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", kdfName, "bcrypt") + } + + var opts struct { + Salt string + Rounds uint32 + } + if err := Unmarshal([]byte(kdfOpts), &opts); err != nil { + return nil, err + } + + k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16) + if err != nil { + return nil, err + } + key, iv := k[:32], k[32:] + + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + switch cipherName { + case "aes256-ctr": + ctr := cipher.NewCTR(c, iv) + ctr.XORKeyStream(privKeyBlock, privKeyBlock) + case "aes256-cbc": + if len(privKeyBlock)%c.BlockSize() != 0 { + return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size") + } + cbc := cipher.NewCBCDecrypter(c, iv) + cbc.CryptBlocks(privKeyBlock, privKeyBlock) + default: + return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc") + } + + return privKeyBlock, nil + } +} + +type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error) + +// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt +// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used +// as the decrypt function to parse an unencrypted private key. See +// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key. +func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) { + const magic = "openssh-key-v1\x00" + if len(key) < len(magic) || string(key[:len(magic)]) != magic { + return nil, errors.New("ssh: invalid openssh private key format") + } + remaining := key[len(magic):] + + var w struct { + CipherName string + KdfName string + KdfOpts string + NumKeys uint32 + PubKey []byte + PrivKeyBlock []byte + } + + if err := Unmarshal(remaining, &w); err != nil { + return nil, err + } + if w.NumKeys != 1 { + // We only support single key files, and so does OpenSSH. + // https://github.com/openssh/openssh-portable/blob/4103a3ec7/sshkey.c#L4171 + return nil, errors.New("ssh: multi-key files are not supported") + } + + privKeyBlock, err := decrypt(w.CipherName, w.KdfName, w.KdfOpts, w.PrivKeyBlock) + if err != nil { + if err, ok := err.(*PassphraseMissingError); ok { + pub, errPub := ParsePublicKey(w.PubKey) + if errPub != nil { + return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", errPub) + } + err.PublicKey = pub + } + return nil, err + } + + pk1 := struct { + Check1 uint32 + Check2 uint32 + Keytype string + Rest []byte `ssh:"rest"` + }{} + + if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 { + if w.CipherName != "none" { + return nil, x509.IncorrectPasswordError + } + return nil, errors.New("ssh: malformed OpenSSH key") + } + + switch pk1.Keytype { + case KeyAlgoRSA: + // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773 + key := struct { + N *big.Int + E *big.Int + D *big.Int + Iqmp *big.Int + P *big.Int + Q *big.Int + Comment string + Pad []byte `ssh:"rest"` + }{} + + if err := Unmarshal(pk1.Rest, &key); err != nil { + return nil, err + } + + if err := checkOpenSSHKeyPadding(key.Pad); err != nil { + return nil, err + } + + pk := &rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + N: key.N, + E: int(key.E.Int64()), + }, + D: key.D, + Primes: []*big.Int{key.P, key.Q}, + } + + if err := pk.Validate(); err != nil { + return nil, err + } + + pk.Precompute() + + return pk, nil + case KeyAlgoED25519: + key := struct { + Pub []byte + Priv []byte + Comment string + Pad []byte `ssh:"rest"` + }{} + + if err := Unmarshal(pk1.Rest, &key); err != nil { + return nil, err + } + + if len(key.Priv) != ed25519.PrivateKeySize { + return nil, errors.New("ssh: private key unexpected length") + } + + if err := checkOpenSSHKeyPadding(key.Pad); err != nil { + return nil, err + } + + pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) + copy(pk, key.Priv) + return &pk, nil + case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: + key := struct { + Curve string + Pub []byte + D *big.Int + Comment string + Pad []byte `ssh:"rest"` + }{} + + if err := Unmarshal(pk1.Rest, &key); err != nil { + return nil, err + } + + if err := checkOpenSSHKeyPadding(key.Pad); err != nil { + return nil, err + } + + var curve elliptic.Curve + switch key.Curve { + case "nistp256": + curve = elliptic.P256() + case "nistp384": + curve = elliptic.P384() + case "nistp521": + curve = elliptic.P521() + default: + return nil, errors.New("ssh: unhandled elliptic curve: " + key.Curve) + } + + X, Y := elliptic.Unmarshal(curve, key.Pub) + if X == nil || Y == nil { + return nil, errors.New("ssh: failed to unmarshal public key") + } + + if key.D.Cmp(curve.Params().N) >= 0 { + return nil, errors.New("ssh: scalar is out of range") + } + + x, y := curve.ScalarBaseMult(key.D.Bytes()) + if x.Cmp(X) != 0 || y.Cmp(Y) != 0 { + return nil, errors.New("ssh: public key does not match private key") + } + + return &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: curve, + X: X, + Y: Y, + }, + D: key.D, + }, nil + default: + return nil, errors.New("ssh: unhandled key type") + } +} + +func checkOpenSSHKeyPadding(pad []byte) error { + for i, b := range pad { + if int(b) != i+1 { + return errors.New("ssh: padding not as expected") + } + } + return nil +} + +// FingerprintLegacyMD5 returns the user presentation of the key's +// fingerprint as described by RFC 4716 section 4. +func FingerprintLegacyMD5(pubKey PublicKey) string { + md5sum := md5.Sum(pubKey.Marshal()) + hexarray := make([]string, len(md5sum)) + for i, c := range md5sum { + hexarray[i] = hex.EncodeToString([]byte{c}) + } + return strings.Join(hexarray, ":") +} + +// FingerprintSHA256 returns the user presentation of the key's +// fingerprint as unpadded base64 encoded sha256 hash. +// This format was introduced from OpenSSH 6.8. +// https://www.openssh.com/txt/release-6.8 +// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding) +func FingerprintSHA256(pubKey PublicKey) string { + sha256sum := sha256.Sum256(pubKey.Marshal()) + hash := base64.RawStdEncoding.EncodeToString(sha256sum[:]) + return "SHA256:" + hash +} diff --git a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go new file mode 100644 index 00000000..260cfe58 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go @@ -0,0 +1,540 @@ +// Copyright 2017 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 knownhosts implements a parser for the OpenSSH known_hosts +// host key database, and provides utility functions for writing +// OpenSSH compliant known_hosts files. +package knownhosts + +import ( + "bufio" + "bytes" + "crypto/hmac" + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "errors" + "fmt" + "io" + "net" + "os" + "strings" + + "golang.org/x/crypto/ssh" +) + +// See the sshd manpage +// (http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT) for +// background. + +type addr struct{ host, port string } + +func (a *addr) String() string { + h := a.host + if strings.Contains(h, ":") { + h = "[" + h + "]" + } + return h + ":" + a.port +} + +type matcher interface { + match(addr) bool +} + +type hostPattern struct { + negate bool + addr addr +} + +func (p *hostPattern) String() string { + n := "" + if p.negate { + n = "!" + } + + return n + p.addr.String() +} + +type hostPatterns []hostPattern + +func (ps hostPatterns) match(a addr) bool { + matched := false + for _, p := range ps { + if !p.match(a) { + continue + } + if p.negate { + return false + } + matched = true + } + return matched +} + +// See +// https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/addrmatch.c +// The matching of * has no regard for separators, unlike filesystem globs +func wildcardMatch(pat []byte, str []byte) bool { + for { + if len(pat) == 0 { + return len(str) == 0 + } + if len(str) == 0 { + return false + } + + if pat[0] == '*' { + if len(pat) == 1 { + return true + } + + for j := range str { + if wildcardMatch(pat[1:], str[j:]) { + return true + } + } + return false + } + + if pat[0] == '?' || pat[0] == str[0] { + pat = pat[1:] + str = str[1:] + } else { + return false + } + } +} + +func (p *hostPattern) match(a addr) bool { + return wildcardMatch([]byte(p.addr.host), []byte(a.host)) && p.addr.port == a.port +} + +type keyDBLine struct { + cert bool + matcher matcher + knownKey KnownKey +} + +func serialize(k ssh.PublicKey) string { + return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal()) +} + +func (l *keyDBLine) match(a addr) bool { + return l.matcher.match(a) +} + +type hostKeyDB struct { + // Serialized version of revoked keys + revoked map[string]*KnownKey + lines []keyDBLine +} + +func newHostKeyDB() *hostKeyDB { + db := &hostKeyDB{ + revoked: make(map[string]*KnownKey), + } + + return db +} + +func keyEq(a, b ssh.PublicKey) bool { + return bytes.Equal(a.Marshal(), b.Marshal()) +} + +// IsAuthorityForHost can be used as a callback in ssh.CertChecker +func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool { + h, p, err := net.SplitHostPort(address) + if err != nil { + return false + } + a := addr{host: h, port: p} + + for _, l := range db.lines { + if l.cert && keyEq(l.knownKey.Key, remote) && l.match(a) { + return true + } + } + return false +} + +// IsRevoked can be used as a callback in ssh.CertChecker +func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool { + _, ok := db.revoked[string(key.Marshal())] + return ok +} + +const markerCert = "@cert-authority" +const markerRevoked = "@revoked" + +func nextWord(line []byte) (string, []byte) { + i := bytes.IndexAny(line, "\t ") + if i == -1 { + return string(line), nil + } + + return string(line[:i]), bytes.TrimSpace(line[i:]) +} + +func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error) { + if w, next := nextWord(line); w == markerCert || w == markerRevoked { + marker = w + line = next + } + + host, line = nextWord(line) + if len(line) == 0 { + return "", "", nil, errors.New("knownhosts: missing host pattern") + } + + // ignore the keytype as it's in the key blob anyway. + _, line = nextWord(line) + if len(line) == 0 { + return "", "", nil, errors.New("knownhosts: missing key type pattern") + } + + keyBlob, _ := nextWord(line) + + keyBytes, err := base64.StdEncoding.DecodeString(keyBlob) + if err != nil { + return "", "", nil, err + } + key, err = ssh.ParsePublicKey(keyBytes) + if err != nil { + return "", "", nil, err + } + + return marker, host, key, nil +} + +func (db *hostKeyDB) parseLine(line []byte, filename string, linenum int) error { + marker, pattern, key, err := parseLine(line) + if err != nil { + return err + } + + if marker == markerRevoked { + db.revoked[string(key.Marshal())] = &KnownKey{ + Key: key, + Filename: filename, + Line: linenum, + } + + return nil + } + + entry := keyDBLine{ + cert: marker == markerCert, + knownKey: KnownKey{ + Filename: filename, + Line: linenum, + Key: key, + }, + } + + if pattern[0] == '|' { + entry.matcher, err = newHashedHost(pattern) + } else { + entry.matcher, err = newHostnameMatcher(pattern) + } + + if err != nil { + return err + } + + db.lines = append(db.lines, entry) + return nil +} + +func newHostnameMatcher(pattern string) (matcher, error) { + var hps hostPatterns + for _, p := range strings.Split(pattern, ",") { + if len(p) == 0 { + continue + } + + var a addr + var negate bool + if p[0] == '!' { + negate = true + p = p[1:] + } + + if len(p) == 0 { + return nil, errors.New("knownhosts: negation without following hostname") + } + + var err error + if p[0] == '[' { + a.host, a.port, err = net.SplitHostPort(p) + if err != nil { + return nil, err + } + } else { + a.host, a.port, err = net.SplitHostPort(p) + if err != nil { + a.host = p + a.port = "22" + } + } + hps = append(hps, hostPattern{ + negate: negate, + addr: a, + }) + } + return hps, nil +} + +// KnownKey represents a key declared in a known_hosts file. +type KnownKey struct { + Key ssh.PublicKey + Filename string + Line int +} + +func (k *KnownKey) String() string { + return fmt.Sprintf("%s:%d: %s", k.Filename, k.Line, serialize(k.Key)) +} + +// KeyError is returned if we did not find the key in the host key +// database, or there was a mismatch. Typically, in batch +// applications, this should be interpreted as failure. Interactive +// applications can offer an interactive prompt to the user. +type KeyError struct { + // Want holds the accepted host keys. For each key algorithm, + // there can be one hostkey. If Want is empty, the host is + // unknown. If Want is non-empty, there was a mismatch, which + // can signify a MITM attack. + Want []KnownKey +} + +func (u *KeyError) Error() string { + if len(u.Want) == 0 { + return "knownhosts: key is unknown" + } + return "knownhosts: key mismatch" +} + +// RevokedError is returned if we found a key that was revoked. +type RevokedError struct { + Revoked KnownKey +} + +func (r *RevokedError) Error() string { + return "knownhosts: key is revoked" +} + +// check checks a key against the host database. This should not be +// used for verifying certificates. +func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.PublicKey) error { + if revoked := db.revoked[string(remoteKey.Marshal())]; revoked != nil { + return &RevokedError{Revoked: *revoked} + } + + host, port, err := net.SplitHostPort(remote.String()) + if err != nil { + return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err) + } + + hostToCheck := addr{host, port} + if address != "" { + // Give preference to the hostname if available. + host, port, err := net.SplitHostPort(address) + if err != nil { + return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err) + } + + hostToCheck = addr{host, port} + } + + return db.checkAddr(hostToCheck, remoteKey) +} + +// checkAddr checks if we can find the given public key for the +// given address. If we only find an entry for the IP address, +// or only the hostname, then this still succeeds. +func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { + // TODO(hanwen): are these the right semantics? What if there + // is just a key for the IP address, but not for the + // hostname? + + // Algorithm => key. + knownKeys := map[string]KnownKey{} + for _, l := range db.lines { + if l.match(a) { + typ := l.knownKey.Key.Type() + if _, ok := knownKeys[typ]; !ok { + knownKeys[typ] = l.knownKey + } + } + } + + keyErr := &KeyError{} + for _, v := range knownKeys { + keyErr.Want = append(keyErr.Want, v) + } + + // Unknown remote host. + if len(knownKeys) == 0 { + return keyErr + } + + // If the remote host starts using a different, unknown key type, we + // also interpret that as a mismatch. + if known, ok := knownKeys[remoteKey.Type()]; !ok || !keyEq(known.Key, remoteKey) { + return keyErr + } + + return nil +} + +// The Read function parses file contents. +func (db *hostKeyDB) Read(r io.Reader, filename string) error { + scanner := bufio.NewScanner(r) + + lineNum := 0 + for scanner.Scan() { + lineNum++ + line := scanner.Bytes() + line = bytes.TrimSpace(line) + if len(line) == 0 || line[0] == '#' { + continue + } + + if err := db.parseLine(line, filename, lineNum); err != nil { + return fmt.Errorf("knownhosts: %s:%d: %v", filename, lineNum, err) + } + } + return scanner.Err() +} + +// New creates a host key callback from the given OpenSSH host key +// files. The returned callback is for use in +// ssh.ClientConfig.HostKeyCallback. By preference, the key check +// operates on the hostname if available, i.e. if a server changes its +// IP address, the host key check will still succeed, even though a +// record of the new IP address is not available. +func New(files ...string) (ssh.HostKeyCallback, error) { + db := newHostKeyDB() + for _, fn := range files { + f, err := os.Open(fn) + if err != nil { + return nil, err + } + defer f.Close() + if err := db.Read(f, fn); err != nil { + return nil, err + } + } + + var certChecker ssh.CertChecker + certChecker.IsHostAuthority = db.IsHostAuthority + certChecker.IsRevoked = db.IsRevoked + certChecker.HostKeyFallback = db.check + + return certChecker.CheckHostKey, nil +} + +// Normalize normalizes an address into the form used in known_hosts +func Normalize(address string) string { + host, port, err := net.SplitHostPort(address) + if err != nil { + host = address + port = "22" + } + entry := host + if port != "22" { + entry = "[" + entry + "]:" + port + } else if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { + entry = "[" + entry + "]" + } + return entry +} + +// Line returns a line to add append to the known_hosts files. +func Line(addresses []string, key ssh.PublicKey) string { + var trimmed []string + for _, a := range addresses { + trimmed = append(trimmed, Normalize(a)) + } + + return strings.Join(trimmed, ",") + " " + serialize(key) +} + +// HashHostname hashes the given hostname. The hostname is not +// normalized before hashing. +func HashHostname(hostname string) string { + // TODO(hanwen): check if we can safely normalize this always. + salt := make([]byte, sha1.Size) + + _, err := rand.Read(salt) + if err != nil { + panic(fmt.Sprintf("crypto/rand failure %v", err)) + } + + hash := hashHost(hostname, salt) + return encodeHash(sha1HashType, salt, hash) +} + +func decodeHash(encoded string) (hashType string, salt, hash []byte, err error) { + if len(encoded) == 0 || encoded[0] != '|' { + err = errors.New("knownhosts: hashed host must start with '|'") + return + } + components := strings.Split(encoded, "|") + if len(components) != 4 { + err = fmt.Errorf("knownhosts: got %d components, want 3", len(components)) + return + } + + hashType = components[1] + if salt, err = base64.StdEncoding.DecodeString(components[2]); err != nil { + return + } + if hash, err = base64.StdEncoding.DecodeString(components[3]); err != nil { + return + } + return +} + +func encodeHash(typ string, salt []byte, hash []byte) string { + return strings.Join([]string{"", + typ, + base64.StdEncoding.EncodeToString(salt), + base64.StdEncoding.EncodeToString(hash), + }, "|") +} + +// See https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 +func hashHost(hostname string, salt []byte) []byte { + mac := hmac.New(sha1.New, salt) + mac.Write([]byte(hostname)) + return mac.Sum(nil) +} + +type hashedHost struct { + salt []byte + hash []byte +} + +const sha1HashType = "1" + +func newHashedHost(encoded string) (*hashedHost, error) { + typ, salt, hash, err := decodeHash(encoded) + if err != nil { + return nil, err + } + + // The type field seems for future algorithm agility, but it's + // actually hardcoded in openssh currently, see + // https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 + if typ != sha1HashType { + return nil, fmt.Errorf("knownhosts: got hash type %s, must be '1'", typ) + } + + return &hashedHost{salt: salt, hash: hash}, nil +} + +func (h *hashedHost) match(a addr) bool { + return bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) +} diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go new file mode 100644 index 00000000..c07a0628 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mac.go @@ -0,0 +1,61 @@ +// 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 ssh + +// Message authentication support + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "hash" +) + +type macMode struct { + keySize int + etm bool + new func(key []byte) hash.Hash +} + +// truncatingMAC wraps around a hash.Hash and truncates the output digest to +// a given size. +type truncatingMAC struct { + length int + hmac hash.Hash +} + +func (t truncatingMAC) Write(data []byte) (int, error) { + return t.hmac.Write(data) +} + +func (t truncatingMAC) Sum(in []byte) []byte { + out := t.hmac.Sum(in) + return out[:len(in)+t.length] +} + +func (t truncatingMAC) Reset() { + t.hmac.Reset() +} + +func (t truncatingMAC) Size() int { + return t.length +} + +func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } + +var macModes = map[string]*macMode{ + "hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { + return hmac.New(sha256.New, key) + }}, + "hmac-sha2-256": {32, false, func(key []byte) hash.Hash { + return hmac.New(sha256.New, key) + }}, + "hmac-sha1": {20, false, func(key []byte) hash.Hash { + return hmac.New(sha1.New, key) + }}, + "hmac-sha1-96": {20, false, func(key []byte) hash.Hash { + return truncatingMAC{12, hmac.New(sha1.New, key)} + }}, +} diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go new file mode 100644 index 00000000..19bc67c4 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/messages.go @@ -0,0 +1,877 @@ +// 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 ssh + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + "reflect" + "strconv" + "strings" +) + +// These are SSH message type numbers. They are scattered around several +// documents but many were taken from [SSH-PARAMETERS]. +const ( + msgIgnore = 2 + msgUnimplemented = 3 + msgDebug = 4 + msgNewKeys = 21 +) + +// SSH messages: +// +// These structures mirror the wire format of the corresponding SSH messages. +// They are marshaled using reflection with the marshal and unmarshal functions +// in this file. The only wrinkle is that a final member of type []byte with a +// ssh tag of "rest" receives the remainder of a packet when unmarshaling. + +// See RFC 4253, section 11.1. +const msgDisconnect = 1 + +// disconnectMsg is the message that signals a disconnect. It is also +// the error type returned from mux.Wait() +type disconnectMsg struct { + Reason uint32 `sshtype:"1"` + Message string + Language string +} + +func (d *disconnectMsg) Error() string { + return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message) +} + +// See RFC 4253, section 7.1. +const msgKexInit = 20 + +type kexInitMsg struct { + Cookie [16]byte `sshtype:"20"` + KexAlgos []string + ServerHostKeyAlgos []string + CiphersClientServer []string + CiphersServerClient []string + MACsClientServer []string + MACsServerClient []string + CompressionClientServer []string + CompressionServerClient []string + LanguagesClientServer []string + LanguagesServerClient []string + FirstKexFollows bool + Reserved uint32 +} + +// See RFC 4253, section 8. + +// Diffie-Helman +const msgKexDHInit = 30 + +type kexDHInitMsg struct { + X *big.Int `sshtype:"30"` +} + +const msgKexECDHInit = 30 + +type kexECDHInitMsg struct { + ClientPubKey []byte `sshtype:"30"` +} + +const msgKexECDHReply = 31 + +type kexECDHReplyMsg struct { + HostKey []byte `sshtype:"31"` + EphemeralPubKey []byte + Signature []byte +} + +const msgKexDHReply = 31 + +type kexDHReplyMsg struct { + HostKey []byte `sshtype:"31"` + Y *big.Int + Signature []byte +} + +// See RFC 4419, section 5. +const msgKexDHGexGroup = 31 + +type kexDHGexGroupMsg struct { + P *big.Int `sshtype:"31"` + G *big.Int +} + +const msgKexDHGexInit = 32 + +type kexDHGexInitMsg struct { + X *big.Int `sshtype:"32"` +} + +const msgKexDHGexReply = 33 + +type kexDHGexReplyMsg struct { + HostKey []byte `sshtype:"33"` + Y *big.Int + Signature []byte +} + +const msgKexDHGexRequest = 34 + +type kexDHGexRequestMsg struct { + MinBits uint32 `sshtype:"34"` + PreferedBits uint32 + MaxBits uint32 +} + +// See RFC 4253, section 10. +const msgServiceRequest = 5 + +type serviceRequestMsg struct { + Service string `sshtype:"5"` +} + +// See RFC 4253, section 10. +const msgServiceAccept = 6 + +type serviceAcceptMsg struct { + Service string `sshtype:"6"` +} + +// See RFC 8308, section 2.3 +const msgExtInfo = 7 + +type extInfoMsg struct { + NumExtensions uint32 `sshtype:"7"` + Payload []byte `ssh:"rest"` +} + +// See RFC 4252, section 5. +const msgUserAuthRequest = 50 + +type userAuthRequestMsg struct { + User string `sshtype:"50"` + Service string + Method string + Payload []byte `ssh:"rest"` +} + +// Used for debug printouts of packets. +type userAuthSuccessMsg struct { +} + +// See RFC 4252, section 5.1 +const msgUserAuthFailure = 51 + +type userAuthFailureMsg struct { + Methods []string `sshtype:"51"` + PartialSuccess bool +} + +// See RFC 4252, section 5.1 +const msgUserAuthSuccess = 52 + +// See RFC 4252, section 5.4 +const msgUserAuthBanner = 53 + +type userAuthBannerMsg struct { + Message string `sshtype:"53"` + // unused, but required to allow message parsing + Language string +} + +// See RFC 4256, section 3.2 +const msgUserAuthInfoRequest = 60 +const msgUserAuthInfoResponse = 61 + +type userAuthInfoRequestMsg struct { + Name string `sshtype:"60"` + Instruction string + Language string + NumPrompts uint32 + Prompts []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.1. +const msgChannelOpen = 90 + +type channelOpenMsg struct { + ChanType string `sshtype:"90"` + PeersID uint32 + PeersWindow uint32 + MaxPacketSize uint32 + TypeSpecificData []byte `ssh:"rest"` +} + +const msgChannelExtendedData = 95 +const msgChannelData = 94 + +// Used for debug print outs of packets. +type channelDataMsg struct { + PeersID uint32 `sshtype:"94"` + Length uint32 + Rest []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.1. +const msgChannelOpenConfirm = 91 + +type channelOpenConfirmMsg struct { + PeersID uint32 `sshtype:"91"` + MyID uint32 + MyWindow uint32 + MaxPacketSize uint32 + TypeSpecificData []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.1. +const msgChannelOpenFailure = 92 + +type channelOpenFailureMsg struct { + PeersID uint32 `sshtype:"92"` + Reason RejectionReason + Message string + Language string +} + +const msgChannelRequest = 98 + +type channelRequestMsg struct { + PeersID uint32 `sshtype:"98"` + Request string + WantReply bool + RequestSpecificData []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.4. +const msgChannelSuccess = 99 + +type channelRequestSuccessMsg struct { + PeersID uint32 `sshtype:"99"` +} + +// See RFC 4254, section 5.4. +const msgChannelFailure = 100 + +type channelRequestFailureMsg struct { + PeersID uint32 `sshtype:"100"` +} + +// See RFC 4254, section 5.3 +const msgChannelClose = 97 + +type channelCloseMsg struct { + PeersID uint32 `sshtype:"97"` +} + +// See RFC 4254, section 5.3 +const msgChannelEOF = 96 + +type channelEOFMsg struct { + PeersID uint32 `sshtype:"96"` +} + +// See RFC 4254, section 4 +const msgGlobalRequest = 80 + +type globalRequestMsg struct { + Type string `sshtype:"80"` + WantReply bool + Data []byte `ssh:"rest"` +} + +// See RFC 4254, section 4 +const msgRequestSuccess = 81 + +type globalRequestSuccessMsg struct { + Data []byte `ssh:"rest" sshtype:"81"` +} + +// See RFC 4254, section 4 +const msgRequestFailure = 82 + +type globalRequestFailureMsg struct { + Data []byte `ssh:"rest" sshtype:"82"` +} + +// See RFC 4254, section 5.2 +const msgChannelWindowAdjust = 93 + +type windowAdjustMsg struct { + PeersID uint32 `sshtype:"93"` + AdditionalBytes uint32 +} + +// See RFC 4252, section 7 +const msgUserAuthPubKeyOk = 60 + +type userAuthPubKeyOkMsg struct { + Algo string `sshtype:"60"` + PubKey []byte +} + +// See RFC 4462, section 3 +const msgUserAuthGSSAPIResponse = 60 + +type userAuthGSSAPIResponse struct { + SupportMech []byte `sshtype:"60"` +} + +const msgUserAuthGSSAPIToken = 61 + +type userAuthGSSAPIToken struct { + Token []byte `sshtype:"61"` +} + +const msgUserAuthGSSAPIMIC = 66 + +type userAuthGSSAPIMIC struct { + MIC []byte `sshtype:"66"` +} + +// See RFC 4462, section 3.9 +const msgUserAuthGSSAPIErrTok = 64 + +type userAuthGSSAPIErrTok struct { + ErrorToken []byte `sshtype:"64"` +} + +// See RFC 4462, section 3.8 +const msgUserAuthGSSAPIError = 65 + +type userAuthGSSAPIError struct { + MajorStatus uint32 `sshtype:"65"` + MinorStatus uint32 + Message string + LanguageTag string +} + +// typeTags returns the possible type bytes for the given reflect.Type, which +// should be a struct. The possible values are separated by a '|' character. +func typeTags(structType reflect.Type) (tags []byte) { + tagStr := structType.Field(0).Tag.Get("sshtype") + + for _, tag := range strings.Split(tagStr, "|") { + i, err := strconv.Atoi(tag) + if err == nil { + tags = append(tags, byte(i)) + } + } + + return tags +} + +func fieldError(t reflect.Type, field int, problem string) error { + if problem != "" { + problem = ": " + problem + } + return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem) +} + +var errShortRead = errors.New("ssh: short read") + +// Unmarshal parses data in SSH wire format into a structure. The out +// argument should be a pointer to struct. If the first member of the +// struct has the "sshtype" tag set to a '|'-separated set of numbers +// in decimal, the packet must start with one of those numbers. In +// case of error, Unmarshal returns a ParseError or +// UnexpectedMessageError. +func Unmarshal(data []byte, out interface{}) error { + v := reflect.ValueOf(out).Elem() + structType := v.Type() + expectedTypes := typeTags(structType) + + var expectedType byte + if len(expectedTypes) > 0 { + expectedType = expectedTypes[0] + } + + if len(data) == 0 { + return parseError(expectedType) + } + + if len(expectedTypes) > 0 { + goodType := false + for _, e := range expectedTypes { + if e > 0 && data[0] == e { + goodType = true + break + } + } + if !goodType { + return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes) + } + data = data[1:] + } + + var ok bool + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + t := field.Type() + switch t.Kind() { + case reflect.Bool: + if len(data) < 1 { + return errShortRead + } + field.SetBool(data[0] != 0) + data = data[1:] + case reflect.Array: + if t.Elem().Kind() != reflect.Uint8 { + return fieldError(structType, i, "array of unsupported type") + } + if len(data) < t.Len() { + return errShortRead + } + for j, n := 0, t.Len(); j < n; j++ { + field.Index(j).Set(reflect.ValueOf(data[j])) + } + data = data[t.Len():] + case reflect.Uint64: + var u64 uint64 + if u64, data, ok = parseUint64(data); !ok { + return errShortRead + } + field.SetUint(u64) + case reflect.Uint32: + var u32 uint32 + if u32, data, ok = parseUint32(data); !ok { + return errShortRead + } + field.SetUint(uint64(u32)) + case reflect.Uint8: + if len(data) < 1 { + return errShortRead + } + field.SetUint(uint64(data[0])) + data = data[1:] + case reflect.String: + var s []byte + if s, data, ok = parseString(data); !ok { + return fieldError(structType, i, "") + } + field.SetString(string(s)) + case reflect.Slice: + switch t.Elem().Kind() { + case reflect.Uint8: + if structType.Field(i).Tag.Get("ssh") == "rest" { + field.Set(reflect.ValueOf(data)) + data = nil + } else { + var s []byte + if s, data, ok = parseString(data); !ok { + return errShortRead + } + field.Set(reflect.ValueOf(s)) + } + case reflect.String: + var nl []string + if nl, data, ok = parseNameList(data); !ok { + return errShortRead + } + field.Set(reflect.ValueOf(nl)) + default: + return fieldError(structType, i, "slice of unsupported type") + } + case reflect.Ptr: + if t == bigIntType { + var n *big.Int + if n, data, ok = parseInt(data); !ok { + return errShortRead + } + field.Set(reflect.ValueOf(n)) + } else { + return fieldError(structType, i, "pointer to unsupported type") + } + default: + return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t)) + } + } + + if len(data) != 0 { + return parseError(expectedType) + } + + return nil +} + +// Marshal serializes the message in msg to SSH wire format. The msg +// argument should be a struct or pointer to struct. If the first +// member has the "sshtype" tag set to a number in decimal, that +// number is prepended to the result. If the last of member has the +// "ssh" tag set to "rest", its contents are appended to the output. +func Marshal(msg interface{}) []byte { + out := make([]byte, 0, 64) + return marshalStruct(out, msg) +} + +func marshalStruct(out []byte, msg interface{}) []byte { + v := reflect.Indirect(reflect.ValueOf(msg)) + msgTypes := typeTags(v.Type()) + if len(msgTypes) > 0 { + out = append(out, msgTypes[0]) + } + + for i, n := 0, v.NumField(); i < n; i++ { + field := v.Field(i) + switch t := field.Type(); t.Kind() { + case reflect.Bool: + var v uint8 + if field.Bool() { + v = 1 + } + out = append(out, v) + case reflect.Array: + if t.Elem().Kind() != reflect.Uint8 { + panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface())) + } + for j, l := 0, t.Len(); j < l; j++ { + out = append(out, uint8(field.Index(j).Uint())) + } + case reflect.Uint32: + out = appendU32(out, uint32(field.Uint())) + case reflect.Uint64: + out = appendU64(out, uint64(field.Uint())) + case reflect.Uint8: + out = append(out, uint8(field.Uint())) + case reflect.String: + s := field.String() + out = appendInt(out, len(s)) + out = append(out, s...) + case reflect.Slice: + switch t.Elem().Kind() { + case reflect.Uint8: + if v.Type().Field(i).Tag.Get("ssh") != "rest" { + out = appendInt(out, field.Len()) + } + out = append(out, field.Bytes()...) + case reflect.String: + offset := len(out) + out = appendU32(out, 0) + if n := field.Len(); n > 0 { + for j := 0; j < n; j++ { + f := field.Index(j) + if j != 0 { + out = append(out, ',') + } + out = append(out, f.String()...) + } + // overwrite length value + binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4)) + } + default: + panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface())) + } + case reflect.Ptr: + if t == bigIntType { + var n *big.Int + nValue := reflect.ValueOf(&n) + nValue.Elem().Set(field) + needed := intLength(n) + oldLength := len(out) + + if cap(out)-len(out) < needed { + newOut := make([]byte, len(out), 2*(len(out)+needed)) + copy(newOut, out) + out = newOut + } + out = out[:oldLength+needed] + marshalInt(out[oldLength:], n) + } else { + panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface())) + } + } + } + + return out +} + +var bigOne = big.NewInt(1) + +func parseString(in []byte) (out, rest []byte, ok bool) { + if len(in) < 4 { + return + } + length := binary.BigEndian.Uint32(in) + in = in[4:] + if uint32(len(in)) < length { + return + } + out = in[:length] + rest = in[length:] + ok = true + return +} + +var ( + comma = []byte{','} + emptyNameList = []string{} +) + +func parseNameList(in []byte) (out []string, rest []byte, ok bool) { + contents, rest, ok := parseString(in) + if !ok { + return + } + if len(contents) == 0 { + out = emptyNameList + return + } + parts := bytes.Split(contents, comma) + out = make([]string, len(parts)) + for i, part := range parts { + out[i] = string(part) + } + return +} + +func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { + contents, rest, ok := parseString(in) + if !ok { + return + } + out = new(big.Int) + + if len(contents) > 0 && contents[0]&0x80 == 0x80 { + // This is a negative number + notBytes := make([]byte, len(contents)) + for i := range notBytes { + notBytes[i] = ^contents[i] + } + out.SetBytes(notBytes) + out.Add(out, bigOne) + out.Neg(out) + } else { + // Positive number + out.SetBytes(contents) + } + ok = true + return +} + +func parseUint32(in []byte) (uint32, []byte, bool) { + if len(in) < 4 { + return 0, nil, false + } + return binary.BigEndian.Uint32(in), in[4:], true +} + +func parseUint64(in []byte) (uint64, []byte, bool) { + if len(in) < 8 { + return 0, nil, false + } + return binary.BigEndian.Uint64(in), in[8:], true +} + +func intLength(n *big.Int) int { + length := 4 /* length bytes */ + if n.Sign() < 0 { + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bitLen := nMinus1.BitLen() + if bitLen%8 == 0 { + // The number will need 0xff padding + length++ + } + length += (bitLen + 7) / 8 + } else if n.Sign() == 0 { + // A zero is the zero length string + } else { + bitLen := n.BitLen() + if bitLen%8 == 0 { + // The number will need 0x00 padding + length++ + } + length += (bitLen + 7) / 8 + } + + return length +} + +func marshalUint32(to []byte, n uint32) []byte { + binary.BigEndian.PutUint32(to, n) + return to[4:] +} + +func marshalUint64(to []byte, n uint64) []byte { + binary.BigEndian.PutUint64(to, n) + return to[8:] +} + +func marshalInt(to []byte, n *big.Int) []byte { + lengthBytes := to + to = to[4:] + length := 0 + + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement + // form. So we'll subtract 1 and invert. If the + // most-significant-bit isn't set then we'll need to pad the + // beginning with 0xff in order to keep the number negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if len(bytes) == 0 || bytes[0]&0x80 == 0 { + to[0] = 0xff + to = to[1:] + length++ + } + nBytes := copy(to, bytes) + to = to[nBytes:] + length += nBytes + } else if n.Sign() == 0 { + // A zero is the zero length string + } else { + bytes := n.Bytes() + if len(bytes) > 0 && bytes[0]&0x80 != 0 { + // We'll have to pad this with a 0x00 in order to + // stop it looking like a negative number. + to[0] = 0 + to = to[1:] + length++ + } + nBytes := copy(to, bytes) + to = to[nBytes:] + length += nBytes + } + + lengthBytes[0] = byte(length >> 24) + lengthBytes[1] = byte(length >> 16) + lengthBytes[2] = byte(length >> 8) + lengthBytes[3] = byte(length) + return to +} + +func writeInt(w io.Writer, n *big.Int) { + length := intLength(n) + buf := make([]byte, length) + marshalInt(buf, n) + w.Write(buf) +} + +func writeString(w io.Writer, s []byte) { + var lengthBytes [4]byte + lengthBytes[0] = byte(len(s) >> 24) + lengthBytes[1] = byte(len(s) >> 16) + lengthBytes[2] = byte(len(s) >> 8) + lengthBytes[3] = byte(len(s)) + w.Write(lengthBytes[:]) + w.Write(s) +} + +func stringLength(n int) int { + return 4 + n +} + +func marshalString(to []byte, s []byte) []byte { + to[0] = byte(len(s) >> 24) + to[1] = byte(len(s) >> 16) + to[2] = byte(len(s) >> 8) + to[3] = byte(len(s)) + to = to[4:] + copy(to, s) + return to[len(s):] +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)) + +// Decode a packet into its corresponding message. +func decode(packet []byte) (interface{}, error) { + var msg interface{} + switch packet[0] { + case msgDisconnect: + msg = new(disconnectMsg) + case msgServiceRequest: + msg = new(serviceRequestMsg) + case msgServiceAccept: + msg = new(serviceAcceptMsg) + case msgExtInfo: + msg = new(extInfoMsg) + case msgKexInit: + msg = new(kexInitMsg) + case msgKexDHInit: + msg = new(kexDHInitMsg) + case msgKexDHReply: + msg = new(kexDHReplyMsg) + case msgUserAuthRequest: + msg = new(userAuthRequestMsg) + case msgUserAuthSuccess: + return new(userAuthSuccessMsg), nil + case msgUserAuthFailure: + msg = new(userAuthFailureMsg) + case msgUserAuthPubKeyOk: + msg = new(userAuthPubKeyOkMsg) + case msgGlobalRequest: + msg = new(globalRequestMsg) + case msgRequestSuccess: + msg = new(globalRequestSuccessMsg) + case msgRequestFailure: + msg = new(globalRequestFailureMsg) + case msgChannelOpen: + msg = new(channelOpenMsg) + case msgChannelData: + msg = new(channelDataMsg) + case msgChannelOpenConfirm: + msg = new(channelOpenConfirmMsg) + case msgChannelOpenFailure: + msg = new(channelOpenFailureMsg) + case msgChannelWindowAdjust: + msg = new(windowAdjustMsg) + case msgChannelEOF: + msg = new(channelEOFMsg) + case msgChannelClose: + msg = new(channelCloseMsg) + case msgChannelRequest: + msg = new(channelRequestMsg) + case msgChannelSuccess: + msg = new(channelRequestSuccessMsg) + case msgChannelFailure: + msg = new(channelRequestFailureMsg) + case msgUserAuthGSSAPIToken: + msg = new(userAuthGSSAPIToken) + case msgUserAuthGSSAPIMIC: + msg = new(userAuthGSSAPIMIC) + case msgUserAuthGSSAPIErrTok: + msg = new(userAuthGSSAPIErrTok) + case msgUserAuthGSSAPIError: + msg = new(userAuthGSSAPIError) + default: + return nil, unexpectedMessageError(0, packet[0]) + } + if err := Unmarshal(packet, msg); err != nil { + return nil, err + } + return msg, nil +} + +var packetTypeNames = map[byte]string{ + msgDisconnect: "disconnectMsg", + msgServiceRequest: "serviceRequestMsg", + msgServiceAccept: "serviceAcceptMsg", + msgExtInfo: "extInfoMsg", + msgKexInit: "kexInitMsg", + msgKexDHInit: "kexDHInitMsg", + msgKexDHReply: "kexDHReplyMsg", + msgUserAuthRequest: "userAuthRequestMsg", + msgUserAuthSuccess: "userAuthSuccessMsg", + msgUserAuthFailure: "userAuthFailureMsg", + msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg", + msgGlobalRequest: "globalRequestMsg", + msgRequestSuccess: "globalRequestSuccessMsg", + msgRequestFailure: "globalRequestFailureMsg", + msgChannelOpen: "channelOpenMsg", + msgChannelData: "channelDataMsg", + msgChannelOpenConfirm: "channelOpenConfirmMsg", + msgChannelOpenFailure: "channelOpenFailureMsg", + msgChannelWindowAdjust: "windowAdjustMsg", + msgChannelEOF: "channelEOFMsg", + msgChannelClose: "channelCloseMsg", + msgChannelRequest: "channelRequestMsg", + msgChannelSuccess: "channelRequestSuccessMsg", + msgChannelFailure: "channelRequestFailureMsg", +} diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go new file mode 100644 index 00000000..9654c018 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mux.go @@ -0,0 +1,351 @@ +// 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 ssh + +import ( + "encoding/binary" + "fmt" + "io" + "log" + "sync" + "sync/atomic" +) + +// debugMux, if set, causes messages in the connection protocol to be +// logged. +const debugMux = false + +// chanList is a thread safe channel list. +type chanList struct { + // protects concurrent access to chans + sync.Mutex + + // chans are indexed by the local id of the channel, which the + // other side should send in the PeersId field. + chans []*channel + + // This is a debugging aid: it offsets all IDs by this + // amount. This helps distinguish otherwise identical + // server/client muxes + offset uint32 +} + +// Assigns a channel ID to the given channel. +func (c *chanList) add(ch *channel) uint32 { + c.Lock() + defer c.Unlock() + for i := range c.chans { + if c.chans[i] == nil { + c.chans[i] = ch + return uint32(i) + c.offset + } + } + c.chans = append(c.chans, ch) + return uint32(len(c.chans)-1) + c.offset +} + +// getChan returns the channel for the given ID. +func (c *chanList) getChan(id uint32) *channel { + id -= c.offset + + c.Lock() + defer c.Unlock() + if id < uint32(len(c.chans)) { + return c.chans[id] + } + return nil +} + +func (c *chanList) remove(id uint32) { + id -= c.offset + c.Lock() + if id < uint32(len(c.chans)) { + c.chans[id] = nil + } + c.Unlock() +} + +// dropAll forgets all channels it knows, returning them in a slice. +func (c *chanList) dropAll() []*channel { + c.Lock() + defer c.Unlock() + var r []*channel + + for _, ch := range c.chans { + if ch == nil { + continue + } + r = append(r, ch) + } + c.chans = nil + return r +} + +// mux represents the state for the SSH connection protocol, which +// multiplexes many channels onto a single packet transport. +type mux struct { + conn packetConn + chanList chanList + + incomingChannels chan NewChannel + + globalSentMu sync.Mutex + globalResponses chan interface{} + incomingRequests chan *Request + + errCond *sync.Cond + err error +} + +// When debugging, each new chanList instantiation has a different +// offset. +var globalOff uint32 + +func (m *mux) Wait() error { + m.errCond.L.Lock() + defer m.errCond.L.Unlock() + for m.err == nil { + m.errCond.Wait() + } + return m.err +} + +// newMux returns a mux that runs over the given connection. +func newMux(p packetConn) *mux { + m := &mux{ + conn: p, + incomingChannels: make(chan NewChannel, chanSize), + globalResponses: make(chan interface{}, 1), + incomingRequests: make(chan *Request, chanSize), + errCond: newCond(), + } + if debugMux { + m.chanList.offset = atomic.AddUint32(&globalOff, 1) + } + + go m.loop() + return m +} + +func (m *mux) sendMessage(msg interface{}) error { + p := Marshal(msg) + if debugMux { + log.Printf("send global(%d): %#v", m.chanList.offset, msg) + } + return m.conn.writePacket(p) +} + +func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { + if wantReply { + m.globalSentMu.Lock() + defer m.globalSentMu.Unlock() + } + + if err := m.sendMessage(globalRequestMsg{ + Type: name, + WantReply: wantReply, + Data: payload, + }); err != nil { + return false, nil, err + } + + if !wantReply { + return false, nil, nil + } + + msg, ok := <-m.globalResponses + if !ok { + return false, nil, io.EOF + } + switch msg := msg.(type) { + case *globalRequestFailureMsg: + return false, msg.Data, nil + case *globalRequestSuccessMsg: + return true, msg.Data, nil + default: + return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) + } +} + +// ackRequest must be called after processing a global request that +// has WantReply set. +func (m *mux) ackRequest(ok bool, data []byte) error { + if ok { + return m.sendMessage(globalRequestSuccessMsg{Data: data}) + } + return m.sendMessage(globalRequestFailureMsg{Data: data}) +} + +func (m *mux) Close() error { + return m.conn.Close() +} + +// loop runs the connection machine. It will process packets until an +// error is encountered. To synchronize on loop exit, use mux.Wait. +func (m *mux) loop() { + var err error + for err == nil { + err = m.onePacket() + } + + for _, ch := range m.chanList.dropAll() { + ch.close() + } + + close(m.incomingChannels) + close(m.incomingRequests) + close(m.globalResponses) + + m.conn.Close() + + m.errCond.L.Lock() + m.err = err + m.errCond.Broadcast() + m.errCond.L.Unlock() + + if debugMux { + log.Println("loop exit", err) + } +} + +// onePacket reads and processes one packet. +func (m *mux) onePacket() error { + packet, err := m.conn.readPacket() + if err != nil { + return err + } + + if debugMux { + if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { + log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) + } else { + p, _ := decode(packet) + log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) + } + } + + switch packet[0] { + case msgChannelOpen: + return m.handleChannelOpen(packet) + case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: + return m.handleGlobalPacket(packet) + } + + // assume a channel packet. + if len(packet) < 5 { + return parseError(packet[0]) + } + id := binary.BigEndian.Uint32(packet[1:]) + ch := m.chanList.getChan(id) + if ch == nil { + return m.handleUnknownChannelPacket(id, packet) + } + + return ch.handlePacket(packet) +} + +func (m *mux) handleGlobalPacket(packet []byte) error { + msg, err := decode(packet) + if err != nil { + return err + } + + switch msg := msg.(type) { + case *globalRequestMsg: + m.incomingRequests <- &Request{ + Type: msg.Type, + WantReply: msg.WantReply, + Payload: msg.Data, + mux: m, + } + case *globalRequestSuccessMsg, *globalRequestFailureMsg: + m.globalResponses <- msg + default: + panic(fmt.Sprintf("not a global message %#v", msg)) + } + + return nil +} + +// handleChannelOpen schedules a channel to be Accept()ed. +func (m *mux) handleChannelOpen(packet []byte) error { + var msg channelOpenMsg + if err := Unmarshal(packet, &msg); err != nil { + return err + } + + if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { + failMsg := channelOpenFailureMsg{ + PeersID: msg.PeersID, + Reason: ConnectionFailed, + Message: "invalid request", + Language: "en_US.UTF-8", + } + return m.sendMessage(failMsg) + } + + c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) + c.remoteId = msg.PeersID + c.maxRemotePayload = msg.MaxPacketSize + c.remoteWin.add(msg.PeersWindow) + m.incomingChannels <- c + return nil +} + +func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { + ch, err := m.openChannel(chanType, extra) + if err != nil { + return nil, nil, err + } + + return ch, ch.incomingRequests, nil +} + +func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { + ch := m.newChannel(chanType, channelOutbound, extra) + + ch.maxIncomingPayload = channelMaxPacket + + open := channelOpenMsg{ + ChanType: chanType, + PeersWindow: ch.myWindow, + MaxPacketSize: ch.maxIncomingPayload, + TypeSpecificData: extra, + PeersID: ch.localId, + } + if err := m.sendMessage(open); err != nil { + return nil, err + } + + switch msg := (<-ch.msg).(type) { + case *channelOpenConfirmMsg: + return ch, nil + case *channelOpenFailureMsg: + return nil, &OpenChannelError{msg.Reason, msg.Message} + default: + return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) + } +} + +func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) error { + msg, err := decode(packet) + if err != nil { + return err + } + + switch msg := msg.(type) { + // RFC 4254 section 5.4 says unrecognized channel requests should + // receive a failure response. + case *channelRequestMsg: + if msg.WantReply { + return m.sendMessage(channelRequestFailureMsg{ + PeersID: msg.PeersID, + }) + } + return nil + default: + return fmt.Errorf("ssh: invalid channel %d", id) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go new file mode 100644 index 00000000..70045bdf --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -0,0 +1,752 @@ +// 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 ssh + +import ( + "bytes" + "errors" + "fmt" + "io" + "net" + "strings" +) + +// The Permissions type holds fine-grained permissions that are +// specific to a user or a specific authentication method for a user. +// The Permissions value for a successful authentication attempt is +// available in ServerConn, so it can be used to pass information from +// the user-authentication phase to the application layer. +type Permissions struct { + // CriticalOptions indicate restrictions to the default + // permissions, and are typically used in conjunction with + // user certificates. The standard for SSH certificates + // defines "force-command" (only allow the given command to + // execute) and "source-address" (only allow connections from + // the given address). The SSH package currently only enforces + // the "source-address" critical option. It is up to server + // implementations to enforce other critical options, such as + // "force-command", by checking them after the SSH handshake + // is successful. In general, SSH servers should reject + // connections that specify critical options that are unknown + // or not supported. + CriticalOptions map[string]string + + // Extensions are extra functionality that the server may + // offer on authenticated connections. Lack of support for an + // extension does not preclude authenticating a user. Common + // extensions are "permit-agent-forwarding", + // "permit-X11-forwarding". The Go SSH library currently does + // not act on any extension, and it is up to server + // implementations to honor them. Extensions can be used to + // pass data from the authentication callbacks to the server + // application layer. + Extensions map[string]string +} + +type GSSAPIWithMICConfig struct { + // AllowLogin, must be set, is called when gssapi-with-mic + // authentication is selected (RFC 4462 section 3). The srcName is from the + // results of the GSS-API authentication. The format is username@DOMAIN. + // GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions. + // This callback is called after the user identity is established with GSSAPI to decide if the user can login with + // which permissions. If the user is allowed to login, it should return a nil error. + AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error) + + // Server must be set. It's the implementation + // of the GSSAPIServer interface. See GSSAPIServer interface for details. + Server GSSAPIServer +} + +// ServerConfig holds server specific configuration data. +type ServerConfig struct { + // Config contains configuration shared between client and server. + Config + + hostKeys []Signer + + // NoClientAuth is true if clients are allowed to connect without + // authenticating. + NoClientAuth bool + + // MaxAuthTries specifies the maximum number of authentication attempts + // permitted per connection. If set to a negative number, the number of + // attempts are unlimited. If set to zero, the number of attempts are limited + // to 6. + MaxAuthTries int + + // PasswordCallback, if non-nil, is called when a user + // attempts to authenticate using a password. + PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) + + // PublicKeyCallback, if non-nil, is called when a client + // offers a public key for authentication. It must return a nil error + // if the given public key can be used to authenticate the + // given user. For example, see CertChecker.Authenticate. A + // call to this function does not guarantee that the key + // offered is in fact used to authenticate. To record any data + // depending on the public key, store it inside a + // Permissions.Extensions entry. + PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) + + // KeyboardInteractiveCallback, if non-nil, is called when + // keyboard-interactive authentication is selected (RFC + // 4256). The client object's Challenge function should be + // used to query the user. The callback may offer multiple + // Challenge rounds. To avoid information leaks, the client + // should be presented a challenge even if the user is + // unknown. + KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) + + // AuthLogCallback, if non-nil, is called to log all authentication + // attempts. + AuthLogCallback func(conn ConnMetadata, method string, err error) + + // ServerVersion is the version identification string to announce in + // the public handshake. + // If empty, a reasonable default is used. + // Note that RFC 4253 section 4.2 requires that this string start with + // "SSH-2.0-". + ServerVersion string + + // BannerCallback, if present, is called and the return string is sent to + // the client after key exchange completed but before authentication. + BannerCallback func(conn ConnMetadata) string + + // GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used + // when gssapi-with-mic authentication is selected (RFC 4462 section 3). + GSSAPIWithMICConfig *GSSAPIWithMICConfig +} + +// AddHostKey adds a private key as a host key. If an existing host +// key exists with the same public key format, it is replaced. Each server +// config must have at least one host key. +func (s *ServerConfig) AddHostKey(key Signer) { + for i, k := range s.hostKeys { + if k.PublicKey().Type() == key.PublicKey().Type() { + s.hostKeys[i] = key + return + } + } + + s.hostKeys = append(s.hostKeys, key) +} + +// cachedPubKey contains the results of querying whether a public key is +// acceptable for a user. +type cachedPubKey struct { + user string + pubKeyData []byte + result error + perms *Permissions +} + +const maxCachedPubKeys = 16 + +// pubKeyCache caches tests for public keys. Since SSH clients +// will query whether a public key is acceptable before attempting to +// authenticate with it, we end up with duplicate queries for public +// key validity. The cache only applies to a single ServerConn. +type pubKeyCache struct { + keys []cachedPubKey +} + +// get returns the result for a given user/algo/key tuple. +func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { + for _, k := range c.keys { + if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { + return k, true + } + } + return cachedPubKey{}, false +} + +// add adds the given tuple to the cache. +func (c *pubKeyCache) add(candidate cachedPubKey) { + if len(c.keys) < maxCachedPubKeys { + c.keys = append(c.keys, candidate) + } +} + +// ServerConn is an authenticated SSH connection, as seen from the +// server +type ServerConn struct { + Conn + + // If the succeeding authentication callback returned a + // non-nil Permissions pointer, it is stored here. + Permissions *Permissions +} + +// NewServerConn starts a new SSH server with c as the underlying +// transport. It starts with a handshake and, if the handshake is +// unsuccessful, it closes the connection and returns an error. The +// Request and NewChannel channels must be serviced, or the connection +// will hang. +// +// The returned error may be of type *ServerAuthError for +// authentication errors. +func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { + fullConf := *config + fullConf.SetDefaults() + if fullConf.MaxAuthTries == 0 { + fullConf.MaxAuthTries = 6 + } + // Check if the config contains any unsupported key exchanges + for _, kex := range fullConf.KeyExchanges { + if _, ok := serverForbiddenKexAlgos[kex]; ok { + return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex) + } + } + + s := &connection{ + sshConn: sshConn{conn: c}, + } + perms, err := s.serverHandshake(&fullConf) + if err != nil { + c.Close() + return nil, nil, nil, err + } + return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil +} + +// signAndMarshal signs the data with the appropriate algorithm, +// and serializes the result in SSH wire format. algo is the negotiate +// algorithm and may be a certificate type. +func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) { + sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo)) + if err != nil { + return nil, err + } + + return Marshal(sig), nil +} + +// handshake performs key exchange and user authentication. +func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { + if len(config.hostKeys) == 0 { + return nil, errors.New("ssh: server has no host keys") + } + + if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && + config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil || + config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) { + return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") + } + + if config.ServerVersion != "" { + s.serverVersion = []byte(config.ServerVersion) + } else { + s.serverVersion = []byte(packageVersion) + } + var err error + s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) + if err != nil { + return nil, err + } + + tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) + s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) + + if err := s.transport.waitSession(); err != nil { + return nil, err + } + + // We just did the key change, so the session ID is established. + s.sessionID = s.transport.getSessionID() + + var packet []byte + if packet, err = s.transport.readPacket(); err != nil { + return nil, err + } + + var serviceRequest serviceRequestMsg + if err = Unmarshal(packet, &serviceRequest); err != nil { + return nil, err + } + if serviceRequest.Service != serviceUserAuth { + return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") + } + serviceAccept := serviceAcceptMsg{ + Service: serviceUserAuth, + } + if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { + return nil, err + } + + perms, err := s.serverAuthenticate(config) + if err != nil { + return nil, err + } + s.mux = newMux(s.transport) + return perms, err +} + +func isAcceptableAlgo(algo string) bool { + switch algo { + case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519, + CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: + return true + } + return false +} + +func checkSourceAddress(addr net.Addr, sourceAddrs string) error { + if addr == nil { + return errors.New("ssh: no address known for client, but source-address match required") + } + + tcpAddr, ok := addr.(*net.TCPAddr) + if !ok { + return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) + } + + for _, sourceAddr := range strings.Split(sourceAddrs, ",") { + if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { + if allowedIP.Equal(tcpAddr.IP) { + return nil + } + } else { + _, ipNet, err := net.ParseCIDR(sourceAddr) + if err != nil { + return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) + } + + if ipNet.Contains(tcpAddr.IP) { + return nil + } + } + } + + return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) +} + +func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection, + sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) { + gssAPIServer := gssapiConfig.Server + defer gssAPIServer.DeleteSecContext() + var srcName string + for { + var ( + outToken []byte + needContinue bool + ) + outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken) + if err != nil { + return err, nil, nil + } + if len(outToken) != 0 { + if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{ + Token: outToken, + })); err != nil { + return nil, nil, err + } + } + if !needContinue { + break + } + packet, err := s.transport.readPacket() + if err != nil { + return nil, nil, err + } + userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} + if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { + return nil, nil, err + } + } + packet, err := s.transport.readPacket() + if err != nil { + return nil, nil, err + } + userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{} + if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil { + return nil, nil, err + } + mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method) + if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil { + return err, nil, nil + } + perms, authErr = gssapiConfig.AllowLogin(s, srcName) + return authErr, perms, nil +} + +// ServerAuthError represents server authentication errors and is +// sometimes returned by NewServerConn. It appends any authentication +// errors that may occur, and is returned if all of the authentication +// methods provided by the user failed to authenticate. +type ServerAuthError struct { + // Errors contains authentication errors returned by the authentication + // callback methods. The first entry is typically ErrNoAuth. + Errors []error +} + +func (l ServerAuthError) Error() string { + var errs []string + for _, err := range l.Errors { + errs = append(errs, err.Error()) + } + return "[" + strings.Join(errs, ", ") + "]" +} + +// ErrNoAuth is the error value returned if no +// authentication method has been passed yet. This happens as a normal +// part of the authentication loop, since the client first tries +// 'none' authentication to discover available methods. +// It is returned in ServerAuthError.Errors from NewServerConn. +var ErrNoAuth = errors.New("ssh: no auth passed yet") + +func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { + sessionID := s.transport.getSessionID() + var cache pubKeyCache + var perms *Permissions + + authFailures := 0 + var authErrs []error + var displayedBanner bool + +userAuthLoop: + for { + if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { + discMsg := &disconnectMsg{ + Reason: 2, + Message: "too many authentication failures", + } + + if err := s.transport.writePacket(Marshal(discMsg)); err != nil { + return nil, err + } + + return nil, discMsg + } + + var userAuthReq userAuthRequestMsg + if packet, err := s.transport.readPacket(); err != nil { + if err == io.EOF { + return nil, &ServerAuthError{Errors: authErrs} + } + return nil, err + } else if err = Unmarshal(packet, &userAuthReq); err != nil { + return nil, err + } + + if userAuthReq.Service != serviceSSH { + return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) + } + + s.user = userAuthReq.User + + if !displayedBanner && config.BannerCallback != nil { + displayedBanner = true + msg := config.BannerCallback(s) + if msg != "" { + bannerMsg := &userAuthBannerMsg{ + Message: msg, + } + if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil { + return nil, err + } + } + } + + perms = nil + authErr := ErrNoAuth + + switch userAuthReq.Method { + case "none": + if config.NoClientAuth { + authErr = nil + } + + // allow initial attempt of 'none' without penalty + if authFailures == 0 { + authFailures-- + } + case "password": + if config.PasswordCallback == nil { + authErr = errors.New("ssh: password auth not configured") + break + } + payload := userAuthReq.Payload + if len(payload) < 1 || payload[0] != 0 { + return nil, parseError(msgUserAuthRequest) + } + payload = payload[1:] + password, payload, ok := parseString(payload) + if !ok || len(payload) > 0 { + return nil, parseError(msgUserAuthRequest) + } + + perms, authErr = config.PasswordCallback(s, password) + case "keyboard-interactive": + if config.KeyboardInteractiveCallback == nil { + authErr = errors.New("ssh: keyboard-interactive auth not configured") + break + } + + prompter := &sshClientKeyboardInteractive{s} + perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) + case "publickey": + if config.PublicKeyCallback == nil { + authErr = errors.New("ssh: publickey auth not configured") + break + } + payload := userAuthReq.Payload + if len(payload) < 1 { + return nil, parseError(msgUserAuthRequest) + } + isQuery := payload[0] == 0 + payload = payload[1:] + algoBytes, payload, ok := parseString(payload) + if !ok { + return nil, parseError(msgUserAuthRequest) + } + algo := string(algoBytes) + if !isAcceptableAlgo(algo) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) + break + } + + pubKeyData, payload, ok := parseString(payload) + if !ok { + return nil, parseError(msgUserAuthRequest) + } + + pubKey, err := ParsePublicKey(pubKeyData) + if err != nil { + return nil, err + } + + candidate, ok := cache.get(s.user, pubKeyData) + if !ok { + candidate.user = s.user + candidate.pubKeyData = pubKeyData + candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) + if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { + candidate.result = checkSourceAddress( + s.RemoteAddr(), + candidate.perms.CriticalOptions[sourceAddressCriticalOption]) + } + cache.add(candidate) + } + + if isQuery { + // The client can query if the given public key + // would be okay. + + if len(payload) > 0 { + return nil, parseError(msgUserAuthRequest) + } + + if candidate.result == nil { + okMsg := userAuthPubKeyOkMsg{ + Algo: algo, + PubKey: pubKeyData, + } + if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { + return nil, err + } + continue userAuthLoop + } + authErr = candidate.result + } else { + sig, payload, ok := parseSignature(payload) + if !ok || len(payload) > 0 { + return nil, parseError(msgUserAuthRequest) + } + + // Ensure the public key algo and signature algo + // are supported. Compare the private key + // algorithm name that corresponds to algo with + // sig.Format. This is usually the same, but + // for certs, the names differ. + if !isAcceptableAlgo(sig.Format) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) + break + } + if underlyingAlgo(algo) != sig.Format { + authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo) + break + } + + signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData) + + if err := pubKey.Verify(signedData, sig); err != nil { + return nil, err + } + + authErr = candidate.result + perms = candidate.perms + } + case "gssapi-with-mic": + if config.GSSAPIWithMICConfig == nil { + authErr = errors.New("ssh: gssapi-with-mic auth not configured") + break + } + gssapiConfig := config.GSSAPIWithMICConfig + userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload) + if err != nil { + return nil, parseError(msgUserAuthRequest) + } + // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication. + if userAuthRequestGSSAPI.N == 0 { + authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported") + break + } + var i uint32 + present := false + for i = 0; i < userAuthRequestGSSAPI.N; i++ { + if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) { + present = true + break + } + } + if !present { + authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism") + break + } + // Initial server response, see RFC 4462 section 3.3. + if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{ + SupportMech: krb5OID, + })); err != nil { + return nil, err + } + // Exchange token, see RFC 4462 section 3.4. + packet, err := s.transport.readPacket() + if err != nil { + return nil, err + } + userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} + if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { + return nil, err + } + authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID, + userAuthReq) + if err != nil { + return nil, err + } + default: + authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) + } + + authErrs = append(authErrs, authErr) + + if config.AuthLogCallback != nil { + config.AuthLogCallback(s, userAuthReq.Method, authErr) + } + + if authErr == nil { + break userAuthLoop + } + + authFailures++ + if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries { + // If we have hit the max attempts, don't bother sending the + // final SSH_MSG_USERAUTH_FAILURE message, since there are + // no more authentication methods which can be attempted, + // and this message may cause the client to re-attempt + // authentication while we send the disconnect message. + // Continue, and trigger the disconnect at the start of + // the loop. + // + // The SSH specification is somewhat confusing about this, + // RFC 4252 Section 5.1 requires each authentication failure + // be responded to with a respective SSH_MSG_USERAUTH_FAILURE + // message, but Section 4 says the server should disconnect + // after some number of attempts, but it isn't explicit which + // message should take precedence (i.e. should there be a failure + // message than a disconnect message, or if we are going to + // disconnect, should we only send that message.) + // + // Either way, OpenSSH disconnects immediately after the last + // failed authnetication attempt, and given they are typically + // considered the golden implementation it seems reasonable + // to match that behavior. + continue + } + + var failureMsg userAuthFailureMsg + if config.PasswordCallback != nil { + failureMsg.Methods = append(failureMsg.Methods, "password") + } + if config.PublicKeyCallback != nil { + failureMsg.Methods = append(failureMsg.Methods, "publickey") + } + if config.KeyboardInteractiveCallback != nil { + failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") + } + if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil && + config.GSSAPIWithMICConfig.AllowLogin != nil { + failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic") + } + + if len(failureMsg.Methods) == 0 { + return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") + } + + if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { + return nil, err + } + } + + if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { + return nil, err + } + return perms, nil +} + +// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by +// asking the client on the other side of a ServerConn. +type sshClientKeyboardInteractive struct { + *connection +} + +func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) { + if len(questions) != len(echos) { + return nil, errors.New("ssh: echos and questions must have equal length") + } + + var prompts []byte + for i := range questions { + prompts = appendString(prompts, questions[i]) + prompts = appendBool(prompts, echos[i]) + } + + if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ + Name: name, + Instruction: instruction, + NumPrompts: uint32(len(questions)), + Prompts: prompts, + })); err != nil { + return nil, err + } + + packet, err := c.transport.readPacket() + if err != nil { + return nil, err + } + if packet[0] != msgUserAuthInfoResponse { + return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) + } + packet = packet[1:] + + n, packet, ok := parseUint32(packet) + if !ok || int(n) != len(questions) { + return nil, parseError(msgUserAuthInfoResponse) + } + + for i := uint32(0); i < n; i++ { + ans, rest, ok := parseString(packet) + if !ok { + return nil, parseError(msgUserAuthInfoResponse) + } + + answers = append(answers, string(ans)) + packet = rest + } + if len(packet) != 0 { + return nil, errors.New("ssh: junk at end of message") + } + + return answers, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go new file mode 100644 index 00000000..eca31a22 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/session.go @@ -0,0 +1,648 @@ +// 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 ssh + +// Session implements an interactive session described in +// "RFC 4254, section 6". + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "sync" +) + +type Signal string + +// POSIX signals as listed in RFC 4254 Section 6.10. +const ( + SIGABRT Signal = "ABRT" + SIGALRM Signal = "ALRM" + SIGFPE Signal = "FPE" + SIGHUP Signal = "HUP" + SIGILL Signal = "ILL" + SIGINT Signal = "INT" + SIGKILL Signal = "KILL" + SIGPIPE Signal = "PIPE" + SIGQUIT Signal = "QUIT" + SIGSEGV Signal = "SEGV" + SIGTERM Signal = "TERM" + SIGUSR1 Signal = "USR1" + SIGUSR2 Signal = "USR2" +) + +var signals = map[Signal]int{ + SIGABRT: 6, + SIGALRM: 14, + SIGFPE: 8, + SIGHUP: 1, + SIGILL: 4, + SIGINT: 2, + SIGKILL: 9, + SIGPIPE: 13, + SIGQUIT: 3, + SIGSEGV: 11, + SIGTERM: 15, +} + +type TerminalModes map[uint8]uint32 + +// POSIX terminal mode flags as listed in RFC 4254 Section 8. +const ( + tty_OP_END = 0 + VINTR = 1 + VQUIT = 2 + VERASE = 3 + VKILL = 4 + VEOF = 5 + VEOL = 6 + VEOL2 = 7 + VSTART = 8 + VSTOP = 9 + VSUSP = 10 + VDSUSP = 11 + VREPRINT = 12 + VWERASE = 13 + VLNEXT = 14 + VFLUSH = 15 + VSWTCH = 16 + VSTATUS = 17 + VDISCARD = 18 + IGNPAR = 30 + PARMRK = 31 + INPCK = 32 + ISTRIP = 33 + INLCR = 34 + IGNCR = 35 + ICRNL = 36 + IUCLC = 37 + IXON = 38 + IXANY = 39 + IXOFF = 40 + IMAXBEL = 41 + IUTF8 = 42 // RFC 8160 + ISIG = 50 + ICANON = 51 + XCASE = 52 + ECHO = 53 + ECHOE = 54 + ECHOK = 55 + ECHONL = 56 + NOFLSH = 57 + TOSTOP = 58 + IEXTEN = 59 + ECHOCTL = 60 + ECHOKE = 61 + PENDIN = 62 + OPOST = 70 + OLCUC = 71 + ONLCR = 72 + OCRNL = 73 + ONOCR = 74 + ONLRET = 75 + CS7 = 90 + CS8 = 91 + PARENB = 92 + PARODD = 93 + TTY_OP_ISPEED = 128 + TTY_OP_OSPEED = 129 +) + +// A Session represents a connection to a remote command or shell. +type Session struct { + // Stdin specifies the remote process's standard input. + // If Stdin is nil, the remote process reads from an empty + // bytes.Buffer. + Stdin io.Reader + + // Stdout and Stderr specify the remote process's standard + // output and error. + // + // If either is nil, Run connects the corresponding file + // descriptor to an instance of ioutil.Discard. There is a + // fixed amount of buffering that is shared for the two streams. + // If either blocks it may eventually cause the remote + // command to block. + Stdout io.Writer + Stderr io.Writer + + ch Channel // the channel backing this session + started bool // true once Start, Run or Shell is invoked. + copyFuncs []func() error + errors chan error // one send per copyFunc + + // true if pipe method is active + stdinpipe, stdoutpipe, stderrpipe bool + + // stdinPipeWriter is non-nil if StdinPipe has not been called + // and Stdin was specified by the user; it is the write end of + // a pipe connecting Session.Stdin to the stdin channel. + stdinPipeWriter io.WriteCloser + + exitStatus chan error +} + +// SendRequest sends an out-of-band channel request on the SSH channel +// underlying the session. +func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { + return s.ch.SendRequest(name, wantReply, payload) +} + +func (s *Session) Close() error { + return s.ch.Close() +} + +// RFC 4254 Section 6.4. +type setenvRequest struct { + Name string + Value string +} + +// Setenv sets an environment variable that will be applied to any +// command executed by Shell or Run. +func (s *Session) Setenv(name, value string) error { + msg := setenvRequest{ + Name: name, + Value: value, + } + ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) + if err == nil && !ok { + err = errors.New("ssh: setenv failed") + } + return err +} + +// RFC 4254 Section 6.2. +type ptyRequestMsg struct { + Term string + Columns uint32 + Rows uint32 + Width uint32 + Height uint32 + Modelist string +} + +// RequestPty requests the association of a pty with the session on the remote host. +func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { + var tm []byte + for k, v := range termmodes { + kv := struct { + Key byte + Val uint32 + }{k, v} + + tm = append(tm, Marshal(&kv)...) + } + tm = append(tm, tty_OP_END) + req := ptyRequestMsg{ + Term: term, + Columns: uint32(w), + Rows: uint32(h), + Width: uint32(w * 8), + Height: uint32(h * 8), + Modelist: string(tm), + } + ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) + if err == nil && !ok { + err = errors.New("ssh: pty-req failed") + } + return err +} + +// RFC 4254 Section 6.5. +type subsystemRequestMsg struct { + Subsystem string +} + +// RequestSubsystem requests the association of a subsystem with the session on the remote host. +// A subsystem is a predefined command that runs in the background when the ssh session is initiated +func (s *Session) RequestSubsystem(subsystem string) error { + msg := subsystemRequestMsg{ + Subsystem: subsystem, + } + ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) + if err == nil && !ok { + err = errors.New("ssh: subsystem request failed") + } + return err +} + +// RFC 4254 Section 6.7. +type ptyWindowChangeMsg struct { + Columns uint32 + Rows uint32 + Width uint32 + Height uint32 +} + +// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. +func (s *Session) WindowChange(h, w int) error { + req := ptyWindowChangeMsg{ + Columns: uint32(w), + Rows: uint32(h), + Width: uint32(w * 8), + Height: uint32(h * 8), + } + _, err := s.ch.SendRequest("window-change", false, Marshal(&req)) + return err +} + +// RFC 4254 Section 6.9. +type signalMsg struct { + Signal string +} + +// Signal sends the given signal to the remote process. +// sig is one of the SIG* constants. +func (s *Session) Signal(sig Signal) error { + msg := signalMsg{ + Signal: string(sig), + } + + _, err := s.ch.SendRequest("signal", false, Marshal(&msg)) + return err +} + +// RFC 4254 Section 6.5. +type execMsg struct { + Command string +} + +// Start runs cmd on the remote host. Typically, the remote +// server passes cmd to the shell for interpretation. +// A Session only accepts one call to Run, Start or Shell. +func (s *Session) Start(cmd string) error { + if s.started { + return errors.New("ssh: session already started") + } + req := execMsg{ + Command: cmd, + } + + ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) + if err == nil && !ok { + err = fmt.Errorf("ssh: command %v failed", cmd) + } + if err != nil { + return err + } + return s.start() +} + +// Run runs cmd on the remote host. Typically, the remote +// server passes cmd to the shell for interpretation. +// A Session only accepts one call to Run, Start, Shell, Output, +// or CombinedOutput. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the remote server does not send an exit status, an error of type +// *ExitMissingError is returned. If the command completes +// unsuccessfully or is interrupted by a signal, the error is of type +// *ExitError. Other error types may be returned for I/O problems. +func (s *Session) Run(cmd string) error { + err := s.Start(cmd) + if err != nil { + return err + } + return s.Wait() +} + +// Output runs cmd on the remote host and returns its standard output. +func (s *Session) Output(cmd string) ([]byte, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + var b bytes.Buffer + s.Stdout = &b + err := s.Run(cmd) + return b.Bytes(), err +} + +type singleWriter struct { + b bytes.Buffer + mu sync.Mutex +} + +func (w *singleWriter) Write(p []byte) (int, error) { + w.mu.Lock() + defer w.mu.Unlock() + return w.b.Write(p) +} + +// CombinedOutput runs cmd on the remote host and returns its combined +// standard output and standard error. +func (s *Session) CombinedOutput(cmd string) ([]byte, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + if s.Stderr != nil { + return nil, errors.New("ssh: Stderr already set") + } + var b singleWriter + s.Stdout = &b + s.Stderr = &b + err := s.Run(cmd) + return b.b.Bytes(), err +} + +// Shell starts a login shell on the remote host. A Session only +// accepts one call to Run, Start, Shell, Output, or CombinedOutput. +func (s *Session) Shell() error { + if s.started { + return errors.New("ssh: session already started") + } + + ok, err := s.ch.SendRequest("shell", true, nil) + if err == nil && !ok { + return errors.New("ssh: could not start shell") + } + if err != nil { + return err + } + return s.start() +} + +func (s *Session) start() error { + s.started = true + + type F func(*Session) + for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { + setupFd(s) + } + + s.errors = make(chan error, len(s.copyFuncs)) + for _, fn := range s.copyFuncs { + go func(fn func() error) { + s.errors <- fn() + }(fn) + } + return nil +} + +// Wait waits for the remote command to exit. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the remote server does not send an exit status, an error of type +// *ExitMissingError is returned. If the command completes +// unsuccessfully or is interrupted by a signal, the error is of type +// *ExitError. Other error types may be returned for I/O problems. +func (s *Session) Wait() error { + if !s.started { + return errors.New("ssh: session not started") + } + waitErr := <-s.exitStatus + + if s.stdinPipeWriter != nil { + s.stdinPipeWriter.Close() + } + var copyError error + for range s.copyFuncs { + if err := <-s.errors; err != nil && copyError == nil { + copyError = err + } + } + if waitErr != nil { + return waitErr + } + return copyError +} + +func (s *Session) wait(reqs <-chan *Request) error { + wm := Waitmsg{status: -1} + // Wait for msg channel to be closed before returning. + for msg := range reqs { + switch msg.Type { + case "exit-status": + wm.status = int(binary.BigEndian.Uint32(msg.Payload)) + case "exit-signal": + var sigval struct { + Signal string + CoreDumped bool + Error string + Lang string + } + if err := Unmarshal(msg.Payload, &sigval); err != nil { + return err + } + + // Must sanitize strings? + wm.signal = sigval.Signal + wm.msg = sigval.Error + wm.lang = sigval.Lang + default: + // This handles keepalives and matches + // OpenSSH's behaviour. + if msg.WantReply { + msg.Reply(false, nil) + } + } + } + if wm.status == 0 { + return nil + } + if wm.status == -1 { + // exit-status was never sent from server + if wm.signal == "" { + // signal was not sent either. RFC 4254 + // section 6.10 recommends against this + // behavior, but it is allowed, so we let + // clients handle it. + return &ExitMissingError{} + } + wm.status = 128 + if _, ok := signals[Signal(wm.signal)]; ok { + wm.status += signals[Signal(wm.signal)] + } + } + + return &ExitError{wm} +} + +// ExitMissingError is returned if a session is torn down cleanly, but +// the server sends no confirmation of the exit status. +type ExitMissingError struct{} + +func (e *ExitMissingError) Error() string { + return "wait: remote command exited without exit status or exit signal" +} + +func (s *Session) stdin() { + if s.stdinpipe { + return + } + var stdin io.Reader + if s.Stdin == nil { + stdin = new(bytes.Buffer) + } else { + r, w := io.Pipe() + go func() { + _, err := io.Copy(w, s.Stdin) + w.CloseWithError(err) + }() + stdin, s.stdinPipeWriter = r, w + } + s.copyFuncs = append(s.copyFuncs, func() error { + _, err := io.Copy(s.ch, stdin) + if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { + err = err1 + } + return err + }) +} + +func (s *Session) stdout() { + if s.stdoutpipe { + return + } + if s.Stdout == nil { + s.Stdout = ioutil.Discard + } + s.copyFuncs = append(s.copyFuncs, func() error { + _, err := io.Copy(s.Stdout, s.ch) + return err + }) +} + +func (s *Session) stderr() { + if s.stderrpipe { + return + } + if s.Stderr == nil { + s.Stderr = ioutil.Discard + } + s.copyFuncs = append(s.copyFuncs, func() error { + _, err := io.Copy(s.Stderr, s.ch.Stderr()) + return err + }) +} + +// sessionStdin reroutes Close to CloseWrite. +type sessionStdin struct { + io.Writer + ch Channel +} + +func (s *sessionStdin) Close() error { + return s.ch.CloseWrite() +} + +// StdinPipe returns a pipe that will be connected to the +// remote command's standard input when the command starts. +func (s *Session) StdinPipe() (io.WriteCloser, error) { + if s.Stdin != nil { + return nil, errors.New("ssh: Stdin already set") + } + if s.started { + return nil, errors.New("ssh: StdinPipe after process started") + } + s.stdinpipe = true + return &sessionStdin{s.ch, s.ch}, nil +} + +// StdoutPipe returns a pipe that will be connected to the +// remote command's standard output when the command starts. +// There is a fixed amount of buffering that is shared between +// stdout and stderr streams. If the StdoutPipe reader is +// not serviced fast enough it may eventually cause the +// remote command to block. +func (s *Session) StdoutPipe() (io.Reader, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + if s.started { + return nil, errors.New("ssh: StdoutPipe after process started") + } + s.stdoutpipe = true + return s.ch, nil +} + +// StderrPipe returns a pipe that will be connected to the +// remote command's standard error when the command starts. +// There is a fixed amount of buffering that is shared between +// stdout and stderr streams. If the StderrPipe reader is +// not serviced fast enough it may eventually cause the +// remote command to block. +func (s *Session) StderrPipe() (io.Reader, error) { + if s.Stderr != nil { + return nil, errors.New("ssh: Stderr already set") + } + if s.started { + return nil, errors.New("ssh: StderrPipe after process started") + } + s.stderrpipe = true + return s.ch.Stderr(), nil +} + +// newSession returns a new interactive session on the remote host. +func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { + s := &Session{ + ch: ch, + } + s.exitStatus = make(chan error, 1) + go func() { + s.exitStatus <- s.wait(reqs) + }() + + return s, nil +} + +// An ExitError reports unsuccessful completion of a remote command. +type ExitError struct { + Waitmsg +} + +func (e *ExitError) Error() string { + return e.Waitmsg.String() +} + +// Waitmsg stores the information about an exited remote command +// as reported by Wait. +type Waitmsg struct { + status int + signal string + msg string + lang string +} + +// ExitStatus returns the exit status of the remote command. +func (w Waitmsg) ExitStatus() int { + return w.status +} + +// Signal returns the exit signal of the remote command if +// it was terminated violently. +func (w Waitmsg) Signal() string { + return w.signal +} + +// Msg returns the exit message given by the remote command +func (w Waitmsg) Msg() string { + return w.msg +} + +// Lang returns the language tag. See RFC 3066 +func (w Waitmsg) Lang() string { + return w.lang +} + +func (w Waitmsg) String() string { + str := fmt.Sprintf("Process exited with status %v", w.status) + if w.signal != "" { + str += fmt.Sprintf(" from signal %v", w.signal) + } + if w.msg != "" { + str += fmt.Sprintf(". Reason was: %v", w.msg) + } + return str +} diff --git a/vendor/golang.org/x/crypto/ssh/ssh_gss.go b/vendor/golang.org/x/crypto/ssh/ssh_gss.go new file mode 100644 index 00000000..24bd7c8e --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/ssh_gss.go @@ -0,0 +1,139 @@ +// 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 ssh + +import ( + "encoding/asn1" + "errors" +) + +var krb5OID []byte + +func init() { + krb5OID, _ = asn1.Marshal(krb5Mesh) +} + +// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins. +type GSSAPIClient interface { + // InitSecContext initiates the establishment of a security context for GSS-API between the + // ssh client and ssh server. Initially the token parameter should be specified as nil. + // The routine may return a outputToken which should be transferred to + // the ssh server, where the ssh server will present it to + // AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting + // needContinue to false. To complete the context + // establishment, one or more reply tokens may be required from the ssh + // server;if so, InitSecContext will return a needContinue which is true. + // In this case, InitSecContext should be called again when the + // reply token is received from the ssh server, passing the reply + // token to InitSecContext via the token parameters. + // See RFC 2743 section 2.2.1 and RFC 4462 section 3.4. + InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error) + // GetMIC generates a cryptographic MIC for the SSH2 message, and places + // the MIC in a token for transfer to the ssh server. + // The contents of the MIC field are obtained by calling GSS_GetMIC() + // over the following, using the GSS-API context that was just + // established: + // string session identifier + // byte SSH_MSG_USERAUTH_REQUEST + // string user name + // string service + // string "gssapi-with-mic" + // See RFC 2743 section 2.3.1 and RFC 4462 3.5. + GetMIC(micFiled []byte) ([]byte, error) + // Whenever possible, it should be possible for + // DeleteSecContext() calls to be successfully processed even + // if other calls cannot succeed, thereby enabling context-related + // resources to be released. + // In addition to deleting established security contexts, + // gss_delete_sec_context must also be able to delete "half-built" + // security contexts resulting from an incomplete sequence of + // InitSecContext()/AcceptSecContext() calls. + // See RFC 2743 section 2.2.3. + DeleteSecContext() error +} + +// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins. +type GSSAPIServer interface { + // AcceptSecContext allows a remotely initiated security context between the application + // and a remote peer to be established by the ssh client. The routine may return a + // outputToken which should be transferred to the ssh client, + // where the ssh client will present it to InitSecContext. + // If no token need be sent, AcceptSecContext will indicate this + // by setting the needContinue to false. To + // complete the context establishment, one or more reply tokens may be + // required from the ssh client. if so, AcceptSecContext + // will return a needContinue which is true, in which case it + // should be called again when the reply token is received from the ssh + // client, passing the token to AcceptSecContext via the + // token parameters. + // The srcName return value is the authenticated username. + // See RFC 2743 section 2.2.2 and RFC 4462 section 3.4. + AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error) + // VerifyMIC verifies that a cryptographic MIC, contained in the token parameter, + // fits the supplied message is received from the ssh client. + // See RFC 2743 section 2.3.2. + VerifyMIC(micField []byte, micToken []byte) error + // Whenever possible, it should be possible for + // DeleteSecContext() calls to be successfully processed even + // if other calls cannot succeed, thereby enabling context-related + // resources to be released. + // In addition to deleting established security contexts, + // gss_delete_sec_context must also be able to delete "half-built" + // security contexts resulting from an incomplete sequence of + // InitSecContext()/AcceptSecContext() calls. + // See RFC 2743 section 2.2.3. + DeleteSecContext() error +} + +var ( + // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication, + // so we also support the krb5 mechanism only. + // See RFC 1964 section 1. + krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2} +) + +// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST +// See RFC 4462 section 3.2. +type userAuthRequestGSSAPI struct { + N uint32 + OIDS []asn1.ObjectIdentifier +} + +func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { + n, rest, ok := parseUint32(payload) + if !ok { + return nil, errors.New("parse uint32 failed") + } + s := &userAuthRequestGSSAPI{ + N: n, + OIDS: make([]asn1.ObjectIdentifier, n), + } + for i := 0; i < int(n); i++ { + var ( + desiredMech []byte + err error + ) + desiredMech, rest, ok = parseString(rest) + if !ok { + return nil, errors.New("parse string failed") + } + if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil { + return nil, err + } + + } + return s, nil +} + +// See RFC 4462 section 3.6. +func buildMIC(sessionID string, username string, service string, authMethod string) []byte { + out := make([]byte, 0, 0) + out = appendString(out, sessionID) + out = append(out, msgUserAuthRequest) + out = appendString(out, username) + out = appendString(out, service) + out = appendString(out, authMethod) + return out +} diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go new file mode 100644 index 00000000..b171b330 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go @@ -0,0 +1,116 @@ +package ssh + +import ( + "errors" + "io" + "net" +) + +// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message +// with "direct-streamlocal@openssh.com" string. +// +// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding +// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235 +type streamLocalChannelOpenDirectMsg struct { + socketPath string + reserved0 string + reserved1 uint32 +} + +// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message +// with "forwarded-streamlocal@openssh.com" string. +type forwardedStreamLocalPayload struct { + SocketPath string + Reserved0 string +} + +// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message +// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string. +type streamLocalChannelForwardMsg struct { + socketPath string +} + +// ListenUnix is similar to ListenTCP but uses a Unix domain socket. +func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) + m := streamLocalChannelForwardMsg{ + socketPath, + } + // send message + ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m)) + if err != nil { + return nil, err + } + if !ok { + return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") + } + ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) + + return &unixListener{socketPath, c, ch}, nil +} + +func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { + msg := streamLocalChannelOpenDirectMsg{ + socketPath: socketPath, + } + ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg)) + if err != nil { + return nil, err + } + go DiscardRequests(in) + return ch, err +} + +type unixListener struct { + socketPath string + + conn *Client + in <-chan forward +} + +// Accept waits for and returns the next connection to the listener. +func (l *unixListener) Accept() (net.Conn, error) { + s, ok := <-l.in + if !ok { + return nil, io.EOF + } + ch, incoming, err := s.newCh.Accept() + if err != nil { + return nil, err + } + go DiscardRequests(incoming) + + return &chanConn{ + Channel: ch, + laddr: &net.UnixAddr{ + Name: l.socketPath, + Net: "unix", + }, + raddr: &net.UnixAddr{ + Name: "@", + Net: "unix", + }, + }, nil +} + +// Close closes the listener. +func (l *unixListener) Close() error { + // this also closes the listener. + l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) + m := streamLocalChannelForwardMsg{ + l.socketPath, + } + ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m)) + if err == nil && !ok { + err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed") + } + return err +} + +// Addr returns the listener's network address. +func (l *unixListener) Addr() net.Addr { + return &net.UnixAddr{ + Name: l.socketPath, + Net: "unix", + } +} diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go new file mode 100644 index 00000000..80d35f5e --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/tcpip.go @@ -0,0 +1,474 @@ +// 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 ssh + +import ( + "errors" + "fmt" + "io" + "math/rand" + "net" + "strconv" + "strings" + "sync" + "time" +) + +// Listen requests the remote peer open a listening socket on +// addr. Incoming connections will be available by calling Accept on +// the returned net.Listener. The listener must be serviced, or the +// SSH connection may hang. +// N must be "tcp", "tcp4", "tcp6", or "unix". +func (c *Client) Listen(n, addr string) (net.Listener, error) { + switch n { + case "tcp", "tcp4", "tcp6": + laddr, err := net.ResolveTCPAddr(n, addr) + if err != nil { + return nil, err + } + return c.ListenTCP(laddr) + case "unix": + return c.ListenUnix(addr) + default: + return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) + } +} + +// Automatic port allocation is broken with OpenSSH before 6.0. See +// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In +// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, +// rather than the actual port number. This means you can never open +// two different listeners with auto allocated ports. We work around +// this by trying explicit ports until we succeed. + +const openSSHPrefix = "OpenSSH_" + +var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) + +// isBrokenOpenSSHVersion returns true if the given version string +// specifies a version of OpenSSH that is known to have a bug in port +// forwarding. +func isBrokenOpenSSHVersion(versionStr string) bool { + i := strings.Index(versionStr, openSSHPrefix) + if i < 0 { + return false + } + i += len(openSSHPrefix) + j := i + for ; j < len(versionStr); j++ { + if versionStr[j] < '0' || versionStr[j] > '9' { + break + } + } + version, _ := strconv.Atoi(versionStr[i:j]) + return version < 6 +} + +// autoPortListenWorkaround simulates automatic port allocation by +// trying random ports repeatedly. +func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { + var sshListener net.Listener + var err error + const tries = 10 + for i := 0; i < tries; i++ { + addr := *laddr + addr.Port = 1024 + portRandomizer.Intn(60000) + sshListener, err = c.ListenTCP(&addr) + if err == nil { + laddr.Port = addr.Port + return sshListener, err + } + } + return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) +} + +// RFC 4254 7.1 +type channelForwardMsg struct { + addr string + rport uint32 +} + +// handleForwards starts goroutines handling forwarded connections. +// It's called on first use by (*Client).ListenTCP to not launch +// goroutines until needed. +func (c *Client) handleForwards() { + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip")) + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com")) +} + +// ListenTCP requests the remote peer open a listening socket +// on laddr. Incoming connections will be available by calling +// Accept on the returned net.Listener. +func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) + if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { + return c.autoPortListenWorkaround(laddr) + } + + m := channelForwardMsg{ + laddr.IP.String(), + uint32(laddr.Port), + } + // send message + ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) + if err != nil { + return nil, err + } + if !ok { + return nil, errors.New("ssh: tcpip-forward request denied by peer") + } + + // If the original port was 0, then the remote side will + // supply a real port number in the response. + if laddr.Port == 0 { + var p struct { + Port uint32 + } + if err := Unmarshal(resp, &p); err != nil { + return nil, err + } + laddr.Port = int(p.Port) + } + + // Register this forward, using the port number we obtained. + ch := c.forwards.add(laddr) + + return &tcpListener{laddr, c, ch}, nil +} + +// forwardList stores a mapping between remote +// forward requests and the tcpListeners. +type forwardList struct { + sync.Mutex + entries []forwardEntry +} + +// forwardEntry represents an established mapping of a laddr on a +// remote ssh server to a channel connected to a tcpListener. +type forwardEntry struct { + laddr net.Addr + c chan forward +} + +// forward represents an incoming forwarded tcpip connection. The +// arguments to add/remove/lookup should be address as specified in +// the original forward-request. +type forward struct { + newCh NewChannel // the ssh client channel underlying this forward + raddr net.Addr // the raddr of the incoming connection +} + +func (l *forwardList) add(addr net.Addr) chan forward { + l.Lock() + defer l.Unlock() + f := forwardEntry{ + laddr: addr, + c: make(chan forward, 1), + } + l.entries = append(l.entries, f) + return f.c +} + +// See RFC 4254, section 7.2 +type forwardedTCPPayload struct { + Addr string + Port uint32 + OriginAddr string + OriginPort uint32 +} + +// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. +func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { + if port == 0 || port > 65535 { + return nil, fmt.Errorf("ssh: port number out of range: %d", port) + } + ip := net.ParseIP(string(addr)) + if ip == nil { + return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) + } + return &net.TCPAddr{IP: ip, Port: int(port)}, nil +} + +func (l *forwardList) handleChannels(in <-chan NewChannel) { + for ch := range in { + var ( + laddr net.Addr + raddr net.Addr + err error + ) + switch channelType := ch.ChannelType(); channelType { + case "forwarded-tcpip": + var payload forwardedTCPPayload + if err = Unmarshal(ch.ExtraData(), &payload); err != nil { + ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) + continue + } + + // RFC 4254 section 7.2 specifies that incoming + // addresses should list the address, in string + // format. It is implied that this should be an IP + // address, as it would be impossible to connect to it + // otherwise. + laddr, err = parseTCPAddr(payload.Addr, payload.Port) + if err != nil { + ch.Reject(ConnectionFailed, err.Error()) + continue + } + raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort) + if err != nil { + ch.Reject(ConnectionFailed, err.Error()) + continue + } + + case "forwarded-streamlocal@openssh.com": + var payload forwardedStreamLocalPayload + if err = Unmarshal(ch.ExtraData(), &payload); err != nil { + ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error()) + continue + } + laddr = &net.UnixAddr{ + Name: payload.SocketPath, + Net: "unix", + } + raddr = &net.UnixAddr{ + Name: "@", + Net: "unix", + } + default: + panic(fmt.Errorf("ssh: unknown channel type %s", channelType)) + } + if ok := l.forward(laddr, raddr, ch); !ok { + // Section 7.2, implementations MUST reject spurious incoming + // connections. + ch.Reject(Prohibited, "no forward for address") + continue + } + + } +} + +// remove removes the forward entry, and the channel feeding its +// listener. +func (l *forwardList) remove(addr net.Addr) { + l.Lock() + defer l.Unlock() + for i, f := range l.entries { + if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() { + l.entries = append(l.entries[:i], l.entries[i+1:]...) + close(f.c) + return + } + } +} + +// closeAll closes and clears all forwards. +func (l *forwardList) closeAll() { + l.Lock() + defer l.Unlock() + for _, f := range l.entries { + close(f.c) + } + l.entries = nil +} + +func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { + l.Lock() + defer l.Unlock() + for _, f := range l.entries { + if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() { + f.c <- forward{newCh: ch, raddr: raddr} + return true + } + } + return false +} + +type tcpListener struct { + laddr *net.TCPAddr + + conn *Client + in <-chan forward +} + +// Accept waits for and returns the next connection to the listener. +func (l *tcpListener) Accept() (net.Conn, error) { + s, ok := <-l.in + if !ok { + return nil, io.EOF + } + ch, incoming, err := s.newCh.Accept() + if err != nil { + return nil, err + } + go DiscardRequests(incoming) + + return &chanConn{ + Channel: ch, + laddr: l.laddr, + raddr: s.raddr, + }, nil +} + +// Close closes the listener. +func (l *tcpListener) Close() error { + m := channelForwardMsg{ + l.laddr.IP.String(), + uint32(l.laddr.Port), + } + + // this also closes the listener. + l.conn.forwards.remove(l.laddr) + ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) + if err == nil && !ok { + err = errors.New("ssh: cancel-tcpip-forward failed") + } + return err +} + +// Addr returns the listener's network address. +func (l *tcpListener) Addr() net.Addr { + return l.laddr +} + +// Dial initiates a connection to the addr from the remote host. +// The resulting connection has a zero LocalAddr() and RemoteAddr(). +func (c *Client) Dial(n, addr string) (net.Conn, error) { + var ch Channel + switch n { + case "tcp", "tcp4", "tcp6": + // Parse the address into host and numeric port. + host, portString, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + port, err := strconv.ParseUint(portString, 10, 16) + if err != nil { + return nil, err + } + ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port)) + if err != nil { + return nil, err + } + // Use a zero address for local and remote address. + zeroAddr := &net.TCPAddr{ + IP: net.IPv4zero, + Port: 0, + } + return &chanConn{ + Channel: ch, + laddr: zeroAddr, + raddr: zeroAddr, + }, nil + case "unix": + var err error + ch, err = c.dialStreamLocal(addr) + if err != nil { + return nil, err + } + return &chanConn{ + Channel: ch, + laddr: &net.UnixAddr{ + Name: "@", + Net: "unix", + }, + raddr: &net.UnixAddr{ + Name: addr, + Net: "unix", + }, + }, nil + default: + return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) + } +} + +// DialTCP connects to the remote address raddr on the network net, +// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used +// as the local address for the connection. +func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { + if laddr == nil { + laddr = &net.TCPAddr{ + IP: net.IPv4zero, + Port: 0, + } + } + ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) + if err != nil { + return nil, err + } + return &chanConn{ + Channel: ch, + laddr: laddr, + raddr: raddr, + }, nil +} + +// RFC 4254 7.2 +type channelOpenDirectMsg struct { + raddr string + rport uint32 + laddr string + lport uint32 +} + +func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { + msg := channelOpenDirectMsg{ + raddr: raddr, + rport: uint32(rport), + laddr: laddr, + lport: uint32(lport), + } + ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) + if err != nil { + return nil, err + } + go DiscardRequests(in) + return ch, err +} + +type tcpChan struct { + Channel // the backing channel +} + +// chanConn fulfills the net.Conn interface without +// the tcpChan having to hold laddr or raddr directly. +type chanConn struct { + Channel + laddr, raddr net.Addr +} + +// LocalAddr returns the local network address. +func (t *chanConn) LocalAddr() net.Addr { + return t.laddr +} + +// RemoteAddr returns the remote network address. +func (t *chanConn) RemoteAddr() net.Addr { + return t.raddr +} + +// SetDeadline sets the read and write deadlines associated +// with the connection. +func (t *chanConn) SetDeadline(deadline time.Time) error { + if err := t.SetReadDeadline(deadline); err != nil { + return err + } + return t.SetWriteDeadline(deadline) +} + +// SetReadDeadline sets the read deadline. +// A zero value for t means Read will not time out. +// After the deadline, the error from Read will implement net.Error +// with Timeout() == true. +func (t *chanConn) SetReadDeadline(deadline time.Time) error { + // for compatibility with previous version, + // the error message contains "tcpChan" + return errors.New("ssh: tcpChan: deadline not supported") +} + +// SetWriteDeadline exists to satisfy the net.Conn interface +// but is not implemented by this type. It always returns an error. +func (t *chanConn) SetWriteDeadline(deadline time.Time) error { + return errors.New("ssh: tcpChan: deadline not supported") +} diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go new file mode 100644 index 00000000..acf5a21b --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/transport.go @@ -0,0 +1,357 @@ +// 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 ssh + +import ( + "bufio" + "bytes" + "errors" + "io" + "log" +) + +// debugTransport if set, will print packet types as they go over the +// wire. No message decoding is done, to minimize the impact on timing. +const debugTransport = false + +const ( + gcmCipherID = "aes128-gcm@openssh.com" + aes128cbcID = "aes128-cbc" + tripledescbcID = "3des-cbc" +) + +// packetConn represents a transport that implements packet based +// operations. +type packetConn interface { + // Encrypt and send a packet of data to the remote peer. + writePacket(packet []byte) error + + // Read a packet from the connection. The read is blocking, + // i.e. if error is nil, then the returned byte slice is + // always non-empty. + readPacket() ([]byte, error) + + // Close closes the write-side of the connection. + Close() error +} + +// transport is the keyingTransport that implements the SSH packet +// protocol. +type transport struct { + reader connectionState + writer connectionState + + bufReader *bufio.Reader + bufWriter *bufio.Writer + rand io.Reader + isClient bool + io.Closer +} + +// packetCipher represents a combination of SSH encryption/MAC +// protocol. A single instance should be used for one direction only. +type packetCipher interface { + // writeCipherPacket encrypts the packet and writes it to w. The + // contents of the packet are generally scrambled. + writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error + + // readCipherPacket reads and decrypts a packet of data. The + // returned packet may be overwritten by future calls of + // readPacket. + readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error) +} + +// connectionState represents one side (read or write) of the +// connection. This is necessary because each direction has its own +// keys, and can even have its own algorithms +type connectionState struct { + packetCipher + seqNum uint32 + dir direction + pendingKeyChange chan packetCipher +} + +// prepareKeyChange sets up key material for a keychange. The key changes in +// both directions are triggered by reading and writing a msgNewKey packet +// respectively. +func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { + ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult) + if err != nil { + return err + } + t.reader.pendingKeyChange <- ciph + + ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult) + if err != nil { + return err + } + t.writer.pendingKeyChange <- ciph + + return nil +} + +func (t *transport) printPacket(p []byte, write bool) { + if len(p) == 0 { + return + } + who := "server" + if t.isClient { + who = "client" + } + what := "read" + if write { + what = "write" + } + + log.Println(what, who, p[0]) +} + +// Read and decrypt next packet. +func (t *transport) readPacket() (p []byte, err error) { + for { + p, err = t.reader.readPacket(t.bufReader) + if err != nil { + break + } + if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { + break + } + } + if debugTransport { + t.printPacket(p, false) + } + + return p, err +} + +func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { + packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) + s.seqNum++ + if err == nil && len(packet) == 0 { + err = errors.New("ssh: zero length packet") + } + + if len(packet) > 0 { + switch packet[0] { + case msgNewKeys: + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher + default: + return nil, errors.New("ssh: got bogus newkeys message") + } + + case msgDisconnect: + // Transform a disconnect message into an + // error. Since this is lowest level at which + // we interpret message types, doing it here + // ensures that we don't have to handle it + // elsewhere. + var msg disconnectMsg + if err := Unmarshal(packet, &msg); err != nil { + return nil, err + } + return nil, &msg + } + } + + // The packet may point to an internal buffer, so copy the + // packet out here. + fresh := make([]byte, len(packet)) + copy(fresh, packet) + + return fresh, err +} + +func (t *transport) writePacket(packet []byte) error { + if debugTransport { + t.printPacket(packet, true) + } + return t.writer.writePacket(t.bufWriter, t.rand, packet) +} + +func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { + changeKeys := len(packet) > 0 && packet[0] == msgNewKeys + + err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) + if err != nil { + return err + } + if err = w.Flush(); err != nil { + return err + } + s.seqNum++ + if changeKeys { + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher + default: + panic("ssh: no key material for msgNewKeys") + } + } + return err +} + +func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { + t := &transport{ + bufReader: bufio.NewReader(rwc), + bufWriter: bufio.NewWriter(rwc), + rand: rand, + reader: connectionState{ + packetCipher: &streamPacketCipher{cipher: noneCipher{}}, + pendingKeyChange: make(chan packetCipher, 1), + }, + writer: connectionState{ + packetCipher: &streamPacketCipher{cipher: noneCipher{}}, + pendingKeyChange: make(chan packetCipher, 1), + }, + Closer: rwc, + } + t.isClient = isClient + + if isClient { + t.reader.dir = serverKeys + t.writer.dir = clientKeys + } else { + t.reader.dir = clientKeys + t.writer.dir = serverKeys + } + + return t +} + +type direction struct { + ivTag []byte + keyTag []byte + macKeyTag []byte +} + +var ( + serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} + clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} +) + +// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as +// described in RFC 4253, section 6.4. direction should either be serverKeys +// (to setup server->client keys) or clientKeys (for client->server keys). +func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { + cipherMode := cipherModes[algs.Cipher] + + iv := make([]byte, cipherMode.ivSize) + key := make([]byte, cipherMode.keySize) + + generateKeyMaterial(iv, d.ivTag, kex) + generateKeyMaterial(key, d.keyTag, kex) + + var macKey []byte + if !aeadCiphers[algs.Cipher] { + macMode := macModes[algs.MAC] + macKey = make([]byte, macMode.keySize) + generateKeyMaterial(macKey, d.macKeyTag, kex) + } + + return cipherModes[algs.Cipher].create(key, iv, macKey, algs) +} + +// generateKeyMaterial fills out with key material generated from tag, K, H +// and sessionId, as specified in RFC 4253, section 7.2. +func generateKeyMaterial(out, tag []byte, r *kexResult) { + var digestsSoFar []byte + + h := r.Hash.New() + for len(out) > 0 { + h.Reset() + h.Write(r.K) + h.Write(r.H) + + if len(digestsSoFar) == 0 { + h.Write(tag) + h.Write(r.SessionID) + } else { + h.Write(digestsSoFar) + } + + digest := h.Sum(nil) + n := copy(out, digest) + out = out[n:] + if len(out) > 0 { + digestsSoFar = append(digestsSoFar, digest...) + } + } +} + +const packageVersion = "SSH-2.0-Go" + +// Sends and receives a version line. The versionLine string should +// be US ASCII, start with "SSH-2.0-", and should not include a +// newline. exchangeVersions returns the other side's version line. +func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { + // Contrary to the RFC, we do not ignore lines that don't + // start with "SSH-2.0-" to make the library usable with + // nonconforming servers. + for _, c := range versionLine { + // The spec disallows non US-ASCII chars, and + // specifically forbids null chars. + if c < 32 { + return nil, errors.New("ssh: junk character in version line") + } + } + if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { + return + } + + them, err = readVersion(rw) + return them, err +} + +// maxVersionStringBytes is the maximum number of bytes that we'll +// accept as a version string. RFC 4253 section 4.2 limits this at 255 +// chars +const maxVersionStringBytes = 255 + +// Read version string as specified by RFC 4253, section 4.2. +func readVersion(r io.Reader) ([]byte, error) { + versionString := make([]byte, 0, 64) + var ok bool + var buf [1]byte + + for length := 0; length < maxVersionStringBytes; length++ { + _, err := io.ReadFull(r, buf[:]) + if err != nil { + return nil, err + } + // The RFC says that the version should be terminated with \r\n + // but several SSH servers actually only send a \n. + if buf[0] == '\n' { + if !bytes.HasPrefix(versionString, []byte("SSH-")) { + // RFC 4253 says we need to ignore all version string lines + // except the one containing the SSH version (provided that + // all the lines do not exceed 255 bytes in total). + versionString = versionString[:0] + continue + } + ok = true + break + } + + // non ASCII chars are disallowed, but we are lenient, + // since Go doesn't use null-terminated strings. + + // The RFC allows a comment after a space, however, + // all of it (version and comments) goes into the + // session hash. + versionString = append(versionString, buf[0]) + } + + if !ok { + return nil, errors.New("ssh: overflow reading version string") + } + + // There might be a '\r' on the end which we should remove. + if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { + versionString = versionString[:len(versionString)-1] + } + return versionString, nil +} diff --git a/vendor/golang.org/x/net/internal/socks/client.go b/vendor/golang.org/x/net/internal/socks/client.go new file mode 100644 index 00000000..3d6f516a --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/client.go @@ -0,0 +1,168 @@ +// Copyright 2018 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 socks + +import ( + "context" + "errors" + "io" + "net" + "strconv" + "time" +) + +var ( + noDeadline = time.Time{} + aLongTimeAgo = time.Unix(1, 0) +) + +func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { + host, port, err := splitHostPort(address) + if err != nil { + return nil, err + } + if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { + c.SetDeadline(deadline) + defer c.SetDeadline(noDeadline) + } + if ctx != context.Background() { + errCh := make(chan error, 1) + done := make(chan struct{}) + defer func() { + close(done) + if ctxErr == nil { + ctxErr = <-errCh + } + }() + go func() { + select { + case <-ctx.Done(): + c.SetDeadline(aLongTimeAgo) + errCh <- ctx.Err() + case <-done: + errCh <- nil + } + }() + } + + b := make([]byte, 0, 6+len(host)) // the size here is just an estimate + b = append(b, Version5) + if len(d.AuthMethods) == 0 || d.Authenticate == nil { + b = append(b, 1, byte(AuthMethodNotRequired)) + } else { + ams := d.AuthMethods + if len(ams) > 255 { + return nil, errors.New("too many authentication methods") + } + b = append(b, byte(len(ams))) + for _, am := range ams { + b = append(b, byte(am)) + } + } + if _, ctxErr = c.Write(b); ctxErr != nil { + return + } + + if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { + return + } + if b[0] != Version5 { + return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) + } + am := AuthMethod(b[1]) + if am == AuthMethodNoAcceptableMethods { + return nil, errors.New("no acceptable authentication methods") + } + if d.Authenticate != nil { + if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { + return + } + } + + b = b[:0] + b = append(b, Version5, byte(d.cmd), 0) + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + b = append(b, AddrTypeIPv4) + b = append(b, ip4...) + } else if ip6 := ip.To16(); ip6 != nil { + b = append(b, AddrTypeIPv6) + b = append(b, ip6...) + } else { + return nil, errors.New("unknown address type") + } + } else { + if len(host) > 255 { + return nil, errors.New("FQDN too long") + } + b = append(b, AddrTypeFQDN) + b = append(b, byte(len(host))) + b = append(b, host...) + } + b = append(b, byte(port>>8), byte(port)) + if _, ctxErr = c.Write(b); ctxErr != nil { + return + } + + if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { + return + } + if b[0] != Version5 { + return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) + } + if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { + return nil, errors.New("unknown error " + cmdErr.String()) + } + if b[2] != 0 { + return nil, errors.New("non-zero reserved field") + } + l := 2 + var a Addr + switch b[3] { + case AddrTypeIPv4: + l += net.IPv4len + a.IP = make(net.IP, net.IPv4len) + case AddrTypeIPv6: + l += net.IPv6len + a.IP = make(net.IP, net.IPv6len) + case AddrTypeFQDN: + if _, err := io.ReadFull(c, b[:1]); err != nil { + return nil, err + } + l += int(b[0]) + default: + return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) + } + if cap(b) < l { + b = make([]byte, l) + } else { + b = b[:l] + } + if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { + return + } + if a.IP != nil { + copy(a.IP, b) + } else { + a.Name = string(b[:len(b)-2]) + } + a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) + return &a, nil +} + +func splitHostPort(address string) (string, int, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return "", 0, err + } + portnum, err := strconv.Atoi(port) + if err != nil { + return "", 0, err + } + if 1 > portnum || portnum > 0xffff { + return "", 0, errors.New("port number out of range " + port) + } + return host, portnum, nil +} diff --git a/vendor/golang.org/x/net/internal/socks/socks.go b/vendor/golang.org/x/net/internal/socks/socks.go new file mode 100644 index 00000000..97db2340 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/socks.go @@ -0,0 +1,317 @@ +// Copyright 2018 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 socks provides a SOCKS version 5 client implementation. +// +// SOCKS protocol version 5 is defined in RFC 1928. +// Username/Password authentication for SOCKS version 5 is defined in +// RFC 1929. +package socks + +import ( + "context" + "errors" + "io" + "net" + "strconv" +) + +// A Command represents a SOCKS command. +type Command int + +func (cmd Command) String() string { + switch cmd { + case CmdConnect: + return "socks connect" + case cmdBind: + return "socks bind" + default: + return "socks " + strconv.Itoa(int(cmd)) + } +} + +// An AuthMethod represents a SOCKS authentication method. +type AuthMethod int + +// A Reply represents a SOCKS command reply code. +type Reply int + +func (code Reply) String() string { + switch code { + case StatusSucceeded: + return "succeeded" + case 0x01: + return "general SOCKS server failure" + case 0x02: + return "connection not allowed by ruleset" + case 0x03: + return "network unreachable" + case 0x04: + return "host unreachable" + case 0x05: + return "connection refused" + case 0x06: + return "TTL expired" + case 0x07: + return "command not supported" + case 0x08: + return "address type not supported" + default: + return "unknown code: " + strconv.Itoa(int(code)) + } +} + +// Wire protocol constants. +const ( + Version5 = 0x05 + + AddrTypeIPv4 = 0x01 + AddrTypeFQDN = 0x03 + AddrTypeIPv6 = 0x04 + + CmdConnect Command = 0x01 // establishes an active-open forward proxy connection + cmdBind Command = 0x02 // establishes a passive-open forward proxy connection + + AuthMethodNotRequired AuthMethod = 0x00 // no authentication required + AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password + AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods + + StatusSucceeded Reply = 0x00 +) + +// An Addr represents a SOCKS-specific address. +// Either Name or IP is used exclusively. +type Addr struct { + Name string // fully-qualified domain name + IP net.IP + Port int +} + +func (a *Addr) Network() string { return "socks" } + +func (a *Addr) String() string { + if a == nil { + return "" + } + port := strconv.Itoa(a.Port) + if a.IP == nil { + return net.JoinHostPort(a.Name, port) + } + return net.JoinHostPort(a.IP.String(), port) +} + +// A Conn represents a forward proxy connection. +type Conn struct { + net.Conn + + boundAddr net.Addr +} + +// BoundAddr returns the address assigned by the proxy server for +// connecting to the command target address from the proxy server. +func (c *Conn) BoundAddr() net.Addr { + if c == nil { + return nil + } + return c.boundAddr +} + +// A Dialer holds SOCKS-specific options. +type Dialer struct { + cmd Command // either CmdConnect or cmdBind + proxyNetwork string // network between a proxy server and a client + proxyAddress string // proxy server address + + // ProxyDial specifies the optional dial function for + // establishing the transport connection. + ProxyDial func(context.Context, string, string) (net.Conn, error) + + // AuthMethods specifies the list of request authentication + // methods. + // If empty, SOCKS client requests only AuthMethodNotRequired. + AuthMethods []AuthMethod + + // Authenticate specifies the optional authentication + // function. It must be non-nil when AuthMethods is not empty. + // It must return an error when the authentication is failed. + Authenticate func(context.Context, io.ReadWriter, AuthMethod) error +} + +// DialContext connects to the provided address on the provided +// network. +// +// The returned error value may be a net.OpError. When the Op field of +// net.OpError contains "socks", the Source field contains a proxy +// server address and the Addr field contains a command target +// address. +// +// See func Dial of the net package of standard library for a +// description of the network and address parameters. +func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if ctx == nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} + } + var err error + var c net.Conn + if d.ProxyDial != nil { + c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) + } else { + var dd net.Dialer + c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) + } + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + a, err := d.connect(ctx, c, address) + if err != nil { + c.Close() + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + return &Conn{Conn: c, boundAddr: a}, nil +} + +// DialWithConn initiates a connection from SOCKS server to the target +// network and address using the connection c that is already +// connected to the SOCKS server. +// +// It returns the connection's local address assigned by the SOCKS +// server. +func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if ctx == nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} + } + a, err := d.connect(ctx, c, address) + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + return a, nil +} + +// Dial connects to the provided address on the provided network. +// +// Unlike DialContext, it returns a raw transport connection instead +// of a forward proxy connection. +// +// Deprecated: Use DialContext or DialWithConn instead. +func (d *Dialer) Dial(network, address string) (net.Conn, error) { + if err := d.validateTarget(network, address); err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + var err error + var c net.Conn + if d.ProxyDial != nil { + c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) + } else { + c, err = net.Dial(d.proxyNetwork, d.proxyAddress) + } + if err != nil { + proxy, dst, _ := d.pathAddrs(address) + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} + } + if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { + c.Close() + return nil, err + } + return c, nil +} + +func (d *Dialer) validateTarget(network, address string) error { + switch network { + case "tcp", "tcp6", "tcp4": + default: + return errors.New("network not implemented") + } + switch d.cmd { + case CmdConnect, cmdBind: + default: + return errors.New("command not implemented") + } + return nil +} + +func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { + for i, s := range []string{d.proxyAddress, address} { + host, port, err := splitHostPort(s) + if err != nil { + return nil, nil, err + } + a := &Addr{Port: port} + a.IP = net.ParseIP(host) + if a.IP == nil { + a.Name = host + } + if i == 0 { + proxy = a + } else { + dst = a + } + } + return +} + +// NewDialer returns a new Dialer that dials through the provided +// proxy server's network and address. +func NewDialer(network, address string) *Dialer { + return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} +} + +const ( + authUsernamePasswordVersion = 0x01 + authStatusSucceeded = 0x00 +) + +// UsernamePassword are the credentials for the username/password +// authentication method. +type UsernamePassword struct { + Username string + Password string +} + +// Authenticate authenticates a pair of username and password with the +// proxy server. +func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { + switch auth { + case AuthMethodNotRequired: + return nil + case AuthMethodUsernamePassword: + if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 { + return errors.New("invalid username/password") + } + b := []byte{authUsernamePasswordVersion} + b = append(b, byte(len(up.Username))) + b = append(b, up.Username...) + b = append(b, byte(len(up.Password))) + b = append(b, up.Password...) + // TODO(mikio): handle IO deadlines and cancelation if + // necessary + if _, err := rw.Write(b); err != nil { + return err + } + if _, err := io.ReadFull(rw, b[:2]); err != nil { + return err + } + if b[0] != authUsernamePasswordVersion { + return errors.New("invalid username/password version") + } + if b[1] != authStatusSucceeded { + return errors.New("username/password authentication failed") + } + return nil + } + return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) +} diff --git a/vendor/golang.org/x/net/proxy/dial.go b/vendor/golang.org/x/net/proxy/dial.go new file mode 100644 index 00000000..811c2e4e --- /dev/null +++ b/vendor/golang.org/x/net/proxy/dial.go @@ -0,0 +1,54 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( + "context" + "net" +) + +// A ContextDialer dials using a context. +type ContextDialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment. +// +// The passed ctx is only used for returning the Conn, not the lifetime of the Conn. +// +// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer +// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout. +// +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func Dial(ctx context.Context, network, address string) (net.Conn, error) { + d := FromEnvironment() + if xd, ok := d.(ContextDialer); ok { + return xd.DialContext(ctx, network, address) + } + return dialContext(ctx, d, network, address) +} + +// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) { + var ( + conn net.Conn + done = make(chan struct{}, 1) + err error + ) + go func() { + conn, err = d.Dial(network, address) + close(done) + if conn != nil && ctx.Err() != nil { + conn.Close() + } + }() + select { + case <-ctx.Done(): + err = ctx.Err() + case <-done: + } + return conn, err +} diff --git a/vendor/golang.org/x/net/proxy/direct.go b/vendor/golang.org/x/net/proxy/direct.go new file mode 100644 index 00000000..3d66bdef --- /dev/null +++ b/vendor/golang.org/x/net/proxy/direct.go @@ -0,0 +1,31 @@ +// 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 proxy + +import ( + "context" + "net" +) + +type direct struct{} + +// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext. +var Direct = direct{} + +var ( + _ Dialer = Direct + _ ContextDialer = Direct +) + +// Dial directly invokes net.Dial with the supplied parameters. +func (direct) Dial(network, addr string) (net.Conn, error) { + return net.Dial(network, addr) +} + +// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters. +func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + var d net.Dialer + return d.DialContext(ctx, network, addr) +} diff --git a/vendor/golang.org/x/net/proxy/per_host.go b/vendor/golang.org/x/net/proxy/per_host.go new file mode 100644 index 00000000..573fe79e --- /dev/null +++ b/vendor/golang.org/x/net/proxy/per_host.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. + +package proxy + +import ( + "context" + "net" + "strings" +) + +// A PerHost directs connections to a default Dialer unless the host name +// requested matches one of a number of exceptions. +type PerHost struct { + def, bypass Dialer + + bypassNetworks []*net.IPNet + bypassIPs []net.IP + bypassZones []string + bypassHosts []string +} + +// NewPerHost returns a PerHost Dialer that directs connections to either +// defaultDialer or bypass, depending on whether the connection matches one of +// the configured rules. +func NewPerHost(defaultDialer, bypass Dialer) *PerHost { + return &PerHost{ + def: defaultDialer, + bypass: bypass, + } +} + +// Dial connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + return p.dialerForRequest(host).Dial(network, addr) +} + +// DialContext connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + d := p.dialerForRequest(host) + if x, ok := d.(ContextDialer); ok { + return x.DialContext(ctx, network, addr) + } + return dialContext(ctx, d, network, addr) +} + +func (p *PerHost) dialerForRequest(host string) Dialer { + if ip := net.ParseIP(host); ip != nil { + for _, net := range p.bypassNetworks { + if net.Contains(ip) { + return p.bypass + } + } + for _, bypassIP := range p.bypassIPs { + if bypassIP.Equal(ip) { + return p.bypass + } + } + return p.def + } + + for _, zone := range p.bypassZones { + if strings.HasSuffix(host, zone) { + return p.bypass + } + if host == zone[1:] { + // For a zone ".example.com", we match "example.com" + // too. + return p.bypass + } + } + for _, bypassHost := range p.bypassHosts { + if bypassHost == host { + return p.bypass + } + } + return p.def +} + +// AddFromString parses a string that contains comma-separated values +// specifying hosts that should use the bypass proxy. Each value is either an +// IP address, a CIDR range, a zone (*.example.com) or a host name +// (localhost). A best effort is made to parse the string and errors are +// ignored. +func (p *PerHost) AddFromString(s string) { + hosts := strings.Split(s, ",") + for _, host := range hosts { + host = strings.TrimSpace(host) + if len(host) == 0 { + continue + } + if strings.Contains(host, "/") { + // We assume that it's a CIDR address like 127.0.0.0/8 + if _, net, err := net.ParseCIDR(host); err == nil { + p.AddNetwork(net) + } + continue + } + if ip := net.ParseIP(host); ip != nil { + p.AddIP(ip) + continue + } + if strings.HasPrefix(host, "*.") { + p.AddZone(host[1:]) + continue + } + p.AddHost(host) + } +} + +// AddIP specifies an IP address that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match an IP. +func (p *PerHost) AddIP(ip net.IP) { + p.bypassIPs = append(p.bypassIPs, ip) +} + +// AddNetwork specifies an IP range that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match. +func (p *PerHost) AddNetwork(net *net.IPNet) { + p.bypassNetworks = append(p.bypassNetworks, net) +} + +// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of +// "example.com" matches "example.com" and all of its subdomains. +func (p *PerHost) AddZone(zone string) { + if strings.HasSuffix(zone, ".") { + zone = zone[:len(zone)-1] + } + if !strings.HasPrefix(zone, ".") { + zone = "." + zone + } + p.bypassZones = append(p.bypassZones, zone) +} + +// AddHost specifies a host name that will use the bypass proxy. +func (p *PerHost) AddHost(host string) { + if strings.HasSuffix(host, ".") { + host = host[:len(host)-1] + } + p.bypassHosts = append(p.bypassHosts, host) +} diff --git a/vendor/golang.org/x/net/proxy/proxy.go b/vendor/golang.org/x/net/proxy/proxy.go new file mode 100644 index 00000000..9ff4b9a7 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/proxy.go @@ -0,0 +1,149 @@ +// 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 proxy provides support for a variety of protocols to proxy network +// data. +package proxy // import "golang.org/x/net/proxy" + +import ( + "errors" + "net" + "net/url" + "os" + "sync" +) + +// A Dialer is a means to establish a connection. +// Custom dialers should also implement ContextDialer. +type Dialer interface { + // Dial connects to the given address via the proxy. + Dial(network, addr string) (c net.Conn, err error) +} + +// Auth contains authentication parameters that specific Dialers may require. +type Auth struct { + User, Password string +} + +// FromEnvironment returns the dialer specified by the proxy-related +// variables in the environment and makes underlying connections +// directly. +func FromEnvironment() Dialer { + return FromEnvironmentUsing(Direct) +} + +// FromEnvironmentUsing returns the dialer specify by the proxy-related +// variables in the environment and makes underlying connections +// using the provided forwarding Dialer (for instance, a *net.Dialer +// with desired configuration). +func FromEnvironmentUsing(forward Dialer) Dialer { + allProxy := allProxyEnv.Get() + if len(allProxy) == 0 { + return forward + } + + proxyURL, err := url.Parse(allProxy) + if err != nil { + return forward + } + proxy, err := FromURL(proxyURL, forward) + if err != nil { + return forward + } + + noProxy := noProxyEnv.Get() + if len(noProxy) == 0 { + return proxy + } + + perHost := NewPerHost(proxy, forward) + perHost.AddFromString(noProxy) + return perHost +} + +// proxySchemes is a map from URL schemes to a function that creates a Dialer +// from a URL with such a scheme. +var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) + +// RegisterDialerType takes a URL scheme and a function to generate Dialers from +// a URL with that scheme and a forwarding Dialer. Registered schemes are used +// by FromURL. +func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { + if proxySchemes == nil { + proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) + } + proxySchemes[scheme] = f +} + +// FromURL returns a Dialer given a URL specification and an underlying +// Dialer for it to make network requests. +func FromURL(u *url.URL, forward Dialer) (Dialer, error) { + var auth *Auth + if u.User != nil { + auth = new(Auth) + auth.User = u.User.Username() + if p, ok := u.User.Password(); ok { + auth.Password = p + } + } + + switch u.Scheme { + case "socks5", "socks5h": + addr := u.Hostname() + port := u.Port() + if port == "" { + port = "1080" + } + return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) + } + + // If the scheme doesn't match any of the built-in schemes, see if it + // was registered by another package. + if proxySchemes != nil { + if f, ok := proxySchemes[u.Scheme]; ok { + return f(u, forward) + } + } + + return nil, errors.New("proxy: unknown scheme: " + u.Scheme) +} + +var ( + allProxyEnv = &envOnce{ + names: []string{"ALL_PROXY", "all_proxy"}, + } + noProxyEnv = &envOnce{ + names: []string{"NO_PROXY", "no_proxy"}, + } +) + +// envOnce looks up an environment variable (optionally by multiple +// names) once. It mitigates expensive lookups on some platforms +// (e.g. Windows). +// (Borrowed from net/http/transport.go) +type envOnce struct { + names []string + once sync.Once + val string +} + +func (e *envOnce) Get() string { + e.once.Do(e.init) + return e.val +} + +func (e *envOnce) init() { + for _, n := range e.names { + e.val = os.Getenv(n) + if e.val != "" { + return + } + } +} + +// reset is used by tests +func (e *envOnce) reset() { + e.once = sync.Once{} + e.val = "" +} diff --git a/vendor/golang.org/x/net/proxy/socks5.go b/vendor/golang.org/x/net/proxy/socks5.go new file mode 100644 index 00000000..c91651f9 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/socks5.go @@ -0,0 +1,42 @@ +// 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 proxy + +import ( + "context" + "net" + + "golang.org/x/net/internal/socks" +) + +// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given +// address with an optional username and password. +// See RFC 1928 and RFC 1929. +func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { + d := socks.NewDialer(network, address) + if forward != nil { + if f, ok := forward.(ContextDialer); ok { + d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { + return f.DialContext(ctx, network, address) + } + } else { + d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { + return dialContext(ctx, forward, network, address) + } + } + } + if auth != nil { + up := socks.UsernamePassword{ + Username: auth.User, + Password: auth.Password, + } + d.AuthMethods = []socks.AuthMethod{ + socks.AuthMethodNotRequired, + socks.AuthMethodUsernamePassword, + } + d.Authenticate = up.Authenticate + } + return d, nil +} diff --git a/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s new file mode 100644 index 00000000..db9171c2 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s @@ -0,0 +1,18 @@ +// Copyright 2018 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. + +//go:build gc +// +build gc + +#include "textflag.h" + +// +// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go +// + +TEXT ·syscall6(SB),NOSPLIT,$0-88 + JMP syscall·syscall6(SB) + +TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/cpu/byteorder.go b/vendor/golang.org/x/sys/cpu/byteorder.go new file mode 100644 index 00000000..271055be --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/byteorder.go @@ -0,0 +1,66 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import ( + "runtime" +) + +// byteOrder is a subset of encoding/binary.ByteOrder. +type byteOrder interface { + Uint32([]byte) uint32 + Uint64([]byte) uint64 +} + +type littleEndian struct{} +type bigEndian struct{} + +func (littleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func (littleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func (bigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func (bigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + +// hostByteOrder returns littleEndian on little-endian machines and +// bigEndian on big-endian machines. +func hostByteOrder() byteOrder { + switch runtime.GOARCH { + case "386", "amd64", "amd64p32", + "alpha", + "arm", "arm64", + "loong64", + "mipsle", "mips64le", "mips64p32le", + "nios2", + "ppc64le", + "riscv", "riscv64", + "sh": + return littleEndian{} + case "armbe", "arm64be", + "m68k", + "mips", "mips64", "mips64p32", + "ppc", "ppc64", + "s390", "s390x", + "shbe", + "sparc", "sparc64": + return bigEndian{} + } + panic("unknown architecture") +} diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 00000000..83f112c4 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,287 @@ +// Copyright 2018 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 cpu implements processor feature detection for +// various CPU architectures. +package cpu + +import ( + "os" + "strings" +) + +// Initialized reports whether the CPU features were initialized. +// +// For some GOOS/GOARCH combinations initialization of the CPU features depends +// on reading an operating specific file, e.g. /proc/self/auxv on linux/arm +// Initialized will report false if reading the file fails. +var Initialized bool + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasAVX512 bool // Advanced vector extension 512 + HasAVX512F bool // Advanced vector extension 512 Foundation Instructions + HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions + HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions + HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions Instructions + HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions + HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions + HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions + HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add + HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions + HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision + HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision + HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions + HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations + HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions + HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions + HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions + HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 + HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms + HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasCX16 bool // Compare and exchange 16 Bytes + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasRDRAND bool // RDRAND instruction (on-chip random number generator) + HasRDSEED bool // RDSEED instruction (on-chip random number generator) + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} + +// ARM contains the supported CPU features of the current ARM (32-bit) platform. +// All feature flags are false if: +// 1. the current platform is not arm, or +// 2. the current operating system is not Linux. +var ARM struct { + _ CacheLinePad + HasSWP bool // SWP instruction support + HasHALF bool // Half-word load and store support + HasTHUMB bool // ARM Thumb instruction set + Has26BIT bool // Address space limited to 26-bits + HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support + HasFPA bool // Floating point arithmetic support + HasVFP bool // Vector floating point support + HasEDSP bool // DSP Extensions support + HasJAVA bool // Java instruction set + HasIWMMXT bool // Intel Wireless MMX technology support + HasCRUNCH bool // MaverickCrunch context switching and handling + HasTHUMBEE bool // Thumb EE instruction set + HasNEON bool // NEON instruction set + HasVFPv3 bool // Vector floating point version 3 support + HasVFPv3D16 bool // Vector floating point version 3 D8-D15 + HasTLS bool // Thread local storage support + HasVFPv4 bool // Vector floating point version 4 support + HasIDIVA bool // Integer divide instruction support in ARM mode + HasIDIVT bool // Integer divide instruction support in Thumb mode + HasVFPD32 bool // Vector floating point version 3 D15-D31 + HasLPAE bool // Large Physical Address Extensions + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + _ CacheLinePad +} + +// MIPS64X contains the supported CPU features of the current mips64/mips64le +// platforms. If the current platform is not mips64/mips64le or the current +// operating system is not Linux then all feature flags are false. +var MIPS64X struct { + _ CacheLinePad + HasMSA bool // MIPS SIMD architecture + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8 + _ CacheLinePad +} + +// S390X contains the supported CPU features of the current IBM Z +// (s390x) platform. If the current platform is not IBM Z then all +// feature flags are false. +// +// S390X is padded to avoid false sharing. Further HasVX is only set +// if the OS supports vector registers in addition to the STFLE +// feature bit being set. +var S390X struct { + _ CacheLinePad + HasZARCH bool // z/Architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended + HasLDISP bool // long (20-bit) displacements + HasEIMM bool // 32-bit immediates + HasDFP bool // decimal floating point + HasETF3EH bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions + HasVX bool // vector facility + HasVXE bool // vector-enhancements facility 1 + _ CacheLinePad +} + +func init() { + archInit() + initOptions() + processOptions() +} + +// options contains the cpu debug options that can be used in GODEBUG. +// Options are arch dependent and are added by the arch specific initOptions functions. +// Features that are mandatory for the specific GOARCH should have the Required field set +// (e.g. SSE2 on amd64). +var options []option + +// Option names should be lower case. e.g. avx instead of AVX. +type option struct { + Name string + Feature *bool + Specified bool // whether feature value was specified in GODEBUG + Enable bool // whether feature should be enabled + Required bool // whether feature is mandatory and can not be disabled +} + +func processOptions() { + env := os.Getenv("GODEBUG") +field: + for env != "" { + field := "" + i := strings.IndexByte(env, ',') + if i < 0 { + field, env = env, "" + } else { + field, env = env[:i], env[i+1:] + } + if len(field) < 4 || field[:4] != "cpu." { + continue + } + i = strings.IndexByte(field, '=') + if i < 0 { + print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") + continue + } + key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" + + var enable bool + switch value { + case "on": + enable = true + case "off": + enable = false + default: + print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") + continue field + } + + if key == "all" { + for i := range options { + options[i].Specified = true + options[i].Enable = enable || options[i].Required + } + continue field + } + + for i := range options { + if options[i].Name == key { + options[i].Specified = true + options[i].Enable = enable + continue field + } + } + + print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") + } + + for _, o := range options { + if !o.Specified { + continue + } + + if o.Enable && !*o.Feature { + print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") + continue + } + + if !o.Enable && o.Required { + print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") + continue + } + + *o.Feature = o.Enable + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_aix.go b/vendor/golang.org/x/sys/cpu/cpu_aix.go new file mode 100644 index 00000000..8aaeef54 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_aix.go @@ -0,0 +1,34 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix +// +build aix + +package cpu + +const ( + // getsystemcfg constants + _SC_IMPL = 2 + _IMPL_POWER8 = 0x10000 + _IMPL_POWER9 = 0x20000 +) + +func archInit() { + impl := getsystemcfg(_SC_IMPL) + if impl&_IMPL_POWER8 != 0 { + PPC64.IsPOWER8 = true + } + if impl&_IMPL_POWER9 != 0 { + PPC64.IsPOWER8 = true + PPC64.IsPOWER9 = true + } + + Initialized = true +} + +func getsystemcfg(label int) (n uint64) { + r0, _ := callgetsystemcfg(label) + n = uint64(r0) + return +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 00000000..301b752e --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,73 @@ +// Copyright 2018 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 cpu + +const cacheLineSize = 32 + +// HWCAP/HWCAP2 bits. +// These are specific to Linux. +const ( + hwcap_SWP = 1 << 0 + hwcap_HALF = 1 << 1 + hwcap_THUMB = 1 << 2 + hwcap_26BIT = 1 << 3 + hwcap_FAST_MULT = 1 << 4 + hwcap_FPA = 1 << 5 + hwcap_VFP = 1 << 6 + hwcap_EDSP = 1 << 7 + hwcap_JAVA = 1 << 8 + hwcap_IWMMXT = 1 << 9 + hwcap_CRUNCH = 1 << 10 + hwcap_THUMBEE = 1 << 11 + hwcap_NEON = 1 << 12 + hwcap_VFPv3 = 1 << 13 + hwcap_VFPv3D16 = 1 << 14 + hwcap_TLS = 1 << 15 + hwcap_VFPv4 = 1 << 16 + hwcap_IDIVA = 1 << 17 + hwcap_IDIVT = 1 << 18 + hwcap_VFPD32 = 1 << 19 + hwcap_LPAE = 1 << 20 + hwcap_EVTSTRM = 1 << 21 + + hwcap2_AES = 1 << 0 + hwcap2_PMULL = 1 << 1 + hwcap2_SHA1 = 1 << 2 + hwcap2_SHA2 = 1 << 3 + hwcap2_CRC32 = 1 << 4 +) + +func initOptions() { + options = []option{ + {Name: "pmull", Feature: &ARM.HasPMULL}, + {Name: "sha1", Feature: &ARM.HasSHA1}, + {Name: "sha2", Feature: &ARM.HasSHA2}, + {Name: "swp", Feature: &ARM.HasSWP}, + {Name: "thumb", Feature: &ARM.HasTHUMB}, + {Name: "thumbee", Feature: &ARM.HasTHUMBEE}, + {Name: "tls", Feature: &ARM.HasTLS}, + {Name: "vfp", Feature: &ARM.HasVFP}, + {Name: "vfpd32", Feature: &ARM.HasVFPD32}, + {Name: "vfpv3", Feature: &ARM.HasVFPv3}, + {Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16}, + {Name: "vfpv4", Feature: &ARM.HasVFPv4}, + {Name: "half", Feature: &ARM.HasHALF}, + {Name: "26bit", Feature: &ARM.Has26BIT}, + {Name: "fastmul", Feature: &ARM.HasFASTMUL}, + {Name: "fpa", Feature: &ARM.HasFPA}, + {Name: "edsp", Feature: &ARM.HasEDSP}, + {Name: "java", Feature: &ARM.HasJAVA}, + {Name: "iwmmxt", Feature: &ARM.HasIWMMXT}, + {Name: "crunch", Feature: &ARM.HasCRUNCH}, + {Name: "neon", Feature: &ARM.HasNEON}, + {Name: "idivt", Feature: &ARM.HasIDIVT}, + {Name: "idiva", Feature: &ARM.HasIDIVA}, + {Name: "lpae", Feature: &ARM.HasLPAE}, + {Name: "evtstrm", Feature: &ARM.HasEVTSTRM}, + {Name: "aes", Feature: &ARM.HasAES}, + {Name: "crc32", Feature: &ARM.HasCRC32}, + } + +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_arm64.go new file mode 100644 index 00000000..87dd5e30 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -0,0 +1,172 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +import "runtime" + +const cacheLineSize = 64 + +func initOptions() { + options = []option{ + {Name: "fp", Feature: &ARM64.HasFP}, + {Name: "asimd", Feature: &ARM64.HasASIMD}, + {Name: "evstrm", Feature: &ARM64.HasEVTSTRM}, + {Name: "aes", Feature: &ARM64.HasAES}, + {Name: "fphp", Feature: &ARM64.HasFPHP}, + {Name: "jscvt", Feature: &ARM64.HasJSCVT}, + {Name: "lrcpc", Feature: &ARM64.HasLRCPC}, + {Name: "pmull", Feature: &ARM64.HasPMULL}, + {Name: "sha1", Feature: &ARM64.HasSHA1}, + {Name: "sha2", Feature: &ARM64.HasSHA2}, + {Name: "sha3", Feature: &ARM64.HasSHA3}, + {Name: "sha512", Feature: &ARM64.HasSHA512}, + {Name: "sm3", Feature: &ARM64.HasSM3}, + {Name: "sm4", Feature: &ARM64.HasSM4}, + {Name: "sve", Feature: &ARM64.HasSVE}, + {Name: "crc32", Feature: &ARM64.HasCRC32}, + {Name: "atomics", Feature: &ARM64.HasATOMICS}, + {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, + {Name: "cpuid", Feature: &ARM64.HasCPUID}, + {Name: "asimrdm", Feature: &ARM64.HasASIMDRDM}, + {Name: "fcma", Feature: &ARM64.HasFCMA}, + {Name: "dcpop", Feature: &ARM64.HasDCPOP}, + {Name: "asimddp", Feature: &ARM64.HasASIMDDP}, + {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, + } +} + +func archInit() { + switch runtime.GOOS { + case "freebsd": + readARM64Registers() + case "linux", "netbsd": + doinit() + default: + // Most platforms don't seem to allow reading these registers. + // + // OpenBSD: + // See https://golang.org/issue/31746 + setMinimalFeatures() + } +} + +// setMinimalFeatures fakes the minimal ARM64 features expected by +// TestARM64minimalFeatures. +func setMinimalFeatures() { + ARM64.HasASIMD = true + ARM64.HasFP = true +} + +func readARM64Registers() { + Initialized = true + + parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0()) +} + +func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { + // ID_AA64ISAR0_EL1 + switch extractBits(isar0, 4, 7) { + case 1: + ARM64.HasAES = true + case 2: + ARM64.HasAES = true + ARM64.HasPMULL = true + } + + switch extractBits(isar0, 8, 11) { + case 1: + ARM64.HasSHA1 = true + } + + switch extractBits(isar0, 12, 15) { + case 1: + ARM64.HasSHA2 = true + case 2: + ARM64.HasSHA2 = true + ARM64.HasSHA512 = true + } + + switch extractBits(isar0, 16, 19) { + case 1: + ARM64.HasCRC32 = true + } + + switch extractBits(isar0, 20, 23) { + case 2: + ARM64.HasATOMICS = true + } + + switch extractBits(isar0, 28, 31) { + case 1: + ARM64.HasASIMDRDM = true + } + + switch extractBits(isar0, 32, 35) { + case 1: + ARM64.HasSHA3 = true + } + + switch extractBits(isar0, 36, 39) { + case 1: + ARM64.HasSM3 = true + } + + switch extractBits(isar0, 40, 43) { + case 1: + ARM64.HasSM4 = true + } + + switch extractBits(isar0, 44, 47) { + case 1: + ARM64.HasASIMDDP = true + } + + // ID_AA64ISAR1_EL1 + switch extractBits(isar1, 0, 3) { + case 1: + ARM64.HasDCPOP = true + } + + switch extractBits(isar1, 12, 15) { + case 1: + ARM64.HasJSCVT = true + } + + switch extractBits(isar1, 16, 19) { + case 1: + ARM64.HasFCMA = true + } + + switch extractBits(isar1, 20, 23) { + case 1: + ARM64.HasLRCPC = true + } + + // ID_AA64PFR0_EL1 + switch extractBits(pfr0, 16, 19) { + case 0: + ARM64.HasFP = true + case 1: + ARM64.HasFP = true + ARM64.HasFPHP = true + } + + switch extractBits(pfr0, 20, 23) { + case 0: + ARM64.HasASIMD = true + case 1: + ARM64.HasASIMD = true + ARM64.HasASIMDHP = true + } + + switch extractBits(pfr0, 32, 35) { + case 1: + ARM64.HasSVE = true + } +} + +func extractBits(data uint64, start, end uint) uint { + return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/vendor/golang.org/x/sys/cpu/cpu_arm64.s new file mode 100644 index 00000000..c61f95a0 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.s @@ -0,0 +1,32 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +#include "textflag.h" + +// func getisar0() uint64 +TEXT ·getisar0(SB),NOSPLIT,$0-8 + // get Instruction Set Attributes 0 into x0 + // mrs x0, ID_AA64ISAR0_EL1 = d5380600 + WORD $0xd5380600 + MOVD R0, ret+0(FP) + RET + +// func getisar1() uint64 +TEXT ·getisar1(SB),NOSPLIT,$0-8 + // get Instruction Set Attributes 1 into x0 + // mrs x0, ID_AA64ISAR1_EL1 = d5380620 + WORD $0xd5380620 + MOVD R0, ret+0(FP) + RET + +// func getpfr0() uint64 +TEXT ·getpfr0(SB),NOSPLIT,$0-8 + // get Processor Feature Register 0 into x0 + // mrs x0, ID_AA64PFR0_EL1 = d5380400 + WORD $0xd5380400 + MOVD R0, ret+0(FP) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go new file mode 100644 index 00000000..ccf542a7 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +package cpu + +func getisar0() uint64 +func getisar1() uint64 +func getpfr0() uint64 diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go new file mode 100644 index 00000000..0af2f248 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go @@ -0,0 +1,22 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return true } + +// The following feature detection functions are defined in cpu_s390x.s. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList +func kmQuery() queryResult +func kmcQuery() queryResult +func kmctrQuery() queryResult +func kmaQuery() queryResult +func kimdQuery() queryResult +func klmdQuery() queryResult diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 00000000..fa7cdb9b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,17 @@ +// Copyright 2018 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. + +//go:build (386 || amd64 || amd64p32) && gc +// +build 386 amd64 amd64p32 +// +build gc + +package cpu + +// cpuid is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go new file mode 100644 index 00000000..2aff3189 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gccgo +// +build gccgo + +package cpu + +func getisar0() uint64 { return 0 } +func getisar1() uint64 { return 0 } +func getpfr0() uint64 { return 0 } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go new file mode 100644 index 00000000..4bfbda61 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go @@ -0,0 +1,23 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gccgo +// +build gccgo + +package cpu + +// haveAsmFunctions reports whether the other functions in this file can +// be safely called. +func haveAsmFunctions() bool { return false } + +// TODO(mundaym): the following feature detection functions are currently +// stubs. See https://golang.org/cl/162887 for how to fix this. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList { panic("not implemented for gccgo") } +func kmQuery() queryResult { panic("not implemented for gccgo") } +func kmcQuery() queryResult { panic("not implemented for gccgo") } +func kmctrQuery() queryResult { panic("not implemented for gccgo") } +func kmaQuery() queryResult { panic("not implemented for gccgo") } +func kimdQuery() queryResult { panic("not implemented for gccgo") } +func klmdQuery() queryResult { panic("not implemented for gccgo") } diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c new file mode 100644 index 00000000..a4605e6d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c @@ -0,0 +1,38 @@ +// Copyright 2018 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 386 amd64 amd64p32 +// +build gccgo + +#include +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC push_options +#pragma GCC target("xsave") +#pragma clang attribute push (__attribute__((target("xsave"))), apply_to=function) + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + uint64_t v = _xgetbv(0); + *eax = v & 0xffffffff; + *edx = v >> 32; +} + +#pragma clang attribute pop +#pragma GCC pop_options diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go new file mode 100644 index 00000000..863d415a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +//go:build (386 || amd64 || amd64p32) && gccgo +// +build 386 amd64 amd64p32 +// +build gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} + +// gccgo doesn't build on Darwin, per: +// https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76 +func darwinSupportsAVX512() bool { + return false +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/golang.org/x/sys/cpu/cpu_linux.go new file mode 100644 index 00000000..159a686f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux.go @@ -0,0 +1,16 @@ +// Copyright 2018 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. + +//go:build !386 && !amd64 && !amd64p32 && !arm64 +// +build !386,!amd64,!amd64p32,!arm64 + +package cpu + +func archInit() { + if err := readHWCAP(); err != nil { + return + } + doinit() + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go new file mode 100644 index 00000000..2057006d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go @@ -0,0 +1,39 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +func doinit() { + ARM.HasSWP = isSet(hwCap, hwcap_SWP) + ARM.HasHALF = isSet(hwCap, hwcap_HALF) + ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB) + ARM.Has26BIT = isSet(hwCap, hwcap_26BIT) + ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT) + ARM.HasFPA = isSet(hwCap, hwcap_FPA) + ARM.HasVFP = isSet(hwCap, hwcap_VFP) + ARM.HasEDSP = isSet(hwCap, hwcap_EDSP) + ARM.HasJAVA = isSet(hwCap, hwcap_JAVA) + ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT) + ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH) + ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE) + ARM.HasNEON = isSet(hwCap, hwcap_NEON) + ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3) + ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16) + ARM.HasTLS = isSet(hwCap, hwcap_TLS) + ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4) + ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA) + ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT) + ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32) + ARM.HasLPAE = isSet(hwCap, hwcap_LPAE) + ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM.HasAES = isSet(hwCap2, hwcap2_AES) + ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL) + ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1) + ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2) + ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go new file mode 100644 index 00000000..79a38a0b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -0,0 +1,71 @@ +// Copyright 2018 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 cpu + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 +) + +func doinit() { + if err := readHWCAP(); err != nil { + // failed to read /proc/self/auxv, try reading registers directly + readARM64Registers() + return + } + + // HWCAP feature bits + ARM64.HasFP = isSet(hwCap, hwcap_FP) + ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(hwCap, hwcap_AES) + ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(hwCap, hwcap_SM3) + ARM64.HasSM4 = isSet(hwCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) + ARM64.HasSVE = isSet(hwCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go new file mode 100644 index 00000000..6000db4c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go @@ -0,0 +1,24 @@ +// Copyright 2020 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. + +//go:build linux && (mips64 || mips64le) +// +build linux +// +build mips64 mips64le + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel 5.4. +const ( + // CPU features + hwcap_MIPS_MSA = 1 << 1 +) + +func doinit() { + // HWCAP feature bits + MIPS64X.HasMSA = isSet(hwCap, hwcap_MIPS_MSA) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go new file mode 100644 index 00000000..f4992b1a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x +// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x + +package cpu + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go new file mode 100644 index 00000000..021356d6 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go @@ -0,0 +1,32 @@ +// Copyright 2018 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. + +//go:build linux && (ppc64 || ppc64le) +// +build linux +// +build ppc64 ppc64le + +package cpu + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func doinit() { + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go new file mode 100644 index 00000000..1517ac61 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go @@ -0,0 +1,40 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const ( + // bit mask values from /usr/include/bits/hwcap.h + hwcap_ZARCH = 2 + hwcap_STFLE = 4 + hwcap_MSA = 8 + hwcap_LDISP = 16 + hwcap_EIMM = 32 + hwcap_DFP = 64 + hwcap_ETF3EH = 256 + hwcap_VX = 2048 + hwcap_VXE = 8192 +) + +func initS390Xbase() { + // test HWCAP bit vector + has := func(featureMask uint) bool { + return hwCap&featureMask == featureMask + } + + // mandatory + S390X.HasZARCH = has(hwcap_ZARCH) + + // optional + S390X.HasSTFLE = has(hwcap_STFLE) + S390X.HasLDISP = has(hwcap_LDISP) + S390X.HasEIMM = has(hwcap_EIMM) + S390X.HasETF3EH = has(hwcap_ETF3EH) + S390X.HasDFP = has(hwcap_DFP) + S390X.HasMSA = has(hwcap_MSA) + S390X.HasVX = has(hwcap_VX) + if S390X.HasVX { + S390X.HasVXE = has(hwcap_VXE) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_loong64.go new file mode 100644 index 00000000..0f57b05b --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_loong64.go @@ -0,0 +1,13 @@ +// Copyright 2022 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. + +//go:build loong64 +// +build loong64 + +package cpu + +const cacheLineSize = 64 + +func initOptions() { +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 00000000..f4063c66 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,16 @@ +// Copyright 2018 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. + +//go:build mips64 || mips64le +// +build mips64 mips64le + +package cpu + +const cacheLineSize = 32 + +func initOptions() { + options = []option{ + {Name: "msa", Feature: &MIPS64X.HasMSA}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 00000000..07c4e36d --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,12 @@ +// Copyright 2018 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. + +//go:build mips || mipsle +// +build mips mipsle + +package cpu + +const cacheLineSize = 32 + +func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go new file mode 100644 index 00000000..ebfb3fc8 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go @@ -0,0 +1,173 @@ +// Copyright 2020 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 cpu + +import ( + "syscall" + "unsafe" +) + +// Minimal copy of functionality from x/sys/unix so the cpu package can call +// sysctl without depending on x/sys/unix. + +const ( + _CTL_QUERY = -2 + + _SYSCTL_VERS_1 = 0x1000000 +) + +var _zero uintptr + +func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(_p0), + uintptr(len(mib)), + uintptr(unsafe.Pointer(old)), + uintptr(unsafe.Pointer(oldlen)), + uintptr(unsafe.Pointer(new)), + uintptr(newlen)) + if errno != 0 { + return errno + } + return nil +} + +type sysctlNode struct { + Flags uint32 + Num int32 + Name [32]int8 + Ver uint32 + __rsvd uint32 + Un [16]byte + _sysctl_size [8]byte + _sysctl_func [8]byte + _sysctl_parent [8]byte + _sysctl_desc [8]byte +} + +func sysctlNodes(mib []int32) ([]sysctlNode, error) { + var olen uintptr + + // Get a list of all sysctl nodes below the given MIB by performing + // a sysctl for the given MIB with CTL_QUERY appended. + mib = append(mib, _CTL_QUERY) + qnode := sysctlNode{Flags: _SYSCTL_VERS_1} + qp := (*byte)(unsafe.Pointer(&qnode)) + sz := unsafe.Sizeof(qnode) + if err := sysctl(mib, nil, &olen, qp, sz); err != nil { + return nil, err + } + + // Now that we know the size, get the actual nodes. + nodes := make([]sysctlNode, olen/sz) + np := (*byte)(unsafe.Pointer(&nodes[0])) + if err := sysctl(mib, np, &olen, qp, sz); err != nil { + return nil, err + } + + return nodes, nil +} + +func nametomib(name string) ([]int32, error) { + // Split name into components. + var parts []string + last := 0 + for i := 0; i < len(name); i++ { + if name[i] == '.' { + parts = append(parts, name[last:i]) + last = i + 1 + } + } + parts = append(parts, name[last:]) + + mib := []int32{} + // Discover the nodes and construct the MIB OID. + for partno, part := range parts { + nodes, err := sysctlNodes(mib) + if err != nil { + return nil, err + } + for _, node := range nodes { + n := make([]byte, 0) + for i := range node.Name { + if node.Name[i] != 0 { + n = append(n, byte(node.Name[i])) + } + } + if string(n) == part { + mib = append(mib, int32(node.Num)) + break + } + } + if len(mib) != partno+1 { + return nil, err + } + } + + return mib, nil +} + +// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's +type aarch64SysctlCPUID struct { + midr uint64 /* Main ID Register */ + revidr uint64 /* Revision ID Register */ + mpidr uint64 /* Multiprocessor Affinity Register */ + aa64dfr0 uint64 /* A64 Debug Feature Register 0 */ + aa64dfr1 uint64 /* A64 Debug Feature Register 1 */ + aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */ + aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */ + aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */ + aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */ + aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */ + aa64pfr0 uint64 /* A64 Processor Feature Register 0 */ + aa64pfr1 uint64 /* A64 Processor Feature Register 1 */ + aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */ + mvfr0 uint32 /* Media and VFP Feature Register 0 */ + mvfr1 uint32 /* Media and VFP Feature Register 1 */ + mvfr2 uint32 /* Media and VFP Feature Register 2 */ + pad uint32 + clidr uint64 /* Cache Level ID Register */ + ctr uint64 /* Cache Type Register */ +} + +func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) { + mib, err := nametomib(name) + if err != nil { + return nil, err + } + + out := aarch64SysctlCPUID{} + n := unsafe.Sizeof(out) + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(len(mib)), + uintptr(unsafe.Pointer(&out)), + uintptr(unsafe.Pointer(&n)), + uintptr(0), + uintptr(0)) + if errno != 0 { + return nil, errno + } + return &out, nil +} + +func doinit() { + cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id") + if err != nil { + setMinimalFeatures() + return + } + parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0) + + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go new file mode 100644 index 00000000..d7b4fb4c --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm.go @@ -0,0 +1,10 @@ +// Copyright 2020 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. + +//go:build !linux && arm +// +build !linux,arm + +package cpu + +func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go new file mode 100644 index 00000000..f8c484f5 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && !netbsd && arm64 +// +build !linux,!netbsd,arm64 + +package cpu + +func doinit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go new file mode 100644 index 00000000..0dafe964 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go @@ -0,0 +1,13 @@ +// Copyright 2020 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. + +//go:build !linux && (mips64 || mips64le) +// +build !linux +// +build mips64 mips64le + +package cpu + +func archInit() { + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go new file mode 100644 index 00000000..dd10eb79 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go @@ -0,0 +1,12 @@ +// Copyright 2022 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. + +//go:build !linux && riscv64 +// +build !linux,riscv64 + +package cpu + +func archInit() { + Initialized = true +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go new file mode 100644 index 00000000..4e8acd16 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go @@ -0,0 +1,17 @@ +// Copyright 2020 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. + +//go:build ppc64 || ppc64le +// +build ppc64 ppc64le + +package cpu + +const cacheLineSize = 128 + +func initOptions() { + options = []option{ + {Name: "darn", Feature: &PPC64.HasDARN}, + {Name: "scv", Feature: &PPC64.HasSCV}, + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go new file mode 100644 index 00000000..bd6c128a --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_riscv64.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build riscv64 +// +build riscv64 + +package cpu + +const cacheLineSize = 32 + +func initOptions() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_s390x.go new file mode 100644 index 00000000..5881b883 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.go @@ -0,0 +1,172 @@ +// Copyright 2020 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 cpu + +const cacheLineSize = 256 + +func initOptions() { + options = []option{ + {Name: "zarch", Feature: &S390X.HasZARCH, Required: true}, + {Name: "stfle", Feature: &S390X.HasSTFLE, Required: true}, + {Name: "ldisp", Feature: &S390X.HasLDISP, Required: true}, + {Name: "eimm", Feature: &S390X.HasEIMM, Required: true}, + {Name: "dfp", Feature: &S390X.HasDFP}, + {Name: "etf3eh", Feature: &S390X.HasETF3EH}, + {Name: "msa", Feature: &S390X.HasMSA}, + {Name: "aes", Feature: &S390X.HasAES}, + {Name: "aescbc", Feature: &S390X.HasAESCBC}, + {Name: "aesctr", Feature: &S390X.HasAESCTR}, + {Name: "aesgcm", Feature: &S390X.HasAESGCM}, + {Name: "ghash", Feature: &S390X.HasGHASH}, + {Name: "sha1", Feature: &S390X.HasSHA1}, + {Name: "sha256", Feature: &S390X.HasSHA256}, + {Name: "sha3", Feature: &S390X.HasSHA3}, + {Name: "sha512", Feature: &S390X.HasSHA512}, + {Name: "vx", Feature: &S390X.HasVX}, + {Name: "vxe", Feature: &S390X.HasVXE}, + } +} + +// bitIsSet reports whether the bit at index is set. The bit index +// is in big endian order, so bit index 0 is the leftmost bit. +func bitIsSet(bits []uint64, index uint) bool { + return bits[index/64]&((1<<63)>>(index%64)) != 0 +} + +// facility is a bit index for the named facility. +type facility uint8 + +const ( + // mandatory facilities + zarch facility = 1 // z architecture mode is active + stflef facility = 7 // store-facility-list-extended + ldisp facility = 18 // long-displacement + eimm facility = 21 // extended-immediate + + // miscellaneous facilities + dfp facility = 42 // decimal-floating-point + etf3eh facility = 30 // extended-translation 3 enhancement + + // cryptography facilities + msa facility = 17 // message-security-assist + msa3 facility = 76 // message-security-assist extension 3 + msa4 facility = 77 // message-security-assist extension 4 + msa5 facility = 57 // message-security-assist extension 5 + msa8 facility = 146 // message-security-assist extension 8 + msa9 facility = 155 // message-security-assist extension 9 + + // vector facilities + vx facility = 129 // vector facility + vxe facility = 135 // vector-enhancements 1 + vxe2 facility = 148 // vector-enhancements 2 +) + +// facilityList contains the result of an STFLE call. +// Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type facilityList struct { + bits [4]uint64 +} + +// Has reports whether the given facilities are present. +func (s *facilityList) Has(fs ...facility) bool { + if len(fs) == 0 { + panic("no facility bits provided") + } + for _, f := range fs { + if !bitIsSet(s.bits[:], uint(f)) { + return false + } + } + return true +} + +// function is the code for the named cryptographic function. +type function uint8 + +const ( + // KM{,A,C,CTR} function codes + aes128 function = 18 // AES-128 + aes192 function = 19 // AES-192 + aes256 function = 20 // AES-256 + + // K{I,L}MD function codes + sha1 function = 1 // SHA-1 + sha256 function = 2 // SHA-256 + sha512 function = 3 // SHA-512 + sha3_224 function = 32 // SHA3-224 + sha3_256 function = 33 // SHA3-256 + sha3_384 function = 34 // SHA3-384 + sha3_512 function = 35 // SHA3-512 + shake128 function = 36 // SHAKE-128 + shake256 function = 37 // SHAKE-256 + + // KLMD function codes + ghash function = 65 // GHASH +) + +// queryResult contains the result of a Query function +// call. Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type queryResult struct { + bits [2]uint64 +} + +// Has reports whether the given functions are present. +func (q *queryResult) Has(fns ...function) bool { + if len(fns) == 0 { + panic("no function codes provided") + } + for _, f := range fns { + if !bitIsSet(q.bits[:], uint(f)) { + return false + } + } + return true +} + +func doinit() { + initS390Xbase() + + // We need implementations of stfle, km and so on + // to detect cryptographic features. + if !haveAsmFunctions() { + return + } + + // optional cryptographic functions + if S390X.HasMSA { + aes := []function{aes128, aes192, aes256} + + // cipher message + km, kmc := kmQuery(), kmcQuery() + S390X.HasAES = km.Has(aes...) + S390X.HasAESCBC = kmc.Has(aes...) + if S390X.HasSTFLE { + facilities := stfle() + if facilities.Has(msa4) { + kmctr := kmctrQuery() + S390X.HasAESCTR = kmctr.Has(aes...) + } + if facilities.Has(msa8) { + kma := kmaQuery() + S390X.HasAESGCM = kma.Has(aes...) + } + } + + // compute message digest + kimd := kimdQuery() // intermediate (no padding) + klmd := klmdQuery() // last (padding) + S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) + S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) + S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) + S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist + sha3 := []function{ + sha3_224, sha3_256, sha3_384, sha3_512, + shake128, shake256, + } + S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) + } +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/vendor/golang.org/x/sys/cpu/cpu_s390x.s new file mode 100644 index 00000000..96f81e20 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.s @@ -0,0 +1,58 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +// +build gc + +#include "textflag.h" + +// func stfle() facilityList +TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 + MOVD $ret+0(FP), R1 + MOVD $3, R0 // last doubleword index to store + XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) + WORD $0xb2b01000 // store facility list extended (STFLE) + RET + +// func kmQuery() queryResult +TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KM-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92E0024 // cipher message (KM) + RET + +// func kmcQuery() queryResult +TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMC-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92F0024 // cipher message with chaining (KMC) + RET + +// func kmctrQuery() queryResult +TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMCTR-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92D4024 // cipher message with counter (KMCTR) + RET + +// func kmaQuery() queryResult +TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMA-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xb9296024 // cipher message with authentication (KMA) + RET + +// func kimdQuery() queryResult +TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KIMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93E0024 // compute intermediate message digest (KIMD) + RET + +// func klmdQuery() queryResult +TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KLMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93F0024 // compute last message digest (KLMD) + RET diff --git a/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/vendor/golang.org/x/sys/cpu/cpu_wasm.go new file mode 100644 index 00000000..7747d888 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_wasm.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build wasm +// +build wasm + +package cpu + +// We're compiling the cpu package for an unknown (software-abstracted) CPU. +// Make CacheLinePad an empty struct and hope that the usual struct alignment +// rules are good enough. + +const cacheLineSize = 0 + +func initOptions() {} + +func archInit() {} diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 00000000..f5aacfc8 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,145 @@ +// Copyright 2018 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. + +//go:build 386 || amd64 || amd64p32 +// +build 386 amd64 amd64p32 + +package cpu + +import "runtime" + +const cacheLineSize = 64 + +func initOptions() { + options = []option{ + {Name: "adx", Feature: &X86.HasADX}, + {Name: "aes", Feature: &X86.HasAES}, + {Name: "avx", Feature: &X86.HasAVX}, + {Name: "avx2", Feature: &X86.HasAVX2}, + {Name: "avx512", Feature: &X86.HasAVX512}, + {Name: "avx512f", Feature: &X86.HasAVX512F}, + {Name: "avx512cd", Feature: &X86.HasAVX512CD}, + {Name: "avx512er", Feature: &X86.HasAVX512ER}, + {Name: "avx512pf", Feature: &X86.HasAVX512PF}, + {Name: "avx512vl", Feature: &X86.HasAVX512VL}, + {Name: "avx512bw", Feature: &X86.HasAVX512BW}, + {Name: "avx512dq", Feature: &X86.HasAVX512DQ}, + {Name: "avx512ifma", Feature: &X86.HasAVX512IFMA}, + {Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI}, + {Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW}, + {Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS}, + {Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ}, + {Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ}, + {Name: "avx512vnni", Feature: &X86.HasAVX512VNNI}, + {Name: "avx512gfni", Feature: &X86.HasAVX512GFNI}, + {Name: "avx512vaes", Feature: &X86.HasAVX512VAES}, + {Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2}, + {Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG}, + {Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, + {Name: "bmi1", Feature: &X86.HasBMI1}, + {Name: "bmi2", Feature: &X86.HasBMI2}, + {Name: "cx16", Feature: &X86.HasCX16}, + {Name: "erms", Feature: &X86.HasERMS}, + {Name: "fma", Feature: &X86.HasFMA}, + {Name: "osxsave", Feature: &X86.HasOSXSAVE}, + {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, + {Name: "popcnt", Feature: &X86.HasPOPCNT}, + {Name: "rdrand", Feature: &X86.HasRDRAND}, + {Name: "rdseed", Feature: &X86.HasRDSEED}, + {Name: "sse3", Feature: &X86.HasSSE3}, + {Name: "sse41", Feature: &X86.HasSSE41}, + {Name: "sse42", Feature: &X86.HasSSE42}, + {Name: "ssse3", Feature: &X86.HasSSSE3}, + + // These capabilities should always be enabled on amd64: + {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, + } +} + +func archInit() { + + Initialized = true + + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasCX16 = isSet(13, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + X86.HasRDRAND = isSet(30, ecx1) + + var osSupportsAVX, osSupportsAVX512 bool + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + + if runtime.GOOS == "darwin" { + // Darwin doesn't save/restore AVX-512 mask registers correctly across signal handlers. + // Since users can't rely on mask register contents, let's not advertise AVX-512 support. + // See issue 49233. + osSupportsAVX512 = false + } else { + // Check if OPMASK and ZMM registers have OS support. + osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) + } + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + _, ebx7, ecx7, edx7 := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasRDSEED = isSet(18, ebx7) + X86.HasADX = isSet(19, ebx7) + + X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension + if X86.HasAVX512 { + X86.HasAVX512F = true + X86.HasAVX512CD = isSet(28, ebx7) + X86.HasAVX512ER = isSet(27, ebx7) + X86.HasAVX512PF = isSet(26, ebx7) + X86.HasAVX512VL = isSet(31, ebx7) + X86.HasAVX512BW = isSet(30, ebx7) + X86.HasAVX512DQ = isSet(17, ebx7) + X86.HasAVX512IFMA = isSet(21, ebx7) + X86.HasAVX512VBMI = isSet(1, ecx7) + X86.HasAVX5124VNNIW = isSet(2, edx7) + X86.HasAVX5124FMAPS = isSet(3, edx7) + X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) + X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) + X86.HasAVX512VNNI = isSet(11, ecx7) + X86.HasAVX512GFNI = isSet(8, ecx7) + X86.HasAVX512VAES = isSet(9, ecx7) + X86.HasAVX512VBMI2 = isSet(6, ecx7) + X86.HasAVX512BITALG = isSet(12, ecx7) + + eax71, _, _, _ := cpuid(7, 1) + X86.HasAVX512BF16 = isSet(5, eax71) + } +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1<> 63)) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var hwCap uint +var hwCap2 uint + +func readHWCAP() error { + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + // e.g. on android /proc/self/auxv is not accessible, so silently + // ignore the error and leave Initialized = false. On some + // architectures (e.g. arm64) doinit() implements a fallback + // readout and will set Initialized = true again. + return err + } + bo := hostByteOrder() + for len(buf) >= 2*(uintSize/8) { + var tag, val uint + switch uintSize { + case 32: + tag = uint(bo.Uint32(buf[0:])) + val = uint(bo.Uint32(buf[4:])) + buf = buf[8:] + case 64: + tag = uint(bo.Uint64(buf[0:])) + val = uint(bo.Uint64(buf[8:])) + buf = buf[16:] + } + switch tag { + case _AT_HWCAP: + hwCap = val + case _AT_HWCAP2: + hwCap2 = val + } + } + return nil +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go new file mode 100644 index 00000000..96134157 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go @@ -0,0 +1,27 @@ +// Copyright 2020 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. + +// Recreate a getsystemcfg syscall handler instead of +// using the one provided by x/sys/unix to avoid having +// the dependency between them. (See golang.org/issue/32102) +// Moreover, this file will be used during the building of +// gccgo's libgo and thus must not used a CGo method. + +//go:build aix && gccgo +// +build aix,gccgo + +package cpu + +import ( + "syscall" +) + +//extern getsystemcfg +func gccgoGetsystemcfg(label uint32) (r uint64) + +func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { + r1 = uintptr(gccgoGetsystemcfg(uint32(label))) + e1 = syscall.GetErrno() + return +} diff --git a/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go new file mode 100644 index 00000000..904be42f --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go @@ -0,0 +1,36 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Minimal copy of x/sys/unix so the cpu package can make a +// system call on AIX without depending on x/sys/unix. +// (See golang.org/issue/32102) + +//go:build aix && ppc64 && gc +// +build aix,ppc64,gc + +package cpu + +import ( + "syscall" + "unsafe" +) + +//go:cgo_import_dynamic libc_getsystemcfg getsystemcfg "libc.a/shr_64.o" + +//go:linkname libc_getsystemcfg libc_getsystemcfg + +type syscallFunc uintptr + +var libc_getsystemcfg syscallFunc + +type errno = syscall.Errno + +// Implemented in runtime/syscall_aix.go. +func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) +func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err errno) + +func callgetsystemcfg(label int) (r1 uintptr, e1 errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_getsystemcfg)), 1, uintptr(label), 0, 0, 0, 0, 0) + return +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/.gitignore b/vendor/gopkg.in/src-d/go-billy.v4/.gitignore new file mode 100644 index 00000000..7aeb4669 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/.gitignore @@ -0,0 +1,4 @@ +/coverage.txt +/vendor +Gopkg.lock +Gopkg.toml diff --git a/vendor/gopkg.in/src-d/go-billy.v4/.travis.yml b/vendor/gopkg.in/src-d/go-billy.v4/.travis.yml new file mode 100644 index 00000000..a70b470d --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/.travis.yml @@ -0,0 +1,17 @@ +language: go + +go: + - 1.9.x + - 1.10.x + +go_import_path: gopkg.in/src-d/go-billy.v4 + +install: + - go get -v -t ./... + +script: + - make test-coverage + - ./.ci/test-building-binaries-for-supported-os.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/gopkg.in/src-d/go-billy.v4/DCO b/vendor/gopkg.in/src-d/go-billy.v4/DCO new file mode 100644 index 00000000..29c1b920 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/DCO @@ -0,0 +1,25 @@ + Developer's Certificate of Origin 1.1 + + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/gopkg.in/src-d/go-billy.v4/LICENSE b/vendor/gopkg.in/src-d/go-billy.v4/LICENSE new file mode 100644 index 00000000..9d607568 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Sourced Technologies S.L. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS b/vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS new file mode 100644 index 00000000..8dbba477 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/MAINTAINERS @@ -0,0 +1 @@ +Máximo Cuadros (@mcuadros) diff --git a/vendor/gopkg.in/src-d/go-billy.v4/Makefile b/vendor/gopkg.in/src-d/go-billy.v4/Makefile new file mode 100644 index 00000000..19e74337 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/Makefile @@ -0,0 +1,25 @@ +# General +WORKDIR = $(PWD) + +# Go parameters +GOCMD = go +GOTEST = $(GOCMD) test -v + +# Coverage +COVERAGE_REPORT = coverage.txt +COVERAGE_PROFILE = profile.out +COVERAGE_MODE = atomic + +test-coverage: + cd $(WORKDIR); \ + echo "" > $(COVERAGE_REPORT); \ + for dir in `find . -name "*.go" | grep -o '.*/' | sort | uniq`; do \ + $(GOTEST) $$dir -coverprofile=$(COVERAGE_PROFILE) -covermode=$(COVERAGE_MODE); \ + if [ $$? != 0 ]; then \ + exit 2; \ + fi; \ + if [ -f $(COVERAGE_PROFILE) ]; then \ + cat $(COVERAGE_PROFILE) >> $(COVERAGE_REPORT); \ + rm $(COVERAGE_PROFILE); \ + fi; \ + done; \ diff --git a/vendor/gopkg.in/src-d/go-billy.v4/README.md b/vendor/gopkg.in/src-d/go-billy.v4/README.md new file mode 100644 index 00000000..ae4a3f86 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/README.md @@ -0,0 +1,72 @@ +# go-billy [![GoDoc](https://godoc.org/gopkg.in/src-d/go-billy.v4?status.svg)](https://godoc.org/gopkg.in/src-d/go-billy.v4) [![Build Status](https://travis-ci.com/src-d/go-billy.svg)](https://travis-ci.com/src-d/go-billy) [![Build status](https://ci.appveyor.com/api/projects/status/vx2qn6vlakbi724t?svg=true)](https://ci.appveyor.com/project/mcuadros/go-billy) [![codecov](https://codecov.io/gh/src-d/go-billy/branch/master/graph/badge.svg)](https://codecov.io/gh/src-d/go-billy) + +The missing interface filesystem abstraction for Go. +Billy implements an interface based on the `os` standard library, allowing to develop applications without dependency on the underlying storage. Makes it virtually free to implement mocks and testing over filesystem operations. + +Billy was born as part of [src-d/go-git](https://github.com/src-d/go-git) project. + +## Installation + +```go +go get -u gopkg.in/src-d/go-billy.v4/... +``` + +## Usage + +Billy exposes filesystems using the +[`Filesystem` interface](https://godoc.org/github.com/src-d/go-billy#Filesystem). +Each filesystem implementation gives you a `New` method, whose arguments depend on +the implementation itself, that returns a new `Filesystem`. + +The following example caches in memory all readable files in a directory from any +billy's filesystem implementation. + +```go +func LoadToMemory(origin billy.Filesystem, path string) (*memory.Memory, error) { + memory := memory.New() + + files, err := origin.ReadDir("/") + if err != nil { + return nil, err + } + + for _, file := range files { + if file.IsDir() { + continue + } + + src, err := origin.Open(file.Name()) + if err != nil { + return nil, err + } + + dst, err := memory.Create(file.Name()) + if err != nil { + return nil, err + } + + if _, err = io.Copy(dst, src); err != nil { + return nil, err + } + + if err := dst.Close(); err != nil { + return nil, err + } + + if err := src.Close(); err != nil { + return nil, err + } + } + + return memory, nil +} +``` + +## Why billy? + +The library billy deals with storage systems and Billy is the name of a well-known, IKEA +bookcase. That's it. + +## License + +Apache License Version 2.0, see [LICENSE](LICENSE) diff --git a/vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml b/vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml new file mode 100644 index 00000000..91c0b40c --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/appveyor.yml @@ -0,0 +1,15 @@ +version: "{build}" +platform: x64 + +clone_folder: c:\gopath\src\gopkg.in\src-d\go-billy.v4 + +environment: + GOPATH: c:\gopath + +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - go version + - go get -v -t ./... + +build_script: + - go test -v ./... diff --git a/vendor/gopkg.in/src-d/go-billy.v4/fs.go b/vendor/gopkg.in/src-d/go-billy.v4/fs.go new file mode 100644 index 00000000..a9efccde --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/fs.go @@ -0,0 +1,202 @@ +package billy + +import ( + "errors" + "io" + "os" + "time" +) + +var ( + ErrReadOnly = errors.New("read-only filesystem") + ErrNotSupported = errors.New("feature not supported") + ErrCrossedBoundary = errors.New("chroot boundary crossed") +) + +// Capability holds the supported features of a billy filesystem. This does +// not mean that the capability has to be supported by the underlying storage. +// For example, a billy filesystem may support WriteCapability but the +// storage be mounted in read only mode. +type Capability uint64 + +const ( + // WriteCapability means that the fs is writable. + WriteCapability Capability = 1 << iota + // ReadCapability means that the fs is readable. + ReadCapability + // ReadAndWriteCapability is the ability to open a file in read and write mode. + ReadAndWriteCapability + // SeekCapability means it is able to move position inside the file. + SeekCapability + // TruncateCapability means that a file can be truncated. + TruncateCapability + // LockCapability is the ability to lock a file. + LockCapability + + // DefaultCapabilities lists all capable features supported by filesystems + // without Capability interface. This list should not be changed until a + // major version is released. + DefaultCapabilities Capability = WriteCapability | ReadCapability | + ReadAndWriteCapability | SeekCapability | TruncateCapability | + LockCapability + + // AllCapabilities lists all capable features. + AllCapabilities Capability = WriteCapability | ReadCapability | + ReadAndWriteCapability | SeekCapability | TruncateCapability | + LockCapability +) + +// Filesystem abstract the operations in a storage-agnostic interface. +// Each method implementation mimics the behavior of the equivalent functions +// at the os package from the standard library. +type Filesystem interface { + Basic + TempFile + Dir + Symlink + Chroot +} + +// Basic abstract the basic operations in a storage-agnostic interface as +// an extension to the Basic interface. +type Basic interface { + // Create 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. + Create(filename string) (File, error) + // Open 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. + Open(filename string) (File, error) + // OpenFile 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. + OpenFile(filename string, flag int, perm os.FileMode) (File, error) + // Stat returns a FileInfo describing the named file. + Stat(filename string) (os.FileInfo, error) + // Rename renames (moves) oldpath to newpath. If newpath already exists and + // is not a directory, Rename replaces it. OS-specific restrictions may + // apply when oldpath and newpath are in different directories. + Rename(oldpath, newpath string) error + // Remove removes the named file or directory. + Remove(filename string) error + // Join joins any number of path elements into a single path, adding a + // Separator if necessary. Join calls filepath.Clean on the result; in + // particular, all empty strings are ignored. On Windows, the result is a + // UNC path if and only if the first path element is a UNC path. + Join(elem ...string) string +} + +type TempFile interface { + // 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. + TempFile(dir, prefix string) (File, error) +} + +// Dir abstract the dir related operations in a storage-agnostic interface as +// an extension to the Basic interface. +type Dir interface { + // ReadDir reads the directory named by dirname and returns a list of + // directory entries sorted by filename. + ReadDir(path string) ([]os.FileInfo, error) + // MkdirAll creates a directory named path, along with any necessary + // parents, and returns nil, or else returns an error. The permission bits + // perm are used for all directories that MkdirAll creates. If path is/ + // already a directory, MkdirAll does nothing and returns nil. + MkdirAll(filename string, perm os.FileMode) error +} + +// Symlink abstract the symlink related operations in a storage-agnostic +// interface as an extension to the Basic interface. +type Symlink interface { + // Lstat returns a FileInfo describing the named file. If the file is a + // symbolic link, the returned FileInfo describes the symbolic link. Lstat + // makes no attempt to follow the link. + Lstat(filename string) (os.FileInfo, error) + // Symlink creates a symbolic-link from link to target. target may be an + // absolute or relative path, and need not refer to an existing node. + // Parent directories of link are created as necessary. + Symlink(target, link string) error + // Readlink returns the target path of link. + Readlink(link string) (string, error) +} + +// Change abstract the FileInfo change related operations in a storage-agnostic +// interface as an extension to the Basic interface +type Change interface { + // Chmod changes the mode of the named file to mode. If the file is a + // symbolic link, it changes the mode of the link's target. + Chmod(name string, mode os.FileMode) error + // Lchown changes the numeric uid and gid of the named file. If the file is + // a symbolic link, it changes the uid and gid of the link itself. + Lchown(name string, uid, gid int) error + // Chown changes the numeric uid and gid of the named file. If the file is a + // symbolic link, it changes the uid and gid of the link's target. + Chown(name string, uid, gid int) error + // Chtimes changes the access and modification times of the named file, + // similar to the Unix utime() or utimes() functions. + // + // The underlying filesystem may truncate or round the values to a less + // precise time unit. + Chtimes(name string, atime time.Time, mtime time.Time) error +} + +// Chroot abstract the chroot related operations in a storage-agnostic interface +// as an extension to the Basic interface. +type Chroot interface { + // Chroot returns a new filesystem from the same type where the new root is + // the given path. Files outside of the designated directory tree cannot be + // accessed. + Chroot(path string) (Filesystem, error) + // Root returns the root path of the filesystem. + Root() string +} + +// File represent a file, being a subset of the os.File +type File interface { + // Name returns the name of the file as presented to Open. + Name() string + io.Writer + io.Reader + io.ReaderAt + io.Seeker + io.Closer + // Lock locks the file like e.g. flock. It protects against access from + // other processes. + Lock() error + // Unlock unlocks the file. + Unlock() error + // Truncate the file. + Truncate(size int64) error +} + +// Capable interface can return the available features of a filesystem. +type Capable interface { + // Capabilities returns the capabilities of a filesystem in bit flags. + Capabilities() Capability +} + +// Capabilities returns the features supported by a filesystem. If the FS +// does not implement Capable interface it returns all features. +func Capabilities(fs Basic) Capability { + capable, ok := fs.(Capable) + if !ok { + return DefaultCapabilities + } + + return capable.Capabilities() +} + +// CapabilityCheck tests the filesystem for the provided capabilities and +// returns true in case it supports all of them. +func CapabilityCheck(fs Basic, capabilities Capability) bool { + fsCaps := Capabilities(fs) + return fsCaps&capabilities == capabilities +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go b/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go new file mode 100644 index 00000000..44ddb3db --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go @@ -0,0 +1,242 @@ +package chroot + +import ( + "os" + "path/filepath" + "strings" + + "gopkg.in/src-d/go-billy.v4" + "gopkg.in/src-d/go-billy.v4/helper/polyfill" +) + +// ChrootHelper is a helper to implement billy.Chroot. +type ChrootHelper struct { + underlying billy.Filesystem + base string +} + +// New creates a new filesystem wrapping up the given 'fs'. +// The created filesystem has its base in the given ChrootHelperectory of the +// underlying filesystem. +func New(fs billy.Basic, base string) billy.Filesystem { + return &ChrootHelper{ + underlying: polyfill.New(fs), + base: base, + } +} + +func (fs *ChrootHelper) underlyingPath(filename string) (string, error) { + if isCrossBoundaries(filename) { + return "", billy.ErrCrossedBoundary + } + + return fs.Join(fs.Root(), filename), nil +} + +func isCrossBoundaries(path string) bool { + path = filepath.ToSlash(path) + path = filepath.Clean(path) + + return strings.HasPrefix(path, ".."+string(filepath.Separator)) +} + +func (fs *ChrootHelper) Create(filename string) (billy.File, error) { + fullpath, err := fs.underlyingPath(filename) + if err != nil { + return nil, err + } + + f, err := fs.underlying.Create(fullpath) + if err != nil { + return nil, err + } + + return newFile(fs, f, filename), nil +} + +func (fs *ChrootHelper) Open(filename string) (billy.File, error) { + fullpath, err := fs.underlyingPath(filename) + if err != nil { + return nil, err + } + + f, err := fs.underlying.Open(fullpath) + if err != nil { + return nil, err + } + + return newFile(fs, f, filename), nil +} + +func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (billy.File, error) { + fullpath, err := fs.underlyingPath(filename) + if err != nil { + return nil, err + } + + f, err := fs.underlying.OpenFile(fullpath, flag, mode) + if err != nil { + return nil, err + } + + return newFile(fs, f, filename), nil +} + +func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) { + fullpath, err := fs.underlyingPath(filename) + if err != nil { + return nil, err + } + + return fs.underlying.Stat(fullpath) +} + +func (fs *ChrootHelper) Rename(from, to string) error { + var err error + from, err = fs.underlyingPath(from) + if err != nil { + return err + } + + to, err = fs.underlyingPath(to) + if err != nil { + return err + } + + return fs.underlying.Rename(from, to) +} + +func (fs *ChrootHelper) Remove(path string) error { + fullpath, err := fs.underlyingPath(path) + if err != nil { + return err + } + + return fs.underlying.Remove(fullpath) +} + +func (fs *ChrootHelper) Join(elem ...string) string { + return fs.underlying.Join(elem...) +} + +func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) { + fullpath, err := fs.underlyingPath(dir) + if err != nil { + return nil, err + } + + f, err := fs.underlying.(billy.TempFile).TempFile(fullpath, prefix) + if err != nil { + return nil, err + } + + return newFile(fs, f, fs.Join(dir, filepath.Base(f.Name()))), nil +} + +func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) { + fullpath, err := fs.underlyingPath(path) + if err != nil { + return nil, err + } + + return fs.underlying.(billy.Dir).ReadDir(fullpath) +} + +func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error { + fullpath, err := fs.underlyingPath(filename) + if err != nil { + return err + } + + return fs.underlying.(billy.Dir).MkdirAll(fullpath, perm) +} + +func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) { + fullpath, err := fs.underlyingPath(filename) + if err != nil { + return nil, err + } + + return fs.underlying.(billy.Symlink).Lstat(fullpath) +} + +func (fs *ChrootHelper) Symlink(target, link string) error { + target = filepath.FromSlash(target) + + // only rewrite target if it's already absolute + if filepath.IsAbs(target) || strings.HasPrefix(target, string(filepath.Separator)) { + target = fs.Join(fs.Root(), target) + target = filepath.Clean(filepath.FromSlash(target)) + } + + link, err := fs.underlyingPath(link) + if err != nil { + return err + } + + return fs.underlying.(billy.Symlink).Symlink(target, link) +} + +func (fs *ChrootHelper) Readlink(link string) (string, error) { + fullpath, err := fs.underlyingPath(link) + if err != nil { + return "", err + } + + target, err := fs.underlying.(billy.Symlink).Readlink(fullpath) + if err != nil { + return "", err + } + + if !filepath.IsAbs(target) && !strings.HasPrefix(target, string(filepath.Separator)) { + return target, nil + } + + target, err = filepath.Rel(fs.base, target) + if err != nil { + return "", err + } + + return string(os.PathSeparator) + target, nil +} + +func (fs *ChrootHelper) Chroot(path string) (billy.Filesystem, error) { + fullpath, err := fs.underlyingPath(path) + if err != nil { + return nil, err + } + + return New(fs.underlying, fullpath), nil +} + +func (fs *ChrootHelper) Root() string { + return fs.base +} + +func (fs *ChrootHelper) Underlying() billy.Basic { + return fs.underlying +} + +// Capabilities implements the Capable interface. +func (fs *ChrootHelper) Capabilities() billy.Capability { + return billy.Capabilities(fs.underlying) +} + +type file struct { + billy.File + name string +} + +func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File { + filename = fs.Join(fs.Root(), filename) + filename, _ = filepath.Rel(fs.Root(), filename) + + return &file{ + File: f, + name: filename, + } +} + +func (f *file) Name() string { + return f.name +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go b/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go new file mode 100644 index 00000000..f613c255 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go @@ -0,0 +1,105 @@ +package polyfill + +import ( + "os" + "path/filepath" + + "gopkg.in/src-d/go-billy.v4" +) + +// Polyfill is a helper that implements all missing method from billy.Filesystem. +type Polyfill struct { + billy.Basic + c capabilities +} + +type capabilities struct{ tempfile, dir, symlink, chroot bool } + +// New creates a new filesystem wrapping up 'fs' the intercepts all the calls +// made and errors if fs doesn't implement any of the billy interfaces. +func New(fs billy.Basic) billy.Filesystem { + if original, ok := fs.(billy.Filesystem); ok { + return original + } + + h := &Polyfill{Basic: fs} + + _, h.c.tempfile = h.Basic.(billy.TempFile) + _, h.c.dir = h.Basic.(billy.Dir) + _, h.c.symlink = h.Basic.(billy.Symlink) + _, h.c.chroot = h.Basic.(billy.Chroot) + return h +} + +func (h *Polyfill) TempFile(dir, prefix string) (billy.File, error) { + if !h.c.tempfile { + return nil, billy.ErrNotSupported + } + + return h.Basic.(billy.TempFile).TempFile(dir, prefix) +} + +func (h *Polyfill) ReadDir(path string) ([]os.FileInfo, error) { + if !h.c.dir { + return nil, billy.ErrNotSupported + } + + return h.Basic.(billy.Dir).ReadDir(path) +} + +func (h *Polyfill) MkdirAll(filename string, perm os.FileMode) error { + if !h.c.dir { + return billy.ErrNotSupported + } + + return h.Basic.(billy.Dir).MkdirAll(filename, perm) +} + +func (h *Polyfill) Symlink(target, link string) error { + if !h.c.symlink { + return billy.ErrNotSupported + } + + return h.Basic.(billy.Symlink).Symlink(target, link) +} + +func (h *Polyfill) Readlink(link string) (string, error) { + if !h.c.symlink { + return "", billy.ErrNotSupported + } + + return h.Basic.(billy.Symlink).Readlink(link) +} + +func (h *Polyfill) Lstat(path string) (os.FileInfo, error) { + if !h.c.symlink { + return nil, billy.ErrNotSupported + } + + return h.Basic.(billy.Symlink).Lstat(path) +} + +func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) { + if !h.c.chroot { + return nil, billy.ErrNotSupported + } + + return h.Basic.(billy.Chroot).Chroot(path) +} + +func (h *Polyfill) Root() string { + if !h.c.chroot { + return string(filepath.Separator) + } + + return h.Basic.(billy.Chroot).Root() +} + +func (h *Polyfill) Underlying() billy.Basic { + return h.Basic +} + +// Capabilities implements the Capable interface. +func (h *Polyfill) Capabilities() billy.Capability { + return billy.Capabilities(h.Basic) +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go new file mode 100644 index 00000000..ff35a3ba --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go @@ -0,0 +1,139 @@ +// Package osfs provides a billy filesystem for the OS. +package osfs // import "gopkg.in/src-d/go-billy.v4/osfs" + +import ( + "io/ioutil" + "os" + "path/filepath" + "sync" + + "gopkg.in/src-d/go-billy.v4" + "gopkg.in/src-d/go-billy.v4/helper/chroot" +) + +const ( + defaultDirectoryMode = 0755 + defaultCreateMode = 0666 +) + +// OS is a filesystem based on the os filesystem. +type OS struct{} + +// New returns a new OS filesystem. +func New(baseDir string) billy.Filesystem { + return chroot.New(&OS{}, baseDir) +} + +func (fs *OS) Create(filename string) (billy.File, error) { + return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, defaultCreateMode) +} + +func (fs *OS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) { + if flag&os.O_CREATE != 0 { + if err := fs.createDir(filename); err != nil { + return nil, err + } + } + + f, err := os.OpenFile(filename, flag, perm) + if err != nil { + return nil, err + } + return &file{File: f}, err +} + +func (fs *OS) createDir(fullpath string) error { + dir := filepath.Dir(fullpath) + if dir != "." { + if err := os.MkdirAll(dir, defaultDirectoryMode); err != nil { + return err + } + } + + return nil +} + +func (fs *OS) ReadDir(path string) ([]os.FileInfo, error) { + l, err := ioutil.ReadDir(path) + if err != nil { + return nil, err + } + + var s = make([]os.FileInfo, len(l)) + for i, f := range l { + s[i] = f + } + + return s, nil +} + +func (fs *OS) Rename(from, to string) error { + if err := fs.createDir(to); err != nil { + return err + } + + return os.Rename(from, to) +} + +func (fs *OS) MkdirAll(path string, perm os.FileMode) error { + return os.MkdirAll(path, defaultDirectoryMode) +} + +func (fs *OS) Open(filename string) (billy.File, error) { + return fs.OpenFile(filename, os.O_RDONLY, 0) +} + +func (fs *OS) Stat(filename string) (os.FileInfo, error) { + return os.Stat(filename) +} + +func (fs *OS) Remove(filename string) error { + return os.Remove(filename) +} + +func (fs *OS) TempFile(dir, prefix string) (billy.File, error) { + if err := fs.createDir(dir + string(os.PathSeparator)); err != nil { + return nil, err + } + + f, err := ioutil.TempFile(dir, prefix) + if err != nil { + return nil, err + } + return &file{File: f}, nil +} + +func (fs *OS) Join(elem ...string) string { + return filepath.Join(elem...) +} + +func (fs *OS) RemoveAll(path string) error { + return os.RemoveAll(filepath.Clean(path)) +} + +func (fs *OS) Lstat(filename string) (os.FileInfo, error) { + return os.Lstat(filepath.Clean(filename)) +} + +func (fs *OS) Symlink(target, link string) error { + if err := fs.createDir(link); err != nil { + return err + } + + return os.Symlink(target, link) +} + +func (fs *OS) Readlink(link string) (string, error) { + return os.Readlink(link) +} + +// Capabilities implements the Capable interface. +func (fs *OS) Capabilities() billy.Capability { + return billy.DefaultCapabilities +} + +// file is a wrapper for an os.File which adds support for file locking. +type file struct { + *os.File + m sync.Mutex +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go new file mode 100644 index 00000000..144cde1c --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go @@ -0,0 +1,21 @@ +// +build !windows + +package osfs + +import ( + "golang.org/x/sys/unix" +) + +func (f *file) Lock() error { + f.m.Lock() + defer f.m.Unlock() + + return unix.Flock(int(f.File.Fd()), unix.LOCK_EX) +} + +func (f *file) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + return unix.Flock(int(f.File.Fd()), unix.LOCK_UN) +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go new file mode 100644 index 00000000..5eb98829 --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go @@ -0,0 +1,57 @@ +// +build windows + +package osfs + +import ( + "os" + "runtime" + "unsafe" + + "golang.org/x/sys/windows" +) + +type fileInfo struct { + os.FileInfo + name string +} + +func (fi *fileInfo) Name() string { + return fi.name +} + +var ( + kernel32DLL = windows.NewLazySystemDLL("kernel32.dll") + lockFileExProc = kernel32DLL.NewProc("LockFileEx") + unlockFileProc = kernel32DLL.NewProc("UnlockFile") +) + +const ( + lockfileExclusiveLock = 0x2 +) + +func (f *file) Lock() error { + f.m.Lock() + defer f.m.Unlock() + + var overlapped windows.Overlapped + // err is always non-nil as per sys/windows semantics. + ret, _, err := lockFileExProc.Call(f.File.Fd(), lockfileExclusiveLock, 0, 0xFFFFFFFF, 0, + uintptr(unsafe.Pointer(&overlapped))) + runtime.KeepAlive(&overlapped) + if ret == 0 { + return err + } + return nil +} + +func (f *file) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // err is always non-nil as per sys/windows semantics. + ret, _, err := unlockFileProc.Call(f.File.Fd(), 0, 0, 0xFFFFFFFF, 0) + if ret == 0 { + return err + } + return nil +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go b/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go new file mode 100644 index 00000000..fdcb3e5f --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go @@ -0,0 +1,111 @@ +package util + +import ( + "path/filepath" + "sort" + "strings" + + "gopkg.in/src-d/go-billy.v4" +) + +// Glob returns the names of all files matching pattern or nil +// if there is no matching file. The syntax of patterns is the same +// as in Match. The pattern may describe hierarchical names such as +// /usr/*/bin/ed (assuming the Separator is '/'). +// +// Glob ignores file system errors such as I/O errors reading directories. +// The only possible returned error is ErrBadPattern, when pattern +// is malformed. +// +// Function originally from https://golang.org/src/path/filepath/match_test.go +func Glob(fs billy.Filesystem, pattern string) (matches []string, err error) { + if !hasMeta(pattern) { + if _, err = fs.Lstat(pattern); err != nil { + return nil, nil + } + return []string{pattern}, nil + } + + dir, file := filepath.Split(pattern) + // Prevent infinite recursion. See issue 15879. + if dir == pattern { + return nil, filepath.ErrBadPattern + } + + var m []string + m, err = Glob(fs, cleanGlobPath(dir)) + if err != nil { + return + } + for _, d := range m { + matches, err = glob(fs, d, file, matches) + if err != nil { + return + } + } + return +} + +// cleanGlobPath prepares path for glob matching. +func cleanGlobPath(path string) string { + switch path { + case "": + return "." + case string(filepath.Separator): + // do nothing to the path + return path + default: + return path[0 : len(path)-1] // chop off trailing separator + } +} + +// glob searches for files matching pattern in the directory dir +// and appends them to matches. If the directory cannot be +// opened, it returns the existing matches. New matches are +// added in lexicographical order. +func glob(fs billy.Filesystem, dir, pattern string, matches []string) (m []string, e error) { + m = matches + fi, err := fs.Stat(dir) + if err != nil { + return + } + + if !fi.IsDir() { + return + } + + names, _ := readdirnames(fs, dir) + sort.Strings(names) + + for _, n := range names { + matched, err := filepath.Match(pattern, n) + if err != nil { + return m, err + } + if matched { + m = append(m, filepath.Join(dir, n)) + } + } + return +} + +// hasMeta reports whether path contains any of the magic characters +// recognized by Match. +func hasMeta(path string) bool { + // TODO(niemeyer): Should other magic characters be added here? + return strings.ContainsAny(path, "*?[") +} + +func readdirnames(fs billy.Filesystem, dir string) ([]string, error) { + files, err := fs.ReadDir(dir) + if err != nil { + return nil, err + } + + var names []string + for _, file := range files { + names = append(names, file.Name()) + } + + return names, nil +} diff --git a/vendor/gopkg.in/src-d/go-billy.v4/util/util.go b/vendor/gopkg.in/src-d/go-billy.v4/util/util.go new file mode 100644 index 00000000..cf7fb57f --- /dev/null +++ b/vendor/gopkg.in/src-d/go-billy.v4/util/util.go @@ -0,0 +1,224 @@ +package util + +import ( + "io" + "os" + "path/filepath" + "strconv" + "sync" + "time" + + "gopkg.in/src-d/go-billy.v4" +) + +// RemoveAll removes path and any children it contains. It removes everything it +// can but returns the first error it encounters. If the path does not exist, +// RemoveAll returns nil (no error). +func RemoveAll(fs billy.Basic, path string) error { + fs, path = getUnderlyingAndPath(fs, path) + + if r, ok := fs.(removerAll); ok { + return r.RemoveAll(path) + } + + return removeAll(fs, path) +} + +type removerAll interface { + RemoveAll(string) error +} + +func removeAll(fs billy.Basic, path string) error { + // This implementation is adapted from os.RemoveAll. + + // Simple case: if Remove works, we're done. + err := fs.Remove(path) + if err == nil || os.IsNotExist(err) { + return nil + } + + // Otherwise, is this a directory we need to recurse into? + dir, serr := fs.Stat(path) + if serr != nil { + if os.IsNotExist(serr) { + return nil + } + + return serr + } + + if !dir.IsDir() { + // Not a directory; return the error from Remove. + return err + } + + dirfs, ok := fs.(billy.Dir) + if !ok { + return billy.ErrNotSupported + } + + // Directory. + fis, err := dirfs.ReadDir(path) + if err != nil { + if os.IsNotExist(err) { + // Race. It was deleted between the Lstat and Open. + // Return nil per RemoveAll's docs. + return nil + } + + return err + } + + // Remove contents & return first error. + err = nil + for _, fi := range fis { + cpath := fs.Join(path, fi.Name()) + err1 := removeAll(fs, cpath) + if err == nil { + err = err1 + } + } + + // Remove directory. + err1 := fs.Remove(path) + if err1 == nil || os.IsNotExist(err1) { + return nil + } + + if err == nil { + err = err1 + } + + return err + +} + +// WriteFile writes data to a file named by filename in the given filesystem. +// If the file does not exist, WriteFile creates it with permissions perm; +// otherwise WriteFile truncates it before writing. +func WriteFile(fs billy.Basic, filename string, data []byte, perm os.FileMode) error { + f, err := fs.OpenFile(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 +} + +// Random number state. +// We generate random temporary file names so that there's a good +// chance the file doesn't exist yet - keeps the number of tries in +// TempFile to a minimum. +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:] +} + +// 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 TempFile(fs billy.Basic, dir, prefix string) (f billy.File, err error) { + // This implementation is based on stdlib ioutil.TempFile. + + if dir == "" { + dir = os.TempDir() + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + name := filepath.Join(dir, prefix+nextSuffix()) + f, err = fs.OpenFile(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 +} + +// TempDir creates a new temporary directory in the directory dir +// with a name beginning with prefix and returns the path of the +// new directory. If dir is the empty string, TempDir uses the +// default directory for temporary files (see os.TempDir). +// Multiple programs calling TempDir simultaneously +// will not choose the same directory. It is the caller's responsibility +// to remove the directory when no longer needed. +func TempDir(fs billy.Dir, dir, prefix string) (name string, err error) { + // This implementation is based on stdlib ioutil.TempDir + + if dir == "" { + dir = os.TempDir() + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + try := filepath.Join(dir, prefix+nextSuffix()) + err = fs.MkdirAll(try, 0700) + if os.IsExist(err) { + if nconflict++; nconflict > 10 { + randmu.Lock() + rand = reseed() + randmu.Unlock() + } + continue + } + if os.IsNotExist(err) { + if _, err := os.Stat(dir); os.IsNotExist(err) { + return "", err + } + } + if err == nil { + name = try + } + break + } + return +} + +type underlying interface { + Underlying() billy.Basic +} + +func getUnderlyingAndPath(fs billy.Basic, path string) (billy.Basic, string) { + u, ok := fs.(underlying) + if !ok { + return fs, path + } + if ch, ok := fs.(billy.Chroot); ok { + path = fs.Join(ch.Root(), path) + } + + return u.Underlying(), path +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f91aa18e..69cba9f4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -16,26 +16,45 @@ github.com/devtron-labs/common-lib/pubsub-lib github.com/devtron-labs/common-lib/utils # github.com/devtron-labs/go-git v1.5.0 ## explicit; go 1.20 +github.com/devtron-labs/go-git github.com/devtron-labs/go-git/config +github.com/devtron-labs/go-git/internal/revision github.com/devtron-labs/go-git/internal/url github.com/devtron-labs/go-git/plumbing +github.com/devtron-labs/go-git/plumbing/cache github.com/devtron-labs/go-git/plumbing/filemode github.com/devtron-labs/go-git/plumbing/format/config github.com/devtron-labs/go-git/plumbing/format/diff +github.com/devtron-labs/go-git/plumbing/format/gitignore +github.com/devtron-labs/go-git/plumbing/format/idxfile github.com/devtron-labs/go-git/plumbing/format/index +github.com/devtron-labs/go-git/plumbing/format/objfile +github.com/devtron-labs/go-git/plumbing/format/packfile github.com/devtron-labs/go-git/plumbing/format/pktline github.com/devtron-labs/go-git/plumbing/object github.com/devtron-labs/go-git/plumbing/protocol/packp github.com/devtron-labs/go-git/plumbing/protocol/packp/capability github.com/devtron-labs/go-git/plumbing/protocol/packp/sideband +github.com/devtron-labs/go-git/plumbing/revlist github.com/devtron-labs/go-git/plumbing/storer github.com/devtron-labs/go-git/plumbing/transport +github.com/devtron-labs/go-git/plumbing/transport/client +github.com/devtron-labs/go-git/plumbing/transport/file +github.com/devtron-labs/go-git/plumbing/transport/git +github.com/devtron-labs/go-git/plumbing/transport/http +github.com/devtron-labs/go-git/plumbing/transport/internal/common +github.com/devtron-labs/go-git/plumbing/transport/server +github.com/devtron-labs/go-git/plumbing/transport/ssh github.com/devtron-labs/go-git/storage +github.com/devtron-labs/go-git/storage/filesystem +github.com/devtron-labs/go-git/storage/filesystem/dotgit github.com/devtron-labs/go-git/storage/memory github.com/devtron-labs/go-git/utils/binary github.com/devtron-labs/go-git/utils/diff github.com/devtron-labs/go-git/utils/ioutil github.com/devtron-labs/go-git/utils/merkletrie +github.com/devtron-labs/go-git/utils/merkletrie/filesystem +github.com/devtron-labs/go-git/utils/merkletrie/index github.com/devtron-labs/go-git/utils/merkletrie/internal/frame github.com/devtron-labs/go-git/utils/merkletrie/noder # github.com/devtron-labs/protos v0.0.0-20230503113602-282404f70fd2 @@ -91,6 +110,7 @@ github.com/jbenet/go-context/io github.com/jinzhu/inflection # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd ## explicit +github.com/kevinburke/ssh_config # github.com/klauspost/compress v1.15.12 ## explicit; go 1.17 # github.com/matttproud/golang_protobuf_extensions v1.0.1 @@ -100,6 +120,7 @@ github.com/matttproud/golang_protobuf_extensions/pbutil ## explicit; go 1.15 # github.com/mitchellh/go-homedir v1.1.0 ## explicit +github.com/mitchellh/go-homedir # github.com/nats-io/jwt/v2 v2.3.0 ## explicit; go 1.16 # github.com/nats-io/nats.go v1.19.0 @@ -171,6 +192,7 @@ github.com/tidwall/match github.com/tidwall/pretty # github.com/xanzy/ssh-agent v0.2.1 ## explicit +github.com/xanzy/ssh-agent # go.uber.org/atomic v1.7.0 ## explicit; go 1.13 go.uber.org/atomic @@ -187,8 +209,14 @@ go.uber.org/zap/internal/exit go.uber.org/zap/zapcore # golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa ## explicit; go 1.17 +golang.org/x/crypto/blowfish golang.org/x/crypto/cast5 +golang.org/x/crypto/chacha20 +golang.org/x/crypto/curve25519 +golang.org/x/crypto/curve25519/internal/field golang.org/x/crypto/ed25519 +golang.org/x/crypto/internal/poly1305 +golang.org/x/crypto/internal/subtle golang.org/x/crypto/openpgp golang.org/x/crypto/openpgp/armor golang.org/x/crypto/openpgp/elgamal @@ -196,6 +224,10 @@ golang.org/x/crypto/openpgp/errors golang.org/x/crypto/openpgp/packet golang.org/x/crypto/openpgp/s2k golang.org/x/crypto/pbkdf2 +golang.org/x/crypto/ssh +golang.org/x/crypto/ssh/agent +golang.org/x/crypto/ssh/internal/bcrypt_pbkdf +golang.org/x/crypto/ssh/knownhosts # golang.org/x/net v0.0.0-20220722155237-a158d28d115b ## explicit; go 1.17 golang.org/x/net/context @@ -203,10 +235,13 @@ golang.org/x/net/http/httpguts golang.org/x/net/http2 golang.org/x/net/http2/hpack golang.org/x/net/idna +golang.org/x/net/internal/socks golang.org/x/net/internal/timeseries +golang.org/x/net/proxy golang.org/x/net/trace # golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f ## explicit; go 1.17 +golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix golang.org/x/sys/windows @@ -310,6 +345,11 @@ google.golang.org/protobuf/types/known/timestamppb ## explicit # gopkg.in/src-d/go-billy.v4 v4.3.2 ## explicit +gopkg.in/src-d/go-billy.v4 +gopkg.in/src-d/go-billy.v4/helper/chroot +gopkg.in/src-d/go-billy.v4/helper/polyfill +gopkg.in/src-d/go-billy.v4/osfs +gopkg.in/src-d/go-billy.v4/util # gopkg.in/warnings.v0 v0.1.2 ## explicit gopkg.in/warnings.v0