From 330720fea4d599cb41a80e42d07c13696bd24e7f Mon Sep 17 00:00:00 2001 From: Stream Date: Wed, 6 May 2026 10:20:01 +0300 Subject: [PATCH] auto-sync: 2026-05-06 10:20:01 --- .../prototype/deploy-ruler-fix.js | 112 + .../prototype/node_modules/.package-lock.json | 61 + .../prototype/node_modules/asn1/Jenkinsfile | 65 + .../prototype/node_modules/asn1/LICENSE | 19 + .../prototype/node_modules/asn1/README.md | 50 + .../node_modules/asn1/lib/ber/errors.js | 13 + .../node_modules/asn1/lib/ber/index.js | 27 + .../node_modules/asn1/lib/ber/reader.js | 262 ++ .../node_modules/asn1/lib/ber/types.js | 36 + .../node_modules/asn1/lib/ber/writer.js | 317 ++ .../prototype/node_modules/asn1/lib/index.js | 20 + .../prototype/node_modules/asn1/package.json | 31 + .../node_modules/bcrypt-pbkdf/CONTRIBUTING.md | 13 + .../node_modules/bcrypt-pbkdf/LICENSE | 66 + .../node_modules/bcrypt-pbkdf/README.md | 45 + .../node_modules/bcrypt-pbkdf/index.js | 556 +++ .../node_modules/bcrypt-pbkdf/package.json | 15 + .../node_modules/nan/.github/workflows/ci.yml | 52 + .../node_modules/nan/.pre-commit-config.yaml | 8 + .../prototype/node_modules/nan/CHANGELOG.md | 599 +++ .../prototype/node_modules/nan/CMakeLists.txt | 138 + .../prototype/node_modules/nan/LICENSE.md | 9 + .../prototype/node_modules/nan/README.md | 456 ++ .../node_modules/nan/doc/asyncworker.md | 146 + .../prototype/node_modules/nan/doc/buffers.md | 54 + .../node_modules/nan/doc/callback.md | 76 + .../node_modules/nan/doc/converters.md | 41 + .../prototype/node_modules/nan/doc/errors.md | 226 + .../prototype/node_modules/nan/doc/json.md | 62 + .../node_modules/nan/doc/maybe_types.md | 583 +++ .../prototype/node_modules/nan/doc/methods.md | 689 +++ .../prototype/node_modules/nan/doc/new.md | 147 + .../node_modules/nan/doc/node_misc.md | 123 + .../node_modules/nan/doc/object_wrappers.md | 263 ++ .../node_modules/nan/doc/persistent.md | 296 ++ .../prototype/node_modules/nan/doc/scopes.md | 73 + .../prototype/node_modules/nan/doc/script.md | 58 + .../node_modules/nan/doc/string_bytes.md | 81 + .../node_modules/nan/doc/v8_internals.md | 199 + .../prototype/node_modules/nan/doc/v8_misc.md | 85 + .../node_modules/nan/include_dirs.js | 1 + .../prototype/node_modules/nan/nan.h | 3202 +++++++++++++ .../node_modules/nan/nan_callbacks.h | 141 + .../node_modules/nan/nan_callbacks_12_inl.h | 690 +++ .../nan/nan_callbacks_pre_12_inl.h | 524 +++ .../node_modules/nan/nan_converters.h | 72 + .../node_modules/nan/nan_converters_43_inl.h | 68 + .../nan/nan_converters_pre_43_inl.h | 42 + .../nan/nan_define_own_property_helper.h | 29 + .../nan/nan_implementation_12_inl.h | 430 ++ .../nan/nan_implementation_pre_12_inl.h | 263 ++ .../prototype/node_modules/nan/nan_json.h | 166 + .../node_modules/nan/nan_maybe_43_inl.h | 360 ++ .../node_modules/nan/nan_maybe_pre_43_inl.h | 268 ++ .../prototype/node_modules/nan/nan_new.h | 340 ++ .../node_modules/nan/nan_object_wrap.h | 156 + .../node_modules/nan/nan_persistent_12_inl.h | 132 + .../nan/nan_persistent_pre_12_inl.h | 242 + .../prototype/node_modules/nan/nan_private.h | 73 + .../node_modules/nan/nan_scriptorigin.h | 97 + .../node_modules/nan/nan_string_bytes.h | 305 ++ .../nan/nan_typedarray_contents.h | 96 + .../prototype/node_modules/nan/nan_weak.h | 453 ++ .../prototype/node_modules/nan/package.json | 38 + .../prototype/node_modules/nan/tools/1to2.js | 412 ++ .../node_modules/nan/tools/README.md | 14 + .../node_modules/nan/tools/package.json | 19 + .../node_modules/safer-buffer/LICENSE | 21 + .../safer-buffer/Porting-Buffer.md | 268 ++ .../node_modules/safer-buffer/Readme.md | 156 + .../node_modules/safer-buffer/dangerous.js | 58 + .../node_modules/safer-buffer/package.json | 34 + .../node_modules/safer-buffer/safer.js | 77 + .../node_modules/safer-buffer/tests.js | 406 ++ .../prototype/node_modules/ssh2/.eslintignore | 4 + .../prototype/node_modules/ssh2/.eslintrc.js | 5 + .../ssh2/.github/workflows/ci.yml | 110 + .../ssh2/.github/workflows/lint.yml | 27 + .../prototype/node_modules/ssh2/LICENSE | 19 + .../prototype/node_modules/ssh2/README.md | 1529 +++++++ .../prototype/node_modules/ssh2/SFTP.md | 413 ++ .../node_modules/ssh2/examples/server-chat.js | 238 + .../examples/sftp-server-download-only.js | 134 + .../prototype/node_modules/ssh2/install.js | 27 + .../node_modules/ssh2/lib/Channel.js | 295 ++ .../prototype/node_modules/ssh2/lib/agent.js | 1123 +++++ .../prototype/node_modules/ssh2/lib/client.js | 2176 +++++++++ .../node_modules/ssh2/lib/http-agents.js | 84 + .../prototype/node_modules/ssh2/lib/index.js | 44 + .../prototype/node_modules/ssh2/lib/keygen.js | 582 +++ .../ssh2/lib/protocol/Protocol.js | 2136 +++++++++ .../node_modules/ssh2/lib/protocol/SFTP.js | 4052 +++++++++++++++++ .../ssh2/lib/protocol/constants.js | 356 ++ .../node_modules/ssh2/lib/protocol/crypto.js | 1602 +++++++ .../ssh2/lib/protocol/crypto/binding.gyp | 23 + .../ssh2/lib/protocol/crypto/build/Makefile | 354 ++ .../protocol/crypto/build/binding.Makefile | 6 + .../lib/protocol/crypto/build/config.gypi | 532 +++ .../protocol/crypto/build/sshcrypto.target.mk | 164 + .../ssh2/lib/protocol/crypto/poly1305.js | 43 + .../ssh2/lib/protocol/crypto/src/binding.cc | 2300 ++++++++++ .../ssh2/lib/protocol/handlers.js | 16 + .../ssh2/lib/protocol/handlers.misc.js | 1285 ++++++ .../node_modules/ssh2/lib/protocol/kex.js | 1908 ++++++++ .../ssh2/lib/protocol/keyParser.js | 1484 ++++++ .../ssh2/lib/protocol/node-fs-compat.js | 115 + .../node_modules/ssh2/lib/protocol/utils.js | 356 ++ .../node_modules/ssh2/lib/protocol/zlib.js | 255 ++ .../prototype/node_modules/ssh2/lib/server.js | 1380 ++++++ .../prototype/node_modules/ssh2/lib/utils.js | 336 ++ .../prototype/node_modules/ssh2/package.json | 49 + .../node_modules/ssh2/test/common.js | 316 ++ .../ssh2/test/fixtures/bad_rsa_private_key | 26 + .../ssh2/test/fixtures/https_cert.pem | 33 + .../ssh2/test/fixtures/https_key.pem | 52 + .../node_modules/ssh2/test/fixtures/id_dsa | 12 + .../node_modules/ssh2/test/fixtures/id_ecdsa | 5 + .../node_modules/ssh2/test/fixtures/id_rsa | 15 + .../ssh2/test/fixtures/id_rsa.ppk | 26 + .../ssh2/test/fixtures/id_rsa_enc | 30 + .../test/fixtures/keyParser/openssh_new_dsa | 21 + .../fixtures/keyParser/openssh_new_dsa.pub | 1 + .../keyParser/openssh_new_dsa.pub.result | 7 + .../fixtures/keyParser/openssh_new_dsa.result | 7 + .../fixtures/keyParser/openssh_new_dsa_enc | 22 + .../keyParser/openssh_new_dsa_enc.pub | 1 + .../keyParser/openssh_new_dsa_enc.pub.result | 7 + .../keyParser/openssh_new_dsa_enc.result | 7 + .../keyParser/openssh_new_dsa_enc_gcm | 23 + .../keyParser/openssh_new_dsa_enc_gcm.pub | 1 + .../openssh_new_dsa_enc_gcm.pub.result | 7 + .../keyParser/openssh_new_dsa_enc_gcm.result | 7 + .../test/fixtures/keyParser/openssh_new_ecdsa | 9 + .../fixtures/keyParser/openssh_new_ecdsa.pub | 1 + .../keyParser/openssh_new_ecdsa.pub.result | 7 + .../keyParser/openssh_new_ecdsa.result | 7 + .../fixtures/keyParser/openssh_new_ecdsa_enc | 10 + .../keyParser/openssh_new_ecdsa_enc.pub | 1 + .../openssh_new_ecdsa_enc.pub.result | 8 + .../keyParser/openssh_new_ecdsa_enc.result | 7 + .../keyParser/openssh_new_ecdsa_enc_gcm | 10 + .../keyParser/openssh_new_ecdsa_enc_gcm.pub | 1 + .../openssh_new_ecdsa_enc_gcm.pub.result | 8 + .../openssh_new_ecdsa_enc_gcm.result | 7 + .../fixtures/keyParser/openssh_new_ed25519 | 7 + .../keyParser/openssh_new_ed25519.pub | 1 + .../keyParser/openssh_new_ed25519.pub.result | 7 + .../keyParser/openssh_new_ed25519.result | 7 + .../test/fixtures/keyParser/openssh_new_rsa | 27 + .../fixtures/keyParser/openssh_new_rsa.pub | 1 + .../keyParser/openssh_new_rsa.pub.result | 7 + .../fixtures/keyParser/openssh_new_rsa.result | 7 + .../fixtures/keyParser/openssh_new_rsa_enc | 28 + .../keyParser/openssh_new_rsa_enc.pub | 1 + .../keyParser/openssh_new_rsa_enc.pub.result | 8 + .../keyParser/openssh_new_rsa_enc.result | 7 + .../keyParser/openssh_new_rsa_enc_gcm | 29 + .../keyParser/openssh_new_rsa_enc_gcm.pub | 1 + .../openssh_new_rsa_enc_gcm.pub.result | 8 + .../keyParser/openssh_new_rsa_enc_gcm.result | 7 + .../test/fixtures/keyParser/openssh_old_dsa | 12 + .../fixtures/keyParser/openssh_old_dsa.pub | 1 + .../keyParser/openssh_old_dsa.pub.result | 7 + .../fixtures/keyParser/openssh_old_dsa.result | 7 + .../fixtures/keyParser/openssh_old_dsa_enc | 15 + .../keyParser/openssh_old_dsa_enc.pub | 1 + .../keyParser/openssh_old_dsa_enc.pub.result | 8 + .../keyParser/openssh_old_dsa_enc.result | 7 + .../test/fixtures/keyParser/openssh_old_ecdsa | 5 + .../fixtures/keyParser/openssh_old_ecdsa.pub | 1 + .../keyParser/openssh_old_ecdsa.pub.result | 7 + .../keyParser/openssh_old_ecdsa.result | 7 + .../fixtures/keyParser/openssh_old_ecdsa_enc | 8 + .../keyParser/openssh_old_ecdsa_enc.pub | 1 + .../openssh_old_ecdsa_enc.pub.result | 8 + .../keyParser/openssh_old_ecdsa_enc.result | 7 + .../test/fixtures/keyParser/openssh_old_rsa | 27 + .../fixtures/keyParser/openssh_old_rsa.pub | 1 + .../keyParser/openssh_old_rsa.pub.result | 7 + .../fixtures/keyParser/openssh_old_rsa.result | 7 + .../fixtures/keyParser/openssh_old_rsa_enc | 30 + .../keyParser/openssh_old_rsa_enc.pub | 1 + .../keyParser/openssh_old_rsa_enc.pub.result | 8 + .../keyParser/openssh_old_rsa_enc.result | 7 + .../keyParser/openssh_old_rsa_enc_aes256 | 54 + .../keyParser/openssh_old_rsa_enc_aes256.pub | 1 + .../openssh_old_rsa_enc_aes256.pub.result | 6 + .../openssh_old_rsa_enc_aes256.result | 6 + .../ssh2/test/fixtures/keyParser/ppk_dsa_enc | 17 + .../fixtures/keyParser/ppk_dsa_enc.result | 7 + .../ssh2/test/fixtures/keyParser/ppk_rsa | 26 + .../test/fixtures/keyParser/ppk_rsa.result | 7 + .../ssh2/test/fixtures/keyParser/ppk_rsa_enc | 18 + .../fixtures/keyParser/ppk_rsa_enc.result | 7 + .../test/fixtures/keyParser/rfc4716_rsa.pub | 9 + .../fixtures/keyParser/rfc4716_rsa.pub.result | 7 + .../test/fixtures/keyParser/rfc4716_rsa2.pub | 10 + .../keyParser/rfc4716_rsa2.pub.result | 7 + .../test/fixtures/keyParser/rfc4716_rsa3.pub | 11 + .../keyParser/rfc4716_rsa3.pub.result | 7 + .../test/fixtures/keyParser/rfc4716_rsa4.pub | 11 + .../keyParser/rfc4716_rsa4.pub.result | 7 + .../test/fixtures/keyParser/rfc4716_rsa5.pub | 8 + .../keyParser/rfc4716_rsa5.pub.result | 7 + .../test/fixtures/keyParser/rfc4716_rsa6.pub | 13 + .../keyParser/rfc4716_rsa6.pub.result | 7 + .../ssh2/test/fixtures/openssh_new_rsa | 27 + .../ssh2/test/fixtures/ssh_host_dsa_key | 12 + .../ssh2/test/fixtures/ssh_host_ecdsa_key | 5 + .../ssh2/test/fixtures/ssh_host_rsa_key | 15 + .../node_modules/ssh2/test/test-exec.js | 578 +++ .../ssh2/test/test-integration-openssh.js | 486 ++ .../node_modules/ssh2/test/test-keygen.js | 60 + .../ssh2/test/test-misc-client-server.js | 1460 ++++++ .../node_modules/ssh2/test/test-openssh.js | 261 ++ .../ssh2/test/test-protocol-crypto.js | 631 +++ .../ssh2/test/test-protocol-keyparser.js | 177 + .../ssh2/test/test-server-hostkeys.js | 138 + .../node_modules/ssh2/test/test-sftp.js | 842 ++++ .../node_modules/ssh2/test/test-shell.js | 109 + .../ssh2/test/test-userauth-agent-openssh.js | 110 + .../ssh2/test/test-userauth-agent.js | 171 + .../node_modules/ssh2/test/test-userauth.js | 611 +++ .../ssh2/test/test-worker-imports.js | 25 + .../prototype/node_modules/ssh2/test/test.js | 20 + .../node_modules/ssh2/util/build_pagent.bat | 2 + .../prototype/node_modules/ssh2/util/pagent.c | 88 + .../node_modules/ssh2/util/pagent.exe | Bin 0 -> 50688 bytes .../node_modules/tweetnacl/.npmignore | 4 + .../node_modules/tweetnacl/AUTHORS.md | 28 + .../node_modules/tweetnacl/CHANGELOG.md | 221 + .../prototype/node_modules/tweetnacl/LICENSE | 24 + .../tweetnacl/PULL_REQUEST_TEMPLATE.md | 20 + .../node_modules/tweetnacl/README.md | 459 ++ .../node_modules/tweetnacl/nacl-fast.js | 2388 ++++++++++ .../node_modules/tweetnacl/nacl-fast.min.js | 2 + .../node_modules/tweetnacl/nacl.d.ts | 98 + .../prototype/node_modules/tweetnacl/nacl.js | 1175 +++++ .../node_modules/tweetnacl/nacl.min.js | 1 + .../node_modules/tweetnacl/package.json | 58 + .../enduro-trails/prototype/package-lock.json | 89 + tasks/enduro-trails/prototype/package.json | 5 + tasks/enduro-trails/prototype/static/app.js | 54 +- .../enduro-trails/prototype/static/index.html | 2 +- 244 files changed, 53131 insertions(+), 10 deletions(-) create mode 100644 tasks/enduro-trails/prototype/deploy-ruler-fix.js create mode 100644 tasks/enduro-trails/prototype/node_modules/.package-lock.json create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/Jenkinsfile create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/LICENSE create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/README.md create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/errors.js create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/index.js create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/reader.js create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/types.js create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/writer.js create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/lib/index.js create mode 100644 tasks/enduro-trails/prototype/node_modules/asn1/package.json create mode 100644 tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/CONTRIBUTING.md create mode 100644 tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/LICENSE create mode 100644 tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/README.md create mode 100644 tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/index.js create mode 100644 tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/package.json create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/.github/workflows/ci.yml create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/.pre-commit-config.yaml create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/CHANGELOG.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/CMakeLists.txt create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/LICENSE.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/README.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/asyncworker.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/buffers.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/callback.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/converters.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/errors.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/json.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/maybe_types.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/methods.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/new.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/node_misc.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/object_wrappers.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/persistent.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/scopes.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/script.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/string_bytes.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/v8_internals.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/doc/v8_misc.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/include_dirs.js create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_12_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_pre_12_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_converters.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_converters_43_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_converters_pre_43_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_define_own_property_helper.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_12_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_pre_12_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_json.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_43_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_pre_43_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_new.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_object_wrap.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_12_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_pre_12_inl.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_private.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_scriptorigin.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_string_bytes.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_typedarray_contents.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/nan_weak.h create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/package.json create mode 100755 tasks/enduro-trails/prototype/node_modules/nan/tools/1to2.js create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/tools/README.md create mode 100644 tasks/enduro-trails/prototype/node_modules/nan/tools/package.json create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/LICENSE create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/Porting-Buffer.md create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/Readme.md create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/dangerous.js create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/package.json create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/safer.js create mode 100644 tasks/enduro-trails/prototype/node_modules/safer-buffer/tests.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/.eslintignore create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/.eslintrc.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/ci.yml create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/lint.yml create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/LICENSE create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/README.md create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/SFTP.md create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/examples/server-chat.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/examples/sftp-server-download-only.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/install.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/Channel.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/agent.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/client.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/http-agents.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/index.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/keygen.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/Protocol.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/SFTP.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/constants.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/binding.gyp create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/Makefile create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/binding.Makefile create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/config.gypi create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/poly1305.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/src/binding.cc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.misc.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/kex.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/keyParser.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/node-fs-compat.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/utils.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/zlib.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/server.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/lib/utils.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/package.json create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/common.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/bad_rsa_private_key create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_cert.pem create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_key.pem create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_dsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_ecdsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa.ppk create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/openssh_new_rsa create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_dsa_key create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_rsa_key create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-exec.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-integration-openssh.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-keygen.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-misc-client-server.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-openssh.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-crypto.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-keyparser.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-server-hostkeys.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-sftp.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-shell.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent-openssh.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test-worker-imports.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/test/test.js create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/util/build_pagent.bat create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.c create mode 100644 tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.exe create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/.npmignore create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/AUTHORS.md create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/CHANGELOG.md create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/LICENSE create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/README.md create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.js create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.min.js create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.d.ts create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.js create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.min.js create mode 100644 tasks/enduro-trails/prototype/node_modules/tweetnacl/package.json create mode 100644 tasks/enduro-trails/prototype/package-lock.json create mode 100644 tasks/enduro-trails/prototype/package.json diff --git a/tasks/enduro-trails/prototype/deploy-ruler-fix.js b/tasks/enduro-trails/prototype/deploy-ruler-fix.js new file mode 100644 index 0000000..d60b783 --- /dev/null +++ b/tasks/enduro-trails/prototype/deploy-ruler-fix.js @@ -0,0 +1,112 @@ +const { Client } = require('ssh2'); +const fs = require('fs'); +const path = require('path'); + +const conn = new Client(); + +const config = { + host: '82.22.50.71', + username: 'slin', + password: 'motoZ@yaz2010', + readyTimeout: 30000 +}; + +const localAppJs = path.join(__dirname, 'static', 'app.js'); +const localIndexHtml = path.join(__dirname, 'static', 'index.html'); +const remoteDir = '/home/slin/enduro-trails/prototype/static/'; +const containerName = 'prototype-enduro-trails-1'; + +console.log('🔌 Connecting to server...'); + +conn.on('ready', () => { + console.log('✅ Connected'); + + conn.sftp((err, sftp) => { + if (err) { + console.error('❌ SFTP error:', err); + conn.end(); + process.exit(1); + } + + console.log('📤 Uploading app.js...'); + const appJsStream = sftp.createWriteStream(remoteDir + 'app.js'); + fs.createReadStream(localAppJs).pipe(appJsStream); + + appJsStream.on('close', () => { + console.log('✅ app.js uploaded'); + + console.log('📤 Uploading index.html...'); + const indexStream = sftp.createWriteStream(remoteDir + 'index.html'); + fs.createReadStream(localIndexHtml).pipe(indexStream); + + indexStream.on('close', () => { + console.log('✅ index.html uploaded'); + + console.log('🔄 Copying files into container...'); + conn.exec(`docker cp ${remoteDir}app.js ${containerName}:/app/static/app.js && docker cp ${remoteDir}index.html ${containerName}:/app/static/index.html`, (err, stream) => { + if (err) { + console.error('❌ Docker cp error:', err); + conn.end(); + process.exit(1); + } + + let output = ''; + stream.on('data', (data) => { output += data.toString(); }); + stream.stderr.on('data', (data) => { output += data.toString(); }); + + stream.on('close', (code) => { + if (code !== 0) { + console.error('❌ Docker cp failed:', output); + conn.end(); + process.exit(1); + } + console.log('✅ Files copied into container'); + + console.log('🔄 Restarting container...'); + conn.exec(`docker restart ${containerName}`, (err, stream) => { + if (err) { + console.error('❌ Restart error:', err); + conn.end(); + process.exit(1); + } + + let restartOutput = ''; + stream.on('data', (data) => { restartOutput += data.toString(); }); + stream.stderr.on('data', (data) => { restartOutput += data.toString(); }); + + stream.on('close', (code) => { + if (code !== 0) { + console.error('❌ Restart failed:', restartOutput); + conn.end(); + process.exit(1); + } + console.log('✅ Container restarted'); + console.log('🎉 Deploy complete!'); + conn.end(); + }); + }); + }); + }); + }); + + indexStream.on('error', (err) => { + console.error('❌ index.html upload error:', err); + conn.end(); + process.exit(1); + }); + }); + + appJsStream.on('error', (err) => { + console.error('❌ app.js upload error:', err); + conn.end(); + process.exit(1); + }); + }); +}); + +conn.on('error', (err) => { + console.error('❌ Connection error:', err); + process.exit(1); +}); + +conn.connect(config); diff --git a/tasks/enduro-trails/prototype/node_modules/.package-lock.json b/tasks/enduro-trails/prototype/node_modules/.package-lock.json new file mode 100644 index 0000000..03dc161 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/.package-lock.json @@ -0,0 +1,61 @@ +{ + "name": "prototype", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/nan": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", + "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", + "license": "MIT", + "optional": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/ssh2": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.17.0.tgz", + "integrity": "sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==", + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.23.0" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + } + } +} diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/Jenkinsfile b/tasks/enduro-trails/prototype/node_modules/asn1/Jenkinsfile new file mode 100644 index 0000000..d1b4593 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/Jenkinsfile @@ -0,0 +1,65 @@ +@Library('jenkins-joylib@v1.0.8') _ + +pipeline { + + agent none + + options { + buildDiscarder(logRotator(numToKeepStr: '45')) + timestamps() + } + + stages { + stage('top') { + parallel { + stage('v4-zone') { + agent { + label joyCommonLabels(image_ver: '15.4.1') + } + tools { + nodejs 'sdcnode-v4-zone' + } + stages { + stage('check') { + steps{ + sh('make check') + } + } + stage('test') { + steps{ + sh('make test') + } + } + } + } + + stage('v6-zone64') { + agent { + label joyCommonLabels(image_ver: '18.4.0') + } + tools { + nodejs 'sdcnode-v6-zone64' + } + stages { + stage('check') { + steps{ + sh('make check') + } + } + stage('test') { + steps{ + sh('make test') + } + } + } + } + } + } + } + + post { + always { + joySlackNotifications() + } + } +} diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/LICENSE b/tasks/enduro-trails/prototype/node_modules/asn1/LICENSE new file mode 100644 index 0000000..9b5dcdb --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Mark Cavage, All rights reserved. + +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/tasks/enduro-trails/prototype/node_modules/asn1/README.md b/tasks/enduro-trails/prototype/node_modules/asn1/README.md new file mode 100644 index 0000000..2208210 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/README.md @@ -0,0 +1,50 @@ +node-asn1 is a library for encoding and decoding ASN.1 datatypes in pure JS. +Currently BER encoding is supported; at some point I'll likely have to do DER. + +## Usage + +Mostly, if you're *actually* needing to read and write ASN.1, you probably don't +need this readme to explain what and why. If you have no idea what ASN.1 is, +see this: ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +The source is pretty much self-explanatory, and has read/write methods for the +common types out there. + +### Decoding + +The following reads an ASN.1 sequence with a boolean. + + var Ber = require('asn1').Ber; + + var reader = new Ber.Reader(Buffer.from([0x30, 0x03, 0x01, 0x01, 0xff])); + + reader.readSequence(); + console.log('Sequence len: ' + reader.length); + if (reader.peek() === Ber.Boolean) + console.log(reader.readBoolean()); + +### Encoding + +The following generates the same payload as above. + + var Ber = require('asn1').Ber; + + var writer = new Ber.Writer(); + + writer.startSequence(); + writer.writeBoolean(true); + writer.endSequence(); + + console.log(writer.buffer); + +## Installation + + npm install asn1 + +## License + +MIT. + +## Bugs + +See . diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/errors.js b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/errors.js new file mode 100644 index 0000000..4557b8a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/errors.js @@ -0,0 +1,13 @@ +// Copyright 2011 Mark Cavage All rights reserved. + + +module.exports = { + + newInvalidAsn1Error: function (msg) { + var e = new Error(); + e.name = 'InvalidAsn1Error'; + e.message = msg || ''; + return e; + } + +}; diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/index.js b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/index.js new file mode 100644 index 0000000..387d132 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/index.js @@ -0,0 +1,27 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var errors = require('./errors'); +var types = require('./types'); + +var Reader = require('./reader'); +var Writer = require('./writer'); + + +// --- Exports + +module.exports = { + + Reader: Reader, + + Writer: Writer + +}; + +for (var t in types) { + if (types.hasOwnProperty(t)) + module.exports[t] = types[t]; +} +for (var e in errors) { + if (errors.hasOwnProperty(e)) + module.exports[e] = errors[e]; +} diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/reader.js b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/reader.js new file mode 100644 index 0000000..8a7e4ca --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/reader.js @@ -0,0 +1,262 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var assert = require('assert'); +var Buffer = require('safer-buffer').Buffer; + +var ASN1 = require('./types'); +var errors = require('./errors'); + + +// --- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + + + +// --- API + +function Reader(data) { + if (!data || !Buffer.isBuffer(data)) + throw new TypeError('data must be a node Buffer'); + + this._buf = data; + this._size = data.length; + + // These hold the "current" state + this._len = 0; + this._offset = 0; +} + +Object.defineProperty(Reader.prototype, 'length', { + enumerable: true, + get: function () { return (this._len); } +}); + +Object.defineProperty(Reader.prototype, 'offset', { + enumerable: true, + get: function () { return (this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'remain', { + get: function () { return (this._size - this._offset); } +}); + +Object.defineProperty(Reader.prototype, 'buffer', { + get: function () { return (this._buf.slice(this._offset)); } +}); + + +/** + * Reads a single byte and advances offset; you can pass in `true` to make this + * a "peek" operation (i.e., get the byte, but don't advance the offset). + * + * @param {Boolean} peek true means don't move offset. + * @return {Number} the next byte, null if not enough data. + */ +Reader.prototype.readByte = function (peek) { + if (this._size - this._offset < 1) + return null; + + var b = this._buf[this._offset] & 0xff; + + if (!peek) + this._offset += 1; + + return b; +}; + + +Reader.prototype.peek = function () { + return this.readByte(true); +}; + + +/** + * Reads a (potentially) variable length off the BER buffer. This call is + * not really meant to be called directly, as callers have to manipulate + * the internal buffer afterwards. + * + * As a result of this call, you can call `Reader.length`, until the + * next thing called that does a readLength. + * + * @return {Number} the amount of offset to advance the buffer. + * @throws {InvalidAsn1Error} on bad ASN.1 + */ +Reader.prototype.readLength = function (offset) { + if (offset === undefined) + offset = this._offset; + + if (offset >= this._size) + return null; + + var lenB = this._buf[offset++] & 0xff; + if (lenB === null) + return null; + + if ((lenB & 0x80) === 0x80) { + lenB &= 0x7f; + + if (lenB === 0) + throw newInvalidAsn1Error('Indefinite length not supported'); + + if (lenB > 4) + throw newInvalidAsn1Error('encoding too long'); + + if (this._size - offset < lenB) + return null; + + this._len = 0; + for (var i = 0; i < lenB; i++) + this._len = (this._len << 8) + (this._buf[offset++] & 0xff); + + } else { + // Wasn't a variable length + this._len = lenB; + } + + return offset; +}; + + +/** + * Parses the next sequence in this BER buffer. + * + * To get the length of the sequence, call `Reader.length`. + * + * @return {Number} the sequence's tag. + */ +Reader.prototype.readSequence = function (tag) { + var seq = this.peek(); + if (seq === null) + return null; + if (tag !== undefined && tag !== seq) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + seq.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + + this._offset = o; + return seq; +}; + + +Reader.prototype.readInt = function () { + return this._readTag(ASN1.Integer); +}; + + +Reader.prototype.readBoolean = function () { + return (this._readTag(ASN1.Boolean) === 0 ? false : true); +}; + + +Reader.prototype.readEnumeration = function () { + return this._readTag(ASN1.Enumeration); +}; + + +Reader.prototype.readString = function (tag, retbuf) { + if (!tag) + tag = ASN1.OctetString; + + var b = this.peek(); + if (b === null) + return null; + + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + + if (o === null) + return null; + + if (this.length > this._size - o) + return null; + + this._offset = o; + + if (this.length === 0) + return retbuf ? Buffer.alloc(0) : ''; + + var str = this._buf.slice(this._offset, this._offset + this.length); + this._offset += this.length; + + return retbuf ? str : str.toString('utf8'); +}; + +Reader.prototype.readOID = function (tag) { + if (!tag) + tag = ASN1.OID; + + var b = this.readString(tag, true); + if (b === null) + return null; + + var values = []; + var value = 0; + + for (var i = 0; i < b.length; i++) { + var byte = b[i] & 0xff; + + value <<= 7; + value += byte & 0x7f; + if ((byte & 0x80) === 0) { + values.push(value); + value = 0; + } + } + + value = values.shift(); + values.unshift(value % 40); + values.unshift((value / 40) >> 0); + + return values.join('.'); +}; + + +Reader.prototype._readTag = function (tag) { + assert.ok(tag !== undefined); + + var b = this.peek(); + + if (b === null) + return null; + + if (b !== tag) + throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) + + ': got 0x' + b.toString(16)); + + var o = this.readLength(this._offset + 1); // stored in `length` + if (o === null) + return null; + + if (this.length > 4) + throw newInvalidAsn1Error('Integer too long: ' + this.length); + + if (this.length > this._size - o) + return null; + this._offset = o; + + var fb = this._buf[this._offset]; + var value = 0; + + for (var i = 0; i < this.length; i++) { + value <<= 8; + value |= (this._buf[this._offset++] & 0xff); + } + + if ((fb & 0x80) === 0x80 && i !== 4) + value -= (1 << (i * 8)); + + return value >> 0; +}; + + + +// --- Exported API + +module.exports = Reader; diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/types.js b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/types.js new file mode 100644 index 0000000..8aea000 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/types.js @@ -0,0 +1,36 @@ +// Copyright 2011 Mark Cavage All rights reserved. + + +module.exports = { + EOC: 0, + Boolean: 1, + Integer: 2, + BitString: 3, + OctetString: 4, + Null: 5, + OID: 6, + ObjectDescriptor: 7, + External: 8, + Real: 9, // float + Enumeration: 10, + PDV: 11, + Utf8String: 12, + RelativeOID: 13, + Sequence: 16, + Set: 17, + NumericString: 18, + PrintableString: 19, + T61String: 20, + VideotexString: 21, + IA5String: 22, + UTCTime: 23, + GeneralizedTime: 24, + GraphicString: 25, + VisibleString: 26, + GeneralString: 28, + UniversalString: 29, + CharacterString: 30, + BMPString: 31, + Constructor: 32, + Context: 128 +}; diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/writer.js b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/writer.js new file mode 100644 index 0000000..3515acf --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/lib/ber/writer.js @@ -0,0 +1,317 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +var assert = require('assert'); +var Buffer = require('safer-buffer').Buffer; +var ASN1 = require('./types'); +var errors = require('./errors'); + + +// --- Globals + +var newInvalidAsn1Error = errors.newInvalidAsn1Error; + +var DEFAULT_OPTS = { + size: 1024, + growthFactor: 8 +}; + + +// --- Helpers + +function merge(from, to) { + assert.ok(from); + assert.equal(typeof (from), 'object'); + assert.ok(to); + assert.equal(typeof (to), 'object'); + + var keys = Object.getOwnPropertyNames(from); + keys.forEach(function (key) { + if (to[key]) + return; + + var value = Object.getOwnPropertyDescriptor(from, key); + Object.defineProperty(to, key, value); + }); + + return to; +} + + + +// --- API + +function Writer(options) { + options = merge(DEFAULT_OPTS, options || {}); + + this._buf = Buffer.alloc(options.size || 1024); + this._size = this._buf.length; + this._offset = 0; + this._options = options; + + // A list of offsets in the buffer where we need to insert + // sequence tag/len pairs. + this._seq = []; +} + +Object.defineProperty(Writer.prototype, 'buffer', { + get: function () { + if (this._seq.length) + throw newInvalidAsn1Error(this._seq.length + ' unended sequence(s)'); + + return (this._buf.slice(0, this._offset)); + } +}); + +Writer.prototype.writeByte = function (b) { + if (typeof (b) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(1); + this._buf[this._offset++] = b; +}; + + +Writer.prototype.writeInt = function (i, tag) { + if (typeof (i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof (tag) !== 'number') + tag = ASN1.Integer; + + var sz = 4; + + while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) && + (sz > 1)) { + sz--; + i <<= 8; + } + + if (sz > 4) + throw newInvalidAsn1Error('BER ints cannot be > 0xffffffff'); + + this._ensure(2 + sz); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = sz; + + while (sz-- > 0) { + this._buf[this._offset++] = ((i & 0xff000000) >>> 24); + i <<= 8; + } + +}; + + +Writer.prototype.writeNull = function () { + this.writeByte(ASN1.Null); + this.writeByte(0x00); +}; + + +Writer.prototype.writeEnumeration = function (i, tag) { + if (typeof (i) !== 'number') + throw new TypeError('argument must be a Number'); + if (typeof (tag) !== 'number') + tag = ASN1.Enumeration; + + return this.writeInt(i, tag); +}; + + +Writer.prototype.writeBoolean = function (b, tag) { + if (typeof (b) !== 'boolean') + throw new TypeError('argument must be a Boolean'); + if (typeof (tag) !== 'number') + tag = ASN1.Boolean; + + this._ensure(3); + this._buf[this._offset++] = tag; + this._buf[this._offset++] = 0x01; + this._buf[this._offset++] = b ? 0xff : 0x00; +}; + + +Writer.prototype.writeString = function (s, tag) { + if (typeof (s) !== 'string') + throw new TypeError('argument must be a string (was: ' + typeof (s) + ')'); + if (typeof (tag) !== 'number') + tag = ASN1.OctetString; + + var len = Buffer.byteLength(s); + this.writeByte(tag); + this.writeLength(len); + if (len) { + this._ensure(len); + this._buf.write(s, this._offset); + this._offset += len; + } +}; + + +Writer.prototype.writeBuffer = function (buf, tag) { + if (typeof (tag) !== 'number') + throw new TypeError('tag must be a number'); + if (!Buffer.isBuffer(buf)) + throw new TypeError('argument must be a buffer'); + + this.writeByte(tag); + this.writeLength(buf.length); + this._ensure(buf.length); + buf.copy(this._buf, this._offset, 0, buf.length); + this._offset += buf.length; +}; + + +Writer.prototype.writeStringArray = function (strings) { + if ((!strings instanceof Array)) + throw new TypeError('argument must be an Array[String]'); + + var self = this; + strings.forEach(function (s) { + self.writeString(s); + }); +}; + +// This is really to solve DER cases, but whatever for now +Writer.prototype.writeOID = function (s, tag) { + if (typeof (s) !== 'string') + throw new TypeError('argument must be a string'); + if (typeof (tag) !== 'number') + tag = ASN1.OID; + + if (!/^([0-9]+\.){3,}[0-9]+$/.test(s)) + throw new Error('argument is not a valid OID string'); + + function encodeOctet(bytes, octet) { + if (octet < 128) { + bytes.push(octet); + } else if (octet < 16384) { + bytes.push((octet >>> 7) | 0x80); + bytes.push(octet & 0x7F); + } else if (octet < 2097152) { + bytes.push((octet >>> 14) | 0x80); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else if (octet < 268435456) { + bytes.push((octet >>> 21) | 0x80); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } else { + bytes.push(((octet >>> 28) | 0x80) & 0xFF); + bytes.push(((octet >>> 21) | 0x80) & 0xFF); + bytes.push(((octet >>> 14) | 0x80) & 0xFF); + bytes.push(((octet >>> 7) | 0x80) & 0xFF); + bytes.push(octet & 0x7F); + } + } + + var tmp = s.split('.'); + var bytes = []; + bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10)); + tmp.slice(2).forEach(function (b) { + encodeOctet(bytes, parseInt(b, 10)); + }); + + var self = this; + this._ensure(2 + bytes.length); + this.writeByte(tag); + this.writeLength(bytes.length); + bytes.forEach(function (b) { + self.writeByte(b); + }); +}; + + +Writer.prototype.writeLength = function (len) { + if (typeof (len) !== 'number') + throw new TypeError('argument must be a Number'); + + this._ensure(4); + + if (len <= 0x7f) { + this._buf[this._offset++] = len; + } else if (len <= 0xff) { + this._buf[this._offset++] = 0x81; + this._buf[this._offset++] = len; + } else if (len <= 0xffff) { + this._buf[this._offset++] = 0x82; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else if (len <= 0xffffff) { + this._buf[this._offset++] = 0x83; + this._buf[this._offset++] = len >> 16; + this._buf[this._offset++] = len >> 8; + this._buf[this._offset++] = len; + } else { + throw newInvalidAsn1Error('Length too long (> 4 bytes)'); + } +}; + +Writer.prototype.startSequence = function (tag) { + if (typeof (tag) !== 'number') + tag = ASN1.Sequence | ASN1.Constructor; + + this.writeByte(tag); + this._seq.push(this._offset); + this._ensure(3); + this._offset += 3; +}; + + +Writer.prototype.endSequence = function () { + var seq = this._seq.pop(); + var start = seq + 3; + var len = this._offset - start; + + if (len <= 0x7f) { + this._shift(start, len, -2); + this._buf[seq] = len; + } else if (len <= 0xff) { + this._shift(start, len, -1); + this._buf[seq] = 0x81; + this._buf[seq + 1] = len; + } else if (len <= 0xffff) { + this._buf[seq] = 0x82; + this._buf[seq + 1] = len >> 8; + this._buf[seq + 2] = len; + } else if (len <= 0xffffff) { + this._shift(start, len, 1); + this._buf[seq] = 0x83; + this._buf[seq + 1] = len >> 16; + this._buf[seq + 2] = len >> 8; + this._buf[seq + 3] = len; + } else { + throw newInvalidAsn1Error('Sequence too long'); + } +}; + + +Writer.prototype._shift = function (start, len, shift) { + assert.ok(start !== undefined); + assert.ok(len !== undefined); + assert.ok(shift); + + this._buf.copy(this._buf, start + shift, start, start + len); + this._offset += shift; +}; + +Writer.prototype._ensure = function (len) { + assert.ok(len); + + if (this._size - this._offset < len) { + var sz = this._size * this._options.growthFactor; + if (sz - this._offset < len) + sz += len; + + var buf = Buffer.alloc(sz); + + this._buf.copy(buf, 0, 0, this._offset); + this._buf = buf; + this._size = sz; + } +}; + + + +// --- Exported API + +module.exports = Writer; diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/lib/index.js b/tasks/enduro-trails/prototype/node_modules/asn1/lib/index.js new file mode 100644 index 0000000..ede3ab2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/lib/index.js @@ -0,0 +1,20 @@ +// Copyright 2011 Mark Cavage All rights reserved. + +// If you have no idea what ASN.1 or BER is, see this: +// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc + +var Ber = require('./ber/index'); + + + +// --- Exported API + +module.exports = { + + Ber: Ber, + + BerReader: Ber.Reader, + + BerWriter: Ber.Writer + +}; diff --git a/tasks/enduro-trails/prototype/node_modules/asn1/package.json b/tasks/enduro-trails/prototype/node_modules/asn1/package.json new file mode 100644 index 0000000..e31cce5 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/asn1/package.json @@ -0,0 +1,31 @@ +{ + "author": "Joyent (joyent.com)", + "contributors": [ + "Mark Cavage ", + "David Gwynne ", + "Yunong Xiao ", + "Alex Wilson " + ], + "name": "asn1", + "description": "Contains parsers and serializers for ASN.1 (currently BER only)", + "version": "0.2.6", + "repository": { + "type": "git", + "url": "https://github.com/joyent/node-asn1.git" + }, + "main": "lib/index.js", + "dependencies": { + "safer-buffer": "~2.1.0" + }, + "devDependencies": { + "istanbul": "^0.3.6", + "faucet": "0.0.1", + "tape": "^3.5.0", + "eslint": "2.13.1", + "eslint-plugin-joyent": "~1.3.0" + }, + "scripts": { + "test": "./node_modules/.bin/tape ./test/ber/*.test.js" + }, + "license": "MIT" +} diff --git a/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/CONTRIBUTING.md b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/CONTRIBUTING.md new file mode 100644 index 0000000..401d34e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Contributing + +This repository uses [cr.joyent.us](https://cr.joyent.us) (Gerrit) for new +changes. Anyone can submit changes. To get started, see the [cr.joyent.us user +guide](https://github.com/joyent/joyent-gerrit/blob/master/docs/user/README.md). +This repo does not use GitHub pull requests. + +See the [Joyent Engineering +Guidelines](https://github.com/joyent/eng/blob/master/docs/index.md) for general +best practices expected in this repository. + +If you're changing something non-trivial or user-facing, you may want to submit +an issue first. diff --git a/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/LICENSE b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/LICENSE new file mode 100644 index 0000000..fc58d2a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/LICENSE @@ -0,0 +1,66 @@ +The Blowfish portions are under the following license: + +Blowfish block cipher for OpenBSD +Copyright 1997 Niels Provos +All rights reserved. + +Implementation advice by David Mazieres . + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +The bcrypt_pbkdf portions are under the following license: + +Copyright (c) 2013 Ted Unangst + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + + +Performance improvements (Javascript-specific): + +Copyright 2016, Joyent Inc +Author: Alex Wilson + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/README.md b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/README.md new file mode 100644 index 0000000..7551f33 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/README.md @@ -0,0 +1,45 @@ +Port of the OpenBSD `bcrypt_pbkdf` function to pure Javascript. `npm`-ified +version of [Devi Mandiri's port](https://github.com/devi/tmp/blob/master/js/bcrypt_pbkdf.js), +with some minor performance improvements. The code is copied verbatim (and +un-styled) from Devi's work. + +This product includes software developed by Niels Provos. + +## API + +### `bcrypt_pbkdf.pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds)` + +Derive a cryptographic key of arbitrary length from a given password and salt, +using the OpenBSD `bcrypt_pbkdf` function. This is a combination of Blowfish and +SHA-512. + +See [this article](http://www.tedunangst.com/flak/post/bcrypt-pbkdf) for +further information. + +Parameters: + + * `pass`, a Uint8Array of length `passlen` + * `passlen`, an integer Number + * `salt`, a Uint8Array of length `saltlen` + * `saltlen`, an integer Number + * `key`, a Uint8Array of length `keylen`, will be filled with output + * `keylen`, an integer Number + * `rounds`, an integer Number, number of rounds of the PBKDF to run + +### `bcrypt_pbkdf.hash(sha2pass, sha2salt, out)` + +Calculate a Blowfish hash, given SHA2-512 output of a password and salt. Used as +part of the inner round function in the PBKDF. + +Parameters: + + * `sha2pass`, a Uint8Array of length 64 + * `sha2salt`, a Uint8Array of length 64 + * `out`, a Uint8Array of length 32, will be filled with output + +## License + +This source form is a 1:1 port from the OpenBSD `blowfish.c` and `bcrypt_pbkdf.c`. +As a result, it retains the original copyright and license. The two files are +under slightly different (but compatible) licenses, and are here combined in +one file. For each of the full license texts see `LICENSE`. diff --git a/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/index.js b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/index.js new file mode 100644 index 0000000..b1b5ad4 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/index.js @@ -0,0 +1,556 @@ +'use strict'; + +var crypto_hash_sha512 = require('tweetnacl').lowlevel.crypto_hash; + +/* + * This file is a 1:1 port from the OpenBSD blowfish.c and bcrypt_pbkdf.c. As a + * result, it retains the original copyright and license. The two files are + * under slightly different (but compatible) licenses, and are here combined in + * one file. + * + * Credit for the actual porting work goes to: + * Devi Mandiri + */ + +/* + * The Blowfish portions are under the following license: + * + * Blowfish block cipher for OpenBSD + * Copyright 1997 Niels Provos + * All rights reserved. + * + * Implementation advice by David Mazieres . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The bcrypt_pbkdf portions are under the following license: + * + * Copyright (c) 2013 Ted Unangst + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Performance improvements (Javascript-specific): + * + * Copyright 2016, Joyent Inc + * Author: Alex Wilson + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// Ported from OpenBSD bcrypt_pbkdf.c v1.9 + +var BLF_J = 0; + +var Blowfish = function() { + this.S = [ + new Uint32Array([ + 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]), + new Uint32Array([ + 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]), + new Uint32Array([ + 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]), + new Uint32Array([ + 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]) + ]; + this.P = new Uint32Array([ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b]); +}; + +function F(S, x8, i) { + return (((S[0][x8[i+3]] + + S[1][x8[i+2]]) ^ + S[2][x8[i+1]]) + + S[3][x8[i]]); +}; + +Blowfish.prototype.encipher = function(x, x8) { + if (x8 === undefined) { + x8 = new Uint8Array(x.buffer); + if (x.byteOffset !== 0) + x8 = x8.subarray(x.byteOffset); + } + x[0] ^= this.P[0]; + for (var i = 1; i < 16; i += 2) { + x[1] ^= F(this.S, x8, 0) ^ this.P[i]; + x[0] ^= F(this.S, x8, 4) ^ this.P[i+1]; + } + var t = x[0]; + x[0] = x[1] ^ this.P[17]; + x[1] = t; +}; + +Blowfish.prototype.decipher = function(x) { + var x8 = new Uint8Array(x.buffer); + if (x.byteOffset !== 0) + x8 = x8.subarray(x.byteOffset); + x[0] ^= this.P[17]; + for (var i = 16; i > 0; i -= 2) { + x[1] ^= F(this.S, x8, 0) ^ this.P[i]; + x[0] ^= F(this.S, x8, 4) ^ this.P[i-1]; + } + var t = x[0]; + x[0] = x[1] ^ this.P[0]; + x[1] = t; +}; + +function stream2word(data, databytes){ + var i, temp = 0; + for (i = 0; i < 4; i++, BLF_J++) { + if (BLF_J >= databytes) BLF_J = 0; + temp = (temp << 8) | data[BLF_J]; + } + return temp; +}; + +Blowfish.prototype.expand0state = function(key, keybytes) { + var d = new Uint32Array(2), i, k; + var d8 = new Uint8Array(d.buffer); + + for (i = 0, BLF_J = 0; i < 18; i++) { + this.P[i] ^= stream2word(key, keybytes); + } + BLF_J = 0; + + for (i = 0; i < 18; i += 2) { + this.encipher(d, d8); + this.P[i] = d[0]; + this.P[i+1] = d[1]; + } + + for (i = 0; i < 4; i++) { + for (k = 0; k < 256; k += 2) { + this.encipher(d, d8); + this.S[i][k] = d[0]; + this.S[i][k+1] = d[1]; + } + } +}; + +Blowfish.prototype.expandstate = function(data, databytes, key, keybytes) { + var d = new Uint32Array(2), i, k; + + for (i = 0, BLF_J = 0; i < 18; i++) { + this.P[i] ^= stream2word(key, keybytes); + } + + for (i = 0, BLF_J = 0; i < 18; i += 2) { + d[0] ^= stream2word(data, databytes); + d[1] ^= stream2word(data, databytes); + this.encipher(d); + this.P[i] = d[0]; + this.P[i+1] = d[1]; + } + + for (i = 0; i < 4; i++) { + for (k = 0; k < 256; k += 2) { + d[0] ^= stream2word(data, databytes); + d[1] ^= stream2word(data, databytes); + this.encipher(d); + this.S[i][k] = d[0]; + this.S[i][k+1] = d[1]; + } + } + BLF_J = 0; +}; + +Blowfish.prototype.enc = function(data, blocks) { + for (var i = 0; i < blocks; i++) { + this.encipher(data.subarray(i*2)); + } +}; + +Blowfish.prototype.dec = function(data, blocks) { + for (var i = 0; i < blocks; i++) { + this.decipher(data.subarray(i*2)); + } +}; + +var BCRYPT_BLOCKS = 8, + BCRYPT_HASHSIZE = 32; + +function bcrypt_hash(sha2pass, sha2salt, out) { + var state = new Blowfish(), + cdata = new Uint32Array(BCRYPT_BLOCKS), i, + ciphertext = new Uint8Array([79,120,121,99,104,114,111,109,97,116,105, + 99,66,108,111,119,102,105,115,104,83,119,97,116,68,121,110,97,109, + 105,116,101]); //"OxychromaticBlowfishSwatDynamite" + + state.expandstate(sha2salt, 64, sha2pass, 64); + for (i = 0; i < 64; i++) { + state.expand0state(sha2salt, 64); + state.expand0state(sha2pass, 64); + } + + for (i = 0; i < BCRYPT_BLOCKS; i++) + cdata[i] = stream2word(ciphertext, ciphertext.byteLength); + for (i = 0; i < 64; i++) + state.enc(cdata, cdata.byteLength / 8); + + for (i = 0; i < BCRYPT_BLOCKS; i++) { + out[4*i+3] = cdata[i] >>> 24; + out[4*i+2] = cdata[i] >>> 16; + out[4*i+1] = cdata[i] >>> 8; + out[4*i+0] = cdata[i]; + } +}; + +function bcrypt_pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds) { + var sha2pass = new Uint8Array(64), + sha2salt = new Uint8Array(64), + out = new Uint8Array(BCRYPT_HASHSIZE), + tmpout = new Uint8Array(BCRYPT_HASHSIZE), + countsalt = new Uint8Array(saltlen+4), + i, j, amt, stride, dest, count, + origkeylen = keylen; + + if (rounds < 1) + return -1; + if (passlen === 0 || saltlen === 0 || keylen === 0 || + keylen > (out.byteLength * out.byteLength) || saltlen > (1<<20)) + return -1; + + stride = Math.floor((keylen + out.byteLength - 1) / out.byteLength); + amt = Math.floor((keylen + stride - 1) / stride); + + for (i = 0; i < saltlen; i++) + countsalt[i] = salt[i]; + + crypto_hash_sha512(sha2pass, pass, passlen); + + for (count = 1; keylen > 0; count++) { + countsalt[saltlen+0] = count >>> 24; + countsalt[saltlen+1] = count >>> 16; + countsalt[saltlen+2] = count >>> 8; + countsalt[saltlen+3] = count; + + crypto_hash_sha512(sha2salt, countsalt, saltlen + 4); + bcrypt_hash(sha2pass, sha2salt, tmpout); + for (i = out.byteLength; i--;) + out[i] = tmpout[i]; + + for (i = 1; i < rounds; i++) { + crypto_hash_sha512(sha2salt, tmpout, tmpout.byteLength); + bcrypt_hash(sha2pass, sha2salt, tmpout); + for (j = 0; j < out.byteLength; j++) + out[j] ^= tmpout[j]; + } + + amt = Math.min(amt, keylen); + for (i = 0; i < amt; i++) { + dest = i * stride + (count - 1); + if (dest >= origkeylen) + break; + key[dest] = out[i]; + } + keylen -= i; + } + + return 0; +}; + +module.exports = { + BLOCKS: BCRYPT_BLOCKS, + HASHSIZE: BCRYPT_HASHSIZE, + hash: bcrypt_hash, + pbkdf: bcrypt_pbkdf +}; diff --git a/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/package.json b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/package.json new file mode 100644 index 0000000..e93a969 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/bcrypt-pbkdf/package.json @@ -0,0 +1,15 @@ +{ + "name": "bcrypt-pbkdf", + "version": "1.0.2", + "description": "Port of the OpenBSD bcrypt_pbkdf function to pure JS", + "repository": { + "type": "git", + "url": "git://github.com/joyent/node-bcrypt-pbkdf.git" + }, + "main": "index.js", + "dependencies": { + "tweetnacl": "^0.14.3" + }, + "devDependencies": {}, + "license": "BSD-3-Clause" +} diff --git a/tasks/enduro-trails/prototype/node_modules/nan/.github/workflows/ci.yml b/tasks/enduro-trails/prototype/node_modules/nan/.github/workflows/ci.yml new file mode 100644 index 0000000..e12a2c9 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs +# https://github.com/actions/setup-node +# https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories + +name: ci +on: + push: + # branches: [main] + pull_request: + # branches: [main] + workflow_dispatch: +permissions: + contents: read +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pre-commit/action@v3.0.1 + + ci: + strategy: + fail-fast: false + matrix: + node-version: [25.x, 24.x, 23.x, 22.x, 21.x, 20.x, 19.x, 18.x, 17.x, 16.x] + os: [windows-latest] + include: + - node-version: lts/* + os: macos-15-intel # macOS on Intel + - node-version: lts/* + os: macos-latest # macOS on arm64 + - node-version: lts/* + os: ubuntu-latest # Linux on x64 + - node-version: lts/* + os: ubuntu-24.04-arm # Linux on arm64 + - node-version: lts/* + os: windows-2025 + - node-version: lts/* + os: windows-11-arm # Windows on arm64 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + # TODO: On Windows Node.js v11 these will fail but `make test` will succeed + - if: matrix.node-version != '11.x' + run: | + npm run-script rebuild-tests + npm test + - run: make test diff --git a/tasks/enduro-trails/prototype/node_modules/nan/.pre-commit-config.yaml b/tasks/enduro-trails/prototype/node_modules/nan/.pre-commit-config.yaml new file mode 100644 index 0000000..c1b1470 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/.pre-commit-config.yaml @@ -0,0 +1,8 @@ +repos: + - repo: https://github.com/cpplint/cpplint + rev: 2.0.0 + hooks: + - id: cpplint + args: + - --filter=-whitespace/indent_namespace,-whitespace/parens + - --linelength=88 diff --git a/tasks/enduro-trails/prototype/node_modules/nan/CHANGELOG.md b/tasks/enduro-trails/prototype/node_modules/nan/CHANGELOG.md new file mode 100644 index 0000000..2293232 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/CHANGELOG.md @@ -0,0 +1,599 @@ +# NAN ChangeLog + +**Version 2.26.2: current Node 25.8.1, Node 0.12: 0.12.18, Node 0.10: 0.10.48, iojs: 3.3.1** + +### 2.26.2 Mar 18 2026 + - Bugfix: Fix nan_weak.h for V8 >= 14.2.194 (missing EmbedderDataTypeTag) (#1013) 794124c493555106eebaa3e82c0d6147d0213183 + +### 2.26.1 Mar 17 2026 + - Bugfix: remove unintended copy-pasted line (#1011) 0456abb33a3ce412b644c45fb8401776d2f647eb + +### 2.26.0 Mar 17 2026 + - Feature: Add EmbedderDataTypeTag to SetAlignedPointerInInternalField and GetAlignedPointerFromInternalField for v8 >= 14 (#1010) fcc7b7d4698f9cd87c7dc08b431ab82bed1b3b8c + +### 2.25.0 Jan 25 2026 + - Feature: Updating SetAccessor method to support v8 14.4 (#1007) 333d98942f1fe412a4dd859d6b1b0a9bef43c1f8 + +### 2.24.0 Dec 03 2025 + - Feature: Adding new Nan::TryEncode() wrapper for node::TryEncode() (#1005) fd5ff3f5ab3f5bb6bb6dd2d247f3eccd79227854 + +### 2.23.1 Nov 05 2025 + - Feature: Adding WriteUtf8V2() and SetPrototypeV2() methods to support v8 14.3 (#1004) 9e1106ab7b7036d262df7f430eee3bff33757e9a + +### 2.23.0 Jul 10 2025 + + - Feature: Support Node 23 (#979) 59ab6d03d5d68554290ee9f34003cd90aa92c185 + +### 2.22.2 Feb 26 2025 + + - Bugfix: Fix version guard for `ScriptOrigin` constructors (#989) 053239d73702ac11fa0c3c438f85c1409f960f89 + +### 2.22.1 Feb 21 2025 + + - Build: Fix compatibility with Python >= 3.12 (#987) b5d90f15730b620fb6cc4fed079674740424539a + +### 2.22.0 Oct 11 2024 + + - Feature: replace SetAccessor -> SetNativeDataProperty (#977) 6bd62c9a0004339d5d1e18a945c84929d0f6b808 + +### 2.21.0 Oct 10 2024 + + - Feature: Support for node version 20.17.0 (#976) a7df36eda8a7fe8581c00a18590f5e4faafca7ae + +### 2.20.0 Jun 12 2024 + + - Feature: fix removal of v8::CopyablePersistent (#970) 5805ca5c4c2eef9a65316b68741e29f4825c511f + +### 2.19.0 Mar 6 2024 + + - Feature: Fix builds for Electron 29 (#966) 1b630ddb3412cde35b64513662b440f9fd71e1ff + +### 2.18.0 Sep 12 2023 + + - Feature: Cast v8::Object::GetInternalField() return value to v8::Value (#956) bdfee1788239f735b67fe6b46b1439da755e9b62 + +### 2.17.0 Oct 10 2022 + + - Feature: overload deprecated AccessorSignatures (#943) 7f9ceb80fbc45c9ba1a10e6591ccbef9e8dee6b4 + +### 2.16.0 May 25 2022 + + - Feature: Add support for Node 18 (#937) 16fa32231e2ccd89d2804b3f765319128b20c4ac + +### 2.15.0 Aug 4 2021 + + - Feature: add ScriptOrigin (#918) d09debf9eeedcb7ca4073e84ffe5fbb455ecb709 + +### 2.14.2 Oct 13 2020 + + - Bugfix: fix gcc 8 function cast warning (#899) 35f0fab205574b2cbda04e6347c8b2db755e124f + +### 2.14.1 Apr 21 2020 + + - Bugfix: use GetBackingStore() instead of GetContents() (#888) 2c023bd447661a61071da318b0ff4003c3858d39 + +### 2.14.0 May 16 2019 + + - Feature: Add missing methods to Nan::Maybe (#852) 4e962489fb84a184035b9fa74f245f650249aca6 + +### 2.13.2 Mar 24 2019 + + - Bugfix: remove usage of deprecated `IsNearDeath` (#842) fbaf42252af279c3d867c6b193571f9711c39847 + +### 2.13.1 Mar 14 2019 + + - Bugfix: check V8 version directly instead of inferring from NMV (#840) 12f9df9f393285de8fb4a8cd01478dc4fe3b089d + +### 2.13.0 Mar 13 2019 + + - Feature: add support for node master (#831) 113c0282072e7ff4f9dfc98b432fd894b798c2c + +### 2.12.1 Dec 18 2018 + + - Bugfix: Fix build breakage with Node.js 10.0.0-10.9.0. (#833) 625e90e8fef8d39ffa7247250a76a100b2487474 + +### 2.12.0 Dec 16 2018 + + - Bugfix: Add scope.Escape() to Call() (#817) 2e5ed4fc3a8ac80a6ef1f2a55099ab3ac8800dc6 + - Bugfix: Fix Node.js v10.12.0 deprecation warnings. 509859cc23b1770376b56550a027840a2ce0f73d + - Feature: Allow SetWeak() for non-object persistent handles. (#824) e6ef6a48e7e671fe3e4b7dddaa8912a3f8262ecd + +### 2.11.1 Sep 29 2018 + + - Fix: adapt to V8 7.0 24a22c3b25eeeec2016c6ec239bdd6169e985447 + +### 2.11.0 Aug 25 2018 + + - Removal: remove `FunctionCallbackInfo::Callee` for nodejs `>= 10` 1a56c0a6efd4fac944cb46c30912a8e023bda7d4 + - Bugfix: Fix `AsyncProgressWorkerBase::WorkProgress` sends invalid data b0c764d1dab11e9f8b37ffb81e2560a4498aad5e + - Feature: Introduce `GetCurrentEventLoop` b4911b0bb1f6d47d860e10ec014d941c51efac5e + - Feature: Add `NAN_MODULE_WORKER_ENABLED` macro as a replacement for `NAN_MODULE` b058fb047d18a58250e66ae831444441c1f2ac7a + +### 2.10.0 Mar 16 2018 + + - Deprecation: Deprecate `MakeCallback` 5e92b19a59e194241d6a658bd6ff7bfbda372950 + - Feature: add `Nan::Call` overload 4482e1242fe124d166fc1a5b2be3c1cc849fe452 + - Feature: add more `Nan::Call` overloads 8584e63e6d04c7d2eb8c4a664e4ef57d70bf672b + - Feature: Fix deprecation warnings for Node 10 1caf258243b0602ed56922bde74f1c91b0cbcb6a + +### 2.9.2 Feb 22 2018 + + - Bugfix: Bandaid for async hooks 212bd2f849be14ef1b02fc85010b053daa24252b + +### 2.9.1 Feb 22 2018 + + - Bugfix: Avoid deprecation warnings in deprecated `Nan::Callback::operator()` 372b14d91289df4604b0f81780709708c45a9aa4 + - Bugfix: Avoid deprecation warnings in `Nan::JSON` 3bc294bce0b7d0a3ee4559926303e5ed4866fda2 + +### 2.9.0 Feb 22 2018 + + - Deprecation: Deprecate legacy `Callback::Call` 6dd5fa690af61ca3523004b433304c581b3ea309 + - Feature: introduce `AsyncResource` class 90c0a179c0d8cb5fd26f1a7d2b1d6231eb402d48o + - Feature: Add context aware `Nan::Callback::Call` functions 7169e09fb088418b6e388222e88b4c13f07ebaee + - Feature: Make `AsyncWorker` context aware 066ba21a6fb9e2b5230c9ed3a6fc51f1211736a4 + - Feature: add `Callback` overload to `Nan::Call` 5328daf66e202658c1dc0d916c3aaba99b3cc606 + - Bugfix: fix warning: suggest parentheses around `&&` within `||` b2bb63d68b8ae623a526b542764e1ac82319cb2c + - Bugfix: Fix compilation on io.js 3 d06114dba0a522fb436f0c5f47b994210968cd7b + +### 2.8.0 Nov 15 2017 + + - Deprecation: Deprecate `Nan::ForceSet` in favor of `Nan::DefineOwnProperty()` 95cbb976d6fbbba88ba0f86dd188223a8591b4e7 + - Feature: Add `Nan::AsyncProgressQueueWorker` a976636ecc2ef617d1b061ce4a6edf39923691cb + - Feature: Add `Nan::DefineOwnProperty()` 95cbb976d6fbbba88ba0f86dd188223a8591b4e7 + - Bugfix: Fix compiling on io.js 1 & 2 82705a64503ce60c62e98df5bd02972bba090900 + - Bugfix: Use DefineOwnProperty instead of ForceSet 95cbb976d6fbbba88ba0f86dd188223a8591b4e7 + +### 2.7.0 Aug 30 2017 + + - Feature: Add `Nan::To()` overload. b93280670c9f6da42ed4cf6cbf085ffdd87bd65b + - Bugfix: Fix ternary in `Nan::MaybeLocal::FromMaybe()`. 79a26f7d362e756a9524e672a82c3d603b542867 + +### 2.6.2 Apr 12 2017 + + - Bugfix: Fix v8::JSON::Parse() deprecation warning. 87f6a3c65815fa062296a994cc863e2fa124867d + +### 2.6.1 Apr 6 2017 + + - Bugfix: nan_json.h: fix build breakage in Node 6 ac8d47dc3c10bfbf3f15a6b951633120c0ee6d51 + +### 2.6.0 Apr 6 2017 + + - Feature: nan: add support for JSON::Parse & Stringify b533226c629cce70e1932a873bb6f849044a56c5 + +### 2.5.1 Jan 23 2017 + + - Bugfix: Fix disappearing handle for private value 6a80995694f162ef63dbc9948fbefd45d4485aa0 + - Bugfix: Add missing scopes a93b8bae6bc7d32a170db6e89228b7f60ee57112 + - Bugfix: Use string::data instead of string::front in NewOneByteString d5f920371e67e1f3b268295daee6e83af86b6e50 + +### 2.5.0 Dec 21 2016 + + - Feature: Support Private accessors a86255cb357e8ad8ccbf1f6a4a901c921e39a178 + - Bugfix: Abort in delete operators that shouldn't be called 0fe38215ff8581703967dfd26c12793feb960018 + +### 2.4.0 Jul 10 2016 + + - Feature: Rewrite Callback to add Callback::Reset c4cf44d61f8275cd5f7b0c911d7a806d4004f649 + - Feature: AsyncProgressWorker: add template types for .send 1242c9a11a7ed481c8f08ec06316385cacc513d0 + - Bugfix: Add constness to old Persistent comparison operators bd43cb9982c7639605d60fd073efe8cae165d9b2 + +### 2.3.5 May 31 2016 + + - Bugfix: Replace NAN_INLINE with 'inline' keyword. 71819d8725f822990f439479c9aba3b240804909 + +### 2.3.4 May 31 2016 + + - Bugfix: Remove V8 deprecation warnings 0592fb0a47f3a1c7763087ebea8e1138829f24f9 + - Bugfix: Fix new versions not to use WeakCallbackInfo::IsFirstPass 615c19d9e03d4be2049c10db0151edbc3b229246 + - Bugfix: Make ObjectWrap::handle() const d19af99595587fe7a26bd850af6595c2a7145afc + - Bugfix: Fix compilation errors related to 0592fb0a47f3a1c7763087ebea8e1138829f24f9 e9191c525b94f652718325e28610a1adcf90fed8 + +### 2.3.3 May 4 2016 + + - Bugfix: Refactor SetMethod() to deal with v8::Templates (#566) b9083cf6d5de6ebe6bcb49c7502fbb7c0d9ddda8 + +### 2.3.2 Apr 27 2016 + + - Bugfix: Fix compilation on outdated versions due to Handle removal f8b7c875d04d425a41dfd4f3f8345bc3a11e6c52 + +### 2.3.1 Apr 27 2016 + + - Bugfix: Don't use deprecated v8::Template::Set() in SetMethod a90951e9ea70fa1b3836af4b925322919159100e + +### 2.3.0 Apr 27 2016 + + - Feature: added Signal() for invoking async callbacks without sending data from AsyncProgressWorker d8adba45f20e077d00561b20199133620c990b38 + - Bugfix: Don't use deprecated v8::Template::Set() 00dacf0a4b86027415867fa7f1059acc499dcece + +### 2.2.1 Mar 29 2016 + + - Bugfix: Use NewFromUnsigned in ReturnValue::Set(uint32_t i) for pre_12 3a18f9bdce29826e0e4c217854bc476918241a58 + - Performance: Remove unneeeded nullptr checks b715ef44887931c94f0d1605b3b1a4156eebece9 + +### 2.2.0 Jan 9 2016 + + - Feature: Add Function::Call wrapper 4c157474dacf284d125c324177b45aa5dabc08c6 + - Feature: Rename GC*logueCallback to GCCallback for > 4.0 3603435109f981606d300eb88004ca101283acec + - Bugfix: Fix Global::Pass for old versions 367e82a60fbaa52716232cc89db1cc3f685d77d9 + - Bugfix: Remove weird MaybeLocal wrapping of what already is a MaybeLocal 23b4590db10c2ba66aee2338aebe9751c4cb190b + +### 2.1.0 Oct 8 2015 + + - Deprecation: Deprecate NanErrnoException in favor of ErrnoException 0af1ca4cf8b3f0f65ed31bc63a663ab3319da55c + - Feature: added helper class for accessing contents of typedarrays 17b51294c801e534479d5463697a73462d0ca555 + - Feature: [Maybe types] Add MakeMaybe(...) 48d7b53d9702b0c7a060e69ea10fea8fb48d814d + - Feature: new: allow utf16 string with length 66ac6e65c8ab9394ef588adfc59131b3b9d8347b + - Feature: Introduce SetCallHandler and SetCallAsFunctionHandler 7764a9a115d60ba10dc24d86feb0fbc9b4f75537 + - Bugfix: Enable creating Locals from Globals under Node 0.10. 9bf9b8b190821af889790fdc18ace57257e4f9ff + - Bugfix: Fix issue #462 where PropertyCallbackInfo data is not stored safely. 55f50adedd543098526c7b9f4fffd607d3f9861f + +### 2.0.9 Sep 8 2015 + + - Bugfix: EscapableHandleScope in Nan::NewBuffer for Node 0.8 and 0.10 b1654d7 + +### 2.0.8 Aug 28 2015 + + - Work around duplicate linking bug in clang 11902da + +### 2.0.7 Aug 26 2015 + + - Build: Repackage + +### 2.0.6 Aug 26 2015 + + - Bugfix: Properly handle null callback in FunctionTemplate factory 6e99cb1 + - Bugfix: Remove unused static std::map instances 525bddc + - Bugfix: Make better use of maybe versions of APIs bfba85b + - Bugfix: Fix shadowing issues with handle in ObjectWrap 0a9072d + +### 2.0.5 Aug 10 2015 + + - Bugfix: Reimplement weak callback in ObjectWrap 98d38c1 + - Bugfix: Make sure callback classes are not assignable, copyable or movable 81f9b1d + +### 2.0.4 Aug 6 2015 + + - Build: Repackage + +### 2.0.3 Aug 6 2015 + + - Bugfix: Don't use clang++ / g++ syntax extension. 231450e + +### 2.0.2 Aug 6 2015 + + - Build: Repackage + +### 2.0.1 Aug 6 2015 + + - Bugfix: Add workaround for missing REPLACE_INVALID_UTF8 60d6687 + - Bugfix: Reimplement ObjectWrap from scratch to prevent memory leaks 6484601 + - Bugfix: Fix Persistent leak in FunctionCallbackInfo and PropertyCallbackInfo 641ef5f + - Bugfix: Add missing overload for Nan::NewInstance that takes argc/argv 29450ed + +### 2.0.0 Jul 31 2015 + + - Change: Renamed identifiers with leading underscores b5932b4 + - Change: Replaced NanObjectWrapHandle with class NanObjectWrap 464f1e1 + - Change: Replace NanScope and NanEscpableScope macros with classes 47751c4 + - Change: Rename NanNewBufferHandle to NanNewBuffer 6745f99 + - Change: Rename NanBufferUse to NanNewBuffer 3e8b0a5 + - Change: Rename NanNewBuffer to NanCopyBuffer d6af78d + - Change: Remove Nan prefix from all names 72d1f67 + - Change: Update Buffer API for new upstream changes d5d3291 + - Change: Rename Scope and EscapableScope to HandleScope and EscapableHandleScope 21a7a6a + - Change: Get rid of Handles e6c0daf + - Feature: Support io.js 3 with V8 4.4 + - Feature: Introduce NanPersistent 7fed696 + - Feature: Introduce NanGlobal 4408da1 + - Feature: Added NanTryCatch 10f1ca4 + - Feature: Update for V8 v4.3 4b6404a + - Feature: Introduce NanNewOneByteString c543d32 + - Feature: Introduce namespace Nan 67ed1b1 + - Removal: Remove NanLocker and NanUnlocker dd6e401 + - Removal: Remove string converters, except NanUtf8String, which now follows the node implementation b5d00a9 + - Removal: Remove NanReturn* macros d90a25c + - Removal: Remove HasInstance e8f84fe + + +### 1.9.0 Jul 31 2015 + + - Feature: Added `NanFatalException` 81d4a2c + - Feature: Added more error types 4265f06 + - Feature: Added dereference and function call operators to NanCallback c4b2ed0 + - Feature: Added indexed GetFromPersistent and SaveToPersistent edd510c + - Feature: Added more overloads of SaveToPersistent and GetFromPersistent 8b1cef6 + - Feature: Added NanErrnoException dd87d9e + - Correctness: Prevent assign, copy, and move for classes that do not support it 1f55c59, 4b808cb, c96d9b2, fba4a29, 3357130 + - Deprecation: Deprecate `NanGetPointerSafe` and `NanSetPointerSafe` 81d4a2c + - Deprecation: Deprecate `NanBooleanOptionValue` and `NanUInt32OptionValue` 0ad254b + +### 1.8.4 Apr 26 2015 + + - Build: Repackage + +### 1.8.3 Apr 26 2015 + + - Bugfix: Include missing header 1af8648 + +### 1.8.2 Apr 23 2015 + + - Build: Repackage + +### 1.8.1 Apr 23 2015 + + - Bugfix: NanObjectWrapHandle should take a pointer 155f1d3 + +### 1.8.0 Apr 23 2015 + + - Feature: Allow primitives with NanReturnValue 2e4475e + - Feature: Added comparison operators to NanCallback 55b075e + - Feature: Backport thread local storage 15bb7fa + - Removal: Remove support for signatures with arguments 8a2069d + - Correcteness: Replaced NanObjectWrapHandle macro with function 0bc6d59 + +### 1.7.0 Feb 28 2015 + + - Feature: Made NanCallback::Call accept optional target 8d54da7 + - Feature: Support atom-shell 0.21 0b7f1bb + +### 1.6.2 Feb 6 2015 + + - Bugfix: NanEncode: fix argument type for node::Encode on io.js 2be8639 + +### 1.6.1 Jan 23 2015 + + - Build: version bump + +### 1.5.3 Jan 23 2015 + + - Build: repackage + +### 1.6.0 Jan 23 2015 + + - Deprecated `NanNewContextHandle` in favor of `NanNew` 49259af + - Support utility functions moved in newer v8 versions (Node 0.11.15, io.js 1.0) a0aa179 + - Added `NanEncode`, `NanDecodeBytes` and `NanDecodeWrite` 75e6fb9 + +### 1.5.2 Jan 23 2015 + + - Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4 + - Bugfix: Readded missing String constructors 18d828f + - Bugfix: Add overload handling NanNew(..) 5ef813b + - Bugfix: Fix uv_work_cb versioning 997e4ae + - Bugfix: Add function factory and test 4eca89c + - Bugfix: Add object template factory and test cdcb951 + - Correctness: Lifted an io.js related typedef c9490be + - Correctness: Make explicit downcasts of String lengths 00074e6 + - Windows: Limit the scope of disabled warning C4530 83d7deb + +### 1.5.1 Jan 15 2015 + + - Build: version bump + +### 1.4.3 Jan 15 2015 + + - Build: version bump + +### 1.4.2 Jan 15 2015 + + - Feature: Support io.js 0dbc5e8 + +### 1.5.0 Jan 14 2015 + + - Feature: Support io.js b003843 + - Correctness: Improved NanNew internals 9cd4f6a + - Feature: Implement progress to NanAsyncWorker 8d6a160 + +### 1.4.1 Nov 8 2014 + + - Bugfix: Handle DEBUG definition correctly + - Bugfix: Accept int as Boolean + +### 1.4.0 Nov 1 2014 + + - Feature: Added NAN_GC_CALLBACK 6a5c245 + - Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8 + - Correctness: Added constness to references in NanHasInstance 02c61cd + - Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6 + - Windoze: Shut Visual Studio up when compiling 8d558c1 + - License: Switch to plain MIT from custom hacked MIT license 11de983 + - Build: Added test target to Makefile e232e46 + - Performance: Removed superfluous scope in NanAsyncWorker f4b7821 + - Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208 + - Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450 + +### 1.3.0 Aug 2 2014 + + - Added NanNew(std::string) + - Added NanNew(std::string&) + - Added NanAsciiString helper class + - Added NanUtf8String helper class + - Added NanUcs2String helper class + - Deprecated NanRawString() + - Deprecated NanCString() + - Added NanGetIsolateData(v8::Isolate *isolate) + - Added NanMakeCallback(v8::Handle target, v8::Handle func, int argc, v8::Handle* argv) + - Added NanMakeCallback(v8::Handle target, v8::Handle symbol, int argc, v8::Handle* argv) + - Added NanMakeCallback(v8::Handle target, const char* method, int argc, v8::Handle* argv) + - Added NanSetTemplate(v8::Handle templ, v8::Handle name , v8::Handle value, v8::PropertyAttribute attributes) + - Added NanSetPrototypeTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) + - Added NanSetInstanceTemplate(v8::Local templ, const char *name, v8::Handle value) + - Added NanSetInstanceTemplate(v8::Local templ, v8::Handle name, v8::Handle value, v8::PropertyAttribute attributes) + +### 1.2.0 Jun 5 2014 + + - Add NanSetPrototypeTemplate + - Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class, + introduced _NanWeakCallbackDispatcher + - Removed -Wno-unused-local-typedefs from test builds + - Made test builds Windows compatible ('Sleep()') + +### 1.1.2 May 28 2014 + + - Release to fix more stuff-ups in 1.1.1 + +### 1.1.1 May 28 2014 + + - Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0 + +### 1.1.0 May 25 2014 + + - Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead + - Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]), + (uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*, + v8::String::ExternalAsciiStringResource* + - Deprecate NanSymbol() + - Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker + +### 1.0.0 May 4 2014 + + - Heavy API changes for V8 3.25 / Node 0.11.13 + - Use cpplint.py + - Removed NanInitPersistent + - Removed NanPersistentToLocal + - Removed NanFromV8String + - Removed NanMakeWeak + - Removed NanNewLocal + - Removed NAN_WEAK_CALLBACK_OBJECT + - Removed NAN_WEAK_CALLBACK_DATA + - Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions + - Introduce NanUndefined, NanNull, NanTrue and NanFalse + - Introduce NanEscapableScope and NanEscapeScope + - Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node) + - Introduce NanMakeCallback for node::MakeCallback + - Introduce NanSetTemplate + - Introduce NanGetCurrentContext + - Introduce NanCompileScript and NanRunScript + - Introduce NanAdjustExternalMemory + - Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback + - Introduce NanGetHeapStatistics + - Rename NanAsyncWorker#SavePersistent() to SaveToPersistent() + +### 0.8.0 Jan 9 2014 + + - NanDispose -> NanDisposePersistent, deprecate NanDispose + - Extract _NAN_*_RETURN_TYPE, pull up NAN_*() + +### 0.7.1 Jan 9 2014 + + - Fixes to work against debug builds of Node + - Safer NanPersistentToLocal (avoid reinterpret_cast) + - Speed up common NanRawString case by only extracting flattened string when necessary + +### 0.7.0 Dec 17 2013 + + - New no-arg form of NanCallback() constructor. + - NanCallback#Call takes Handle rather than Local + - Removed deprecated NanCallback#Run method, use NanCallback#Call instead + - Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS + - Restore (unofficial) Node 0.6 compatibility at NanCallback#Call() + - Introduce NanRawString() for char* (or appropriate void*) from v8::String + (replacement for NanFromV8String) + - Introduce NanCString() for null-terminated char* from v8::String + +### 0.6.0 Nov 21 2013 + + - Introduce NanNewLocal(v8::Handle value) for use in place of + v8::Local::New(...) since v8 started requiring isolate in Node 0.11.9 + +### 0.5.2 Nov 16 2013 + + - Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public + +### 0.5.1 Nov 12 2013 + + - Use node::MakeCallback() instead of direct v8::Function::Call() + +### 0.5.0 Nov 11 2013 + + - Added @TooTallNate as collaborator + - New, much simpler, "include_dirs" for binding.gyp + - Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros + +### 0.4.4 Nov 2 2013 + + - Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+ + +### 0.4.3 Nov 2 2013 + + - Include node_object_wrap.h, removed from node.h for Node 0.11.8. + +### 0.4.2 Nov 2 2013 + + - Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for + Node 0.11.8 release. + +### 0.4.1 Sep 16 2013 + + - Added explicit `#include ` as it was removed from node.h for v0.11.8 + +### 0.4.0 Sep 2 2013 + + - Added NAN_INLINE and NAN_DEPRECATED and made use of them + - Added NanError, NanTypeError and NanRangeError + - Cleaned up code + +### 0.3.2 Aug 30 2013 + + - Fix missing scope declaration in GetFromPersistent() and SaveToPersistent + in NanAsyncWorker + +### 0.3.1 Aug 20 2013 + + - fix "not all control paths return a value" compile warning on some platforms + +### 0.3.0 Aug 19 2013 + + - Made NAN work with NPM + - Lots of fixes to NanFromV8String, pulling in features from new Node core + - Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API + - Added optional error number argument for NanThrowError() + - Added NanInitPersistent() + - Added NanReturnNull() and NanReturnEmptyString() + - Added NanLocker and NanUnlocker + - Added missing scopes + - Made sure to clear disposed Persistent handles + - Changed NanAsyncWorker to allocate error messages on the heap + - Changed NanThrowError(Local) to NanThrowError(Handle) + - Fixed leak in NanAsyncWorker when errmsg is used + +### 0.2.2 Aug 5 2013 + + - Fixed usage of undefined variable with node::BASE64 in NanFromV8String() + +### 0.2.1 Aug 5 2013 + + - Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for + NanFromV8String() + +### 0.2.0 Aug 5 2013 + + - Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR, + NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY + - Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS, + _NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS, + _NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS, + _NAN_PROPERTY_QUERY_ARGS + - Added NanGetInternalFieldPointer, NanSetInternalFieldPointer + - Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT, + NAN_WEAK_CALLBACK_DATA, NanMakeWeak + - Renamed THROW_ERROR to _NAN_THROW_ERROR + - Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*) + - Added NanBufferUse(char*, uint32_t) + - Added NanNewContextHandle(v8::ExtensionConfiguration*, + v8::Handle, v8::Handle) + - Fixed broken NanCallback#GetFunction() + - Added optional encoding and size arguments to NanFromV8String() + - Added NanGetPointerSafe() and NanSetPointerSafe() + - Added initial test suite (to be expanded) + - Allow NanUInt32OptionValue to convert any Number object + +### 0.1.0 Jul 21 2013 + + - Added `NAN_GETTER`, `NAN_SETTER` + - Added `NanThrowError` with single Local argument + - Added `NanNewBufferHandle` with single uint32_t argument + - Added `NanHasInstance(Persistent&, Handle)` + - Added `Local NanCallback#GetFunction()` + - Added `NanCallback#Call(int, Local[])` + - Deprecated `NanCallback#Run(int, Local[])` in favour of Call diff --git a/tasks/enduro-trails/prototype/node_modules/nan/CMakeLists.txt b/tasks/enduro-trails/prototype/node_modules/nan/CMakeLists.txt new file mode 100644 index 0000000..fe3a7e0 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/CMakeLists.txt @@ -0,0 +1,138 @@ +cmake_minimum_required(VERSION 3.5) +project(nan) + +set(CMAKE_CXX_STANDARD 11) + +set(CPPLINT "${CMAKE_CURRENT_SOURCE_DIR}/cpplint.py") +set(MODULES symbols strings) +set(SOURCES "") +set(ADDONS "") + +foreach(MODULE ${MODULES}) + list(APPEND SOURCES "test/cpp/${MODULE}.cpp") + list(APPEND ADDONS "test/build/${CMAKE_BUILD_TYPE}/${MODULE}.node") +endforeach() + +set(LINT_SOURCES examples/async_pi_estimate/addon.cc + examples/async_pi_estimate/async.cc + examples/async_pi_estimate/async.h + examples/async_pi_estimate/pi_est.cc + examples/async_pi_estimate/pi_est.h + examples/async_pi_estimate/sync.cc + examples/async_pi_estimate/sync.h + nan.h + nan_callbacks.h + nan_callbacks_12_inl.h + nan_callbacks_pre_12_inl.h + nan_converters.h + nan_converters_43_inl.h + nan_converters_pre_43_inl.h + nan_define_own_property_helper.h + nan_implementation_12_inl.h + nan_implementation_pre_12_inl.h + nan_json.h + nan_maybe_43_inl.h + nan_maybe_pre_43_inl.h + nan_new.h + nan_object_wrap.h + nan_persistent_12_inl.h + nan_persistent_pre_12_inl.h + nan_private.h + nan_scriptorigin.h + nan_string_bytes.h + nan_weak.h + test/cpp/accessors.cpp + test/cpp/accessors2.cpp + test/cpp/asyncresource.cpp + test/cpp/asyncworker.cpp + test/cpp/asyncprogressworker.cpp + test/cpp/asyncprogressworkerstream.cpp + test/cpp/asyncprogressworkersignal.cpp + test/cpp/asyncprogressqueueworker.cpp + test/cpp/asyncprogressqueueworkerstream.cpp + test/cpp/asyncworkererror.cpp + test/cpp/buffer.cpp + test/cpp/bufferworkerpersistent.cpp + test/cpp/error.cpp + test/cpp/gc.cpp + test/cpp/indexedinterceptors.cpp + test/cpp/callbackcontext.cpp + test/cpp/converters.cpp + test/cpp/isolatedata.cpp + test/cpp/json-parse.cpp + test/cpp/json-stringify.cpp + test/cpp/makecallback.cpp + test/cpp/maybe.cpp + test/cpp/morenews.cpp + test/cpp/multifile1.cpp + test/cpp/multifile2.cpp + test/cpp/multifile2.h + test/cpp/namedinterceptors.cpp + test/cpp/nancallback.cpp + test/cpp/nannew.cpp + test/cpp/news.cpp + test/cpp/objectwraphandle.cpp + test/cpp/persistent.cpp + test/cpp/private.cpp + test/cpp/returnemptystring.cpp + test/cpp/returnnull.cpp + test/cpp/returnundefined.cpp + test/cpp/returnvalue.cpp + test/cpp/setcallhandler.cpp + test/cpp/settemplate.cpp + test/cpp/sleep.h + test/cpp/strings.cpp + test/cpp/symbols.cpp + test/cpp/threadlocal.cpp + test/cpp/trycatch.cpp + test/cpp/typedarrays.cpp + test/cpp/weak.cpp + test/cpp/weak2.cpp + test/cpp/wrappedobjectfactory.cpp + node_modules/node-gyp/gyp/data/win/large-pdb-shim.cc) + +set(FILTER "-build/include_subdir,-whitespace/parens") + +find_package(Python COMPONENTS Interpreter Development REQUIRED) + +execute_process( + COMMAND npm install + OUTPUT_FILE node_modules + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_custom_target(lint + COMMAND ${Python_EXECUTABLE} ${CPPLINT} --filter=${FILTER} ${LINT_SOURCES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_custom_target(test + DEPENDS ${ADDONS} + COMMAND npm test +) + +add_custom_target(forcetest + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test + COMMAND ../node_modules/.bin/node-gyp rebuild + COMMAND npm test +) + +add_custom_target(docs + DEPENDS README.md doc/.build.sh doc/asyncworker.md doc/buffers.md doc/callback.md + doc/converters.md doc/errors.md doc/maybe_types.md doc/methods.md doc/new.md + doc/node_misc.md doc/persistent.md doc/scopes.md doc/script.md doc/string_bytes.md + doc/v8_internals.md doc/json.md doc/v8_misc.md + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND doc/.build.sh +) + +add_custom_command(OUTPUT ${ADDONS} + DEPENDS ${SOURCES} nan.h nan_new.h nan_implementation_pre_12_inl.h nan_implementation_12_inl.h + nan_callbacks.h nan_callbacks_12_inl.h nan_callbacks_pre_12_inl.h nan_converters.h + nan_converters_43_inl.h nan_converters_pre_43_inl.h nan_define_own_property_helper.h + nan_json.h nan_maybe_43_inl.h nan_maybe_pre_43_inl.h nan_persistent_12_inl.h + nan_persistent_pre_12_inl.h nan_private.h nan_weak.h nan_scriptorigin.h nan_string_bytes.h + test/binding.gyp + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test + COMMAND ../node_modules/.bin/node-gyp rebuild +) \ No newline at end of file diff --git a/tasks/enduro-trails/prototype/node_modules/nan/LICENSE.md b/tasks/enduro-trails/prototype/node_modules/nan/LICENSE.md new file mode 100644 index 0000000..2d33043 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2018 [NAN contributors]() + +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/tasks/enduro-trails/prototype/node_modules/nan/README.md b/tasks/enduro-trails/prototype/node_modules/nan/README.md new file mode 100644 index 0000000..31f6e38 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/README.md @@ -0,0 +1,456 @@ +Native Abstractions for Node.js +=============================== + +**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24 and 25.** + +***Current version: 2.26.2*** + +*(See [CHANGELOG.md](https://github.com/nodejs/nan/blob/master/CHANGELOG.md) for complete ChangeLog)* + +[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/) + +[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan) + +Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.12 to 4.0, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle. + +This project also contains some helper utilities that make addon development a bit more pleasant. + + * **[News & Updates](#news)** + * **[Usage](#usage)** + * **[Example](#example)** + * **[API](#api)** + * **[Tests](#tests)** + * **[Known issues](#issues)** + * **[Governance & Contributing](#governance)** + + + +## News & Updates + + + +## Usage + +Simply add **NAN** as a dependency using a package manager like npm, yarn, or bun: + +``` bash +$ npm install nan +``` + +Pull in the path to **NAN** in your *binding.gyp* so that you can use `#include ` in your *.cpp* files: + +``` python +"include_dirs" : [ + "` when compiling your addon. + + + +## Example + +Just getting started with Nan? Take a look at the **[Node Add-on Examples](https://github.com/nodejs/node-addon-examples)**. + +Refer to a [quick-start **Nan** Boilerplate](https://github.com/fcanas/node-native-boilerplate) for a ready-to-go project that utilizes basic Nan functionality. + +For a simpler example, see the **[async pi estimation example](https://github.com/nodejs/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**. + +Yet another example is **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon. + +Also take a look at our comprehensive **[C++ test suite](https://github.com/nodejs/nan/tree/master/test/cpp)** which has a plethora of code snippets for your pasting pleasure. + + + +## API + +Additional to the NAN documentation below, please consult: + +* [The V8 Getting Started * Guide](https://v8.dev/docs/embed) +* [V8 API Documentation](https://v8docs.nodesource.com/) +* [Node Add-on Documentation](https://nodejs.org/api/addons.html) + + + +### JavaScript-accessible methods + +A _template_ is a blueprint for JavaScript functions and objects in a context. You can use a template to wrap C++ functions and data structures within JavaScript objects so that they can be manipulated from JavaScript. See the V8 Embedders Guide section on [Templates](https://github.com/v8/v8/wiki/Embedder%27s-Guide#templates) for further information. + +In order to expose functionality to JavaScript via a template, you must provide it to V8 in a form that it understands. Across the versions of V8 supported by NAN, JavaScript-accessible method signatures vary widely, NAN fully abstracts method declaration and provides you with an interface that is similar to the most recent V8 API but is backward-compatible with older versions that still use the now-deceased `v8::Argument` type. + +* **Method argument types** + - Nan::FunctionCallbackInfo + - Nan::PropertyCallbackInfo + - Nan::ReturnValue +* **Method declarations** + - Method declaration + - Getter declaration + - Setter declaration + - Property getter declaration + - Property setter declaration + - Property enumerator declaration + - Property deleter declaration + - Property query declaration + - Index getter declaration + - Index setter declaration + - Index enumerator declaration + - Index deleter declaration + - Index query declaration +* Method and template helpers + - Nan::SetMethod() + - Nan::SetPrototypeMethod() + - Nan::SetAccessor() + - Nan::SetNamedPropertyHandler() + - Nan::SetIndexedPropertyHandler() + - Nan::SetTemplate() + - Nan::SetPrototypeTemplate() + - Nan::SetInstanceTemplate() + - Nan::SetCallHandler() + - Nan::SetCallAsFunctionHandler() + +### Scopes + +A _local handle_ is a pointer to an object. All V8 objects are accessed using handles, they are necessary because of the way the V8 garbage collector works. + +A handle scope can be thought of as a container for any number of handles. When you've finished with your handles, instead of deleting each one individually you can simply delete their scope. + +The creation of `HandleScope` objects is different across the supported versions of V8. Therefore, NAN provides its own implementations that can be used safely across these. + + - Nan::HandleScope + - Nan::EscapableHandleScope + +Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://github.com/v8/v8/wiki/Embedder%27s%20Guide#handles-and-garbage-collection). + +### Persistent references + +An object reference that is independent of any `HandleScope` is a _persistent_ reference. Where a `Local` handle only lives as long as the `HandleScope` in which it was allocated, a `Persistent` handle remains valid until it is explicitly disposed. + +Due to the evolution of the V8 API, it is necessary for NAN to provide a wrapper implementation of the `Persistent` classes to supply compatibility across the V8 versions supported. + + - Nan::PersistentBase & v8::PersistentBase + - Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits + - Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits + - Nan::Persistent + - Nan::Global + - Nan::WeakCallbackInfo + - Nan::WeakCallbackType + +Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://v8.dev/docs/embed#handles-and-garbage-collection). + +### New + +NAN provides a `Nan::New()` helper for the creation of new JavaScript objects in a way that's compatible across the supported versions of V8. + + - Nan::New() + - Nan::Undefined() + - Nan::Null() + - Nan::True() + - Nan::False() + - Nan::EmptyString() + + +### Converters + +NAN contains functions that convert `v8::Value`s to other `v8::Value` types and native types. Since type conversion is not guaranteed to succeed, they return `Nan::Maybe` types. These converters can be used in place of `value->ToX()` and `value->XValue()` (where `X` is one of the types, e.g. `Boolean`) in a way that provides a consistent interface across V8 versions. Newer versions of V8 use the new `v8::Maybe` and `v8::MaybeLocal` types for these conversions, older versions don't have this functionality so it is provided by NAN. + + - Nan::To() + +### Maybe Types + +The `Nan::MaybeLocal` and `Nan::Maybe` types are monads that encapsulate `v8::Local` handles that _may be empty_. + +* **Maybe Types** + - Nan::MaybeLocal + - Nan::Maybe + - Nan::Nothing + - Nan::Just +* **Maybe Helpers** + - Nan::Call() + - Nan::ToDetailString() + - Nan::ToArrayIndex() + - Nan::Equals() + - Nan::NewInstance() + - Nan::GetFunction() + - Nan::Set() + - Nan::DefineOwnProperty() + - Nan::ForceSet() + - Nan::Get() + - Nan::GetPropertyAttributes() + - Nan::Has() + - Nan::Delete() + - Nan::GetPropertyNames() + - Nan::GetOwnPropertyNames() + - Nan::SetPrototype() + - Nan::ObjectProtoToString() + - Nan::HasOwnProperty() + - Nan::HasRealNamedProperty() + - Nan::HasRealIndexedProperty() + - Nan::HasRealNamedCallbackProperty() + - Nan::GetRealNamedPropertyInPrototypeChain() + - Nan::GetRealNamedProperty() + - Nan::CallAsFunction() + - Nan::CallAsConstructor() + - Nan::GetSourceLine() + - Nan::GetLineNumber() + - Nan::GetStartColumn() + - Nan::GetEndColumn() + - Nan::CloneElementAt() + - Nan::HasPrivate() + - Nan::GetPrivate() + - Nan::SetPrivate() + - Nan::DeletePrivate() + - Nan::MakeMaybe() + +### Script + +NAN provides `v8::Script` helpers as the API has changed over the supported versions of V8. + + - Nan::CompileScript() + - Nan::RunScript() + - Nan::ScriptOrigin + + +### JSON + +The _JSON_ object provides the C++ versions of the methods offered by the `JSON` object in javascript. V8 exposes these methods via the `v8::JSON` object. + + - Nan::JSON.Parse + - Nan::JSON.Stringify + +Refer to the V8 JSON object in the [V8 documentation](https://v8docs.nodesource.com/node-8.16/da/d6f/classv8_1_1_j_s_o_n.html) for more information about these methods and their arguments. + +### Errors + +NAN includes helpers for creating, throwing and catching Errors as much of this functionality varies across the supported versions of V8 and must be abstracted. + +Note that an Error object is simply a specialized form of `v8::Value`. + +Also consult the V8 Embedders Guide section on [Exceptions](https://v8.dev/docs/embed#exceptions) for more information. + + - Nan::Error() + - Nan::RangeError() + - Nan::ReferenceError() + - Nan::SyntaxError() + - Nan::TypeError() + - Nan::ThrowError() + - Nan::ThrowRangeError() + - Nan::ThrowReferenceError() + - Nan::ThrowSyntaxError() + - Nan::ThrowTypeError() + - Nan::FatalException() + - Nan::ErrnoException() + - Nan::TryCatch + + +### Buffers + +NAN's `node::Buffer` helpers exist as the API has changed across supported Node versions. Use these methods to ensure compatibility. + + - Nan::NewBuffer() + - Nan::CopyBuffer() + - Nan::FreeCallback() + +### Nan::Callback + +`Nan::Callback` makes it easier to use `v8::Function` handles as callbacks. A class that wraps a `v8::Function` handle, protecting it from garbage collection and making it particularly useful for storage and use across asynchronous execution. + + - Nan::Callback + +### Asynchronous work helpers + +`Nan::AsyncWorker`, `Nan::AsyncProgressWorker` and `Nan::AsyncProgressQueueWorker` are helper classes that make working with asynchronous code easier. + + - Nan::AsyncWorker + - Nan::AsyncProgressWorkerBase & Nan::AsyncProgressWorker + - Nan::AsyncProgressQueueWorker + - Nan::AsyncQueueWorker + +### Strings & Bytes + +Miscellaneous string & byte encoding and decoding functionality provided for compatibility across supported versions of V8 and Node. Implemented by NAN to ensure that all encoding types are supported, even for older versions of Node where they are missing. + + - Nan::Encoding + - Nan::Encode() + - Nan::TryEncode() + - Nan::DecodeBytes() + - Nan::DecodeWrite() + + +### Object Wrappers + +The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects. + + - Nan::ObjectWrap + + +### V8 internals + +The hooks to access V8 internals—including GC and statistics—are different across the supported versions of V8, therefore NAN provides its own hooks that call the appropriate V8 methods. + + - NAN_GC_CALLBACK() + - Nan::AddGCEpilogueCallback() + - Nan::RemoveGCEpilogueCallback() + - Nan::AddGCPrologueCallback() + - Nan::RemoveGCPrologueCallback() + - Nan::GetHeapStatistics() + - Nan::SetCounterFunction() + - Nan::SetCreateHistogramFunction() + - Nan::SetAddHistogramSampleFunction() + - Nan::IdleNotification() + - Nan::LowMemoryNotification() + - Nan::ContextDisposedNotification() + - Nan::GetInternalFieldPointer() + - Nan::SetInternalFieldPointer() + - Nan::AdjustExternalMemory() + + +### Miscellaneous V8 Helpers + + - Nan::Utf8String + - Nan::GetCurrentContext() + - Nan::SetIsolateData() + - Nan::GetIsolateData() + - Nan::TypedArrayContents + + +### Miscellaneous Node Helpers + + - Nan::AsyncResource + - Nan::MakeCallback() + - NAN_MODULE_INIT() + - Nan::Export() + + + + + + +### Tests + +To run the NAN tests do: + +``` sh +npm install +npm run-script rebuild-tests +npm test +``` + +Or just: + +``` sh +npm install +make test +``` + + + +## Known issues + +### Compiling against Node.js 0.12 on OSX + +With new enough compilers available on OSX, the versions of V8 headers corresponding to Node.js 0.12 +do not compile anymore. The error looks something like: + +``` +❯ CXX(target) Release/obj.target/accessors/cpp/accessors.o +In file included from ../cpp/accessors.cpp:9: +In file included from ../../nan.h:51: +In file included from /Users/ofrobots/.node-gyp/0.12.18/include/node/node.h:61: +/Users/ofrobots/.node-gyp/0.12.18/include/node/v8.h:5800:54: error: 'CreateHandle' is a protected member of 'v8::HandleScope' + return Handle(reinterpret_cast(HandleScope::CreateHandle( + ~~~~~~~~~~~~~^~~~~~~~~~~~ +``` + +This can be worked around by patching your local versions of v8.h corresponding to Node 0.12 to make +`v8::Handle` a friend of `v8::HandleScope`. Since neither Node.js not V8 support this release line anymore +this patch cannot be released by either project in an official release. + +For this reason, we do not test against Node.js 0.12 on OSX in this project's CI. If you need to support +that configuration, you will need to either get an older compiler, or apply a source patch to the version +of V8 headers as a workaround. + + + +## Governance & Contributing + +NAN is governed by the [Node.js Addon API Working Group](https://github.com/nodejs/CTC/blob/master/WORKING_GROUPS.md#addon-api) + +### Addon API Working Group (WG) + +The NAN project is jointly governed by a Working Group which is responsible for high-level guidance of the project. + +Members of the WG are also known as Collaborators, there is no distinction between the two, unlike other Node.js projects. + +The WG has final authority over this project including: + +* Technical direction +* Project governance and process (including this policy) +* Contribution policy +* GitHub repository hosting +* Maintaining the list of additional Collaborators + +For the current list of WG members, see the project [README.md](./README.md#collaborators). + +Individuals making significant and valuable contributions are made members of the WG and given commit-access to the project. These individuals are identified by the WG and their addition to the WG is discussed via GitHub and requires unanimous consensus amongst those WG members participating in the discussion with a quorum of 50% of WG members required for acceptance of the vote. + +_Note:_ If you make a significant contribution and are not considered for commit-access log an issue or contact a WG member directly. + +For the current list of WG members / Collaborators, see the project [README.md](./README.md#collaborators). + +### Consensus Seeking Process + +The WG follows a [Consensus Seeking](https://en.wikipedia.org/wiki/Consensus-seeking_decision-making) decision making model. + +Modifications of the contents of the NAN repository are made on a collaborative basis. Anybody with a GitHub account may propose a modification via pull request and it will be considered by the WG. All pull requests must be reviewed and accepted by a WG member with sufficient expertise who is able to take full responsibility for the change. In the case of pull requests proposed by an existing WG member, an additional WG member is required for sign-off. Consensus should be sought if additional WG members participate and there is disagreement around a particular modification. + +If a change proposal cannot reach a consensus, a WG member can call for a vote amongst the members of the WG. Simple majority wins. + + + +## 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. + + + +### WG Members / Collaborators + + + + + + + + + + +
Rod VaggGitHub/rvaggTwitter/@rvagg
Benjamin ByholmGitHub/kkoopa-
Trevor NorrisGitHub/trevnorrisTwitter/@trevnorris
Nathan RajlichGitHub/TooTallNateTwitter/@TooTallNate
Brett LawsonGitHub/brett19Twitter/@brett19x
Ben NoordhuisGitHub/bnoordhuisTwitter/@bnoordhuis
David SiegelGitHub/agnatTwitter/@agnat
Michael Ira KrufkyGitHub/mkrufkyTwitter/@mkrufky
+ +## Licence & copyright + +Copyright (c) 2018 NAN WG Members / Collaborators (listed above). + +Native Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details. diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/asyncworker.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/asyncworker.md new file mode 100644 index 0000000..04231f8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/asyncworker.md @@ -0,0 +1,146 @@ +## Asynchronous work helpers + +`Nan::AsyncWorker`, `Nan::AsyncProgressWorker` and `Nan::AsyncProgressQueueWorker` are helper classes that make working with asynchronous code easier. + + - Nan::AsyncWorker + - Nan::AsyncProgressWorkerBase & Nan::AsyncProgressWorker + - Nan::AsyncProgressQueueWorker + - Nan::AsyncQueueWorker + + +### Nan::AsyncWorker + +`Nan::AsyncWorker` is an _abstract_ class that you can subclass to have much of the annoying asynchronous queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the asynchronous work is in progress. + +This class internally handles the details of creating an [`AsyncResource`][AsyncResource], and running the callback in the +correct async context. To be able to identify the async resources created by this class in async-hooks, provide a +`resource_name` to the constructor. It is recommended that the module name be used as a prefix to the `resource_name` to avoid +collisions in the names. For more details see [`AsyncResource`][AsyncResource] documentation. The `resource_name` needs to stay valid for the lifetime of the worker instance. + +Definition: + +```c++ +class AsyncWorker { + public: + explicit AsyncWorker(Callback *callback_, const char* resource_name = "nan:AsyncWorker"); + + virtual ~AsyncWorker(); + + virtual void WorkComplete(); + + void SaveToPersistent(const char *key, const v8::Local &value); + + void SaveToPersistent(const v8::Local &key, + const v8::Local &value); + + void SaveToPersistent(uint32_t index, + const v8::Local &value); + + v8::Local GetFromPersistent(const char *key) const; + + v8::Local GetFromPersistent(const v8::Local &key) const; + + v8::Local GetFromPersistent(uint32_t index) const; + + virtual void Execute() = 0; + + uv_work_t request; + + virtual void Destroy(); + + protected: + Persistent persistentHandle; + + Callback *callback; + + virtual void HandleOKCallback(); + + virtual void HandleErrorCallback(); + + void SetErrorMessage(const char *msg); + + const char* ErrorMessage(); +}; +``` + + +### Nan::AsyncProgressWorkerBase & Nan::AsyncProgressWorker + +`Nan::AsyncProgressWorkerBase` is an _abstract_ class template that extends `Nan::AsyncWorker` and adds additional progress reporting callbacks that can be used during the asynchronous work execution to provide progress data back to JavaScript. + +Previously the definition of `Nan::AsyncProgressWorker` only allowed sending `const char` data. Now extending `Nan::AsyncProgressWorker` will yield an instance of the implicit `Nan::AsyncProgressWorkerBase` template with type `` for compatibility. + +`Nan::AsyncProgressWorkerBase` & `Nan::AsyncProgressWorker` is intended for best-effort delivery of nonessential progress messages, e.g. a progress bar. The last event sent before the main thread is woken will be delivered. + +Definition: + +```c++ +template +class AsyncProgressWorkerBase : public AsyncWorker { + public: + explicit AsyncProgressWorkerBase(Callback *callback_, const char* resource_name = ...); + + virtual ~AsyncProgressWorkerBase(); + + void WorkProgress(); + + class ExecutionProgress { + public: + void Signal() const; + void Send(const T* data, size_t count) const; + }; + + virtual void Execute(const ExecutionProgress& progress) = 0; + + virtual void HandleProgressCallback(const T *data, size_t count) = 0; + + virtual void Destroy(); +}; + +typedef AsyncProgressWorkerBase AsyncProgressWorker; +``` + + +### Nan::AsyncProgressQueueWorker + +`Nan::AsyncProgressQueueWorker` is an _abstract_ class template that extends `Nan::AsyncWorker` and adds additional progress reporting callbacks that can be used during the asynchronous work execution to provide progress data back to JavaScript. + +`Nan::AsyncProgressQueueWorker` behaves exactly the same as `Nan::AsyncProgressWorker`, except all events are queued and delivered to the main thread. + +Definition: + +```c++ +template +class AsyncProgressQueueWorker : public AsyncWorker { + public: + explicit AsyncProgressQueueWorker(Callback *callback_, const char* resource_name = "nan:AsyncProgressQueueWorker"); + + virtual ~AsyncProgressQueueWorker(); + + void WorkProgress(); + + class ExecutionProgress { + public: + void Send(const T* data, size_t count) const; + }; + + virtual void Execute(const ExecutionProgress& progress) = 0; + + virtual void HandleProgressCallback(const T *data, size_t count) = 0; + + virtual void Destroy(); +}; +``` + + +### Nan::AsyncQueueWorker + +`Nan::AsyncQueueWorker` will run a `Nan::AsyncWorker` asynchronously via libuv. Both the `execute` and `after_work` steps are taken care of for you. Most of the logic for this is embedded in `Nan::AsyncWorker`. + +Definition: + +```c++ +void AsyncQueueWorker(AsyncWorker *); +``` + +[AsyncResource]: node_misc.md#api_nan_asyncresource diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/buffers.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/buffers.md new file mode 100644 index 0000000..8d8d25c --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/buffers.md @@ -0,0 +1,54 @@ +## Buffers + +NAN's `node::Buffer` helpers exist as the API has changed across supported Node versions. Use these methods to ensure compatibility. + + - Nan::NewBuffer() + - Nan::CopyBuffer() + - Nan::FreeCallback() + + +### Nan::NewBuffer() + +Allocate a new `node::Buffer` object with the specified size and optional data. Calls `node::Buffer::New()`. + +Note that when creating a `Buffer` using `Nan::NewBuffer()` and an existing `char*`, it is assumed that the ownership of the pointer is being transferred to the new `Buffer` for management. +When a `node::Buffer` instance is garbage collected and a `FreeCallback` has not been specified, `data` will be disposed of via a call to `free()`. +You _must not_ free the memory space manually once you have created a `Buffer` in this way. + +Signature: + +```c++ +Nan::MaybeLocal Nan::NewBuffer(uint32_t size) +Nan::MaybeLocal Nan::NewBuffer(char* data, uint32_t size) +Nan::MaybeLocal Nan::NewBuffer(char *data, + size_t length, + Nan::FreeCallback callback, + void *hint) +``` + + + +### Nan::CopyBuffer() + +Similar to [`Nan::NewBuffer()`](#api_nan_new_buffer) except that an implicit memcpy will occur within Node. Calls `node::Buffer::Copy()`. + +Management of the `char*` is left to the user, you should manually free the memory space if necessary as the new `Buffer` will have its own copy. + +Signature: + +```c++ +Nan::MaybeLocal Nan::CopyBuffer(const char *data, uint32_t size) +``` + + + +### Nan::FreeCallback() + +A free callback that can be provided to [`Nan::NewBuffer()`](#api_nan_new_buffer). +The supplied callback will be invoked when the `Buffer` undergoes garbage collection. + +Signature: + +```c++ +typedef void (*FreeCallback)(char *data, void *hint); +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/callback.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/callback.md new file mode 100644 index 0000000..f7af0bf --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/callback.md @@ -0,0 +1,76 @@ +## Nan::Callback + +`Nan::Callback` makes it easier to use `v8::Function` handles as callbacks. A class that wraps a `v8::Function` handle, protecting it from garbage collection and making it particularly useful for storage and use across asynchronous execution. + + - Nan::Callback + + +### Nan::Callback + +```c++ +class Callback { + public: + Callback(); + + explicit Callback(const v8::Local &fn); + + ~Callback(); + + bool operator==(const Callback &other) const; + + bool operator!=(const Callback &other) const; + + v8::Local operator*() const; + + MaybeLocal operator()(AsyncResource* async_resource, + v8::Local target, + int argc = 0, + v8::Local argv[] = 0) const; + + MaybeLocal operator()(AsyncResource* async_resource, + int argc = 0, + v8::Local argv[] = 0) const; + + void SetFunction(const v8::Local &fn); + + v8::Local GetFunction() const; + + bool IsEmpty() const; + + void Reset(const v8::Local &fn); + + void Reset(); + + MaybeLocal Call(v8::Local target, + int argc, + v8::Local argv[], + AsyncResource* async_resource) const; + MaybeLocal Call(int argc, + v8::Local argv[], + AsyncResource* async_resource) const; + + // Deprecated versions. Use the versions that accept an async_resource instead + // as they run the callback in the correct async context as specified by the + // resource. If you want to call a synchronous JS function (i.e. on a + // non-empty JS stack), you can use Nan::Call instead. + v8::Local operator()(v8::Local target, + int argc = 0, + v8::Local argv[] = 0) const; + + v8::Local operator()(int argc = 0, + v8::Local argv[] = 0) const; + v8::Local Call(v8::Local target, + int argc, + v8::Local argv[]) const; + + v8::Local Call(int argc, v8::Local argv[]) const; +}; +``` + +Example usage: + +```c++ +v8::Local function; +Nan::Callback callback(function); +callback.Call(0, 0); +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/converters.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/converters.md new file mode 100644 index 0000000..d20861b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/converters.md @@ -0,0 +1,41 @@ +## Converters + +NAN contains functions that convert `v8::Value`s to other `v8::Value` types and native types. Since type conversion is not guaranteed to succeed, they return `Nan::Maybe` types. These converters can be used in place of `value->ToX()` and `value->XValue()` (where `X` is one of the types, e.g. `Boolean`) in a way that provides a consistent interface across V8 versions. Newer versions of V8 use the new `v8::Maybe` and `v8::MaybeLocal` types for these conversions, older versions don't have this functionality so it is provided by NAN. + + - Nan::To() + + +### Nan::To() + +Converts a `v8::Local` to a different subtype of `v8::Value` or to a native data type. Returns a `Nan::MaybeLocal<>` or a `Nan::Maybe<>` accordingly. + +See [maybe_types.md](./maybe_types.md) for more information on `Nan::Maybe` types. + +Signatures: + +```c++ +// V8 types +Nan::MaybeLocal Nan::To(v8::Local val); +Nan::MaybeLocal Nan::To(v8::Local val); +Nan::MaybeLocal Nan::To(v8::Local val); +Nan::MaybeLocal Nan::To(v8::Local val); +Nan::MaybeLocal Nan::To(v8::Local val); +Nan::MaybeLocal Nan::To(v8::Local val); +Nan::MaybeLocal Nan::To(v8::Local val); + +// Native types +Nan::Maybe Nan::To(v8::Local val); +Nan::Maybe Nan::To(v8::Local val); +Nan::Maybe Nan::To(v8::Local val); +Nan::Maybe Nan::To(v8::Local val); +Nan::Maybe Nan::To(v8::Local val); +``` + +### Example + +```c++ +v8::Local val; +Nan::MaybeLocal str = Nan::To(val); +Nan::Maybe d = Nan::To(val); +``` + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/errors.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/errors.md new file mode 100644 index 0000000..173a8ea --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/errors.md @@ -0,0 +1,226 @@ +## Errors + +NAN includes helpers for creating, throwing and catching Errors as much of this functionality varies across the supported versions of V8 and must be abstracted. + +Note that an Error object is simply a specialized form of `v8::Value`. + +Also consult the V8 Embedders Guide section on [Exceptions](https://v8.dev/docs/embed#exceptions) for more information. + + - Nan::Error() + - Nan::RangeError() + - Nan::ReferenceError() + - Nan::SyntaxError() + - Nan::TypeError() + - Nan::ThrowError() + - Nan::ThrowRangeError() + - Nan::ThrowReferenceError() + - Nan::ThrowSyntaxError() + - Nan::ThrowTypeError() + - Nan::FatalException() + - Nan::ErrnoException() + - Nan::TryCatch + + + +### Nan::Error() + +Create a new Error object using the [v8::Exception](https://v8docs.nodesource.com/node-8.16/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8. + +Note that an Error object is simply a specialized form of `v8::Value`. + +Signature: + +```c++ +v8::Local Nan::Error(const char *msg); +v8::Local Nan::Error(v8::Local msg); +``` + + + +### Nan::RangeError() + +Create a new RangeError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.16/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8. + +Note that an RangeError object is simply a specialized form of `v8::Value`. + +Signature: + +```c++ +v8::Local Nan::RangeError(const char *msg); +v8::Local Nan::RangeError(v8::Local msg); +``` + + + +### Nan::ReferenceError() + +Create a new ReferenceError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.16/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8. + +Note that an ReferenceError object is simply a specialized form of `v8::Value`. + +Signature: + +```c++ +v8::Local Nan::ReferenceError(const char *msg); +v8::Local Nan::ReferenceError(v8::Local msg); +``` + + + +### Nan::SyntaxError() + +Create a new SyntaxError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.16/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8. + +Note that an SyntaxError object is simply a specialized form of `v8::Value`. + +Signature: + +```c++ +v8::Local Nan::SyntaxError(const char *msg); +v8::Local Nan::SyntaxError(v8::Local msg); +``` + + + +### Nan::TypeError() + +Create a new TypeError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.16/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8. + +Note that an TypeError object is simply a specialized form of `v8::Value`. + +Signature: + +```c++ +v8::Local Nan::TypeError(const char *msg); +v8::Local Nan::TypeError(v8::Local msg); +``` + + + +### Nan::ThrowError() + +Throw an Error object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new Error object will be created. + +Signature: + +```c++ +void Nan::ThrowError(const char *msg); +void Nan::ThrowError(v8::Local msg); +void Nan::ThrowError(v8::Local error); +``` + + + +### Nan::ThrowRangeError() + +Throw an RangeError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new RangeError object will be created. + +Signature: + +```c++ +void Nan::ThrowRangeError(const char *msg); +void Nan::ThrowRangeError(v8::Local msg); +void Nan::ThrowRangeError(v8::Local error); +``` + + + +### Nan::ThrowReferenceError() + +Throw an ReferenceError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new ReferenceError object will be created. + +Signature: + +```c++ +void Nan::ThrowReferenceError(const char *msg); +void Nan::ThrowReferenceError(v8::Local msg); +void Nan::ThrowReferenceError(v8::Local error); +``` + + + +### Nan::ThrowSyntaxError() + +Throw an SyntaxError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new SyntaxError object will be created. + +Signature: + +```c++ +void Nan::ThrowSyntaxError(const char *msg); +void Nan::ThrowSyntaxError(v8::Local msg); +void Nan::ThrowSyntaxError(v8::Local error); +``` + + + +### Nan::ThrowTypeError() + +Throw an TypeError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new TypeError object will be created. + +Signature: + +```c++ +void Nan::ThrowTypeError(const char *msg); +void Nan::ThrowTypeError(v8::Local msg); +void Nan::ThrowTypeError(v8::Local error); +``` + + +### Nan::FatalException() + +Replaces `node::FatalException()` which has a different API across supported versions of Node. For use with [`Nan::TryCatch`](#api_nan_try_catch). + +Signature: + +```c++ +void Nan::FatalException(const Nan::TryCatch& try_catch); +``` + + +### Nan::ErrnoException() + +Replaces `node::ErrnoException()` which has a different API across supported versions of Node. + +Signature: + +```c++ +v8::Local Nan::ErrnoException(int errorno, + const char* syscall = NULL, + const char* message = NULL, + const char* path = NULL); +``` + + + +### Nan::TryCatch + +A simple wrapper around [`v8::TryCatch`](https://v8docs.nodesource.com/node-8.16/d4/dc6/classv8_1_1_try_catch.html) compatible with all supported versions of V8. Can be used as a direct replacement in most cases. See also [`Nan::FatalException()`](#api_nan_fatal_exception) for an internal use compatible with `node::FatalException`. + +Signature: + +```c++ +class Nan::TryCatch { + public: + Nan::TryCatch(); + + bool HasCaught() const; + + bool CanContinue() const; + + v8::Local ReThrow(); + + v8::Local Exception() const; + + // Nan::MaybeLocal for older versions of V8 + v8::MaybeLocal StackTrace() const; + + v8::Local Message() const; + + void Reset(); + + void SetVerbose(bool value); + + void SetCaptureMessage(bool value); +}; +``` + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/json.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/json.md new file mode 100644 index 0000000..55beb26 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/json.md @@ -0,0 +1,62 @@ +## JSON + +The _JSON_ object provides the C++ versions of the methods offered by the `JSON` object in javascript. V8 exposes these methods via the `v8::JSON` object. + + - Nan::JSON.Parse + - Nan::JSON.Stringify + +Refer to the V8 JSON object in the [V8 documentation](https://v8docs.nodesource.com/node-8.16/da/d6f/classv8_1_1_j_s_o_n.html) for more information about these methods and their arguments. + + + +### Nan::JSON.Parse + +A simple wrapper around [`v8::JSON::Parse`](https://v8docs.nodesource.com/node-8.16/da/d6f/classv8_1_1_j_s_o_n.html#a936310d2540fb630ed37d3ee3ffe4504). + +Definition: + +```c++ +Nan::MaybeLocal Nan::JSON::Parse(v8::Local json_string); +``` + +Use `JSON.Parse(json_string)` to parse a string into a `v8::Value`. + +Example: + +```c++ +v8::Local json_string = Nan::New("{ \"JSON\": \"object\" }").ToLocalChecked(); + +Nan::JSON NanJSON; +Nan::MaybeLocal result = NanJSON.Parse(json_string); +if (!result.IsEmpty()) { + v8::Local val = result.ToLocalChecked(); +} +``` + + + +### Nan::JSON.Stringify + +A simple wrapper around [`v8::JSON::Stringify`](https://v8docs.nodesource.com/node-8.16/da/d6f/classv8_1_1_j_s_o_n.html#a44b255c3531489ce43f6110209138860). + +Definition: + +```c++ +Nan::MaybeLocal Nan::JSON::Stringify(v8::Local json_object, v8::Local gap = v8::Local()); +``` + +Use `JSON.Stringify(value)` to stringify a `v8::Object`. + +Example: + +```c++ +// using `v8::Local val` from the `JSON::Parse` example +v8::Local obj = Nan::To(val).ToLocalChecked(); + +Nan::JSON NanJSON; +Nan::MaybeLocal result = NanJSON.Stringify(obj); +if (!result.IsEmpty()) { + v8::Local stringified = result.ToLocalChecked(); +} +``` + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/maybe_types.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/maybe_types.md new file mode 100644 index 0000000..142851a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/maybe_types.md @@ -0,0 +1,583 @@ +## Maybe Types + +The `Nan::MaybeLocal` and `Nan::Maybe` types are monads that encapsulate `v8::Local` handles that _may be empty_. + +* **Maybe Types** + - Nan::MaybeLocal + - Nan::Maybe + - Nan::Nothing + - Nan::Just +* **Maybe Helpers** + - Nan::Call() + - Nan::ToDetailString() + - Nan::ToArrayIndex() + - Nan::Equals() + - Nan::NewInstance() + - Nan::GetFunction() + - Nan::Set() + - Nan::DefineOwnProperty() + - Nan::ForceSet() + - Nan::Get() + - Nan::GetPropertyAttributes() + - Nan::Has() + - Nan::Delete() + - Nan::GetPropertyNames() + - Nan::GetOwnPropertyNames() + - Nan::SetPrototype() + - Nan::ObjectProtoToString() + - Nan::HasOwnProperty() + - Nan::HasRealNamedProperty() + - Nan::HasRealIndexedProperty() + - Nan::HasRealNamedCallbackProperty() + - Nan::GetRealNamedPropertyInPrototypeChain() + - Nan::GetRealNamedProperty() + - Nan::CallAsFunction() + - Nan::CallAsConstructor() + - Nan::GetSourceLine() + - Nan::GetLineNumber() + - Nan::GetStartColumn() + - Nan::GetEndColumn() + - Nan::CloneElementAt() + - Nan::HasPrivate() + - Nan::GetPrivate() + - Nan::SetPrivate() + - Nan::DeletePrivate() + - Nan::MakeMaybe() + + +### Nan::MaybeLocal + +A `Nan::MaybeLocal` is a wrapper around [`v8::Local`](https://v8docs.nodesource.com/node-8.16/de/deb/classv8_1_1_local.html) that enforces a check that determines whether the `v8::Local` is empty before it can be used. + +If an API method returns a `Nan::MaybeLocal`, the API method can potentially fail either because an exception is thrown, or because an exception is pending, e.g. because a previous API call threw an exception that hasn't been caught yet, or because a `v8::TerminateExecution` exception was thrown. In that case, an empty `Nan::MaybeLocal` is returned. + +Definition: + +```c++ +template class Nan::MaybeLocal { + public: + MaybeLocal(); + + template MaybeLocal(v8::Local that); + + bool IsEmpty() const; + + template bool ToLocal(v8::Local *out); + + // Will crash if the MaybeLocal<> is empty. + v8::Local ToLocalChecked(); + + template v8::Local FromMaybe(v8::Local default_value) const; +}; +``` + +See the documentation for [`v8::MaybeLocal`](https://v8docs.nodesource.com/node-8.16/d8/d7d/classv8_1_1_maybe_local.html) for further details. + + +### Nan::Maybe + +A simple `Nan::Maybe` type, representing an object which may or may not have a value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html. + +If an API method returns a `Nan::Maybe<>`, the API method can potentially fail either because an exception is thrown, or because an exception is pending, e.g. because a previous API call threw an exception that hasn't been caught yet, or because a `v8::TerminateExecution` exception was thrown. In that case, a "Nothing" value is returned. + +Definition: + +```c++ +template class Nan::Maybe { + public: + bool IsNothing() const; + bool IsJust() const; + + // Will crash if the Maybe<> is nothing. + T FromJust(); + + T FromMaybe(const T& default_value); + + bool operator==(const Maybe &other); + + bool operator!=(const Maybe &other); +}; +``` + +See the documentation for [`v8::Maybe`](https://v8docs.nodesource.com/node-8.16/d9/d4b/classv8_1_1_maybe.html) for further details. + + +### Nan::Nothing + +Construct an empty `Nan::Maybe` type representing _nothing_. + +```c++ +template Nan::Maybe Nan::Nothing(); +``` + + +### Nan::Just + +Construct a `Nan::Maybe` type representing _just_ a value. + +```c++ +template Nan::Maybe Nan::Just(const T &t); +``` + + +### Nan::Call() + +A helper method for calling a synchronous [`v8::Function#Call()`](https://v8docs.nodesource.com/node-8.16/d5/d54/classv8_1_1_function.html#a9c3d0e4e13ddd7721fce238aa5b94a11) in a way compatible across supported versions of V8. + +For asynchronous callbacks, use Nan::Callback::Call along with an AsyncResource. + +Signature: + +```c++ +Nan::MaybeLocal Nan::Call(v8::Local fun, v8::Local recv, int argc, v8::Local argv[]); +Nan::MaybeLocal Nan::Call(const Nan::Callback& callback, v8::Local recv, + int argc, v8::Local argv[]); +Nan::MaybeLocal Nan::Call(const Nan::Callback& callback, int argc, v8::Local argv[]); +``` + + + +### Nan::ToDetailString() + +A helper method for calling [`v8::Value#ToDetailString()`](https://v8docs.nodesource.com/node-8.16/dc/d0a/classv8_1_1_value.html#a2f9770296dc2c8d274bc8cc0dca243e5) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::ToDetailString(v8::Local val); +``` + + + +### Nan::ToArrayIndex() + +A helper method for calling [`v8::Value#ToArrayIndex()`](https://v8docs.nodesource.com/node-8.16/dc/d0a/classv8_1_1_value.html#acc5bbef3c805ec458470c0fcd6f13493) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::ToArrayIndex(v8::Local val); +``` + + + +### Nan::Equals() + +A helper method for calling [`v8::Value#Equals()`](https://v8docs.nodesource.com/node-8.16/dc/d0a/classv8_1_1_value.html#a08fba1d776a59bbf6864b25f9152c64b) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::Equals(v8::Local a, v8::Local(b)); +``` + + + +### Nan::NewInstance() + +A helper method for calling [`v8::Function#NewInstance()`](https://v8docs.nodesource.com/node-8.16/d5/d54/classv8_1_1_function.html#ae477558b10c14b76ed00e8dbab44ce5b) and [`v8::ObjectTemplate#NewInstance()`](https://v8docs.nodesource.com/node-8.16/db/d5f/classv8_1_1_object_template.html#ad605a7543cfbc5dab54cdb0883d14ae4) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::NewInstance(v8::Local h); +Nan::MaybeLocal Nan::NewInstance(v8::Local h, int argc, v8::Local argv[]); +Nan::MaybeLocal Nan::NewInstance(v8::Local h); +``` + + + +### Nan::GetFunction() + +A helper method for calling [`v8::FunctionTemplate#GetFunction()`](https://v8docs.nodesource.com/node-8.16/d8/d83/classv8_1_1_function_template.html#a56d904662a86eca78da37d9bb0ed3705) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetFunction(v8::Local t); +``` + + + +### Nan::Set() + +A helper method for calling [`v8::Object#Set()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a67604ea3734f170c66026064ea808f20) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::Set(v8::Local obj, + v8::Local key, + v8::Local value) +Nan::Maybe Nan::Set(v8::Local obj, + uint32_t index, + v8::Local value); +``` + + + +### Nan::DefineOwnProperty() + +A helper method for calling [`v8::Object#DefineOwnProperty()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a6f76b2ed605cb8f9185b92de0033a820) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::DefineOwnProperty(v8::Local obj, + v8::Local key, + v8::Local value, + v8::PropertyAttribute attribs = v8::None); +``` + + + +### Nan::ForceSet() + +Deprecated, use Nan::DefineOwnProperty(). + +A helper method for calling [`v8::Object#ForceSet()`](https://v8docs.nodesource.com/node-0.12/db/d85/classv8_1_1_object.html#acfbdfd7427b516ebdb5c47c4df5ed96c) in a way compatible across supported versions of V8. + +Signature: + +```c++ +NAN_DEPRECATED Nan::Maybe Nan::ForceSet(v8::Local obj, + v8::Local key, + v8::Local value, + v8::PropertyAttribute attribs = v8::None); +``` + + + +### Nan::Get() + +A helper method for calling [`v8::Object#Get()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a2565f03e736694f6b1e1cf22a0b4eac2) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::Get(v8::Local obj, + v8::Local key); +Nan::MaybeLocal Nan::Get(v8::Local obj, uint32_t index); +``` + + + +### Nan::GetPropertyAttributes() + +A helper method for calling [`v8::Object#GetPropertyAttributes()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a9b898894da3d1db2714fd9325a54fe57) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::GetPropertyAttributes( + v8::Local obj, + v8::Local key); +``` + + + +### Nan::Has() + +A helper method for calling [`v8::Object#Has()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ab3c3d89ea7c2f9afd08965bd7299a41d) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::Has(v8::Local obj, v8::Local key); +Nan::Maybe Nan::Has(v8::Local obj, uint32_t index); +``` + + + +### Nan::Delete() + +A helper method for calling [`v8::Object#Delete()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a48e4a19b2cedff867eecc73ddb7d377f) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::Delete(v8::Local obj, + v8::Local key); +Nan::Maybe Nan::Delete(v8::Local obj, uint32_t index); +``` + + + +### Nan::GetPropertyNames() + +A helper method for calling [`v8::Object#GetPropertyNames()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#aced885270cfd2c956367b5eedc7fbfe8) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetPropertyNames(v8::Local obj); +``` + + + +### Nan::GetOwnPropertyNames() + +A helper method for calling [`v8::Object#GetOwnPropertyNames()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a79a6e4d66049b9aa648ed4dfdb23e6eb) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetOwnPropertyNames(v8::Local obj); +``` + + + +### Nan::SetPrototype() + +A helper method for calling [`v8::Object#SetPrototype()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a442706b22fceda6e6d1f632122a9a9f4) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::SetPrototype(v8::Local obj, + v8::Local prototype); +``` + + + +### Nan::ObjectProtoToString() + +A helper method for calling [`v8::Object#ObjectProtoToString()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ab7a92b4dcf822bef72f6c0ac6fea1f0b) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::ObjectProtoToString(v8::Local obj); +``` + + + +### Nan::HasOwnProperty() + +A helper method for calling [`v8::Object#HasOwnProperty()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ab7b7245442ca6de1e1c145ea3fd653ff) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::HasOwnProperty(v8::Local obj, + v8::Local key); +``` + + + +### Nan::HasRealNamedProperty() + +A helper method for calling [`v8::Object#HasRealNamedProperty()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ad8b80a59c9eb3c1e6c3cd6c84571f767) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::HasRealNamedProperty(v8::Local obj, + v8::Local key); +``` + + + +### Nan::HasRealIndexedProperty() + +A helper method for calling [`v8::Object#HasRealIndexedProperty()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#af94fc1135a5e74a2193fb72c3a1b9855) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::HasRealIndexedProperty(v8::Local obj, + uint32_t index); +``` + + + +### Nan::HasRealNamedCallbackProperty() + +A helper method for calling [`v8::Object#HasRealNamedCallbackProperty()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#af743b7ea132b89f84d34d164d0668811) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::HasRealNamedCallbackProperty( + v8::Local obj, + v8::Local key); +``` + + + +### Nan::GetRealNamedPropertyInPrototypeChain() + +A helper method for calling [`v8::Object#GetRealNamedPropertyInPrototypeChain()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a8700b1862e6b4783716964ba4d5e6172) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetRealNamedPropertyInPrototypeChain( + v8::Local obj, + v8::Local key); +``` + + + +### Nan::GetRealNamedProperty() + +A helper method for calling [`v8::Object#GetRealNamedProperty()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a84471a824576a5994fdd0ffcbf99ccc0) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetRealNamedProperty(v8::Local obj, + v8::Local key); +``` + + + +### Nan::CallAsFunction() + +A helper method for calling [`v8::Object#CallAsFunction()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ad3ffc36f3dfc3592ce2a96bc047ee2cd) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::CallAsFunction(v8::Local obj, + v8::Local recv, + int argc, + v8::Local argv[]); +``` + + + +### Nan::CallAsConstructor() + +A helper method for calling [`v8::Object#CallAsConstructor()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a50d571de50d0b0dfb28795619d07a01b) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::CallAsConstructor(v8::Local obj, + int argc, + v8::Local argv[]); +``` + + + +### Nan::GetSourceLine() + +A helper method for calling [`v8::Message#GetSourceLine()`](https://v8docs.nodesource.com/node-8.16/d9/d28/classv8_1_1_message.html#a849f7a6c41549d83d8159825efccd23a) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetSourceLine(v8::Local msg); +``` + + + +### Nan::GetLineNumber() + +A helper method for calling [`v8::Message#GetLineNumber()`](https://v8docs.nodesource.com/node-8.16/d9/d28/classv8_1_1_message.html#adbe46c10a88a6565f2732a2d2adf99b9) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::GetLineNumber(v8::Local msg); +``` + + + +### Nan::GetStartColumn() + +A helper method for calling [`v8::Message#GetStartColumn()`](https://v8docs.nodesource.com/node-8.16/d9/d28/classv8_1_1_message.html#a60ede616ba3822d712e44c7a74487ba6) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::GetStartColumn(v8::Local msg); +``` + + + +### Nan::GetEndColumn() + +A helper method for calling [`v8::Message#GetEndColumn()`](https://v8docs.nodesource.com/node-8.16/d9/d28/classv8_1_1_message.html#aaa004cf19e529da980bc19fcb76d93be) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::GetEndColumn(v8::Local msg); +``` + + + +### Nan::CloneElementAt() + +A helper method for calling [`v8::Array#CloneElementAt()`](https://v8docs.nodesource.com/node-4.8/d3/d32/classv8_1_1_array.html#a1d3a878d4c1c7cae974dd50a1639245e) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::CloneElementAt(v8::Local array, uint32_t index); +``` + + +### Nan::HasPrivate() + +A helper method for calling [`v8::Object#HasPrivate()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#af68a0b98066cfdeb8f943e98a40ba08d) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::HasPrivate(v8::Local object, v8::Local key); +``` + + +### Nan::GetPrivate() + +A helper method for calling [`v8::Object#GetPrivate()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a169f2da506acbec34deadd9149a1925a) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::GetPrivate(v8::Local object, v8::Local key); +``` + + +### Nan::SetPrivate() + +A helper method for calling [`v8::Object#SetPrivate()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ace1769b0f3b86bfe9fda1010916360ee) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::SetPrivate(v8::Local object, v8::Local key, v8::Local value); +``` + + +### Nan::DeletePrivate() + +A helper method for calling [`v8::Object#DeletePrivate()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a138bb32a304f3982be02ad499693b8fd) in a way compatible across supported versions of V8. + +Signature: + +```c++ +Nan::Maybe Nan::DeletePrivate(v8::Local object, v8::Local key); +``` + + +### Nan::MakeMaybe() + +Wraps a `v8::Local<>` in a `Nan::MaybeLocal<>`. When called with a `Nan::MaybeLocal<>` it just returns its argument. This is useful in generic template code that builds on NAN. + +Synopsis: + +```c++ + MaybeLocal someNumber = MakeMaybe(New(3.141592654)); + MaybeLocal someString = MakeMaybe(New("probably")); +``` + +Signature: + +```c++ +template class MaybeMaybe> +Nan::MaybeLocal Nan::MakeMaybe(MaybeMaybe v); +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/methods.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/methods.md new file mode 100644 index 0000000..52e4b9e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/methods.md @@ -0,0 +1,689 @@ +## JavaScript-accessible methods + +A _template_ is a blueprint for JavaScript functions and objects in a context. You can use a template to wrap C++ functions and data structures within JavaScript objects so that they can be manipulated from JavaScript. See the V8 Embedders Guide section on [Templates](https://github.com/v8/v8/wiki/Embedder%27s-Guide#templates) for further information. + +In order to expose functionality to JavaScript via a template, you must provide it to V8 in a form that it understands. Across the versions of V8 supported by NAN, JavaScript-accessible method signatures vary widely, NAN fully abstracts method declaration and provides you with an interface that is similar to the most recent V8 API but is backward-compatible with older versions that still use the now-deceased `v8::Argument` type. + +* **Method argument types** + - Nan::FunctionCallbackInfo + - Nan::PropertyCallbackInfo + - Nan::ReturnValue +* **Method declarations** + - Method declaration + - Getter declaration + - Setter declaration + - Property getter declaration + - Property setter declaration + - Property enumerator declaration + - Property deleter declaration + - Property query declaration + - Index getter declaration + - Index setter declaration + - Index enumerator declaration + - Index deleter declaration + - Index query declaration +* Method and template helpers + - Nan::SetMethod() + - Nan::SetPrototypeMethod() + - Nan::SetAccessor() + - Nan::SetNamedPropertyHandler() + - Nan::SetIndexedPropertyHandler() + - Nan::SetTemplate() + - Nan::SetPrototypeTemplate() + - Nan::SetInstanceTemplate() + - Nan::SetCallHandler() + - Nan::SetCallAsFunctionHandler() + + +### Nan::FunctionCallbackInfo + +`Nan::FunctionCallbackInfo` should be used in place of [`v8::FunctionCallbackInfo`](https://v8docs.nodesource.com/node-8.16/dd/d0d/classv8_1_1_function_callback_info.html), even with older versions of Node where `v8::FunctionCallbackInfo` does not exist. + +Definition: + +```c++ +template class FunctionCallbackInfo { + public: + ReturnValue GetReturnValue() const; + v8::Local Callee(); // NOTE: Not available in NodeJS >= 10.0.0 + v8::Local Data(); + v8::Local Holder(); + bool IsConstructCall(); + int Length() const; + v8::Local operator[](int i) const; + v8::Local This() const; + v8::Isolate *GetIsolate() const; +}; +``` + +See the [`v8::FunctionCallbackInfo`](https://v8docs.nodesource.com/node-8.16/dd/d0d/classv8_1_1_function_callback_info.html) documentation for usage details on these. See [`Nan::ReturnValue`](#api_nan_return_value) for further information on how to set a return value from methods. + +**Note:** `FunctionCallbackInfo::Callee` is removed in Node.js after `10.0.0` because it is was deprecated in V8. Consider using `info.Data()` to pass any information you need. + + +### Nan::PropertyCallbackInfo + +`Nan::PropertyCallbackInfo` should be used in place of [`v8::PropertyCallbackInfo`](https://v8docs.nodesource.com/node-8.16/d7/dc5/classv8_1_1_property_callback_info.html), even with older versions of Node where `v8::PropertyCallbackInfo` does not exist. + +Definition: + +```c++ +template class PropertyCallbackInfo : public PropertyCallbackInfoBase { + public: + ReturnValue GetReturnValue() const; + v8::Isolate* GetIsolate() const; + v8::Local Data() const; + v8::Local This() const; + v8::Local Holder() const; +}; +``` + +See the [`v8::PropertyCallbackInfo`](https://v8docs.nodesource.com/node-8.16/d7/dc5/classv8_1_1_property_callback_info.html) documentation for usage details on these. See [`Nan::ReturnValue`](#api_nan_return_value) for further information on how to set a return value from property accessor methods. + + +### Nan::ReturnValue + +`Nan::ReturnValue` is used in place of [`v8::ReturnValue`](https://v8docs.nodesource.com/node-8.16/da/da7/classv8_1_1_return_value.html) on both [`Nan::FunctionCallbackInfo`](#api_nan_function_callback_info) and [`Nan::PropertyCallbackInfo`](#api_nan_property_callback_info) as the return type of `GetReturnValue()`. + +Example usage: + +```c++ +void EmptyArray(const Nan::FunctionCallbackInfo& info) { + info.GetReturnValue().Set(Nan::New()); +} +``` + +Definition: + +```c++ +template class ReturnValue { + public: + // Handle setters + template void Set(const v8::Local &handle); + template void Set(const Nan::Global &handle); + + // Fast primitive setters + void Set(bool value); + void Set(double i); + void Set(int32_t i); + void Set(uint32_t i); + + // Fast JS primitive setters + void SetNull(); + void SetUndefined(); + void SetEmptyString(); + + // Convenience getter for isolate + v8::Isolate *GetIsolate() const; +}; +``` + +See the documentation on [`v8::ReturnValue`](https://v8docs.nodesource.com/node-8.16/da/da7/classv8_1_1_return_value.html) for further information on this. + + +### Method declaration + +JavaScript-accessible methods should be declared with the following signature to form a `Nan::FunctionCallback`: + +```c++ +typedef void(*FunctionCallback)(const FunctionCallbackInfo&); +``` + +Example: + +```c++ +void MethodName(const Nan::FunctionCallbackInfo& info) { + ... +} +``` + +You do not need to declare a new `HandleScope` within a method as one is implicitly created for you. + +**Example usage** + +```c++ +// .h: +class Foo : public Nan::ObjectWrap { + ... + + static void Bar(const Nan::FunctionCallbackInfo& info); + static void Baz(const Nan::FunctionCallbackInfo& info); +} + + +// .cc: +void Foo::Bar(const Nan::FunctionCallbackInfo& info) { + ... +} + +void Foo::Baz(const Nan::FunctionCallbackInfo& info) { + ... +} +``` + +A helper macro `NAN_METHOD(methodname)` exists, compatible with NAN v1 method declarations. + +**Example usage with `NAN_METHOD(methodname)`** + +```c++ +// .h: +class Foo : public Nan::ObjectWrap { + ... + + static NAN_METHOD(Bar); + static NAN_METHOD(Baz); +} + + +// .cc: +NAN_METHOD(Foo::Bar) { + ... +} + +NAN_METHOD(Foo::Baz) { + ... +} +``` + +Use [`Nan::SetPrototypeMethod`](#api_nan_set_prototype_method) to attach a method to a JavaScript function prototype or [`Nan::SetMethod`](#api_nan_set_method) to attach a method directly on a JavaScript object. + + +### Getter declaration + +JavaScript-accessible getters should be declared with the following signature to form a `Nan::GetterCallback`: + +```c++ +typedef void(*GetterCallback)(v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void GetterName(v8::Local property, + const Nan::PropertyCallbackInfo& info) { + ... +} +``` + +You do not need to declare a new `HandleScope` within a getter as one is implicitly created for you. + +A helper macro `NAN_GETTER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on [Accessors](https://v8.dev/docs/embed#accessors). + + +### Setter declaration + +JavaScript-accessible setters should be declared with the following signature to form a Nan::SetterCallback: + +```c++ +typedef void(*SetterCallback)(v8::Local, + v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void SetterName(v8::Local property, + v8::Local value, + const Nan::PropertyCallbackInfo& info) { + ... +} +``` + +You do not need to declare a new `HandleScope` within a setter as one is implicitly created for you. + +A helper macro `NAN_SETTER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on [Accessors](https://v8.dev/docs/embed#accessors). + + +### Property getter declaration + +JavaScript-accessible property getters should be declared with the following signature to form a Nan::PropertyGetterCallback: + +```c++ +typedef void(*PropertyGetterCallback)(v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void PropertyGetterName(v8::Local property, + const Nan::PropertyCallbackInfo& info) { + ... +} +``` + +You do not need to declare a new `HandleScope` within a property getter as one is implicitly created for you. + +A helper macro `NAN_PROPERTY_GETTER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on named property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Property setter declaration + +JavaScript-accessible property setters should be declared with the following signature to form a Nan::PropertySetterCallback: + +```c++ +typedef void(*PropertySetterCallback)(v8::Local, + v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void PropertySetterName(v8::Local property, + v8::Local value, + const Nan::PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a property setter as one is implicitly created for you. + +A helper macro `NAN_PROPERTY_SETTER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on named property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Property enumerator declaration + +JavaScript-accessible property enumerators should be declared with the following signature to form a Nan::PropertyEnumeratorCallback: + +```c++ +typedef void(*PropertyEnumeratorCallback)(const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void PropertyEnumeratorName(const Nan::PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a property enumerator as one is implicitly created for you. + +A helper macro `NAN_PROPERTY_ENUMERATOR(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on named property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Property deleter declaration + +JavaScript-accessible property deleters should be declared with the following signature to form a Nan::PropertyDeleterCallback: + +```c++ +typedef void(*PropertyDeleterCallback)(v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void PropertyDeleterName(v8::Local property, + const Nan::PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a property deleter as one is implicitly created for you. + +A helper macro `NAN_PROPERTY_DELETER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on named property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Property query declaration + +JavaScript-accessible property query methods should be declared with the following signature to form a Nan::PropertyQueryCallback: + +```c++ +typedef void(*PropertyQueryCallback)(v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void PropertyQueryName(v8::Local property, + const Nan::PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a property query method as one is implicitly created for you. + +A helper macro `NAN_PROPERTY_QUERY(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on named property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Index getter declaration + +JavaScript-accessible index getter methods should be declared with the following signature to form a Nan::IndexGetterCallback: + +```c++ +typedef void(*IndexGetterCallback)(uint32_t, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void IndexGetterName(uint32_t index, const PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a index getter as one is implicitly created for you. + +A helper macro `NAN_INDEX_GETTER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Index setter declaration + +JavaScript-accessible index setter methods should be declared with the following signature to form a Nan::IndexSetterCallback: + +```c++ +typedef void(*IndexSetterCallback)(uint32_t, + v8::Local, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void IndexSetterName(uint32_t index, + v8::Local value, + const PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a index setter as one is implicitly created for you. + +A helper macro `NAN_INDEX_SETTER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Index enumerator declaration + +JavaScript-accessible index enumerator methods should be declared with the following signature to form a Nan::IndexEnumeratorCallback: + +```c++ +typedef void(*IndexEnumeratorCallback)(const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void IndexEnumeratorName(const PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a index enumerator as one is implicitly created for you. + +A helper macro `NAN_INDEX_ENUMERATOR(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Index deleter declaration + +JavaScript-accessible index deleter methods should be declared with the following signature to form a Nan::IndexDeleterCallback: + +```c++ +typedef void(*IndexDeleterCallback)(uint32_t, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void IndexDeleterName(uint32_t index, const PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a index deleter as one is implicitly created for you. + +A helper macro `NAN_INDEX_DELETER(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Index query declaration + +JavaScript-accessible index query methods should be declared with the following signature to form a Nan::IndexQueryCallback: + +```c++ +typedef void(*IndexQueryCallback)(uint32_t, + const PropertyCallbackInfo&); +``` + +Example: + +```c++ +void IndexQueryName(uint32_t index, const PropertyCallbackInfo& info); +``` + +You do not need to declare a new `HandleScope` within a index query method as one is implicitly created for you. + +A helper macro `NAN_INDEX_QUERY(methodname)` exists, compatible with NAN v1 method declarations. + +Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://v8.dev/docs/embed#interceptors). + + +### Nan::SetMethod() + +Sets a method with a given name directly on a JavaScript object where the method has the `Nan::FunctionCallback` signature (see Method declaration). + +Signature: + +```c++ +void Nan::SetMethod(v8::Local recv, + const char *name, + Nan::FunctionCallback callback, + v8::Local data = v8::Local()) +void Nan::SetMethod(v8::Local templ, + const char *name, + Nan::FunctionCallback callback, + v8::Local data = v8::Local()) +``` + + +### Nan::SetPrototypeMethod() + +Sets a method with a given name on a `FunctionTemplate`'s prototype where the method has the `Nan::FunctionCallback` signature (see Method declaration). + +Signature: + +```c++ +void Nan::SetPrototypeMethod(v8::Local recv, + const char* name, + Nan::FunctionCallback callback, + v8::Local data = v8::Local()) +``` + + +### Nan::SetAccessor() + +Sets getters and setters for a property with a given name on an `ObjectTemplate` or a plain `Object`. Accepts getters with the `Nan::GetterCallback` signature (see Getter declaration) and setters with the `Nan::SetterCallback` signature (see Setter declaration). + +**Note** `v8::AccessControl` was deprectaed in v8 14.2 and subsequently removed. To maintain backward compatibility new enum `enum AccessControl {DEFAULT = 0};` was added. Nan will determine v8 version used and switch to a correct signature. + +Signature: + +```c++ +// The signature parameter was deprecated in Node 16 and subsequently removed +NAN_DEPRECATED void SetAccessor(v8::Local tpl, + v8::Local name, + Nan::GetterCallback getter, + Nan::SetterCallback setter = 0, + v8::Local data = v8::Local(), + v8::AccessControl settings = v8::DEFAULT, + v8::PropertyAttribute attribute = v8::None, + imp::Sig signature = imp::Sig()); +void SetAccessor(v8::Local tpl, + v8::Local name, + Nan::GetterCallback getter, + Nan::SetterCallback setter = 0, + v8::Local data = v8::Local(), + v8::AccessControl settings = v8::DEFAULT, + v8::PropertyAttribute attribute = v8::None); +bool SetAccessor(v8::Local obj, + v8::Local name, + Nan::GetterCallback getter, + Nan::SetterCallback setter = 0, + v8::Local data = v8::Local(), + v8::AccessControl settings = v8::DEFAULT, + v8::PropertyAttribute attribute = v8::None) +// Starting from v8 14.2 new enum is used +void SetAccessor(v8::Local tpl, + v8::Local name, + Nan::GetterCallback getter, + Nan::SetterCallback setter = 0, + v8::Local data = v8::Local(), + enum Nan::AccessControl settings = DEFAULT, + v8::PropertyAttribute attribute = v8::None); +bool SetAccessor(v8::Local obj, + v8::Local name, + Nan::GetterCallback getter, + Nan::SetterCallback setter = 0, + v8::Local data = v8::Local(), + enum Nan::AccessControl settings = DEFAULT, + v8::PropertyAttribute attribute = v8::None) +``` + +See the V8 [`ObjectTemplate#SetAccessor()`](https://v8docs.nodesource.com/node-8.16/db/d5f/classv8_1_1_object_template.html#aca0ed196f8a9adb1f68b1aadb6c9cd77) and [`Object#SetAccessor()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ae91b3b56b357f285288c89fbddc46d1b) for further information about how to use `Nan::SetAccessor()`. + + +### Nan::SetNamedPropertyHandler() + +Sets named property getters, setters, query, deleter and enumerator methods on an `ObjectTemplate`. Accepts: + +* Property getters with the `Nan::PropertyGetterCallback` signature (see Property getter declaration) +* Property setters with the `Nan::PropertySetterCallback` signature (see Property setter declaration) +* Property query methods with the `Nan::PropertyQueryCallback` signature (see Property query declaration) +* Property deleters with the `Nan::PropertyDeleterCallback` signature (see Property deleter declaration) +* Property enumerators with the `Nan::PropertyEnumeratorCallback` signature (see Property enumerator declaration) + +Signature: + +```c++ +void SetNamedPropertyHandler(v8::Local tpl, + Nan::PropertyGetterCallback getter, + Nan::PropertySetterCallback setter = 0, + Nan::PropertyQueryCallback query = 0, + Nan::PropertyDeleterCallback deleter = 0, + Nan::PropertyEnumeratorCallback enumerator = 0, + v8::Local data = v8::Local()) +``` + +See the V8 [`ObjectTemplate#SetNamedPropertyHandler()`](https://v8docs.nodesource.com/node-8.16/db/d5f/classv8_1_1_object_template.html#a33b3ebd7de641f6cc6414b7de01fc1c7) for further information about how to use `Nan::SetNamedPropertyHandler()`. + + +### Nan::SetIndexedPropertyHandler() + +Sets indexed property getters, setters, query, deleter and enumerator methods on an `ObjectTemplate`. Accepts: + +* Indexed property getters with the `Nan::IndexGetterCallback` signature (see Index getter declaration) +* Indexed property setters with the `Nan::IndexSetterCallback` signature (see Index setter declaration) +* Indexed property query methods with the `Nan::IndexQueryCallback` signature (see Index query declaration) +* Indexed property deleters with the `Nan::IndexDeleterCallback` signature (see Index deleter declaration) +* Indexed property enumerators with the `Nan::IndexEnumeratorCallback` signature (see Index enumerator declaration) + +Signature: + +```c++ +void SetIndexedPropertyHandler(v8::Local tpl, + Nan::IndexGetterCallback getter, + Nan::IndexSetterCallback setter = 0, + Nan::IndexQueryCallback query = 0, + Nan::IndexDeleterCallback deleter = 0, + Nan::IndexEnumeratorCallback enumerator = 0, + v8::Local data = v8::Local()) +``` + +See the V8 [`ObjectTemplate#SetIndexedPropertyHandler()`](https://v8docs.nodesource.com/node-8.16/db/d5f/classv8_1_1_object_template.html#ac89f06d634add0e890452033f7d17ff1) for further information about how to use `Nan::SetIndexedPropertyHandler()`. + + +### Nan::SetTemplate() + +Adds properties on an `Object`'s or `Function`'s template. + +Signature: + +```c++ +void Nan::SetTemplate(v8::Local templ, + const char *name, + v8::Local value); +void Nan::SetTemplate(v8::Local templ, + v8::Local name, + v8::Local value, + v8::PropertyAttribute attributes) +``` + +Calls the `Template`'s [`Set()`](https://v8docs.nodesource.com/node-8.16/db/df7/classv8_1_1_template.html#ae3fbaff137557aa6a0233bc7e52214ac). + + +### Nan::SetPrototypeTemplate() + +Adds properties on an `Object`'s or `Function`'s prototype template. + +Signature: + +```c++ +void Nan::SetPrototypeTemplate(v8::Local templ, + const char *name, + v8::Local value); +void Nan::SetPrototypeTemplate(v8::Local templ, + v8::Local name, + v8::Local value, + v8::PropertyAttribute attributes) +``` + +Calls the `FunctionTemplate`'s _PrototypeTemplate's_ [`Set()`](https://v8docs.nodesource.com/node-8.16/db/df7/classv8_1_1_template.html#a2db6a56597bf23c59659c0659e564ddf). + + +### Nan::SetInstanceTemplate() + +Use to add instance properties on `FunctionTemplate`'s. + +Signature: + +```c++ +void Nan::SetInstanceTemplate(v8::Local templ, + const char *name, + v8::Local value); +void Nan::SetInstanceTemplate(v8::Local templ, + v8::Local name, + v8::Local value, + v8::PropertyAttribute attributes) +``` + +Calls the `FunctionTemplate`'s _InstanceTemplate's_ [`Set()`](https://v8docs.nodesource.com/node-8.16/db/df7/classv8_1_1_template.html#a2db6a56597bf23c59659c0659e564ddf). + + +### Nan::SetCallHandler() + +Set the call-handler callback for a `v8::FunctionTemplate`. +This callback is called whenever the function created from this FunctionTemplate is called. + +Signature: + +```c++ +void Nan::SetCallHandler(v8::Local templ, Nan::FunctionCallback callback, v8::Local data = v8::Local()) +``` + +Calls the `FunctionTemplate`'s [`SetCallHandler()`](https://v8docs.nodesource.com/node-8.16/d8/d83/classv8_1_1_function_template.html#ab7574b298db3c27fbc2ed465c08ea2f8). + + +### Nan::SetCallAsFunctionHandler() + +Sets the callback to be used when calling instances created from the `v8::ObjectTemplate` as a function. +If no callback is set, instances behave like normal JavaScript objects that cannot be called as a function. + +Signature: + +```c++ +void Nan::SetCallAsFunctionHandler(v8::Local templ, Nan::FunctionCallback callback, v8::Local data = v8::Local()) +``` + +Calls the `ObjectTemplate`'s [`SetCallAsFunctionHandler()`](https://v8docs.nodesource.com/node-8.16/db/d5f/classv8_1_1_object_template.html#a5e9612fc80bf6db8f2da199b9b0bd04e). + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/new.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/new.md new file mode 100644 index 0000000..0f28a0e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/new.md @@ -0,0 +1,147 @@ +## New + +NAN provides a `Nan::New()` helper for the creation of new JavaScript objects in a way that's compatible across the supported versions of V8. + + - Nan::New() + - Nan::Undefined() + - Nan::Null() + - Nan::True() + - Nan::False() + - Nan::EmptyString() + + + +### Nan::New() + +`Nan::New()` should be used to instantiate new JavaScript objects. + +Refer to the specific V8 type in the [V8 documentation](https://v8docs.nodesource.com/node-8.16/d1/d83/classv8_1_1_data.html) for information on the types of arguments required for instantiation. + +Signatures: + +Return types are mostly omitted from the signatures for simplicity. In most cases the type will be contained within a `v8::Local`. The following types will be contained within a `Nan::MaybeLocal`: `v8::String`, `v8::Date`, `v8::RegExp`, `v8::Script`, `v8::UnboundScript`. + +Empty objects: + +```c++ +Nan::New(); +``` + +Generic single and multiple-argument: + +```c++ +Nan::New(A0 arg0); +Nan::New(A0 arg0, A1 arg1); +Nan::New(A0 arg0, A1 arg1, A2 arg2); +Nan::New(A0 arg0, A1 arg1, A2 arg2, A3 arg3); +``` + +For creating `v8::FunctionTemplate` and `v8::Function` objects: + +_The definition of `Nan::FunctionCallback` can be found in the [Method declaration](./methods.md#api_nan_method) documentation._ + +```c++ +Nan::New(Nan::FunctionCallback callback, + v8::Local data = v8::Local()); +Nan::New(Nan::FunctionCallback callback, + v8::Local data = v8::Local(), + A2 a2 = A2()); +``` + +Native number types: + +```c++ +v8::Local Nan::New(bool value); +v8::Local Nan::New(int32_t value); +v8::Local Nan::New(uint32_t value); +v8::Local Nan::New(double value); +``` + +String types: + +```c++ +Nan::MaybeLocal Nan::New(std::string const& value); +Nan::MaybeLocal Nan::New(const char * value, int length); +Nan::MaybeLocal Nan::New(const char * value); +Nan::MaybeLocal Nan::New(const uint16_t * value); +Nan::MaybeLocal Nan::New(const uint16_t * value, int length); +``` + +Specialized types: + +```c++ +v8::Local Nan::New(v8::String::ExternalStringResource * value); +v8::Local Nan::New(Nan::ExternalOneByteStringResource * value); +v8::Local Nan::New(v8::Local pattern, v8::RegExp::Flags flags); +``` + +Note that `Nan::ExternalOneByteStringResource` maps to [`v8::String::ExternalOneByteStringResource`](https://v8docs.nodesource.com/node-8.16/d9/db3/classv8_1_1_string_1_1_external_one_byte_string_resource.html), and `v8::String::ExternalAsciiStringResource` in older versions of V8. + + + +### Nan::Undefined() + +A helper method to reference the `v8::Undefined` object in a way that is compatible across all supported versions of V8. + +Signature: + +```c++ +v8::Local Nan::Undefined() +``` + + +### Nan::Null() + +A helper method to reference the `v8::Null` object in a way that is compatible across all supported versions of V8. + +Signature: + +```c++ +v8::Local Nan::Null() +``` + + +### Nan::True() + +A helper method to reference the `v8::Boolean` object representing the `true` value in a way that is compatible across all supported versions of V8. + +Signature: + +```c++ +v8::Local Nan::True() +``` + + +### Nan::False() + +A helper method to reference the `v8::Boolean` object representing the `false` value in a way that is compatible across all supported versions of V8. + +Signature: + +```c++ +v8::Local Nan::False() +``` + + +### Nan::EmptyString() + +Call [`v8::String::Empty`](https://v8docs.nodesource.com/node-8.16/d2/db3/classv8_1_1_string.html#a7c1bc8886115d7ee46f1d571dd6ebc6d) to reference the empty string in a way that is compatible across all supported versions of V8. + +Signature: + +```c++ +v8::Local Nan::EmptyString() +``` + + + +### Nan::NewOneByteString() + +An implementation of [`v8::String::NewFromOneByte()`](https://v8docs.nodesource.com/node-8.16/d2/db3/classv8_1_1_string.html#a5264d50b96d2c896ce525a734dc10f09) provided for consistent availability and API across supported versions of V8. Allocates a new string from Latin-1 data. + +Signature: + +```c++ +Nan::MaybeLocal Nan::NewOneByteString(const uint8_t * value, + int length = -1) +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/node_misc.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/node_misc.md new file mode 100644 index 0000000..17578e3 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/node_misc.md @@ -0,0 +1,123 @@ +## Miscellaneous Node Helpers + + - Nan::AsyncResource + - Nan::MakeCallback() + - NAN_MODULE_INIT() + - Nan::Export() + + +### Nan::AsyncResource + +This class is analogous to the `AsyncResource` JavaScript class exposed by Node's [async_hooks][] API. + +When calling back into JavaScript asynchronously, special care must be taken to ensure that the runtime can properly track +async hops. `Nan::AsyncResource` is a class that provides an RAII wrapper around `node::EmitAsyncInit`, `node::EmitAsyncDestroy`, +and `node::MakeCallback`. Using this mechanism to call back into JavaScript, as opposed to `Nan::MakeCallback` or +`v8::Function::Call` ensures that the callback is executed in the correct async context. This ensures that async mechanisms +such as domains and [async_hooks][] function correctly. + +Definition: + +```c++ +class AsyncResource { + public: + AsyncResource(v8::Local name, + v8::Local resource = New()); + AsyncResource(const char* name, + v8::Local resource = New()); + ~AsyncResource(); + + v8::MaybeLocal runInAsyncScope(v8::Local target, + v8::Local func, + int argc, + v8::Local* argv); + v8::MaybeLocal runInAsyncScope(v8::Local target, + v8::Local symbol, + int argc, + v8::Local* argv); + v8::MaybeLocal runInAsyncScope(v8::Local target, + const char* method, + int argc, + v8::Local* argv); +}; +``` + +* `name`: Identifier for the kind of resource that is being provided for diagnostics information exposed by the [async_hooks][] + API. This will be passed to the possible `init` hook as the `type`. To avoid name collisions with other modules we recommend + that the name include the name of the owning module as a prefix. For example `mysql` module could use something like + `mysql:batch-db-query-resource`. +* `resource`: An optional object associated with the async work that will be passed to the possible [async_hooks][] + `init` hook. If this parameter is omitted, or an empty handle is provided, this object will be created automatically. +* When calling JS on behalf of this resource, one can use `runInAsyncScope`. This will ensure that the callback runs in the + correct async execution context. +* `AsyncDestroy` is automatically called when an AsyncResource object is destroyed. + +For more details, see the Node [async_hooks][] documentation. You might also want to take a look at the documentation for the +[N-API counterpart][napi]. For example usage, see the `asyncresource.cpp` example in the `test/cpp` directory. + + +### Nan::MakeCallback() + +Deprecated wrappers around the legacy `node::MakeCallback()` APIs. Node.js 10+ +has deprecated these legacy APIs as they do not provide a mechanism to preserve +async context. + +We recommend that you use the `AsyncResource` class and `AsyncResource::runInAsyncScope` instead of using `Nan::MakeCallback` or +`v8::Function#Call()` directly. `AsyncResource` properly takes care of running the callback in the correct async execution +context – something that is essential for functionality like domains, async_hooks and async debugging. + +Signatures: + +```c++ +NAN_DEPRECATED +v8::Local Nan::MakeCallback(v8::Local target, + v8::Local func, + int argc, + v8::Local* argv); +NAN_DEPRECATED +v8::Local Nan::MakeCallback(v8::Local target, + v8::Local symbol, + int argc, + v8::Local* argv); +NAN_DEPRECATED +v8::Local Nan::MakeCallback(v8::Local target, + const char* method, + int argc, + v8::Local* argv); +``` + + + +### NAN_MODULE_INIT() + +Used to define the entry point function to a Node add-on. Creates a function with a given `name` that receives a `target` object representing the equivalent of the JavaScript `exports` object. + +See example below. + + +### Nan::Export() + +A simple helper to register a `v8::FunctionTemplate` from a JavaScript-accessible method (see [Methods](./methods.md)) as a property on an object. Can be used in a way similar to assigning properties to `module.exports` in JavaScript. + +Signature: + +```c++ +void Export(v8::Local target, const char *name, Nan::FunctionCallback f) +``` + +Also available as the shortcut `NAN_EXPORT` macro. + +Example: + +```c++ +NAN_METHOD(Foo) { + ... +} + +NAN_MODULE_INIT(Init) { + NAN_EXPORT(target, Foo); +} +``` + +[async_hooks]: https://nodejs.org/dist/latest-v9.x/docs/api/async_hooks.html +[napi]: https://nodejs.org/dist/latest-v9.x/docs/api/n-api.html#n_api_custom_asynchronous_operations diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/object_wrappers.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/object_wrappers.md new file mode 100644 index 0000000..07d8c05 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/object_wrappers.md @@ -0,0 +1,263 @@ +## Object Wrappers + +The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects. + + - Nan::ObjectWrap + + + +### Nan::ObjectWrap() + +A reimplementation of `node::ObjectWrap` that adds some API not present in older versions of Node. Should be preferred over `node::ObjectWrap` in all cases for consistency. + +Definition: + +```c++ +class ObjectWrap { + public: + ObjectWrap(); + + virtual ~ObjectWrap(); + + template + static inline T* Unwrap(v8::Local handle); + + inline v8::Local handle(); + + inline Nan::Persistent& persistent(); + + protected: + inline void Wrap(v8::Local handle); + + inline void MakeWeak(); + + /* Ref() marks the object as being attached to an event loop. + * Refed objects will not be garbage collected, even if + * all references are lost. + */ + virtual void Ref(); + + /* Unref() marks an object as detached from the event loop. This is its + * default state. When an object with a "weak" reference changes from + * attached to detached state it will be freed. Be careful not to access + * the object after making this call as it might be gone! + * (A "weak reference" means an object that only has a + * persistent handle.) + * + * DO NOT CALL THIS FROM DESTRUCTOR + */ + virtual void Unref(); + + int refs_; // ro +}; +``` + +See the Node documentation on [Wrapping C++ Objects](https://nodejs.org/api/addons.html#addons_wrapping_c_objects) for more details. + +### This vs. Holder + +When calling `Unwrap`, it is important that the argument is indeed some JavaScript object which got wrapped by a `Wrap` call for this class or any derived class. +The `Signature` installed by [`Nan::SetPrototypeMethod()`](methods.md#api_nan_set_prototype_method) does ensure that `info.Holder()` is just such an instance. +In Node 0.12 and later, `info.This()` will also be of such a type, since otherwise the invocation will get rejected. +However, in Node 0.10 and before it was possible to invoke a method on a JavaScript object which just had the extension type in its prototype chain. +In such a situation, calling `Unwrap` on `info.This()` will likely lead to a failed assertion causing a crash, but could lead to even more serious corruption. + +On the other hand, calling `Unwrap` in an [accessor](methods.md#api_nan_set_accessor) should not use `Holder()` if the accessor is defined on the prototype. +So either define your accessors on the instance template, +or use `This()` after verifying that it is indeed a valid object. + +### Examples + +#### Basic + +```c++ +class MyObject : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + v8::Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("MyObject").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(tpl, "getHandle", GetHandle); + Nan::SetPrototypeMethod(tpl, "getValue", GetValue); + + constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + Nan::Set(target, Nan::New("MyObject").ToLocalChecked(), + Nan::GetFunction(tpl).ToLocalChecked()); + } + + private: + explicit MyObject(double value = 0) : value_(value) {} + ~MyObject() {} + + static NAN_METHOD(New) { + if (info.IsConstructCall()) { + double value = info[0]->IsUndefined() ? 0 : Nan::To(info[0]).FromJust(); + MyObject *obj = new MyObject(value); + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } else { + const int argc = 1; + v8::Local argv[argc] = {info[0]}; + v8::Local cons = Nan::New(constructor()); + info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked()); + } + } + + static NAN_METHOD(GetHandle) { + MyObject* obj = Nan::ObjectWrap::Unwrap(info.Holder()); + info.GetReturnValue().Set(obj->handle()); + } + + static NAN_METHOD(GetValue) { + MyObject* obj = Nan::ObjectWrap::Unwrap(info.Holder()); + info.GetReturnValue().Set(obj->value_); + } + + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + double value_; +}; + +NODE_MODULE(objectwrapper, MyObject::Init) +``` + +To use in Javascript: + +```Javascript +var objectwrapper = require('bindings')('objectwrapper'); + +var obj = new objectwrapper.MyObject(5); +console.log('Should be 5: ' + obj.getValue()); +``` + +#### Factory of wrapped objects + +```c++ +class MyFactoryObject : public Nan::ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + v8::Local tpl = Nan::New(New); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Nan::SetPrototypeMethod(tpl, "getValue", GetValue); + + constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked()); + } + + static NAN_METHOD(NewInstance) { + v8::Local cons = Nan::New(constructor()); + double value = info[0]->IsNumber() ? Nan::To(info[0]).FromJust() : 0; + const int argc = 1; + v8::Local argv[1] = {Nan::New(value)}; + info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked()); + } + + // Needed for the next example: + inline double value() const { + return value_; + } + + private: + explicit MyFactoryObject(double value = 0) : value_(value) {} + ~MyFactoryObject() {} + + static NAN_METHOD(New) { + if (info.IsConstructCall()) { + double value = info[0]->IsNumber() ? Nan::To(info[0]).FromJust() : 0; + MyFactoryObject * obj = new MyFactoryObject(value); + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } else { + const int argc = 1; + v8::Local argv[argc] = {info[0]}; + v8::Local cons = Nan::New(constructor()); + info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked()); + } + } + + static NAN_METHOD(GetValue) { + MyFactoryObject* obj = ObjectWrap::Unwrap(info.Holder()); + info.GetReturnValue().Set(obj->value_); + } + + static inline Nan::Persistent & constructor() { + static Nan::Persistent my_constructor; + return my_constructor; + } + + double value_; +}; + +NAN_MODULE_INIT(Init) { + MyFactoryObject::Init(target); + Nan::Set(target, + Nan::New("newFactoryObjectInstance").ToLocalChecked(), + Nan::GetFunction( + Nan::New(MyFactoryObject::NewInstance)).ToLocalChecked() + ); +} + +NODE_MODULE(wrappedobjectfactory, Init) +``` + +To use in Javascript: + +```Javascript +var wrappedobjectfactory = require('bindings')('wrappedobjectfactory'); + +var obj = wrappedobjectfactory.newFactoryObjectInstance(10); +console.log('Should be 10: ' + obj.getValue()); +``` + +#### Passing wrapped objects around + +Use the `MyFactoryObject` class above along with the following: + +```c++ +static NAN_METHOD(Sum) { + Nan::MaybeLocal maybe1 = Nan::To(info[0]); + Nan::MaybeLocal maybe2 = Nan::To(info[1]); + + // Quick check: + if (maybe1.IsEmpty() || maybe2.IsEmpty()) { + // return value is undefined by default + return; + } + + MyFactoryObject* obj1 = + Nan::ObjectWrap::Unwrap(maybe1.ToLocalChecked()); + MyFactoryObject* obj2 = + Nan::ObjectWrap::Unwrap(maybe2.ToLocalChecked()); + + info.GetReturnValue().Set(Nan::New(obj1->value() + obj2->value())); +} + +NAN_MODULE_INIT(Init) { + MyFactoryObject::Init(target); + Nan::Set(target, + Nan::New("newFactoryObjectInstance").ToLocalChecked(), + Nan::GetFunction( + Nan::New(MyFactoryObject::NewInstance)).ToLocalChecked() + ); + Nan::Set(target, + Nan::New("sum").ToLocalChecked(), + Nan::GetFunction(Nan::New(Sum)).ToLocalChecked() + ); +} + +NODE_MODULE(myaddon, Init) +``` + +To use in Javascript: + +```Javascript +var myaddon = require('bindings')('myaddon'); + +var obj1 = myaddon.newFactoryObjectInstance(5); +var obj2 = myaddon.newFactoryObjectInstance(10); +console.log('sum of object values: ' + myaddon.sum(obj1, obj2)); +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/persistent.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/persistent.md new file mode 100644 index 0000000..9a7bb94 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/persistent.md @@ -0,0 +1,296 @@ +## Persistent references + +An object reference that is independent of any `HandleScope` is a _persistent_ reference. Where a `Local` handle only lives as long as the `HandleScope` in which it was allocated, a `Persistent` handle remains valid until it is explicitly disposed. + +Due to the evolution of the V8 API, it is necessary for NAN to provide a wrapper implementation of the `Persistent` classes to supply compatibility across the V8 versions supported. + + - Nan::PersistentBase & v8::PersistentBase + - Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits + - Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits + - Nan::Persistent + - Nan::Global + - Nan::WeakCallbackInfo + - Nan::WeakCallbackType + +Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://v8.dev/docs/embed#handles-and-garbage-collection). + + +### Nan::PersistentBase & v8::PersistentBase + +A persistent handle contains a reference to a storage cell in V8 which holds an object value and which is updated by the garbage collector whenever the object is moved. A new storage cell can be created using the constructor or `Nan::PersistentBase::Reset()`. Existing handles can be disposed using an argument-less `Nan::PersistentBase::Reset()`. + +Definition: + +_(note: this is implemented as `Nan::PersistentBase` for older versions of V8 and the native `v8::PersistentBase` is used for newer versions of V8)_ + +```c++ +template class PersistentBase { + public: + /** + * If non-empty, destroy the underlying storage cell + */ + void Reset(); + + /** + * If non-empty, destroy the underlying storage cell and create a new one with + * the contents of another if it is also non-empty + */ + template void Reset(const v8::Local &other); + + /** + * If non-empty, destroy the underlying storage cell and create a new one with + * the contents of another if it is also non-empty + */ + template void Reset(const PersistentBase &other); + + /** Returns true if the handle is empty. */ + bool IsEmpty() const; + + /** + * If non-empty, destroy the underlying storage cell + * IsEmpty() will return true after this call. + */ + void Empty(); + + template bool operator==(const PersistentBase &that); + + template bool operator==(const v8::Local &that); + + template bool operator!=(const PersistentBase &that); + + template bool operator!=(const v8::Local &that); + + /** + * Install a finalization callback on this object. + * NOTE: There is no guarantee as to *when* or even *if* the callback is + * invoked. The invocation is performed solely on a best effort basis. + * As always, GC-based finalization should *not* be relied upon for any + * critical form of resource management! At the moment you can either + * specify a parameter for the callback or the location of two internal + * fields in the dying object. + */ + template + void SetWeak(P *parameter, + typename WeakCallbackInfo

::Callback callback, + WeakCallbackType type); + + void ClearWeak(); + + /** + * Marks the reference to this object independent. Garbage collector is free + * to ignore any object groups containing this object. Weak callback for an + * independent handle should not assume that it will be preceded by a global + * GC prologue callback or followed by a global GC epilogue callback. + */ + void MarkIndependent() const; + + bool IsIndependent() const; + + /** Checks if the handle holds the only reference to an object. */ + bool IsNearDeath() const; + + /** Returns true if the handle's reference is weak. */ + bool IsWeak() const +}; +``` + +See the V8 documentation for [`PersistentBase`](https://v8docs.nodesource.com/node-8.16/d4/dca/classv8_1_1_persistent_base.html) for further information. + +**Tip:** To get a `v8::Local` reference to the original object back from a `PersistentBase` or `Persistent` object: + +```c++ +v8::Local object = Nan::New(persistent); +``` + + +### Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits + +Default traits for `Nan::Persistent`. This class does not allow use of the a copy constructor or assignment operator. At present `kResetInDestructor` is not set, but that will change in a future version. + +Definition: + +_(note: this is implemented as `Nan::NonCopyablePersistentTraits` for older versions of V8 and the native `v8::NonCopyablePersistentTraits` is used for newer versions of V8)_ + +```c++ +template class NonCopyablePersistentTraits { + public: + typedef Persistent > NonCopyablePersistent; + + static const bool kResetInDestructor = false; + + template + static void Copy(const Persistent &source, + NonCopyablePersistent *dest); + + template static void Uncompilable(); +}; +``` + +See the V8 documentation for [`NonCopyablePersistentTraits`](https://v8docs.nodesource.com/node-8.16/de/d73/classv8_1_1_non_copyable_persistent_traits.html) for further information. + + +### Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits + +A helper class of traits to allow copying and assignment of `Persistent`. This will clone the contents of storage cell, but not any of the flags, etc.. + +Definition: + +_(note: this is implemented as `Nan::CopyablePersistentTraits` for older versions of V8 and the native `v8::NonCopyablePersistentTraits` is used for newer versions of V8)_ + +```c++ +template +class CopyablePersistentTraits { + public: + typedef Persistent > CopyablePersistent; + + static const bool kResetInDestructor = true; + + template + static void Copy(const Persistent &source, + CopyablePersistent *dest); +}; +``` + +See the V8 documentation for [`CopyablePersistentTraits`](https://v8docs.nodesource.com/node-8.16/da/d5c/structv8_1_1_copyable_persistent_traits.html) for further information. + + +### Nan::Persistent + +A type of `PersistentBase` which allows copy and assignment. Copy, assignment and destructor behavior is controlled by the traits class `M`. + +Definition: + +```c++ +template > +class Persistent; + +template class Persistent : public PersistentBase { + public: + /** + * A Persistent with no storage cell. + */ + Persistent(); + + /** + * Construct a Persistent from a v8::Local. When the v8::Local is non-empty, a + * new storage cell is created pointing to the same object, and no flags are + * set. + */ + template Persistent(v8::Local that); + + /** + * Construct a Persistent from a Persistent. When the Persistent is non-empty, + * a new storage cell is created pointing to the same object, and no flags are + * set. + */ + Persistent(const Persistent &that); + + /** + * The copy constructors and assignment operator create a Persistent exactly + * as the Persistent constructor, but the Copy function from the traits class + * is called, allowing the setting of flags based on the copied Persistent. + */ + Persistent &operator=(const Persistent &that); + + template + Persistent &operator=(const Persistent &that); + + /** + * The destructor will dispose the Persistent based on the kResetInDestructor + * flags in the traits class. Since not calling dispose can result in a + * memory leak, it is recommended to always set this flag. + */ + ~Persistent(); +}; +``` + +See the V8 documentation for [`Persistent`](https://v8docs.nodesource.com/node-8.16/d2/d78/classv8_1_1_persistent.html) for further information. + + +### Nan::Global + +A type of `PersistentBase` which has move semantics. + +```c++ +template class Global : public PersistentBase { + public: + /** + * A Global with no storage cell. + */ + Global(); + + /** + * Construct a Global from a v8::Local. When the v8::Local is non-empty, a new + * storage cell is created pointing to the same object, and no flags are set. + */ + template Global(v8::Local that); + /** + * Construct a Global from a PersistentBase. When the Persistent is non-empty, + * a new storage cell is created pointing to the same object, and no flags are + * set. + */ + template Global(const PersistentBase &that); + + /** + * Pass allows returning globals from functions, etc. + */ + Global Pass(); +}; +``` + +See the V8 documentation for [`Global`](https://v8docs.nodesource.com/node-8.16/d5/d40/classv8_1_1_global.html) for further information. + + +### Nan::WeakCallbackInfo + +`Nan::WeakCallbackInfo` is used as an argument when setting a persistent reference as weak. You may need to free any external resources attached to the object. It is a mirror of `v8:WeakCallbackInfo` as found in newer versions of V8. + +Definition: + +```c++ +template class WeakCallbackInfo { + public: + typedef void (*Callback)(const WeakCallbackInfo& data); + + v8::Isolate *GetIsolate() const; + + /** + * Get the parameter that was associated with the weak handle. + */ + T *GetParameter() const; + + /** + * Get pointer from internal field, index can be 0 or 1. + */ + void *GetInternalField(int index) const; +}; +``` + +Example usage: + +```c++ +void weakCallback(const WeakCallbackInfo &data) { + int *parameter = data.GetParameter(); + delete parameter; +} + +Persistent obj; +int *data = new int(0); +obj.SetWeak(data, callback, WeakCallbackType::kParameter); +``` + +See the V8 documentation for [`WeakCallbackInfo`](https://v8docs.nodesource.com/node-8.16/d8/d06/classv8_1_1_weak_callback_info.html) for further information. + + +### Nan::WeakCallbackType + +Represents the type of a weak callback. +A weak callback of type `kParameter` makes the supplied parameter to `Nan::PersistentBase::SetWeak` available through `WeakCallbackInfo::GetParameter`. +A weak callback of type `kInternalFields` uses up to two internal fields at indices 0 and 1 on the `Nan::PersistentBase` being made weak. +Note that only `v8::Object`s and derivatives can have internal fields. + +Definition: + +```c++ +enum class WeakCallbackType { kParameter, kInternalFields }; +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/scopes.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/scopes.md new file mode 100644 index 0000000..84000ee --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/scopes.md @@ -0,0 +1,73 @@ +## Scopes + +A _local handle_ is a pointer to an object. All V8 objects are accessed using handles, they are necessary because of the way the V8 garbage collector works. + +A handle scope can be thought of as a container for any number of handles. When you've finished with your handles, instead of deleting each one individually you can simply delete their scope. + +The creation of `HandleScope` objects is different across the supported versions of V8. Therefore, NAN provides its own implementations that can be used safely across these. + + - Nan::HandleScope + - Nan::EscapableHandleScope + +Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://github.com/v8/v8/wiki/Embedder%27s%20Guide#handles-and-garbage-collection). + + +### Nan::HandleScope + +A simple wrapper around [`v8::HandleScope`](https://v8docs.nodesource.com/node-8.16/d3/d95/classv8_1_1_handle_scope.html). + +Definition: + +```c++ +class Nan::HandleScope { + public: + Nan::HandleScope(); + static int NumberOfHandles(); +}; +``` + +Allocate a new `Nan::HandleScope` whenever you are creating new V8 JavaScript objects. Note that an implicit `HandleScope` is created for you on JavaScript-accessible methods so you do not need to insert one yourself. + +Example: + +```c++ +// new object is created, it needs a new scope: +void Pointless() { + Nan::HandleScope scope; + v8::Local obj = Nan::New(); +} + +// JavaScript-accessible method already has a HandleScope +NAN_METHOD(Pointless2) { + v8::Local obj = Nan::New(); +} +``` + + +### Nan::EscapableHandleScope + +Similar to [`Nan::HandleScope`](#api_nan_handle_scope) but should be used in cases where a function needs to return a V8 JavaScript type that has been created within it. + +Definition: + +```c++ +class Nan::EscapableHandleScope { + public: + Nan::EscapableHandleScope(); + static int NumberOfHandles(); + template v8::Local Escape(v8::Local value); +} +``` + +Use `Escape(value)` to return the object. + +Example: + +```c++ +v8::Local EmptyObj() { + Nan::EscapableHandleScope scope; + v8::Local obj = Nan::New(); + return scope.Escape(obj); +} +``` + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/script.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/script.md new file mode 100644 index 0000000..301c1b3 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/script.md @@ -0,0 +1,58 @@ +## Script + +NAN provides `v8::Script` helpers as the API has changed over the supported versions of V8. + + - Nan::CompileScript() + - Nan::RunScript() + - Nan::ScriptOrigin + + + +### Nan::CompileScript() + +A wrapper around [`v8::ScriptCompiler::Compile()`](https://v8docs.nodesource.com/node-8.16/da/da5/classv8_1_1_script_compiler.html#a93f5072a0db55d881b969e9fc98e564b). + +Note that `Nan::BoundScript` is an alias for `v8::Script`. + +Signature: + +```c++ +Nan::MaybeLocal Nan::CompileScript( + v8::Local s, + const v8::ScriptOrigin& origin); +Nan::MaybeLocal Nan::CompileScript(v8::Local s); +``` + + + +### Nan::RunScript() + +Calls `script->Run()` or `script->BindToCurrentContext()->Run(Nan::GetCurrentContext())`. + +Note that `Nan::BoundScript` is an alias for `v8::Script` and `Nan::UnboundScript` is an alias for `v8::UnboundScript` where available and `v8::Script` on older versions of V8. + +Signature: + +```c++ +Nan::MaybeLocal Nan::RunScript(v8::Local script) +Nan::MaybeLocal Nan::RunScript(v8::Local script) +``` + + +### Nan::ScriptOrigin + +A class transparently extending [`v8::ScriptOrigin`](https://v8docs.nodesource.com/node-16.0/db/d84/classv8_1_1_script_origin.html#pub-methods) +to provide backwards compatibility. Only the listed methods are guaranteed to +be available on all versions of Node. + +Declaration: + +```c++ +class Nan::ScriptOrigin : public v8::ScriptOrigin { + public: + ScriptOrigin(v8::Local name, v8::Local line = v8::Local(), v8::Local column = v8::Local()) + v8::Local ResourceName() const; + v8::Local ResourceLineOffset() const; + v8::Local ResourceColumnOffset() const; +} +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/string_bytes.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/string_bytes.md new file mode 100644 index 0000000..dbd8c51 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/string_bytes.md @@ -0,0 +1,81 @@ +## Strings & Bytes + +Miscellaneous string & byte encoding and decoding functionality provided for compatibility across supported versions of V8 and Node. Implemented by NAN to ensure that all encoding types are supported, even for older versions of Node where they are missing. + + - Nan::Encoding + - Nan::Encode() + - Nan::TryEncode() + - Nan::DecodeBytes() + - Nan::DecodeWrite() + + + +### Nan::Encoding + +An enum representing the supported encoding types. A copy of `node::encoding` that is consistent across versions of Node. + +Definition: + +```c++ +enum Nan::Encoding { ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER } +``` + + + +### Nan::Encode() + +A wrapper around `node::Encode()` that provides a consistent implementation across supported versions of Node. + +**Note** `node::Encode()` was deprecated in Node 24 but will remain to maintain backwards compatibility. For Node 24 and higher consider using [`Nan::TryEncode()`](#api_nan_try_encode). + +Signature: + +```c++ +v8::Local Nan::Encode(const void *buf, + size_t len, + enum Nan::Encoding encoding = BINARY); +``` + + + +### Nan::TryEncode() + +A wrapper around `node::TryEncode()` that provides a consistent implementation across supported versions of Node. + +**Note** Only available in Node 24 and higher. For earlier versions use [`Nan::Encode()`](#api_nan_encode). + +Signature: + +```c++ +Nan::MaybeLocal Nan::TryEncode(const void *buf, + size_t len, + enum Nan::Encoding encoding = BINARY); +``` + + + +### Nan::DecodeBytes() + +A wrapper around `node::DecodeBytes()` that provides a consistent implementation across supported versions of Node. + +Signature: + +```c++ +ssize_t Nan::DecodeBytes(v8::Local val, + enum Nan::Encoding encoding = BINARY); +``` + + + +### Nan::DecodeWrite() + +A wrapper around `node::DecodeWrite()` that provides a consistent implementation across supported versions of Node. + +Signature: + +```c++ +ssize_t Nan::DecodeWrite(char *buf, + size_t len, + v8::Local val, + enum Nan::Encoding encoding = BINARY); +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/v8_internals.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/v8_internals.md new file mode 100644 index 0000000..2e7c918 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/v8_internals.md @@ -0,0 +1,199 @@ +## V8 internals + +The hooks to access V8 internals—including GC and statistics—are different across the supported versions of V8, therefore NAN provides its own hooks that call the appropriate V8 methods. + + - NAN_GC_CALLBACK() + - Nan::AddGCEpilogueCallback() + - Nan::RemoveGCEpilogueCallback() + - Nan::AddGCPrologueCallback() + - Nan::RemoveGCPrologueCallback() + - Nan::GetHeapStatistics() + - Nan::SetCounterFunction() + - Nan::SetCreateHistogramFunction() + - Nan::SetAddHistogramSampleFunction() + - Nan::IdleNotification() + - Nan::LowMemoryNotification() + - Nan::ContextDisposedNotification() + - Nan::GetInternalFieldPointer() + - Nan::SetInternalFieldPointer() + - Nan::AdjustExternalMemory() + + + +### NAN_GC_CALLBACK(callbackname) + +Use `NAN_GC_CALLBACK` to declare your callbacks for `Nan::AddGCPrologueCallback()` and `Nan::AddGCEpilogueCallback()`. Your new method receives the arguments `v8::GCType type` and `v8::GCCallbackFlags flags`. + +```c++ +static Nan::Persistent callback; + +NAN_GC_CALLBACK(gcPrologueCallback) { + v8::Local argv[] = { Nan::New("prologue").ToLocalChecked() }; + Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(callback), 1, argv); +} + +NAN_METHOD(Hook) { + callback.Reset(To(args[0]).ToLocalChecked()); + Nan::AddGCPrologueCallback(gcPrologueCallback); + info.GetReturnValue().Set(info.Holder()); +} +``` + + +### Nan::AddGCEpilogueCallback() + +Signature: + +```c++ +void Nan::AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback, v8::GCType gc_type_filter = v8::kGCTypeAll) +``` + +Calls V8's [`AddGCEpilogueCallback()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a580f976e4290cead62c2fc4dd396be3e). + + +### Nan::RemoveGCEpilogueCallback() + +Signature: + +```c++ +void Nan::RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback) +``` + +Calls V8's [`RemoveGCEpilogueCallback()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#adca9294555a3908e9f23c7bb0f0f284c). + + +### Nan::AddGCPrologueCallback() + +Signature: + +```c++ +void Nan::AddGCPrologueCallback(v8::Isolate::GCPrologueCallback, v8::GCType gc_type_filter callback) +``` + +Calls V8's [`AddGCPrologueCallback()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a6dbef303603ebdb03da6998794ea05b8). + + +### Nan::RemoveGCPrologueCallback() + +Signature: + +```c++ +void Nan::RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback) +``` + +Calls V8's [`RemoveGCPrologueCallback()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a5f72c7cda21415ce062bbe5c58abe09e). + + +### Nan::GetHeapStatistics() + +Signature: + +```c++ +void Nan::GetHeapStatistics(v8::HeapStatistics *heap_statistics) +``` + +Calls V8's [`GetHeapStatistics()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a5593ac74687b713095c38987e5950b34). + + +### Nan::SetCounterFunction() + +Signature: + +```c++ +void Nan::SetCounterFunction(v8::CounterLookupCallback cb) +``` + +Calls V8's [`SetCounterFunction()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a045d7754e62fa0ec72ae6c259b29af94). + + +### Nan::SetCreateHistogramFunction() + +Signature: + +```c++ +void Nan::SetCreateHistogramFunction(v8::CreateHistogramCallback cb) +``` + +Calls V8's [`SetCreateHistogramFunction()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a542d67e85089cb3f92aadf032f99e732). + + +### Nan::SetAddHistogramSampleFunction() + +Signature: + +```c++ +void Nan::SetAddHistogramSampleFunction(v8::AddHistogramSampleCallback cb) +``` + +Calls V8's [`SetAddHistogramSampleFunction()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#aeb420b690bc2c216882d6fdd00ddd3ea). + + +### Nan::IdleNotification() + +Signature: + +```c++ +NAN_DEPRECATED bool Nan::IdleNotification(int idle_time_in_ms) +``` + +Calls V8's [`IdleNotification()` or `IdleNotificationDeadline()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#ad6a2a02657f5425ad460060652a5a118) depending on V8 version. Removed in V8 12.7.41. + + +### Nan::LowMemoryNotification() + +Signature: + +```c++ +void Nan::LowMemoryNotification() +``` + +Calls V8's [`LowMemoryNotification()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a24647f61d6b41f69668094bdcd6ea91f). + + +### Nan::ContextDisposedNotification() + +Signature: + +```c++ +void Nan::ContextDisposedNotification() +``` + +Calls V8's [`ContextDisposedNotification()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#ad7f5dc559866343fe6cd8db1f134d48b). + + +### Nan::GetInternalFieldPointer() + +Gets a pointer to the internal field with at `index` from a V8 `Object` handle. + +Signature: + +```c++ +void* Nan::GetInternalFieldPointer(v8::Local object, int index) +``` + +Calls the Object's [`GetAlignedPointerFromInternalField()` or `GetPointerFromInternalField()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#a580ea84afb26c005d6762eeb9e3c308f) depending on the version of V8. + + +### Nan::SetInternalFieldPointer() + +Sets the value of the internal field at `index` on a V8 `Object` handle. + +Signature: + +```c++ +void Nan::SetInternalFieldPointer(v8::Local object, int index, void* value) +``` + +Calls the Object's [`SetAlignedPointerInInternalField()` or `SetPointerInInternalField()`](https://v8docs.nodesource.com/node-8.16/db/d85/classv8_1_1_object.html#ab3c57184263cf29963ef0017bec82281) depending on the version of V8. + + +### Nan::AdjustExternalMemory() + +Signature: + +```c++ +int Nan::AdjustExternalMemory(int bytesChange) +``` + +Calls V8's [`AdjustAmountOfExternalAllocatedMemory()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#ae1a59cac60409d3922582c4af675473e). + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/doc/v8_misc.md b/tasks/enduro-trails/prototype/node_modules/nan/doc/v8_misc.md new file mode 100644 index 0000000..1bd46d3 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/doc/v8_misc.md @@ -0,0 +1,85 @@ +## Miscellaneous V8 Helpers + + - Nan::Utf8String + - Nan::GetCurrentContext() + - Nan::SetIsolateData() + - Nan::GetIsolateData() + - Nan::TypedArrayContents + + + +### Nan::Utf8String + +Converts an object to a UTF-8-encoded character array. If conversion to a string fails (e.g. due to an exception in the toString() method of the object) then the length() method returns 0 and the * operator returns NULL. The underlying memory used for this object is managed by the object. + +An implementation of [`v8::String::Utf8Value`](https://v8docs.nodesource.com/node-8.16/d4/d1b/classv8_1_1_string_1_1_utf8_value.html) that is consistent across all supported versions of V8. + +Definition: + +```c++ +class Nan::Utf8String { + public: + Nan::Utf8String(v8::Local from); + + int length() const; + + char* operator*(); + const char* operator*() const; +}; +``` + + +### Nan::GetCurrentContext() + +A call to [`v8::Isolate::GetCurrent()->GetCurrentContext()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a81c7a1ed7001ae2a65e89107f75fd053) that works across all supported versions of V8. + +Signature: + +```c++ +v8::Local Nan::GetCurrentContext() +``` + + +### Nan::SetIsolateData() + +A helper to provide a consistent API to [`v8::Isolate#SetData()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#a7acadfe7965997e9c386a05f098fbe36). + +Signature: + +```c++ +void Nan::SetIsolateData(v8::Isolate *isolate, T *data) +``` + + + +### Nan::GetIsolateData() + +A helper to provide a consistent API to [`v8::Isolate#GetData()`](https://v8docs.nodesource.com/node-8.16/d5/dda/classv8_1_1_isolate.html#aabd223436bc1100a787dadaa024c6257). + +Signature: + +```c++ +T *Nan::GetIsolateData(v8::Isolate *isolate) +``` + + +### Nan::TypedArrayContents + +A helper class for accessing the contents of an ArrayBufferView (aka a typedarray) from C++. If the input array is not a valid typedarray, then the data pointer of TypedArrayContents will default to `NULL` and the length will be 0. If the data pointer is not compatible with the alignment requirements of type, an assertion error will fail. + +Note that you must store a reference to the `array` object while you are accessing its contents. + +Definition: + +```c++ +template +class Nan::TypedArrayContents { + public: + TypedArrayContents(v8::Local array); + + size_t length() const; + + T* const operator*(); + const T* const operator*() const; +}; +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/include_dirs.js b/tasks/enduro-trails/prototype/node_modules/nan/include_dirs.js new file mode 100644 index 0000000..4f1dfb4 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/include_dirs.js @@ -0,0 +1 @@ +console.log(require('path').relative('.', __dirname)); diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan.h b/tasks/enduro-trails/prototype/node_modules/nan/nan.h new file mode 100644 index 0000000..e1ad126 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan.h @@ -0,0 +1,3202 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors: + * - Rod Vagg + * - Benjamin Byholm + * - Trevor Norris + * - Nathan Rajlich + * - Brett Lawson + * - Ben Noordhuis + * - David Siegel + * - Michael Ira Krufky + * + * MIT License + * + * Version 2.26.2: current Node 25.8.1, Node 0.12: 0.12.18, Node 0.10: 0.10.48, iojs: 3.3.1 + * + * See https://github.com/nodejs/nan for the latest update to this file + **********************************************************************************/ + +#ifndef NAN_H_ +#define NAN_H_ + +#include + +#define NODE_0_10_MODULE_VERSION 11 +#define NODE_0_12_MODULE_VERSION 14 +#define ATOM_0_21_MODULE_VERSION 41 +#define IOJS_1_0_MODULE_VERSION 42 +#define IOJS_1_1_MODULE_VERSION 43 +#define IOJS_2_0_MODULE_VERSION 44 +#define IOJS_3_0_MODULE_VERSION 45 +#define NODE_4_0_MODULE_VERSION 46 +#define NODE_5_0_MODULE_VERSION 47 +#define NODE_6_0_MODULE_VERSION 48 +#define NODE_7_0_MODULE_VERSION 51 +#define NODE_8_0_MODULE_VERSION 57 +#define NODE_9_0_MODULE_VERSION 59 +#define NODE_10_0_MODULE_VERSION 64 +#define NODE_11_0_MODULE_VERSION 67 +#define NODE_12_0_MODULE_VERSION 72 +#define NODE_13_0_MODULE_VERSION 79 +#define NODE_14_0_MODULE_VERSION 83 +#define NODE_15_0_MODULE_VERSION 88 +#define NODE_16_0_MODULE_VERSION 93 +#define NODE_17_0_MODULE_VERSION 102 +#define NODE_18_0_MODULE_VERSION 108 +#define NODE_19_0_MODULE_VERSION 111 +#define NODE_20_0_MODULE_VERSION 115 +#define NODE_21_0_MODULE_VERSION 120 +#define NODE_22_0_MODULE_VERSION 127 +#define NODE_23_0_MODULE_VERSION 131 +#define NODE_24_0_MODULE_VERSION 137 +#define NODE_25_0_MODULE_VERSION 141 + +#ifdef _MSC_VER +# define NAN_HAS_CPLUSPLUS_11 (_MSC_VER >= 1800) +#else +# define NAN_HAS_CPLUSPLUS_11 (__cplusplus >= 201103L) +#endif + +#if NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION && !NAN_HAS_CPLUSPLUS_11 +# error This version of node/NAN/v8 requires a C++11 compiler +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_MSC_VER) +# pragma warning( push ) +# pragma warning( disable : 4530 ) +# include +# include +# include +# pragma warning( pop ) +#else +# include +# include +# include +#endif + +// uv helpers +#ifdef UV_VERSION_MAJOR +# ifndef UV_VERSION_PATCH +# define UV_VERSION_PATCH 0 +# endif +# define NAUV_UVVERSION ((UV_VERSION_MAJOR << 16) | \ + (UV_VERSION_MINOR << 8) | \ + (UV_VERSION_PATCH)) +#else +# define NAUV_UVVERSION 0x000b00 +#endif + +#if NAUV_UVVERSION < 0x000b0b +# ifdef WIN32 +# include +# else +# include +# endif +#endif + +namespace Nan { + +#define NAN_CONCAT(a, b) NAN_CONCAT_HELPER(a, b) +#define NAN_CONCAT_HELPER(a, b) a##b + +#define NAN_INLINE inline // TODO(bnoordhuis) Remove in v3.0.0. + +#if defined(__GNUC__) && \ + !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS) +# define NAN_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) && \ + !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS) +# define NAN_DEPRECATED __declspec(deprecated) +#else +# define NAN_DEPRECATED +#endif + +#if NAN_HAS_CPLUSPLUS_11 +# define NAN_DISALLOW_ASSIGN(CLASS) void operator=(const CLASS&) = delete; +# define NAN_DISALLOW_COPY(CLASS) CLASS(const CLASS&) = delete; +# define NAN_DISALLOW_MOVE(CLASS) \ + CLASS(CLASS&&) = delete; /* NOLINT(build/c++11) */ \ + void operator=(CLASS&&) = delete; +#else +# define NAN_DISALLOW_ASSIGN(CLASS) void operator=(const CLASS&); +# define NAN_DISALLOW_COPY(CLASS) CLASS(const CLASS&); +# define NAN_DISALLOW_MOVE(CLASS) +#endif + +#define NAN_DISALLOW_ASSIGN_COPY(CLASS) \ + NAN_DISALLOW_ASSIGN(CLASS) \ + NAN_DISALLOW_COPY(CLASS) + +#define NAN_DISALLOW_ASSIGN_MOVE(CLASS) \ + NAN_DISALLOW_ASSIGN(CLASS) \ + NAN_DISALLOW_MOVE(CLASS) + +#define NAN_DISALLOW_COPY_MOVE(CLASS) \ + NAN_DISALLOW_COPY(CLASS) \ + NAN_DISALLOW_MOVE(CLASS) + +#define NAN_DISALLOW_ASSIGN_COPY_MOVE(CLASS) \ + NAN_DISALLOW_ASSIGN(CLASS) \ + NAN_DISALLOW_COPY(CLASS) \ + NAN_DISALLOW_MOVE(CLASS) + +#define TYPE_CHECK(T, S) \ + while (false) { \ + *(static_cast(0)) = static_cast(0); \ + } + +//=== RegistrationFunction ===================================================== + +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + typedef v8::Handle ADDON_REGISTER_FUNCTION_ARGS_TYPE; +#else + typedef v8::Local ADDON_REGISTER_FUNCTION_ARGS_TYPE; +#endif + +#define NAN_MODULE_INIT(name) \ + void name(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) + +#if NODE_MAJOR_VERSION >= 10 || \ + NODE_MAJOR_VERSION == 9 && NODE_MINOR_VERSION >= 3 +#define NAN_MODULE_WORKER_ENABLED(module_name, registration) \ + extern "C" NODE_MODULE_EXPORT void \ + NAN_CONCAT(node_register_module_v, NODE_MODULE_VERSION)( \ + v8::Local exports, v8::Local module, \ + v8::Local context) \ + { \ + registration(exports); \ + } +#else +#define NAN_MODULE_WORKER_ENABLED(module_name, registration) \ + NODE_MODULE(module_name, registration) +#endif + +//=== CallbackInfo ============================================================= + +#include "nan_callbacks.h" // NOLINT(build/include_subdir) + +//============================================================================== + +#if (NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION) +typedef v8::Script UnboundScript; +typedef v8::Script BoundScript; +#else +typedef v8::UnboundScript UnboundScript; +typedef v8::Script BoundScript; +#endif + +#if (NODE_MODULE_VERSION < ATOM_0_21_MODULE_VERSION) +typedef v8::String::ExternalAsciiStringResource + ExternalOneByteStringResource; +#else +typedef v8::String::ExternalOneByteStringResource + ExternalOneByteStringResource; +#endif + +#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) +template +class NonCopyablePersistentTraits : + public v8::NonCopyablePersistentTraits {}; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 10 || \ + (V8_MAJOR_VERSION == 10 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 5)) +template struct CopyablePersistentTraits { + typedef v8::Persistent > CopyablePersistent; + static const bool kResetInDestructor = true; + template + static NAN_INLINE void Copy(const v8::Persistent &source, + CopyablePersistent *dest) { + } +}; +#else +template +class CopyablePersistentTraits : + public v8::CopyablePersistentTraits {}; +#endif + +template +class PersistentBase : + public v8::PersistentBase {}; + +template > +class Persistent; +#else +template class NonCopyablePersistentTraits; +template class PersistentBase; +template class WeakCallbackData; +template > +class Persistent; +#endif // NODE_MODULE_VERSION + +template +class Maybe { + public: + inline bool IsNothing() const { return !has_value_; } + inline bool IsJust() const { return has_value_; } + + inline T ToChecked() const { return FromJust(); } + inline void Check() const { FromJust(); } + + inline bool To(T* out) const { + if (IsJust()) *out = value_; + return IsJust(); + } + + inline T FromJust() const { +#if defined(V8_ENABLE_CHECKS) + assert(IsJust() && "FromJust is Nothing"); +#endif // V8_ENABLE_CHECKS + return value_; + } + + inline T FromMaybe(const T& default_value) const { + return has_value_ ? value_ : default_value; + } + + inline bool operator==(const Maybe &other) const { + return (IsJust() == other.IsJust()) && + (!IsJust() || FromJust() == other.FromJust()); + } + + inline bool operator!=(const Maybe &other) const { + return !operator==(other); + } + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + // Allow implicit conversions from v8::Maybe to Nan::Maybe. + Maybe(const v8::Maybe& that) // NOLINT(runtime/explicit) + : has_value_(that.IsJust()) + , value_(that.FromMaybe(T())) {} +#endif + + private: + Maybe() : has_value_(false) {} + explicit Maybe(const T& t) : has_value_(true), value_(t) {} + bool has_value_; + T value_; + + template + friend Maybe Nothing(); + template + friend Maybe Just(const U& u); +}; + +template +inline Maybe Nothing() { + return Maybe(); +} + +template +inline Maybe Just(const T& t) { + return Maybe(t); +} + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +# include "nan_maybe_43_inl.h" // NOLINT(build/include) +#else +# include "nan_maybe_pre_43_inl.h" // NOLINT(build/include) +#endif + +#include "nan_converters.h" // NOLINT(build/include_subdir) +#include "nan_new.h" // NOLINT(build/include_subdir) + +#if NAUV_UVVERSION < 0x000b17 +#define NAUV_WORK_CB(func) \ + void func(uv_async_t *async, int) +#else +#define NAUV_WORK_CB(func) \ + void func(uv_async_t *async) +#endif + +#if NAUV_UVVERSION >= 0x000b0b + +typedef uv_key_t nauv_key_t; + +inline int nauv_key_create(nauv_key_t *key) { + return uv_key_create(key); +} + +inline void nauv_key_delete(nauv_key_t *key) { + uv_key_delete(key); +} + +inline void* nauv_key_get(nauv_key_t *key) { + return uv_key_get(key); +} + +inline void nauv_key_set(nauv_key_t *key, void *value) { + uv_key_set(key, value); +} + +#else + +/* Implement thread local storage for older versions of libuv. + * This is essentially a backport of libuv commit 5d2434bf + * written by Ben Noordhuis, adjusted for names and inline. + */ + +#ifndef WIN32 + +typedef pthread_key_t nauv_key_t; + +inline int nauv_key_create(nauv_key_t* key) { + return -pthread_key_create(key, NULL); +} + +inline void nauv_key_delete(nauv_key_t* key) { + if (pthread_key_delete(*key)) + abort(); +} + +inline void* nauv_key_get(nauv_key_t* key) { + return pthread_getspecific(*key); +} + +inline void nauv_key_set(nauv_key_t* key, void* value) { + if (pthread_setspecific(*key, value)) + abort(); +} + +#else + +typedef struct { + DWORD tls_index; +} nauv_key_t; + +inline int nauv_key_create(nauv_key_t* key) { + key->tls_index = TlsAlloc(); + if (key->tls_index == TLS_OUT_OF_INDEXES) + return UV_ENOMEM; + return 0; +} + +inline void nauv_key_delete(nauv_key_t* key) { + if (TlsFree(key->tls_index) == FALSE) + abort(); + key->tls_index = TLS_OUT_OF_INDEXES; +} + +inline void* nauv_key_get(nauv_key_t* key) { + void* value = TlsGetValue(key->tls_index); + if (value == NULL) + if (GetLastError() != ERROR_SUCCESS) + abort(); + return value; +} + +inline void nauv_key_set(nauv_key_t* key, void* value) { + if (TlsSetValue(key->tls_index, value) == FALSE) + abort(); +} + +#endif +#endif + +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION +template +v8::Local New(v8::Handle); +#endif + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + typedef v8::WeakCallbackType WeakCallbackType; +#else +struct WeakCallbackType { + enum E {kParameter, kInternalFields}; + E type; + WeakCallbackType(E other) : type(other) {} // NOLINT(runtime/explicit) + inline bool operator==(E other) { return other == this->type; } + inline bool operator!=(E other) { return !operator==(other); } +}; +#endif + +template class WeakCallbackInfo; + +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION +# include "nan_persistent_12_inl.h" // NOLINT(build/include) +#else +# include "nan_persistent_pre_12_inl.h" // NOLINT(build/include) +#endif + +namespace imp { + static const size_t kMaxLength = 0x3fffffff; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 13 || \ + (V8_MAJOR_VERSION == 13 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 4)) + static const unsigned kReplaceInvalidUtf8 + = v8::String::WriteFlags::kReplaceInvalidUtf8; +#else + static const unsigned kReplaceInvalidUtf8 = v8::String::REPLACE_INVALID_UTF8; +#endif +} // end of namespace imp + +//=== HandleScope ============================================================== + +class HandleScope { + v8::HandleScope scope; + + public: +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + inline HandleScope() : scope(v8::Isolate::GetCurrent()) {} + inline static int NumberOfHandles() { + return v8::HandleScope::NumberOfHandles(v8::Isolate::GetCurrent()); + } +#else + inline HandleScope() : scope() {} + inline static int NumberOfHandles() { + return v8::HandleScope::NumberOfHandles(); + } +#endif + + private: + // Make it hard to create heap-allocated or illegal handle scopes by + // disallowing certain operations. + HandleScope(const HandleScope &); + void operator=(const HandleScope &); + void *operator new(size_t size); + void operator delete(void *, size_t) { + abort(); + } +}; + +class EscapableHandleScope { + public: +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + inline EscapableHandleScope() : scope(v8::Isolate::GetCurrent()) {} + + inline static int NumberOfHandles() { + return v8::EscapableHandleScope::NumberOfHandles(v8::Isolate::GetCurrent()); + } + + template + inline v8::Local Escape(v8::Local value) { + return scope.Escape(value); + } + + private: + v8::EscapableHandleScope scope; +#else + inline EscapableHandleScope() : scope() {} + + inline static int NumberOfHandles() { + return v8::HandleScope::NumberOfHandles(); + } + + template + inline v8::Local Escape(v8::Local value) { + return scope.Close(value); + } + + private: + v8::HandleScope scope; +#endif + + private: + // Make it hard to create heap-allocated or illegal handle scopes by + // disallowing certain operations. + EscapableHandleScope(const EscapableHandleScope &); + void operator=(const EscapableHandleScope &); + void *operator new(size_t size); + void operator delete(void *, size_t) { + abort(); + } +}; + +//=== TryCatch ================================================================= + +class TryCatch { + v8::TryCatch try_catch_; + friend void FatalException(const TryCatch&); + + public: +#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION + TryCatch() : try_catch_(v8::Isolate::GetCurrent()) {} +#endif + + inline bool HasCaught() const { return try_catch_.HasCaught(); } + + inline bool CanContinue() const { return try_catch_.CanContinue(); } + + inline v8::Local ReThrow() { +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + return New(try_catch_.ReThrow()); +#else + return try_catch_.ReThrow(); +#endif + } + + inline v8::Local Exception() const { + return try_catch_.Exception(); + } + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + inline v8::MaybeLocal StackTrace() const { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(try_catch_.StackTrace(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); + } +#else + inline MaybeLocal StackTrace() const { + return try_catch_.StackTrace(); + } +#endif + + inline v8::Local Message() const { + return try_catch_.Message(); + } + + inline void Reset() { try_catch_.Reset(); } + + inline void SetVerbose(bool value) { try_catch_.SetVerbose(value); } + + inline void SetCaptureMessage(bool value) { + try_catch_.SetCaptureMessage(value); + } +}; + +v8::Local MakeCallback(v8::Local target, + v8::Local func, + int argc, + v8::Local* argv); +v8::Local MakeCallback(v8::Local target, + v8::Local symbol, + int argc, + v8::Local* argv); +v8::Local MakeCallback(v8::Local target, + const char* method, + int argc, + v8::Local* argv); + +// === AsyncResource =========================================================== + +class AsyncResource { + public: + AsyncResource( + v8::Local name + , v8::Local resource = New()) { +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + + if (resource.IsEmpty()) { + resource = New(); + } + + context = node::EmitAsyncInit(isolate, resource, name); +#endif + } + + AsyncResource( + const char* name + , v8::Local resource = New()) { +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + + if (resource.IsEmpty()) { + resource = New(); + } + + v8::Local name_string = + New(name).ToLocalChecked(); + context = node::EmitAsyncInit(isolate, resource, name_string); +#endif + } + + ~AsyncResource() { +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + node::EmitAsyncDestroy(isolate, context); +#endif + } + + inline MaybeLocal runInAsyncScope( + v8::Local target + , v8::Local func + , int argc + , v8::Local* argv) { +#if NODE_MODULE_VERSION < NODE_9_0_MODULE_VERSION + return MakeCallback(target, func, argc, argv); +#else + return node::MakeCallback( + v8::Isolate::GetCurrent(), target, func, argc, argv, context); +#endif + } + + inline MaybeLocal runInAsyncScope( + v8::Local target + , v8::Local symbol + , int argc + , v8::Local* argv) { +#if NODE_MODULE_VERSION < NODE_9_0_MODULE_VERSION + return MakeCallback(target, symbol, argc, argv); +#else + return node::MakeCallback( + v8::Isolate::GetCurrent(), target, symbol, argc, argv, context); +#endif + } + + inline MaybeLocal runInAsyncScope( + v8::Local target + , const char* method + , int argc + , v8::Local* argv) { +#if NODE_MODULE_VERSION < NODE_9_0_MODULE_VERSION + return MakeCallback(target, method, argc, argv); +#else + return node::MakeCallback( + v8::Isolate::GetCurrent(), target, method, argc, argv, context); +#endif + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(AsyncResource) +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + node::async_context context; +#endif +}; + +inline uv_loop_t* GetCurrentEventLoop() { +#if NODE_MAJOR_VERSION >= 10 || \ + NODE_MAJOR_VERSION == 9 && NODE_MINOR_VERSION >= 3 || \ + NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION >= 10 + return node::GetCurrentEventLoop(v8::Isolate::GetCurrent()); +#else + return uv_default_loop(); +#endif +} + +//============ ================================================================= + +/* node 0.12 */ +#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION + inline + void SetCounterFunction(v8::CounterLookupCallback cb) { + v8::Isolate::GetCurrent()->SetCounterFunction(cb); + } + + inline + void SetCreateHistogramFunction(v8::CreateHistogramCallback cb) { + v8::Isolate::GetCurrent()->SetCreateHistogramFunction(cb); + } + + inline + void SetAddHistogramSampleFunction(v8::AddHistogramSampleCallback cb) { + v8::Isolate::GetCurrent()->SetAddHistogramSampleFunction(cb); + } + +#if defined(V8_MAJOR_VERSION) && \ + (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && \ + V8_MINOR_VERSION >= 7)) + NAN_DEPRECATED inline bool IdleNotification(int) { + return true; + } +# elif defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + NAN_DEPRECATED inline bool IdleNotification(int idle_time_in_ms) { + return v8::Isolate::GetCurrent()->IdleNotificationDeadline( + idle_time_in_ms * 0.001); + } +# else + NAN_DEPRECATED inline bool IdleNotification(int idle_time_in_ms) { + return v8::Isolate::GetCurrent()->IdleNotification(idle_time_in_ms); + } +#endif + + inline void LowMemoryNotification() { + v8::Isolate::GetCurrent()->LowMemoryNotification(); + } + + inline void ContextDisposedNotification() { + v8::Isolate::GetCurrent()->ContextDisposedNotification(); + } +#else + inline + void SetCounterFunction(v8::CounterLookupCallback cb) { + v8::V8::SetCounterFunction(cb); + } + + inline + void SetCreateHistogramFunction(v8::CreateHistogramCallback cb) { + v8::V8::SetCreateHistogramFunction(cb); + } + + inline + void SetAddHistogramSampleFunction(v8::AddHistogramSampleCallback cb) { + v8::V8::SetAddHistogramSampleFunction(cb); + } + + inline bool IdleNotification(int idle_time_in_ms) { + return v8::V8::IdleNotification(idle_time_in_ms); + } + + inline void LowMemoryNotification() { + v8::V8::LowMemoryNotification(); + } + + inline void ContextDisposedNotification() { + v8::V8::ContextDisposedNotification(); + } +#endif + +#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) // Node 0.12 + inline v8::Local Undefined() { +# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(v8::Undefined(v8::Isolate::GetCurrent()))); +# else + return v8::Undefined(v8::Isolate::GetCurrent()); +# endif + } + + inline v8::Local Null() { +# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(v8::Null(v8::Isolate::GetCurrent()))); +# else + return v8::Null(v8::Isolate::GetCurrent()); +# endif + } + + inline v8::Local True() { +# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(v8::True(v8::Isolate::GetCurrent()))); +# else + return v8::True(v8::Isolate::GetCurrent()); +# endif + } + + inline v8::Local False() { +# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(v8::False(v8::Isolate::GetCurrent()))); +# else + return v8::False(v8::Isolate::GetCurrent()); +# endif + } + + inline v8::Local EmptyString() { + return v8::String::Empty(v8::Isolate::GetCurrent()); + } + + inline int AdjustExternalMemory(int bc) { + return static_cast( + v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(bc)); + } + + inline void SetTemplate( + v8::Local templ + , const char *name + , v8::Local value) { + templ->Set(v8::Isolate::GetCurrent(), name, value); + } + + inline void SetTemplate( + v8::Local templ + , v8::Local name + , v8::Local value + , v8::PropertyAttribute attributes) { + templ->Set(name, value, attributes); + } + + inline v8::Local GetCurrentContext() { + return v8::Isolate::GetCurrent()->GetCurrentContext(); + } + + inline void* GetInternalFieldPointer( + v8::Local object + , int index) { +#if (V8_MAJOR_VERSION > 14) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION > 2) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 2 && V8_BUILD_NUMBER >= 194) + return object->GetAlignedPointerFromInternalField( + index, v8::kEmbedderDataTypeTagDefault + ); +# else + return object->GetAlignedPointerFromInternalField(index); +# endif + } + + inline void SetInternalFieldPointer( + v8::Local object + , int index + , void* value) { +#if (V8_MAJOR_VERSION > 14) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION > 2) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 2 && V8_BUILD_NUMBER >= 194) + object->SetAlignedPointerInInternalField( + index, value, v8::kEmbedderDataTypeTagDefault + ); +# else + object->SetAlignedPointerInInternalField(index, value); +# endif + } + +# define NAN_GC_CALLBACK(name) \ + void name(v8::Isolate *isolate, v8::GCType type, v8::GCCallbackFlags flags) + +#if NODE_MODULE_VERSION <= NODE_4_0_MODULE_VERSION + typedef v8::Isolate::GCEpilogueCallback GCEpilogueCallback; + typedef v8::Isolate::GCPrologueCallback GCPrologueCallback; +#else + typedef v8::Isolate::GCCallback GCEpilogueCallback; + typedef v8::Isolate::GCCallback GCPrologueCallback; +#endif + + inline void AddGCEpilogueCallback( + GCEpilogueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::Isolate::GetCurrent()->AddGCEpilogueCallback(callback, gc_type_filter); + } + + inline void RemoveGCEpilogueCallback( + GCEpilogueCallback callback) { + v8::Isolate::GetCurrent()->RemoveGCEpilogueCallback(callback); + } + + inline void AddGCPrologueCallback( + GCPrologueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::Isolate::GetCurrent()->AddGCPrologueCallback(callback, gc_type_filter); + } + + inline void RemoveGCPrologueCallback( + GCPrologueCallback callback) { + v8::Isolate::GetCurrent()->RemoveGCPrologueCallback(callback); + } + + inline void GetHeapStatistics( + v8::HeapStatistics *heap_statistics) { + v8::Isolate::GetCurrent()->GetHeapStatistics(heap_statistics); + } + +# define X(NAME) \ + inline v8::Local NAME(const char *msg) { \ + EscapableHandleScope scope; \ + return scope.Escape(v8::Exception::NAME(New(msg).ToLocalChecked())); \ + } \ + \ + inline \ + v8::Local NAME(v8::Local msg) { \ + return v8::Exception::NAME(msg); \ + } \ + \ + inline void Throw ## NAME(const char *msg) { \ + HandleScope scope; \ + v8::Isolate::GetCurrent()->ThrowException( \ + v8::Exception::NAME(New(msg).ToLocalChecked())); \ + } \ + \ + inline void Throw ## NAME(v8::Local msg) { \ + HandleScope scope; \ + v8::Isolate::GetCurrent()->ThrowException( \ + v8::Exception::NAME(msg)); \ + } + + X(Error) + X(RangeError) + X(ReferenceError) + X(SyntaxError) + X(TypeError) + +# undef X + + inline void ThrowError(v8::Local error) { + v8::Isolate::GetCurrent()->ThrowException(error); + } + + inline MaybeLocal NewBuffer( + char *data + , size_t length +#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION + , node::Buffer::FreeCallback callback +#else + , node::smalloc::FreeCallback callback +#endif + , void *hint + ) { + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(length <= imp::kMaxLength && "too large buffer"); +#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION + return node::Buffer::New( + v8::Isolate::GetCurrent(), data, length, callback, hint); +#else + return node::Buffer::New(v8::Isolate::GetCurrent(), data, length, callback, + hint); +#endif + } + + inline MaybeLocal CopyBuffer( + const char *data + , uint32_t size + ) { + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(size <= imp::kMaxLength && "too large buffer"); +#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION + return node::Buffer::Copy( + v8::Isolate::GetCurrent(), data, size); +#else + return node::Buffer::New(v8::Isolate::GetCurrent(), data, size); +#endif + } + + inline MaybeLocal NewBuffer(uint32_t size) { + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(size <= imp::kMaxLength && "too large buffer"); +#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION + return node::Buffer::New( + v8::Isolate::GetCurrent(), size); +#else + return node::Buffer::New(v8::Isolate::GetCurrent(), size); +#endif + } + + inline MaybeLocal NewBuffer( + char* data + , uint32_t size + ) { + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(size <= imp::kMaxLength && "too large buffer"); +#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION + return node::Buffer::New(v8::Isolate::GetCurrent(), data, size); +#else + return node::Buffer::Use(v8::Isolate::GetCurrent(), data, size); +#endif + } + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + inline MaybeLocal + NewOneByteString(const uint8_t * value, int length = -1) { + return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value, + v8::NewStringType::kNormal, length); + } + + inline MaybeLocal CompileScript( + v8::Local s + , const v8::ScriptOrigin& origin + ) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::ScriptCompiler::Source source(s, origin); + return scope.Escape( + v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &source) + .FromMaybe(v8::Local())); + } + + inline MaybeLocal CompileScript( + v8::Local s + ) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::ScriptCompiler::Source source(s); + return scope.Escape( + v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &source) + .FromMaybe(v8::Local())); + } + + inline MaybeLocal RunScript( + v8::Local script + ) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(script->BindToCurrentContext() + ->Run(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); + } + + inline MaybeLocal RunScript( + v8::Local script + ) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(script->Run(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); + } +#else + inline MaybeLocal + NewOneByteString(const uint8_t * value, int length = -1) { + return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value, + v8::String::kNormalString, length); + } + + inline MaybeLocal CompileScript( + v8::Local s + , const v8::ScriptOrigin& origin + ) { + v8::ScriptCompiler::Source source(s, origin); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source); + } + + inline MaybeLocal CompileScript( + v8::Local s + ) { + v8::ScriptCompiler::Source source(s); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source); + } + + inline MaybeLocal RunScript( + v8::Local script + ) { + EscapableHandleScope scope; + return scope.Escape(script->BindToCurrentContext()->Run()); + } + + inline MaybeLocal RunScript( + v8::Local script + ) { + return script->Run(); + } +#endif + + NAN_DEPRECATED inline v8::Local MakeCallback( + v8::Local target + , v8::Local func + , int argc + , v8::Local* argv) { +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(node::MakeCallback( + v8::Isolate::GetCurrent(), target, func, argc, argv))); +#else +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource res("nan:makeCallback"); + return res.runInAsyncScope(target, func, argc, argv) + .FromMaybe(v8::Local()); +# else + return node::MakeCallback( + v8::Isolate::GetCurrent(), target, func, argc, argv); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#endif // NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + } + + NAN_DEPRECATED inline v8::Local MakeCallback( + v8::Local target + , v8::Local symbol + , int argc + , v8::Local* argv) { +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(node::MakeCallback( + v8::Isolate::GetCurrent(), target, symbol, argc, argv))); +#else +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource res("nan:makeCallback"); + return res.runInAsyncScope(target, symbol, argc, argv) + .FromMaybe(v8::Local()); +# else + return node::MakeCallback( + v8::Isolate::GetCurrent(), target, symbol, argc, argv); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#endif // NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + } + + NAN_DEPRECATED inline v8::Local MakeCallback( + v8::Local target + , const char* method + , int argc + , v8::Local* argv) { +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + return scope.Escape(New(node::MakeCallback( + v8::Isolate::GetCurrent(), target, method, argc, argv))); +#else +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource res("nan:makeCallback"); + return res.runInAsyncScope(target, method, argc, argv) + .FromMaybe(v8::Local()); +# else + return node::MakeCallback( + v8::Isolate::GetCurrent(), target, method, argc, argv); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#endif // NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + } + + inline void FatalException(const TryCatch& try_catch) { + node::FatalException(v8::Isolate::GetCurrent(), try_catch.try_catch_); + } + + inline v8::Local ErrnoException( + int errorno + , const char* syscall = NULL + , const char* message = NULL + , const char* path = NULL) { + return node::ErrnoException(v8::Isolate::GetCurrent(), errorno, syscall, + message, path); + } + + NAN_DEPRECATED inline v8::Local NanErrnoException( + int errorno + , const char* syscall = NULL + , const char* message = NULL + , const char* path = NULL) { + return ErrnoException(errorno, syscall, message, path); + } + + template + inline void SetIsolateData( + v8::Isolate *isolate + , T *data + ) { + isolate->SetData(0, data); + } + + template + inline T *GetIsolateData( + v8::Isolate *isolate + ) { + return static_cast(isolate->GetData(0)); + } + +class Utf8String { + public: + inline explicit Utf8String(v8::Local from) : + length_(0), str_(str_st_) { + HandleScope scope; + if (!from.IsEmpty()) { +#if NODE_MAJOR_VERSION >= 10 + v8::Local context = GetCurrentContext(); + v8::Local string = + from->ToString(context).FromMaybe(v8::Local()); +#else + v8::Local string = from->ToString(); +#endif + if (!string.IsEmpty()) { + size_t len = 3 * string->Length() + 1; + assert(len <= INT_MAX); + if (len > sizeof (str_st_)) { + str_ = static_cast(malloc(len)); + assert(str_ != 0); + } +#if NODE_MAJOR_VERSION >= 11 +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 13 || \ + (V8_MAJOR_VERSION == 13 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 4)) + length_ = string->WriteUtf8V2(v8::Isolate::GetCurrent(), str_, + static_cast(len), imp::kReplaceInvalidUtf8); +#else + const int flags = + v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8; + length_ = string->WriteUtf8(v8::Isolate::GetCurrent(), str_, + static_cast(len), 0, flags); +#endif + +#else + // See https://github.com/nodejs/nan/issues/832. + // Disable the warning as there is no way around it. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + const int flags = + v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8; + length_ = string->WriteUtf8(str_, static_cast(len), 0, flags); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif // NODE_MAJOR_VERSION < 11 + str_[length_] = '\0'; + } + } + } + + inline int length() const { + return length_; + } + + inline char* operator*() { return str_; } + inline const char* operator*() const { return str_; } + + inline ~Utf8String() { + if (str_ != str_st_) { + free(str_); + } + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(Utf8String) + + int length_; + char *str_; + char str_st_[1024]; +}; + +#else // Node 0.8 and 0.10 + inline v8::Local Undefined() { + EscapableHandleScope scope; + return scope.Escape(New(v8::Undefined())); + } + + inline v8::Local Null() { + EscapableHandleScope scope; + return scope.Escape(New(v8::Null())); + } + + inline v8::Local True() { + EscapableHandleScope scope; + return scope.Escape(New(v8::True())); + } + + inline v8::Local False() { + EscapableHandleScope scope; + return scope.Escape(New(v8::False())); + } + + inline v8::Local EmptyString() { + return v8::String::Empty(); + } + + inline int AdjustExternalMemory(int bc) { + return static_cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(bc)); + } + + inline void SetTemplate( + v8::Local templ + , const char *name + , v8::Local value) { + templ->Set(name, value); + } + + inline void SetTemplate( + v8::Local templ + , v8::Local name + , v8::Local value + , v8::PropertyAttribute attributes) { + templ->Set(name, value, attributes); + } + + inline v8::Local GetCurrentContext() { + return v8::Context::GetCurrent(); + } + + inline void* GetInternalFieldPointer( + v8::Local object + , int index) { + return object->GetPointerFromInternalField(index); + } + + inline void SetInternalFieldPointer( + v8::Local object + , int index + , void* value) { + object->SetPointerInInternalField(index, value); + } + +# define NAN_GC_CALLBACK(name) \ + void name(v8::GCType type, v8::GCCallbackFlags flags) + + inline void AddGCEpilogueCallback( + v8::GCEpilogueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::V8::AddGCEpilogueCallback(callback, gc_type_filter); + } + inline void RemoveGCEpilogueCallback( + v8::GCEpilogueCallback callback) { + v8::V8::RemoveGCEpilogueCallback(callback); + } + inline void AddGCPrologueCallback( + v8::GCPrologueCallback callback + , v8::GCType gc_type_filter = v8::kGCTypeAll) { + v8::V8::AddGCPrologueCallback(callback, gc_type_filter); + } + inline void RemoveGCPrologueCallback( + v8::GCPrologueCallback callback) { + v8::V8::RemoveGCPrologueCallback(callback); + } + inline void GetHeapStatistics( + v8::HeapStatistics *heap_statistics) { + v8::V8::GetHeapStatistics(heap_statistics); + } + +# define X(NAME) \ + inline v8::Local NAME(const char *msg) { \ + EscapableHandleScope scope; \ + return scope.Escape(v8::Exception::NAME(New(msg).ToLocalChecked())); \ + } \ + \ + inline \ + v8::Local NAME(v8::Local msg) { \ + return v8::Exception::NAME(msg); \ + } \ + \ + inline void Throw ## NAME(const char *msg) { \ + HandleScope scope; \ + v8::ThrowException(v8::Exception::NAME(New(msg).ToLocalChecked())); \ + } \ + \ + inline \ + void Throw ## NAME(v8::Local errmsg) { \ + HandleScope scope; \ + v8::ThrowException(v8::Exception::NAME(errmsg)); \ + } + + X(Error) + X(RangeError) + X(ReferenceError) + X(SyntaxError) + X(TypeError) + +# undef X + + inline void ThrowError(v8::Local error) { + v8::ThrowException(error); + } + + inline MaybeLocal NewBuffer( + char *data + , size_t length + , node::Buffer::free_callback callback + , void *hint + ) { + EscapableHandleScope scope; + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(length <= imp::kMaxLength && "too large buffer"); + return scope.Escape( + New(node::Buffer::New(data, length, callback, hint)->handle_)); + } + + inline MaybeLocal CopyBuffer( + const char *data + , uint32_t size + ) { + EscapableHandleScope scope; + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(size <= imp::kMaxLength && "too large buffer"); +#if NODE_MODULE_VERSION >= NODE_0_10_MODULE_VERSION + return scope.Escape(New(node::Buffer::New(data, size)->handle_)); +#else + return scope.Escape( + New(node::Buffer::New(const_cast(data), size)->handle_)); +#endif + } + + inline MaybeLocal NewBuffer(uint32_t size) { + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + EscapableHandleScope scope; + assert(size <= imp::kMaxLength && "too large buffer"); + return scope.Escape(New(node::Buffer::New(size)->handle_)); + } + + inline void FreeData(char *data, void *hint) { + (void) hint; // unused + delete[] data; + } + + inline MaybeLocal NewBuffer( + char* data + , uint32_t size + ) { + EscapableHandleScope scope; + // arbitrary buffer lengths requires + // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION + assert(size <= imp::kMaxLength && "too large buffer"); + return scope.Escape( + New(node::Buffer::New(data, size, FreeData, NULL)->handle_)); + } + +namespace imp { +inline void +widenString(std::vector *ws, const uint8_t *s, int l) { + size_t len = static_cast(l); + if (l < 0) { + len = strlen(reinterpret_cast(s)); + } + assert(len <= INT_MAX && "string too long"); + ws->resize(len); + std::copy(s, s + len, ws->begin()); // NOLINT(build/include_what_you_use) +} +} // end of namespace imp + + inline MaybeLocal + NewOneByteString(const uint8_t * value, int length = -1) { + std::vector wideString; // NOLINT(build/include_what_you_use) + imp::widenString(&wideString, value, length); + return v8::String::New(wideString.data(), + static_cast(wideString.size())); + } + + inline MaybeLocal CompileScript( + v8::Local s + , const v8::ScriptOrigin& origin + ) { + return v8::Script::Compile(s, const_cast(&origin)); + } + + inline MaybeLocal CompileScript( + v8::Local s + ) { + return v8::Script::Compile(s); + } + + inline + MaybeLocal RunScript(v8::Local script) { + return script->Run(); + } + + inline v8::Local MakeCallback( + v8::Local target + , v8::Local func + , int argc + , v8::Local* argv) { + v8::HandleScope scope; + return scope.Close(New(node::MakeCallback(target, func, argc, argv))); + } + + inline v8::Local MakeCallback( + v8::Local target + , v8::Local symbol + , int argc + , v8::Local* argv) { + v8::HandleScope scope; + return scope.Close(New(node::MakeCallback(target, symbol, argc, argv))); + } + + inline v8::Local MakeCallback( + v8::Local target + , const char* method + , int argc + , v8::Local* argv) { + v8::HandleScope scope; + return scope.Close(New(node::MakeCallback(target, method, argc, argv))); + } + + inline void FatalException(const TryCatch& try_catch) { + node::FatalException(const_cast(try_catch.try_catch_)); + } + + inline v8::Local ErrnoException( + int errorno + , const char* syscall = NULL + , const char* message = NULL + , const char* path = NULL) { + return node::ErrnoException(errorno, syscall, message, path); + } + + NAN_DEPRECATED inline v8::Local NanErrnoException( + int errorno + , const char* syscall = NULL + , const char* message = NULL + , const char* path = NULL) { + return ErrnoException(errorno, syscall, message, path); + } + + + template + inline void SetIsolateData( + v8::Isolate *isolate + , T *data + ) { + isolate->SetData(data); + } + + template + inline T *GetIsolateData( + v8::Isolate *isolate + ) { + return static_cast(isolate->GetData()); + } + +class Utf8String { + public: + inline explicit Utf8String(v8::Local from) : + length_(0), str_(str_st_) { + v8::HandleScope scope; + if (!from.IsEmpty()) { + v8::Local string = from->ToString(); + if (!string.IsEmpty()) { + size_t len = 3 * string->Length() + 1; + assert(len <= INT_MAX); + if (len > sizeof (str_st_)) { + str_ = static_cast(malloc(len)); + assert(str_ != 0); + } + const int flags = + v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8; + length_ = string->WriteUtf8(str_, static_cast(len), 0, flags); + str_[length_] = '\0'; + } + } + } + + inline int length() const { + return length_; + } + + inline char* operator*() { return str_; } + inline const char* operator*() const { return str_; } + + inline ~Utf8String() { + if (str_ != str_st_) { + free(str_); + } + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(Utf8String) + + int length_; + char *str_; + char str_st_[1024]; +}; + +#endif // NODE_MODULE_VERSION + +typedef void (*FreeCallback)(char *data, void *hint); + +typedef const FunctionCallbackInfo& NAN_METHOD_ARGS_TYPE; +typedef void NAN_METHOD_RETURN_TYPE; + +typedef const PropertyCallbackInfo& NAN_GETTER_ARGS_TYPE; +typedef void NAN_GETTER_RETURN_TYPE; + +typedef const PropertyCallbackInfo& NAN_SETTER_ARGS_TYPE; +typedef void NAN_SETTER_RETURN_TYPE; + +typedef const PropertyCallbackInfo& + NAN_PROPERTY_GETTER_ARGS_TYPE; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_PROPERTY_GETTER_RETURN_TYPE; +#else +typedef void NAN_PROPERTY_GETTER_RETURN_TYPE; +#endif + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef const PropertyCallbackInfo& + NAN_PROPERTY_SETTER_ARGS_TYPE; +typedef v8::Intercepted NAN_PROPERTY_SETTER_RETURN_TYPE; +#else +typedef const PropertyCallbackInfo& + NAN_PROPERTY_SETTER_ARGS_TYPE; +typedef void NAN_PROPERTY_SETTER_RETURN_TYPE; +#endif + +typedef const PropertyCallbackInfo& + NAN_PROPERTY_ENUMERATOR_ARGS_TYPE; +typedef void NAN_PROPERTY_ENUMERATOR_RETURN_TYPE; + +typedef const PropertyCallbackInfo& + NAN_PROPERTY_DELETER_ARGS_TYPE; + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_PROPERTY_DELETER_RETURN_TYPE; +#else +typedef void NAN_PROPERTY_DELETER_RETURN_TYPE; +#endif + + +typedef const PropertyCallbackInfo& + NAN_PROPERTY_QUERY_ARGS_TYPE; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_PROPERTY_QUERY_RETURN_TYPE; +#else +typedef void NAN_PROPERTY_QUERY_RETURN_TYPE; +#endif + +typedef const PropertyCallbackInfo& NAN_INDEX_GETTER_ARGS_TYPE; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_INDEX_GETTER_RETURN_TYPE; +#else +typedef void NAN_INDEX_GETTER_RETURN_TYPE; +#endif + + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef const PropertyCallbackInfo& NAN_INDEX_SETTER_ARGS_TYPE; +typedef v8::Intercepted NAN_INDEX_SETTER_RETURN_TYPE; +#else +typedef const PropertyCallbackInfo& NAN_INDEX_SETTER_ARGS_TYPE; +typedef void NAN_INDEX_SETTER_RETURN_TYPE; +#endif + +typedef const PropertyCallbackInfo& + NAN_INDEX_ENUMERATOR_ARGS_TYPE; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_INDEX_ENUMERATOR_RETURN_TYPE; +#else +typedef void NAN_INDEX_ENUMERATOR_RETURN_TYPE; +#endif + +typedef const PropertyCallbackInfo& + NAN_INDEX_DELETER_ARGS_TYPE; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_INDEX_DELETER_RETURN_TYPE; +#else +typedef void NAN_INDEX_DELETER_RETURN_TYPE; +#endif + +typedef const PropertyCallbackInfo& + NAN_INDEX_QUERY_ARGS_TYPE; +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted NAN_INDEX_QUERY_RETURN_TYPE; +#else +typedef void NAN_INDEX_QUERY_RETURN_TYPE; +#endif + +#define NAN_METHOD(name) \ + Nan::NAN_METHOD_RETURN_TYPE name(Nan::NAN_METHOD_ARGS_TYPE info) +#define NAN_GETTER(name) \ + Nan::NAN_GETTER_RETURN_TYPE name( \ + v8::Local property \ + , Nan::NAN_GETTER_ARGS_TYPE info) +#define NAN_SETTER(name) \ + Nan::NAN_SETTER_RETURN_TYPE name( \ + v8::Local property \ + , v8::Local value \ + , Nan::NAN_SETTER_ARGS_TYPE info) +#define NAN_PROPERTY_GETTER(name) \ + Nan::NAN_PROPERTY_GETTER_RETURN_TYPE name( \ + v8::Local property \ + , Nan::NAN_PROPERTY_GETTER_ARGS_TYPE info) +#define NAN_PROPERTY_SETTER(name) \ + Nan::NAN_PROPERTY_SETTER_RETURN_TYPE name( \ + v8::Local property \ + , v8::Local value \ + , Nan::NAN_PROPERTY_SETTER_ARGS_TYPE info) +#define NAN_PROPERTY_ENUMERATOR(name) \ + Nan::NAN_PROPERTY_ENUMERATOR_RETURN_TYPE name( \ + Nan::NAN_PROPERTY_ENUMERATOR_ARGS_TYPE info) +#define NAN_PROPERTY_DELETER(name) \ + Nan::NAN_PROPERTY_DELETER_RETURN_TYPE name( \ + v8::Local property \ + , Nan::NAN_PROPERTY_DELETER_ARGS_TYPE info) +#define NAN_PROPERTY_QUERY(name) \ + Nan::NAN_PROPERTY_QUERY_RETURN_TYPE name( \ + v8::Local property \ + , Nan::NAN_PROPERTY_QUERY_ARGS_TYPE info) +# define NAN_INDEX_GETTER(name) \ + Nan::NAN_INDEX_GETTER_RETURN_TYPE name( \ + uint32_t index \ + , Nan::NAN_INDEX_GETTER_ARGS_TYPE info) +#define NAN_INDEX_SETTER(name) \ + Nan::NAN_INDEX_SETTER_RETURN_TYPE name( \ + uint32_t index \ + , v8::Local value \ + , Nan::NAN_INDEX_SETTER_ARGS_TYPE info) +#define NAN_INDEX_ENUMERATOR(name) \ + Nan::NAN_INDEX_ENUMERATOR_RETURN_TYPE \ + name(Nan::NAN_INDEX_ENUMERATOR_ARGS_TYPE info) +#define NAN_INDEX_DELETER(name) \ + Nan::NAN_INDEX_DELETER_RETURN_TYPE name( \ + uint32_t index \ + , Nan::NAN_INDEX_DELETER_ARGS_TYPE info) +#define NAN_INDEX_QUERY(name) \ + Nan::NAN_INDEX_QUERY_RETURN_TYPE name( \ + uint32_t index \ + , Nan::NAN_INDEX_QUERY_ARGS_TYPE info) + +class Callback { + public: + Callback() {} + + explicit Callback(const v8::Local &fn) : handle_(fn) {} + + ~Callback() { + handle_.Reset(); + } + + bool operator==(const Callback &other) const { + return handle_ == other.handle_; + } + + bool operator!=(const Callback &other) const { + return !operator==(other); + } + + inline + v8::Local operator*() const { return GetFunction(); } + + NAN_DEPRECATED inline v8::Local operator()( + v8::Local target + , int argc = 0 + , v8::Local argv[] = 0) const { +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource async("nan:Callback:operator()"); + return Call_(isolate, target, argc, argv, &async) + .FromMaybe(v8::Local()); +# else + return Call_(isolate, target, argc, argv); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#else + return Call_(target, argc, argv); +#endif // NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + } + + NAN_DEPRECATED inline v8::Local operator()( + int argc = 0 + , v8::Local argv[] = 0) const { +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource async("nan:Callback:operator()"); + return scope.Escape(Call_(isolate, isolate->GetCurrentContext()->Global(), + argc, argv, &async) + .FromMaybe(v8::Local())); +# else + return scope.Escape( + Call_(isolate, isolate->GetCurrentContext()->Global(), argc, argv)); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#else + v8::HandleScope scope; + return scope.Close(Call_(v8::Context::GetCurrent()->Global(), argc, argv)); +#endif // NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + } + + inline MaybeLocal operator()( + AsyncResource* resource + , int argc = 0 + , v8::Local argv[] = 0) const { + return this->Call(argc, argv, resource); + } + + inline MaybeLocal operator()( + AsyncResource* resource + , v8::Local target + , int argc = 0 + , v8::Local argv[] = 0) const { + return this->Call(target, argc, argv, resource); + } + + // TODO(kkoopa): remove + inline void SetFunction(const v8::Local &fn) { + Reset(fn); + } + + inline void Reset(const v8::Local &fn) { + handle_.Reset(fn); + } + + inline void Reset() { + handle_.Reset(); + } + + inline v8::Local GetFunction() const { + return New(handle_); + } + + inline bool IsEmpty() const { + return handle_.IsEmpty(); + } + + // Deprecated: For async callbacks Use the versions that accept an + // AsyncResource. If this callback does not correspond to an async resource, + // that is, it is a synchronous function call on a non-empty JS stack, you + // should Nan::Call instead. + NAN_DEPRECATED inline v8::Local + Call(v8::Local target + , int argc + , v8::Local argv[]) const { +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource async("nan:Callback:Call"); + return Call_(isolate, target, argc, argv, &async) + .FromMaybe(v8::Local()); +# else + return Call_(isolate, target, argc, argv); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#else + return Call_(target, argc, argv); +#endif + } + + // Deprecated: For async callbacks Use the versions that accept an + // AsyncResource. If this callback does not correspond to an async resource, + // that is, it is a synchronous function call on a non-empty JS stack, you + // should Nan::Call instead. + NAN_DEPRECATED inline v8::Local + Call(int argc, v8::Local argv[]) const { +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); +# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + AsyncResource async("nan:Callback:Call"); + return scope.Escape(Call_(isolate, isolate->GetCurrentContext()->Global(), + argc, argv, &async) + .FromMaybe(v8::Local())); +# else + return scope.Escape( + Call_(isolate, isolate->GetCurrentContext()->Global(), argc, argv)); +# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION +#else + v8::HandleScope scope; + return scope.Close(Call_(v8::Context::GetCurrent()->Global(), argc, argv)); +#endif + } + + inline MaybeLocal + Call(v8::Local target + , int argc + , v8::Local argv[] + , AsyncResource* resource) const { +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + return Call_(isolate, target, argc, argv, resource); +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + return Call_(isolate, target, argc, argv); +#else + return Call_(target, argc, argv); +#endif + } + + inline MaybeLocal + Call(int argc, v8::Local argv[], AsyncResource* resource) const { +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + return Call(isolate->GetCurrentContext()->Global(), argc, argv, resource); +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape( + Call_(isolate, isolate->GetCurrentContext()->Global(), argc, argv)); +#else + v8::HandleScope scope; + return scope.Close(Call_(v8::Context::GetCurrent()->Global(), argc, argv)); +#endif + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(Callback) + Persistent handle_; + +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + MaybeLocal Call_(v8::Isolate *isolate + , v8::Local target + , int argc + , v8::Local argv[] + , AsyncResource* resource) const { + EscapableHandleScope scope; + v8::Local func = New(handle_); + auto maybe = resource->runInAsyncScope(target, func, argc, argv); + v8::Local local; + if (!maybe.ToLocal(&local)) return MaybeLocal(); + return scope.Escape(local); + } +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Local Call_(v8::Isolate *isolate + , v8::Local target + , int argc + , v8::Local argv[]) const { + EscapableHandleScope scope; + + v8::Local callback = New(handle_); +# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION + return scope.Escape(New(node::MakeCallback( + isolate + , target + , callback + , argc + , argv + ))); +# else + return scope.Escape(node::MakeCallback( + isolate + , target + , callback + , argc + , argv + )); +# endif + } +#else + v8::Local Call_(v8::Local target + , int argc + , v8::Local argv[]) const { + EscapableHandleScope scope; + + v8::Local callback = New(handle_); + return scope.Escape(New(node::MakeCallback( + target + , callback + , argc + , argv + ))); + } +#endif +}; + +inline MaybeLocal Call( + const Nan::Callback& callback + , v8::Local recv + , int argc + , v8::Local argv[]) { + return Call(*callback, recv, argc, argv); +} + +inline MaybeLocal Call( + const Nan::Callback& callback + , int argc + , v8::Local argv[]) { +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape( + Call(*callback, isolate->GetCurrentContext()->Global(), argc, argv) + .FromMaybe(v8::Local())); +#else + EscapableHandleScope scope; + return scope.Escape( + Call(*callback, v8::Context::GetCurrent()->Global(), argc, argv) + .FromMaybe(v8::Local())); +#endif +} + +inline MaybeLocal Call( + v8::Local symbol + , v8::Local recv + , int argc + , v8::Local argv[]) { + EscapableHandleScope scope; + v8::Local fn_v = + Get(recv, symbol).FromMaybe(v8::Local()); + if (fn_v.IsEmpty() || !fn_v->IsFunction()) return v8::Local(); + v8::Local fn = fn_v.As(); + return scope.Escape( + Call(fn, recv, argc, argv).FromMaybe(v8::Local())); +} + +inline MaybeLocal Call( + const char* method + , v8::Local recv + , int argc + , v8::Local argv[]) { + EscapableHandleScope scope; + v8::Local method_string = + New(method).ToLocalChecked(); + return scope.Escape( + Call(method_string, recv, argc, argv).FromMaybe(v8::Local())); +} + +/* abstract */ class AsyncWorker { + public: + explicit AsyncWorker(Callback *callback_, + const char* resource_name = "nan:AsyncWorker") + : callback(callback_), errmsg_(NULL) { + request.data = this; + + HandleScope scope; + v8::Local obj = New(); + persistentHandle.Reset(obj); + async_resource = new AsyncResource(resource_name, obj); + } + + virtual ~AsyncWorker() { + HandleScope scope; + + if (!persistentHandle.IsEmpty()) + persistentHandle.Reset(); + delete callback; + delete[] errmsg_; + delete async_resource; + } + + virtual void WorkComplete() { + HandleScope scope; + + if (errmsg_ == NULL) + HandleOKCallback(); + else + HandleErrorCallback(); + delete callback; + callback = NULL; + } + + inline void SaveToPersistent( + const char *key, const v8::Local &value) { + HandleScope scope; + Set(New(persistentHandle), New(key).ToLocalChecked(), value).FromJust(); + } + + inline void SaveToPersistent( + const v8::Local &key, const v8::Local &value) { + HandleScope scope; + Set(New(persistentHandle), key, value).FromJust(); + } + + inline void SaveToPersistent( + uint32_t index, const v8::Local &value) { + HandleScope scope; + Set(New(persistentHandle), index, value).FromJust(); + } + + inline v8::Local GetFromPersistent(const char *key) const { + EscapableHandleScope scope; + return scope.Escape( + Get(New(persistentHandle), New(key).ToLocalChecked()) + .FromMaybe(v8::Local())); + } + + inline v8::Local + GetFromPersistent(const v8::Local &key) const { + EscapableHandleScope scope; + return scope.Escape( + Get(New(persistentHandle), key) + .FromMaybe(v8::Local())); + } + + inline v8::Local GetFromPersistent(uint32_t index) const { + EscapableHandleScope scope; + return scope.Escape( + Get(New(persistentHandle), index) + .FromMaybe(v8::Local())); + } + + virtual void Execute() = 0; + + uv_work_t request; + + virtual void Destroy() { + delete this; + } + + protected: + Persistent persistentHandle; + Callback *callback; + AsyncResource *async_resource; + + virtual void HandleOKCallback() { + HandleScope scope; + + callback->Call(0, NULL, async_resource); + } + + virtual void HandleErrorCallback() { + HandleScope scope; + + v8::Local argv[] = { + v8::Exception::Error(New(ErrorMessage()).ToLocalChecked()) + }; + callback->Call(1, argv, async_resource); + } + + void SetErrorMessage(const char *msg) { + delete[] errmsg_; + + size_t size = strlen(msg) + 1; + errmsg_ = new char[size]; + memcpy(errmsg_, msg, size); + } + + const char* ErrorMessage() const { + return errmsg_; + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(AsyncWorker) + char *errmsg_; +}; + +/* abstract */ class AsyncBareProgressWorkerBase : public AsyncWorker { + public: + explicit AsyncBareProgressWorkerBase( + Callback *callback_, + const char* resource_name = "nan:AsyncBareProgressWorkerBase") + : AsyncWorker(callback_, resource_name) { + uv_async_init( + GetCurrentEventLoop() + , &async + , AsyncProgress_ + ); + async.data = this; + } + + virtual ~AsyncBareProgressWorkerBase() { + } + + virtual void WorkProgress() = 0; + + virtual void Destroy() { + uv_close(reinterpret_cast(&async), AsyncClose_); + } + + private: + inline static NAUV_WORK_CB(AsyncProgress_) { + AsyncBareProgressWorkerBase *worker = + static_cast(async->data); + worker->WorkProgress(); + } + + inline static void AsyncClose_(uv_handle_t* handle) { + AsyncBareProgressWorkerBase *worker = + static_cast(handle->data); + delete worker; + } + + protected: + uv_async_t async; +}; + +template +/* abstract */ +class AsyncBareProgressWorker : public AsyncBareProgressWorkerBase { + public: + explicit AsyncBareProgressWorker( + Callback *callback_, + const char* resource_name = "nan:AsyncBareProgressWorker") + : AsyncBareProgressWorkerBase(callback_, resource_name) { + uv_mutex_init(&async_lock); + } + + virtual ~AsyncBareProgressWorker() { + uv_mutex_destroy(&async_lock); + } + + class ExecutionProgress { + friend class AsyncBareProgressWorker; + public: + void Signal() const { + uv_mutex_lock(&that_->async_lock); + uv_async_send(&that_->async); + uv_mutex_unlock(&that_->async_lock); + } + + void Send(const T* data, size_t count) const { + that_->SendProgress_(data, count); + } + + private: + explicit ExecutionProgress(AsyncBareProgressWorker *that) : that_(that) {} + NAN_DISALLOW_ASSIGN_COPY_MOVE(ExecutionProgress) + AsyncBareProgressWorker* const that_; + }; + + virtual void Execute(const ExecutionProgress& progress) = 0; + virtual void HandleProgressCallback(const T *data, size_t size) = 0; + + protected: + uv_mutex_t async_lock; + + private: + void Execute() /*final override*/ { + ExecutionProgress progress(this); + Execute(progress); + } + + virtual void SendProgress_(const T *data, size_t count) = 0; +}; + +template +/* abstract */ +class AsyncProgressWorkerBase : public AsyncBareProgressWorker { + public: + explicit AsyncProgressWorkerBase( + Callback *callback_, + const char* resource_name = "nan:AsyncProgressWorkerBase") + : AsyncBareProgressWorker(callback_, resource_name), asyncdata_(NULL), + asyncsize_(0) { + } + + virtual ~AsyncProgressWorkerBase() { + delete[] asyncdata_; + } + + void WorkProgress() { + uv_mutex_lock(&this->async_lock); + T *data = asyncdata_; + size_t size = asyncsize_; + asyncdata_ = NULL; + asyncsize_ = 0; + uv_mutex_unlock(&this->async_lock); + + // Don't send progress events after we've already completed. + if (this->callback) { + this->HandleProgressCallback(data, size); + } + delete[] data; + } + + private: + void SendProgress_(const T *data, size_t count) { + T *new_data = new T[count]; + std::copy(data, data + count, new_data); + + uv_mutex_lock(&this->async_lock); + T *old_data = asyncdata_; + asyncdata_ = new_data; + asyncsize_ = count; + uv_async_send(&this->async); + uv_mutex_unlock(&this->async_lock); + + delete[] old_data; + } + + T *asyncdata_; + size_t asyncsize_; +}; + +// This ensures compatibility to the previous un-templated AsyncProgressWorker +// class definition. +typedef AsyncProgressWorkerBase AsyncProgressWorker; + +template +/* abstract */ +class AsyncBareProgressQueueWorker : public AsyncBareProgressWorkerBase { + public: + explicit AsyncBareProgressQueueWorker( + Callback *callback_, + const char* resource_name = "nan:AsyncBareProgressQueueWorker") + : AsyncBareProgressWorkerBase(callback_, resource_name) { + } + + virtual ~AsyncBareProgressQueueWorker() { + } + + class ExecutionProgress { + friend class AsyncBareProgressQueueWorker; + public: + void Send(const T* data, size_t count) const { + that_->SendProgress_(data, count); + } + + private: + explicit ExecutionProgress(AsyncBareProgressQueueWorker *that) + : that_(that) {} + NAN_DISALLOW_ASSIGN_COPY_MOVE(ExecutionProgress) + AsyncBareProgressQueueWorker* const that_; + }; + + virtual void Execute(const ExecutionProgress& progress) = 0; + virtual void HandleProgressCallback(const T *data, size_t size) = 0; + + private: + void Execute() /*final override*/ { + ExecutionProgress progress(this); + Execute(progress); + } + + virtual void SendProgress_(const T *data, size_t count) = 0; +}; + +template +/* abstract */ +class AsyncProgressQueueWorker : public AsyncBareProgressQueueWorker { + public: + explicit AsyncProgressQueueWorker( + Callback *callback_, + const char* resource_name = "nan:AsyncProgressQueueWorker") + : AsyncBareProgressQueueWorker(callback_) { + uv_mutex_init(&async_lock); + } + + virtual ~AsyncProgressQueueWorker() { + uv_mutex_lock(&async_lock); + + while (!asyncdata_.empty()) { + std::pair &datapair = asyncdata_.front(); + T *data = datapair.first; + + asyncdata_.pop(); + + delete[] data; + } + + uv_mutex_unlock(&async_lock); + uv_mutex_destroy(&async_lock); + } + + void WorkComplete() { + WorkProgress(); + AsyncWorker::WorkComplete(); + } + + void WorkProgress() { + uv_mutex_lock(&async_lock); + + while (!asyncdata_.empty()) { + std::pair &datapair = asyncdata_.front(); + + T *data = datapair.first; + size_t size = datapair.second; + + asyncdata_.pop(); + uv_mutex_unlock(&async_lock); + + // Don't send progress events after we've already completed. + if (this->callback) { + this->HandleProgressCallback(data, size); + } + + delete[] data; + + uv_mutex_lock(&async_lock); + } + + uv_mutex_unlock(&async_lock); + } + + private: + void SendProgress_(const T *data, size_t count) { + T *new_data = new T[count]; + std::copy(data, data + count, new_data); + + uv_mutex_lock(&async_lock); + asyncdata_.push(std::pair(new_data, count)); + uv_mutex_unlock(&async_lock); + + uv_async_send(&this->async); + } + + uv_mutex_t async_lock; + std::queue > asyncdata_; +}; + +inline void AsyncExecute (uv_work_t* req) { + AsyncWorker *worker = static_cast(req->data); + worker->Execute(); +} + +/* uv_after_work_cb has 1 argument before node-v0.9.4 and + * 2 arguments since node-v0.9.4 + * https://github.com/libuv/libuv/commit/92fb84b751e18f032c02609467f44bfe927b80c5 + */ +inline void AsyncExecuteComplete(uv_work_t *req) { + AsyncWorker* worker = static_cast(req->data); + worker->WorkComplete(); + worker->Destroy(); +} +inline void AsyncExecuteComplete (uv_work_t* req, int status) { + AsyncExecuteComplete(req); +} + +inline void AsyncQueueWorker (AsyncWorker* worker) { + uv_queue_work( + GetCurrentEventLoop() + , &worker->request + , AsyncExecute + , AsyncExecuteComplete + ); +} + +namespace imp { + +inline +ExternalOneByteStringResource const* +GetExternalResource(v8::Local str) { +#if NODE_MODULE_VERSION < ATOM_0_21_MODULE_VERSION + return str->GetExternalAsciiStringResource(); +#else + return str->GetExternalOneByteStringResource(); +#endif +} + +inline +bool +IsExternal(v8::Local str) { +#if NODE_MODULE_VERSION < ATOM_0_21_MODULE_VERSION + return str->IsExternalAscii(); +#else + return str->IsExternalOneByte(); +#endif +} + +} // end of namespace imp + +enum Encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER}; + +#if NODE_MODULE_VERSION < NODE_0_10_MODULE_VERSION +# include "nan_string_bytes.h" // NOLINT(build/include) +#endif + +#if NODE_MAJOR_VERSION >= 24 +inline MaybeLocal TryEncode( + const void *buf, size_t len, enum Encoding encoding = BINARY) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + node::encoding node_enc = static_cast(encoding); + + if (encoding == UCS2) { + return node::TryEncode( + isolate + , reinterpret_cast(buf) + , len / 2); + } else { + return node::TryEncode( + isolate + , reinterpret_cast(buf) + , len + , node_enc); + } +} + +inline v8::Local Encode( + const void *buf, size_t len, enum Encoding encoding = BINARY) { + return TryEncode(buf, len, encoding).ToLocalChecked(); +} + +#else + +inline v8::Local Encode( + const void *buf, size_t len, enum Encoding encoding = BINARY) { +#if (NODE_MODULE_VERSION >= ATOM_0_21_MODULE_VERSION) + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + node::encoding node_enc = static_cast(encoding); + + if (encoding == UCS2) { + return node::Encode( + isolate + , reinterpret_cast(buf) + , len / 2); + } else { + return node::Encode( + isolate + , reinterpret_cast(buf) + , len + , node_enc); + } +#elif (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) + return node::Encode( + v8::Isolate::GetCurrent() + , buf, len + , static_cast(encoding)); +#else +# if NODE_MODULE_VERSION >= NODE_0_10_MODULE_VERSION + return node::Encode(buf, len, static_cast(encoding)); +# else + return imp::Encode(reinterpret_cast(buf), len, encoding); +# endif +#endif +} +#endif + +inline ssize_t DecodeBytes( + v8::Local val, enum Encoding encoding = BINARY) { +#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) + return node::DecodeBytes( + v8::Isolate::GetCurrent() + , val + , static_cast(encoding)); +#else +# if (NODE_MODULE_VERSION < NODE_0_10_MODULE_VERSION) + if (encoding == BUFFER) { + return node::DecodeBytes(val, node::BINARY); + } +# endif + return node::DecodeBytes(val, static_cast(encoding)); +#endif +} + +inline ssize_t DecodeWrite( + char *buf + , size_t len + , v8::Local val + , enum Encoding encoding = BINARY) { +#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) + return node::DecodeWrite( + v8::Isolate::GetCurrent() + , buf + , len + , val + , static_cast(encoding)); +#else +# if (NODE_MODULE_VERSION < NODE_0_10_MODULE_VERSION) + if (encoding == BUFFER) { + return node::DecodeWrite(buf, len, val, node::BINARY); + } +# endif + return node::DecodeWrite( + buf + , len + , val + , static_cast(encoding)); +#endif +} + +inline void SetPrototypeTemplate( + v8::Local templ + , const char *name + , v8::Local value +) { + HandleScope scope; + SetTemplate(templ->PrototypeTemplate(), name, value); +} + +inline void SetPrototypeTemplate( + v8::Local templ + , v8::Local name + , v8::Local value + , v8::PropertyAttribute attributes +) { + HandleScope scope; + SetTemplate(templ->PrototypeTemplate(), name, value, attributes); +} + +inline void SetInstanceTemplate( + v8::Local templ + , const char *name + , v8::Local value +) { + HandleScope scope; + SetTemplate(templ->InstanceTemplate(), name, value); +} + +inline void SetInstanceTemplate( + v8::Local templ + , v8::Local name + , v8::Local value + , v8::PropertyAttribute attributes +) { + HandleScope scope; + SetTemplate(templ->InstanceTemplate(), name, value, attributes); +} + +namespace imp { + +// Note(@agnat): Helper to distinguish different receiver types. The first +// version deals with receivers derived from v8::Template. The second version +// handles everything else. The final argument only serves as discriminator and +// is unused. +template +inline +void +SetMethodAux(T recv, + v8::Local name, + v8::Local tpl, + v8::Template *) { + recv->Set(name, tpl); +} + +template +inline +void +SetMethodAux(T recv, + v8::Local name, + v8::Local tpl, + ...) { + Set(recv, name, GetFunction(tpl).ToLocalChecked()); +} + +} // end of namespace imp + +template class HandleType> +inline void SetMethod( + HandleType recv + , const char *name + , FunctionCallback callback + , v8::Local data = v8::Local()) { + HandleScope scope; + v8::Local t = New(callback, data); + v8::Local fn_name = New(name).ToLocalChecked(); + t->SetClassName(fn_name); + // Note(@agnat): Pass an empty T* as discriminator. See note on + // SetMethodAux(...) above + imp::SetMethodAux(recv, fn_name, t, static_cast(0)); +} + +inline void SetPrototypeMethod( + v8::Local recv + , const char* name + , FunctionCallback callback + , v8::Local data = v8::Local()) { + HandleScope scope; + v8::Local t = New( + callback + , data + , New(recv)); + v8::Local fn_name = New(name).ToLocalChecked(); + recv->PrototypeTemplate()->Set(fn_name, t); + t->SetClassName(fn_name); +} + +//=== Accessors and Such ======================================================= +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 14 \ + || (V8_MAJOR_VERSION == 14 && defined(V8_MINOR_VERSION) \ + && V8_MINOR_VERSION >= 2)) + +enum AccessControl {DEFAULT = 0}; + +inline void SetAccessor( + v8::Local tpl + , v8::Local name + , GetterCallback getter + , SetterCallback setter = 0 + , v8::Local data = v8::Local() + , enum AccessControl settings = DEFAULT + , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + + imp::NativeGetter getter_ = + imp::GetterCallbackWrapper; + imp::NativeSetter setter_ = + setter ? imp::SetterCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kAccessorFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kGetterIndex + , New(reinterpret_cast(getter))); + + if (setter != 0) { + obj->SetInternalField( + imp::kSetterIndex + , New(reinterpret_cast(setter))); + } + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + + tpl->SetNativeDataProperty( + name + , getter_ + , setter_ + , obj + , attribute + ); +} + +inline bool SetAccessor( + v8::Local obj + , v8::Local name + , GetterCallback getter + , SetterCallback setter = 0 + , v8::Local data = v8::Local() + , enum AccessControl settings = DEFAULT + , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + + imp::NativeGetter getter_ = + imp::GetterCallbackWrapper; + imp::NativeSetter setter_ = + setter ? imp::SetterCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kAccessorFieldCount); + v8::Local dataobj = NewInstance(otpl).ToLocalChecked(); + + dataobj->SetInternalField( + imp::kGetterIndex + , New(reinterpret_cast(getter))); + + if (!data.IsEmpty()) { + dataobj->SetInternalField(imp::kDataIndex, data); + } + + if (setter) { + dataobj->SetInternalField( + imp::kSetterIndex + , New(reinterpret_cast(setter))); + } + return obj->SetNativeDataProperty( + GetCurrentContext() + , name + , getter_ + , setter_ + , dataobj + , attribute).FromMaybe(false); +} + +#else + +NAN_DEPRECATED inline void SetAccessor( + v8::Local tpl + , v8::Local name + , GetterCallback getter + , SetterCallback setter + , v8::Local data + , v8::AccessControl settings + , v8::PropertyAttribute attribute + , imp::Sig signature) { + HandleScope scope; + + imp::NativeGetter getter_ = + imp::GetterCallbackWrapper; + imp::NativeSetter setter_ = + setter ? imp::SetterCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kAccessorFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kGetterIndex + , New(reinterpret_cast(getter))); + + if (setter != 0) { + obj->SetInternalField( + imp::kSetterIndex + , New(reinterpret_cast(setter))); + } + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 \ + || (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) \ + && V8_MINOR_VERSION >= 5)) + tpl->SetNativeDataProperty( +#else + tpl->SetAccessor( +#endif + name + , getter_ + , setter_ + , obj +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION < 12 \ + || (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) \ + && V8_MINOR_VERSION == 0)) + , settings +#endif + , attribute +#if (NODE_MODULE_VERSION < NODE_16_0_MODULE_VERSION) + , signature +#endif + ); +} + +inline void SetAccessor( + v8::Local tpl + , v8::Local name + , GetterCallback getter + , SetterCallback setter = 0 + , v8::Local data = v8::Local() + , v8::AccessControl settings = v8::DEFAULT + , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + + imp::NativeGetter getter_ = + imp::GetterCallbackWrapper; + imp::NativeSetter setter_ = + setter ? imp::SetterCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kAccessorFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kGetterIndex + , New(reinterpret_cast(getter))); + + if (setter != 0) { + obj->SetInternalField( + imp::kSetterIndex + , New(reinterpret_cast(setter))); + } + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 \ + || (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) \ + && V8_MINOR_VERSION >= 5)) + tpl->SetNativeDataProperty( +#else + tpl->SetAccessor( +#endif + name + , getter_ + , setter_ + , obj +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION < 12 \ + || (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) \ + && V8_MINOR_VERSION == 0)) + , settings +#endif + , attribute + ); +} + +inline bool SetAccessor( + v8::Local obj + , v8::Local name + , GetterCallback getter + , SetterCallback setter = 0 + , v8::Local data = v8::Local() + , v8::AccessControl settings = v8::DEFAULT + , v8::PropertyAttribute attribute = v8::None) { + HandleScope scope; + + imp::NativeGetter getter_ = + imp::GetterCallbackWrapper; + imp::NativeSetter setter_ = + setter ? imp::SetterCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kAccessorFieldCount); + v8::Local dataobj = NewInstance(otpl).ToLocalChecked(); + + dataobj->SetInternalField( + imp::kGetterIndex + , New(reinterpret_cast(getter))); + + if (!data.IsEmpty()) { + dataobj->SetInternalField(imp::kDataIndex, data); + } + + if (setter) { + dataobj->SetInternalField( + imp::kSetterIndex + , New(reinterpret_cast(setter))); + } + +#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION) +#if defined(V8_MAJOR_VERSION) && \ + (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && \ + V8_MINOR_VERSION >= 5)) + return obj->SetNativeDataProperty( + GetCurrentContext() + , name + , getter_ + , setter_ + , dataobj + , attribute).FromMaybe(false); +#else + return obj->SetAccessor( + GetCurrentContext() + , name + , getter_ + , setter_ + , dataobj + , settings + , attribute).FromMaybe(false); +#endif +#else + return obj->SetAccessor( + name + , getter_ + , setter_ + , dataobj + , settings + , attribute); +#endif +} +#endif +inline void SetNamedPropertyHandler( + v8::Local tpl + , PropertyGetterCallback getter + , PropertySetterCallback setter = 0 + , PropertyQueryCallback query = 0 + , PropertyDeleterCallback deleter = 0 + , PropertyEnumeratorCallback enumerator = 0 + , v8::Local data = v8::Local()) { + HandleScope scope; + + imp::NativePropertyGetter getter_ = + imp::PropertyGetterCallbackWrapper; + imp::NativePropertySetter setter_ = + setter ? imp::PropertySetterCallbackWrapper : 0; + imp::NativePropertyQuery query_ = + query ? imp::PropertyQueryCallbackWrapper : 0; + imp::NativePropertyDeleter *deleter_ = + deleter ? imp::PropertyDeleterCallbackWrapper : 0; + imp::NativePropertyEnumerator enumerator_ = + enumerator ? imp::PropertyEnumeratorCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kPropertyFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + obj->SetInternalField( + imp::kPropertyGetterIndex + , New(reinterpret_cast(getter))); + + if (setter) { + obj->SetInternalField( + imp::kPropertySetterIndex + , New(reinterpret_cast(setter))); + } + + if (query) { + obj->SetInternalField( + imp::kPropertyQueryIndex + , New(reinterpret_cast(query))); + } + + if (deleter) { + obj->SetInternalField( + imp::kPropertyDeleterIndex + , New(reinterpret_cast(deleter))); + } + + if (enumerator) { + obj->SetInternalField( + imp::kPropertyEnumeratorIndex + , New(reinterpret_cast(enumerator))); + } + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + +#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION + tpl->SetHandler(v8::NamedPropertyHandlerConfiguration( + getter_, setter_, query_, deleter_, enumerator_, obj)); +#else + tpl->SetNamedPropertyHandler( + getter_ + , setter_ + , query_ + , deleter_ + , enumerator_ + , obj); +#endif +} + +inline void SetIndexedPropertyHandler( + v8::Local tpl + , IndexGetterCallback getter + , IndexSetterCallback setter = 0 + , IndexQueryCallback query = 0 + , IndexDeleterCallback deleter = 0 + , IndexEnumeratorCallback enumerator = 0 + , v8::Local data = v8::Local()) { + HandleScope scope; + + imp::NativeIndexGetter getter_ = + imp::IndexGetterCallbackWrapper; + imp::NativeIndexSetter setter_ = + setter ? imp::IndexSetterCallbackWrapper : 0; + imp::NativeIndexQuery query_ = + query ? imp::IndexQueryCallbackWrapper : 0; + imp::NativeIndexDeleter deleter_ = + deleter ? imp::IndexDeleterCallbackWrapper : 0; + imp::NativeIndexEnumerator enumerator_ = + enumerator ? imp::IndexEnumeratorCallbackWrapper : 0; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kIndexPropertyFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + obj->SetInternalField( + imp::kIndexPropertyGetterIndex + , New(reinterpret_cast(getter))); + + if (setter) { + obj->SetInternalField( + imp::kIndexPropertySetterIndex + , New(reinterpret_cast(setter))); + } + + if (query) { + obj->SetInternalField( + imp::kIndexPropertyQueryIndex + , New(reinterpret_cast(query))); + } + + if (deleter) { + obj->SetInternalField( + imp::kIndexPropertyDeleterIndex + , New(reinterpret_cast(deleter))); + } + + if (enumerator) { + obj->SetInternalField( + imp::kIndexPropertyEnumeratorIndex + , New(reinterpret_cast(enumerator))); + } + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + +#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION + tpl->SetHandler(v8::IndexedPropertyHandlerConfiguration( + getter_, setter_, query_, deleter_, enumerator_, obj)); +#else + tpl->SetIndexedPropertyHandler( + getter_ + , setter_ + , query_ + , deleter_ + , enumerator_ + , obj); +#endif +} + +inline void SetCallHandler( + v8::Local tpl + , FunctionCallback callback + , v8::Local data = v8::Local()) { + HandleScope scope; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kFunctionFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kFunctionIndex + , New(reinterpret_cast(callback))); + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + + tpl->SetCallHandler(imp::FunctionCallbackWrapper, obj); +} + + +inline void SetCallAsFunctionHandler( + v8::Local tpl, + FunctionCallback callback, + v8::Local data = v8::Local()) { + HandleScope scope; + + v8::Local otpl = New(); + otpl->SetInternalFieldCount(imp::kFunctionFieldCount); + v8::Local obj = NewInstance(otpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kFunctionIndex + , New(reinterpret_cast(callback))); + + if (!data.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, data); + } + + tpl->SetCallAsFunctionHandler(imp::FunctionCallbackWrapper, obj); +} + +//=== Weak Persistent Handling ================================================= + +#include "nan_weak.h" // NOLINT(build/include_subdir) + +//=== ObjectWrap =============================================================== + +#include "nan_object_wrap.h" // NOLINT(build/include_subdir) + +//=== HiddenValue/Private ====================================================== + +#include "nan_private.h" // NOLINT(build/include_subdir) + +//=== Export ================================================================== + +inline +void +Export(ADDON_REGISTER_FUNCTION_ARGS_TYPE target, const char *name, + FunctionCallback f) { + HandleScope scope; + + Set(target, New(name).ToLocalChecked(), + GetFunction(New(f)).ToLocalChecked()); +} + +//=== Tap Reverse Binding ===================================================== + +struct Tap { + explicit Tap(v8::Local t) : t_() { + HandleScope scope; + + t_.Reset(To(t).ToLocalChecked()); + } + + ~Tap() { t_.Reset(); } // not sure if necessary + + inline void plan(int i) { + HandleScope scope; + v8::Local arg = New(i); + Call("plan", New(t_), 1, &arg); + } + + inline void ok(bool isOk, const char *msg = NULL) { + HandleScope scope; + v8::Local args[2]; + args[0] = New(isOk); + if (msg) args[1] = New(msg).ToLocalChecked(); + Call("ok", New(t_), msg ? 2 : 1, args); + } + + inline void pass(const char * msg = NULL) { + HandleScope scope; + v8::Local hmsg; + if (msg) hmsg = New(msg).ToLocalChecked(); + Call("pass", New(t_), msg ? 1 : 0, &hmsg); + } + + inline void end() { + HandleScope scope; + Call("end", New(t_), 0, NULL); + } + + private: + Persistent t_; +}; + +#define NAN_STRINGIZE2(x) #x +#define NAN_STRINGIZE(x) NAN_STRINGIZE2(x) +#define NAN_TEST_EXPRESSION(expression) \ + ( expression ), __FILE__ ":" NAN_STRINGIZE(__LINE__) ": " #expression + +#define NAN_EXPORT(target, function) Export(target, #function, function) + +#undef TYPE_CHECK + +//=== Generic Maybefication =================================================== + +namespace imp { + +template struct Maybefier; + +template struct Maybefier > { + inline static MaybeLocal convert(v8::Local v) { + return v; + } +}; + +template struct Maybefier > { + inline static MaybeLocal convert(MaybeLocal v) { + return v; + } +}; + +} // end of namespace imp + +template class MaybeMaybe> +inline MaybeLocal +MakeMaybe(MaybeMaybe v) { + return imp::Maybefier >::convert(v); +} + +//=== TypedArrayContents ======================================================= + +#include "nan_typedarray_contents.h" // NOLINT(build/include_subdir) + +//=== JSON ===================================================================== + +#include "nan_json.h" // NOLINT(build/include_subdir) + +//=== ScriptOrigin ============================================================= + +#include "nan_scriptorigin.h" // NOLINT(build/include_subdir) + +} // end of namespace Nan + +#endif // NAN_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks.h new file mode 100644 index 0000000..2eb76fc --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks.h @@ -0,0 +1,141 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_CALLBACKS_H_ +#define NAN_CALLBACKS_H_ + +template class FunctionCallbackInfo; +template class PropertyCallbackInfo; +template class Global; + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +namespace Intercepted { + constexpr v8::Intercepted No() { return v8::Intercepted::kNo; } + constexpr v8::Intercepted Yes() { return v8::Intercepted::kYes; } +}; +#else +namespace Intercepted { + inline void No() {} + inline void Yes() {} +}; +#endif + +typedef void(*FunctionCallback)(const FunctionCallbackInfo&); +typedef void(*GetterCallback) + (v8::Local, const PropertyCallbackInfo&); +typedef void(*SetterCallback)( + v8::Local, + v8::Local, + const PropertyCallbackInfo&); + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted(*PropertyGetterCallback)( + v8::Local, + const PropertyCallbackInfo&); +typedef v8::Intercepted(*PropertySetterCallback)( + v8::Local, + v8::Local, + const PropertyCallbackInfo&); +#else +typedef void(*PropertyGetterCallback)( + v8::Local, + const PropertyCallbackInfo&); +typedef void(*PropertySetterCallback)( + v8::Local, + v8::Local, + const PropertyCallbackInfo&); +#endif +typedef void(*PropertyEnumeratorCallback) + (const PropertyCallbackInfo&); +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +typedef v8::Intercepted(*PropertyDeleterCallback)( + v8::Local, + const PropertyCallbackInfo&); +typedef v8::Intercepted(*PropertyQueryCallback)( + v8::Local, + const PropertyCallbackInfo&); +typedef v8::Intercepted(*IndexGetterCallback)( + uint32_t, + const PropertyCallbackInfo&); +typedef v8::Intercepted(*IndexSetterCallback)( + uint32_t, + v8::Local, + const PropertyCallbackInfo&); +typedef v8::Intercepted(*IndexEnumeratorCallback) + (const PropertyCallbackInfo&); +typedef v8::Intercepted(*IndexDeleterCallback)( + uint32_t, + const PropertyCallbackInfo&); +typedef v8::Intercepted(*IndexQueryCallback)( + uint32_t, + const PropertyCallbackInfo&); +#else +typedef void(*PropertyDeleterCallback)( + v8::Local, + const PropertyCallbackInfo&); +typedef void(*PropertyQueryCallback)( + v8::Local, + const PropertyCallbackInfo&); +typedef void(*IndexGetterCallback)( + uint32_t, + const PropertyCallbackInfo&); +typedef void(*IndexSetterCallback)( + uint32_t, + v8::Local, + const PropertyCallbackInfo&); +typedef void(*IndexEnumeratorCallback) + (const PropertyCallbackInfo&); +typedef void(*IndexDeleterCallback)( + uint32_t, + const PropertyCallbackInfo&); +typedef void(*IndexQueryCallback)( + uint32_t, + const PropertyCallbackInfo&); +#endif +namespace imp { +#if (NODE_MODULE_VERSION < NODE_16_0_MODULE_VERSION) +typedef v8::Local Sig; +#else +typedef v8::Local Sig; +#endif + +static const int kDataIndex = 0; + +static const int kFunctionIndex = 1; +static const int kFunctionFieldCount = 2; + +static const int kGetterIndex = 1; +static const int kSetterIndex = 2; +static const int kAccessorFieldCount = 3; + +static const int kPropertyGetterIndex = 1; +static const int kPropertySetterIndex = 2; +static const int kPropertyEnumeratorIndex = 3; +static const int kPropertyDeleterIndex = 4; +static const int kPropertyQueryIndex = 5; +static const int kPropertyFieldCount = 6; + +static const int kIndexPropertyGetterIndex = 1; +static const int kIndexPropertySetterIndex = 2; +static const int kIndexPropertyEnumeratorIndex = 3; +static const int kIndexPropertyDeleterIndex = 4; +static const int kIndexPropertyQueryIndex = 5; +static const int kIndexPropertyFieldCount = 6; + +} // end of namespace imp + +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION +# include "nan_callbacks_12_inl.h" // NOLINT(build/include) +#else +# include "nan_callbacks_pre_12_inl.h" // NOLINT(build/include) +#endif + +#endif // NAN_CALLBACKS_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_12_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_12_inl.h new file mode 100644 index 0000000..ff3b654 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_12_inl.h @@ -0,0 +1,690 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_CALLBACKS_12_INL_H_ +#define NAN_CALLBACKS_12_INL_H_ + +template +class ReturnValue { + v8::ReturnValue value_; + + public: + template + explicit inline ReturnValue(const v8::ReturnValue &value) : + value_(value) {} + template + explicit inline ReturnValue(const ReturnValue& that) + : value_(that.value_) { + TYPE_CHECK(T, S); + } + + // Handle setters + template inline void Set(const v8::Local &handle) { + TYPE_CHECK(T, S); + value_.Set(handle); + } + + template inline void Set(const Global &handle) { + TYPE_CHECK(T, S); +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && \ + (V8_MINOR_VERSION > 5 || (V8_MINOR_VERSION == 5 && \ + defined(V8_BUILD_NUMBER) && V8_BUILD_NUMBER >= 8)))) + value_.Set(handle); +#else + value_.Set(*reinterpret_cast*>(&handle)); + const_cast &>(handle).Reset(); +#endif + } + + // Fast primitive setters + inline void Set(bool value) { + TYPE_CHECK(T, v8::Boolean); + value_.Set(value); + } + + inline void Set(double i) { + TYPE_CHECK(T, v8::Number); + value_.Set(i); + } + + inline void Set(int32_t i) { + TYPE_CHECK(T, v8::Integer); + value_.Set(i); + } + + inline void Set(uint32_t i) { + TYPE_CHECK(T, v8::Integer); + value_.Set(i); + } + + // Fast JS primitive setters + inline void SetNull() { + TYPE_CHECK(T, v8::Primitive); + value_.SetNull(); + } + + inline void SetUndefined() { + TYPE_CHECK(T, v8::Primitive); + value_.SetUndefined(); + } + + inline void SetEmptyString() { + TYPE_CHECK(T, v8::String); + value_.SetEmptyString(); + } + + // Convenience getter for isolate + inline v8::Isolate *GetIsolate() const { + return value_.GetIsolate(); + } + + // Pointer setter: Uncompilable to prevent inadvertent misuse. + template + inline void Set(S *whatever) { TYPE_CHECK(S*, v8::Primitive); } +}; + +template +class FunctionCallbackInfo { + const v8::FunctionCallbackInfo &info_; + const v8::Local data_; + + public: + explicit inline FunctionCallbackInfo( + const v8::FunctionCallbackInfo &info + , v8::Local data) : + info_(info) + , data_(data) {} + + inline ReturnValue GetReturnValue() const { + return ReturnValue(info_.GetReturnValue()); + } + +#if NODE_MAJOR_VERSION < 10 + NAN_DEPRECATED inline v8::Local Callee() const { + return info_.Callee(); + } +#endif + inline v8::Local Data() const { return data_; } + inline v8::Local Holder() const { +#if defined(V8_MAJOR_VERSION) && \ + (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && \ + (defined(V8_MINOR_VERSION) && \ + (V8_MINOR_VERSION > 5 || \ + (V8_MINOR_VERSION == 5 && defined(V8_BUILD_NUMBER) && \ + V8_BUILD_NUMBER >= 214))))) + return info_.This(); +#else + return info_.Holder(); +#endif + } + inline bool IsConstructCall() const { return info_.IsConstructCall(); } + inline int Length() const { return info_.Length(); } + inline v8::Local operator[](int i) const { return info_[i]; } + inline v8::Local This() const { return info_.This(); } + inline v8::Isolate *GetIsolate() const { return info_.GetIsolate(); } + + + protected: + static const int kHolderIndex = 0; + static const int kIsolateIndex = 1; + static const int kReturnValueDefaultValueIndex = 2; + static const int kReturnValueIndex = 3; + static const int kDataIndex = 4; + static const int kCalleeIndex = 5; + static const int kContextSaveIndex = 6; + static const int kArgsLength = 7; + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(FunctionCallbackInfo) +}; + +template +class PropertyCallbackInfo { + const v8::PropertyCallbackInfo &info_; + const v8::Local data_; + + public: + explicit inline PropertyCallbackInfo( + const v8::PropertyCallbackInfo &info + , const v8::Local data) : + info_(info) + , data_(data) {} + + inline v8::Isolate* GetIsolate() const { return info_.GetIsolate(); } + inline v8::Local Data() const { return data_; } + inline v8::Local This() const { return info_.This(); } + inline v8::Local Holder() const { return info_.Holder(); } + inline ReturnValue GetReturnValue() const { + return ReturnValue(info_.GetReturnValue()); + } + + protected: + static const int kHolderIndex = 0; + static const int kIsolateIndex = 1; + static const int kReturnValueDefaultValueIndex = 2; + static const int kReturnValueIndex = 3; + static const int kDataIndex = 4; + static const int kThisIndex = 5; + static const int kArgsLength = 6; + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(PropertyCallbackInfo) +}; + +namespace imp { +static +void FunctionCallbackWrapper(const v8::FunctionCallbackInfo &info) { + v8::Local obj = info.Data().As(); + FunctionCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kFunctionIndex) + .As().As()->Value())); + FunctionCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + callback(cbinfo); +} + +typedef void (*NativeFunction)(const v8::FunctionCallbackInfo &); + +#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION +static +void GetterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + GetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kGetterIndex) + .As().As()->Value())); + callback(property.As(), cbinfo); +} + +typedef void (*NativeGetter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +void SetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + SetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kSetterIndex) + .As().As()->Value())); + callback(property.As(), value, cbinfo); +} + +typedef void (*NativeSetter)( + v8::Local + , v8::Local + , const v8::PropertyCallbackInfo &); +#else +static +void GetterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + GetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kGetterIndex) + .As().As()->Value())); + callback(property, cbinfo); +} + +typedef void (*NativeGetter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +void SetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + SetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kSetterIndex) + .As().As()->Value())); + callback(property, value, cbinfo); +} + +typedef void (*NativeSetter)( + v8::Local + , v8::Local + , const v8::PropertyCallbackInfo &); +#endif + +#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +static +v8::Intercepted PropertyGetterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyGetterIndex) + .As().As()->Value())); + return callback(property.As(), cbinfo); +} + +typedef v8::Intercepted (*NativePropertyGetter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +v8::Intercepted PropertySetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertySetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertySetterIndex) + .As().As()->Value())); + return callback(property.As(), value, cbinfo); +} + +typedef v8::Intercepted (*NativePropertySetter)( + v8::Local + , v8::Local + , const v8::PropertyCallbackInfo &); + +#else +static +void PropertyGetterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyGetterIndex) + .As().As()->Value())); + callback(property.As(), cbinfo); +} + +typedef void (*NativePropertyGetter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +void PropertySetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertySetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertySetterIndex) + .As().As()->Value())); + callback(property.As(), value, cbinfo); +} + +typedef void (*NativePropertySetter)( + v8::Local + , v8::Local + , const v8::PropertyCallbackInfo &); +#endif + +static +void PropertyEnumeratorCallbackWrapper( + const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyEnumeratorCallback callback = + reinterpret_cast(reinterpret_cast( + obj->GetInternalField(kPropertyEnumeratorIndex) + .As().As()->Value())); + callback(cbinfo); +} + +typedef void (*NativePropertyEnumerator) + (const v8::PropertyCallbackInfo &); + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +static +v8::Intercepted PropertyDeleterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyDeleterIndex) + .As().As()->Value())); + return callback(property.As(), cbinfo); +} + +typedef v8::Intercepted (NativePropertyDeleter) + (v8::Local, const v8::PropertyCallbackInfo &); + + +static +v8::Intercepted PropertyQueryCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyQueryIndex) + .As().As()->Value())); + return callback(property.As(), cbinfo); +} + +typedef v8::Intercepted (*NativePropertyQuery) + (v8::Local, const v8::PropertyCallbackInfo &); +#else +static +void PropertyDeleterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyDeleterIndex) + .As().As()->Value())); + callback(property.As(), cbinfo); +} + +typedef void (NativePropertyDeleter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +void PropertyQueryCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyQueryIndex) + .As().As()->Value())); + callback(property.As(), cbinfo); +} + +typedef void (*NativePropertyQuery) + (v8::Local, const v8::PropertyCallbackInfo &); +#endif +#else +static +void PropertyGetterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyGetterIndex) + .As().As()->Value())); + callback(property, cbinfo); +} + +typedef void (*NativePropertyGetter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +void PropertySetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertySetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertySetterIndex) + .As().As()->Value())); + callback(property, value, cbinfo); +} + +typedef void (*NativePropertySetter)( + v8::Local + , v8::Local + , const v8::PropertyCallbackInfo &); + +static +void PropertyEnumeratorCallbackWrapper( + const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyEnumeratorCallback callback = + reinterpret_cast(reinterpret_cast( + obj->GetInternalField(kPropertyEnumeratorIndex) + .As().As()->Value())); + callback(cbinfo); +} + +typedef void (*NativePropertyEnumerator) + (const v8::PropertyCallbackInfo &); + +static +void PropertyDeleterCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyDeleterIndex) + .As().As()->Value())); + callback(property, cbinfo); +} + +typedef void (NativePropertyDeleter) + (v8::Local, const v8::PropertyCallbackInfo &); + +static +void PropertyQueryCallbackWrapper( + v8::Local property + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + PropertyQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyQueryIndex) + .As().As()->Value())); + callback(property, cbinfo); +} + +typedef void (*NativePropertyQuery) + (v8::Local, const v8::PropertyCallbackInfo &); +#endif + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +static +v8::Intercepted IndexGetterCallbackWrapper( + uint32_t index, const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyGetterIndex) + .As().As()->Value())); + return callback(index, cbinfo); +} + +typedef v8::Intercepted (*NativeIndexGetter) + (uint32_t, const v8::PropertyCallbackInfo &); + +static +v8::Intercepted IndexSetterCallbackWrapper( + uint32_t index + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexSetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertySetterIndex) + .As().As()->Value())); + return callback(index, value, cbinfo); +} + +typedef v8::Intercepted (*NativeIndexSetter)( + uint32_t + , v8::Local + , const v8::PropertyCallbackInfo &); + +#else +static +void IndexGetterCallbackWrapper( + uint32_t index, const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyGetterIndex) + .As().As()->Value())); + callback(index, cbinfo); +} + +typedef void (*NativeIndexGetter) + (uint32_t, const v8::PropertyCallbackInfo &); +static +void IndexSetterCallbackWrapper( + uint32_t index + , v8::Local value + , const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexSetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertySetterIndex) + .As().As()->Value())); + callback(index, value, cbinfo); +} + +typedef void (*NativeIndexSetter)( + uint32_t + , v8::Local + , const v8::PropertyCallbackInfo &); + +#endif + +static +void IndexEnumeratorCallbackWrapper( + const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexEnumeratorCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField( + kIndexPropertyEnumeratorIndex) + .As().As()->Value())); + callback(cbinfo); +} + +typedef void (*NativeIndexEnumerator) + (const v8::PropertyCallbackInfo &); + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION > 4)) +static +v8::Intercepted IndexDeleterCallbackWrapper( + uint32_t index, const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyDeleterIndex) + .As().As()->Value())); + return callback(index, cbinfo); +} + +typedef v8::Intercepted (*NativeIndexDeleter) + (uint32_t, const v8::PropertyCallbackInfo &); + +static +v8::Intercepted IndexQueryCallbackWrapper( + uint32_t index, const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyQueryIndex) + .As().As()->Value())); + return callback(index, cbinfo); +} + +typedef v8::Intercepted (*NativeIndexQuery) + (uint32_t, const v8::PropertyCallbackInfo &); +#else +static +void IndexDeleterCallbackWrapper( + uint32_t index, const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyDeleterIndex) + .As().As()->Value())); + callback(index, cbinfo); +} + +typedef void (*NativeIndexDeleter) + (uint32_t, const v8::PropertyCallbackInfo &); + +static +void IndexQueryCallbackWrapper( + uint32_t index, const v8::PropertyCallbackInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex).As()); + IndexQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyQueryIndex) + .As().As()->Value())); + callback(index, cbinfo); +} + +typedef void (*NativeIndexQuery) + (uint32_t, const v8::PropertyCallbackInfo &); + +#endif +} // end of namespace imp + +#endif // NAN_CALLBACKS_12_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_pre_12_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_pre_12_inl.h new file mode 100644 index 0000000..74861e2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_callbacks_pre_12_inl.h @@ -0,0 +1,524 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_CALLBACKS_PRE_12_INL_H_ +#define NAN_CALLBACKS_PRE_12_INL_H_ + +namespace imp { +template class ReturnValueImp; +} // end of namespace imp + +template +class ReturnValue { + v8::Isolate *isolate_; + v8::Persistent *value_; + friend class imp::ReturnValueImp; + + public: + template + explicit inline ReturnValue(v8::Isolate *isolate, v8::Persistent *p) : + isolate_(isolate), value_(p) {} + template + explicit inline ReturnValue(const ReturnValue& that) + : isolate_(that.isolate_), value_(that.value_) { + TYPE_CHECK(T, S); + } + + // Handle setters + template inline void Set(const v8::Local &handle) { + TYPE_CHECK(T, S); + value_->Dispose(); + *value_ = v8::Persistent::New(handle); + } + + template inline void Set(const Global &handle) { + TYPE_CHECK(T, S); + value_->Dispose(); + *value_ = v8::Persistent::New(handle.persistent); + const_cast &>(handle).Reset(); + } + + // Fast primitive setters + inline void Set(bool value) { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::Boolean); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::Boolean::New(value)); + } + + inline void Set(double i) { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::Number); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::Number::New(i)); + } + + inline void Set(int32_t i) { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::Integer); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::Int32::New(i)); + } + + inline void Set(uint32_t i) { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::Integer); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::Uint32::NewFromUnsigned(i)); + } + + // Fast JS primitive setters + inline void SetNull() { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::Primitive); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::Null()); + } + + inline void SetUndefined() { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::Primitive); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::Undefined()); + } + + inline void SetEmptyString() { + v8::HandleScope scope; + + TYPE_CHECK(T, v8::String); + value_->Dispose(); + *value_ = v8::Persistent::New(v8::String::Empty()); + } + + // Convenience getter for isolate + inline v8::Isolate *GetIsolate() const { + return isolate_; + } + + // Pointer setter: Uncompilable to prevent inadvertent misuse. + template + inline void Set(S *whatever) { TYPE_CHECK(S*, v8::Primitive); } +}; + +template +class FunctionCallbackInfo { + const v8::Arguments &args_; + v8::Local data_; + ReturnValue return_value_; + v8::Persistent retval_; + + public: + explicit inline FunctionCallbackInfo( + const v8::Arguments &args + , v8::Local data) : + args_(args) + , data_(data) + , return_value_(args.GetIsolate(), &retval_) + , retval_(v8::Persistent::New(v8::Undefined())) {} + + inline ~FunctionCallbackInfo() { + retval_.Dispose(); + retval_.Clear(); + } + + inline ReturnValue GetReturnValue() const { + return ReturnValue(return_value_); + } + + NAN_DEPRECATED inline v8::Local Callee() const { + return args_.Callee(); + } + inline v8::Local Data() const { return data_; } + inline v8::Local Holder() const { + return args_.Holder(); + } + inline bool IsConstructCall() const { return args_.IsConstructCall(); } + inline int Length() const { return args_.Length(); } + inline v8::Local operator[](int i) const { return args_[i]; } + inline v8::Local This() const { return args_.This(); } + inline v8::Isolate *GetIsolate() const { return args_.GetIsolate(); } + + + protected: + static const int kHolderIndex = 0; + static const int kIsolateIndex = 1; + static const int kReturnValueDefaultValueIndex = 2; + static const int kReturnValueIndex = 3; + static const int kDataIndex = 4; + static const int kCalleeIndex = 5; + static const int kContextSaveIndex = 6; + static const int kArgsLength = 7; + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(FunctionCallbackInfo) +}; + +template +class PropertyCallbackInfoBase { + const v8::AccessorInfo &info_; + const v8::Local data_; + + public: + explicit inline PropertyCallbackInfoBase( + const v8::AccessorInfo &info + , const v8::Local data) : + info_(info) + , data_(data) {} + + inline v8::Isolate* GetIsolate() const { return info_.GetIsolate(); } + inline v8::Local Data() const { return data_; } + inline v8::Local This() const { return info_.This(); } + inline v8::Local Holder() const { return info_.Holder(); } + + protected: + static const int kHolderIndex = 0; + static const int kIsolateIndex = 1; + static const int kReturnValueDefaultValueIndex = 2; + static const int kReturnValueIndex = 3; + static const int kDataIndex = 4; + static const int kThisIndex = 5; + static const int kArgsLength = 6; + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(PropertyCallbackInfoBase) +}; + +template +class PropertyCallbackInfo : public PropertyCallbackInfoBase { + ReturnValue return_value_; + v8::Persistent retval_; + + public: + explicit inline PropertyCallbackInfo( + const v8::AccessorInfo &info + , const v8::Local data) : + PropertyCallbackInfoBase(info, data) + , return_value_(info.GetIsolate(), &retval_) + , retval_(v8::Persistent::New(v8::Undefined())) {} + + inline ~PropertyCallbackInfo() { + retval_.Dispose(); + retval_.Clear(); + } + + inline ReturnValue GetReturnValue() const { return return_value_; } +}; + +template<> +class PropertyCallbackInfo : + public PropertyCallbackInfoBase { + ReturnValue return_value_; + v8::Persistent retval_; + + public: + explicit inline PropertyCallbackInfo( + const v8::AccessorInfo &info + , const v8::Local data) : + PropertyCallbackInfoBase(info, data) + , return_value_(info.GetIsolate(), &retval_) + , retval_(v8::Persistent::New(v8::Local())) {} + + inline ~PropertyCallbackInfo() { + retval_.Dispose(); + retval_.Clear(); + } + + inline ReturnValue GetReturnValue() const { + return return_value_; + } +}; + +template<> +class PropertyCallbackInfo : + public PropertyCallbackInfoBase { + ReturnValue return_value_; + v8::Persistent retval_; + + public: + explicit inline PropertyCallbackInfo( + const v8::AccessorInfo &info + , const v8::Local data) : + PropertyCallbackInfoBase(info, data) + , return_value_(info.GetIsolate(), &retval_) + , retval_(v8::Persistent::New(v8::Local())) {} + + inline ~PropertyCallbackInfo() { + retval_.Dispose(); + retval_.Clear(); + } + + inline ReturnValue GetReturnValue() const { + return return_value_; + } +}; + +template<> +class PropertyCallbackInfo : + public PropertyCallbackInfoBase { + ReturnValue return_value_; + v8::Persistent retval_; + + public: + explicit inline PropertyCallbackInfo( + const v8::AccessorInfo &info + , const v8::Local data) : + PropertyCallbackInfoBase(info, data) + , return_value_(info.GetIsolate(), &retval_) + , retval_(v8::Persistent::New(v8::Local())) {} + + inline ~PropertyCallbackInfo() { + retval_.Dispose(); + retval_.Clear(); + } + + inline ReturnValue GetReturnValue() const { + return return_value_; + } +}; + +namespace imp { +template +class ReturnValueImp : public ReturnValue { + public: + explicit ReturnValueImp(ReturnValue that) : + ReturnValue(that) {} + inline v8::Handle Value() { + return *ReturnValue::value_; + } +}; + +static +v8::Handle FunctionCallbackWrapper(const v8::Arguments &args) { + v8::Local obj = args.Data().As(); + FunctionCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kFunctionIndex).As()->Value())); + FunctionCallbackInfo + cbinfo(args, obj->GetInternalField(kDataIndex)); + callback(cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeFunction)(const v8::Arguments &); + +static +v8::Handle GetterCallbackWrapper( + v8::Local property, const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + GetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kGetterIndex).As()->Value())); + callback(property, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeGetter) + (v8::Local, const v8::AccessorInfo &); + +static +void SetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + SetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kSetterIndex).As()->Value())); + callback(property, value, cbinfo); +} + +typedef void (*NativeSetter) + (v8::Local, v8::Local, const v8::AccessorInfo &); + +static +v8::Handle PropertyGetterCallbackWrapper( + v8::Local property, const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + PropertyGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyGetterIndex) + .As()->Value())); + callback(property, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativePropertyGetter) + (v8::Local, const v8::AccessorInfo &); + +static +v8::Handle PropertySetterCallbackWrapper( + v8::Local property + , v8::Local value + , const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + PropertySetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertySetterIndex) + .As()->Value())); + callback(property, value, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativePropertySetter) + (v8::Local, v8::Local, const v8::AccessorInfo &); + +static +v8::Handle PropertyEnumeratorCallbackWrapper( + const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + PropertyEnumeratorCallback callback = + reinterpret_cast(reinterpret_cast( + obj->GetInternalField(kPropertyEnumeratorIndex) + .As()->Value())); + callback(cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativePropertyEnumerator) + (const v8::AccessorInfo &); + +static +v8::Handle PropertyDeleterCallbackWrapper( + v8::Local property + , const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + PropertyDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyDeleterIndex) + .As()->Value())); + callback(property, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (NativePropertyDeleter) + (v8::Local, const v8::AccessorInfo &); + +static +v8::Handle PropertyQueryCallbackWrapper( + v8::Local property, const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + PropertyQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kPropertyQueryIndex) + .As()->Value())); + callback(property, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativePropertyQuery) + (v8::Local, const v8::AccessorInfo &); + +static +v8::Handle IndexGetterCallbackWrapper( + uint32_t index, const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + IndexGetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyGetterIndex) + .As()->Value())); + callback(index, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeIndexGetter) + (uint32_t, const v8::AccessorInfo &); + +static +v8::Handle IndexSetterCallbackWrapper( + uint32_t index + , v8::Local value + , const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + IndexSetterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertySetterIndex) + .As()->Value())); + callback(index, value, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeIndexSetter) + (uint32_t, v8::Local, const v8::AccessorInfo &); + +static +v8::Handle IndexEnumeratorCallbackWrapper( + const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + IndexEnumeratorCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyEnumeratorIndex) + .As()->Value())); + callback(cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeIndexEnumerator) + (const v8::AccessorInfo &); + +static +v8::Handle IndexDeleterCallbackWrapper( + uint32_t index, const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + IndexDeleterCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyDeleterIndex) + .As()->Value())); + callback(index, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeIndexDeleter) + (uint32_t, const v8::AccessorInfo &); + +static +v8::Handle IndexQueryCallbackWrapper( + uint32_t index, const v8::AccessorInfo &info) { + v8::Local obj = info.Data().As(); + PropertyCallbackInfo + cbinfo(info, obj->GetInternalField(kDataIndex)); + IndexQueryCallback callback = reinterpret_cast( + reinterpret_cast( + obj->GetInternalField(kIndexPropertyQueryIndex) + .As()->Value())); + callback(index, cbinfo); + return ReturnValueImp(cbinfo.GetReturnValue()).Value(); +} + +typedef v8::Handle (*NativeIndexQuery) + (uint32_t, const v8::AccessorInfo &); +} // end of namespace imp + +#endif // NAN_CALLBACKS_PRE_12_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_converters.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_converters.h new file mode 100644 index 0000000..c0b3272 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_converters.h @@ -0,0 +1,72 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_CONVERTERS_H_ +#define NAN_CONVERTERS_H_ + +namespace imp { +template struct ToFactoryBase { + typedef MaybeLocal return_t; +}; +template struct ValueFactoryBase { typedef Maybe return_t; }; + +template struct ToFactory; + +template<> +struct ToFactory : ToFactoryBase { + static inline return_t convert(v8::Local val) { + if (val.IsEmpty() || !val->IsFunction()) return MaybeLocal(); + return MaybeLocal(val.As()); + } +}; + +#define X(TYPE) \ + template<> \ + struct ToFactory : ToFactoryBase { \ + static inline return_t convert(v8::Local val); \ + }; + +X(Boolean) +X(Number) +X(String) +X(Object) +X(Integer) +X(Uint32) +X(Int32) + +#undef X + +#define X(TYPE) \ + template<> \ + struct ToFactory : ValueFactoryBase { \ + static inline return_t convert(v8::Local val); \ + }; + +X(bool) +X(double) +X(int64_t) +X(uint32_t) +X(int32_t) + +#undef X +} // end of namespace imp + +template +inline +typename imp::ToFactory::return_t To(v8::Local val) { + return imp::ToFactory::convert(val); +} + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +# include "nan_converters_43_inl.h" +#else +# include "nan_converters_pre_43_inl.h" +#endif + +#endif // NAN_CONVERTERS_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_converters_43_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_converters_43_inl.h new file mode 100644 index 0000000..41b72de --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_converters_43_inl.h @@ -0,0 +1,68 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_CONVERTERS_43_INL_H_ +#define NAN_CONVERTERS_43_INL_H_ + +#define X(TYPE) \ +imp::ToFactory::return_t \ +imp::ToFactory::convert(v8::Local val) { \ + v8::Isolate *isolate = v8::Isolate::GetCurrent(); \ + v8::EscapableHandleScope scope(isolate); \ + return scope.Escape( \ + val->To ## TYPE(isolate->GetCurrentContext()) \ + .FromMaybe(v8::Local())); \ +} + +X(Number) +X(String) +X(Object) +X(Integer) +X(Uint32) +X(Int32) +// V8 <= 7.0 +#if V8_MAJOR_VERSION < 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION == 0) +X(Boolean) +#else +imp::ToFactory::return_t \ +imp::ToFactory::convert(v8::Local val) { \ + v8::Isolate *isolate = v8::Isolate::GetCurrent(); \ + v8::EscapableHandleScope scope(isolate); \ + return scope.Escape(val->ToBoolean(isolate)); \ +} +#endif + +#undef X + +#define X(TYPE, NAME) \ +imp::ToFactory::return_t \ +imp::ToFactory::convert(v8::Local val) { \ + v8::Isolate *isolate = v8::Isolate::GetCurrent(); \ + v8::HandleScope scope(isolate); \ + return val->NAME ## Value(isolate->GetCurrentContext()); \ +} + +X(double, Number) +X(int64_t, Integer) +X(uint32_t, Uint32) +X(int32_t, Int32) +// V8 <= 7.0 +#if V8_MAJOR_VERSION < 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION == 0) +X(bool, Boolean) +#else +imp::ToFactory::return_t \ +imp::ToFactory::convert(v8::Local val) { \ + v8::Isolate *isolate = v8::Isolate::GetCurrent(); \ + v8::HandleScope scope(isolate); \ + return Just(val->BooleanValue(isolate)); \ +} +#endif + +#undef X + +#endif // NAN_CONVERTERS_43_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_converters_pre_43_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_converters_pre_43_inl.h new file mode 100644 index 0000000..ae0518a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_converters_pre_43_inl.h @@ -0,0 +1,42 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_CONVERTERS_PRE_43_INL_H_ +#define NAN_CONVERTERS_PRE_43_INL_H_ + +#define X(TYPE) \ +imp::ToFactory::return_t \ +imp::ToFactory::convert(v8::Local val) { \ + return val->To ## TYPE(); \ +} + +X(Boolean) +X(Number) +X(String) +X(Object) +X(Integer) +X(Uint32) +X(Int32) + +#undef X + +#define X(TYPE, NAME) \ +imp::ToFactory::return_t \ +imp::ToFactory::convert(v8::Local val) { \ + return Just(val->NAME ## Value()); \ +} + +X(bool, Boolean) +X(double, Number) +X(int64_t, Integer) +X(uint32_t, Uint32) +X(int32_t, Int32) + +#undef X + +#endif // NAN_CONVERTERS_PRE_43_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_define_own_property_helper.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_define_own_property_helper.h new file mode 100644 index 0000000..d710ef2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_define_own_property_helper.h @@ -0,0 +1,29 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_DEFINE_OWN_PROPERTY_HELPER_H_ +#define NAN_DEFINE_OWN_PROPERTY_HELPER_H_ + +namespace imp { + +inline Maybe DefineOwnPropertyHelper( + v8::PropertyAttribute current + , v8::Handle obj + , v8::Handle key + , v8::Handle value + , v8::PropertyAttribute attribs = v8::None) { + return !(current & v8::DontDelete) || // configurable OR + (!(current & v8::ReadOnly) && // writable AND + !((attribs ^ current) & ~v8::ReadOnly)) // same excluding RO + ? Just(obj->ForceSet(key, value, attribs)) + : Nothing(); +} + +} // end of namespace imp + +#endif // NAN_DEFINE_OWN_PROPERTY_HELPER_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_12_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_12_inl.h new file mode 100644 index 0000000..255293a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_12_inl.h @@ -0,0 +1,430 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_IMPLEMENTATION_12_INL_H_ +#define NAN_IMPLEMENTATION_12_INL_H_ +//============================================================================== +// node v0.11 implementation +//============================================================================== + +namespace imp { + +//=== Array ==================================================================== + +Factory::return_t +Factory::New() { + return v8::Array::New(v8::Isolate::GetCurrent()); +} + +Factory::return_t +Factory::New(int length) { + return v8::Array::New(v8::Isolate::GetCurrent(), length); +} + +//=== Boolean ================================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::Boolean::New(v8::Isolate::GetCurrent(), value); +} + +//=== Boolean Object =========================================================== + +Factory::return_t +Factory::New(bool value) { +#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION) + return v8::BooleanObject::New( + v8::Isolate::GetCurrent(), value).As(); +#else + return v8::BooleanObject::New(value).As(); +#endif +} + +//=== Context ================================================================== + +Factory::return_t +Factory::New( v8::ExtensionConfiguration* extensions + , v8::Local tmpl + , v8::Local obj) { + return v8::Context::New(v8::Isolate::GetCurrent(), extensions, tmpl, obj); +} + +//=== Date ===================================================================== + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +Factory::return_t +Factory::New(double value) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(v8::Date::New(isolate->GetCurrentContext(), value) + .FromMaybe(v8::Local()).As()); +} +#else +Factory::return_t +Factory::New(double value) { + return v8::Date::New(v8::Isolate::GetCurrent(), value).As(); +} +#endif + +//=== External ================================================================= + +Factory::return_t +Factory::New(void * value) { + return v8::External::New(v8::Isolate::GetCurrent(), value); +} + +//=== Function ================================================================= + +Factory::return_t +Factory::New( FunctionCallback callback + , v8::Local data) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::Local tpl = v8::ObjectTemplate::New(isolate); + tpl->SetInternalFieldCount(imp::kFunctionFieldCount); + v8::Local obj = NewInstance(tpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kFunctionIndex + , v8::External::New(isolate, reinterpret_cast(callback))); + + v8::Local val = v8::Local::New(isolate, data); + + if (!val.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, val); + } + +#if NODE_MAJOR_VERSION >= 10 + v8::Local context = isolate->GetCurrentContext(); + v8::Local function = + v8::Function::New(context, imp::FunctionCallbackWrapper, obj) + .ToLocalChecked(); +#else + v8::Local function = + v8::Function::New(isolate, imp::FunctionCallbackWrapper, obj); +#endif + + return scope.Escape(function); +} + +//=== Function Template ======================================================== + +Factory::return_t +Factory::New( FunctionCallback callback + , v8::Local data + , v8::Local signature) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + if (callback) { + v8::EscapableHandleScope scope(isolate); + v8::Local tpl = v8::ObjectTemplate::New(isolate); + tpl->SetInternalFieldCount(imp::kFunctionFieldCount); + v8::Local obj = NewInstance(tpl).ToLocalChecked(); + + obj->SetInternalField( + imp::kFunctionIndex + , v8::External::New(isolate, reinterpret_cast(callback))); + v8::Local val = v8::Local::New(isolate, data); + + if (!val.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, val); + } + + return scope.Escape(v8::FunctionTemplate::New( isolate + , imp::FunctionCallbackWrapper + , obj + , signature)); + } else { + return v8::FunctionTemplate::New(isolate, 0, data, signature); + } +} + +//=== Number =================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Number::New(v8::Isolate::GetCurrent(), value); +} + +//=== Number Object ============================================================ + +Factory::return_t +Factory::New(double value) { + return v8::NumberObject::New( v8::Isolate::GetCurrent() + , value).As(); +} + +//=== Integer, Int32 and Uint32 ================================================ + +template +typename IntegerFactory::return_t +IntegerFactory::New(int32_t value) { + return To(T::New(v8::Isolate::GetCurrent(), value)); +} + +template +typename IntegerFactory::return_t +IntegerFactory::New(uint32_t value) { + return To(T::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); +} + +Factory::return_t +Factory::New(int32_t value) { + return To( + v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); +} + +Factory::return_t +Factory::New(uint32_t value) { + return To( + v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value)); +} + +//=== Object =================================================================== + +Factory::return_t +Factory::New() { + return v8::Object::New(v8::Isolate::GetCurrent()); +} + +//=== Object Template ========================================================== + +Factory::return_t +Factory::New() { + return v8::ObjectTemplate::New(v8::Isolate::GetCurrent()); +} + +//=== RegExp =================================================================== + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +Factory::return_t +Factory::New( + v8::Local pattern + , v8::RegExp::Flags flags) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape( + v8::RegExp::New(isolate->GetCurrentContext(), pattern, flags) + .FromMaybe(v8::Local())); +} +#else +Factory::return_t +Factory::New( + v8::Local pattern + , v8::RegExp::Flags flags) { + return v8::RegExp::New(pattern, flags); +} +#endif + +//=== Script =================================================================== + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +Factory::return_t +Factory::New( v8::Local source) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::ScriptCompiler::Source src(source); + return scope.Escape( + v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &src) + .FromMaybe(v8::Local())); +} + +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::ScriptCompiler::Source src(source, origin); + return scope.Escape( + v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &src) + .FromMaybe(v8::Local())); +} +#else +Factory::return_t +Factory::New( v8::Local source) { + v8::ScriptCompiler::Source src(source); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src); +} + +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + v8::ScriptCompiler::Source src(source, origin); + return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src); +} +#endif + +//=== Signature ================================================================ + +Factory::return_t +Factory::New(Factory::FTH receiver) { + return v8::Signature::New(v8::Isolate::GetCurrent(), receiver); +} + +//=== String =================================================================== + +Factory::return_t +Factory::New() { + return v8::String::Empty(v8::Isolate::GetCurrent()); +} + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +Factory::return_t +Factory::New(const char * value, int length) { + return v8::String::NewFromUtf8( + v8::Isolate::GetCurrent(), value, v8::NewStringType::kNormal, length); +} + +Factory::return_t +Factory::New(std::string const& value) { + assert(value.size() <= INT_MAX && "string too long"); + return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), + value.data(), v8::NewStringType::kNormal, static_cast(value.size())); +} + +Factory::return_t +Factory::New(const uint16_t * value, int length) { + return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value, + v8::NewStringType::kNormal, length); +} + +Factory::return_t +Factory::New(v8::String::ExternalStringResource * value) { + return v8::String::NewExternalTwoByte(v8::Isolate::GetCurrent(), value); +} + +Factory::return_t +Factory::New(ExternalOneByteStringResource * value) { + return v8::String::NewExternalOneByte(v8::Isolate::GetCurrent(), value); +} +#else +Factory::return_t +Factory::New(const char * value, int length) { + return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value, + v8::String::kNormalString, length); +} + +Factory::return_t +Factory::New( + std::string const& value) /* NOLINT(build/include_what_you_use) */ { + assert(value.size() <= INT_MAX && "string too long"); + return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value.data(), + v8::String::kNormalString, + static_cast(value.size())); +} + +Factory::return_t +Factory::New(const uint16_t * value, int length) { + return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value, + v8::String::kNormalString, length); +} + +Factory::return_t +Factory::New(v8::String::ExternalStringResource * value) { + return v8::String::NewExternal(v8::Isolate::GetCurrent(), value); +} + +Factory::return_t +Factory::New(ExternalOneByteStringResource * value) { + return v8::String::NewExternal(v8::Isolate::GetCurrent(), value); +} +#endif + +//=== String Object ============================================================ + +// See https://github.com/nodejs/nan/pull/811#discussion_r224594980. +// Disable the warning as there is no way around it. +// TODO(bnoordhuis) Use isolate-based version in Node.js v12. +Factory::return_t +Factory::New(v8::Local value) { +// V8 > 7.0 +#if V8_MAJOR_VERSION > 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION > 0) + return v8::StringObject::New(v8::Isolate::GetCurrent(), value) + .As(); +#else +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + return v8::StringObject::New(value).As(); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif +} + +//=== Unbound Script =========================================================== + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +Factory::return_t +Factory::New(v8::Local source) { + v8::ScriptCompiler::Source src(source); + return v8::ScriptCompiler::CompileUnboundScript( + v8::Isolate::GetCurrent(), &src); +} + +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + v8::ScriptCompiler::Source src(source, origin); + return v8::ScriptCompiler::CompileUnboundScript( + v8::Isolate::GetCurrent(), &src); +} +#else +Factory::return_t +Factory::New(v8::Local source) { + v8::ScriptCompiler::Source src(source); + return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src); +} + +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + v8::ScriptCompiler::Source src(source, origin); + return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src); +} +#endif + +} // end of namespace imp + +//=== Presistents and Handles ================================================== + +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION +template +inline v8::Local New(v8::Handle h) { + return v8::Local::New(v8::Isolate::GetCurrent(), h); +} +#endif + +template +inline v8::Local New(v8::Persistent const& p) { + return v8::Local::New(v8::Isolate::GetCurrent(), p); +} + +template +inline v8::Local New(Persistent const& p) { + return v8::Local::New(v8::Isolate::GetCurrent(), p); +} + +template +inline v8::Local New(Global const& p) { + return v8::Local::New(v8::Isolate::GetCurrent(), p); +} + +#endif // NAN_IMPLEMENTATION_12_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_pre_12_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_pre_12_inl.h new file mode 100644 index 0000000..1472421 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_implementation_pre_12_inl.h @@ -0,0 +1,263 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_IMPLEMENTATION_PRE_12_INL_H_ +#define NAN_IMPLEMENTATION_PRE_12_INL_H_ + +//============================================================================== +// node v0.10 implementation +//============================================================================== + +namespace imp { + +//=== Array ==================================================================== + +Factory::return_t +Factory::New() { + return v8::Array::New(); +} + +Factory::return_t +Factory::New(int length) { + return v8::Array::New(length); +} + +//=== Boolean ================================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::Boolean::New(value)->ToBoolean(); +} + +//=== Boolean Object =========================================================== + +Factory::return_t +Factory::New(bool value) { + return v8::BooleanObject::New(value).As(); +} + +//=== Context ================================================================== + +Factory::return_t +Factory::New( v8::ExtensionConfiguration* extensions + , v8::Local tmpl + , v8::Local obj) { + v8::Persistent ctx = v8::Context::New(extensions, tmpl, obj); + v8::Local lctx = v8::Local::New(ctx); + ctx.Dispose(); + return lctx; +} + +//=== Date ===================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Date::New(value).As(); +} + +//=== External ================================================================= + +Factory::return_t +Factory::New(void * value) { + return v8::External::New(value); +} + +//=== Function ================================================================= + +Factory::return_t +Factory::New( FunctionCallback callback + , v8::Local data) { + v8::HandleScope scope; + + return scope.Close(Factory::New( + callback, data, v8::Local()) + ->GetFunction()); +} + + +//=== FunctionTemplate ========================================================= + +Factory::return_t +Factory::New( FunctionCallback callback + , v8::Local data + , v8::Local signature) { + if (callback) { + v8::HandleScope scope; + + v8::Local tpl = v8::ObjectTemplate::New(); + tpl->SetInternalFieldCount(imp::kFunctionFieldCount); + v8::Local obj = tpl->NewInstance(); + + obj->SetInternalField( + imp::kFunctionIndex + , v8::External::New(reinterpret_cast(callback))); + + v8::Local val = v8::Local::New(data); + + if (!val.IsEmpty()) { + obj->SetInternalField(imp::kDataIndex, val); + } + + // Note(agnat): Emulate length argument here. Unfortunately, I couldn't find + // a way. Have at it though... + return scope.Close( + v8::FunctionTemplate::New(imp::FunctionCallbackWrapper + , obj + , signature)); + } else { + return v8::FunctionTemplate::New(0, data, signature); + } +} + +//=== Number =================================================================== + +Factory::return_t +Factory::New(double value) { + return v8::Number::New(value); +} + +//=== Number Object ============================================================ + +Factory::return_t +Factory::New(double value) { + return v8::NumberObject::New(value).As(); +} + +//=== Integer, Int32 and Uint32 ================================================ + +template +typename IntegerFactory::return_t +IntegerFactory::New(int32_t value) { + return To(T::New(value)); +} + +template +typename IntegerFactory::return_t +IntegerFactory::New(uint32_t value) { + return To(T::NewFromUnsigned(value)); +} + +Factory::return_t +Factory::New(int32_t value) { + return To(v8::Uint32::NewFromUnsigned(value)); +} + +Factory::return_t +Factory::New(uint32_t value) { + return To(v8::Uint32::NewFromUnsigned(value)); +} + + +//=== Object =================================================================== + +Factory::return_t +Factory::New() { + return v8::Object::New(); +} + +//=== Object Template ========================================================== + +Factory::return_t +Factory::New() { + return v8::ObjectTemplate::New(); +} + +//=== RegExp =================================================================== + +Factory::return_t +Factory::New( + v8::Local pattern + , v8::RegExp::Flags flags) { + return v8::RegExp::New(pattern, flags); +} + +//=== Script =================================================================== + +Factory::return_t +Factory::New( v8::Local source) { + return v8::Script::New(source); +} +Factory::return_t +Factory::New( v8::Local source + , v8::ScriptOrigin const& origin) { + return v8::Script::New(source, const_cast(&origin)); +} + +//=== Signature ================================================================ + +Factory::return_t +Factory::New(Factory::FTH receiver) { + return v8::Signature::New(receiver); +} + +//=== String =================================================================== + +Factory::return_t +Factory::New() { + return v8::String::Empty(); +} + +Factory::return_t +Factory::New(const char * value, int length) { + return v8::String::New(value, length); +} + +Factory::return_t +Factory::New( + std::string const& value) /* NOLINT(build/include_what_you_use) */ { + assert(value.size() <= INT_MAX && "string too long"); + return v8::String::New(value.data(), static_cast(value.size())); +} + +Factory::return_t +Factory::New(const uint16_t * value, int length) { + return v8::String::New(value, length); +} + +Factory::return_t +Factory::New(v8::String::ExternalStringResource * value) { + return v8::String::NewExternal(value); +} + +Factory::return_t +Factory::New(v8::String::ExternalAsciiStringResource * value) { + return v8::String::NewExternal(value); +} + +//=== String Object ============================================================ + +Factory::return_t +Factory::New(v8::Local value) { + return v8::StringObject::New(value).As(); +} + +} // end of namespace imp + +//=== Presistents and Handles ================================================== + +template +inline v8::Local New(v8::Handle h) { + return v8::Local::New(h); +} + +template +inline v8::Local New(v8::Persistent const& p) { + return v8::Local::New(p); +} + +template +inline v8::Local New(Persistent const& p) { + return v8::Local::New(p.persistent); +} + +template +inline v8::Local New(Global const& p) { + return v8::Local::New(p.persistent); +} + +#endif // NAN_IMPLEMENTATION_PRE_12_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_json.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_json.h new file mode 100644 index 0000000..33ac8ba --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_json.h @@ -0,0 +1,166 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_JSON_H_ +#define NAN_JSON_H_ + +#if NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION +#define NAN_JSON_H_NEED_PARSE 1 +#else +#define NAN_JSON_H_NEED_PARSE 0 +#endif // NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION + +#if NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION +#define NAN_JSON_H_NEED_STRINGIFY 0 +#else +#define NAN_JSON_H_NEED_STRINGIFY 1 +#endif // NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION + +class JSON { + public: + JSON() { +#if NAN_JSON_H_NEED_PARSE + NAN_JSON_H_NEED_STRINGIFY + Nan::HandleScope scope; + + Nan::MaybeLocal maybe_global_json = Nan::Get( + Nan::GetCurrentContext()->Global(), + Nan::New("JSON").ToLocalChecked() + ); + + assert(!maybe_global_json.IsEmpty() && "global JSON is empty"); + v8::Local val_global_json = maybe_global_json.ToLocalChecked(); + + assert(val_global_json->IsObject() && "global JSON is not an object"); + Nan::MaybeLocal maybe_obj_global_json = + Nan::To(val_global_json); + + assert(!maybe_obj_global_json.IsEmpty() && "global JSON object is empty"); + v8::Local global_json = maybe_obj_global_json.ToLocalChecked(); + +#if NAN_JSON_H_NEED_PARSE + Nan::MaybeLocal maybe_parse_method = Nan::Get( + global_json, Nan::New("parse").ToLocalChecked() + ); + + assert(!maybe_parse_method.IsEmpty() && "JSON.parse is empty"); + v8::Local parse_method = maybe_parse_method.ToLocalChecked(); + + assert(parse_method->IsFunction() && "JSON.parse is not a function"); + parse_cb_.Reset(parse_method.As()); +#endif // NAN_JSON_H_NEED_PARSE + +#if NAN_JSON_H_NEED_STRINGIFY + Nan::MaybeLocal maybe_stringify_method = Nan::Get( + global_json, Nan::New("stringify").ToLocalChecked() + ); + + assert(!maybe_stringify_method.IsEmpty() && "JSON.stringify is empty"); + v8::Local stringify_method = + maybe_stringify_method.ToLocalChecked(); + + assert( + stringify_method->IsFunction() && "JSON.stringify is not a function" + ); + stringify_cb_.Reset(stringify_method.As()); +#endif // NAN_JSON_H_NEED_STRINGIFY +#endif // NAN_JSON_H_NEED_PARSE + NAN_JSON_H_NEED_STRINGIFY + } + + inline + Nan::MaybeLocal Parse(v8::Local json_string) { + Nan::EscapableHandleScope scope; +#if NAN_JSON_H_NEED_PARSE + return scope.Escape(parse(json_string)); +#else + Nan::MaybeLocal result; +#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION && \ + NODE_MODULE_VERSION <= IOJS_2_0_MODULE_VERSION + result = v8::JSON::Parse(json_string); +#else +#if NODE_MODULE_VERSION > NODE_6_0_MODULE_VERSION + v8::Local context_or_isolate = Nan::GetCurrentContext(); +#else + v8::Isolate* context_or_isolate = v8::Isolate::GetCurrent(); +#endif // NODE_MODULE_VERSION > NODE_6_0_MODULE_VERSION + result = v8::JSON::Parse(context_or_isolate, json_string); +#endif // NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION && + // NODE_MODULE_VERSION <= IOJS_2_0_MODULE_VERSION + if (result.IsEmpty()) return v8::Local(); + return scope.Escape(result.ToLocalChecked()); +#endif // NAN_JSON_H_NEED_PARSE + } + + inline + Nan::MaybeLocal Stringify(v8::Local json_object) { + Nan::EscapableHandleScope scope; + Nan::MaybeLocal result = +#if NAN_JSON_H_NEED_STRINGIFY + Nan::To(stringify(json_object)); +#else + v8::JSON::Stringify(Nan::GetCurrentContext(), json_object); +#endif // NAN_JSON_H_NEED_STRINGIFY + if (result.IsEmpty()) return v8::Local(); + return scope.Escape(result.ToLocalChecked()); + } + + inline + Nan::MaybeLocal Stringify(v8::Local json_object, + v8::Local gap) { + Nan::EscapableHandleScope scope; + Nan::MaybeLocal result = +#if NAN_JSON_H_NEED_STRINGIFY + Nan::To(stringify(json_object, gap)); +#else + v8::JSON::Stringify(Nan::GetCurrentContext(), json_object, gap); +#endif // NAN_JSON_H_NEED_STRINGIFY + if (result.IsEmpty()) return v8::Local(); + return scope.Escape(result.ToLocalChecked()); + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(JSON) +#if NAN_JSON_H_NEED_PARSE + Nan::Callback parse_cb_; +#endif // NAN_JSON_H_NEED_PARSE +#if NAN_JSON_H_NEED_STRINGIFY + Nan::Callback stringify_cb_; +#endif // NAN_JSON_H_NEED_STRINGIFY + +#if NAN_JSON_H_NEED_PARSE + inline v8::Local parse(v8::Local arg) { + assert(!parse_cb_.IsEmpty() && "parse_cb_ is empty"); + AsyncResource resource("nan:JSON.parse"); + return parse_cb_.Call(1, &arg, &resource).FromMaybe(v8::Local()); + } +#endif // NAN_JSON_H_NEED_PARSE + +#if NAN_JSON_H_NEED_STRINGIFY + inline v8::Local stringify(v8::Local arg) { + assert(!stringify_cb_.IsEmpty() && "stringify_cb_ is empty"); + AsyncResource resource("nan:JSON.stringify"); + return stringify_cb_.Call(1, &arg, &resource) + .FromMaybe(v8::Local()); + } + + inline v8::Local stringify(v8::Local arg, + v8::Local gap) { + assert(!stringify_cb_.IsEmpty() && "stringify_cb_ is empty"); + + v8::Local argv[] = { + arg, + Nan::Null(), + gap + }; + AsyncResource resource("nan:JSON.stringify"); + return stringify_cb_.Call(3, argv, &resource) + .FromMaybe(v8::Local()); + } +#endif // NAN_JSON_H_NEED_STRINGIFY +}; + +#endif // NAN_JSON_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_43_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_43_inl.h new file mode 100644 index 0000000..48b62e9 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_43_inl.h @@ -0,0 +1,360 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_MAYBE_43_INL_H_ +#define NAN_MAYBE_43_INL_H_ + +template +using MaybeLocal = v8::MaybeLocal; + +inline +MaybeLocal ToDetailString(v8::Local val) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(val->ToDetailString(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline +MaybeLocal ToArrayIndex(v8::Local val) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(val->ToArrayIndex(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline +Maybe Equals(v8::Local a, v8::Local(b)) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return a->Equals(isolate->GetCurrentContext(), b); +} + +inline +MaybeLocal NewInstance(v8::Local h) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(h->NewInstance(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline +MaybeLocal NewInstance( + v8::Local h + , int argc + , v8::Local argv[]) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(h->NewInstance(isolate->GetCurrentContext(), argc, argv) + .FromMaybe(v8::Local())); +} + +inline +MaybeLocal NewInstance(v8::Local h) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(h->NewInstance(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + + +inline MaybeLocal GetFunction( + v8::Local t) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(t->GetFunction(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline Maybe Set( + v8::Local obj + , v8::Local key + , v8::Local value) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->Set(isolate->GetCurrentContext(), key, value); +} + +inline Maybe Set( + v8::Local obj + , uint32_t index + , v8::Local value) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->Set(isolate->GetCurrentContext(), index, value); +} + +#if NODE_MODULE_VERSION < NODE_4_0_MODULE_VERSION +#include "nan_define_own_property_helper.h" // NOLINT(build/include_subdir) +#endif + +inline Maybe DefineOwnProperty( + v8::Local obj + , v8::Local key + , v8::Local value + , v8::PropertyAttribute attribs = v8::None) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); +#if NODE_MODULE_VERSION >= NODE_4_0_MODULE_VERSION + return obj->DefineOwnProperty(isolate->GetCurrentContext(), key, value, + attribs); +#else + Maybe maybeCurrent = + obj->GetPropertyAttributes(isolate->GetCurrentContext(), key); + if (maybeCurrent.IsNothing()) { + return Nothing(); + } + v8::PropertyAttribute current = maybeCurrent.FromJust(); + return imp::DefineOwnPropertyHelper(current, obj, key, value, attribs); +#endif +} + +NAN_DEPRECATED inline Maybe ForceSet( + v8::Local obj + , v8::Local key + , v8::Local value + , v8::PropertyAttribute attribs = v8::None) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); +#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION + return key->IsName() + ? obj->DefineOwnProperty(isolate->GetCurrentContext(), + key.As(), value, attribs) + : Nothing(); +#else + return obj->ForceSet(isolate->GetCurrentContext(), key, value, attribs); +#endif +} + +inline MaybeLocal Get( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(obj->Get(isolate->GetCurrentContext(), key) + .FromMaybe(v8::Local())); +} + +inline +MaybeLocal Get(v8::Local obj, uint32_t index) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(obj->Get(isolate->GetCurrentContext(), index) + .FromMaybe(v8::Local())); +} + +inline v8::PropertyAttribute GetPropertyAttributes( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->GetPropertyAttributes(isolate->GetCurrentContext(), key) + .FromJust(); +} + +inline Maybe Has( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->Has(isolate->GetCurrentContext(), key); +} + +inline Maybe Has(v8::Local obj, uint32_t index) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->Has(isolate->GetCurrentContext(), index); +} + +inline Maybe Delete( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->Delete(isolate->GetCurrentContext(), key); +} + +inline +Maybe Delete(v8::Local obj, uint32_t index) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->Delete(isolate->GetCurrentContext(), index); +} + +inline +MaybeLocal GetPropertyNames(v8::Local obj) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(obj->GetPropertyNames(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline +MaybeLocal GetOwnPropertyNames(v8::Local obj) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(obj->GetOwnPropertyNames(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline Maybe SetPrototype( + v8::Local obj + , v8::Local prototype) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION >= 14) + return obj->SetPrototypeV2(isolate->GetCurrentContext(), prototype); +#else + return obj->SetPrototype(isolate->GetCurrentContext(), prototype); +#endif +} + +inline MaybeLocal ObjectProtoToString( + v8::Local obj) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(obj->ObjectProtoToString(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline Maybe HasOwnProperty( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->HasOwnProperty(isolate->GetCurrentContext(), key); +} + +inline Maybe HasRealNamedProperty( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->HasRealNamedProperty(isolate->GetCurrentContext(), key); +} + +inline Maybe HasRealIndexedProperty( + v8::Local obj + , uint32_t index) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->HasRealIndexedProperty(isolate->GetCurrentContext(), index); +} + +inline Maybe HasRealNamedCallbackProperty( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return obj->HasRealNamedCallbackProperty(isolate->GetCurrentContext(), key); +} + +inline MaybeLocal GetRealNamedPropertyInPrototypeChain( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(obj->GetRealNamedPropertyInPrototypeChain( + isolate->GetCurrentContext(), key) + .FromMaybe(v8::Local())); +} + +inline MaybeLocal GetRealNamedProperty( + v8::Local obj + , v8::Local key) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape( + obj->GetRealNamedProperty(isolate->GetCurrentContext(), key) + .FromMaybe(v8::Local())); +} + +inline MaybeLocal CallAsFunction( + v8::Local obj + , v8::Local recv + , int argc + , v8::Local argv[]) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape( + obj->CallAsFunction(isolate->GetCurrentContext(), recv, argc, argv) + .FromMaybe(v8::Local())); +} + +inline MaybeLocal CallAsConstructor( + v8::Local obj + , int argc, v8::Local argv[]) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape( + obj->CallAsConstructor(isolate->GetCurrentContext(), argc, argv) + .FromMaybe(v8::Local())); +} + +inline +MaybeLocal GetSourceLine(v8::Local msg) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(msg->GetSourceLine(isolate->GetCurrentContext()) + .FromMaybe(v8::Local())); +} + +inline Maybe GetLineNumber(v8::Local msg) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return msg->GetLineNumber(isolate->GetCurrentContext()); +} + +inline Maybe GetStartColumn(v8::Local msg) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return msg->GetStartColumn(isolate->GetCurrentContext()); +} + +inline Maybe GetEndColumn(v8::Local msg) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + return msg->GetEndColumn(isolate->GetCurrentContext()); +} + +inline MaybeLocal CloneElementAt( + v8::Local array + , uint32_t index) { +#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION) + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::Local context = isolate->GetCurrentContext(); + v8::Local elem; + v8::Local obj; + if (!array->Get(context, index).ToLocal(&elem)) { + return scope.Escape(obj); + } + if (!elem->ToObject(context).ToLocal(&obj)) { + return scope.Escape(v8::Local()); + } + return scope.Escape(obj->Clone()); +#else + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(array->CloneElementAt(isolate->GetCurrentContext(), index) + .FromMaybe(v8::Local())); +#endif +} + +inline MaybeLocal Call( + v8::Local fun + , v8::Local recv + , int argc + , v8::Local argv[]) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + return scope.Escape(fun->Call(isolate->GetCurrentContext(), recv, argc, argv) + .FromMaybe(v8::Local())); +} + +#endif // NAN_MAYBE_43_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_pre_43_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_pre_43_inl.h new file mode 100644 index 0000000..84e2c11 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_maybe_pre_43_inl.h @@ -0,0 +1,268 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_MAYBE_PRE_43_INL_H_ +#define NAN_MAYBE_PRE_43_INL_H_ + +template +class MaybeLocal { + public: + inline MaybeLocal() : val_(v8::Local()) {} + + template +# if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION + inline + MaybeLocal(v8::Local that) : val_(that) {} // NOLINT(runtime/explicit) +# else + inline + MaybeLocal(v8::Local that) : // NOLINT(runtime/explicit) + val_(*reinterpret_cast*>(&that)) {} +# endif + + inline bool IsEmpty() const { return val_.IsEmpty(); } + + template + inline bool ToLocal(v8::Local *out) const { + *out = val_; + return !IsEmpty(); + } + + inline v8::Local ToLocalChecked() const { +#if defined(V8_ENABLE_CHECKS) + assert(!IsEmpty() && "ToLocalChecked is Empty"); +#endif // V8_ENABLE_CHECKS + return val_; + } + + template + inline v8::Local FromMaybe(v8::Local default_value) const { + return IsEmpty() ? default_value : v8::Local(val_); + } + + private: + v8::Local val_; +}; + +inline +MaybeLocal ToDetailString(v8::Handle val) { + return MaybeLocal(val->ToDetailString()); +} + +inline +MaybeLocal ToArrayIndex(v8::Handle val) { + return MaybeLocal(val->ToArrayIndex()); +} + +inline +Maybe Equals(v8::Handle a, v8::Handle(b)) { + return Just(a->Equals(b)); +} + +inline +MaybeLocal NewInstance(v8::Handle h) { + return MaybeLocal(h->NewInstance()); +} + +inline +MaybeLocal NewInstance( + v8::Local h + , int argc + , v8::Local argv[]) { + return MaybeLocal(h->NewInstance(argc, argv)); +} + +inline +MaybeLocal NewInstance(v8::Handle h) { + return MaybeLocal(h->NewInstance()); +} + +inline +MaybeLocal GetFunction(v8::Handle t) { + return MaybeLocal(t->GetFunction()); +} + +inline Maybe Set( + v8::Handle obj + , v8::Handle key + , v8::Handle value) { + return Just(obj->Set(key, value)); +} + +inline Maybe Set( + v8::Handle obj + , uint32_t index + , v8::Handle value) { + return Just(obj->Set(index, value)); +} + +#include "nan_define_own_property_helper.h" // NOLINT(build/include_subdir) + +inline Maybe DefineOwnProperty( + v8::Handle obj + , v8::Handle key + , v8::Handle value + , v8::PropertyAttribute attribs = v8::None) { + v8::PropertyAttribute current = obj->GetPropertyAttributes(key); + return imp::DefineOwnPropertyHelper(current, obj, key, value, attribs); +} + +NAN_DEPRECATED inline Maybe ForceSet( + v8::Handle obj + , v8::Handle key + , v8::Handle value + , v8::PropertyAttribute attribs = v8::None) { + return Just(obj->ForceSet(key, value, attribs)); +} + +inline MaybeLocal Get( + v8::Handle obj + , v8::Handle key) { + return MaybeLocal(obj->Get(key)); +} + +inline MaybeLocal Get( + v8::Handle obj + , uint32_t index) { + return MaybeLocal(obj->Get(index)); +} + +inline Maybe GetPropertyAttributes( + v8::Handle obj + , v8::Handle key) { + return Just(obj->GetPropertyAttributes(key)); +} + +inline Maybe Has( + v8::Handle obj + , v8::Handle key) { + return Just(obj->Has(key)); +} + +inline Maybe Has( + v8::Handle obj + , uint32_t index) { + return Just(obj->Has(index)); +} + +inline Maybe Delete( + v8::Handle obj + , v8::Handle key) { + return Just(obj->Delete(key)); +} + +inline Maybe Delete( + v8::Handle obj + , uint32_t index) { + return Just(obj->Delete(index)); +} + +inline +MaybeLocal GetPropertyNames(v8::Handle obj) { + return MaybeLocal(obj->GetPropertyNames()); +} + +inline +MaybeLocal GetOwnPropertyNames(v8::Handle obj) { + return MaybeLocal(obj->GetOwnPropertyNames()); +} + +inline Maybe SetPrototype( + v8::Handle obj + , v8::Handle prototype) { + return Just(obj->SetPrototype(prototype)); +} + +inline MaybeLocal ObjectProtoToString( + v8::Handle obj) { + return MaybeLocal(obj->ObjectProtoToString()); +} + +inline Maybe HasOwnProperty( + v8::Handle obj + , v8::Handle key) { + return Just(obj->HasOwnProperty(key)); +} + +inline Maybe HasRealNamedProperty( + v8::Handle obj + , v8::Handle key) { + return Just(obj->HasRealNamedProperty(key)); +} + +inline Maybe HasRealIndexedProperty( + v8::Handle obj + , uint32_t index) { + return Just(obj->HasRealIndexedProperty(index)); +} + +inline Maybe HasRealNamedCallbackProperty( + v8::Handle obj + , v8::Handle key) { + return Just(obj->HasRealNamedCallbackProperty(key)); +} + +inline MaybeLocal GetRealNamedPropertyInPrototypeChain( + v8::Handle obj + , v8::Handle key) { + return MaybeLocal( + obj->GetRealNamedPropertyInPrototypeChain(key)); +} + +inline MaybeLocal GetRealNamedProperty( + v8::Handle obj + , v8::Handle key) { + return MaybeLocal(obj->GetRealNamedProperty(key)); +} + +inline MaybeLocal CallAsFunction( + v8::Handle obj + , v8::Handle recv + , int argc + , v8::Handle argv[]) { + return MaybeLocal(obj->CallAsFunction(recv, argc, argv)); +} + +inline MaybeLocal CallAsConstructor( + v8::Handle obj + , int argc + , v8::Local argv[]) { + return MaybeLocal(obj->CallAsConstructor(argc, argv)); +} + +inline +MaybeLocal GetSourceLine(v8::Handle msg) { + return MaybeLocal(msg->GetSourceLine()); +} + +inline Maybe GetLineNumber(v8::Handle msg) { + return Just(msg->GetLineNumber()); +} + +inline Maybe GetStartColumn(v8::Handle msg) { + return Just(msg->GetStartColumn()); +} + +inline Maybe GetEndColumn(v8::Handle msg) { + return Just(msg->GetEndColumn()); +} + +inline MaybeLocal CloneElementAt( + v8::Handle array + , uint32_t index) { + return MaybeLocal(array->CloneElementAt(index)); +} + +inline MaybeLocal Call( + v8::Local fun + , v8::Local recv + , int argc + , v8::Local argv[]) { + return MaybeLocal(fun->Call(recv, argc, argv)); +} + +#endif // NAN_MAYBE_PRE_43_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_new.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_new.h new file mode 100644 index 0000000..cdf8bbe --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_new.h @@ -0,0 +1,340 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_NEW_H_ +#define NAN_NEW_H_ + +namespace imp { // scnr + +// TODO(agnat): Generalize +template v8::Local To(v8::Local i); + +template <> +inline +v8::Local +To(v8::Local i) { + return Nan::To(i).ToLocalChecked(); +} + +template <> +inline +v8::Local +To(v8::Local i) { + return Nan::To(i).ToLocalChecked(); +} + +template <> +inline +v8::Local +To(v8::Local i) { + return Nan::To(i).ToLocalChecked(); +} + +template struct FactoryBase { + typedef v8::Local return_t; +}; + +template struct MaybeFactoryBase { + typedef MaybeLocal return_t; +}; + +template struct Factory; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); + static inline return_t New(int length); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(bool value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(bool value); +}; + +template <> +struct Factory : FactoryBase { + static inline + return_t + New( v8::ExtensionConfiguration* extensions = NULL + , v8::Local tmpl = v8::Local() + , v8::Local obj = v8::Local()); +}; + +template <> +struct Factory : MaybeFactoryBase { + static inline return_t New(double value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(void *value); +}; + +template <> +struct Factory : FactoryBase { + static inline + return_t + New( FunctionCallback callback + , v8::Local data = v8::Local()); +}; + +template <> +struct Factory : FactoryBase { + static inline + return_t + New( FunctionCallback callback = NULL + , v8::Local data = v8::Local() + , v8::Local signature = v8::Local()); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(double value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(double value); +}; + +template +struct IntegerFactory : FactoryBase { + typedef typename FactoryBase::return_t return_t; + static inline return_t New(int32_t value); + static inline return_t New(uint32_t value); +}; + +template <> +struct Factory : IntegerFactory {}; + +template <> +struct Factory : IntegerFactory {}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(int32_t value); + static inline return_t New(uint32_t value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(); +}; + +template <> +struct Factory : MaybeFactoryBase { + static inline return_t New( + v8::Local pattern, v8::RegExp::Flags flags); +}; + +template <> +struct Factory : MaybeFactoryBase { + static inline return_t New( v8::Local source); + static inline return_t New( v8::Local source + , v8::ScriptOrigin const& origin); +}; + +template <> +struct Factory : FactoryBase { + typedef v8::Local FTH; + static inline return_t New(FTH receiver = FTH()); +}; + +template <> +struct Factory : MaybeFactoryBase { + static inline return_t New(); + static inline return_t New(const char *value, int length = -1); + static inline return_t New(const uint16_t *value, int length = -1); + static inline return_t New(std::string const& value); + + static inline return_t New(v8::String::ExternalStringResource * value); + static inline return_t New(ExternalOneByteStringResource * value); +}; + +template <> +struct Factory : FactoryBase { + static inline return_t New(v8::Local value); +}; + +} // end of namespace imp + +#if (NODE_MODULE_VERSION >= 12) + +namespace imp { + +template <> +struct Factory : MaybeFactoryBase { + static inline return_t New( v8::Local source); + static inline return_t New( v8::Local source + , v8::ScriptOrigin const& origin); +}; + +} // end of namespace imp + +# include "nan_implementation_12_inl.h" + +#else // NODE_MODULE_VERSION >= 12 + +# include "nan_implementation_pre_12_inl.h" + +#endif + +//=== API ====================================================================== + +template +typename imp::Factory::return_t +New() { + return imp::Factory::New(); +} + +template +typename imp::Factory::return_t +New(A0 arg0) { + return imp::Factory::New(arg0); +} + +template +typename imp::Factory::return_t +New(A0 arg0, A1 arg1) { + return imp::Factory::New(arg0, arg1); +} + +template +typename imp::Factory::return_t +New(A0 arg0, A1 arg1, A2 arg2) { + return imp::Factory::New(arg0, arg1, arg2); +} + +template +typename imp::Factory::return_t +New(A0 arg0, A1 arg1, A2 arg2, A3 arg3) { + return imp::Factory::New(arg0, arg1, arg2, arg3); +} + +// Note(agnat): When passing overloaded function pointers to template functions +// as generic arguments the compiler needs help in picking the right overload. +// These two functions handle New and New with +// all argument variations. + +// v8::Function and v8::FunctionTemplate with one or two arguments +template +typename imp::Factory::return_t +New( FunctionCallback callback + , v8::Local data = v8::Local()) { + return imp::Factory::New(callback, data); +} + +// v8::Function and v8::FunctionTemplate with three arguments +template +typename imp::Factory::return_t +New( FunctionCallback callback + , v8::Local data = v8::Local() + , A2 a2 = A2()) { + return imp::Factory::New(callback, data, a2); +} + +// Convenience + +#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION +template inline v8::Local New(v8::Handle h); +#endif + +#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION +template + inline v8::Local New(v8::Persistent const& p); +#else +template inline v8::Local New(v8::Persistent const& p); +#endif +template +inline v8::Local New(Persistent const& p); +template +inline v8::Local New(Global const& p); + +inline +imp::Factory::return_t +New(bool value) { + return New(value); +} + +inline +imp::Factory::return_t +New(int32_t value) { + return New(value); +} + +inline +imp::Factory::return_t +New(uint32_t value) { + return New(value); +} + +inline +imp::Factory::return_t +New(double value) { + return New(value); +} + +inline +imp::Factory::return_t +New(std::string const& value) { // NOLINT(build/include_what_you_use) + return New(value); +} + +inline +imp::Factory::return_t +New(const char * value, int length) { + return New(value, length); +} + +inline +imp::Factory::return_t +New(const uint16_t * value, int length) { + return New(value, length); +} + +inline +imp::Factory::return_t +New(const char * value) { + return New(value); +} + +inline +imp::Factory::return_t +New(const uint16_t * value) { + return New(value); +} + +inline +imp::Factory::return_t +New(v8::String::ExternalStringResource * value) { + return New(value); +} + +inline +imp::Factory::return_t +New(ExternalOneByteStringResource * value) { + return New(value); +} + +inline +imp::Factory::return_t +New(v8::Local pattern, v8::RegExp::Flags flags) { + return New(pattern, flags); +} + +#endif // NAN_NEW_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_object_wrap.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_object_wrap.h new file mode 100644 index 0000000..78712f9 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_object_wrap.h @@ -0,0 +1,156 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_OBJECT_WRAP_H_ +#define NAN_OBJECT_WRAP_H_ + +class ObjectWrap { + public: + ObjectWrap() { + refs_ = 0; + } + + + virtual ~ObjectWrap() { + if (persistent().IsEmpty()) { + return; + } + + persistent().ClearWeak(); + persistent().Reset(); + } + + + template + static inline T* Unwrap(v8::Local object) { + assert(!object.IsEmpty()); + assert(object->InternalFieldCount() > 0); + // Cast to ObjectWrap before casting to T. A direct cast from void + // to T won't work right when T has more than one base class. + void* ptr = GetInternalFieldPointer(object, 0); + ObjectWrap* wrap = static_cast(ptr); + return static_cast(wrap); + } + + + inline v8::Local handle() const { + return New(handle_); + } + + + inline Persistent& persistent() { + return handle_; + } + + + protected: + inline void Wrap(v8::Local object) { + assert(persistent().IsEmpty()); + assert(object->InternalFieldCount() > 0); + SetInternalFieldPointer(object, 0, this); + persistent().Reset(object); + MakeWeak(); + } + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + + inline void MakeWeak() { + persistent().v8::PersistentBase::SetWeak( + this, WeakCallback, v8::WeakCallbackType::kParameter); +#if NODE_MAJOR_VERSION < 10 + // FIXME(bnoordhuis) Probably superfluous in older Node.js versions too. + persistent().MarkIndependent(); +#endif + } + +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + + inline void MakeWeak() { + persistent().v8::PersistentBase::SetWeak(this, WeakCallback); + persistent().MarkIndependent(); + } + +#else + + inline void MakeWeak() { + persistent().persistent.MakeWeak(this, WeakCallback); + persistent().MarkIndependent(); + } + +#endif + + /* Ref() marks the object as being attached to an event loop. + * Refed objects will not be garbage collected, even if + * all references are lost. + */ + virtual void Ref() { + assert(!persistent().IsEmpty()); + persistent().ClearWeak(); + refs_++; + } + + /* Unref() marks an object as detached from the event loop. This is its + * default state. When an object with a "weak" reference changes from + * attached to detached state it will be freed. Be careful not to access + * the object after making this call as it might be gone! + * (A "weak reference" means an object that only has a + * persistent handle.) + * + * DO NOT CALL THIS FROM DESTRUCTOR + */ + virtual void Unref() { + assert(!persistent().IsEmpty()); + assert(!persistent().IsWeak()); + assert(refs_ > 0); + if (--refs_ == 0) + MakeWeak(); + } + + int refs_; // ro + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(ObjectWrap) +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + + static void + WeakCallback(v8::WeakCallbackInfo const& info) { + ObjectWrap* wrap = info.GetParameter(); + assert(wrap->refs_ == 0); + wrap->handle_.Reset(); + delete wrap; + } + +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + + static void + WeakCallback(v8::WeakCallbackData const& data) { + ObjectWrap* wrap = data.GetParameter(); + assert(wrap->refs_ == 0); + assert(wrap->handle_.IsNearDeath()); + wrap->handle_.Reset(); + delete wrap; + } + +#else + + static void WeakCallback(v8::Persistent value, void *data) { + ObjectWrap *wrap = static_cast(data); + assert(wrap->refs_ == 0); + assert(wrap->handle_.IsNearDeath()); + wrap->handle_.Reset(); + delete wrap; + } + +#endif + Persistent handle_; +}; + + +#endif // NAN_OBJECT_WRAP_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_12_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_12_inl.h new file mode 100644 index 0000000..d9649e8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_12_inl.h @@ -0,0 +1,132 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_PERSISTENT_12_INL_H_ +#define NAN_PERSISTENT_12_INL_H_ + +template class Persistent : + public v8::Persistent { + public: + inline Persistent() : v8::Persistent() {} + + template inline Persistent(v8::Local that) : + v8::Persistent(v8::Isolate::GetCurrent(), that) {} + + template + inline + Persistent(const v8::Persistent &that) : // NOLINT(runtime/explicit) + v8::Persistent(v8::Isolate::GetCurrent(), that) {} + + inline void Reset() { v8::PersistentBase::Reset(); } + + template + inline void Reset(const v8::Local &other) { + v8::PersistentBase::Reset(v8::Isolate::GetCurrent(), other); + } + + template + inline void Reset(const v8::PersistentBase &other) { + v8::PersistentBase::Reset(v8::Isolate::GetCurrent(), other); + } + + template + inline void SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type); + + private: + inline T *operator*() const { return *PersistentBase::persistent; } + + template + inline void Copy(const Persistent &that) { + TYPE_CHECK(T, S); + + this->Reset(); + + if (!that.IsEmpty()) { + this->Reset(that); + M::Copy(that, this); + } + } +}; + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +template +class Global : public v8::Global { + public: + inline Global() : v8::Global() {} + + template inline Global(v8::Local that) : + v8::Global(v8::Isolate::GetCurrent(), that) {} + + template + inline + Global(const v8::PersistentBase &that) : // NOLINT(runtime/explicit) + v8::Global(v8::Isolate::GetCurrent(), that) {} + + inline void Reset() { v8::PersistentBase::Reset(); } + + template + inline void Reset(const v8::Local &other) { + v8::PersistentBase::Reset(v8::Isolate::GetCurrent(), other); + } + + template + inline void Reset(const v8::PersistentBase &other) { + v8::PersistentBase::Reset(v8::Isolate::GetCurrent(), other); + } + + template + inline void SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + reinterpret_cast*>(this)->SetWeak( + parameter, callback, type); + } +}; +#else +template +class Global : public v8::UniquePersistent { + public: + inline Global() : v8::UniquePersistent() {} + + template inline Global(v8::Local that) : + v8::UniquePersistent(v8::Isolate::GetCurrent(), that) {} + + template + inline + Global(const v8::PersistentBase &that) : // NOLINT(runtime/explicit) + v8::UniquePersistent(v8::Isolate::GetCurrent(), that) {} + + inline void Reset() { v8::PersistentBase::Reset(); } + + template + inline void Reset(const v8::Local &other) { + v8::PersistentBase::Reset(v8::Isolate::GetCurrent(), other); + } + + template + inline void Reset(const v8::PersistentBase &other) { + v8::PersistentBase::Reset(v8::Isolate::GetCurrent(), other); + } + + template + inline void SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + reinterpret_cast*>(this)->SetWeak( + parameter, callback, type); + } +}; +#endif + +#endif // NAN_PERSISTENT_12_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_pre_12_inl.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_pre_12_inl.h new file mode 100644 index 0000000..4c9c59d --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_persistent_pre_12_inl.h @@ -0,0 +1,242 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_PERSISTENT_PRE_12_INL_H_ +#define NAN_PERSISTENT_PRE_12_INL_H_ + +template +class PersistentBase { + v8::Persistent persistent; + template + friend v8::Local New(const PersistentBase &p); + template + friend v8::Local New(const Persistent &p); + template + friend v8::Local New(const Global &p); + template friend class ReturnValue; + + public: + inline PersistentBase() : + persistent() {} + + inline void Reset() { + persistent.Dispose(); + persistent.Clear(); + } + + template + inline void Reset(const v8::Local &other) { + TYPE_CHECK(T, S); + + if (!persistent.IsEmpty()) { + persistent.Dispose(); + } + + if (other.IsEmpty()) { + persistent.Clear(); + } else { + persistent = v8::Persistent::New(other); + } + } + + template + inline void Reset(const PersistentBase &other) { + TYPE_CHECK(T, S); + + if (!persistent.IsEmpty()) { + persistent.Dispose(); + } + + if (other.IsEmpty()) { + persistent.Clear(); + } else { + persistent = v8::Persistent::New(other.persistent); + } + } + + inline bool IsEmpty() const { return persistent.IsEmpty(); } + + inline void Empty() { persistent.Clear(); } + + template + inline bool operator==(const PersistentBase &that) const { + return this->persistent == that.persistent; + } + + template + inline bool operator==(const v8::Local &that) const { + return this->persistent == that; + } + + template + inline bool operator!=(const PersistentBase &that) const { + return !operator==(that); + } + + template + inline bool operator!=(const v8::Local &that) const { + return !operator==(that); + } + + template + inline void SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type); + + inline void ClearWeak() { persistent.ClearWeak(); } + + inline void MarkIndependent() { persistent.MarkIndependent(); } + + inline bool IsIndependent() const { return persistent.IsIndependent(); } + + inline bool IsNearDeath() const { return persistent.IsNearDeath(); } + + inline bool IsWeak() const { return persistent.IsWeak(); } + + private: + inline explicit PersistentBase(v8::Persistent that) : + persistent(that) { } + inline explicit PersistentBase(T *val) : persistent(val) {} + template friend class Persistent; + template friend class Global; + friend class ObjectWrap; +}; + +template +class NonCopyablePersistentTraits { + public: + typedef Persistent > + NonCopyablePersistent; + static const bool kResetInDestructor = false; + template + inline static void Copy(const Persistent &source, + NonCopyablePersistent *dest) { + Uncompilable(); + } + + template inline static void Uncompilable() { + TYPE_CHECK(O, v8::Primitive); + } +}; + +template +struct CopyablePersistentTraits { + typedef Persistent > CopyablePersistent; + static const bool kResetInDestructor = true; + template + static inline void Copy(const Persistent &source, + CopyablePersistent *dest) {} +}; + +template class Persistent : + public PersistentBase { + public: + inline Persistent() {} + + template inline Persistent(v8::Handle that) + : PersistentBase(v8::Persistent::New(that)) { + TYPE_CHECK(T, S); + } + + inline Persistent(const Persistent &that) : PersistentBase() { + Copy(that); + } + + template + inline Persistent(const Persistent &that) : + PersistentBase() { + Copy(that); + } + + inline Persistent &operator=(const Persistent &that) { + Copy(that); + return *this; + } + + template + inline Persistent &operator=(const Persistent &that) { + Copy(that); + return *this; + } + + inline ~Persistent() { + if (M::kResetInDestructor) this->Reset(); + } + + private: + inline T *operator*() const { return *PersistentBase::persistent; } + + template + inline void Copy(const Persistent &that) { + TYPE_CHECK(T, S); + + this->Reset(); + + if (!that.IsEmpty()) { + this->persistent = v8::Persistent::New(that.persistent); + M::Copy(that, this); + } + } +}; + +template +class Global : public PersistentBase { + struct RValue { + inline explicit RValue(Global* obj) : object(obj) {} + Global* object; + }; + + public: + inline Global() : PersistentBase(0) { } + + template + inline Global(v8::Local that) // NOLINT(runtime/explicit) + : PersistentBase(v8::Persistent::New(that)) { + TYPE_CHECK(T, S); + } + + template + inline Global(const PersistentBase &that) // NOLINT(runtime/explicit) + : PersistentBase(that) { + TYPE_CHECK(T, S); + } + /** + * Move constructor. + */ + inline Global(RValue rvalue) // NOLINT(runtime/explicit) + : PersistentBase(rvalue.object->persistent) { + rvalue.object->Reset(); + } + inline ~Global() { this->Reset(); } + /** + * Move via assignment. + */ + template + inline Global &operator=(Global rhs) { + TYPE_CHECK(T, S); + this->Reset(rhs.persistent); + rhs.Reset(); + return *this; + } + /** + * Cast operator for moves. + */ + inline operator RValue() { return RValue(this); } + /** + * Pass allows returning uniques from functions, etc. + */ + Global Pass() { return Global(RValue(this)); } + + private: + Global(Global &); + void operator=(Global &); + template friend class ReturnValue; +}; + +#endif // NAN_PERSISTENT_PRE_12_INL_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_private.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_private.h new file mode 100644 index 0000000..15f44cc --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_private.h @@ -0,0 +1,73 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_PRIVATE_H_ +#define NAN_PRIVATE_H_ + +inline Maybe +HasPrivate(v8::Local object, v8::Local key) { + HandleScope scope; +#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::Local context = isolate->GetCurrentContext(); + v8::Local private_key = v8::Private::ForApi(isolate, key); + return object->HasPrivate(context, private_key); +#else + return Just(!object->GetHiddenValue(key).IsEmpty()); +#endif +} + +inline MaybeLocal +GetPrivate(v8::Local object, v8::Local key) { +#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); + v8::Local context = isolate->GetCurrentContext(); + v8::Local private_key = v8::Private::ForApi(isolate, key); + v8::MaybeLocal v = object->GetPrivate(context, private_key); + return scope.Escape(v.ToLocalChecked()); +#else + EscapableHandleScope scope; + v8::Local v = object->GetHiddenValue(key); + if (v.IsEmpty()) { + v = Undefined(); + } + return scope.Escape(v); +#endif +} + +inline Maybe SetPrivate( + v8::Local object, + v8::Local key, + v8::Local value) { +#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION + HandleScope scope; + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::Local context = isolate->GetCurrentContext(); + v8::Local private_key = v8::Private::ForApi(isolate, key); + return object->SetPrivate(context, private_key, value); +#else + return Just(object->SetHiddenValue(key, value)); +#endif +} + +inline Maybe DeletePrivate( + v8::Local object, + v8::Local key) { +#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION + HandleScope scope; + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::Local private_key = v8::Private::ForApi(isolate, key); + return object->DeletePrivate(isolate->GetCurrentContext(), private_key); +#else + return Just(object->DeleteHiddenValue(key)); +#endif +} + +#endif // NAN_PRIVATE_H_ + diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_scriptorigin.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_scriptorigin.h new file mode 100644 index 0000000..6d8251f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_scriptorigin.h @@ -0,0 +1,97 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2021 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_SCRIPTORIGIN_H_ +#define NAN_SCRIPTORIGIN_H_ + +class ScriptOrigin : public v8::ScriptOrigin { + public: +#if defined(V8_MAJOR_VERSION) && \ + (V8_MAJOR_VERSION > 12 || \ + (V8_MAJOR_VERSION == 12 && \ + (defined(V8_MINOR_VERSION) && \ + (V8_MINOR_VERSION > 6 || \ + (V8_MINOR_VERSION == 6 && defined(V8_BUILD_NUMBER) && \ + V8_BUILD_NUMBER >= 175))))) + explicit ScriptOrigin(v8::Local name) : + v8::ScriptOrigin(name) {} + + ScriptOrigin(v8::Local name + , v8::Local line) : + v8::ScriptOrigin(name + , To(line).FromMaybe(0)) {} + + ScriptOrigin(v8::Local name + , v8::Local line + , v8::Local column) : + v8::ScriptOrigin(name + , To(line).FromMaybe(0) + , To(column).FromMaybe(0)) {} +#elif defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 9 || \ + (V8_MAJOR_VERSION == 9 && (defined(V8_MINOR_VERSION) && (V8_MINOR_VERSION > 0\ + || (V8_MINOR_VERSION == 0 && defined(V8_BUILD_NUMBER) \ + && V8_BUILD_NUMBER >= 1))))) + explicit ScriptOrigin(v8::Local name) : + v8::ScriptOrigin(v8::Isolate::GetCurrent(), name) {} + + ScriptOrigin(v8::Local name + , v8::Local line) : + v8::ScriptOrigin(v8::Isolate::GetCurrent() + , name + , To(line).FromMaybe(0)) {} + + ScriptOrigin(v8::Local name + , v8::Local line + , v8::Local column) : + v8::ScriptOrigin(v8::Isolate::GetCurrent() + , name + , To(line).FromMaybe(0) + , To(column).FromMaybe(0)) {} +#elif defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 8 || \ + (V8_MAJOR_VERSION == 8 && (defined(V8_MINOR_VERSION) && (V8_MINOR_VERSION > 9\ + || (V8_MINOR_VERSION == 9 && defined(V8_BUILD_NUMBER) \ + && V8_BUILD_NUMBER >= 45))))) + explicit ScriptOrigin(v8::Local name) : v8::ScriptOrigin(name) {} + + ScriptOrigin(v8::Local name + , v8::Local line) : + v8::ScriptOrigin(name, To(line).FromMaybe(0)) {} + + ScriptOrigin(v8::Local name + , v8::Local line + , v8::Local column) : + v8::ScriptOrigin(name + , To(line).FromMaybe(0) + , To(column).FromMaybe(0)) {} +#else + explicit ScriptOrigin(v8::Local name) : v8::ScriptOrigin(name) {} + + ScriptOrigin(v8::Local name + , v8::Local line) : v8::ScriptOrigin(name, line) {} + + ScriptOrigin(v8::Local name + , v8::Local line + , v8::Local column) : + v8::ScriptOrigin(name, line, column) {} +#endif + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 8 || \ + (V8_MAJOR_VERSION == 8 && (defined(V8_MINOR_VERSION) && (V8_MINOR_VERSION > 9\ + || (V8_MINOR_VERSION == 9 && defined(V8_BUILD_NUMBER) \ + && V8_BUILD_NUMBER >= 45))))) + v8::Local ResourceLineOffset() const { + return New(LineOffset()); + } + + v8::Local ResourceColumnOffset() const { + return New(ColumnOffset()); + } +#endif +}; + +#endif // NAN_SCRIPTORIGIN_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_string_bytes.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_string_bytes.h new file mode 100644 index 0000000..a2e6437 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_string_bytes.h @@ -0,0 +1,305 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +#ifndef NAN_STRING_BYTES_H_ +#define NAN_STRING_BYTES_H_ + +// Decodes a v8::Local or Buffer to a raw char* + +namespace imp { + +using v8::Local; +using v8::Object; +using v8::String; +using v8::Value; + + +//// Base 64 //// + +#define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4) + + + +//// HEX //// + +static bool contains_non_ascii_slow(const char* buf, size_t len) { + for (size_t i = 0; i < len; ++i) { + if (buf[i] & 0x80) return true; + } + return false; +} + + +static bool contains_non_ascii(const char* src, size_t len) { + if (len < 16) { + return contains_non_ascii_slow(src, len); + } + + const unsigned bytes_per_word = sizeof(void*); + const unsigned align_mask = bytes_per_word - 1; + const unsigned unaligned = reinterpret_cast(src) & align_mask; + + if (unaligned > 0) { + const unsigned n = bytes_per_word - unaligned; + if (contains_non_ascii_slow(src, n)) return true; + src += n; + len -= n; + } + + +#if defined(__x86_64__) || defined(_WIN64) + const uintptr_t mask = 0x8080808080808080ll; +#else + const uintptr_t mask = 0x80808080l; +#endif + + const uintptr_t* srcw = reinterpret_cast(src); + + for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { + if (srcw[i] & mask) return true; + } + + const unsigned remainder = len & align_mask; + if (remainder > 0) { + const size_t offset = len - remainder; + if (contains_non_ascii_slow(src + offset, remainder)) return true; + } + + return false; +} + + +static void force_ascii_slow(const char* src, char* dst, size_t len) { + for (size_t i = 0; i < len; ++i) { + dst[i] = src[i] & 0x7f; + } +} + + +static void force_ascii(const char* src, char* dst, size_t len) { + if (len < 16) { + force_ascii_slow(src, dst, len); + return; + } + + const unsigned bytes_per_word = sizeof(void*); + const unsigned align_mask = bytes_per_word - 1; + const unsigned src_unalign = reinterpret_cast(src) & align_mask; + const unsigned dst_unalign = reinterpret_cast(dst) & align_mask; + + if (src_unalign > 0) { + if (src_unalign == dst_unalign) { + const unsigned unalign = bytes_per_word - src_unalign; + force_ascii_slow(src, dst, unalign); + src += unalign; + dst += unalign; + len -= src_unalign; + } else { + force_ascii_slow(src, dst, len); + return; + } + } + +#if defined(__x86_64__) || defined(_WIN64) + const uintptr_t mask = ~0x8080808080808080ll; +#else + const uintptr_t mask = ~0x80808080l; +#endif + + const uintptr_t* srcw = reinterpret_cast(src); + uintptr_t* dstw = reinterpret_cast(dst); + + for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { + dstw[i] = srcw[i] & mask; + } + + const unsigned remainder = len & align_mask; + if (remainder > 0) { + const size_t offset = len - remainder; + force_ascii_slow(src + offset, dst + offset, remainder); + } +} + + +static size_t base64_encode(const char* src, + size_t slen, + char* dst, + size_t dlen) { + // We know how much we'll write, just make sure that there's space. + assert(dlen >= base64_encoded_size(slen) && + "not enough space provided for base64 encode"); + + dlen = base64_encoded_size(slen); + + unsigned a; + unsigned b; + unsigned c; + unsigned i; + unsigned k; + unsigned n; + + static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + i = 0; + k = 0; + n = slen / 3 * 3; + + while (i < n) { + a = src[i + 0] & 0xff; + b = src[i + 1] & 0xff; + c = src[i + 2] & 0xff; + + dst[k + 0] = table[a >> 2]; + dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; + dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)]; + dst[k + 3] = table[c & 0x3f]; + + i += 3; + k += 4; + } + + if (n != slen) { + switch (slen - n) { + case 1: + a = src[i + 0] & 0xff; + dst[k + 0] = table[a >> 2]; + dst[k + 1] = table[(a & 3) << 4]; + dst[k + 2] = '='; + dst[k + 3] = '='; + break; + + case 2: + a = src[i + 0] & 0xff; + b = src[i + 1] & 0xff; + dst[k + 0] = table[a >> 2]; + dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; + dst[k + 2] = table[(b & 0x0f) << 2]; + dst[k + 3] = '='; + break; + } + } + + return dlen; +} + + +static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) { + // We know how much we'll write, just make sure that there's space. + assert(dlen >= slen * 2 && + "not enough space provided for hex encode"); + + dlen = slen * 2; + for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) { + static const char hex[] = "0123456789abcdef"; + uint8_t val = static_cast(src[i]); + dst[k + 0] = hex[val >> 4]; + dst[k + 1] = hex[val & 15]; + } + + return dlen; +} + + + +static Local Encode(const char* buf, + size_t buflen, + enum Encoding encoding) { + assert(buflen <= node::Buffer::kMaxLength); + if (!buflen && encoding != BUFFER) + return New("").ToLocalChecked(); + + Local val; + switch (encoding) { + case BUFFER: + return CopyBuffer(buf, buflen).ToLocalChecked(); + + case ASCII: + if (contains_non_ascii(buf, buflen)) { + char* out = new char[buflen]; + force_ascii(buf, out, buflen); + val = New(out, buflen).ToLocalChecked(); + delete[] out; + } else { + val = New(buf, buflen).ToLocalChecked(); + } + break; + + case UTF8: + val = New(buf, buflen).ToLocalChecked(); + break; + + case BINARY: { + // TODO(isaacs) use ExternalTwoByteString? + const unsigned char *cbuf = reinterpret_cast(buf); + uint16_t * twobytebuf = new uint16_t[buflen]; + for (size_t i = 0; i < buflen; i++) { + // XXX is the following line platform independent? + twobytebuf[i] = cbuf[i]; + } + val = New(twobytebuf, buflen).ToLocalChecked(); + delete[] twobytebuf; + break; + } + + case BASE64: { + size_t dlen = base64_encoded_size(buflen); + char* dst = new char[dlen]; + + size_t written = base64_encode(buf, buflen, dst, dlen); + assert(written == dlen); + + val = New(dst, dlen).ToLocalChecked(); + delete[] dst; + break; + } + + case UCS2: { + const uint16_t* data = reinterpret_cast(buf); + val = New(data, buflen / 2).ToLocalChecked(); + break; + } + + case HEX: { + size_t dlen = buflen * 2; + char* dst = new char[dlen]; + size_t written = hex_encode(buf, buflen, dst, dlen); + assert(written == dlen); + + val = New(dst, dlen).ToLocalChecked(); + delete[] dst; + break; + } + + default: + assert(0 && "unknown encoding"); + break; + } + + return val; +} + +#undef base64_encoded_size + +} // end of namespace imp + +#endif // NAN_STRING_BYTES_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_typedarray_contents.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_typedarray_contents.h new file mode 100644 index 0000000..f2650ed --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_typedarray_contents.h @@ -0,0 +1,96 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_TYPEDARRAY_CONTENTS_H_ +#define NAN_TYPEDARRAY_CONTENTS_H_ + +template +class TypedArrayContents { + public: + inline explicit TypedArrayContents(v8::Local from) : + length_(0), data_(NULL) { + HandleScope scope; + + size_t length = 0; + void* data = NULL; + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + + if (from->IsArrayBufferView()) { + v8::Local array = + v8::Local::Cast(from); + + const size_t byte_length = array->ByteLength(); + const ptrdiff_t byte_offset = array->ByteOffset(); + v8::Local buffer = array->Buffer(); + + length = byte_length / sizeof(T); +// Actually it's 7.9 here but this would lead to ABI issues with Node.js 13 +// using 7.8 till 13.2.0. +#if (V8_MAJOR_VERSION >= 8) + data = static_cast(buffer->GetBackingStore()->Data()) + byte_offset; +#else + data = static_cast(buffer->GetContents().Data()) + byte_offset; +#endif + } + +#else + + if (from->IsObject() && !from->IsNull()) { + v8::Local array = v8::Local::Cast(from); + + MaybeLocal buffer = Get(array, + New("buffer").ToLocalChecked()); + MaybeLocal byte_length = Get(array, + New("byteLength").ToLocalChecked()); + MaybeLocal byte_offset = Get(array, + New("byteOffset").ToLocalChecked()); + + if (!buffer.IsEmpty() && + !byte_length.IsEmpty() && byte_length.ToLocalChecked()->IsUint32() && + !byte_offset.IsEmpty() && byte_offset.ToLocalChecked()->IsUint32()) { + data = array->GetIndexedPropertiesExternalArrayData(); + if(data) { + length = byte_length.ToLocalChecked()->Uint32Value() / sizeof(T); + } + } + } + +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 || __cplusplus >= 201103L + assert(reinterpret_cast(data) % alignof (T) == 0); +#elif defined(_MSC_VER) && _MSC_VER >= 1600 || defined(__GNUC__) + assert(reinterpret_cast(data) % __alignof(T) == 0); +#else + assert(reinterpret_cast(data) % sizeof (T) == 0); +#endif + + length_ = length; + data_ = static_cast(data); + } + + inline size_t length() const { return length_; } + inline T* operator*() { return data_; } + inline const T* operator*() const { return data_; } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(TypedArrayContents) + + // Disable heap allocation + void *operator new(size_t size); + void operator delete(void *, size_t) { + abort(); + } + + size_t length_; + T* data_; +}; + +#endif // NAN_TYPEDARRAY_CONTENTS_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/nan_weak.h b/tasks/enduro-trails/prototype/node_modules/nan/nan_weak.h new file mode 100644 index 0000000..5a3a370 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/nan_weak.h @@ -0,0 +1,453 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef NAN_WEAK_H_ +#define NAN_WEAK_H_ + +static const int kInternalFieldsInWeakCallback = 2; +static const int kNoInternalFieldIndex = -1; + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +# define NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ \ + v8::WeakCallbackInfo > const& +# define NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ \ + NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +# define NAN_WEAK_PARAMETER_CALLBACK_SIG_ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +# define NAN_WEAK_TWOFIELD_CALLBACK_SIG_ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ +#elif NODE_MODULE_VERSION > IOJS_1_1_MODULE_VERSION +# define NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ \ + v8::PhantomCallbackData > const& +# define NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ \ + NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +# define NAN_WEAK_PARAMETER_CALLBACK_SIG_ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +# define NAN_WEAK_TWOFIELD_CALLBACK_SIG_ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ +#elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION +# define NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ \ + v8::PhantomCallbackData > const& +# define NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ \ + v8::InternalFieldsCallbackData, void> const& +# define NAN_WEAK_PARAMETER_CALLBACK_SIG_ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +# define NAN_WEAK_TWOFIELD_CALLBACK_SIG_ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION +# define NAN_WEAK_CALLBACK_DATA_TYPE_ \ + v8::WeakCallbackData > const& +# define NAN_WEAK_CALLBACK_SIG_ NAN_WEAK_CALLBACK_DATA_TYPE_ +#else +# define NAN_WEAK_CALLBACK_DATA_TYPE_ void * +# define NAN_WEAK_CALLBACK_SIG_ \ + v8::Persistent, NAN_WEAK_CALLBACK_DATA_TYPE_ +#endif + +template +class WeakCallbackInfo { + public: + typedef void (*Callback)(const WeakCallbackInfo& data); + WeakCallbackInfo( + Persistent *persistent + , Callback callback + , void *parameter + , void *field1 = 0 + , void *field2 = 0) : + callback_(callback), isolate_(0), parameter_(parameter) { + std::memcpy(&persistent_, persistent, sizeof (v8::Persistent)); + internal_fields_[0] = field1; + internal_fields_[1] = field2; + } + inline v8::Isolate *GetIsolate() const { return isolate_; } + inline T *GetParameter() const { return static_cast(parameter_); } + inline void *GetInternalField(int index) const { + assert((index == 0 || index == 1) && "internal field index out of bounds"); + if (index == 0) { + return internal_fields_[0]; + } else { + return internal_fields_[1]; + } + } + + private: + NAN_DISALLOW_ASSIGN_COPY_MOVE(WeakCallbackInfo) + Callback callback_; + v8::Isolate *isolate_; + void *parameter_; + void *internal_fields_[kInternalFieldsInWeakCallback]; + v8::Persistent persistent_; + template friend class Persistent; + template friend class PersistentBase; +#if NODE_MODULE_VERSION <= NODE_0_12_MODULE_VERSION +# if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + template + static void invoke(NAN_WEAK_CALLBACK_SIG_ data); + template + static WeakCallbackInfo *unwrap(NAN_WEAK_CALLBACK_DATA_TYPE_ data); +# else + static void invoke(NAN_WEAK_CALLBACK_SIG_ data); + static WeakCallbackInfo *unwrap(NAN_WEAK_CALLBACK_DATA_TYPE_ data); +# endif +#else +# if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + template + static void invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data); + template + static void invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data); +# else + static void invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data); + static void invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data); +# endif + static WeakCallbackInfo *unwrapparameter( + NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ data); + static WeakCallbackInfo *unwraptwofield( + NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ data); +#endif +}; + + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) + +template +template +void +WeakCallbackInfo::invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data) { + WeakCallbackInfo *cbinfo = unwrapparameter(data); + if (isFirstPass) { + cbinfo->persistent_.Reset(); + data.SetSecondPassCallback(invokeparameter); + } else { + cbinfo->callback_(*cbinfo); + delete cbinfo; + } +} + +template +template +void +WeakCallbackInfo::invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data) { + WeakCallbackInfo *cbinfo = unwraptwofield(data); + if (isFirstPass) { + cbinfo->persistent_.Reset(); + data.SetSecondPassCallback(invoketwofield); + } else { + cbinfo->callback_(*cbinfo); + delete cbinfo; + } +} + +template +WeakCallbackInfo *WeakCallbackInfo::unwrapparameter( + NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ data) { + WeakCallbackInfo *cbinfo = + static_cast*>(data.GetParameter()); + cbinfo->isolate_ = data.GetIsolate(); + return cbinfo; +} + +template +WeakCallbackInfo *WeakCallbackInfo::unwraptwofield( + NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ data) { + WeakCallbackInfo *cbinfo = + static_cast*>(data.GetInternalField(0)); + cbinfo->isolate_ = data.GetIsolate(); + return cbinfo; +} + +#undef NAN_WEAK_PARAMETER_CALLBACK_SIG_ +#undef NAN_WEAK_TWOFIELD_CALLBACK_SIG_ +#undef NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +#undef NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ +# elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION + +template +void +WeakCallbackInfo::invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data) { + WeakCallbackInfo *cbinfo = unwrapparameter(data); + cbinfo->persistent_.Reset(); + cbinfo->callback_(*cbinfo); + delete cbinfo; +} + +template +void +WeakCallbackInfo::invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data) { + WeakCallbackInfo *cbinfo = unwraptwofield(data); + cbinfo->persistent_.Reset(); + cbinfo->callback_(*cbinfo); + delete cbinfo; +} + +template +WeakCallbackInfo *WeakCallbackInfo::unwrapparameter( + NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ data) { + WeakCallbackInfo *cbinfo = + static_cast*>(data.GetParameter()); + cbinfo->isolate_ = data.GetIsolate(); + return cbinfo; +} + +template +WeakCallbackInfo *WeakCallbackInfo::unwraptwofield( + NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ data) { + WeakCallbackInfo *cbinfo = + static_cast*>(data.GetInternalField1()); + cbinfo->isolate_ = data.GetIsolate(); + return cbinfo; +} + +#undef NAN_WEAK_PARAMETER_CALLBACK_SIG_ +#undef NAN_WEAK_TWOFIELD_CALLBACK_SIG_ +#undef NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ +#undef NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION + +template +template +void WeakCallbackInfo::invoke(NAN_WEAK_CALLBACK_SIG_ data) { + WeakCallbackInfo *cbinfo = unwrap(data); + cbinfo->persistent_.Reset(); + cbinfo->callback_(*cbinfo); + delete cbinfo; +} + +template +template +WeakCallbackInfo *WeakCallbackInfo::unwrap( + NAN_WEAK_CALLBACK_DATA_TYPE_ data) { + void *parameter = data.GetParameter(); + WeakCallbackInfo *cbinfo = + static_cast*>(parameter); + cbinfo->isolate_ = data.GetIsolate(); + return cbinfo; +} + +#undef NAN_WEAK_CALLBACK_SIG_ +#undef NAN_WEAK_CALLBACK_DATA_TYPE_ +#else + +template +void WeakCallbackInfo::invoke(NAN_WEAK_CALLBACK_SIG_ data) { + WeakCallbackInfo *cbinfo = unwrap(data); + cbinfo->persistent_.Dispose(); + cbinfo->persistent_.Clear(); + cbinfo->callback_(*cbinfo); + delete cbinfo; +} + +template +WeakCallbackInfo *WeakCallbackInfo::unwrap( + NAN_WEAK_CALLBACK_DATA_TYPE_ data) { + WeakCallbackInfo *cbinfo = + static_cast*>(data); + cbinfo->isolate_ = v8::Isolate::GetCurrent(); + return cbinfo; +} + +#undef NAN_WEAK_CALLBACK_SIG_ +#undef NAN_WEAK_CALLBACK_DATA_TYPE_ +#endif + +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \ + (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3)) +template +template +inline void Persistent::SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + WeakCallbackInfo

*wcbd; + if (type == WeakCallbackType::kParameter) { + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , parameter); + v8::PersistentBase::SetWeak( + wcbd + , WeakCallbackInfo

::template invokeparameter + , type); + } else { + v8::Local* self_v(reinterpret_cast*>(this)); + assert((*self_v)->IsObject()); + v8::Local self((*self_v).As()); + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { +#if (V8_MAJOR_VERSION > 14) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION > 2) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 2 && V8_BUILD_NUMBER >= 194) + internal_fields[i] = self->GetAlignedPointerFromInternalField( + i, v8::kEmbedderDataTypeTagDefault + ); +# else + internal_fields[i] = self->GetAlignedPointerFromInternalField(i); +# endif + } + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , 0 + , internal_fields[0] + , internal_fields[1]); +#if (V8_MAJOR_VERSION > 14) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION > 2) || \ + (V8_MAJOR_VERSION == 14 && V8_MINOR_VERSION == 2 && V8_BUILD_NUMBER >= 194) + self->SetAlignedPointerInInternalField( + 0, wcbd, v8::kEmbedderDataTypeTagDefault + ); +# else + self->SetAlignedPointerInInternalField(0, wcbd); +# endif + v8::PersistentBase::SetWeak( + static_cast*>(0) + , WeakCallbackInfo

::template invoketwofield + , type); + } +} +#elif NODE_MODULE_VERSION > IOJS_1_1_MODULE_VERSION +template +template +inline void Persistent::SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + WeakCallbackInfo

*wcbd; + if (type == WeakCallbackType::kParameter) { + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , parameter); + v8::PersistentBase::SetPhantom( + wcbd + , WeakCallbackInfo

::invokeparameter); + } else { + v8::Local* self_v(reinterpret_cast*>(this)); + assert((*self_v)->IsObject()); + v8::Local self((*self_v).As()); + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { + internal_fields[i] = self->GetAlignedPointerFromInternalField(i); + } + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , 0 + , internal_fields[0] + , internal_fields[1]); + self->SetAlignedPointerInInternalField(0, wcbd); + v8::PersistentBase::SetPhantom( + static_cast*>(0) + , WeakCallbackInfo

::invoketwofield + , 0 + , count > 1 ? 1 : kNoInternalFieldIndex); + } +} +#elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION +template +template +inline void Persistent::SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + WeakCallbackInfo

*wcbd; + if (type == WeakCallbackType::kParameter) { + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , parameter); + v8::PersistentBase::SetPhantom( + wcbd + , WeakCallbackInfo

::invokeparameter); + } else { + v8::Local* self_v(reinterpret_cast*>(this)); + assert((*self_v)->IsObject()); + v8::Local self((*self_v).As()); + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { + internal_fields[i] = self->GetAlignedPointerFromInternalField(i); + } + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , 0 + , internal_fields[0] + , internal_fields[1]); + self->SetAlignedPointerInInternalField(0, wcbd); + v8::PersistentBase::SetPhantom( + WeakCallbackInfo

::invoketwofield + , 0 + , count > 1 ? 1 : kNoInternalFieldIndex); + } +} +#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION +template +template +inline void Persistent::SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + WeakCallbackInfo

*wcbd; + if (type == WeakCallbackType::kParameter) { + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , parameter); + v8::PersistentBase::SetWeak(wcbd, WeakCallbackInfo

::invoke); + } else { + v8::Local* self_v(reinterpret_cast*>(this)); + assert((*self_v)->IsObject()); + v8::Local self((*self_v).As()); + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { + internal_fields[i] = self->GetAlignedPointerFromInternalField(i); + } + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , 0 + , internal_fields[0] + , internal_fields[1]); + v8::PersistentBase::SetWeak(wcbd, WeakCallbackInfo

::invoke); + } +} +#else +template +template +inline void PersistentBase::SetWeak( + P *parameter + , typename WeakCallbackInfo

::Callback callback + , WeakCallbackType type) { + WeakCallbackInfo

*wcbd; + if (type == WeakCallbackType::kParameter) { + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , parameter); + persistent.MakeWeak(wcbd, WeakCallbackInfo

::invoke); + } else { + v8::Local* self_v(reinterpret_cast*>(this)); + assert((*self_v)->IsObject()); + v8::Local self((*self_v).As()); + int count = self->InternalFieldCount(); + void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0}; + for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) { + internal_fields[i] = self->GetPointerFromInternalField(i); + } + wcbd = new WeakCallbackInfo

( + reinterpret_cast*>(this) + , callback + , 0 + , internal_fields[0] + , internal_fields[1]); + persistent.MakeWeak(wcbd, WeakCallbackInfo

::invoke); + } +} +#endif + +#endif // NAN_WEAK_H_ diff --git a/tasks/enduro-trails/prototype/node_modules/nan/package.json b/tasks/enduro-trails/prototype/node_modules/nan/package.json new file mode 100644 index 0000000..2d0b0ca --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/package.json @@ -0,0 +1,38 @@ +{ + "name": "nan", + "version": "2.26.2", + "description": "Native Abstractions for Node.js: C++ header for Node 0.8 -> 25 compatibility", + "main": "include_dirs.js", + "repository": { + "type": "git", + "url": "git://github.com/nodejs/nan.git" + }, + "scripts": { + "test": "tap --gc --stderr test/js/*-test.js", + "test:worker": "node --experimental-worker test/tap-as-worker.js --gc --stderr test/js/*-test.js", + "rebuild-tests-2015": "node-gyp rebuild --msvs_version=2015 --directory test", + "rebuild-tests": "node-gyp rebuild --directory test", + "docs": "doc/.build.sh" + }, + "contributors": [ + "Rod Vagg (https://github.com/rvagg)", + "Benjamin Byholm (https://github.com/kkoopa/)", + "Trevor Norris (https://github.com/trevnorris)", + "Nathan Rajlich (https://github.com/TooTallNate)", + "Brett Lawson (https://github.com/brett19)", + "Ben Noordhuis (https://github.com/bnoordhuis)", + "David Siegel (https://github.com/agnat)", + "Michael Ira Krufky (https://github.com/mkrufky)" + ], + "devDependencies": { + "bindings": "~1.2.1", + "commander": "^2.8.1", + "glob": "^5.0.14", + "request": "=2.81.0", + "node-gyp": "~12.1.0", + "readable-stream": "^2.1.4", + "tap": "~0.7.1", + "xtend": "~4.0.0" + }, + "license": "MIT" +} diff --git a/tasks/enduro-trails/prototype/node_modules/nan/tools/1to2.js b/tasks/enduro-trails/prototype/node_modules/nan/tools/1to2.js new file mode 100755 index 0000000..bc44151 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/tools/1to2.js @@ -0,0 +1,412 @@ +#!/usr/bin/env node +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +var commander = require('commander'), + fs = require('fs'), + glob = require('glob'), + groups = [], + total = 0, + warning1 = '/* ERROR: Rewrite using Buffer */\n', + warning2 = '\\/\\* ERROR\\: Rewrite using Buffer \\*\\/\\n', + length, + i; + +fs.readFile(__dirname + '/package.json', 'utf8', function (err, data) { + if (err) { + throw err; + } + + commander + .version(JSON.parse(data).version) + .usage('[options] ') + .parse(process.argv); + + if (!process.argv.slice(2).length) { + commander.outputHelp(); + } +}); + +/* construct strings representing regular expressions + each expression contains a unique group allowing for identification of the match + the index of this key group, relative to the regular expression in question, + is indicated by the first array member */ + +/* simple substistutions, key group is the entire match, 0 */ +groups.push([0, [ + '_NAN_', + 'NODE_SET_METHOD', + 'NODE_SET_PROTOTYPE_METHOD', + 'NanAsciiString', + 'NanEscapeScope', + 'NanReturnValue', + 'NanUcs2String'].join('|')]); + +/* substitutions of parameterless macros, key group is 1 */ +groups.push([1, ['(', [ + 'NanEscapableScope', + 'NanReturnNull', + 'NanReturnUndefined', + 'NanScope'].join('|'), ')\\(\\)'].join('')]); + +/* replace TryCatch with NanTryCatch once, gobbling possible namespace, key group 2 */ +groups.push([2, '(?:(?:v8\\:\\:)?|(Nan)?)(TryCatch)']); + +/* NanNew("string") will likely not fail a ToLocalChecked(), key group 1 */ +groups.push([1, ['(NanNew)', '(\\("[^\\"]*"[^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]); + +/* Removed v8 APIs, warn that the code needs rewriting using node::Buffer, key group 2 */ +groups.push([2, ['(', warning2, ')?', '^.*?(', [ + 'GetIndexedPropertiesExternalArrayDataLength', + 'GetIndexedPropertiesExternalArrayData', + 'GetIndexedPropertiesExternalArrayDataType', + 'GetIndexedPropertiesPixelData', + 'GetIndexedPropertiesPixelDataLength', + 'HasIndexedPropertiesInExternalArrayData', + 'HasIndexedPropertiesInPixelData', + 'SetIndexedPropertiesToExternalArrayData', + 'SetIndexedPropertiesToPixelData'].join('|'), ')'].join('')]); + +/* No need for NanScope in V8-exposed methods, key group 2 */ +groups.push([2, ['((', [ + 'NAN_METHOD', + 'NAN_GETTER', + 'NAN_SETTER', + 'NAN_PROPERTY_GETTER', + 'NAN_PROPERTY_SETTER', + 'NAN_PROPERTY_ENUMERATOR', + 'NAN_PROPERTY_DELETER', + 'NAN_PROPERTY_QUERY', + 'NAN_INDEX_GETTER', + 'NAN_INDEX_SETTER', + 'NAN_INDEX_ENUMERATOR', + 'NAN_INDEX_DELETER', + 'NAN_INDEX_QUERY'].join('|'), ')\\([^\\)]*\\)\\s*\\{)\\s*NanScope\\(\\)\\s*;'].join('')]); + +/* v8::Value::ToXXXXXXX returns v8::MaybeLocal, key group 3 */ +groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->(', [ + 'Boolean', + 'Number', + 'String', + 'Object', + 'Integer', + 'Uint32', + 'Int32'].join('|'), ')\\('].join('')]); + +/* v8::Value::XXXXXXXValue returns v8::Maybe, key group 3 */ +groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->((?:', [ + 'Boolean', + 'Number', + 'Integer', + 'Uint32', + 'Int32'].join('|'), ')Value)\\('].join('')]); + +/* NAN_WEAK_CALLBACK macro was removed, write out callback definition, key group 1 */ +groups.push([1, '(NAN_WEAK_CALLBACK)\\(([^\\s\\)]+)\\)']); + +/* node::ObjectWrap and v8::Persistent have been replaced with Nan implementations, key group 1 */ +groups.push([1, ['(', [ + 'NanDisposePersistent', + 'NanObjectWrapHandle'].join('|'), ')\\s*\\(\\s*([^\\s\\)]+)'].join('')]); + +/* Since NanPersistent there is no need for NanMakeWeakPersistent, key group 1 */ +groups.push([1, '(NanMakeWeakPersistent)\\s*\\(\\s*([^\\s,]+)\\s*,\\s*']); + +/* Many methods of v8::Object and others now return v8::MaybeLocal, key group 3 */ +groups.push([3, ['([\\s])([^\\s]+)->(', [ + 'GetEndColumn', + 'GetFunction', + 'GetLineNumber', + 'NewInstance', + 'GetPropertyNames', + 'GetOwnPropertyNames', + 'GetSourceLine', + 'GetStartColumn', + 'ObjectProtoToString', + 'ToArrayIndex', + 'ToDetailString', + 'CallAsConstructor', + 'CallAsFunction', + 'CloneElementAt', + 'Delete', + 'ForceSet', + 'Get', + 'GetPropertyAttributes', + 'GetRealNamedProperty', + 'GetRealNamedPropertyInPrototypeChain', + 'Has', + 'HasOwnProperty', + 'HasRealIndexedProperty', + 'HasRealNamedCallbackProperty', + 'HasRealNamedProperty', + 'Set', + 'SetAccessor', + 'SetIndexedPropertyHandler', + 'SetNamedPropertyHandler', + 'SetPrototype'].join('|'), ')\\('].join('')]); + +/* You should get an error if any of these fail anyways, + or handle the error better, it is indicated either way, key group 2 */ +groups.push([2, ['NanNew(<(?:v8\\:\\:)?(', ['Date', 'String', 'RegExp'].join('|'), ')>)(\\([^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]); + +/* v8::Value::Equals now returns a v8::Maybe, key group 3 */ +groups.push([3, '([\\s\\(\\)])([^\\s\\(\\)]+)->(Equals)\\(([^\\s\\)]+)']); + +/* NanPersistent makes this unnecessary, key group 1 */ +groups.push([1, '(NanAssignPersistent)(?:]+>)?\\(([^,]+),\\s*']); + +/* args has been renamed to info, key group 2 */ +groups.push([2, '(\\W)(args)(\\W)']) + +/* node::ObjectWrap was replaced with NanObjectWrap, key group 2 */ +groups.push([2, '(\\W)(?:node\\:\\:)?(ObjectWrap)(\\W)']); + +/* v8::Persistent was replaced with NanPersistent, key group 2 */ +groups.push([2, '(\\W)(?:v8\\:\\:)?(Persistent)(\\W)']); + +/* counts the number of capturing groups in a well-formed regular expression, + ignoring non-capturing groups and escaped parentheses */ +function groupcount(s) { + var positive = s.match(/\((?!\?)/g), + negative = s.match(/\\\(/g); + return (positive ? positive.length : 0) - (negative ? negative.length : 0); +} + +/* compute the absolute position of each key group in the joined master RegExp */ +for (i = 1, length = groups.length; i < length; i++) { + total += groupcount(groups[i - 1][1]); + groups[i][0] += total; +} + +/* create the master RegExp, which is the union of all the groups' expressions */ +master = new RegExp(groups.map(function (a) { return a[1]; }).join('|'), 'gm'); + +/* replacement function for String.replace, receives 21 arguments */ +function replace() { + /* simple expressions */ + switch (arguments[groups[0][0]]) { + case '_NAN_': + return 'NAN_'; + case 'NODE_SET_METHOD': + return 'NanSetMethod'; + case 'NODE_SET_PROTOTYPE_METHOD': + return 'NanSetPrototypeMethod'; + case 'NanAsciiString': + return 'NanUtf8String'; + case 'NanEscapeScope': + return 'scope.Escape'; + case 'NanReturnNull': + return 'info.GetReturnValue().SetNull'; + case 'NanReturnValue': + return 'info.GetReturnValue().Set'; + case 'NanUcs2String': + return 'v8::String::Value'; + default: + } + + /* macros without arguments */ + switch (arguments[groups[1][0]]) { + case 'NanEscapableScope': + return 'NanEscapableScope scope' + case 'NanReturnUndefined': + return 'return'; + case 'NanScope': + return 'NanScope scope'; + default: + } + + /* TryCatch, emulate negative backref */ + if (arguments[groups[2][0]] === 'TryCatch') { + return arguments[groups[2][0] - 1] ? arguments[0] : 'NanTryCatch'; + } + + /* NanNew("foo") --> NanNew("foo").ToLocalChecked() */ + if (arguments[groups[3][0]] === 'NanNew') { + return [arguments[0], '.ToLocalChecked()'].join(''); + } + + /* insert warning for removed functions as comment on new line above */ + switch (arguments[groups[4][0]]) { + case 'GetIndexedPropertiesExternalArrayData': + case 'GetIndexedPropertiesExternalArrayDataLength': + case 'GetIndexedPropertiesExternalArrayDataType': + case 'GetIndexedPropertiesPixelData': + case 'GetIndexedPropertiesPixelDataLength': + case 'HasIndexedPropertiesInExternalArrayData': + case 'HasIndexedPropertiesInPixelData': + case 'SetIndexedPropertiesToExternalArrayData': + case 'SetIndexedPropertiesToPixelData': + return arguments[groups[4][0] - 1] ? arguments[0] : [warning1, arguments[0]].join(''); + default: + } + + /* remove unnecessary NanScope() */ + switch (arguments[groups[5][0]]) { + case 'NAN_GETTER': + case 'NAN_METHOD': + case 'NAN_SETTER': + case 'NAN_INDEX_DELETER': + case 'NAN_INDEX_ENUMERATOR': + case 'NAN_INDEX_GETTER': + case 'NAN_INDEX_QUERY': + case 'NAN_INDEX_SETTER': + case 'NAN_PROPERTY_DELETER': + case 'NAN_PROPERTY_ENUMERATOR': + case 'NAN_PROPERTY_GETTER': + case 'NAN_PROPERTY_QUERY': + case 'NAN_PROPERTY_SETTER': + return arguments[groups[5][0] - 1]; + default: + } + + /* Value conversion */ + switch (arguments[groups[6][0]]) { + case 'Boolean': + case 'Int32': + case 'Integer': + case 'Number': + case 'Object': + case 'String': + case 'Uint32': + return [arguments[groups[6][0] - 2], 'NanTo(', arguments[groups[6][0] - 1]].join(''); + default: + } + + /* other value conversion */ + switch (arguments[groups[7][0]]) { + case 'BooleanValue': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + case 'Int32Value': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + case 'IntegerValue': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + case 'Uint32Value': + return [arguments[groups[7][0] - 2], 'NanTo(', arguments[groups[7][0] - 1]].join(''); + default: + } + + /* NAN_WEAK_CALLBACK */ + if (arguments[groups[8][0]] === 'NAN_WEAK_CALLBACK') { + return ['template\nvoid ', + arguments[groups[8][0] + 1], '(const NanWeakCallbackInfo &data)'].join(''); + } + + /* use methods on NAN classes instead */ + switch (arguments[groups[9][0]]) { + case 'NanDisposePersistent': + return [arguments[groups[9][0] + 1], '.Reset('].join(''); + case 'NanObjectWrapHandle': + return [arguments[groups[9][0] + 1], '->handle('].join(''); + default: + } + + /* use method on NanPersistent instead */ + if (arguments[groups[10][0]] === 'NanMakeWeakPersistent') { + return arguments[groups[10][0] + 1] + '.SetWeak('; + } + + /* These return Maybes, the upper ones take no arguments */ + switch (arguments[groups[11][0]]) { + case 'GetEndColumn': + case 'GetFunction': + case 'GetLineNumber': + case 'GetOwnPropertyNames': + case 'GetPropertyNames': + case 'GetSourceLine': + case 'GetStartColumn': + case 'NewInstance': + case 'ObjectProtoToString': + case 'ToArrayIndex': + case 'ToDetailString': + return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1]].join(''); + case 'CallAsConstructor': + case 'CallAsFunction': + case 'CloneElementAt': + case 'Delete': + case 'ForceSet': + case 'Get': + case 'GetPropertyAttributes': + case 'GetRealNamedProperty': + case 'GetRealNamedPropertyInPrototypeChain': + case 'Has': + case 'HasOwnProperty': + case 'HasRealIndexedProperty': + case 'HasRealNamedCallbackProperty': + case 'HasRealNamedProperty': + case 'Set': + case 'SetAccessor': + case 'SetIndexedPropertyHandler': + case 'SetNamedPropertyHandler': + case 'SetPrototype': + return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1], ', '].join(''); + default: + } + + /* Automatic ToLocalChecked(), take it or leave it */ + switch (arguments[groups[12][0]]) { + case 'Date': + case 'String': + case 'RegExp': + return ['NanNew', arguments[groups[12][0] - 1], arguments[groups[12][0] + 1], '.ToLocalChecked()'].join(''); + default: + } + + /* NanEquals is now required for uniformity */ + if (arguments[groups[13][0]] === 'Equals') { + return [arguments[groups[13][0] - 1], 'NanEquals(', arguments[groups[13][0] - 1], ', ', arguments[groups[13][0] + 1]].join(''); + } + + /* use method on replacement class instead */ + if (arguments[groups[14][0]] === 'NanAssignPersistent') { + return [arguments[groups[14][0] + 1], '.Reset('].join(''); + } + + /* args --> info */ + if (arguments[groups[15][0]] === 'args') { + return [arguments[groups[15][0] - 1], 'info', arguments[groups[15][0] + 1]].join(''); + } + + /* ObjectWrap --> NanObjectWrap */ + if (arguments[groups[16][0]] === 'ObjectWrap') { + return [arguments[groups[16][0] - 1], 'NanObjectWrap', arguments[groups[16][0] + 1]].join(''); + } + + /* Persistent --> NanPersistent */ + if (arguments[groups[17][0]] === 'Persistent') { + return [arguments[groups[17][0] - 1], 'NanPersistent', arguments[groups[17][0] + 1]].join(''); + } + + /* This should not happen. A switch is probably missing a case if it does. */ + throw 'Unhandled match: ' + arguments[0]; +} + +/* reads a file, runs replacement and writes it back */ +function processFile(file) { + fs.readFile(file, {encoding: 'utf8'}, function (err, data) { + if (err) { + throw err; + } + + /* run replacement twice, might need more runs */ + fs.writeFile(file, data.replace(master, replace).replace(master, replace), function (err) { + if (err) { + throw err; + } + }); + }); +} + +/* process file names from command line and process the identified files */ +for (i = 2, length = process.argv.length; i < length; i++) { + glob(process.argv[i], function (err, matches) { + if (err) { + throw err; + } + matches.forEach(processFile); + }); +} diff --git a/tasks/enduro-trails/prototype/node_modules/nan/tools/README.md b/tasks/enduro-trails/prototype/node_modules/nan/tools/README.md new file mode 100644 index 0000000..7f07e4b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/tools/README.md @@ -0,0 +1,14 @@ +1to2 naively converts source code files from NAN 1 to NAN 2. There will be erroneous conversions, +false positives and missed opportunities. The input files are rewritten in place. Make sure that +you have backups. You will have to manually review the changes afterwards and do some touchups. + +```sh +$ tools/1to2.js + + Usage: 1to2 [options] + + Options: + + -h, --help output usage information + -V, --version output the version number +``` diff --git a/tasks/enduro-trails/prototype/node_modules/nan/tools/package.json b/tasks/enduro-trails/prototype/node_modules/nan/tools/package.json new file mode 100644 index 0000000..2dcdd78 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/nan/tools/package.json @@ -0,0 +1,19 @@ +{ + "name": "1to2", + "version": "1.0.0", + "description": "NAN 1 -> 2 Migration Script", + "main": "1to2.js", + "repository": { + "type": "git", + "url": "git://github.com/nodejs/nan.git" + }, + "contributors": [ + "Benjamin Byholm (https://github.com/kkoopa/)", + "Mathias Küsel (https://github.com/mathiask88/)" + ], + "dependencies": { + "glob": "~5.0.10", + "commander": "~2.8.1" + }, + "license": "MIT" +} diff --git a/tasks/enduro-trails/prototype/node_modules/safer-buffer/LICENSE b/tasks/enduro-trails/prototype/node_modules/safer-buffer/LICENSE new file mode 100644 index 0000000..4fe9e6f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Nikita Skovoroda + +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/tasks/enduro-trails/prototype/node_modules/safer-buffer/Porting-Buffer.md b/tasks/enduro-trails/prototype/node_modules/safer-buffer/Porting-Buffer.md new file mode 100644 index 0000000..68d86ba --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/Porting-Buffer.md @@ -0,0 +1,268 @@ +# Porting to the Buffer.from/Buffer.alloc API + + +## Overview + +- [Variant 1: Drop support for Node.js ≤ 4.4.x and 5.0.0 — 5.9.x.](#variant-1) (*recommended*) +- [Variant 2: Use a polyfill](#variant-2) +- [Variant 3: manual detection, with safeguards](#variant-3) + +### Finding problematic bits of code using grep + +Just run `grep -nrE '[^a-zA-Z](Slow)?Buffer\s*\(' --exclude-dir node_modules`. + +It will find all the potentially unsafe places in your own code (with some considerably unlikely +exceptions). + +### Finding problematic bits of code using Node.js 8 + +If you’re using Node.js ≥ 8.0.0 (which is recommended), Node.js exposes multiple options that help with finding the relevant pieces of code: + +- `--trace-warnings` will make Node.js show a stack trace for this warning and other warnings that are printed by Node.js. +- `--trace-deprecation` does the same thing, but only for deprecation warnings. +- `--pending-deprecation` will show more types of deprecation warnings. In particular, it will show the `Buffer()` deprecation warning, even on Node.js 8. + +You can set these flags using an environment variable: + +```console +$ export NODE_OPTIONS='--trace-warnings --pending-deprecation' +$ cat example.js +'use strict'; +const foo = new Buffer('foo'); +$ node example.js +(node:7147) [DEP0005] DeprecationWarning: The Buffer() and new Buffer() constructors are not recommended for use due to security and usability concerns. Please use the new Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() construction methods instead. + at showFlaggedDeprecation (buffer.js:127:13) + at new Buffer (buffer.js:148:3) + at Object. (/path/to/example.js:2:13) + [... more stack trace lines ...] +``` + +### Finding problematic bits of code using linters + +Eslint rules [no-buffer-constructor](https://eslint.org/docs/rules/no-buffer-constructor) +or +[node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) +also find calls to deprecated `Buffer()` API. Those rules are included in some pre-sets. + +There is a drawback, though, that it doesn't always +[work correctly](https://github.com/chalker/safer-buffer#why-not-safe-buffer) when `Buffer` is +overriden e.g. with a polyfill, so recommended is a combination of this and some other method +described above. + + +## Variant 1: Drop support for Node.js ≤ 4.4.x and 5.0.0 — 5.9.x. + +This is the recommended solution nowadays that would imply only minimal overhead. + +The Node.js 5.x release line has been unsupported since July 2016, and the Node.js 4.x release line reaches its End of Life in April 2018 (→ [Schedule](https://github.com/nodejs/Release#release-schedule)). This means that these versions of Node.js will *not* receive any updates, even in case of security issues, so using these release lines should be avoided, if at all possible. + +What you would do in this case is to convert all `new Buffer()` or `Buffer()` calls to use `Buffer.alloc()` or `Buffer.from()`, in the following way: + +- For `new Buffer(number)`, replace it with `Buffer.alloc(number)`. +- For `new Buffer(string)` (or `new Buffer(string, encoding)`), replace it with `Buffer.from(string)` (or `Buffer.from(string, encoding)`). +- For all other combinations of arguments (these are much rarer), also replace `new Buffer(...arguments)` with `Buffer.from(...arguments)`. + +Note that `Buffer.alloc()` is also _faster_ on the current Node.js versions than +`new Buffer(size).fill(0)`, which is what you would otherwise need to ensure zero-filling. + +Enabling eslint rule [no-buffer-constructor](https://eslint.org/docs/rules/no-buffer-constructor) +or +[node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) +is recommended to avoid accidential unsafe Buffer API usage. + +There is also a [JSCodeshift codemod](https://github.com/joyeecheung/node-dep-codemod#dep005) +for automatically migrating Buffer constructors to `Buffer.alloc()` or `Buffer.from()`. +Note that it currently only works with cases where the arguments are literals or where the +constructor is invoked with two arguments. + +_If you currently support those older Node.js versions and dropping them would be a semver-major change +for you, or if you support older branches of your packages, consider using [Variant 2](#variant-2) +or [Variant 3](#variant-3) on older branches, so people using those older branches will also receive +the fix. That way, you will eradicate potential issues caused by unguarded Buffer API usage and +your users will not observe a runtime deprecation warning when running your code on Node.js 10._ + + +## Variant 2: Use a polyfill + +Utilize [safer-buffer](https://www.npmjs.com/package/safer-buffer) as a polyfill to support older +Node.js versions. + +You would take exacly the same steps as in [Variant 1](#variant-1), but with a polyfill +`const Buffer = require('safer-buffer').Buffer` in all files where you use the new `Buffer` api. + +Make sure that you do not use old `new Buffer` API — in any files where the line above is added, +using old `new Buffer()` API will _throw_. It will be easy to notice that in CI, though. + +Alternatively, you could use [buffer-from](https://www.npmjs.com/package/buffer-from) and/or +[buffer-alloc](https://www.npmjs.com/package/buffer-alloc) [ponyfills](https://ponyfill.com/) — +those are great, the only downsides being 4 deps in the tree and slightly more code changes to +migrate off them (as you would be using e.g. `Buffer.from` under a different name). If you need only +`Buffer.from` polyfilled — `buffer-from` alone which comes with no extra dependencies. + +_Alternatively, you could use [safe-buffer](https://www.npmjs.com/package/safe-buffer) — it also +provides a polyfill, but takes a different approach which has +[it's drawbacks](https://github.com/chalker/safer-buffer#why-not-safe-buffer). It will allow you +to also use the older `new Buffer()` API in your code, though — but that's arguably a benefit, as +it is problematic, can cause issues in your code, and will start emitting runtime deprecation +warnings starting with Node.js 10._ + +Note that in either case, it is important that you also remove all calls to the old Buffer +API manually — just throwing in `safe-buffer` doesn't fix the problem by itself, it just provides +a polyfill for the new API. I have seen people doing that mistake. + +Enabling eslint rule [no-buffer-constructor](https://eslint.org/docs/rules/no-buffer-constructor) +or +[node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) +is recommended. + +_Don't forget to drop the polyfill usage once you drop support for Node.js < 4.5.0._ + + +## Variant 3 — manual detection, with safeguards + +This is useful if you create Buffer instances in only a few places (e.g. one), or you have your own +wrapper around them. + +### Buffer(0) + +This special case for creating empty buffers can be safely replaced with `Buffer.concat([])`, which +returns the same result all the way down to Node.js 0.8.x. + +### Buffer(notNumber) + +Before: + +```js +var buf = new Buffer(notNumber, encoding); +``` + +After: + +```js +var buf; +if (Buffer.from && Buffer.from !== Uint8Array.from) { + buf = Buffer.from(notNumber, encoding); +} else { + if (typeof notNumber === 'number') + throw new Error('The "size" argument must be of type number.'); + buf = new Buffer(notNumber, encoding); +} +``` + +`encoding` is optional. + +Note that the `typeof notNumber` before `new Buffer` is required (for cases when `notNumber` argument is not +hard-coded) and _is not caused by the deprecation of Buffer constructor_ — it's exactly _why_ the +Buffer constructor is deprecated. Ecosystem packages lacking this type-check caused numereous +security issues — situations when unsanitized user input could end up in the `Buffer(arg)` create +problems ranging from DoS to leaking sensitive information to the attacker from the process memory. + +When `notNumber` argument is hardcoded (e.g. literal `"abc"` or `[0,1,2]`), the `typeof` check can +be omitted. + +Also note that using TypeScript does not fix this problem for you — when libs written in +`TypeScript` are used from JS, or when user input ends up there — it behaves exactly as pure JS, as +all type checks are translation-time only and are not present in the actual JS code which TS +compiles to. + +### Buffer(number) + +For Node.js 0.10.x (and below) support: + +```js +var buf; +if (Buffer.alloc) { + buf = Buffer.alloc(number); +} else { + buf = new Buffer(number); + buf.fill(0); +} +``` + +Otherwise (Node.js ≥ 0.12.x): + +```js +const buf = Buffer.alloc ? Buffer.alloc(number) : new Buffer(number).fill(0); +``` + +## Regarding Buffer.allocUnsafe + +Be extra cautious when using `Buffer.allocUnsafe`: + * Don't use it if you don't have a good reason to + * e.g. you probably won't ever see a performance difference for small buffers, in fact, those + might be even faster with `Buffer.alloc()`, + * if your code is not in the hot code path — you also probably won't notice a difference, + * keep in mind that zero-filling minimizes the potential risks. + * If you use it, make sure that you never return the buffer in a partially-filled state, + * if you are writing to it sequentially — always truncate it to the actuall written length + +Errors in handling buffers allocated with `Buffer.allocUnsafe` could result in various issues, +ranged from undefined behaviour of your code to sensitive data (user input, passwords, certs) +leaking to the remote attacker. + +_Note that the same applies to `new Buffer` usage without zero-filling, depending on the Node.js +version (and lacking type checks also adds DoS to the list of potential problems)._ + + +## FAQ + + +### What is wrong with the `Buffer` constructor? + +The `Buffer` constructor could be used to create a buffer in many different ways: + +- `new Buffer(42)` creates a `Buffer` of 42 bytes. Before Node.js 8, this buffer contained + *arbitrary memory* for performance reasons, which could include anything ranging from + program source code to passwords and encryption keys. +- `new Buffer('abc')` creates a `Buffer` that contains the UTF-8-encoded version of + the string `'abc'`. A second argument could specify another encoding: For example, + `new Buffer(string, 'base64')` could be used to convert a Base64 string into the original + sequence of bytes that it represents. +- There are several other combinations of arguments. + +This meant that, in code like `var buffer = new Buffer(foo);`, *it is not possible to tell +what exactly the contents of the generated buffer are* without knowing the type of `foo`. + +Sometimes, the value of `foo` comes from an external source. For example, this function +could be exposed as a service on a web server, converting a UTF-8 string into its Base64 form: + +``` +function stringToBase64(req, res) { + // The request body should have the format of `{ string: 'foobar' }` + const rawBytes = new Buffer(req.body.string) + const encoded = rawBytes.toString('base64') + res.end({ encoded: encoded }) +} +``` + +Note that this code does *not* validate the type of `req.body.string`: + +- `req.body.string` is expected to be a string. If this is the case, all goes well. +- `req.body.string` is controlled by the client that sends the request. +- If `req.body.string` is the *number* `50`, the `rawBytes` would be 50 bytes: + - Before Node.js 8, the content would be uninitialized + - After Node.js 8, the content would be `50` bytes with the value `0` + +Because of the missing type check, an attacker could intentionally send a number +as part of the request. Using this, they can either: + +- Read uninitialized memory. This **will** leak passwords, encryption keys and other + kinds of sensitive information. (Information leak) +- Force the program to allocate a large amount of memory. For example, when specifying + `500000000` as the input value, each request will allocate 500MB of memory. + This can be used to either exhaust the memory available of a program completely + and make it crash, or slow it down significantly. (Denial of Service) + +Both of these scenarios are considered serious security issues in a real-world +web server context. + +when using `Buffer.from(req.body.string)` instead, passing a number will always +throw an exception instead, giving a controlled behaviour that can always be +handled by the program. + + +### The `Buffer()` constructor has been deprecated for a while. Is this really an issue? + +Surveys of code in the `npm` ecosystem have shown that the `Buffer()` constructor is still +widely used. This includes new code, and overall usage of such code has actually been +*increasing*. diff --git a/tasks/enduro-trails/prototype/node_modules/safer-buffer/Readme.md b/tasks/enduro-trails/prototype/node_modules/safer-buffer/Readme.md new file mode 100644 index 0000000..14b0822 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/Readme.md @@ -0,0 +1,156 @@ +# safer-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![javascript style guide][standard-image]][standard-url] [![Security Responsible Disclosure][secuirty-image]][secuirty-url] + +[travis-image]: https://travis-ci.org/ChALkeR/safer-buffer.svg?branch=master +[travis-url]: https://travis-ci.org/ChALkeR/safer-buffer +[npm-image]: https://img.shields.io/npm/v/safer-buffer.svg +[npm-url]: https://npmjs.org/package/safer-buffer +[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg +[standard-url]: https://standardjs.com +[secuirty-image]: https://img.shields.io/badge/Security-Responsible%20Disclosure-green.svg +[secuirty-url]: https://github.com/nodejs/security-wg/blob/master/processes/responsible_disclosure_template.md + +Modern Buffer API polyfill without footguns, working on Node.js from 0.8 to current. + +## How to use? + +First, port all `Buffer()` and `new Buffer()` calls to `Buffer.alloc()` and `Buffer.from()` API. + +Then, to achieve compatibility with outdated Node.js versions (`<4.5.0` and 5.x `<5.9.0`), use +`const Buffer = require('safer-buffer').Buffer` in all files where you make calls to the new +Buffer API. _Use `var` instead of `const` if you need that for your Node.js version range support._ + +Also, see the +[porting Buffer](https://github.com/ChALkeR/safer-buffer/blob/master/Porting-Buffer.md) guide. + +## Do I need it? + +Hopefully, not — dropping support for outdated Node.js versions should be fine nowdays, and that +is the recommended path forward. You _do_ need to port to the `Buffer.alloc()` and `Buffer.from()` +though. + +See the [porting guide](https://github.com/ChALkeR/safer-buffer/blob/master/Porting-Buffer.md) +for a better description. + +## Why not [safe-buffer](https://npmjs.com/safe-buffer)? + +_In short: while `safe-buffer` serves as a polyfill for the new API, it allows old API usage and +itself contains footguns._ + +`safe-buffer` could be used safely to get the new API while still keeping support for older +Node.js versions (like this module), but while analyzing ecosystem usage of the old Buffer API +I found out that `safe-buffer` is itself causing problems in some cases. + +For example, consider the following snippet: + +```console +$ cat example.unsafe.js +console.log(Buffer(20)) +$ ./node-v6.13.0-linux-x64/bin/node example.unsafe.js + +$ standard example.unsafe.js +standard: Use JavaScript Standard Style (https://standardjs.com) + /home/chalker/repo/safer-buffer/example.unsafe.js:2:13: 'Buffer()' was deprecated since v6. Use 'Buffer.alloc()' or 'Buffer.from()' (use 'https://www.npmjs.com/package/safe-buffer' for '<4.5.0') instead. +``` + +This is allocates and writes to console an uninitialized chunk of memory. +[standard](https://www.npmjs.com/package/standard) linter (among others) catch that and warn people +to avoid using unsafe API. + +Let's now throw in `safe-buffer`! + +```console +$ cat example.safe-buffer.js +const Buffer = require('safe-buffer').Buffer +console.log(Buffer(20)) +$ standard example.safe-buffer.js +$ ./node-v6.13.0-linux-x64/bin/node example.safe-buffer.js + +``` + +See the problem? Adding in `safe-buffer` _magically removes the lint warning_, but the behavior +remains identiсal to what we had before, and when launched on Node.js 6.x LTS — this dumps out +chunks of uninitialized memory. +_And this code will still emit runtime warnings on Node.js 10.x and above._ + +That was done by design. I first considered changing `safe-buffer`, prohibiting old API usage or +emitting warnings on it, but that significantly diverges from `safe-buffer` design. After some +discussion, it was decided to move my approach into a separate package, and _this is that separate +package_. + +This footgun is not imaginary — I observed top-downloaded packages doing that kind of thing, +«fixing» the lint warning by blindly including `safe-buffer` without any actual changes. + +Also in some cases, even if the API _was_ migrated to use of safe Buffer API — a random pull request +can bring unsafe Buffer API usage back to the codebase by adding new calls — and that could go +unnoticed even if you have a linter prohibiting that (becase of the reason stated above), and even +pass CI. _I also observed that being done in popular packages._ + +Some examples: + * [webdriverio](https://github.com/webdriverio/webdriverio/commit/05cbd3167c12e4930f09ef7cf93b127ba4effae4#diff-124380949022817b90b622871837d56cR31) + (a module with 548 759 downloads/month), + * [websocket-stream](https://github.com/maxogden/websocket-stream/commit/c9312bd24d08271687d76da0fe3c83493871cf61) + (218 288 d/m, fix in [maxogden/websocket-stream#142](https://github.com/maxogden/websocket-stream/pull/142)), + * [node-serialport](https://github.com/node-serialport/node-serialport/commit/e8d9d2b16c664224920ce1c895199b1ce2def48c) + (113 138 d/m, fix in [node-serialport/node-serialport#1510](https://github.com/node-serialport/node-serialport/pull/1510)), + * [karma](https://github.com/karma-runner/karma/commit/3d94b8cf18c695104ca195334dc75ff054c74eec) + (3 973 193 d/m, fix in [karma-runner/karma#2947](https://github.com/karma-runner/karma/pull/2947)), + * [spdy-transport](https://github.com/spdy-http2/spdy-transport/commit/5375ac33f4a62a4f65bcfc2827447d42a5dbe8b1) + (5 970 727 d/m, fix in [spdy-http2/spdy-transport#53](https://github.com/spdy-http2/spdy-transport/pull/53)). + * And there are a lot more over the ecosystem. + +I filed a PR at +[mysticatea/eslint-plugin-node#110](https://github.com/mysticatea/eslint-plugin-node/pull/110) to +partially fix that (for cases when that lint rule is used), but it is a semver-major change for +linter rules and presets, so it would take significant time for that to reach actual setups. +_It also hasn't been released yet (2018-03-20)._ + +Also, `safer-buffer` discourages the usage of `.allocUnsafe()`, which is often done by a mistake. +It still supports it with an explicit concern barier, by placing it under +`require('safer-buffer/dangereous')`. + +## But isn't throwing bad? + +Not really. It's an error that could be noticed and fixed early, instead of causing havoc later like +unguarded `new Buffer()` calls that end up receiving user input can do. + +This package affects only the files where `var Buffer = require('safer-buffer').Buffer` was done, so +it is really simple to keep track of things and make sure that you don't mix old API usage with that. +Also, CI should hint anything that you might have missed. + +New commits, if tested, won't land new usage of unsafe Buffer API this way. +_Node.js 10.x also deals with that by printing a runtime depecation warning._ + +### Would it affect third-party modules? + +No, unless you explicitly do an awful thing like monkey-patching or overriding the built-in `Buffer`. +Don't do that. + +### But I don't want throwing… + +That is also fine! + +Also, it could be better in some cases when you don't comprehensive enough test coverage. + +In that case — just don't override `Buffer` and use +`var SaferBuffer = require('safer-buffer').Buffer` instead. + +That way, everything using `Buffer` natively would still work, but there would be two drawbacks: + +* `Buffer.from`/`Buffer.alloc` won't be polyfilled — use `SaferBuffer.from` and + `SaferBuffer.alloc` instead. +* You are still open to accidentally using the insecure deprecated API — use a linter to catch that. + +Note that using a linter to catch accidential `Buffer` constructor usage in this case is strongly +recommended. `Buffer` is not overriden in this usecase, so linters won't get confused. + +## «Without footguns»? + +Well, it is still possible to do _some_ things with `Buffer` API, e.g. accessing `.buffer` property +on older versions and duping things from there. You shouldn't do that in your code, probabably. + +The intention is to remove the most significant footguns that affect lots of packages in the +ecosystem, and to do it in the proper way. + +Also, this package doesn't protect against security issues affecting some Node.js versions, so for +usage in your own production code, it is still recommended to update to a Node.js version +[supported by upstream](https://github.com/nodejs/release#release-schedule). diff --git a/tasks/enduro-trails/prototype/node_modules/safer-buffer/dangerous.js b/tasks/enduro-trails/prototype/node_modules/safer-buffer/dangerous.js new file mode 100644 index 0000000..ca41fdc --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/dangerous.js @@ -0,0 +1,58 @@ +/* eslint-disable node/no-deprecated-api */ + +'use strict' + +var buffer = require('buffer') +var Buffer = buffer.Buffer +var safer = require('./safer.js') +var Safer = safer.Buffer + +var dangerous = {} + +var key + +for (key in safer) { + if (!safer.hasOwnProperty(key)) continue + dangerous[key] = safer[key] +} + +var Dangereous = dangerous.Buffer = {} + +// Copy Safer API +for (key in Safer) { + if (!Safer.hasOwnProperty(key)) continue + Dangereous[key] = Safer[key] +} + +// Copy those missing unsafe methods, if they are present +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (Dangereous.hasOwnProperty(key)) continue + Dangereous[key] = Buffer[key] +} + +if (!Dangereous.allocUnsafe) { + Dangereous.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + return Buffer(size) + } +} + +if (!Dangereous.allocUnsafeSlow) { + Dangereous.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + return buffer.SlowBuffer(size) + } +} + +module.exports = dangerous diff --git a/tasks/enduro-trails/prototype/node_modules/safer-buffer/package.json b/tasks/enduro-trails/prototype/node_modules/safer-buffer/package.json new file mode 100644 index 0000000..d452b04 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/package.json @@ -0,0 +1,34 @@ +{ + "name": "safer-buffer", + "version": "2.1.2", + "description": "Modern Buffer API polyfill without footguns", + "main": "safer.js", + "scripts": { + "browserify-test": "browserify --external tape tests.js > browserify-tests.js && tape browserify-tests.js", + "test": "standard && tape tests.js" + }, + "author": { + "name": "Nikita Skovoroda", + "email": "chalkerx@gmail.com", + "url": "https://github.com/ChALkeR" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ChALkeR/safer-buffer.git" + }, + "bugs": { + "url": "https://github.com/ChALkeR/safer-buffer/issues" + }, + "devDependencies": { + "standard": "^11.0.1", + "tape": "^4.9.0" + }, + "files": [ + "Porting-Buffer.md", + "Readme.md", + "tests.js", + "dangerous.js", + "safer.js" + ] +} diff --git a/tasks/enduro-trails/prototype/node_modules/safer-buffer/safer.js b/tasks/enduro-trails/prototype/node_modules/safer-buffer/safer.js new file mode 100644 index 0000000..37c7e1a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/safer.js @@ -0,0 +1,77 @@ +/* eslint-disable node/no-deprecated-api */ + +'use strict' + +var buffer = require('buffer') +var Buffer = buffer.Buffer + +var safer = {} + +var key + +for (key in buffer) { + if (!buffer.hasOwnProperty(key)) continue + if (key === 'SlowBuffer' || key === 'Buffer') continue + safer[key] = buffer[key] +} + +var Safer = safer.Buffer = {} +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue + Safer[key] = Buffer[key] +} + +safer.Buffer.prototype = Buffer.prototype + +if (!Safer.from || Safer.from === Uint8Array.from) { + Safer.from = function (value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) + } + if (value && typeof value.length === 'undefined') { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) + } + return Buffer(value, encodingOrOffset, length) + } +} + +if (!Safer.alloc) { + Safer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + var buf = Buffer(size) + if (!fill || fill.length === 0) { + buf.fill(0) + } else if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + return buf + } +} + +if (!safer.kStringMaxLength) { + try { + safer.kStringMaxLength = process.binding('buffer').kStringMaxLength + } catch (e) { + // we can't determine kStringMaxLength in environments where process.binding + // is unsupported, so let's not set it + } +} + +if (!safer.constants) { + safer.constants = { + MAX_LENGTH: safer.kMaxLength + } + if (safer.kStringMaxLength) { + safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength + } +} + +module.exports = safer diff --git a/tasks/enduro-trails/prototype/node_modules/safer-buffer/tests.js b/tasks/enduro-trails/prototype/node_modules/safer-buffer/tests.js new file mode 100644 index 0000000..7ed2777 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/safer-buffer/tests.js @@ -0,0 +1,406 @@ +/* eslint-disable node/no-deprecated-api */ + +'use strict' + +var test = require('tape') + +var buffer = require('buffer') + +var index = require('./') +var safer = require('./safer') +var dangerous = require('./dangerous') + +/* Inheritance tests */ + +test('Default is Safer', function (t) { + t.equal(index, safer) + t.notEqual(safer, dangerous) + t.notEqual(index, dangerous) + t.end() +}) + +test('Is not a function', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(typeof impl, 'object') + t.equal(typeof impl.Buffer, 'object') + }); + [buffer].forEach(function (impl) { + t.equal(typeof impl, 'object') + t.equal(typeof impl.Buffer, 'function') + }) + t.end() +}) + +test('Constructor throws', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.throws(function () { impl.Buffer() }) + t.throws(function () { impl.Buffer(0) }) + t.throws(function () { impl.Buffer('a') }) + t.throws(function () { impl.Buffer('a', 'utf-8') }) + t.throws(function () { return new impl.Buffer() }) + t.throws(function () { return new impl.Buffer(0) }) + t.throws(function () { return new impl.Buffer('a') }) + t.throws(function () { return new impl.Buffer('a', 'utf-8') }) + }) + t.end() +}) + +test('Safe methods exist', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(typeof impl.Buffer.alloc, 'function', 'alloc') + t.equal(typeof impl.Buffer.from, 'function', 'from') + }) + t.end() +}) + +test('Unsafe methods exist only in Dangerous', function (t) { + [index, safer].forEach(function (impl) { + t.equal(typeof impl.Buffer.allocUnsafe, 'undefined') + t.equal(typeof impl.Buffer.allocUnsafeSlow, 'undefined') + }); + [dangerous].forEach(function (impl) { + t.equal(typeof impl.Buffer.allocUnsafe, 'function') + t.equal(typeof impl.Buffer.allocUnsafeSlow, 'function') + }) + t.end() +}) + +test('Generic methods/properties are defined and equal', function (t) { + ['poolSize', 'isBuffer', 'concat', 'byteLength'].forEach(function (method) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer[method], buffer.Buffer[method], method) + t.notEqual(typeof impl.Buffer[method], 'undefined', method) + }) + }) + t.end() +}) + +test('Built-in buffer static methods/properties are inherited', function (t) { + Object.keys(buffer).forEach(function (method) { + if (method === 'SlowBuffer' || method === 'Buffer') return; + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl[method], buffer[method], method) + t.notEqual(typeof impl[method], 'undefined', method) + }) + }) + t.end() +}) + +test('Built-in Buffer static methods/properties are inherited', function (t) { + Object.keys(buffer.Buffer).forEach(function (method) { + if (method === 'allocUnsafe' || method === 'allocUnsafeSlow') return; + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer[method], buffer.Buffer[method], method) + t.notEqual(typeof impl.Buffer[method], 'undefined', method) + }) + }) + t.end() +}) + +test('.prototype property of Buffer is inherited', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer.prototype, buffer.Buffer.prototype, 'prototype') + t.notEqual(typeof impl.Buffer.prototype, 'undefined', 'prototype') + }) + t.end() +}) + +test('All Safer methods are present in Dangerous', function (t) { + Object.keys(safer).forEach(function (method) { + if (method === 'Buffer') return; + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl[method], safer[method], method) + if (method !== 'kStringMaxLength') { + t.notEqual(typeof impl[method], 'undefined', method) + } + }) + }) + Object.keys(safer.Buffer).forEach(function (method) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer[method], safer.Buffer[method], method) + t.notEqual(typeof impl.Buffer[method], 'undefined', method) + }) + }) + t.end() +}) + +test('Safe methods from Dangerous methods are present in Safer', function (t) { + Object.keys(dangerous).forEach(function (method) { + if (method === 'Buffer') return; + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl[method], dangerous[method], method) + if (method !== 'kStringMaxLength') { + t.notEqual(typeof impl[method], 'undefined', method) + } + }) + }) + Object.keys(dangerous.Buffer).forEach(function (method) { + if (method === 'allocUnsafe' || method === 'allocUnsafeSlow') return; + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer[method], dangerous.Buffer[method], method) + t.notEqual(typeof impl.Buffer[method], 'undefined', method) + }) + }) + t.end() +}) + +/* Behaviour tests */ + +test('Methods return Buffers', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.ok(buffer.Buffer.isBuffer(impl.Buffer.alloc(0))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.alloc(0, 10))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.alloc(0, 'a'))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.alloc(10))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.alloc(10, 'x'))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.alloc(9, 'ab'))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from(''))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from('string'))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from('string', 'utf-8'))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from('b25ldHdvdGhyZWU=', 'base64'))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from([0, 42, 3]))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from(new Uint8Array([0, 42, 3])))) + t.ok(buffer.Buffer.isBuffer(impl.Buffer.from([]))) + }); + ['allocUnsafe', 'allocUnsafeSlow'].forEach(function (method) { + t.ok(buffer.Buffer.isBuffer(dangerous.Buffer[method](0))) + t.ok(buffer.Buffer.isBuffer(dangerous.Buffer[method](10))) + }) + t.end() +}) + +test('Constructor is buffer.Buffer', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer.alloc(0).constructor, buffer.Buffer) + t.equal(impl.Buffer.alloc(0, 10).constructor, buffer.Buffer) + t.equal(impl.Buffer.alloc(0, 'a').constructor, buffer.Buffer) + t.equal(impl.Buffer.alloc(10).constructor, buffer.Buffer) + t.equal(impl.Buffer.alloc(10, 'x').constructor, buffer.Buffer) + t.equal(impl.Buffer.alloc(9, 'ab').constructor, buffer.Buffer) + t.equal(impl.Buffer.from('').constructor, buffer.Buffer) + t.equal(impl.Buffer.from('string').constructor, buffer.Buffer) + t.equal(impl.Buffer.from('string', 'utf-8').constructor, buffer.Buffer) + t.equal(impl.Buffer.from('b25ldHdvdGhyZWU=', 'base64').constructor, buffer.Buffer) + t.equal(impl.Buffer.from([0, 42, 3]).constructor, buffer.Buffer) + t.equal(impl.Buffer.from(new Uint8Array([0, 42, 3])).constructor, buffer.Buffer) + t.equal(impl.Buffer.from([]).constructor, buffer.Buffer) + }); + [0, 10, 100].forEach(function (arg) { + t.equal(dangerous.Buffer.allocUnsafe(arg).constructor, buffer.Buffer) + t.equal(dangerous.Buffer.allocUnsafeSlow(arg).constructor, buffer.SlowBuffer(0).constructor) + }) + t.end() +}) + +test('Invalid calls throw', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.throws(function () { impl.Buffer.from(0) }) + t.throws(function () { impl.Buffer.from(10) }) + t.throws(function () { impl.Buffer.from(10, 'utf-8') }) + t.throws(function () { impl.Buffer.from('string', 'invalid encoding') }) + t.throws(function () { impl.Buffer.from(-10) }) + t.throws(function () { impl.Buffer.from(1e90) }) + t.throws(function () { impl.Buffer.from(Infinity) }) + t.throws(function () { impl.Buffer.from(-Infinity) }) + t.throws(function () { impl.Buffer.from(NaN) }) + t.throws(function () { impl.Buffer.from(null) }) + t.throws(function () { impl.Buffer.from(undefined) }) + t.throws(function () { impl.Buffer.from() }) + t.throws(function () { impl.Buffer.from({}) }) + t.throws(function () { impl.Buffer.alloc('') }) + t.throws(function () { impl.Buffer.alloc('string') }) + t.throws(function () { impl.Buffer.alloc('string', 'utf-8') }) + t.throws(function () { impl.Buffer.alloc('b25ldHdvdGhyZWU=', 'base64') }) + t.throws(function () { impl.Buffer.alloc(-10) }) + t.throws(function () { impl.Buffer.alloc(1e90) }) + t.throws(function () { impl.Buffer.alloc(2 * (1 << 30)) }) + t.throws(function () { impl.Buffer.alloc(Infinity) }) + t.throws(function () { impl.Buffer.alloc(-Infinity) }) + t.throws(function () { impl.Buffer.alloc(null) }) + t.throws(function () { impl.Buffer.alloc(undefined) }) + t.throws(function () { impl.Buffer.alloc() }) + t.throws(function () { impl.Buffer.alloc([]) }) + t.throws(function () { impl.Buffer.alloc([0, 42, 3]) }) + t.throws(function () { impl.Buffer.alloc({}) }) + }); + ['allocUnsafe', 'allocUnsafeSlow'].forEach(function (method) { + t.throws(function () { dangerous.Buffer[method]('') }) + t.throws(function () { dangerous.Buffer[method]('string') }) + t.throws(function () { dangerous.Buffer[method]('string', 'utf-8') }) + t.throws(function () { dangerous.Buffer[method](2 * (1 << 30)) }) + t.throws(function () { dangerous.Buffer[method](Infinity) }) + if (dangerous.Buffer[method] === buffer.Buffer.allocUnsafe) { + t.skip('Skipping, older impl of allocUnsafe coerced negative sizes to 0') + } else { + t.throws(function () { dangerous.Buffer[method](-10) }) + t.throws(function () { dangerous.Buffer[method](-1e90) }) + t.throws(function () { dangerous.Buffer[method](-Infinity) }) + } + t.throws(function () { dangerous.Buffer[method](null) }) + t.throws(function () { dangerous.Buffer[method](undefined) }) + t.throws(function () { dangerous.Buffer[method]() }) + t.throws(function () { dangerous.Buffer[method]([]) }) + t.throws(function () { dangerous.Buffer[method]([0, 42, 3]) }) + t.throws(function () { dangerous.Buffer[method]({}) }) + }) + t.end() +}) + +test('Buffers have appropriate lengths', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.equal(impl.Buffer.alloc(0).length, 0) + t.equal(impl.Buffer.alloc(10).length, 10) + t.equal(impl.Buffer.from('').length, 0) + t.equal(impl.Buffer.from('string').length, 6) + t.equal(impl.Buffer.from('string', 'utf-8').length, 6) + t.equal(impl.Buffer.from('b25ldHdvdGhyZWU=', 'base64').length, 11) + t.equal(impl.Buffer.from([0, 42, 3]).length, 3) + t.equal(impl.Buffer.from(new Uint8Array([0, 42, 3])).length, 3) + t.equal(impl.Buffer.from([]).length, 0) + }); + ['allocUnsafe', 'allocUnsafeSlow'].forEach(function (method) { + t.equal(dangerous.Buffer[method](0).length, 0) + t.equal(dangerous.Buffer[method](10).length, 10) + }) + t.end() +}) + +test('Buffers have appropriate lengths (2)', function (t) { + t.equal(index.Buffer.alloc, safer.Buffer.alloc) + t.equal(index.Buffer.alloc, dangerous.Buffer.alloc) + var ok = true; + [ safer.Buffer.alloc, + dangerous.Buffer.allocUnsafe, + dangerous.Buffer.allocUnsafeSlow + ].forEach(function (method) { + for (var i = 0; i < 1e2; i++) { + var length = Math.round(Math.random() * 1e5) + var buf = method(length) + if (!buffer.Buffer.isBuffer(buf)) ok = false + if (buf.length !== length) ok = false + } + }) + t.ok(ok) + t.end() +}) + +test('.alloc(size) is zero-filled and has correct length', function (t) { + t.equal(index.Buffer.alloc, safer.Buffer.alloc) + t.equal(index.Buffer.alloc, dangerous.Buffer.alloc) + var ok = true + for (var i = 0; i < 1e2; i++) { + var length = Math.round(Math.random() * 2e6) + var buf = index.Buffer.alloc(length) + if (!buffer.Buffer.isBuffer(buf)) ok = false + if (buf.length !== length) ok = false + var j + for (j = 0; j < length; j++) { + if (buf[j] !== 0) ok = false + } + buf.fill(1) + for (j = 0; j < length; j++) { + if (buf[j] !== 1) ok = false + } + } + t.ok(ok) + t.end() +}) + +test('.allocUnsafe / .allocUnsafeSlow are fillable and have correct lengths', function (t) { + ['allocUnsafe', 'allocUnsafeSlow'].forEach(function (method) { + var ok = true + for (var i = 0; i < 1e2; i++) { + var length = Math.round(Math.random() * 2e6) + var buf = dangerous.Buffer[method](length) + if (!buffer.Buffer.isBuffer(buf)) ok = false + if (buf.length !== length) ok = false + buf.fill(0, 0, length) + var j + for (j = 0; j < length; j++) { + if (buf[j] !== 0) ok = false + } + buf.fill(1, 0, length) + for (j = 0; j < length; j++) { + if (buf[j] !== 1) ok = false + } + } + t.ok(ok, method) + }) + t.end() +}) + +test('.alloc(size, fill) is `fill`-filled', function (t) { + t.equal(index.Buffer.alloc, safer.Buffer.alloc) + t.equal(index.Buffer.alloc, dangerous.Buffer.alloc) + var ok = true + for (var i = 0; i < 1e2; i++) { + var length = Math.round(Math.random() * 2e6) + var fill = Math.round(Math.random() * 255) + var buf = index.Buffer.alloc(length, fill) + if (!buffer.Buffer.isBuffer(buf)) ok = false + if (buf.length !== length) ok = false + for (var j = 0; j < length; j++) { + if (buf[j] !== fill) ok = false + } + } + t.ok(ok) + t.end() +}) + +test('.alloc(size, fill) is `fill`-filled', function (t) { + t.equal(index.Buffer.alloc, safer.Buffer.alloc) + t.equal(index.Buffer.alloc, dangerous.Buffer.alloc) + var ok = true + for (var i = 0; i < 1e2; i++) { + var length = Math.round(Math.random() * 2e6) + var fill = Math.round(Math.random() * 255) + var buf = index.Buffer.alloc(length, fill) + if (!buffer.Buffer.isBuffer(buf)) ok = false + if (buf.length !== length) ok = false + for (var j = 0; j < length; j++) { + if (buf[j] !== fill) ok = false + } + } + t.ok(ok) + t.deepEqual(index.Buffer.alloc(9, 'a'), index.Buffer.alloc(9, 97)) + t.notDeepEqual(index.Buffer.alloc(9, 'a'), index.Buffer.alloc(9, 98)) + + var tmp = new buffer.Buffer(2) + tmp.fill('ok') + if (tmp[1] === tmp[0]) { + // Outdated Node.js + t.deepEqual(index.Buffer.alloc(5, 'ok'), index.Buffer.from('ooooo')) + } else { + t.deepEqual(index.Buffer.alloc(5, 'ok'), index.Buffer.from('okoko')) + } + t.notDeepEqual(index.Buffer.alloc(5, 'ok'), index.Buffer.from('kokok')) + + t.end() +}) + +test('safer.Buffer.from returns results same as Buffer constructor', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.deepEqual(impl.Buffer.from(''), new buffer.Buffer('')) + t.deepEqual(impl.Buffer.from('string'), new buffer.Buffer('string')) + t.deepEqual(impl.Buffer.from('string', 'utf-8'), new buffer.Buffer('string', 'utf-8')) + t.deepEqual(impl.Buffer.from('b25ldHdvdGhyZWU=', 'base64'), new buffer.Buffer('b25ldHdvdGhyZWU=', 'base64')) + t.deepEqual(impl.Buffer.from([0, 42, 3]), new buffer.Buffer([0, 42, 3])) + t.deepEqual(impl.Buffer.from(new Uint8Array([0, 42, 3])), new buffer.Buffer(new Uint8Array([0, 42, 3]))) + t.deepEqual(impl.Buffer.from([]), new buffer.Buffer([])) + }) + t.end() +}) + +test('safer.Buffer.from returns consistent results', function (t) { + [index, safer, dangerous].forEach(function (impl) { + t.deepEqual(impl.Buffer.from(''), impl.Buffer.alloc(0)) + t.deepEqual(impl.Buffer.from([]), impl.Buffer.alloc(0)) + t.deepEqual(impl.Buffer.from(new Uint8Array([])), impl.Buffer.alloc(0)) + t.deepEqual(impl.Buffer.from('string', 'utf-8'), impl.Buffer.from('string')) + t.deepEqual(impl.Buffer.from('string'), impl.Buffer.from([115, 116, 114, 105, 110, 103])) + t.deepEqual(impl.Buffer.from('string'), impl.Buffer.from(impl.Buffer.from('string'))) + t.deepEqual(impl.Buffer.from('b25ldHdvdGhyZWU=', 'base64'), impl.Buffer.from('onetwothree')) + t.notDeepEqual(impl.Buffer.from('b25ldHdvdGhyZWU='), impl.Buffer.from('onetwothree')) + }) + t.end() +}) diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/.eslintignore b/tasks/enduro-trails/prototype/node_modules/ssh2/.eslintignore new file mode 100644 index 0000000..73ed104 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/.eslintignore @@ -0,0 +1,4 @@ +node_modules +lib/protocol/crypto/poly1305.js +.eslint-plugins +!.eslintrc.js diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/.eslintrc.js b/tasks/enduro-trails/prototype/node_modules/ssh2/.eslintrc.js new file mode 100644 index 0000000..be9311d --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/.eslintrc.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + extends: '@mscdex/eslint-config', +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/ci.yml b/tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/ci.yml new file mode 100644 index 0000000..25de60e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/ci.yml @@ -0,0 +1,110 @@ +name: CI + +on: + pull_request: + push: + branches: [ master ] + +env: + CI_CHECK_FAIL: ssh2 + OPENSSL_CONF: /dev/null + +jobs: + tests-linux: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [10.16.0, 10.x, 12.x, 14.x, 16.x, 18.x, 20.x, 22.x, 24.x] + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Check Node.js version + run: node -pe process.versions + - name: Check npm version + run: npm -v + - name: Install Python 2.7 (node <16.x) + if: ${{ contains(fromJSON('["10.16.0", "10.x", "12.x", "14.x"]'), matrix.node-version) }} + uses: LizardByte/setup-python-action@v2024.1105.190605 + with: + python-version: '2.7' + - name: Use Python 2.7 (node <16.x) + if: ${{ contains(fromJSON('["10.16.0", "10.x", "12.x", "14.x"]'), matrix.node-version) }} + run: echo "PYTHON=$(which python2.7)" >> "$GITHUB_ENV" + - name: Install module + run: npm install + - name: Run tests + run: npm test + tests-macos: + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + node-version: [16.x, 18.x, 20.x, 22.x, 24.x] + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Install Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Check Node.js version + run: node -pe process.versions + - name: Check npm version + run: npm -v + - name: Install module + run: npm install + - name: Run tests + run: npm test + tests-macos-homebrew: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Use Node.js (latest) + run: brew install node + - name: Install Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Check Node.js version + run: node -pe process.versions + - name: Check npm version + run: npm -v + - name: Install module + run: npm install + - name: Run tests + run: npm test + tests-windows: + runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + node-version: [16.x, 18.x, 20.x, 22.x, 24.x] + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Check Node.js version + run: node -pe process.versions + - name: Check npm version + run: npm -v + - name: Install module + run: npm install + - name: Run tests + run: npm test diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/lint.yml b/tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/lint.yml new file mode 100644 index 0000000..c21c0ad --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/.github/workflows/lint.yml @@ -0,0 +1,27 @@ +name: lint + +on: + pull_request: + push: + branches: [ master ] + +env: + NODE_VERSION: 18.x + +jobs: + lint-js: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Check Node.js version + run: node -pe process.versions + - name: Install ESLint + ESLint configs/plugins + run: npm install --only=dev + - name: Lint files + run: npm run lint diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/LICENSE b/tasks/enduro-trails/prototype/node_modules/ssh2/LICENSE new file mode 100644 index 0000000..290762e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/LICENSE @@ -0,0 +1,19 @@ +Copyright Brian White. All rights reserved. + +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. \ No newline at end of file diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/README.md b/tasks/enduro-trails/prototype/node_modules/ssh2/README.md new file mode 100644 index 0000000..e08c929 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/README.md @@ -0,0 +1,1529 @@ +# Description + +SSH2 client and server modules written in pure JavaScript for [node.js](http://nodejs.org/). + +Development/testing is done against OpenSSH (8.7 currently). + +Changes (breaking or otherwise) in v1.0.0 can be found [here](https://github.com/mscdex/ssh2/issues/935). + +# Table of Contents + +* [Requirements](#requirements) +* [Installation](#installation) +* [Client Examples](#client-examples) + * [Execute 'uptime' on a server](#execute-uptime-on-a-server) + * [Start an interactive shell session](#start-an-interactive-shell-session) + * [Send a raw HTTP request to port 80 on the server](#send-a-raw-http-request-to-port-80-on-the-server) + * [Forward local connections to port 8000 on the server to us](#forward-local-connections-to-port-8000-on-the-server-to-us) + * [Get a directory listing via SFTP](#get-a-directory-listing-via-sftp) + * [Connection hopping](#connection-hopping) + * [Forward remote X11 connections](#forward-remote-x11-connections) + * [Dynamic (1:1) port forwarding using a SOCKSv5 proxy (using `socksv5`)](#dynamic-11-port-forwarding-using-a-socksv5-proxy-using-socksv5) + * [Make HTTP(S) connections easily using a custom http(s).Agent](#make-https-connections-easily-using-a-custom-httpsagent) + * [Invoke an arbitrary subsystem (e.g. netconf)](#invoke-an-arbitrary-subsystem) +* [Server Examples](#server-examples) + * [Password and public key authentication and non-interactive (exec) command execution](#password-and-public-key-authentication-and-non-interactive-exec-command-execution) + * [SFTP-only server](#sftp-only-server) +* [Other Examples](#other-examples) + * [Generate an SSH key](#generate-an-ssh-key) +* [API](#api) + * [Client](#client) + * [Client events](#client-events) + * [Client methods](#client-methods) + * [Server](#server) + * [Server events](#server-events) + * [Server methods](#server-methods) + * [Connection events](#connection-events) + * [Connection methods](#connection-methods) + * [Session events](#session-events) + * [Channel](#channel) + * [Pseudo-TTY settings](#pseudo-tty-settings) + * [Terminal modes](#terminal-modes) + * [HTTPAgent](#httpagent) + * [HTTPAgent methods](#httpagent-methods) + * [HTTPSAgent](#httpsagent) + * [HTTPSAgent methods](#httpsagent-methods) + * [Utilities](#utilities) + +## Requirements + +* [node.js](http://nodejs.org/) -- v10.16.0 or newer + * node v12.0.0 or newer for Ed25519 key support +* (Optional) [`cpu-features`](https://github.com/mscdex/cpu-features) is set as an optional package dependency (you do not need to install it explicitly/separately from `ssh2`) that will be automatically built and used if possible. See the project's documentation for its own requirements. + * This addon is currently used to help generate an optimal default cipher list + +## Installation + + npm install ssh2 + +## Client Examples + +### Execute 'uptime' on a server + +```js +const { readFileSync } = require('fs'); + +const { Client } = require('ssh2'); + +const conn = new Client(); +conn.on('ready', () => { + console.log('Client :: ready'); + conn.exec('uptime', (err, stream) => { + if (err) throw err; + stream.on('close', (code, signal) => { + console.log('Stream :: close :: code: ' + code + ', signal: ' + signal); + conn.end(); + }).on('data', (data) => { + console.log('STDOUT: ' + data); + }).stderr.on('data', (data) => { + console.log('STDERR: ' + data); + }); + }); +}).connect({ + host: '192.168.100.100', + port: 22, + username: 'frylock', + privateKey: readFileSync('/path/to/my/key') +}); + +// example output: +// Client :: ready +// STDOUT: 17:41:15 up 22 days, 18:09, 1 user, load average: 0.00, 0.01, 0.05 +// +// Stream :: exit :: code: 0, signal: undefined +// Stream :: close +``` + +### Start an interactive shell session + +```js +const { readFileSync } = require('fs'); + +const { Client } = require('ssh2'); + +const conn = new Client(); +conn.on('ready', () => { + console.log('Client :: ready'); + conn.shell((err, stream) => { + if (err) throw err; + stream.on('close', () => { + console.log('Stream :: close'); + conn.end(); + }).on('data', (data) => { + console.log('OUTPUT: ' + data); + }); + stream.end('ls -l\nexit\n'); + }); +}).connect({ + host: '192.168.100.100', + port: 22, + username: 'frylock', + privateKey: readFileSync('/path/to/my/key') +}); + +// example output: +// Client :: ready +// STDOUT: Last login: Sun Jun 15 09:37:21 2014 from 192.168.100.100 +// +// STDOUT: ls -l +// exit +// +// STDOUT: frylock@athf:~$ ls -l +// +// STDOUT: total 8 +// +// STDOUT: drwxr-xr-x 2 frylock frylock 4096 Nov 18 2012 mydir +// +// STDOUT: -rw-r--r-- 1 frylock frylock 25 Apr 11 2013 test.txt +// +// STDOUT: frylock@athf:~$ exit +// +// STDOUT: logout +// +// Stream :: close +``` + +### Send a raw HTTP request to port 80 on the server + +```js +const { Client } = require('ssh2'); + +const conn = new Client(); +conn.on('ready', () => { + console.log('Client :: ready'); + conn.forwardOut('192.168.100.102', 8000, '127.0.0.1', 80, (err, stream) => { + if (err) throw err; + stream.on('close', () => { + console.log('TCP :: CLOSED'); + conn.end(); + }).on('data', (data) => { + console.log('TCP :: DATA: ' + data); + }).end([ + 'HEAD / HTTP/1.1', + 'User-Agent: curl/7.27.0', + 'Host: 127.0.0.1', + 'Accept: */*', + 'Connection: close', + '', + '' + ].join('\r\n')); + }); +}).connect({ + host: '192.168.100.100', + port: 22, + username: 'frylock', + password: 'nodejsrules' +}); + +// example output: +// Client :: ready +// TCP :: DATA: HTTP/1.1 200 OK +// Date: Thu, 15 Nov 2012 13:52:58 GMT +// Server: Apache/2.2.22 (Ubuntu) +// X-Powered-By: PHP/5.4.6-1ubuntu1 +// Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT +// Content-Encoding: gzip +// Vary: Accept-Encoding +// Connection: close +// Content-Type: text/html; charset=UTF-8 +// +// +// TCP :: CLOSED +``` + +### Forward local connections to port 8000 on the server to us + +```js +const { Client } = require('ssh2'); + +const conn = new Client(); +conn.on('ready', () => { + console.log('Client :: ready'); + conn.forwardIn('127.0.0.1', 8000, (err) => { + if (err) throw err; + console.log('Listening for connections on server on port 8000!'); + }); +}).on('tcp connection', (info, accept, reject) => { + console.log('TCP :: INCOMING CONNECTION:'); + console.dir(info); + accept().on('close', () => { + console.log('TCP :: CLOSED'); + }).on('data', (data) => { + console.log('TCP :: DATA: ' + data); + }).end([ + 'HTTP/1.1 404 Not Found', + 'Date: Thu, 15 Nov 2012 02:07:58 GMT', + 'Server: ForwardedConnection', + 'Content-Length: 0', + 'Connection: close', + '', + '' + ].join('\r\n')); +}).connect({ + host: '192.168.100.100', + port: 22, + username: 'frylock', + password: 'nodejsrules' +}); + +// example output: +// Client :: ready +// Listening for connections on server on port 8000! +// (.... then from another terminal on the server: `curl -I http://127.0.0.1:8000`) +// TCP :: INCOMING CONNECTION: { destIP: '127.0.0.1', +// destPort: 8000, +// srcIP: '127.0.0.1', +// srcPort: 41969 } +// TCP DATA: HEAD / HTTP/1.1 +// User-Agent: curl/7.27.0 +// Host: 127.0.0.1:8000 +// Accept: */* +// +// +// TCP :: CLOSED +``` + +### Get a directory listing via SFTP + +```js +const { Client } = require('ssh2'); + +const conn = new Client(); +conn.on('ready', () => { + console.log('Client :: ready'); + conn.sftp((err, sftp) => { + if (err) throw err; + sftp.readdir('foo', (err, list) => { + if (err) throw err; + console.dir(list); + conn.end(); + }); + }); +}).connect({ + host: '192.168.100.100', + port: 22, + username: 'frylock', + password: 'nodejsrules' +}); + +// example output: +// Client :: ready +// [ { filename: 'test.txt', +// longname: '-rw-r--r-- 1 frylock frylock 12 Nov 18 11:05 test.txt', +// attrs: +// { size: 12, +// uid: 1000, +// gid: 1000, +// mode: 33188, +// atime: 1353254750, +// mtime: 1353254744 } }, +// { filename: 'mydir', +// longname: 'drwxr-xr-x 2 frylock frylock 4096 Nov 18 15:03 mydir', +// attrs: +// { size: 1048576, +// uid: 1000, +// gid: 1000, +// mode: 16877, +// atime: 1353269007, +// mtime: 1353269007 } } ] +``` + +### Connection hopping + +```js +const { Client } = require('ssh2'); + +const conn1 = new Client(); +const conn2 = new Client(); + +// Checks uptime on 10.1.1.40 via 192.168.1.1 + +conn1.on('ready', () => { + console.log('FIRST :: connection ready'); + // Alternatively, you could use something like netcat or socat with exec() + // instead of forwardOut(), depending on what the server allows + conn1.forwardOut('127.0.0.1', 12345, '10.1.1.40', 22, (err, stream) => { + if (err) { + console.log('FIRST :: forwardOut error: ' + err); + return conn1.end(); + } + conn2.connect({ + sock: stream, + username: 'user2', + password: 'password2', + }); + }); +}).connect({ + host: '192.168.1.1', + username: 'user1', + password: 'password1', +}); + +conn2.on('ready', () => { + // This connection is the one to 10.1.1.40 + + console.log('SECOND :: connection ready'); + conn2.exec('uptime', (err, stream) => { + if (err) { + console.log('SECOND :: exec error: ' + err); + return conn1.end(); + } + stream.on('close', () => { + conn1.end(); // close parent (and this) connection + }).on('data', (data) => { + console.log(data.toString()); + }); + }); +}); +``` + +### Forward remote X11 connections + +```js +const { Socket } = require('net'); + +const { Client } = require('ssh2'); + +const conn = new Client(); + +conn.on('x11', (info, accept, reject) => { + const xserversock = new net.Socket(); + xserversock.on('connect', () => { + const xclientsock = accept(); + xclientsock.pipe(xserversock).pipe(xclientsock); + }); + // connects to localhost:0.0 + xserversock.connect(6000, 'localhost'); +}); + +conn.on('ready', () => { + conn.exec('xeyes', { x11: true }, (err, stream) => { + if (err) throw err; + let code = 0; + stream.on('close', () => { + if (code !== 0) + console.log('Do you have X11 forwarding enabled on your SSH server?'); + conn.end(); + }).on('exit', (exitcode) => { + code = exitcode; + }); + }); +}).connect({ + host: '192.168.1.1', + username: 'foo', + password: 'bar' +}); +``` + +### Dynamic (1:1) port forwarding using a SOCKSv5 proxy (using [socksv5](https://github.com/mscdex/socksv5)) + +```js +const socks = require('socksv5'); +const { Client } = require('ssh2'); + +const sshConfig = { + host: '192.168.100.1', + port: 22, + username: 'nodejs', + password: 'rules' +}; + +socks.createServer((info, accept, deny) => { + // NOTE: you could just use one ssh2 client connection for all forwards, but + // you could run into server-imposed limits if you have too many forwards open + // at any given time + const conn = new Client(); + conn.on('ready', () => { + conn.forwardOut(info.srcAddr, + info.srcPort, + info.dstAddr, + info.dstPort, + (err, stream) => { + if (err) { + conn.end(); + return deny(); + } + + const clientSocket = accept(true); + if (clientSocket) { + stream.pipe(clientSocket).pipe(stream).on('close', () => { + conn.end(); + }); + } else { + conn.end(); + } + }); + }).on('error', (err) => { + deny(); + }).connect(sshConfig); +}).listen(1080, 'localhost', () => { + console.log('SOCKSv5 proxy server started on port 1080'); +}).useAuth(socks.auth.None()); + +// test with cURL: +// curl -i --socks5 localhost:1080 google.com +``` + +### Make HTTP(S) connections easily using a custom http(s).Agent + +```js +const http = require('http'); + +const { Client, HTTPAgent, HTTPSAgent } = require('ssh2'); + +const sshConfig = { + host: '192.168.100.1', + port: 22, + username: 'nodejs', + password: 'rules' +}; + +// Use `HTTPSAgent` instead for an HTTPS request +const agent = new HTTPAgent(sshConfig); +http.get({ + host: '192.168.200.1', + agent, + headers: { Connection: 'close' } +}, (res) => { + console.log(res.statusCode); + console.dir(res.headers); + res.resume(); +}); +``` + + +### Invoke an arbitrary subsystem + +```js +const { Client } = require('ssh2'); + +const xmlhello = ` + + + + urn:ietf:params:netconf:base:1.0 + + ]]>]]>`; + +const conn = new Client(); + +conn.on('ready', () => { + console.log('Client :: ready'); + conn.subsys('netconf', (err, stream) => { + if (err) throw err; + stream.on('data', (data) => { + console.log(data); + }).write(xmlhello); + }); +}).connect({ + host: '1.2.3.4', + port: 22, + username: 'blargh', + password: 'honk' +}); +``` + +## Server Examples + +### Password and public key authentication and non-interactive (exec) command execution + +```js +const { timingSafeEqual } = require('crypto'); +const { readFileSync } = require('fs'); +const { inspect } = require('util'); + +const { utils: { parseKey }, Server } = require('ssh2'); + +const allowedUser = Buffer.from('foo'); +const allowedPassword = Buffer.from('bar'); +const allowedPubKey = parseKey(readFileSync('foo.pub')); + +function checkValue(input, allowed) { + const autoReject = (input.length !== allowed.length); + if (autoReject) { + // Prevent leaking length information by always making a comparison with the + // same input when lengths don't match what we expect ... + allowed = input; + } + const isMatch = timingSafeEqual(input, allowed); + return (!autoReject && isMatch); +} + +new Server({ + hostKeys: [readFileSync('host.key')] +}, (client) => { + console.log('Client connected!'); + + client.on('authentication', (ctx) => { + let allowed = true; + if (!checkValue(Buffer.from(ctx.username), allowedUser)) + allowed = false; + + switch (ctx.method) { + case 'password': + if (!checkValue(Buffer.from(ctx.password), allowedPassword)) + return ctx.reject(); + break; + case 'publickey': + if (ctx.key.algo !== allowedPubKey.type + || !checkValue(ctx.key.data, allowedPubKey.getPublicSSH()) + || (ctx.signature && allowedPubKey.verify(ctx.blob, ctx.signature, ctx.hashAlgo) !== true)) { + return ctx.reject(); + } + break; + default: + return ctx.reject(); + } + + if (allowed) + ctx.accept(); + else + ctx.reject(); + }).on('ready', () => { + console.log('Client authenticated!'); + + client.on('session', (accept, reject) => { + const session = accept(); + session.once('exec', (accept, reject, info) => { + console.log('Client wants to execute: ' + inspect(info.command)); + const stream = accept(); + stream.stderr.write('Oh no, the dreaded errors!\n'); + stream.write('Just kidding about the errors!\n'); + stream.exit(0); + stream.end(); + }); + }); + }).on('close', () => { + console.log('Client disconnected'); + }); +}).listen(0, '127.0.0.1', function() { + console.log('Listening on port ' + this.address().port); +}); +``` + +### SFTP-only server + +```js +const { timingSafeEqual } = require('crypto'); +const { readFileSync } = require('fs'); +const { inspect } = require('util'); + +const { + Server, + sftp: { + OPEN_MODE, + STATUS_CODE, + }, +} = require('ssh2'); + +const allowedUser = Buffer.from('foo'); +const allowedPassword = Buffer.from('bar'); + +function checkValue(input, allowed) { + const autoReject = (input.length !== allowed.length); + if (autoReject) { + // Prevent leaking length information by always making a comparison with the + // same input when lengths don't match what we expect ... + allowed = input; + } + const isMatch = timingSafeEqual(input, allowed); + return (!autoReject && isMatch); +} + +// This simple SFTP server implements file uploading where the contents get +// ignored ... + +new ssh2.Server({ + hostKeys: [readFileSync('host.key')] +}, (client) => { + console.log('Client connected!'); + + client.on('authentication', (ctx) => { + let allowed = true; + if (!checkValue(Buffer.from(ctx.username), allowedUser)) + allowed = false; + + switch (ctx.method) { + case 'password': + if (!checkValue(Buffer.from(ctx.password), allowedPassword)) + return ctx.reject(); + break; + default: + return ctx.reject(); + } + + if (allowed) + ctx.accept(); + else + ctx.reject(); + }).on('ready', () => { + console.log('Client authenticated!'); + + client.on('session', (accept, reject) => { + const session = accept(); + session.on('sftp', (accept, reject) => { + console.log('Client SFTP session'); + const openFiles = new Map(); + let handleCount = 0; + const sftp = accept(); + sftp.on('OPEN', (reqid, filename, flags, attrs) => { + // Only allow opening /tmp/foo.txt for writing + if (filename !== '/tmp/foo.txt' || !(flags & OPEN_MODE.WRITE)) + return sftp.status(reqid, STATUS_CODE.FAILURE); + + // Create a fake handle to return to the client, this could easily + // be a real file descriptor number for example if actually opening + // a file on disk + const handle = Buffer.alloc(4); + openFiles.set(handleCount, true); + handle.writeUInt32BE(handleCount++, 0); + + console.log('Opening file for write') + sftp.handle(reqid, handle); + }).on('WRITE', (reqid, handle, offset, data) => { + if (handle.length !== 4 + || !openFiles.has(handle.readUInt32BE(0))) { + return sftp.status(reqid, STATUS_CODE.FAILURE); + } + + // Fake the write operation + sftp.status(reqid, STATUS_CODE.OK); + + console.log('Write to file at offset ${offset}: ${inspect(data)}'); + }).on('CLOSE', (reqid, handle) => { + let fnum; + if (handle.length !== 4 + || !openFiles.has(fnum = handle.readUInt32BE(0))) { + return sftp.status(reqid, STATUS_CODE.FAILURE); + } + + console.log('Closing file'); + openFiles.delete(fnum); + + sftp.status(reqid, STATUS_CODE.OK); + }); + }); + }); + }).on('close', () => { + console.log('Client disconnected'); + }); +}).listen(0, '127.0.0.1', function() { + console.log('Listening on port ' + this.address().port); +}); +``` + +## Other Examples + +### Generate an SSH key + +```js +const { utils: { generateKeyPair, generateKeyPairSync } } = require('ssh2'); + +// Generate unencrypted ED25519 SSH key synchronously +let keys = generateKeyPairSync('ed25519'); +// ... use `keys.public` and `keys.private` + +// Generate unencrypted ECDSA SSH key synchronously with a comment set +keys = generateKeyPairSync('ecdsa', { bits: 256, comment: 'node.js rules!' }); +// ... use `keys.public` and `keys.private` + +// Generate encrypted RSA SSH key asynchronously +generateKeyPair( + 'rsa', + { bits: 2048, passphrase: 'foobarbaz', cipher: 'aes256-cbc' }, + (err, keys) => { + if (err) throw err; + // ... use `keys.public` and `keys.private` + } +); +``` + +You can find more examples in the `examples` directory of this repository. + +## API + +`require('ssh2').Client` is the **_Client_** constructor. + +`require('ssh2').Server` is the **_Server_** constructor. + +`require('ssh2').utils` is an object containing some useful [utilities](#utilities). + +`require('ssh2').HTTPAgent` is an [`http.Agent`](https://nodejs.org/docs/latest/api/http.html#http_class_http_agent) constructor. + +`require('ssh2').HTTPSAgent` is an [`https.Agent`](https://nodejs.org/docs/latest/api/https.html#https_class_https_agent) constructor. Its API is the same as `HTTPAgent` except it's for HTTPS connections. + +### Agent-related + +`require('ssh2').AgentProtocol` is a Duplex stream [class](#agentprotocol) that aids in communicating over the OpenSSH agent protocol. + +`require('ssh2').BaseAgent` is a base [class](#baseagent) for creating custom authentication agents. + +`require('ssh2').createAgent` is a helper [function](#createagent) that creates a new agent instance using the same logic as the `agent` configuration option: if the platform is Windows and it's the value "pageant", it creates a `PageantAgent`, otherwise if it's not a path to a Windows pipe it creates a `CygwinAgent`. In all other cases, it creates an `OpenSSHAgent`. + +`require('ssh2').CygwinAgent` is an agent [class](#cygwinagent) implementation that communicates with agents in a Cygwin environment. + +`require('ssh2').OpenSSHAgent` is an agent [class](#opensshagent) implementation that communicates with OpenSSH agents over a UNIX socket. + +`require('ssh2').PageantAgent` is an agent [class](#pageantagent) implementation that communicates with Pageant agent processes. + +### Client + +#### Client events + +* **banner**(< _string_ >message, < _string_ >language) - A notice was sent by the server upon connection. + +* **change password**(< _string_ >prompt, < _function_ >done) - If using password-based user authentication, the server has requested that the user's password be changed. Call `done` with the new password. + +* **close**() - The socket was closed. + +* **end**() - The socket was disconnected. + +* **error**(< _Error_ >err) - An error occurred. A 'level' property indicates 'client-socket' for socket-level errors and 'client-ssh' for SSH disconnection messages. In the case of 'client-ssh' messages, there may be a 'description' property that provides more detail. + +* **handshake**(< _object_ >negotiated) - Emitted when a handshake has completed (either initial or rekey). `negotiated` contains the negotiated details of the handshake and is of the form: + +```js + // In this particular case `mac` is empty because there is no separate MAC + // because it's integrated into AES in GCM mode + { kex: 'ecdh-sha2-nistp256', + srvHostKey: 'rsa-sha2-512', + cs: { // Client to server algorithms + cipher: 'aes128-gcm', + mac: '', + compress: 'none', + lang: '' + }, + sc: { // Server to client algorithms + cipher: 'aes128-gcm', + mac: '', + compress: 'none', + lang: '' + } + } +``` + +* **hostkeys**(< _array_ >keys) - Emitted when the server announces its available host keys. `keys` is the list of parsed (using [`parseKey()`](#utilities)) host public keys. + +* **keyboard-interactive**(< _string_ >name, < _string_ >instructions, < _string_ >instructionsLang, < _array_ >prompts, < _function_ >finish) - The server is asking for replies to the given `prompts` for keyboard-interactive user authentication. `name` is generally what you'd use as a window title (for GUI apps). `prompts` is an array of `{ prompt: 'Password: ', echo: false }` style objects (here `echo` indicates whether user input should be displayed on the screen). The answers for all prompts must be provided as an array of strings and passed to `finish` when you are ready to continue. Note: It's possible for the server to come back and ask more questions. + +* **ready**() - Authentication was successful. + +* **rekey**() - Emitted when a rekeying operation has completed (either client or server-initiated). + +* **tcp connection**(< _object_ >details, < _function_ >accept, < _function_ >reject) - An incoming forwarded TCP connection is being requested. Calling `accept` accepts the connection and returns a `Channel` object. Calling `reject` rejects the connection and no further action is needed. `details` contains: + + * **destIP** - _string_ - The remote IP the connection was received on (given in earlier call to `forwardIn()`). + + * **destPort** - _integer_ - The remote port the connection was received on (given in earlier call to `forwardIn()`). + + * **srcIP** - _string_ - The originating IP of the connection. + + * **srcPort** - _integer_ - The originating port of the connection. + +* **unix connection**(< _object_ >details, < _function_ >accept, < _function_ >reject) - An incoming forwarded UNIX socket connection is being requested. Calling `accept` accepts the connection and returns a `Channel` object. Calling `reject` rejects the connection and no further action is needed. `details` contains: + + * **socketPath** - _string_ - The originating UNIX socket path of the connection. + +* **x11**(< _object_ >details, < _function_ >accept, < _function_ >reject) - An incoming X11 connection is being requested. Calling `accept` accepts the connection and returns a `Channel` object. Calling `reject` rejects the connection and no further action is needed. `details` contains: + + * **srcIP** - _string_ - The originating IP of the connection. + + * **srcPort** - _integer_ - The originating port of the connection. + +#### Client methods + +* **(constructor)**() - Creates and returns a new Client instance. + +* **connect**(< _object_ >config) - _(void)_ - Attempts a connection to a server using the information given in `config`: + + * **agent** - _string_ - Path to ssh-agent's UNIX socket for ssh-agent-based user authentication. **Windows users: set to 'pageant' for authenticating with Pageant or (actual) path to a cygwin "UNIX socket."** **Default:** (none) + + * **agentForward** - _boolean_ - Set to `true` to use OpenSSH agent forwarding (`auth-agent@openssh.com`) for the life of the connection. `agent` must also be set to use this feature. **Default:** `false` + + * **algorithms** - _object_ - This option allows you to explicitly override the default transport layer algorithms used for the connection. The value for each category must either be an array of valid algorithm names to set an exact list (with the most preferable first) or an object containing `append`, `prepend`, and/or `remove` properties that each contain an _array_ of algorithm names or RegExps to match to adjust default lists for each category. Valid keys: + + * **cipher** - _mixed_ - Ciphers. + * Default list (in order from most to least preferable): + * `chacha20-poly1305@openssh.com` (priority of chacha20-poly1305 may vary depending upon CPU and/or optional binding availability) + * `aes128-gcm` + * `aes128-gcm@openssh.com` + * `aes256-gcm` + * `aes256-gcm@openssh.com` + * `aes128-ctr` + * `aes192-ctr` + * `aes256-ctr` + * Other supported names: + * `3des-cbc` + * `aes256-cbc` + * `aes192-cbc` + * `aes128-cbc` + * `arcfour256` + * `arcfour128` + * `arcfour` + * `blowfish-cbc` + * `cast128-cbc` + + * **compress** - _mixed_ - Compression algorithms. + * Default list (in order from most to least preferable): + * `none` + * `zlib@openssh.com` + * `zlib` + * Other supported names: + + * **hmac** - _mixed_ - (H)MAC algorithms. + * Default list (in order from most to least preferable): + * `hmac-sha2-256-etm@openssh.com` + * `hmac-sha2-512-etm@openssh.com` + * `hmac-sha1-etm@openssh.com` + * `hmac-sha2-256` + * `hmac-sha2-512` + * `hmac-sha1` + * Other supported names: + * `hmac-md5` + * `hmac-sha2-256-96` + * `hmac-sha2-512-96` + * `hmac-ripemd160` + * `hmac-sha1-96` + * `hmac-md5-96` + + * **kex** - _mixed_ - Key exchange algorithms. + * Default list (in order from most to least preferable): + * `curve25519-sha256` (node v14.0.0+) + * `curve25519-sha256@libssh.org` (node v14.0.0+) + * `ecdh-sha2-nistp256` + * `ecdh-sha2-nistp384` + * `ecdh-sha2-nistp521` + * `diffie-hellman-group-exchange-sha256` + * `diffie-hellman-group14-sha256` + * `diffie-hellman-group15-sha512` + * `diffie-hellman-group16-sha512` + * `diffie-hellman-group17-sha512` + * `diffie-hellman-group18-sha512` + * Other supported names: + * `diffie-hellman-group-exchange-sha1` + * `diffie-hellman-group14-sha1` + * `diffie-hellman-group1-sha1` + + * **serverHostKey** - _mixed_ - Server host key formats. + * Default list (in order from most to least preferable): + * `ssh-ed25519` (node v12.0.0+) + * `ecdsa-sha2-nistp256` + * `ecdsa-sha2-nistp384` + * `ecdsa-sha2-nistp521` + * `rsa-sha2-512` + * `rsa-sha2-256` + * `ssh-rsa` + * Other supported names: + * `ssh-dss` + + * **authHandler** - _mixed_ - Must be an array of objects as described below, an array of strings containing valid authentication method names (username and credentials are pulled from the object passed to `connect()`), or a function with parameters `(methodsLeft, partialSuccess, callback)` where `methodsLeft` and `partialSuccess` are `null` on the first authentication attempt, otherwise are an array and boolean respectively. Return or call `callback()` with either the name of the authentication method or an object containing the method name along with method-specific details to try next (return/pass `false` to signal no more methods to try). Valid method names are: `'none', 'password', 'publickey', 'agent', 'keyboard-interactive', 'hostbased'`. **Default:** function that follows a set method order: None -> Password -> Private Key -> Agent (-> keyboard-interactive if `tryKeyboard` is `true`) -> Hostbased + + * When returning or calling `callback()` with an object, it can take one of the following forms: + + ```js + { + type: 'none', + username: 'foo', + } + ``` + + ```js + { + type: 'password' + username: 'foo', + password: 'bar', + } + ``` + + ```js + { + type: 'publickey' + username: 'foo', + // Can be a string, Buffer, or parsed key containing a private key + key: ..., + // `passphrase` only required for encrypted keys + passphrase: ..., + } + ``` + + ```js + { + type: 'hostbased' + username: 'foo', + localHostname: 'baz', + localUsername: 'quux', + // Can be a string, Buffer, or parsed key containing a private key + key: ..., + // `passphrase` only required for encrypted keys + passphrase: ..., + } + ``` + + ```js + { + type: 'agent' + username: 'foo', + // Can be a string that is interpreted exactly like the `agent` + // connection config option or can be a custom agent + // object/instance that extends and implements `BaseAgent` + agent: ..., + } + ``` + + ```js + { + type: 'keyboard-interactive' + username: 'foo', + // This works exactly the same way as a 'keyboard-interactive' + // Client event handler + prompt: (name, instructions, instructionsLang, prompts, finish) => { + // ... + }, + } + ``` + + * **debug** - _function_ - Set this to a function that receives a single string argument to get detailed (local) debug information. **Default:** (none) + + * **forceIPv4** - _boolean_ - Only connect via resolved IPv4 address for `host`. **Default:** `false` + + * **forceIPv6** - _boolean_ - Only connect via resolved IPv6 address for `host`. **Default:** `false` + + * **host** - _string_ - Hostname or IP address of the server. **Default:** `'localhost'` + + * **hostHash** - _string_ - Any valid hash algorithm supported by node. The host's key is hashed using this algorithm and passed to the **hostVerifier** function as a hex string. **Default:** (none) + + * **hostVerifier** - _function_ - Function with parameters `(key[, callback])` for verifying host keys, where `key` is either a hex _string_ of the hash of the key if `hostHash` was set, otherwise it is the raw host key in _Buffer_ form. Use `utils.parseKey()` to get the host key type. Return `true` to continue with the handshake or `false` to reject and disconnect, or call `callback()` with `true` or `false` if you need to perform asynchronous verification. **Default:** (auto-accept if `hostVerifier` is not set) + + * **keepaliveCountMax** - _integer_ - How many consecutive, unanswered SSH-level keepalive packets that can be sent to the server before disconnection (similar to OpenSSH's ServerAliveCountMax config option). **Default:** `3` + + * **keepaliveInterval** - _integer_ - How often (in milliseconds) to send SSH-level keepalive packets to the server (in a similar way as OpenSSH's ServerAliveInterval config option). Set to 0 to disable. **Default:** `0` + + * **localAddress** - _string_ - IP address of the network interface to use to connect to the server. **Default:** (none -- determined by OS) + + * **localHostname** - _string_ - Along with **localUsername** and **privateKey**, set this to a non-empty string for hostbased user authentication. **Default:** (none) + + * **localPort** - _string_ - The local port number to connect from. **Default:** (none -- determined by OS) + + * **localUsername** - _string_ - Along with **localHostname** and **privateKey**, set this to a non-empty string for hostbased user authentication. **Default:** (none) + + * **passphrase** - _string_ - For an encrypted `privateKey`, this is the passphrase used to decrypt it. **Default:** (none) + + * **password** - _string_ - Password for password-based user authentication. **Default:** (none) + + * **port** - _integer_ - Port number of the server. **Default:** `22` + + * **privateKey** - _mixed_ - _Buffer_ or _string_ that contains a private key for either key-based or hostbased user authentication (OpenSSH format). **Default:** (none) + + * **readyTimeout** - _integer_ - How long (in milliseconds) to wait for the SSH handshake to complete. **Default:** `20000` + + * **sock** - _ReadableStream_ - A _ReadableStream_ to use for communicating with the server instead of creating and using a new TCP connection (useful for connection hopping). + + * **strictVendor** - _boolean_ - Performs a strict server vendor check before sending vendor-specific requests, etc. (e.g. check for OpenSSH server when using `openssh_noMoreSessions()`) **Default:** `true` + + * **tryKeyboard** - _boolean_ - Try keyboard-interactive user authentication if primary user authentication method fails. If you set this to `true`, you need to handle the `keyboard-interactive` event. **Default:** `false` + + * **username** - _string_ - Username for authentication. **Default:** (none) + +* **end**() - _(void)_ - Disconnects the socket. + +* **exec**(< _string_ >command[, < _object_ >options], < _function_ >callback) - _(void)_ - Executes `command` on the server. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. Valid `options` properties are: + + * **env** - _object_ - An environment to use for the execution of the command. + + * **pty** - _mixed_ - Set to `true` to allocate a pseudo-tty with defaults, or an object containing specific pseudo-tty settings (see 'Pseudo-TTY settings'). Setting up a pseudo-tty can be useful when working with remote processes that expect input from an actual terminal (e.g. sudo's password prompt). + + * **x11** - _mixed_ - Set to `true` to use defaults below, set to a number to specify a specific screen number, or an object with the following valid properties: + + * **cookie** - _mixed_ - The authentication cookie. Can be a hex _string_ or a _Buffer_ containing the raw cookie value (which will be converted to a hex string). **Default:** (random 16 byte value) + + * **protocol** - _string_ - The authentication protocol name. **Default:** `'MIT-MAGIC-COOKIE-1'` + + * **screen** - _number_ - Screen number to use **Default:** `0` + + * **single** - _boolean_ - Allow just a single connection? **Default:** `false` + +* **forwardIn**(< _string_ >remoteAddr, < _integer_ >remotePort, < _function_ >callback) - _(void)_ - Bind to `remoteAddr` on `remotePort` on the server and forward incoming TCP connections. `callback` has 2 parameters: < _Error_ >err, < _integer_ >port (`port` is the assigned port number if `remotePort` was 0). Here are some special values for `remoteAddr` and their associated binding behaviors: + + * '' - Connections are to be accepted on all protocol families supported by the server. + + * '0.0.0.0' - Listen on all IPv4 addresses. + + * '::' - Listen on all IPv6 addresses. + + * 'localhost' - Listen on all protocol families supported by the server on loopback addresses only. + + * '127.0.0.1' and '::1' - Listen on the loopback interfaces for IPv4 and IPv6, respectively. + +* **forwardOut**(< _string_ >srcIP, < _integer_ >srcPort, < _string_ >dstIP, < _integer_ >dstPort, < _function_ >callback) - _(void)_ - Open a connection with `srcIP` and `srcPort` as the originating address and port and `dstIP` and `dstPort` as the remote destination address and port. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +* **openssh_forwardInStreamLocal**(< _string_ >socketPath, < _function_ >callback) - _(void)_ - OpenSSH extension that binds to a UNIX domain socket at `socketPath` on the server and forwards incoming connections. `callback` has 1 parameter: < _Error_ >err. + +* **openssh_forwardOutStreamLocal**(< _string_ >socketPath, < _function_ >callback) - _(void)_ - OpenSSH extension that opens a connection to a UNIX domain socket at `socketPath` on the server. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +* **openssh_noMoreSessions**(< _function_ >callback) - _(void)_ - OpenSSH extension that sends a request to reject any new sessions (e.g. exec, shell, sftp, subsys) for this connection. `callback` has 1 parameter: < _Error_ >err. + +* **openssh_unforwardInStreamLocal**(< _string_ >socketPath, < _function_ >callback) - _(void)_ - OpenSSH extension that unbinds from a UNIX domain socket at `socketPath` on the server and stops forwarding incoming connections. `callback` has 1 parameter: < _Error_ >err. + +* **rekey**([< _function_ >callback]) - _(void)_ - Initiates a rekey with the server. If `callback` is supplied, it is added as a one-time handler for the `rekey` event. + +* **setNoDelay**([< _boolean_ >noDelay]) - _Client_ - Calls [`setNoDelay()`](https://nodejs.org/docs/latest/api/net.html#socketsetnodelaynodelay) on the underlying socket. Disabling Nagle's algorithm improves latency at the expense of lower throughput. + +* **sftp**([< _object_ >env, ]< _function_ >callback) - _(void)_ - Starts an SFTP session. `env` is an environment to use when executing `sftp` methods. `callback` has 2 parameters: < _Error_ >err, < _SFTP_ >sftp. For methods available on `sftp`, see the [`SFTP` client documentation](https://github.com/mscdex/ssh2/blob/master/SFTP.md). + +* **shell**([[< _mixed_ >window,] < _object_ >options]< _function_ >callback) - _(void)_ - Starts an interactive shell session on the server, with an optional `window` object containing pseudo-tty settings (see 'Pseudo-TTY settings'). If `window === false`, then no pseudo-tty is allocated. `options` supports the `x11` and `env` options as described in `exec()`. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +* **subsys**(< _string_ >subsystem, < _function_ >callback) - _(void)_ - Invokes `subsystem` on the server. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +* **unforwardIn**(< _string_ >remoteAddr, < _integer_ >remotePort, < _function_ >callback) - _(void)_ - Unbind from `remoteAddr` on `remotePort` on the server and stop forwarding incoming TCP connections. Until `callback` is called, more connections may still come in. `callback` has 1 parameter: < _Error_ >err. + +### Server + +#### Server events + +* **connection**(< _Connection_ >client, < _object_ >info) - A new client has connected. `info` contains the following properties: + + * **family** - _string_ - The `remoteFamily` of the connection. + + * **header** - _object_ - Information about the client's header: + + * **identRaw** - _string_ - The raw client identification string. + + * **versions** - _object_ - Various version information: + + * **protocol** - _string_ - The SSH protocol version (always `1.99` or `2.0`). + + * **software** - _string_ - The software name and version of the client. + + * **comments** - _string_ - Any text that comes after the software name/version. + + Example: the identification string `SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2` would be parsed as: + + ```js + { + identRaw: 'SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2', + version: { + protocol: '2.0', + software: 'OpenSSH_6.6.1p1' + }, + comments: 'Ubuntu-2ubuntu2' + } + ``` + + * **ip** - _string_ - The `remoteAddress` of the connection. + + * **port** - _integer_ - The `remotePort` of the connection. + +#### Server methods + +* **(constructor)**(< _object_ >config[, < _function_ >connectionListener]) - Creates and returns a new Server instance. Server instances also have the same methods/properties/events as [`net.Server`](http://nodejs.org/docs/latest/api/net.html#net_class_net_server). `connectionListener` if supplied, is added as a `connection` listener. Valid `config` properties: + + * **algorithms** - _object_ - This option allows you to explicitly override the default transport layer algorithms used for incoming client connections. Each value must be an array of valid algorithms for that category. The order of the algorithms in the arrays are important, with the most favorable being first. For a list of valid and default algorithm names, please review the documentation for the version of `ssh2` used by this module. Valid keys: + + * **cipher** - _array_ - Ciphers. + + * **compress** - _array_ - Compression algorithms. + + * **hmac** - _array_ - (H)MAC algorithms. + + * **kex** - _array_ - Key exchange algorithms. + + * **serverHostKey** - _array_ - Server host key formats. + + * **banner** - _string_ - A message that is sent to clients once, right before authentication begins. **Default:** (none) + + * **debug** - _function_ - Set this to a function that receives a single string argument to get detailed (local) debug information. **Default:** (none) + + * **greeting** - _string_ - A message that is sent to clients immediately upon connection, before handshaking begins. **Note:** Most clients usually ignore this. **Default:** (none) + + * **highWaterMark** - _integer_ - This is the `highWaterMark` to use for the parser stream. **Default:** `32 * 1024` + + * **hostKeys** - _array_ - An array of either Buffers/strings that contain host private keys or objects in the format of `{ key: , passphrase: }` for encrypted private keys. (**Required**) **Default:** (none) + + * **ident** - _string_ - A custom server software name/version identifier. **Default:** `'ssh2js' + moduleVersion + 'srv'` + +* **injectSocket**(< _DuplexStream_ >socket) - Injects a bidirectional stream as though it were a TCP socket connection. Additionally, `socket` should include `net.Socket`-like properties to ensure the best compatibility (e.g. `socket.remoteAddress`, `socket.remotePort`, `socket.remoteFamily`). + +#### Connection events + +* **authentication**(< _AuthContext_ >ctx) - The client has requested authentication. `ctx.username` contains the client username, `ctx.method` contains the requested authentication method, and `ctx.accept()` and `ctx.reject([< Array >authMethodsLeft[, < Boolean >isPartialSuccess]])` are used to accept or reject the authentication request respectively. `'abort'` is emitted if the client aborts the authentication request. Other properties/methods available on `ctx` depends on the `ctx.method` of authentication the client has requested: + + * `hostbased`: + + * **blob** - _Buffer_ - This contains the data to be verified that is passed to (along with the signature) `key.verify()` where `key` is a public key parsed with [`parseKey()`](#utilities). + + * **key** - _object_ - Contains information about the public key sent by the client: + + * **algo** - _string_ - The name of the key algorithm (e.g. `ssh-rsa`). + + * **data** - _Buffer_ - The actual key data. + + * **localHostname** - _string_ - The local hostname provided by the client. + + * **localUsername** - _string_ - The local username provided by the client. + + * **signature** - _Buffer_ - This contains a signature to be verified that is passed to (along with the blob) `key.verify()` where `key` is a public key parsed with [`parseKey()`](#utilities). + + * **hashAlgo** - _mixed_ - This is either `undefined` or a _string_ containing an explicit hash algorithm to be used during verification (passed to `key.verify()`). + + * `keyboard-interactive`: + + * **prompt**(< _array_ >prompts[, < _string_ >title[, < _string_ >instructions]], < _function_ >callback) - _(void)_ - Send prompts to the client. `prompts` is an array of `{ prompt: 'Prompt text', echo: true }` objects (`prompt` being the prompt text and `echo` indicating whether the client's response to the prompt should be echoed to their display). `callback` is called with `(responses)`, where `responses` is an array of string responses matching up to the `prompts`. + + * **submethods** - _array_ - A list of preferred authentication "sub-methods" sent by the client. This may be used to determine what (if any) prompts to send to the client. + + * `password`: + + * **password** - _string_ - This is the password sent by the client. + + * **requestChange**(< _string_ >prompt, < _function_ >callback) - _(void)_ - Sends a password change request to the client. `callback` is called with `(newPassword)`, where `newPassword` is the new password supplied by the client. You may accept, reject, or prompt for another password change after `callback` is called. + + * `publickey`: + + * **blob** - _mixed_ - If the value is `undefined`, the client is only checking the validity of the `key`. If the value is a _Buffer_, then this contains the data to be verified that is passed to (along with the signature) `key.verify()` where `key` is a public key parsed with [`parseKey()`](#utilities). + + * **key** - _object_ - Contains information about the public key sent by the client: + + * **algo** - _string_ - The name of the key algorithm (e.g. `ssh-rsa`). + + * **data** - _Buffer_ - The actual key data. + + * **signature** - _mixed_ - If the value is `undefined`, the client is only checking the validity of the `key`. If the value is a _Buffer_, then this contains a signature to be verified that is passed to (along with the blob) `key.verify()` where `key` is a public key parsed with [`parseKey()`](#utilities). + + * **hashAlgo** - _mixed_ - This is either `undefined` or a _string_ containing an explicit hash algorithm to be used during verification (passed to `key.verify()`). + +* **close**() - The client socket was closed. + +* **end**() - The client socket disconnected. + +* **error**(< _Error_ >err) - An error occurred. + +* **handshake**(< _object_ >negotiated) - Emitted when a handshake has completed (either initial or rekey). `negotiated` contains the negotiated details of the handshake and is of the form: + +```js + // In this particular case `mac` is empty because there is no separate MAC + // because it's integrated into AES in GCM mode + { kex: 'ecdh-sha2-nistp256', + srvHostKey: 'rsa-sha2-512', + cs: { // Client to server algorithms + cipher: 'aes128-gcm', + mac: '', + compress: 'none', + lang: '' + }, + sc: { // Server to client algorithms + cipher: 'aes128-gcm', + mac: '', + compress: 'none', + lang: '' + } + } +``` + +* **openssh.streamlocal**(< _function_ >accept, < _function_ >reject, < _object_ >info) - Emitted when the client has requested a connection to a UNIX domain socket. `accept()` returns a new _Channel_ instance representing the connection. `info` contains: + + * **socketPath** - _string_ - Destination socket path of outgoing connection. + +* **ready**() - Emitted when the client has been successfully authenticated. + +* **rekey**() - Emitted when a rekeying operation has completed (either client or server-initiated). + +* **request**(< _mixed_ >accept, < _mixed_ >reject, < _string_ >name, < _object_ >info) - Emitted when the client has sent a global request for `name` (e.g. `tcpip-forward` or `cancel-tcpip-forward`). `accept` and `reject` are functions if the client requested a response. If `bindPort === 0`, you should pass the chosen port to `accept()` so that the client will know what port was bound. `info` contains additional details about the request: + + * `cancel-tcpip-forward` and `tcpip-forward`: + + * **bindAddr** - _string_ - The IP address to start/stop binding to. + + * **bindPort** - _integer_ - The port to start/stop binding to. + + * `cancel-streamlocal-forward@openssh.com` and `streamlocal-forward@openssh.com`: + + * **socketPath** - _string_ - The socket path to start/stop binding to. + +* **session**(< _function_ >accept, < _function_ >reject) - Emitted when the client has requested a new session. Sessions are used to start interactive shells, execute commands, request X11 forwarding, etc. `accept()` returns a new _Session_ instance. + +* **tcpip**(< _function_ >accept, < _function_ >reject, < _object_ >info) - Emitted when the client has requested an outbound (TCP) connection. `accept()` returns a new _Channel_ instance representing the connection. `info` contains: + + * **destIP** - _string_ - Destination IP address of outgoing connection. + + * **destPort** - _string_ - Destination port of outgoing connection. + + * **srcIP** - _string_ - Source IP address of outgoing connection. + + * **srcPort** - _string_ - Source port of outgoing connection. + +#### Connection methods + +* **end**() - _(void)_ - Closes the client connection. + +* **forwardOut**(< _string_ >boundAddr, < _integer_ >boundPort, < _string_ >remoteAddr, < _integer_ >remotePort, < _function_ >callback) - _(void)_ - Alert the client of an incoming TCP connection on `boundAddr` on port `boundPort` from `remoteAddr` on port `remotePort`. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +* **openssh_forwardOutStreamLocal**(< _string_ >socketPath, < _function_ >callback) - _(void)_ - Alert the client of an incoming UNIX domain socket connection on `socketPath`. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +* **rekey**([< _function_ >callback]) - _(void)_ - Initiates a rekey with the client. If `callback` is supplied, it is added as a one-time handler for the `rekey` event. + +* **setNoDelay**([< _boolean_ >noDelay]) - _Connection_ - Calls [`setNoDelay()`](https://nodejs.org/docs/latest/api/net.html#socketsetnodelaynodelay) on the underlying socket. Disabling Nagle's algorithm improves latency at the expense of lower throughput. + +* **x11**(< _string_ >originAddr, < _integer_ >originPort, < _function_ >callback) - _(void)_ - Alert the client of an incoming X11 client connection from `originAddr` on port `originPort`. `callback` has 2 parameters: < _Error_ >err, < _Channel_ >stream. + +#### Session events + +* **auth-agent**(< _mixed_ >accept, < _mixed_ >reject) - The client has requested incoming ssh-agent requests be forwarded to them. `accept` and `reject` are functions if the client requested a response. + +* **close**() - The session was closed. + +* **env**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client requested an environment variable to be set for this session. `accept` and `reject` are functions if the client requested a response. `info` has these properties: + + * **key** - _string_ - The environment variable's name. + + * **value** - _string_ - The environment variable's value. + +* **exec**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client has requested execution of a command string. `accept` and `reject` are functions if the client requested a response. `accept()` returns a _Channel_ for the command execution. `info` has these properties: + + * **command** - _string_ - The command line to be executed. + +* **pty**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client requested allocation of a pseudo-TTY for this session. `accept` and `reject` are functions if the client requested a response. `info` has these properties: + + * **term** - _string_ - The terminal type for the pseudo-TTY. + + * **cols** - _integer_ - The number of columns for the pseudo-TTY. + + * **height** - _integer_ - The height of the pseudo-TTY in pixels. + + * **modes** - _object_ - Contains the requested terminal modes of the pseudo-TTY keyed on the mode name with the value being the mode argument. (See the table at the end for valid names). + + * **rows** - _integer_ - The number of rows for the pseudo-TTY. + + * **width** - _integer_ - The width of the pseudo-TTY in pixels. + +* **sftp**(< _mixed_ >accept, < _mixed_ >reject) - The client has requested the SFTP subsystem. `accept` and `reject` are functions if the client requested a response. `accept()` returns an _SFTP_ instance in server mode (see the [`SFTP` documentation](https://github.com/mscdex/ssh2/blob/master/SFTP.md) for details). `info` has these properties: + +* **shell**(< _mixed_ >accept, < _mixed_ >reject) - The client has requested an interactive shell. `accept` and `reject` are functions if the client requested a response. `accept()` returns a _Channel_ for the interactive shell. + +* **signal**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client has sent a signal. `accept` and `reject` are functions if the client requested a response. `info` has these properties: + + * **name** - _string_ - The signal name (e.g. `SIGUSR1`). + +* **subsystem**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client has requested an arbitrary subsystem. `accept` and `reject` are functions if the client requested a response. `accept()` returns a _Channel_ for the subsystem. `info` has these properties: + + * **name** - _string_ - The name of the subsystem. + +* **window-change**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client reported a change in window dimensions during this session. `accept` and `reject` are functions if the client requested a response. `info` has these properties: + + * **cols** - _integer_ - The new number of columns for the client window. + + * **height** - _integer_ - The new height of the client window in pixels. + + * **rows** - _integer_ - The new number of rows for the client window. + + * **width** - _integer_ - The new width of the client window in pixels. + +* **x11**(< _mixed_ >accept, < _mixed_ >reject, < _object_ >info) - The client requested X11 forwarding. `accept` and `reject` are functions if the client requested a response. `info` has these properties: + + * **cookie** - _string_ - The X11 authentication cookie encoded in hexadecimal. + + * **protocol** - _string_ - The name of the X11 authentication method used (e.g. `MIT-MAGIC-COOKIE-1`). + + * **screen** - _integer_ - The screen number to forward X11 connections for. + + * **single** - _boolean_ - `true` if only a single connection should be forwarded. + +### Channel + +This is a normal **streams2** Duplex Stream (used both by clients and servers), with the following changes: + +* A boolean property `allowHalfOpen` exists and behaves similarly to the property of the same name for `net.Socket`. When the stream's end() is called, if `allowHalfOpen` is `true`, only EOF will be sent (the server can still send data if they have not already sent EOF). The default value for this property is `true`. + +* A `close` event is emitted once the channel is completely closed on both the client and server. + +* Client-specific: + + * For exec(): + + * An `exit` event *may* (the SSH2 spec says it is optional) be emitted when the process finishes. If the process finished normally, the process's return value is passed to the `exit` callback. If the process was interrupted by a signal, the following are passed to the `exit` callback: null, < _string_ >signalName, < _boolean_ >didCoreDump, < _string_ >description. + + * If there was an `exit` event, the `close` event will be passed the same arguments for convenience. + + * A `stderr` property contains a Readable stream that represents output from stderr. + + * For exec() and shell(): + + * The readable side represents stdout and the writable side represents stdin. + + * **setWindow**(< _integer_ >rows, < _integer_ >cols, < _integer_ >height, < _integer_ >width) - _(void)_ - Lets the server know that the local terminal window has been resized. The meaning of these arguments are described in the 'Pseudo-TTY settings' section. + + * **signal**(< _string_ >signalName) - _(void)_ - Sends a POSIX signal to the current process on the server. Valid signal names are: 'ABRT', 'ALRM', 'FPE', 'HUP', 'ILL', 'INT', 'KILL', 'PIPE', 'QUIT', 'SEGV', 'TERM', 'USR1', and 'USR2'. Some server implementations may ignore this request if they do not support signals. Note: If you are trying to send SIGINT and you find `signal()` doesn't work, try writing `'\x03'` to the Channel stream instead. + + +* Server-specific: + + * For exec-enabled channel instances there is an additional method available that may be called right before you close the channel. It has two different signatures: + + * **exit**(< _integer_ >exitCode) - _(void)_ - Sends an exit status code to the client. + + * **exit**(< _string_ >signalName[, < _boolean_ >coreDumped[, < _string_ >errorMsg]]) - _(void)_ - Sends an exit status code to the client. + + * For exec and shell-enabled channel instances, `channel.stderr` is a writable stream. + +### Pseudo-TTY settings + +* **cols** - < _integer_ > - Number of columns. **Default:** `80` + +* **height** - < _integer_ > - Height in pixels. **Default:** `480` + +* **modes** - < _object_ > - An object containing [Terminal Modes](#terminal-modes) as keys, with each value set to each mode argument. **Default:** `null` + +* **rows** - < _integer_ > - Number of rows. **Default:** `24` + +* **term** - < _string_ > - The value to use for $TERM. **Default:** `'vt100'` + +* **width** - < _integer_ > - Width in pixels. **Default:** `640` + +`rows` and `cols` override `width` and `height` when `rows` and `cols` are non-zero. + +Pixel dimensions refer to the drawable area of the window. + +Zero dimension parameters are ignored. + +### Terminal modes + +Name | Description +-------------- | ------------ +CS7 | 7 bit mode. +CS8 | 8 bit mode. +ECHOCTL | Echo control characters as ^(Char). +ECHO | Enable echoing. +ECHOE | Visually erase chars. +ECHOKE | Visual erase for line kill. +ECHOK | Kill character discards current line. +ECHONL | Echo NL even if ECHO is off. +ICANON | Canonicalize input lines. +ICRNL | Map CR to NL on input. +IEXTEN | Enable extensions. +IGNCR | Ignore CR on input. +IGNPAR | The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE, and 1 if it is TRUE. +IMAXBEL | Ring bell on input queue full. +INLCR | Map NL into CR on input. +INPCK | Enable checking of parity errors. +ISIG | Enable signals INTR, QUIT, [D]SUSP. +ISTRIP | Strip 8th bit off characters. +IUCLC | Translate uppercase characters to lowercase. +IXANY | Any char will restart after stop. +IXOFF | Enable input flow control. +IXON | Enable output flow control. +NOFLSH | Don't flush after interrupt. +OCRNL | Translate carriage return to newline (output). +OLCUC | Convert lowercase to uppercase. +ONLCR | Map NL to CR-NL. +ONLRET | Newline performs a carriage return (output). +ONOCR | Translate newline to carriage return-newline (output). +OPOST | Enable output processing. +PARENB | Parity enable. +PARMRK | Mark parity and framing errors. +PARODD | Odd parity, else even. +PENDIN | Retype pending input. +TOSTOP | Stop background jobs from output. +TTY_OP_ISPEED | Specifies the input baud rate in bits per second. +TTY_OP_OSPEED | Specifies the output baud rate in bits per second. +VDISCARD | Toggles the flushing of terminal output. +VDSUSP | Another suspend character. +VEOF | End-of-file character (sends EOF from the terminal). +VEOL2 | Additional end-of-line character. +VEOL | End-of-line character in addition to carriage return and/or linefeed. +VERASE | Erase the character to left of the cursor. +VFLUSH | Character to flush output. +VINTR | Interrupt character; 255 if none. Similarly for the other characters. Not all of these characters are supported on all systems. +VKILL | Kill the current input line. +VLNEXT | Enter the next character typed literally, even if it is a special character +VQUIT | The quit character (sends SIGQUIT signal on POSIX systems). +VREPRINT | Reprints the current input line. +VSTART | Continues paused output (normally control-Q). +VSTATUS | Prints system status line (load, command, pid, etc). +VSTOP | Pauses output (normally control-S). +VSUSP | Suspends the current program. +VSWTCH | Switch to a different shell layer. +VWERASE | Erases a word left of cursor. +XCASE | Enable input and output of uppercase characters by preceding their lowercase equivalents with "\". + +### HTTPAgent + +#### HTTPAgent methods + +* **(constructor)**(< _object_ >sshConfig[, < _object_ >agentConfig]) - Creates and returns a new `http.Agent` instance used to tunnel an HTTP connection over SSH. `sshConfig` is what is passed to `client.connect()` and `agentOptions` is passed to the `http.Agent` constructor. + +### HTTPSAgent + +#### HTTPSAgent methods + +* **(constructor)**(< _object_ >sshConfig[, < _object_ >agentConfig]) - Creates and returns a new `https.Agent` instance used to tunnel an HTTP connection over SSH. `sshConfig` is what is passed to `client.connect()` and `agentOptions` is passed to the `https.Agent` constructor. + +### Utilities + +* **generateKeyPair**(< _string_ >keyType[, < _object_ >options], < _function_ >callback) - _(void)_ - Generates an SSH key pair of the given type. `keyType` may be one of `'rsa'`, `'ecdsa'`, or `'ed25519'` (node.js v12+). `callback` has the signature `(err, keys)` where `keys` is an _object_ containing `private` and `public` properties containing the generated SSH keys. `options` may contain: + + * **bits** - _integer_ - For ECDSA and RSA keys, this is the key strength. For ECDSA, this is restricted to `256`, `384`, or `521`. **Default:** (none) + + * **cipher** - _string_ - The (SSH, not OpenSSL) cipher to use to encrypt the key. **Default:** (none) + + * **comment** - _string_ - A comment to include in the private and public keys. **Default:** `''` + + * **format** - _string_ - The SSH key format to use. Currently only `'new'` is supported, which represents the current OpenSSH key formats. **Default:** `'new'` + + * **passphrase** - _mixed_ - The desired passphrase for encrypting the key. This can either be a string or _Buffer_. **Default:** (none) + + * **rounds** - _integer_ - For `'new'`-formatted SSH keys, this is the number of bcrypt rounds to use when generating cipher parameters for encrypted keys. **Default:** `16` + +* **generateKeyPairSync**(< _string_ >keyType[, < _object_ >options]) - _object_ - Generates an SSH key pair of the given type. This is a synchronous version of `generateKeyPair()`. + +* **parseKey**(< _mixed_ >keyData[, < _string_ >passphrase]) - _mixed_ - Parses a private/public key in OpenSSH, RFC4716, or PPK format. For encrypted private keys, the key will be decrypted with the given `passphrase`. `keyData` can be a _Buffer_ or _string_ value containing the key contents. The returned value will be an array of objects (currently in the case of modern OpenSSH keys) or an object with these properties and methods: + + * **comment** - _string_ - The comment for the key + + * **equals**(< _mixed_ >otherKey) - _boolean_ - This returns `true` if `otherKey` (a parsed or parseable key) is the same as this key. This method does not compare the keys' comments + + * **getPrivatePEM**() - _string_ - This returns the PEM version of a private key + + * **getPublicPEM**() - _string_ - This returns the PEM version of a public key (for either public key or derived from a private key) + + * **getPublicSSH**() - _string_ - This returns the SSH version of a public key (for either public key or derived from a private key) + + * **isPrivateKey**() - _boolean_ - This returns `true` if the key is a private key or not + + * **sign**(< _mixed_ >data) - _mixed_ - This signs the given `data` using this key and returns a _Buffer_ containing the signature on success. On failure, an _Error_ will be returned. `data` can be anything accepted by node's [`sign.update()`](https://nodejs.org/docs/latest/api/crypto.html#crypto_sign_update_data_inputencoding). + + * **type** - _string_ - The full key type (e.g. `'ssh-rsa'`) + + * **verify**(< _mixed_ >data, < _Buffer_ >signature) - _mixed_ - This verifies a `signature` of the given `data` using this key and returns `true` if the signature could be verified. On failure, either `false` will be returned or an _Error_ will be returned upon a more critical failure. `data` can be anything accepted by node's [`verify.update()`](https://nodejs.org/docs/latest/api/crypto.html#crypto_verify_update_data_inputencoding). + +* **sftp.OPEN_MODE** - [`OPEN_MODE`](https://github.com/mscdex/ssh2/blob/master/SFTP.md#useful-standalone-data-structures) + +* **sftp.STATUS_CODE** - [`STATUS_CODE`](https://github.com/mscdex/ssh2/blob/master/SFTP.md#useful-standalone-data-structures) + +* **sftp.flagsToString** - [`flagsToString()`](https://github.com/mscdex/ssh2/blob/master/SFTP.md#useful-standalone-methods) + +* **sftp.stringToFlags** - [`stringToFlags()`](https://github.com/mscdex/ssh2/blob/master/SFTP.md#useful-standalone-methods) + +### AgentProtocol + +#### AgentProtocol events + +* **identities**(< _opaque_ >request) - **(Server mode only)** The client has requested a list of public keys stored in the agent. Use `failureReply()` or `getIdentitiesReply()` to reply appropriately. + +* **sign**(< _opaque_ >request, < _mixed_ >pubKey, < _Buffer_ >data, < _object_ >options) - **(Server mode only)** The client has requested `data` to be signed using the key identified by `pubKey`. Use `failureReply()` or `signReply()` to reply appropriately. `options` may contain any of: + + * **hash** - _string_ - The explicitly desired hash to use when computing the signature. Currently if set, this may be either `'sha256'` or `'sha512'` for RSA keys. + +#### AgentProtocol methods + +* **(constructor)**(< _boolean_ >isClient) - Creates and returns a new AgentProtocol instance. `isClient` determines whether the instance operates in client or server mode. + +* **failureReply**(< _opaque_ >request) - _(void)_ - **(Server mode only)** Replies to the given `request` with a failure response. + +* **getIdentities**(< _function_ >callback) - _(void)_ - **(Client mode only)** Requests a list of public keys from the agent. `callback` is passed `(err, keys)` where `keys` is a possible array of public keys for authentication. + +* **getIdentitiesReply**(< _opaque_ >request, < _array_ >keys) - _(void)_ - **(Server mode only)** Responds to a identities list `request` with the given array of keys in `keys`. + +* **sign**(< _mixed_ >pubKey, < _Buffer_ >data, < _object_ >options, < _function_ >callback) - _(void)_ - **(Client mode only)** Requests that the agent sign `data` using the key identified by `pubKey`. `pubKey` can be any parsed (using `utils.parseKey()`) or parseable key value. `callback` is passed `(err, signature)` where `signature` is a possible _Buffer_ containing the signature for the `data`. `options` may contain any of: + + * **hash** - _string_ - The explicitly desired hash to use when computing the signature. Currently if set, this may be either `'sha256'` or `'sha512'` for RSA keys. + +* **signReply**(< _opaque_ >request, < _Buffer_ >signature) - _(void)_ - **(Server mode only)** Responds to a sign `request` with the given signature in `signature`. + +### BaseAgent + +In order to create a custom agent, your class *must*: + + * Extend `BaseAgent` + * Call `super()` in its constructor + * Implement *at least* the following methods: + +* **getIdentities**(< _function_ >callback) - _(void)_ - Passes `(err, keys)` to `callback` where `keys` is a possible array of public keys for authentication. + +* **sign**(< _mixed_ >pubKey, < _Buffer_ >data, < _object_ >options, < _function_ >callback) - _(void)_ - Signs `data` using the key identified by `pubKey`. `pubKey` can be any parsed (using `utils.parseKey()`) or parseable key value. `callback` should be passed `(err, signature)` where `signature` is a possible _Buffer_ containing the signature for the `data`. `options` may contain any of: + + * **hash** - _string_ - The explicitly desired hash to use when computing the signature. Currently if set, this may be either `'sha256'` or `'sha512'` for RSA keys. + +Additionally your class may implement the following method in order to support agent forwarding on the client: + +* **getStream**(< _function_ >callback) - _(void)_ - Passes `(err, stream)` to `callback` where `stream` is a possible Duplex stream to be used to communicate with your agent. You will probably want to utilize `AgentProtocol` as agent forwarding is an OpenSSH feature, so the `stream` needs to be able to transmit/receive OpenSSH agent protocol packets. + +### createAgent + +* **createAgent**(< _string_ >agentValue) - _(Agent)_ - Creates and returns a new agent instance using the same logic as the `Client`'s `agent` configuration option: if the platform is Windows and it's the value "pageant", it creates a `PageantAgent`, otherwise if it's not a path to a Windows pipe it creates a `CygwinAgent`. In all other cases, it creates an `OpenSSHAgent`. + +### CygwinAgent + +#### CygwinAgent methods + +* **(constructor)**(< _string_ >socketPath) - Communicates with an agent listening at `socketPath` in a Cygwin environment. + +### OpenSSHAgent + +#### OpenSSHAgent methods + +* **(constructor)**(< _string_ >socketPath) - Communicates with an OpenSSH agent listening on the UNIX socket at `socketPath`. + +### PageantAgent + +#### PageantAgent methods + +* **(constructor)**() - Creates a new agent instance for communicating with a running Pageant agent process. diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/SFTP.md b/tasks/enduro-trails/prototype/node_modules/ssh2/SFTP.md new file mode 100644 index 0000000..9353ae8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/SFTP.md @@ -0,0 +1,413 @@ +SFTP events +----------- + +**Client/Server events** + +* **ready**() - Emitted after initial protocol version check has passed. + +**Server-only events** + +_Responses to these client requests are sent using one of the methods listed further in this document under `Server-only methods`. The valid response(s) for each request are documented below._ + +* **OPEN**(< _integer_ >reqID, < _string_ >filename, < _integer_ >flags, < _ATTRS_ >attrs) + + `flags` is a bitfield containing any of the flags defined in `OPEN_MODE`. + Use the static method `flagsToString()` to convert the value to a mode + string to be used by `fs.open()` (e.g. `'r'`). + + Respond using one of the following: + + * `handle()` - This indicates a successful opening of the file and passes + the given handle back to the client to use to refer to this open file for + future operations (e.g. reading, writing, closing). + + * `status()` - Use this to indicate a failure to open the requested file. + +* **READ**(< _integer_ >reqID, < _Buffer_ >handle, < _integer_ >offset, < _integer_ >length) + + Respond using one of the following: + + * `data()` - Use this to send the requested chunk of data back to the client. + The amount of data sent is allowed to be less than the `length` requested, + for example if the file ends between `offset` and `offset + length`. + + * `status()` - Use this to indicate either end of file (`STATUS_CODE.EOF`) + has been reached (`offset` is past the end of the file) or if an error + occurred while reading the requested part of the file. + +* **WRITE**(< _integer_ >reqID, < _Buffer_ >handle, < _integer_ >offset, < _Buffer_ >data) + + Respond using: + + * `status()` - Use this to indicate success/failure of the write to the file. + +* **FSTAT**(< _integer_ >reqID, < _Buffer_ >handle) + + Respond using one of the following: + + * `attrs()` - Use this to send the attributes for the requested + file/directory back to the client. + + * `status()` - Use this to indicate an error occurred while accessing the + file/directory. + +* **FSETSTAT**(< _integer_ >reqID, < _Buffer_ >handle, < _ATTRS_ >attrs) + + Respond using: + + * `status()` - Use this to indicates success/failure of the setting of the + given file/directory attributes. + +* **CLOSE**(< _integer_ >reqID, < _Buffer_ >handle) + + Respond using: + + * `status()` - Use this to indicate success (`STATUS_CODE.OK`) or failure of + the closing of the file identified by `handle`. + +* **OPENDIR**(< _integer_ >reqID, < _string_ >path) + + Respond using one of the following: + + * `handle()` - This indicates a successful opening of the directory and + passes the given handle back to the client to use to refer to this open + directory for future operations (e.g. reading directory contents, closing). + + * `status()` - Use this to indicate a failure to open the requested + directory. + +* **READDIR**(< _integer_ >reqID, < _Buffer_ >handle) + + Respond using one of the following: + + * `name()` - Use this to send one or more directory listings for the open + directory back to the client. + + * `status()` - Use this to indicate either end of directory contents + (`STATUS_CODE.EOF`) or if an error occurred while reading the directory + contents. + +* **LSTAT**(< _integer_ >reqID, < _string_ >path) + + Respond using one of the following: + + * `attrs()` - Use this to send the attributes for the requested + file/directory back to the client. + + * `status()` - Use this to indicate an error occurred while accessing the + file/directory. + +* **STAT**(< _integer_ >reqID, < _string_ >path) + + Respond using one of the following: + + * `attrs()` - Use this to send the attributes for the requested + file/directory back to the client. + + * `status()` - Use this to indicate an error occurred while accessing the + file/directory. + +* **REMOVE**(< _integer_ >reqID, < _string_ >path) + + Respond using: + + * `status()` - Use this to indicate success/failure of the removal of the + file at `path`. + +* **RMDIR**(< _integer_ >reqID, < _string_ >path) + + Respond using: + + * `status()` - Use this to indicate success/failure of the removal of the + directory at `path`. + +* **REALPATH**(< _integer_ >reqID, < _string_ >path) + + Respond using one of the following: + + * `name()` - Use this to respond with a normalized version of `path`. + No file/directory attributes are required to be sent in this response. + + * `status()` - Use this to indicate a failure in normalizing `path`. + +* **READLINK**(< _integer_ >reqID, < _string_ >path) + + Respond using one of the following: + + * `name()` - Use this to respond with the target of the symlink at `path`. + No file/directory attributes are required to be sent in this response. + + * `status()` - Use this to indicate a failure in reading the symlink at + `path`. + +* **SETSTAT**(< _integer_ >reqID, < _string_ >path, < _ATTRS_ >attrs) + + Respond using: + + * `status()` - Use this to indicates success/failure of the setting of the + given file/directory attributes. + +* **MKDIR**(< _integer_ >reqID, < _string_ >path, < _ATTRS_ >attrs) + + Respond using: + + * `status()` - Use this to indicate success/failure of the creation of the + directory at `path`. + +* **RENAME**(< _integer_ >reqID, < _string_ >oldPath, < _string_ >newPath) + + Respond using: + + * `status()` - Use this to indicate success/failure of the renaming of the + file/directory at `oldPath` to `newPath`. + +* **SYMLINK**(< _integer_ >reqID, < _string_ >linkPath, < _string_ >targetPath) + + Respond using: + + * `status()` - Use this to indicate success/failure of the symlink creation. + + +Useful standalone data structures +--------------------------------- + +* **STATUS_CODE** - _object_ - Contains the various status codes (for use especially with `status()`): + + * `OK` + + * `EOF` + + * `NO_SUCH_FILE` + + * `PERMISSION_DENIED` + + * `FAILURE` + + * `BAD_MESSAGE` + + * `OP_UNSUPPORTED` + +* **OPEN_MODE** - _object_ - Contains the various open file flags: + + * `READ` + + * `WRITE` + + * `APPEND` + + * `CREAT` + + * `TRUNC` + + * `EXCL` + + +Useful standalone methods +------------------------- + +* **stringToFlags**(< _string_ >flagsStr) - _integer_ - Converts string flags (e.g. `'r'`, `'a+'`, etc.) to the appropriate `OPEN_MODE` flag mask. Returns `null` if conversion failed. + +* **flagsToString**(< _integer_ >flagsMask) - _string_ - Converts flag mask (e.g. number containing `OPEN_MODE` values) to the appropriate string value. Returns `null` if conversion failed. + + +SFTP methods +------------ + +* **(constructor)**(< _object_ >config[, < _string_ >remoteIdentRaw]) - Creates and returns a new SFTP instance. `remoteIdentRaw` can be the raw SSH identification string of the remote party. This is used to change internal behavior based on particular SFTP implementations. `config` can contain: + + * **server** - _boolean_ - Set to `true` to create an instance in server mode. **Default:** `false` + + * **debug** - _function_ - Set this to a function that receives a single string argument to get detailed (local) debug information. **Default:** (none) + + + +**Client-only methods** + +* **fastGet**(< _string_ >remotePath, < _string_ >localPath[, < _object_ >options], < _function_ >callback) - _(void)_ - Downloads a file at `remotePath` to `localPath` using parallel reads for faster throughput. `options` can have the following properties: + + * **concurrency** - _integer_ - Number of concurrent reads **Default:** `64` + + * **chunkSize** - _integer_ - Size of each read in bytes **Default:** `32768` + + * **step** - _function_(< _integer_ >total_transferred, < _integer_ >chunk, < _integer_ >total) - Called every time a part of a file was transferred + + `callback` has 1 parameter: < _Error_ >err. + +* **fastPut**(< _string_ >localPath, < _string_ >remotePath[, < _object_ >options], < _function_ >callback) - _(void)_ - Uploads a file from `localPath` to `remotePath` using parallel reads for faster throughput. `options` can have the following properties: + + * **concurrency** - _integer_ - Number of concurrent reads **Default:** `64` + + * **chunkSize** - _integer_ - Size of each read in bytes **Default:** `32768` + + * **step** - _function_(< _integer_ >total_transferred, < _integer_ >chunk, < _integer_ >total) - Called every time a part of a file was transferred + + * **mode** - _mixed_ - Integer or string representing the file mode to set for the uploaded file. + + `callback` has 1 parameter: < _Error_ >err. + +* **createReadStream**(< _string_ >path[, < _object_ >options]) - _ReadStream_ - Returns a new readable stream for `path`. `options` has the following defaults: + + ```javascript + { flags: 'r', + encoding: null, + handle: null, + mode: 0o666, + autoClose: true + } + ``` + + `options` can include `start` and `end` values to read a range of bytes from the file instead of the entire file. Both `start` and `end` are inclusive and start at 0. The `encoding` can be `'utf8'`, `'ascii'`, or `'base64'`. + + If `autoClose` is false, then the file handle won't be closed, even if there's an error. It is your responsibility to close it and make sure there's no file handle leak. If `autoClose` is set to true (default behavior), on `error` or `end` the file handle will be closed automatically. + + An example to read the last 10 bytes of a file which is 100 bytes long: + + ```javascript + sftp.createReadStream('sample.txt', {start: 90, end: 99}); + ``` + +* **createWriteStream**(< _string_ >path[, < _object_ >options]) - _WriteStream_ - Returns a new writable stream for `path`. `options` has the following defaults: + + ```javascript + { + flags: 'w', + encoding: null, + mode: 0o666, + autoClose: true + } + ``` + + `options` may also include a `start` option to allow writing data at some position past the beginning of the file. Modifying a file rather than replacing it may require a flags mode of 'r+' rather than the default mode 'w'. + + If 'autoClose' is set to false and you pipe to this stream, this stream will not automatically close after there is no more data upstream -- allowing future pipes and/or manual writes. + +* **open**(< _string_ >filename, < _string_ >flags, [< _mixed_ >attrs_mode, ]< _function_ >callback) - _(void)_ - Opens a file `filename` with `flags` with optional _ATTRS_ object or file mode `attrs_mode`. `flags` is any of the flags supported by `fs.open` (except sync flag). `callback` has 2 parameters: < _Error_ >err, < _Buffer_ >handle. + +* **close**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - Closes the resource associated with `handle` given by open() or opendir(). `callback` has 1 parameter: < _Error_ >err. + +* **read**(< _Buffer_ >handle, < _Buffer_ >buffer, < _integer_ >offset, < _integer_ >length, < _integer_ >position, < _function_ >callback) - _(void)_ - Reads `length` bytes from the resource associated with `handle` starting at `position` and stores the bytes in `buffer` starting at `offset`. `callback` has 4 parameters: < _Error_ >err, < _integer_ >bytesRead, < _Buffer_ >buffer (offset adjusted), < _integer_ >position. + +* **write**(< _Buffer_ >handle, < _Buffer_ >buffer, < _integer_ >offset, < _integer_ >length, < _integer_ >position, < _function_ >callback) - _(void)_ - Writes `length` bytes from `buffer` starting at `offset` to the resource associated with `handle` starting at `position`. `callback` has 1 parameter: < _Error_ >err. + +* **fstat**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - Retrieves attributes for the resource associated with `handle`. `callback` has 2 parameters: < _Error_ >err, < _Stats_ >stats. + +* **fsetstat**(< _Buffer_ >handle, < _ATTRS_ >attributes, < _function_ >callback) - _(void)_ - Sets the attributes defined in `attributes` for the resource associated with `handle`. `callback` has 1 parameter: < _Error_ >err. + +* **futimes**(< _Buffer_ >handle, < _mixed_ >atime, < _mixed_ >mtime, < _function_ >callback) - _(void)_ - Sets the access time and modified time for the resource associated with `handle`. `atime` and `mtime` can be Date instances or UNIX timestamps. `callback` has 1 parameter: < _Error_ >err. + +* **fchown**(< _Buffer_ >handle, < _integer_ >uid, < _integer_ >gid, < _function_ >callback) - _(void)_ - Sets the owner for the resource associated with `handle`. `callback` has 1 parameter: < _Error_ >err. + +* **fchmod**(< _Buffer_ >handle, < _mixed_ >mode, < _function_ >callback) - _(void)_ - Sets the mode for the resource associated with `handle`. `mode` can be an integer or a string containing an octal number. `callback` has 1 parameter: < _Error_ >err. + +* **opendir**(< _string_ >path, < _function_ >callback) - _(void)_ - Opens a directory `path`. `callback` has 2 parameters: < _Error_ >err, < _Buffer_ >handle. + +* **readdir**(< _mixed_ >location, < _function_ >callback) - _(void)_ - Retrieves a directory listing. `location` can either be a _Buffer_ containing a valid directory handle from opendir() or a _string_ containing the path to a directory. `callback` has 2 parameters: < _Error_ >err, < _mixed_ >list. `list` is an _Array_ of `{ filename: 'foo', longname: '....', attrs: {...} }` style objects (attrs is of type _ATTR_). If `location` is a directory handle, this function may need to be called multiple times until `list` is boolean false, which indicates that no more directory entries are available for that directory handle. + +* **unlink**(< _string_ >path, < _function_ >callback) - _(void)_ - Removes the file/symlink at `path`. `callback` has 1 parameter: < _Error_ >err. + +* **rename**(< _string_ >srcPath, < _string_ >destPath, < _function_ >callback) - _(void)_ - Renames/moves `srcPath` to `destPath`. `callback` has 1 parameter: < _Error_ >err. + +* **mkdir**(< _string_ >path, [< _ATTRS_ >attributes, ]< _function_ >callback) - _(void)_ - Creates a new directory `path`. `callback` has 1 parameter: < _Error_ >err. + +* **rmdir**(< _string_ >path, < _function_ >callback) - _(void)_ - Removes the directory at `path`. `callback` has 1 parameter: < _Error_ >err. + +* **stat**(< _string_ >path, < _function_ >callback) - _(void)_ - Retrieves attributes for `path`. `callback` has 2 parameter: < _Error_ >err, < _Stats_ >stats. + +* **lstat**(< _string_ >path, < _function_ >callback) - _(void)_ - Retrieves attributes for `path`. If `path` is a symlink, the link itself is stat'ed instead of the resource it refers to. `callback` has 2 parameters: < _Error_ >err, < _Stats_ >stats. + +* **setstat**(< _string_ >path, < _ATTRS_ >attributes, < _function_ >callback) - _(void)_ - Sets the attributes defined in `attributes` for `path`. `callback` has 1 parameter: < _Error_ >err. + +* **utimes**(< _string_ >path, < _mixed_ >atime, < _mixed_ >mtime, < _function_ >callback) - _(void)_ - Sets the access time and modified time for `path`. `atime` and `mtime` can be Date instances or UNIX timestamps. `callback` has 1 parameter: < _Error_ >err. + +* **chown**(< _string_ >path, < _integer_ >uid, < _integer_ >gid, < _function_ >callback) - _(void)_ - Sets the owner for `path`. `callback` has 1 parameter: < _Error_ >err. + +* **chmod**(< _string_ >path, < _mixed_ >mode, < _function_ >callback) - _(void)_ - Sets the mode for `path`. `mode` can be an integer or a string containing an octal number. `callback` has 1 parameter: < _Error_ >err. + +* **readlink**(< _string_ >path, < _function_ >callback) - _(void)_ - Retrieves the target for a symlink at `path`. `callback` has 2 parameters: < _Error_ >err, < _string_ >target. + +* **symlink**(< _string_ >targetPath, < _string_ >linkPath, < _function_ >callback) - _(void)_ - Creates a symlink at `linkPath` to `targetPath`. `callback` has 1 parameter: < _Error_ >err. + +* **realpath**(< _string_ >path, < _function_ >callback) - _(void)_ - Resolves `path` to an absolute path. `callback` has 2 parameters: < _Error_ >err, < _string_ >absPath. + +* **ext_openssh_rename**(< _string_ >srcPath, < _string_ >destPath, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX rename(3) from `srcPath` to `destPath`. `callback` has 1 parameter: < _Error_ >err. + +* **ext_openssh_statvfs**(< _string_ >path, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX statvfs(2) on `path`. `callback` has 2 parameters: < _Error_ >err, < _object_ >fsInfo. `fsInfo` contains the information as found in the [statvfs struct](http://linux.die.net/man/2/statvfs). + +* **ext_openssh_fstatvfs**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX fstatvfs(2) on open handle `handle`. `callback` has 2 parameters: < _Error_ >err, < _object_ >fsInfo. `fsInfo` contains the information as found in the [statvfs struct](http://linux.die.net/man/2/statvfs). + +* **ext_openssh_hardlink**(< _string_ >targetPath, < _string_ >linkPath, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX link(2) to create a hard link to `targetPath` at `linkPath`. `callback` has 1 parameter: < _Error_ >err. + +* **ext_openssh_fsync**(< _Buffer_ >handle, < _function_ >callback) - _(void)_ - **OpenSSH extension** Performs POSIX fsync(3) on the open handle `handle`. `callback` has 1 parameter: < _Error_ >err. + +* **ext_openssh_lsetstat**(< _string_ >path, < _ATTRS_ >attributes, < _function_ >callback) - _(void)_ - **OpenSSH extension** Similar to `setstat()`, but instead sets attributes on symlinks. `callback` has 1 parameter: < _Error_ >err. + +* **ext_openssh_expandPath**(< _string_ >path, < _function_ >callback) - _(void)_ - **OpenSSH extension** Similar to `realpath()`, but supports tilde-expansion, i.e. "\~", "\~/..." and "\~user/...". These paths are expanded using shell-like rules. `callback` has 2 parameters: < _Error_ >err, < _string_ >expandedPath. + +* **ext_copy_data**(< _Buffer_ >srcHandle, < _number_ >srcOffset, < _number_ >length, < _Buffer_ >dstHandle, < _number_ >dstOffset, < _function_ >callback) - _(void)_ - Performs a remote file copy. If `length` is 0, then the server will read from `srcHandle` until EOF is reached. `callback` has 1 parameter: < _Error_ >err. + +* **ext_home_dir**(< _string_ >username, < _function_ >callback) - _(void)_ - Retrieves the home directory of the user identified by `username`. Use an empty string to refer to the current user. `callback` has 2 parameters: < _Error_ >err, < _string_ >homeDirectory. + +* **ext_users_groups**(< _array_ >uids, < _array_ >gids, < _function_ >callback) - _(void)_ - Retrieves the user names and group names associated with the user IDs in `uids` and group IDs in `gids` respectively. Either array can be empty or contain one or more 32-bit unsigned integers. The retrieved user names and group names match the same order as the IDs in `uids` and `gids` respectively. If the server was unable to find a name for a given ID, it will use an empty string. `callback` has 3 parameters: < _Error_ >err, < _array_ >userNames, < _array_ >groupNames. + + +**Server-only methods** + +* **status**(< _integer_ >reqID, < _integer_ >statusCode[, < _string_ >message]) - _(void)_ - Sends a status response for the request identified by `id`. + +* **handle**(< _integer_ >reqID, < _Buffer_ >handle) - _(void)_ - Sends a handle response for the request identified by `id`. `handle` must be less than 256 bytes and is an opaque value that could merely contain the value of a backing file descriptor or some other unique, custom value. + +* **data**(< _integer_ >reqID, < _mixed_ >data[, < _string_ >encoding]) - _(void)_ - Sends a data response for the request identified by `id`. `data` can be a _Buffer_ or _string_. If `data` is a string, `encoding` is the encoding of `data`. + +* **name**(< _integer_ >reqID, < _array_ >names) - _(void)_ - Sends a name response for the request identified by `id`. `names` must be an _array_ of _object_ where each _object_ can contain: + + * **filename** - _string_ - The entry's name. + + * **longname** - _string_ - This is the `ls -l`-style format for the entry (e.g. `-rwxr--r-- 1 bar bar 718 Dec 8 2009 foo`) + + * **attrs** - _ATTRS_ - This is an optional _ATTRS_ object that contains requested/available attributes for the entry. + +* **attrs**(< _integer_ >reqID, < _ATTRS_ >attrs) - _(void)_ - Sends an attrs response for the request identified by `id`. `attrs` contains the requested/available attributes. + + +ATTRS +----- + +An object with the following valid properties: + +* **mode** - _integer_ - Mode/permissions for the resource. + +* **uid** - _integer_ - User ID of the resource. + +* **gid** - _integer_ - Group ID of the resource. + +* **size** - _integer_ - Resource size in bytes. + +* **atime** - _integer_ - UNIX timestamp of the access time of the resource. + +* **mtime** - _integer_ - UNIX timestamp of the modified time of the resource. + +When supplying an ATTRS object to one of the SFTP methods: + +* `atime` and `mtime` can be either a Date instance or a UNIX timestamp. + +* `mode` can either be an integer or a string containing an octal number. + + +Stats +----- + +An object with the same attributes as an ATTRS object with the addition of the following methods: + +* `stats.isDirectory()` + +* `stats.isFile()` + +* `stats.isBlockDevice()` + +* `stats.isCharacterDevice()` + +* `stats.isSymbolicLink()` + +* `stats.isFIFO()` + +* `stats.isSocket()` diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/examples/server-chat.js b/tasks/enduro-trails/prototype/node_modules/ssh2/examples/server-chat.js new file mode 100644 index 0000000..a82a955 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/examples/server-chat.js @@ -0,0 +1,238 @@ +// **BEFORE RUNNING THIS SCRIPT:** +// 1. The server portion is best run on non-Windows systems because they have +// terminfo databases which are needed to properly work with different +// terminal types of client connections +// 2. Install `blessed`: `npm install blessed` +// 3. Create a server host key in this same directory and name it `host.key` +'use strict'; + +const { readFileSync } = require('fs'); + +const blessed = require('blessed'); +const { Server } = require('ssh2'); + +const RE_SPECIAL = +// eslint-disable-next-line no-control-regex + /[\x00-\x1F\x7F]+|(?:\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K])/g; +const MAX_MSG_LEN = 128; +const MAX_NAME_LEN = 10; +const PROMPT_NAME = `Enter a nickname to use (max ${MAX_NAME_LEN} chars): `; + +const users = []; + +function formatMessage(msg, output) { + output.parseTags = true; + msg = output._parseTags(msg); + output.parseTags = false; + return msg; +} + +function userBroadcast(msg, source) { + const sourceMsg = `> ${msg}`; + const name = `{cyan-fg}{bold}${source.name}{/}`; + msg = `: ${msg}`; + for (const user of users) { + const output = user.output; + if (source === user) + output.add(sourceMsg); + else + output.add(formatMessage(name, output) + msg); + } +} + +function localMessage(msg, source) { + const output = source.output; + output.add(formatMessage(msg, output)); +} + +function noop(v) {} + +new Server({ + hostKeys: [readFileSync('host.key')], +}, (client) => { + let stream; + let name; + + client.on('authentication', (ctx) => { + let nick = ctx.username; + let prompt = PROMPT_NAME; + let lowered; + + // Try to use username as nickname + if (nick.length > 0 && nick.length <= MAX_NAME_LEN) { + lowered = nick.toLowerCase(); + let ok = true; + for (const user of users) { + if (user.name.toLowerCase() === lowered) { + ok = false; + prompt = `That nickname is already in use.\n${PROMPT_NAME}`; + break; + } + } + if (ok) { + name = nick; + return ctx.accept(); + } + } else if (nick.length === 0) { + prompt = 'A nickname is required.\n' + PROMPT_NAME; + } else { + prompt = 'That nickname is too long.\n' + PROMPT_NAME; + } + + if (ctx.method !== 'keyboard-interactive') + return ctx.reject(['keyboard-interactive']); + + ctx.prompt(prompt, function retryPrompt(answers) { + if (answers.length === 0) + return ctx.reject(['keyboard-interactive']); + nick = answers[0]; + if (nick.length > MAX_NAME_LEN) { + return ctx.prompt(`That nickname is too long.\n${PROMPT_NAME}`, + retryPrompt); + } else if (nick.length === 0) { + return ctx.prompt(`A nickname is required.\n${PROMPT_NAME}`, + retryPrompt); + } + lowered = nick.toLowerCase(); + for (const user of users) { + if (user.name.toLowerCase() === lowered) { + return ctx.prompt(`That nickname is already in use.\n${PROMPT_NAME}`, + retryPrompt); + } + } + name = nick; + ctx.accept(); + }); + }).on('ready', () => { + let rows; + let cols; + let term; + client.once('session', (accept, reject) => { + accept().once('pty', (accept, reject, info) => { + rows = info.rows; + cols = info.cols; + term = info.term; + accept && accept(); + }).on('window-change', (accept, reject, info) => { + rows = info.rows; + cols = info.cols; + if (stream) { + stream.rows = rows; + stream.columns = cols; + stream.emit('resize'); + } + accept && accept(); + }).once('shell', (accept, reject) => { + stream = accept(); + users.push(stream); + + stream.name = name; + stream.rows = rows || 24; + stream.columns = cols || 80; + stream.isTTY = true; + stream.setRawMode = noop; + stream.on('error', noop); + + const screen = new blessed.screen({ + autoPadding: true, + smartCSR: true, + program: new blessed.program({ + input: stream, + output: stream + }), + terminal: term || 'ansi' + }); + + screen.title = 'SSH Chatting as ' + name; + // Disable local echo + screen.program.attr('invisible', true); + + const output = stream.output = new blessed.log({ + screen: screen, + top: 0, + left: 0, + width: '100%', + bottom: 2, + scrollOnInput: true + }); + screen.append(output); + + screen.append(new blessed.box({ + screen: screen, + height: 1, + bottom: 1, + left: 0, + width: '100%', + type: 'line', + ch: '=' + })); + + const input = new blessed.textbox({ + screen: screen, + bottom: 0, + height: 1, + width: '100%', + inputOnFocus: true + }); + screen.append(input); + + input.focus(); + + // Local greetings + localMessage('{blue-bg}{white-fg}{bold}Welcome to SSH Chat!{/}\n' + + 'There are {bold}' + + (users.length - 1) + + '{/} other user(s) connected.\n' + + 'Type /quit or /exit to exit the chat.', + stream); + + // Let everyone else know that this user just joined + for (const user of users) { + const output = user.output; + if (user === stream) + continue; + output.add(formatMessage('{green-fg}*** {bold}', output) + + name + + formatMessage('{/bold} has joined the chat{/}', output)); + } + + screen.render(); + // XXX This fake resize event is needed for some terminals in order to + // have everything display correctly + screen.program.emit('resize'); + + // Read a line of input from the user + input.on('submit', (line) => { + input.clearValue(); + screen.render(); + if (!input.focused) + input.focus(); + line = line.replace(RE_SPECIAL, '').trim(); + if (line.length > MAX_MSG_LEN) + line = line.substring(0, MAX_MSG_LEN); + if (line.length > 0) { + if (line === '/quit' || line === '/exit') + stream.end(); + else + userBroadcast(line, stream); + } + }); + }); + }); + }).on('close', () => { + if (stream !== undefined) { + users.splice(users.indexOf(stream), 1); + // Let everyone else know that this user just left + for (const user of users) { + const output = user.output; + output.add(formatMessage('{magenta-fg}*** {bold}', output) + + name + + formatMessage('{/bold} has left the chat{/}', output)); + } + } + }).on('error', (err) => { + // Ignore errors + }); +}).listen(0, function() { + console.log('Listening on port ' + this.address().port); +}); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/examples/sftp-server-download-only.js b/tasks/enduro-trails/prototype/node_modules/ssh2/examples/sftp-server-download-only.js new file mode 100644 index 0000000..d4ae4c5 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/examples/sftp-server-download-only.js @@ -0,0 +1,134 @@ +'use strict'; + +const { timingSafeEqual } = require('crypto'); +const { constants, readFileSync } = require('fs'); + +const { Server, sftp: { OPEN_MODE, STATUS_CODE } } = require('ssh2'); + +const allowedUser = Buffer.from('foo'); +const allowedPassword = Buffer.from('bar'); + +function checkValue(input, allowed) { + const autoReject = (input.length !== allowed.length); + if (autoReject) { + // Prevent leaking length information by always making a comparison with the + // same input when lengths don't match what we expect ... + allowed = input; + } + const isMatch = timingSafeEqual(input, allowed); + return (!autoReject && isMatch); +} + +new Server({ + hostKeys: [readFileSync('host.key')] +}, (client) => { + console.log('Client connected!'); + + client.on('authentication', (ctx) => { + let allowed = true; + if (!checkValue(Buffer.from(ctx.username), allowedUser)) + allowed = false; + + switch (ctx.method) { + case 'password': + if (!checkValue(Buffer.from(ctx.password), allowedPassword)) + return ctx.reject(); + break; + default: + return ctx.reject(); + } + + if (allowed) + ctx.accept(); + else + ctx.reject(); + }).on('ready', () => { + console.log('Client authenticated!'); + + client.on('session', (accept, reject) => { + const session = accept(); + session.on('sftp', (accept, reject) => { + console.log('Client SFTP session'); + + const openFiles = new Map(); + let handleCount = 0; + const sftp = accept(); + sftp.on('OPEN', (reqid, filename, flags, attrs) => { + // Only allow opening /tmp/foo.txt for writing + if (filename !== '/tmp/foo.txt' || !(flags & OPEN_MODE.READ)) + return sftp.status(reqid, STATUS_CODE.FAILURE); + + // Create a fake handle to return to the client, this could easily + // be a real file descriptor number for example if actually opening + // the file on the disk + const handle = Buffer.alloc(4); + openFiles.set(handleCount, { read: false }); + handle.writeUInt32BE(handleCount++, 0, true); + + console.log('Opening file for read'); + sftp.handle(reqid, handle); + }).on('READ', (reqid, handle, offset, length) => { + let fnum; + if (handle.length !== 4 + || !openFiles.has(fnum = handle.readUInt32BE(0, true))) { + return sftp.status(reqid, STATUS_CODE.FAILURE); + } + + // Fake the read + const state = openFiles.get(fnum); + if (state.read) { + sftp.status(reqid, STATUS_CODE.EOF); + } else { + state.read = true; + + console.log( + 'Read from file at offset %d, length %d', offset, length + ); + sftp.data(reqid, 'bar'); + } + }).on('CLOSE', (reqid, handle) => { + let fnum; + if (handle.length !== 4 + || !openFiles.has(fnum = handle.readUInt32BE(0))) { + return sftp.status(reqid, STATUS_CODE.FAILURE); + } + + openFiles.delete(fnum); + + console.log('Closing file'); + sftp.status(reqid, STATUS_CODE.OK); + }).on('REALPATH', function(reqid, path) { + const name = [{ + filename: '/tmp/foo.txt', + longname: '-rwxrwxrwx 1 foo foo 3 Dec 8 2009 foo.txt', + attrs: {} + }]; + sftp.name(reqid, name); + }).on('STAT', onSTAT) + .on('LSTAT', onSTAT); + + function onSTAT(reqid, path) { + if (path !== '/tmp/foo.txt') + return sftp.status(reqid, STATUS_CODE.FAILURE); + + let mode = constants.S_IFREG; // Regular file + mode |= constants.S_IRWXU; // Read, write, execute for user + mode |= constants.S_IRWXG; // Read, write, execute for group + mode |= constants.S_IRWXO; // Read, write, execute for other + sftp.attrs(reqid, { + mode: mode, + uid: 0, + gid: 0, + size: 3, + atime: Date.now(), + mtime: Date.now(), + }); + } + }); + }); + }).on('close', () => { + console.log('Client disconnected'); + }); +}).listen(0, '127.0.0.1', function() { + console.log(`Listening on port ${this.address().port}`); +}); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/install.js b/tasks/enduro-trails/prototype/node_modules/ssh2/install.js new file mode 100644 index 0000000..34f7f58 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/install.js @@ -0,0 +1,27 @@ +'use strict'; + +const { spawnSync } = require('child_process'); + +const forceFailOnNonZero = (process.env.CI_CHECK_FAIL === 'ssh2'); + +// Attempt to build the bundled optional binding +const args = [ + `--target=${process.version}`, + `--real_openssl_major=${/^\d+/.exec(process.versions.openssl)[0]}`, + 'rebuild', +]; +const result = spawnSync('node-gyp', args, { + cwd: 'lib/protocol/crypto', + encoding: 'utf8', + shell: true, + stdio: 'inherit', + windowsHide: true, +}); +if (result.error || result.status !== 0) { + console.log('Failed to build optional crypto binding'); + if (forceFailOnNonZero) + process.exit(1); +} else { + console.log('Succeeded in building optional crypto binding'); +} +process.exit(0); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/Channel.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/Channel.js new file mode 100644 index 0000000..0120779 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/Channel.js @@ -0,0 +1,295 @@ +'use strict'; + +const { + Duplex: DuplexStream, + Readable: ReadableStream, + Writable: WritableStream, +} = require('stream'); + +const { + CHANNEL_EXTENDED_DATATYPE: { STDERR }, +} = require('./protocol/constants.js'); +const { bufferSlice } = require('./protocol/utils.js'); + +const PACKET_SIZE = 32 * 1024; +const MAX_WINDOW = 2 * 1024 * 1024; +const WINDOW_THRESHOLD = MAX_WINDOW / 2; + +class ClientStderr extends ReadableStream { + constructor(channel, streamOpts) { + super(streamOpts); + + this._channel = channel; + } + _read(n) { + if (this._channel._waitChanDrain) { + this._channel._waitChanDrain = false; + if (this._channel.incoming.window <= WINDOW_THRESHOLD) + windowAdjust(this._channel); + } + } +} + +class ServerStderr extends WritableStream { + constructor(channel) { + super({ highWaterMark: MAX_WINDOW }); + + this._channel = channel; + } + + _write(data, encoding, cb) { + const channel = this._channel; + const protocol = channel._client._protocol; + const outgoing = channel.outgoing; + const packetSize = outgoing.packetSize; + const id = outgoing.id; + let window = outgoing.window; + const len = data.length; + let p = 0; + + if (outgoing.state !== 'open') + return; + + while (len - p > 0 && window > 0) { + let sliceLen = len - p; + if (sliceLen > window) + sliceLen = window; + if (sliceLen > packetSize) + sliceLen = packetSize; + + if (p === 0 && sliceLen === len) + protocol.channelExtData(id, data, STDERR); + else + protocol.channelExtData(id, bufferSlice(data, p, p + sliceLen), STDERR); + + p += sliceLen; + window -= sliceLen; + } + + outgoing.window = window; + + if (len - p > 0) { + if (window === 0) + channel._waitWindow = true; + if (p > 0) + channel._chunkErr = bufferSlice(data, p, len); + else + channel._chunkErr = data; + channel._chunkcbErr = cb; + return; + } + + cb(); + } +} + +class Channel extends DuplexStream { + constructor(client, info, opts) { + const streamOpts = { + highWaterMark: MAX_WINDOW, + allowHalfOpen: (!opts || (opts && opts.allowHalfOpen !== false)), + emitClose: false, + }; + super(streamOpts); + this.allowHalfOpen = streamOpts.allowHalfOpen; + + const server = !!(opts && opts.server); + + this.server = server; + this.type = info.type; + this.subtype = undefined; + + /* + incoming and outgoing contain these properties: + { + id: undefined, + window: undefined, + packetSize: undefined, + state: 'closed' + } + */ + this.incoming = info.incoming; + this.outgoing = info.outgoing; + this._callbacks = []; + + this._client = client; + this._hasX11 = false; + this._exit = { + code: undefined, + signal: undefined, + dump: undefined, + desc: undefined, + }; + + this.stdin = this.stdout = this; + + if (server) + this.stderr = new ServerStderr(this); + else + this.stderr = new ClientStderr(this, streamOpts); + + // Outgoing data + this._waitWindow = false; // SSH-level backpressure + + // Incoming data + this._waitChanDrain = false; // Channel Readable side backpressure + + this._chunk = undefined; + this._chunkcb = undefined; + this._chunkErr = undefined; + this._chunkcbErr = undefined; + + this.on('finish', onFinish) + .on('prefinish', onFinish); // For node v0.11+ + + this.on('end', onEnd).on('close', onEnd); + } + + _read(n) { + if (this._waitChanDrain) { + this._waitChanDrain = false; + if (this.incoming.window <= WINDOW_THRESHOLD) + windowAdjust(this); + } + } + + _write(data, encoding, cb) { + const protocol = this._client._protocol; + const outgoing = this.outgoing; + const packetSize = outgoing.packetSize; + const id = outgoing.id; + let window = outgoing.window; + const len = data.length; + let p = 0; + + if (outgoing.state !== 'open') + return; + + while (len - p > 0 && window > 0) { + let sliceLen = len - p; + if (sliceLen > window) + sliceLen = window; + if (sliceLen > packetSize) + sliceLen = packetSize; + + if (p === 0 && sliceLen === len) + protocol.channelData(id, data); + else + protocol.channelData(id, bufferSlice(data, p, p + sliceLen)); + + p += sliceLen; + window -= sliceLen; + } + + outgoing.window = window; + + if (len - p > 0) { + if (window === 0) + this._waitWindow = true; + if (p > 0) + this._chunk = bufferSlice(data, p, len); + else + this._chunk = data; + this._chunkcb = cb; + return; + } + + cb(); + } + + eof() { + if (this.outgoing.state === 'open') { + this.outgoing.state = 'eof'; + this._client._protocol.channelEOF(this.outgoing.id); + } + } + + close() { + if (this.outgoing.state === 'open' || this.outgoing.state === 'eof') { + this.outgoing.state = 'closing'; + this._client._protocol.channelClose(this.outgoing.id); + } + } + + destroy() { + this.end(); + this.close(); + return this; + } + + // Session type-specific methods ============================================= + setWindow(rows, cols, height, width) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (this.type === 'session' + && (this.subtype === 'shell' || this.subtype === 'exec') + && this.writable + && this.outgoing.state === 'open') { + this._client._protocol.windowChange(this.outgoing.id, + rows, + cols, + height, + width); + } + } + + signal(signalName) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (this.type === 'session' + && this.writable + && this.outgoing.state === 'open') { + this._client._protocol.signal(this.outgoing.id, signalName); + } + } + + exit(statusOrSignal, coreDumped, msg) { + if (!this.server) + throw new Error('Server-only method called in client mode'); + + if (this.type === 'session' + && this.writable + && this.outgoing.state === 'open') { + if (typeof statusOrSignal === 'number') { + this._client._protocol.exitStatus(this.outgoing.id, statusOrSignal); + } else { + this._client._protocol.exitSignal(this.outgoing.id, + statusOrSignal, + coreDumped, + msg); + } + } + } + +} + +function onFinish() { + this.eof(); + if (this.server || !this.allowHalfOpen) + this.close(); + this.writable = false; +} + +function onEnd() { + this.readable = false; +} + +function windowAdjust(self) { + if (self.outgoing.state === 'closed') + return; + const amt = MAX_WINDOW - self.incoming.window; + if (amt <= 0) + return; + self.incoming.window += amt; + self._client._protocol.channelWindowAdjust(self.outgoing.id, amt); +} + +module.exports = { + Channel, + MAX_WINDOW, + PACKET_SIZE, + windowAdjust, + WINDOW_THRESHOLD, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/agent.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/agent.js new file mode 100644 index 0000000..bb495d1 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/agent.js @@ -0,0 +1,1123 @@ +'use strict'; + +const { Socket } = require('net'); +const { Duplex } = require('stream'); +const { resolve } = require('path'); +const { readFile } = require('fs'); +const { execFile, spawn } = require('child_process'); + +const { isParsedKey, parseKey } = require('./protocol/keyParser.js'); + +const { + makeBufferParser, + readUInt32BE, + writeUInt32BE, + writeUInt32LE, +} = require('./protocol/utils.js'); + +function once(cb) { + let called = false; + return (...args) => { + if (called) + return; + called = true; + cb(...args); + }; +} + +function concat(buf1, buf2) { + const combined = Buffer.allocUnsafe(buf1.length + buf2.length); + buf1.copy(combined, 0); + buf2.copy(combined, buf1.length); + return combined; +} + +function noop() {} + +const EMPTY_BUF = Buffer.alloc(0); + +const binaryParser = makeBufferParser(); + +class BaseAgent { + getIdentities(cb) { + cb(new Error('Missing getIdentities() implementation')); + } + sign(pubKey, data, options, cb) { + if (typeof options === 'function') + cb = options; + cb(new Error('Missing sign() implementation')); + } +} + +class OpenSSHAgent extends BaseAgent { + constructor(socketPath) { + super(); + this.socketPath = socketPath; + } + + getStream(cb) { + cb = once(cb); + const sock = new Socket(); + sock.on('connect', () => { + cb(null, sock); + }); + sock.on('close', onFail) + .on('end', onFail) + .on('error', onFail); + sock.connect(this.socketPath); + + function onFail() { + try { + sock.destroy(); + } catch {} + + cb(new Error('Failed to connect to agent')); + } + } + + getIdentities(cb) { + cb = once(cb); + this.getStream((err, stream) => { + function onFail(err) { + if (stream) { + try { + stream.destroy(); + } catch {} + } + if (!err) + err = new Error('Failed to retrieve identities from agent'); + cb(err); + } + + if (err) + return onFail(err); + + const protocol = new AgentProtocol(true); + protocol.on('error', onFail); + protocol.pipe(stream).pipe(protocol); + + stream.on('close', onFail) + .on('end', onFail) + .on('error', onFail); + + protocol.getIdentities((err, keys) => { + if (err) + return onFail(err); + try { + stream.destroy(); + } catch {} + cb(null, keys); + }); + }); + } + + sign(pubKey, data, options, cb) { + if (typeof options === 'function') { + cb = options; + options = undefined; + } else if (typeof options !== 'object' || options === null) { + options = undefined; + } + + cb = once(cb); + this.getStream((err, stream) => { + function onFail(err) { + if (stream) { + try { + stream.destroy(); + } catch {} + } + if (!err) + err = new Error('Failed to sign data with agent'); + cb(err); + } + + if (err) + return onFail(err); + + const protocol = new AgentProtocol(true); + protocol.on('error', onFail); + protocol.pipe(stream).pipe(protocol); + + stream.on('close', onFail) + .on('end', onFail) + .on('error', onFail); + + protocol.sign(pubKey, data, options, (err, sig) => { + if (err) + return onFail(err); + + try { + stream.destroy(); + } catch {} + + cb(null, sig); + }); + }); + } +} + +const PageantAgent = (() => { + const RET_ERR_BADARGS = 10; + const RET_ERR_UNAVAILABLE = 11; + const RET_ERR_NOMAP = 12; + const RET_ERR_BINSTDIN = 13; + const RET_ERR_BINSTDOUT = 14; + const RET_ERR_BADLEN = 15; + + const EXEPATH = resolve(__dirname, '..', 'util/pagent.exe'); + const ERROR = { + [RET_ERR_BADARGS]: new Error('Invalid pagent.exe arguments'), + [RET_ERR_UNAVAILABLE]: new Error('Pageant is not running'), + [RET_ERR_NOMAP]: new Error('pagent.exe could not create an mmap'), + [RET_ERR_BINSTDIN]: new Error('pagent.exe could not set mode for stdin'), + [RET_ERR_BINSTDOUT]: new Error('pagent.exe could not set mode for stdout'), + [RET_ERR_BADLEN]: + new Error('pagent.exe did not get expected input payload'), + }; + + function destroy(stream) { + stream.buffer = null; + if (stream.proc) { + stream.proc.kill(); + stream.proc = undefined; + } + } + + class PageantSocket extends Duplex { + constructor() { + super(); + this.proc = undefined; + this.buffer = null; + } + _read(n) {} + _write(data, encoding, cb) { + if (this.buffer === null) { + this.buffer = data; + } else { + const newBuffer = Buffer.allocUnsafe(this.buffer.length + data.length); + this.buffer.copy(newBuffer, 0); + data.copy(newBuffer, this.buffer.length); + this.buffer = newBuffer; + } + // Wait for at least all length bytes + if (this.buffer.length < 4) + return cb(); + + const len = readUInt32BE(this.buffer, 0); + // Make sure we have a full message before querying pageant + if ((this.buffer.length - 4) < len) + return cb(); + + data = this.buffer.slice(0, 4 + len); + if (this.buffer.length > (4 + len)) + return cb(new Error('Unexpected multiple agent requests')); + this.buffer = null; + + let error; + const proc = this.proc = spawn(EXEPATH, [ data.length ]); + proc.stdout.on('data', (data) => { + this.push(data); + }); + proc.on('error', (err) => { + error = err; + cb(error); + }); + proc.on('close', (code) => { + this.proc = undefined; + if (!error) { + if (error = ERROR[code]) + return cb(error); + cb(); + } + }); + proc.stdin.end(data); + } + _final(cb) { + destroy(this); + cb(); + } + _destroy(err, cb) { + destroy(this); + cb(); + } + } + + return class PageantAgent extends OpenSSHAgent { + getStream(cb) { + cb(null, new PageantSocket()); + } + }; +})(); + +const CygwinAgent = (() => { + const RE_CYGWIN_SOCK = /^!(\d+) s ([A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8})/; + + return class CygwinAgent extends OpenSSHAgent { + getStream(cb) { + cb = once(cb); + + // The cygwin ssh-agent connection process looks like this: + // 1. Read the "socket" as a file to get the underlying TCP port and a + // special "secret" that must be sent to the TCP server. + // 2. Connect to the server listening on localhost at the TCP port. + // 3. Send the "secret" to the server. + // 4. The server sends back the same "secret". + // 5. Send three 32-bit integer values of zero. This is ordinarily the + // pid, uid, and gid of this process, but cygwin will actually + // send us the correct values as a response. + // 6. The server sends back the pid, uid, gid. + // 7. Disconnect. + // 8. Repeat steps 2-6, except send the received pid, uid, and gid in + // step 5 instead of zeroes. + // 9. Connection is ready to be used. + + let socketPath = this.socketPath; + let triedCygpath = false; + readFile(socketPath, function readCygsocket(err, data) { + if (err) { + if (triedCygpath) + return cb(new Error('Invalid cygwin unix socket path')); + + // Try using `cygpath` to convert a possible *nix-style path to the + // real Windows path before giving up ... + execFile('cygpath', ['-w', socketPath], (err, stdout, stderr) => { + if (err || stdout.length === 0) + return cb(new Error('Invalid cygwin unix socket path')); + + triedCygpath = true; + socketPath = stdout.toString().replace(/[\r\n]/g, ''); + readFile(socketPath, readCygsocket); + }); + return; + } + + const m = RE_CYGWIN_SOCK.exec(data.toString('ascii')); + if (!m) + return cb(new Error('Malformed cygwin unix socket file')); + + let state; + let bc = 0; + let isRetrying = false; + const inBuf = []; + let sock; + + // Use 0 for pid, uid, and gid to ensure we get an error and also + // a valid uid and gid from cygwin so that we don't have to figure it + // out ourselves + let credsBuf = Buffer.alloc(12); + + // Parse cygwin unix socket file contents + const port = parseInt(m[1], 10); + const secret = m[2].replace(/-/g, ''); + const secretBuf = Buffer.allocUnsafe(16); + for (let i = 0, j = 0; j < 32; ++i, j += 2) + secretBuf[i] = parseInt(secret.substring(j, j + 2), 16); + + // Convert to host order (always LE for Windows) + for (let i = 0; i < 16; i += 4) + writeUInt32LE(secretBuf, readUInt32BE(secretBuf, i), i); + + tryConnect(); + + function _onconnect() { + bc = 0; + state = 'secret'; + sock.write(secretBuf); + } + + function _ondata(data) { + bc += data.length; + + if (state === 'secret') { + // The secret we sent is echoed back to us by cygwin, not sure of + // the reason for that, but we ignore it nonetheless ... + if (bc === 16) { + bc = 0; + state = 'creds'; + sock.write(credsBuf); + } + return; + } + + if (state === 'creds') { + // If this is the first attempt, make sure to gather the valid + // uid and gid for our next attempt + if (!isRetrying) + inBuf.push(data); + + if (bc === 12) { + sock.removeListener('connect', _onconnect); + sock.removeListener('data', _ondata); + sock.removeListener('error', onFail); + sock.removeListener('end', onFail); + sock.removeListener('close', onFail); + + if (isRetrying) + return cb(null, sock); + + isRetrying = true; + credsBuf = Buffer.concat(inBuf); + writeUInt32LE(credsBuf, process.pid, 0); + sock.on('error', () => {}); + sock.destroy(); + + tryConnect(); + } + } + } + + function onFail() { + cb(new Error('Problem negotiating cygwin unix socket security')); + } + + function tryConnect() { + sock = new Socket(); + sock.on('connect', _onconnect); + sock.on('data', _ondata); + sock.on('error', onFail); + sock.on('end', onFail); + sock.on('close', onFail); + sock.connect(port); + } + }); + } + }; +})(); + +// Format of `//./pipe/ANYTHING`, with forward slashes and backward slashes +// being interchangeable +const WINDOWS_PIPE_REGEX = /^[/\\][/\\]\.[/\\]pipe[/\\].+/; +function createAgent(path) { + if (process.platform === 'win32' && !WINDOWS_PIPE_REGEX.test(path)) { + return (path === 'pageant' + ? new PageantAgent() + : new CygwinAgent(path)); + } + return new OpenSSHAgent(path); +} + +const AgentProtocol = (() => { + // Client->Server messages + const SSH_AGENTC_REQUEST_IDENTITIES = 11; + const SSH_AGENTC_SIGN_REQUEST = 13; + // const SSH_AGENTC_ADD_IDENTITY = 17; + // const SSH_AGENTC_REMOVE_IDENTITY = 18; + // const SSH_AGENTC_REMOVE_ALL_IDENTITIES = 19; + // const SSH_AGENTC_ADD_SMARTCARD_KEY = 20; + // const SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21; + // const SSH_AGENTC_LOCK = 22; + // const SSH_AGENTC_UNLOCK = 23; + // const SSH_AGENTC_ADD_ID_CONSTRAINED = 25; + // const SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26; + // const SSH_AGENTC_EXTENSION = 27; + // Server->Client messages + const SSH_AGENT_FAILURE = 5; + // const SSH_AGENT_SUCCESS = 6; + const SSH_AGENT_IDENTITIES_ANSWER = 12; + const SSH_AGENT_SIGN_RESPONSE = 14; + // const SSH_AGENT_EXTENSION_FAILURE = 28; + + // const SSH_AGENT_CONSTRAIN_LIFETIME = 1; + // const SSH_AGENT_CONSTRAIN_CONFIRM = 2; + // const SSH_AGENT_CONSTRAIN_EXTENSION = 255; + + const SSH_AGENT_RSA_SHA2_256 = (1 << 1); + const SSH_AGENT_RSA_SHA2_512 = (1 << 2); + + const ROLE_CLIENT = 0; + const ROLE_SERVER = 1; + + // Ensures that responses get sent back in the same order the requests were + // received + function processResponses(protocol) { + let ret; + while (protocol[SYM_REQS].length) { + const nextResponse = protocol[SYM_REQS][0][SYM_RESP]; + if (nextResponse === undefined) + break; + + protocol[SYM_REQS].shift(); + ret = protocol.push(nextResponse); + } + return ret; + } + + const SYM_TYPE = Symbol('Inbound Request Type'); + const SYM_RESP = Symbol('Inbound Request Response'); + const SYM_CTX = Symbol('Inbound Request Context'); + class AgentInboundRequest { + constructor(type, ctx) { + this[SYM_TYPE] = type; + this[SYM_RESP] = undefined; + this[SYM_CTX] = ctx; + } + hasResponded() { + return (this[SYM_RESP] !== undefined); + } + getType() { + return this[SYM_TYPE]; + } + getContext() { + return this[SYM_CTX]; + } + } + function respond(protocol, req, data) { + req[SYM_RESP] = data; + return processResponses(protocol); + } + + function cleanup(protocol) { + protocol[SYM_BUFFER] = null; + if (protocol[SYM_MODE] === ROLE_CLIENT) { + const reqs = protocol[SYM_REQS]; + if (reqs && reqs.length) { + protocol[SYM_REQS] = []; + for (const req of reqs) + req.cb(new Error('No reply from server')); + } + } + + // Node streams hackery to make streams do the "right thing" + try { + protocol.end(); + } catch {} + setImmediate(() => { + if (!protocol[SYM_ENDED]) + protocol.emit('end'); + if (!protocol[SYM_CLOSED]) + protocol.emit('close'); + }); + } + + function onClose() { + this[SYM_CLOSED] = true; + } + + function onEnd() { + this[SYM_ENDED] = true; + } + + const SYM_REQS = Symbol('Requests'); + const SYM_MODE = Symbol('Agent Protocol Role'); + const SYM_BUFFER = Symbol('Agent Protocol Buffer'); + const SYM_MSGLEN = Symbol('Agent Protocol Current Message Length'); + const SYM_CLOSED = Symbol('Agent Protocol Closed'); + const SYM_ENDED = Symbol('Agent Protocol Ended'); + // Implementation based on: + // https://tools.ietf.org/html/draft-miller-ssh-agent-04 + return class AgentProtocol extends Duplex { + /* + Notes: + - `constraint` type consists of: + byte constraint_type + byte[] constraint_data + where `constraint_type` is one of: + * SSH_AGENT_CONSTRAIN_LIFETIME + - `constraint_data` consists of: + uint32 seconds + * SSH_AGENT_CONSTRAIN_CONFIRM + - `constraint_data` N/A + * SSH_AGENT_CONSTRAIN_EXTENSION + - `constraint_data` consists of: + string extension name + byte[] extension-specific details + */ + + constructor(isClient) { + super({ autoDestroy: true, emitClose: false }); + this[SYM_MODE] = (isClient ? ROLE_CLIENT : ROLE_SERVER); + this[SYM_REQS] = []; + this[SYM_BUFFER] = null; + this[SYM_MSGLEN] = -1; + this.once('end', onEnd); + this.once('close', onClose); + } + + _read(n) {} + + _write(data, encoding, cb) { + /* + Messages are of the format: + uint32 message length + byte message type + byte[message length - 1] message contents + */ + if (this[SYM_BUFFER] === null) + this[SYM_BUFFER] = data; + else + this[SYM_BUFFER] = concat(this[SYM_BUFFER], data); + + let buffer = this[SYM_BUFFER]; + let bufferLen = buffer.length; + + let p = 0; + while (p < bufferLen) { + // Wait for length + type + if (bufferLen < 5) + break; + + if (this[SYM_MSGLEN] === -1) + this[SYM_MSGLEN] = readUInt32BE(buffer, p); + + // Check if we have the entire message + if (bufferLen < (4 + this[SYM_MSGLEN])) + break; + + const msgType = buffer[p += 4]; + ++p; + + if (this[SYM_MODE] === ROLE_CLIENT) { + if (this[SYM_REQS].length === 0) + return cb(new Error('Received unexpected message from server')); + + const req = this[SYM_REQS].shift(); + + switch (msgType) { + case SSH_AGENT_FAILURE: + req.cb(new Error('Agent responded with failure')); + break; + case SSH_AGENT_IDENTITIES_ANSWER: { + if (req.type !== SSH_AGENTC_REQUEST_IDENTITIES) + return cb(new Error('Agent responded with wrong message type')); + + /* + byte SSH_AGENT_IDENTITIES_ANSWER + uint32 nkeys + + where `nkeys` is 0 or more of: + string key blob + string comment + */ + + binaryParser.init(buffer, p); + + const numKeys = binaryParser.readUInt32BE(); + + if (numKeys === undefined) { + binaryParser.clear(); + return cb(new Error('Malformed agent response')); + } + + const keys = []; + for (let i = 0; i < numKeys; ++i) { + let pubKey = binaryParser.readString(); + if (pubKey === undefined) { + binaryParser.clear(); + return cb(new Error('Malformed agent response')); + } + + const comment = binaryParser.readString(true); + if (comment === undefined) { + binaryParser.clear(); + return cb(new Error('Malformed agent response')); + } + + pubKey = parseKey(pubKey); + // We continue parsing the packet if we encounter an error + // in case the error is due to the key being an unsupported + // type + if (pubKey instanceof Error) + continue; + + pubKey.comment = pubKey.comment || comment; + + keys.push(pubKey); + } + p = binaryParser.pos(); + binaryParser.clear(); + + req.cb(null, keys); + break; + } + case SSH_AGENT_SIGN_RESPONSE: { + if (req.type !== SSH_AGENTC_SIGN_REQUEST) + return cb(new Error('Agent responded with wrong message type')); + + /* + byte SSH_AGENT_SIGN_RESPONSE + string signature + */ + + binaryParser.init(buffer, p); + let signature = binaryParser.readString(); + p = binaryParser.pos(); + binaryParser.clear(); + + if (signature === undefined) + return cb(new Error('Malformed agent response')); + + // We strip the algorithm from OpenSSH's output and assume it's + // using the algorithm we specified. This makes it easier on + // custom Agent implementations so they don't have to construct + // the correct binary format for a (OpenSSH-style) signature. + + // TODO: verify signature type based on key and options used + // during initial sign request + binaryParser.init(signature, 0); + binaryParser.readString(true); + signature = binaryParser.readString(); + binaryParser.clear(); + + if (signature === undefined) + return cb(new Error('Malformed OpenSSH signature format')); + + req.cb(null, signature); + break; + } + default: + return cb( + new Error('Agent responded with unsupported message type') + ); + } + } else { + switch (msgType) { + case SSH_AGENTC_REQUEST_IDENTITIES: { + const req = new AgentInboundRequest(msgType); + this[SYM_REQS].push(req); + /* + byte SSH_AGENTC_REQUEST_IDENTITIES + */ + this.emit('identities', req); + break; + } + case SSH_AGENTC_SIGN_REQUEST: { + /* + byte SSH_AGENTC_SIGN_REQUEST + string key_blob + string data + uint32 flags + */ + binaryParser.init(buffer, p); + let pubKey = binaryParser.readString(); + const data = binaryParser.readString(); + const flagsVal = binaryParser.readUInt32BE(); + p = binaryParser.pos(); + binaryParser.clear(); + if (flagsVal === undefined) { + const req = new AgentInboundRequest(msgType); + this[SYM_REQS].push(req); + return this.failureReply(req); + } + + pubKey = parseKey(pubKey); + if (pubKey instanceof Error) { + const req = new AgentInboundRequest(msgType); + this[SYM_REQS].push(req); + return this.failureReply(req); + } + + const flags = { + hash: undefined, + }; + let ctx; + if (pubKey.type === 'ssh-rsa') { + if (flagsVal & SSH_AGENT_RSA_SHA2_256) { + ctx = 'rsa-sha2-256'; + flags.hash = 'sha256'; + } else if (flagsVal & SSH_AGENT_RSA_SHA2_512) { + ctx = 'rsa-sha2-512'; + flags.hash = 'sha512'; + } + } + if (ctx === undefined) + ctx = pubKey.type; + + const req = new AgentInboundRequest(msgType, ctx); + this[SYM_REQS].push(req); + + this.emit('sign', req, pubKey, data, flags); + break; + } + default: { + const req = new AgentInboundRequest(msgType); + this[SYM_REQS].push(req); + this.failureReply(req); + } + } + } + + // Get ready for next message + this[SYM_MSGLEN] = -1; + if (p === bufferLen) { + // Nothing left to process for now + this[SYM_BUFFER] = null; + break; + } else { + this[SYM_BUFFER] = buffer = buffer.slice(p); + bufferLen = buffer.length; + p = 0; + } + } + + cb(); + } + + _destroy(err, cb) { + cleanup(this); + cb(); + } + + _final(cb) { + cleanup(this); + cb(); + } + + // Client->Server messages ================================================= + sign(pubKey, data, options, cb) { + if (this[SYM_MODE] !== ROLE_CLIENT) + throw new Error('Client-only method called with server role'); + + if (typeof options === 'function') { + cb = options; + options = undefined; + } else if (typeof options !== 'object' || options === null) { + options = undefined; + } + + let flags = 0; + + pubKey = parseKey(pubKey); + if (pubKey instanceof Error) + throw new Error('Invalid public key argument'); + + if (pubKey.type === 'ssh-rsa' && options) { + switch (options.hash) { + case 'sha256': + flags = SSH_AGENT_RSA_SHA2_256; + break; + case 'sha512': + flags = SSH_AGENT_RSA_SHA2_512; + break; + } + } + pubKey = pubKey.getPublicSSH(); + + /* + byte SSH_AGENTC_SIGN_REQUEST + string key_blob + string data + uint32 flags + */ + const type = SSH_AGENTC_SIGN_REQUEST; + const keyLen = pubKey.length; + const dataLen = data.length; + let p = 0; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + keyLen + 4 + dataLen + 4); + + writeUInt32BE(buf, buf.length - 4, p); + + buf[p += 4] = type; + + writeUInt32BE(buf, keyLen, ++p); + pubKey.copy(buf, p += 4); + + writeUInt32BE(buf, dataLen, p += keyLen); + data.copy(buf, p += 4); + + writeUInt32BE(buf, flags, p += dataLen); + + if (typeof cb !== 'function') + cb = noop; + + this[SYM_REQS].push({ type, cb }); + + return this.push(buf); + } + getIdentities(cb) { + if (this[SYM_MODE] !== ROLE_CLIENT) + throw new Error('Client-only method called with server role'); + + /* + byte SSH_AGENTC_REQUEST_IDENTITIES + */ + const type = SSH_AGENTC_REQUEST_IDENTITIES; + + let p = 0; + const buf = Buffer.allocUnsafe(4 + 1); + + writeUInt32BE(buf, buf.length - 4, p); + + buf[p += 4] = type; + + if (typeof cb !== 'function') + cb = noop; + + this[SYM_REQS].push({ type, cb }); + + return this.push(buf); + } + + // Server->Client messages ================================================= + failureReply(req) { + if (this[SYM_MODE] !== ROLE_SERVER) + throw new Error('Server-only method called with client role'); + + if (!(req instanceof AgentInboundRequest)) + throw new Error('Wrong request argument'); + + if (req.hasResponded()) + return true; + + let p = 0; + const buf = Buffer.allocUnsafe(4 + 1); + + writeUInt32BE(buf, buf.length - 4, p); + + buf[p += 4] = SSH_AGENT_FAILURE; + + return respond(this, req, buf); + } + getIdentitiesReply(req, keys) { + if (this[SYM_MODE] !== ROLE_SERVER) + throw new Error('Server-only method called with client role'); + + if (!(req instanceof AgentInboundRequest)) + throw new Error('Wrong request argument'); + + if (req.hasResponded()) + return true; + + /* + byte SSH_AGENT_IDENTITIES_ANSWER + uint32 nkeys + + where `nkeys` is 0 or more of: + string key blob + string comment + */ + + if (req.getType() !== SSH_AGENTC_REQUEST_IDENTITIES) + throw new Error('Invalid response to request'); + + if (!Array.isArray(keys)) + throw new Error('Keys argument must be an array'); + + let totalKeysLen = 4; // Include `nkeys` size + + const newKeys = []; + for (let i = 0; i < keys.length; ++i) { + const entry = keys[i]; + if (typeof entry !== 'object' || entry === null) + throw new Error(`Invalid key entry: ${entry}`); + + let pubKey; + let comment; + if (isParsedKey(entry)) { + pubKey = entry; + } else if (isParsedKey(entry.pubKey)) { + pubKey = entry.pubKey; + } else { + if (typeof entry.pubKey !== 'object' || entry.pubKey === null) + continue; + ({ pubKey, comment } = entry.pubKey); + pubKey = parseKey(pubKey); + if (pubKey instanceof Error) + continue; // TODO: add debug output + } + comment = pubKey.comment || comment; + pubKey = pubKey.getPublicSSH(); + + totalKeysLen += 4 + pubKey.length; + + if (comment && typeof comment === 'string') + comment = Buffer.from(comment); + else if (!Buffer.isBuffer(comment)) + comment = EMPTY_BUF; + + totalKeysLen += 4 + comment.length; + + newKeys.push({ pubKey, comment }); + } + + let p = 0; + const buf = Buffer.allocUnsafe(4 + 1 + totalKeysLen); + + writeUInt32BE(buf, buf.length - 4, p); + + buf[p += 4] = SSH_AGENT_IDENTITIES_ANSWER; + + writeUInt32BE(buf, newKeys.length, ++p); + p += 4; + for (let i = 0; i < newKeys.length; ++i) { + const { pubKey, comment } = newKeys[i]; + + writeUInt32BE(buf, pubKey.length, p); + pubKey.copy(buf, p += 4); + + writeUInt32BE(buf, comment.length, p += pubKey.length); + p += 4; + if (comment.length) { + comment.copy(buf, p); + p += comment.length; + } + } + + return respond(this, req, buf); + } + signReply(req, signature) { + if (this[SYM_MODE] !== ROLE_SERVER) + throw new Error('Server-only method called with client role'); + + if (!(req instanceof AgentInboundRequest)) + throw new Error('Wrong request argument'); + + if (req.hasResponded()) + return true; + + /* + byte SSH_AGENT_SIGN_RESPONSE + string signature + */ + + if (req.getType() !== SSH_AGENTC_SIGN_REQUEST) + throw new Error('Invalid response to request'); + + if (!Buffer.isBuffer(signature)) + throw new Error('Signature argument must be a Buffer'); + + if (signature.length === 0) + throw new Error('Signature argument must be non-empty'); + + /* + OpenSSH agent signatures are encoded as: + + string signature format identifier (as specified by the + public key/certificate format) + byte[n] signature blob in format specific encoding. + - This is actually a `string` for: rsa, dss, ecdsa, and ed25519 + types + */ + + let p = 0; + const sigFormat = req.getContext(); + const sigFormatLen = Buffer.byteLength(sigFormat); + const buf = Buffer.allocUnsafe( + 4 + 1 + 4 + 4 + sigFormatLen + 4 + signature.length + ); + + writeUInt32BE(buf, buf.length - 4, p); + + buf[p += 4] = SSH_AGENT_SIGN_RESPONSE; + + writeUInt32BE(buf, 4 + sigFormatLen + 4 + signature.length, ++p); + writeUInt32BE(buf, sigFormatLen, p += 4); + buf.utf8Write(sigFormat, p += 4, sigFormatLen); + writeUInt32BE(buf, signature.length, p += sigFormatLen); + signature.copy(buf, p += 4); + + return respond(this, req, buf); + } + }; +})(); + +const SYM_AGENT = Symbol('Agent'); +const SYM_AGENT_KEYS = Symbol('Agent Keys'); +const SYM_AGENT_KEYS_IDX = Symbol('Agent Keys Index'); +const SYM_AGENT_CBS = Symbol('Agent Init Callbacks'); +class AgentContext { + constructor(agent) { + if (typeof agent === 'string') + agent = createAgent(agent); + else if (!isAgent(agent)) + throw new Error('Invalid agent argument'); + this[SYM_AGENT] = agent; + this[SYM_AGENT_KEYS] = null; + this[SYM_AGENT_KEYS_IDX] = -1; + this[SYM_AGENT_CBS] = null; + } + init(cb) { + if (typeof cb !== 'function') + cb = noop; + + if (this[SYM_AGENT_KEYS] === null) { + if (this[SYM_AGENT_CBS] === null) { + this[SYM_AGENT_CBS] = [cb]; + + const doCbs = (...args) => { + process.nextTick(() => { + const cbs = this[SYM_AGENT_CBS]; + this[SYM_AGENT_CBS] = null; + for (const cb of cbs) + cb(...args); + }); + }; + + this[SYM_AGENT].getIdentities(once((err, keys) => { + if (err) + return doCbs(err); + + if (!Array.isArray(keys)) { + return doCbs(new Error( + 'Agent implementation failed to provide keys' + )); + } + + const newKeys = []; + for (let key of keys) { + key = parseKey(key); + if (key instanceof Error) { + // TODO: add debug output + continue; + } + newKeys.push(key); + } + + this[SYM_AGENT_KEYS] = newKeys; + this[SYM_AGENT_KEYS_IDX] = -1; + doCbs(); + })); + } else { + this[SYM_AGENT_CBS].push(cb); + } + } else { + process.nextTick(cb); + } + } + nextKey() { + if (this[SYM_AGENT_KEYS] === null + || ++this[SYM_AGENT_KEYS_IDX] >= this[SYM_AGENT_KEYS].length) { + return false; + } + + return this[SYM_AGENT_KEYS][this[SYM_AGENT_KEYS_IDX]]; + } + currentKey() { + if (this[SYM_AGENT_KEYS] === null + || this[SYM_AGENT_KEYS_IDX] >= this[SYM_AGENT_KEYS].length) { + return null; + } + + return this[SYM_AGENT_KEYS][this[SYM_AGENT_KEYS_IDX]]; + } + pos() { + if (this[SYM_AGENT_KEYS] === null + || this[SYM_AGENT_KEYS_IDX] >= this[SYM_AGENT_KEYS].length) { + return -1; + } + + return this[SYM_AGENT_KEYS_IDX]; + } + reset() { + this[SYM_AGENT_KEYS_IDX] = -1; + } + + sign(...args) { + this[SYM_AGENT].sign(...args); + } +} + +function isAgent(val) { + return (val instanceof BaseAgent); +} + +module.exports = { + AgentContext, + AgentProtocol, + BaseAgent, + createAgent, + CygwinAgent, + isAgent, + OpenSSHAgent, + PageantAgent, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/client.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/client.js new file mode 100644 index 0000000..7291c2c --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/client.js @@ -0,0 +1,2176 @@ +// TODO: +// * add `.connected` or similar property to allow immediate connection +// status checking +// * add/improve debug output during user authentication phase +'use strict'; + +const { + createHash, + getHashes, + randomFillSync, +} = require('crypto'); +const { Socket } = require('net'); +const { lookup: dnsLookup } = require('dns'); +const EventEmitter = require('events'); +const HASHES = getHashes(); + +const { + COMPAT, + CHANNEL_EXTENDED_DATATYPE: { STDERR }, + CHANNEL_OPEN_FAILURE, + DEFAULT_CIPHER, + DEFAULT_COMPRESSION, + DEFAULT_KEX, + DEFAULT_MAC, + DEFAULT_SERVER_HOST_KEY, + DISCONNECT_REASON, + DISCONNECT_REASON_BY_VALUE, + SUPPORTED_CIPHER, + SUPPORTED_COMPRESSION, + SUPPORTED_KEX, + SUPPORTED_MAC, + SUPPORTED_SERVER_HOST_KEY, +} = require('./protocol/constants.js'); +const { init: cryptoInit } = require('./protocol/crypto.js'); +const Protocol = require('./protocol/Protocol.js'); +const { parseKey } = require('./protocol/keyParser.js'); +const { SFTP } = require('./protocol/SFTP.js'); +const { + bufferCopy, + makeBufferParser, + makeError, + readUInt32BE, + sigSSHToASN1, + writeUInt32BE, +} = require('./protocol/utils.js'); + +const { AgentContext, createAgent, isAgent } = require('./agent.js'); +const { + Channel, + MAX_WINDOW, + PACKET_SIZE, + windowAdjust, + WINDOW_THRESHOLD, +} = require('./Channel.js'); +const { + ChannelManager, + generateAlgorithmList, + isWritable, + onChannelOpenFailure, + onCHANNEL_CLOSE, +} = require('./utils.js'); + +const bufferParser = makeBufferParser(); +const sigParser = makeBufferParser(); +const RE_OPENSSH = /^OpenSSH_(?:(?![0-4])\d)|(?:\d{2,})/; +const noop = (err) => {}; + +class Client extends EventEmitter { + constructor() { + super(); + + this.config = { + host: undefined, + port: undefined, + localAddress: undefined, + localPort: undefined, + forceIPv4: undefined, + forceIPv6: undefined, + keepaliveCountMax: undefined, + keepaliveInterval: undefined, + readyTimeout: undefined, + ident: undefined, + + username: undefined, + password: undefined, + privateKey: undefined, + tryKeyboard: undefined, + agent: undefined, + allowAgentFwd: undefined, + authHandler: undefined, + + hostHashAlgo: undefined, + hostHashCb: undefined, + strictVendor: undefined, + debug: undefined + }; + + this._agent = undefined; + this._readyTimeout = undefined; + this._chanMgr = undefined; + this._callbacks = undefined; + this._forwarding = undefined; + this._forwardingUnix = undefined; + this._acceptX11 = undefined; + this._agentFwdEnabled = undefined; + this._remoteVer = undefined; + + this._protocol = undefined; + this._sock = undefined; + this._resetKA = undefined; + } + + connect(cfg) { + if (this._sock && isWritable(this._sock)) { + this.once('close', () => { + this.connect(cfg); + }); + this.end(); + return this; + } + + this.config.host = cfg.hostname || cfg.host || 'localhost'; + this.config.port = cfg.port || 22; + this.config.localAddress = (typeof cfg.localAddress === 'string' + ? cfg.localAddress + : undefined); + this.config.localPort = (typeof cfg.localPort === 'string' + || typeof cfg.localPort === 'number' + ? cfg.localPort + : undefined); + this.config.forceIPv4 = cfg.forceIPv4 || false; + this.config.forceIPv6 = cfg.forceIPv6 || false; + this.config.keepaliveCountMax = (typeof cfg.keepaliveCountMax === 'number' + && cfg.keepaliveCountMax >= 0 + ? cfg.keepaliveCountMax + : 3); + this.config.keepaliveInterval = (typeof cfg.keepaliveInterval === 'number' + && cfg.keepaliveInterval > 0 + ? cfg.keepaliveInterval + : 0); + this.config.readyTimeout = (typeof cfg.readyTimeout === 'number' + && cfg.readyTimeout >= 0 + ? cfg.readyTimeout + : 20000); + this.config.ident = (typeof cfg.ident === 'string' + || Buffer.isBuffer(cfg.ident) + ? cfg.ident + : undefined); + + const algorithms = { + kex: undefined, + serverHostKey: undefined, + cs: { + cipher: undefined, + mac: undefined, + compress: undefined, + lang: [], + }, + sc: undefined, + }; + let allOfferDefaults = true; + if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { + algorithms.kex = generateAlgorithmList(cfg.algorithms.kex, + DEFAULT_KEX, + SUPPORTED_KEX); + if (algorithms.kex !== DEFAULT_KEX) + allOfferDefaults = false; + + algorithms.serverHostKey = + generateAlgorithmList(cfg.algorithms.serverHostKey, + DEFAULT_SERVER_HOST_KEY, + SUPPORTED_SERVER_HOST_KEY); + if (algorithms.serverHostKey !== DEFAULT_SERVER_HOST_KEY) + allOfferDefaults = false; + + algorithms.cs.cipher = generateAlgorithmList(cfg.algorithms.cipher, + DEFAULT_CIPHER, + SUPPORTED_CIPHER); + if (algorithms.cs.cipher !== DEFAULT_CIPHER) + allOfferDefaults = false; + + algorithms.cs.mac = generateAlgorithmList(cfg.algorithms.hmac, + DEFAULT_MAC, + SUPPORTED_MAC); + if (algorithms.cs.mac !== DEFAULT_MAC) + allOfferDefaults = false; + + algorithms.cs.compress = generateAlgorithmList(cfg.algorithms.compress, + DEFAULT_COMPRESSION, + SUPPORTED_COMPRESSION); + if (algorithms.cs.compress !== DEFAULT_COMPRESSION) + allOfferDefaults = false; + + if (!allOfferDefaults) + algorithms.sc = algorithms.cs; + } + + if (typeof cfg.username === 'string') + this.config.username = cfg.username; + else if (typeof cfg.user === 'string') + this.config.username = cfg.user; + else + throw new Error('Invalid username'); + + this.config.password = (typeof cfg.password === 'string' + ? cfg.password + : undefined); + this.config.privateKey = (typeof cfg.privateKey === 'string' + || Buffer.isBuffer(cfg.privateKey) + ? cfg.privateKey + : undefined); + this.config.localHostname = (typeof cfg.localHostname === 'string' + ? cfg.localHostname + : undefined); + this.config.localUsername = (typeof cfg.localUsername === 'string' + ? cfg.localUsername + : undefined); + this.config.tryKeyboard = (cfg.tryKeyboard === true); + if (typeof cfg.agent === 'string' && cfg.agent.length) + this.config.agent = createAgent(cfg.agent); + else if (isAgent(cfg.agent)) + this.config.agent = cfg.agent; + else + this.config.agent = undefined; + this.config.allowAgentFwd = (cfg.agentForward === true + && this.config.agent !== undefined); + let authHandler = this.config.authHandler = ( + typeof cfg.authHandler === 'function' + || Array.isArray(cfg.authHandler) + ? cfg.authHandler + : undefined + ); + + this.config.strictVendor = (typeof cfg.strictVendor === 'boolean' + ? cfg.strictVendor + : true); + + const debug = this.config.debug = (typeof cfg.debug === 'function' + ? cfg.debug + : undefined); + + if (cfg.agentForward === true && !this.config.allowAgentFwd) { + throw new Error( + 'You must set a valid agent path to allow agent forwarding' + ); + } + + let callbacks = this._callbacks = []; + this._chanMgr = new ChannelManager(this); + this._forwarding = {}; + this._forwardingUnix = {}; + this._acceptX11 = 0; + this._agentFwdEnabled = false; + this._agent = (this.config.agent ? this.config.agent : undefined); + this._remoteVer = undefined; + let privateKey; + + if (this.config.privateKey) { + privateKey = parseKey(this.config.privateKey, cfg.passphrase); + if (privateKey instanceof Error) + throw new Error(`Cannot parse privateKey: ${privateKey.message}`); + if (Array.isArray(privateKey)) { + // OpenSSH's newer format only stores 1 key for now + privateKey = privateKey[0]; + } + if (privateKey.getPrivatePEM() === null) { + throw new Error( + 'privateKey value does not contain a (valid) private key' + ); + } + } + + let hostVerifier; + if (typeof cfg.hostVerifier === 'function') { + const hashCb = cfg.hostVerifier; + let hashAlgo; + if (HASHES.indexOf(cfg.hostHash) !== -1) { + // Default to old behavior of hashing on user's behalf + hashAlgo = cfg.hostHash; + } + hostVerifier = (key, verify) => { + if (hashAlgo) + key = createHash(hashAlgo).update(key).digest('hex'); + const ret = hashCb(key, verify); + if (ret !== undefined) + verify(ret); + }; + } + + const sock = this._sock = (cfg.sock || new Socket()); + let ready = false; + let sawHeader = false; + if (this._protocol) + this._protocol.cleanup(); + const DEBUG_HANDLER = (!debug ? undefined : (p, display, msg) => { + debug(`Debug output from server: ${JSON.stringify(msg)}`); + }); + let serverSigAlgs; + const proto = this._protocol = new Protocol({ + ident: this.config.ident, + offer: (allOfferDefaults ? undefined : algorithms), + onWrite: (data) => { + if (isWritable(sock)) + sock.write(data); + }, + onError: (err) => { + if (err.level === 'handshake') + clearTimeout(this._readyTimeout); + if (!proto._destruct) + sock.removeAllListeners('data'); + this.emit('error', err); + try { + sock.end(); + } catch {} + }, + onHeader: (header) => { + sawHeader = true; + this._remoteVer = header.versions.software; + if (header.greeting) + this.emit('greeting', header.greeting); + }, + onHandshakeComplete: (negotiated) => { + this.emit('handshake', negotiated); + if (!ready) { + ready = true; + proto.service('ssh-userauth'); + } + }, + debug, + hostVerifier, + messageHandlers: { + DEBUG: DEBUG_HANDLER, + DISCONNECT: (p, reason, desc) => { + if (reason !== DISCONNECT_REASON.BY_APPLICATION) { + if (!desc) { + desc = DISCONNECT_REASON_BY_VALUE[reason]; + if (desc === undefined) + desc = `Unexpected disconnection reason: ${reason}`; + } + const err = new Error(desc); + err.code = reason; + this.emit('error', err); + } + sock.end(); + }, + SERVICE_ACCEPT: (p, name) => { + if (name === 'ssh-userauth') + tryNextAuth(); + }, + EXT_INFO: (p, exts) => { + if (serverSigAlgs === undefined) { + for (const ext of exts) { + if (ext.name === 'server-sig-algs') { + serverSigAlgs = ext.algs; + return; + } + } + serverSigAlgs = null; + } + }, + USERAUTH_BANNER: (p, msg) => { + this.emit('banner', msg); + }, + USERAUTH_SUCCESS: (p) => { + // Start keepalive mechanism + resetKA(); + + clearTimeout(this._readyTimeout); + + this.emit('ready'); + }, + USERAUTH_FAILURE: (p, authMethods, partialSuccess) => { + // For key-based authentication, check if we should retry the current + // key with a different algorithm first + if (curAuth.keyAlgos) { + const oldKeyAlgo = curAuth.keyAlgos[0][0]; + if (debug) + debug(`Client: ${curAuth.type} (${oldKeyAlgo}) auth failed`); + curAuth.keyAlgos.shift(); + if (curAuth.keyAlgos.length) { + const [keyAlgo, hashAlgo] = curAuth.keyAlgos[0]; + switch (curAuth.type) { + case 'agent': + proto.authPK( + curAuth.username, + curAuth.agentCtx.currentKey(), + keyAlgo + ); + return; + case 'publickey': + proto.authPK(curAuth.username, curAuth.key, keyAlgo); + return; + case 'hostbased': + proto.authHostbased(curAuth.username, + curAuth.key, + curAuth.localHostname, + curAuth.localUsername, + keyAlgo, + (buf, cb) => { + const signature = curAuth.key.sign(buf, hashAlgo); + if (signature instanceof Error) { + signature.message = + `Error while signing with key: ${signature.message}`; + signature.level = 'client-authentication'; + this.emit('error', signature); + return tryNextAuth(); + } + + cb(signature); + }); + return; + } + } else { + curAuth.keyAlgos = undefined; + } + } + + if (curAuth.type === 'agent') { + const pos = curAuth.agentCtx.pos(); + debug && debug(`Client: Agent key #${pos + 1} failed`); + return tryNextAgentKey(); + } + + debug && debug(`Client: ${curAuth.type} auth failed`); + + curPartial = partialSuccess; + curAuthsLeft = authMethods; + tryNextAuth(); + }, + USERAUTH_PASSWD_CHANGEREQ: (p, prompt) => { + if (curAuth.type === 'password') { + // TODO: support a `changePrompt()` on `curAuth` that defaults to + // emitting 'change password' as before + this.emit('change password', prompt, (newPassword) => { + proto.authPassword( + this.config.username, + this.config.password, + newPassword + ); + }); + } + }, + USERAUTH_PK_OK: (p) => { + let keyAlgo; + let hashAlgo; + if (curAuth.keyAlgos) + [keyAlgo, hashAlgo] = curAuth.keyAlgos[0]; + if (curAuth.type === 'agent') { + const key = curAuth.agentCtx.currentKey(); + proto.authPK(curAuth.username, key, keyAlgo, (buf, cb) => { + const opts = { hash: hashAlgo }; + curAuth.agentCtx.sign(key, buf, opts, (err, signed) => { + if (err) { + err.level = 'agent'; + this.emit('error', err); + } else { + return cb(signed); + } + + tryNextAgentKey(); + }); + }); + } else if (curAuth.type === 'publickey') { + proto.authPK(curAuth.username, curAuth.key, keyAlgo, (buf, cb) => { + const signature = curAuth.key.sign(buf, hashAlgo); + if (signature instanceof Error) { + signature.message = + `Error signing data with key: ${signature.message}`; + signature.level = 'client-authentication'; + this.emit('error', signature); + return tryNextAuth(); + } + cb(signature); + }); + } + }, + USERAUTH_INFO_REQUEST: (p, name, instructions, prompts) => { + if (curAuth.type === 'keyboard-interactive') { + const nprompts = (Array.isArray(prompts) ? prompts.length : 0); + if (nprompts === 0) { + debug && debug( + 'Client: Sending automatic USERAUTH_INFO_RESPONSE' + ); + proto.authInfoRes(); + return; + } + // We sent a keyboard-interactive user authentication request and + // now the server is sending us the prompts we need to present to + // the user + curAuth.prompt( + name, + instructions, + '', + prompts, + (answers) => { + proto.authInfoRes(answers); + } + ); + } + }, + REQUEST_SUCCESS: (p, data) => { + if (callbacks.length) + callbacks.shift()(false, data); + }, + REQUEST_FAILURE: (p) => { + if (callbacks.length) + callbacks.shift()(true); + }, + GLOBAL_REQUEST: (p, name, wantReply, data) => { + switch (name) { + case 'hostkeys-00@openssh.com': + // Automatically verify keys before passing to end user + hostKeysProve(this, data, (err, keys) => { + if (err) + return; + this.emit('hostkeys', keys); + }); + if (wantReply) + proto.requestSuccess(); + break; + default: + // Auto-reject all other global requests, this can be especially + // useful if the server is sending us dummy keepalive global + // requests + if (wantReply) + proto.requestFailure(); + } + }, + CHANNEL_OPEN: (p, info) => { + // Handle incoming requests from server, typically a forwarded TCP or + // X11 connection + onCHANNEL_OPEN(this, info); + }, + CHANNEL_OPEN_CONFIRMATION: (p, info) => { + const channel = this._chanMgr.get(info.recipient); + if (typeof channel !== 'function') + return; + + const isSFTP = (channel.type === 'sftp'); + const type = (isSFTP ? 'session' : channel.type); + const chanInfo = { + type, + incoming: { + id: info.recipient, + window: MAX_WINDOW, + packetSize: PACKET_SIZE, + state: 'open' + }, + outgoing: { + id: info.sender, + window: info.window, + packetSize: info.packetSize, + state: 'open' + } + }; + const instance = ( + isSFTP + ? new SFTP(this, chanInfo, { debug }) + : new Channel(this, chanInfo) + ); + this._chanMgr.update(info.recipient, instance); + channel(undefined, instance); + }, + CHANNEL_OPEN_FAILURE: (p, recipient, reason, description) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'function') + return; + + const info = { reason, description }; + onChannelOpenFailure(this, recipient, info, channel); + }, + CHANNEL_DATA: (p, recipient, data) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + // The remote party should not be sending us data if there is no + // window space available ... + // TODO: raise error on data with not enough window? + if (channel.incoming.window === 0) + return; + + channel.incoming.window -= data.length; + + if (channel.push(data) === false) { + channel._waitChanDrain = true; + return; + } + + if (channel.incoming.window <= WINDOW_THRESHOLD) + windowAdjust(channel); + }, + CHANNEL_EXTENDED_DATA: (p, recipient, data, type) => { + if (type !== STDERR) + return; + + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + // The remote party should not be sending us data if there is no + // window space available ... + // TODO: raise error on data with not enough window? + if (channel.incoming.window === 0) + return; + + channel.incoming.window -= data.length; + + if (!channel.stderr.push(data)) { + channel._waitChanDrain = true; + return; + } + + if (channel.incoming.window <= WINDOW_THRESHOLD) + windowAdjust(channel); + }, + CHANNEL_WINDOW_ADJUST: (p, recipient, amount) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + // The other side is allowing us to send `amount` more bytes of data + channel.outgoing.window += amount; + + if (channel._waitWindow) { + channel._waitWindow = false; + + if (channel._chunk) { + channel._write(channel._chunk, null, channel._chunkcb); + } else if (channel._chunkcb) { + channel._chunkcb(); + } else if (channel._chunkErr) { + channel.stderr._write(channel._chunkErr, + null, + channel._chunkcbErr); + } else if (channel._chunkcbErr) { + channel._chunkcbErr(); + } + } + }, + CHANNEL_SUCCESS: (p, recipient) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + this._resetKA(); + + if (channel._callbacks.length) + channel._callbacks.shift()(false); + }, + CHANNEL_FAILURE: (p, recipient) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + this._resetKA(); + + if (channel._callbacks.length) + channel._callbacks.shift()(true); + }, + CHANNEL_REQUEST: (p, recipient, type, wantReply, data) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + const exit = channel._exit; + if (exit.code !== undefined) + return; + switch (type) { + case 'exit-status': + channel.emit('exit', exit.code = data); + return; + case 'exit-signal': + channel.emit('exit', + exit.code = null, + exit.signal = `SIG${data.signal}`, + exit.dump = data.coreDumped, + exit.desc = data.errorMessage); + return; + } + + // Keepalive request? OpenSSH will send one as a channel request if + // there is a channel open + + if (wantReply) + p.channelFailure(channel.outgoing.id); + }, + CHANNEL_EOF: (p, recipient) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.incoming.state !== 'open') + return; + channel.incoming.state = 'eof'; + + if (channel.readable) + channel.push(null); + if (channel.stderr.readable) + channel.stderr.push(null); + }, + CHANNEL_CLOSE: (p, recipient) => { + onCHANNEL_CLOSE(this, recipient, this._chanMgr.get(recipient)); + }, + }, + }); + + sock.pause(); + + // TODO: check keepalive implementation + // Keepalive-related + const kainterval = this.config.keepaliveInterval; + const kacountmax = this.config.keepaliveCountMax; + let kacount = 0; + let katimer; + const sendKA = () => { + if (++kacount > kacountmax) { + clearInterval(katimer); + if (sock.readable) { + const err = new Error('Keepalive timeout'); + err.level = 'client-timeout'; + this.emit('error', err); + sock.destroy(); + } + return; + } + if (isWritable(sock)) { + // Append dummy callback to keep correct callback order + callbacks.push(resetKA); + proto.ping(); + } else { + clearInterval(katimer); + } + }; + function resetKA() { + if (kainterval > 0) { + kacount = 0; + clearInterval(katimer); + if (isWritable(sock)) + katimer = setInterval(sendKA, kainterval); + } + } + this._resetKA = resetKA; + + const onDone = (() => { + let called = false; + return () => { + if (called) + return; + called = true; + if (wasConnected && !sawHeader) { + const err = + makeError('Connection lost before handshake', 'protocol', true); + this.emit('error', err); + } + }; + })(); + const onConnect = (() => { + let called = false; + return () => { + if (called) + return; + called = true; + + wasConnected = true; + debug && debug('Socket connected'); + this.emit('connect'); + + cryptoInit.then(() => { + proto.start(); + sock.on('data', (data) => { + try { + proto.parse(data, 0, data.length); + } catch (ex) { + this.emit('error', ex); + try { + if (isWritable(sock)) + sock.end(); + } catch {} + } + }); + + // Drain stderr if we are connection hopping using an exec stream + if (sock.stderr && typeof sock.stderr.resume === 'function') + sock.stderr.resume(); + + sock.resume(); + }).catch((err) => { + this.emit('error', err); + try { + if (isWritable(sock)) + sock.end(); + } catch {} + }); + }; + })(); + let wasConnected = false; + sock.on('connect', onConnect) + .on('timeout', () => { + this.emit('timeout'); + }).on('error', (err) => { + debug && debug(`Socket error: ${err.message}`); + clearTimeout(this._readyTimeout); + err.level = 'client-socket'; + this.emit('error', err); + }).on('end', () => { + debug && debug('Socket ended'); + onDone(); + proto.cleanup(); + clearTimeout(this._readyTimeout); + clearInterval(katimer); + this.emit('end'); + }).on('close', () => { + debug && debug('Socket closed'); + onDone(); + proto.cleanup(); + clearTimeout(this._readyTimeout); + clearInterval(katimer); + this.emit('close'); + + // Notify outstanding channel requests of disconnection ... + const callbacks_ = callbacks; + callbacks = this._callbacks = []; + const err = new Error('No response from server'); + for (let i = 0; i < callbacks_.length; ++i) + callbacks_[i](err); + + // Simulate error for any channels waiting to be opened + this._chanMgr.cleanup(err); + }); + + // Begin authentication handling =========================================== + let curAuth; + let curPartial = null; + let curAuthsLeft = null; + const authsAllowed = ['none']; + if (this.config.password !== undefined) + authsAllowed.push('password'); + if (privateKey !== undefined) + authsAllowed.push('publickey'); + if (this._agent !== undefined) + authsAllowed.push('agent'); + if (this.config.tryKeyboard) + authsAllowed.push('keyboard-interactive'); + if (privateKey !== undefined + && this.config.localHostname !== undefined + && this.config.localUsername !== undefined) { + authsAllowed.push('hostbased'); + } + + if (Array.isArray(authHandler)) + authHandler = makeSimpleAuthHandler(authHandler); + else if (typeof authHandler !== 'function') + authHandler = makeSimpleAuthHandler(authsAllowed); + + let hasSentAuth = false; + const doNextAuth = (nextAuth) => { + if (hasSentAuth) + return; + hasSentAuth = true; + + if (nextAuth === false) { + const err = new Error('All configured authentication methods failed'); + err.level = 'client-authentication'; + this.emit('error', err); + this.end(); + return; + } + + if (typeof nextAuth === 'string') { + // Remain backwards compatible with original `authHandler()` usage, + // which only supported passing names of next method to try using data + // from the `connect()` config object + + const type = nextAuth; + if (authsAllowed.indexOf(type) === -1) + return skipAuth(`Authentication method not allowed: ${type}`); + + const username = this.config.username; + switch (type) { + case 'password': + nextAuth = { type, username, password: this.config.password }; + break; + case 'publickey': + nextAuth = { type, username, key: privateKey }; + break; + case 'hostbased': + nextAuth = { + type, + username, + key: privateKey, + localHostname: this.config.localHostname, + localUsername: this.config.localUsername, + }; + break; + case 'agent': + nextAuth = { + type, + username, + agentCtx: new AgentContext(this._agent), + }; + break; + case 'keyboard-interactive': + nextAuth = { + type, + username, + prompt: (...args) => this.emit('keyboard-interactive', ...args), + }; + break; + case 'none': + nextAuth = { type, username }; + break; + default: + return skipAuth( + `Skipping unsupported authentication method: ${nextAuth}` + ); + } + } else if (typeof nextAuth !== 'object' || nextAuth === null) { + return skipAuth( + `Skipping invalid authentication attempt: ${nextAuth}` + ); + } else { + const username = nextAuth.username; + if (typeof username !== 'string') { + return skipAuth( + `Skipping invalid authentication attempt: ${nextAuth}` + ); + } + const type = nextAuth.type; + switch (type) { + case 'password': { + const { password } = nextAuth; + if (typeof password !== 'string' && !Buffer.isBuffer(password)) + return skipAuth('Skipping invalid password auth attempt'); + nextAuth = { type, username, password }; + break; + } + case 'publickey': { + const key = parseKey(nextAuth.key, nextAuth.passphrase); + if (key instanceof Error) + return skipAuth('Skipping invalid key auth attempt'); + if (!key.isPrivateKey()) + return skipAuth('Skipping non-private key'); + nextAuth = { type, username, key }; + break; + } + case 'hostbased': { + const { localHostname, localUsername } = nextAuth; + const key = parseKey(nextAuth.key, nextAuth.passphrase); + if (key instanceof Error + || typeof localHostname !== 'string' + || typeof localUsername !== 'string') { + return skipAuth('Skipping invalid hostbased auth attempt'); + } + if (!key.isPrivateKey()) + return skipAuth('Skipping non-private key'); + nextAuth = { type, username, key, localHostname, localUsername }; + break; + } + case 'agent': { + let agent = nextAuth.agent; + if (typeof agent === 'string' && agent.length) { + agent = createAgent(agent); + } else if (!isAgent(agent)) { + return skipAuth( + `Skipping invalid agent: ${nextAuth.agent}` + ); + } + nextAuth = { type, username, agentCtx: new AgentContext(agent) }; + break; + } + case 'keyboard-interactive': { + const { prompt } = nextAuth; + if (typeof prompt !== 'function') { + return skipAuth( + 'Skipping invalid keyboard-interactive auth attempt' + ); + } + nextAuth = { type, username, prompt }; + break; + } + case 'none': + nextAuth = { type, username }; + break; + default: + return skipAuth( + `Skipping unsupported authentication method: ${nextAuth}` + ); + } + } + curAuth = nextAuth; + + // Begin authentication method's process + try { + const username = curAuth.username; + switch (curAuth.type) { + case 'password': + proto.authPassword(username, curAuth.password); + break; + case 'publickey': { + let keyAlgo; + curAuth.keyAlgos = getKeyAlgos(this, curAuth.key, serverSigAlgs); + if (curAuth.keyAlgos) { + if (curAuth.keyAlgos.length) { + keyAlgo = curAuth.keyAlgos[0][0]; + } else { + return skipAuth( + 'Skipping key authentication (no mutual hash algorithm)' + ); + } + } + proto.authPK(username, curAuth.key, keyAlgo); + break; + } + case 'hostbased': { + let keyAlgo; + let hashAlgo; + curAuth.keyAlgos = getKeyAlgos(this, curAuth.key, serverSigAlgs); + if (curAuth.keyAlgos) { + if (curAuth.keyAlgos.length) { + [keyAlgo, hashAlgo] = curAuth.keyAlgos[0]; + } else { + return skipAuth( + 'Skipping hostbased authentication (no mutual hash algorithm)' + ); + } + } + + proto.authHostbased(username, + curAuth.key, + curAuth.localHostname, + curAuth.localUsername, + keyAlgo, + (buf, cb) => { + const signature = curAuth.key.sign(buf, hashAlgo); + if (signature instanceof Error) { + signature.message = + `Error while signing with key: ${signature.message}`; + signature.level = 'client-authentication'; + this.emit('error', signature); + return tryNextAuth(); + } + + cb(signature); + }); + break; + } + case 'agent': + curAuth.agentCtx.init((err) => { + if (err) { + err.level = 'agent'; + this.emit('error', err); + return tryNextAuth(); + } + tryNextAgentKey(); + }); + break; + case 'keyboard-interactive': + proto.authKeyboard(username); + break; + case 'none': + proto.authNone(username); + break; + } + } finally { + hasSentAuth = false; + } + }; + + function skipAuth(msg) { + debug && debug(msg); + process.nextTick(tryNextAuth); + } + + function tryNextAuth() { + hasSentAuth = false; + const auth = authHandler(curAuthsLeft, curPartial, doNextAuth); + if (hasSentAuth || auth === undefined) + return; + doNextAuth(auth); + } + + const tryNextAgentKey = () => { + if (curAuth.type === 'agent') { + const key = curAuth.agentCtx.nextKey(); + if (key === false) { + debug && debug('Agent: No more keys left to try'); + debug && debug('Client: agent auth failed'); + tryNextAuth(); + } else { + const pos = curAuth.agentCtx.pos(); + let keyAlgo; + curAuth.keyAlgos = getKeyAlgos(this, key, serverSigAlgs); + if (curAuth.keyAlgos) { + if (curAuth.keyAlgos.length) { + keyAlgo = curAuth.keyAlgos[0][0]; + } else { + debug && debug( + `Agent: Skipping key #${pos + 1} (no mutual hash algorithm)` + ); + tryNextAgentKey(); + return; + } + } + debug && debug(`Agent: Trying key #${pos + 1}`); + proto.authPK(curAuth.username, key, keyAlgo); + } + } + }; + + const startTimeout = () => { + if (this.config.readyTimeout > 0) { + this._readyTimeout = setTimeout(() => { + const err = new Error('Timed out while waiting for handshake'); + err.level = 'client-timeout'; + this.emit('error', err); + sock.destroy(); + }, this.config.readyTimeout); + } + }; + + if (!cfg.sock) { + let host = this.config.host; + const forceIPv4 = this.config.forceIPv4; + const forceIPv6 = this.config.forceIPv6; + + debug && debug(`Client: Trying ${host} on port ${this.config.port} ...`); + + const doConnect = () => { + startTimeout(); + sock.connect({ + host, + port: this.config.port, + localAddress: this.config.localAddress, + localPort: this.config.localPort + }); + sock.setMaxListeners(0); + sock.setTimeout(typeof cfg.timeout === 'number' ? cfg.timeout : 0); + }; + + if ((!forceIPv4 && !forceIPv6) || (forceIPv4 && forceIPv6)) { + doConnect(); + } else { + dnsLookup(host, (forceIPv4 ? 4 : 6), (err, address, family) => { + if (err) { + const type = (forceIPv4 ? 'IPv4' : 'IPv6'); + const error = new Error( + `Error while looking up ${type} address for '${host}': ${err}` + ); + clearTimeout(this._readyTimeout); + error.level = 'client-dns'; + this.emit('error', error); + this.emit('close'); + return; + } + host = address; + doConnect(); + }); + } + } else { + // Custom socket passed in + startTimeout(); + if (typeof sock.connecting === 'boolean') { + // net.Socket + + if (!sock.connecting) { + // Already connected + onConnect(); + } + } else { + // Assume socket/stream is already "connected" + onConnect(); + } + } + + return this; + } + + end() { + if (this._sock && isWritable(this._sock)) { + this._protocol.disconnect(DISCONNECT_REASON.BY_APPLICATION); + this._sock.end(); + } + return this; + } + + destroy() { + this._sock && isWritable(this._sock) && this._sock.destroy(); + return this; + } + + exec(cmd, opts, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + if (typeof opts === 'function') { + cb = opts; + opts = {}; + } + + const extraOpts = { allowHalfOpen: (opts.allowHalfOpen !== false) }; + + openChannel(this, 'session', extraOpts, (err, chan) => { + if (err) { + cb(err); + return; + } + + const todo = []; + + function reqCb(err) { + if (err) { + chan.close(); + cb(err); + return; + } + if (todo.length) + todo.shift()(); + } + + if (this.config.allowAgentFwd === true + || (opts + && opts.agentForward === true + && this._agent !== undefined)) { + todo.push(() => reqAgentFwd(chan, reqCb)); + } + + if (typeof opts === 'object' && opts !== null) { + if (typeof opts.env === 'object' && opts.env !== null) + reqEnv(chan, opts.env); + if ((typeof opts.pty === 'object' && opts.pty !== null) + || opts.pty === true) { + todo.push(() => reqPty(chan, opts.pty, reqCb)); + } + if ((typeof opts.x11 === 'object' && opts.x11 !== null) + || opts.x11 === 'number' + || opts.x11 === true) { + todo.push(() => reqX11(chan, opts.x11, reqCb)); + } + } + + todo.push(() => reqExec(chan, cmd, opts, cb)); + todo.shift()(); + }); + + return this; + } + + shell(wndopts, opts, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + if (typeof wndopts === 'function') { + cb = wndopts; + wndopts = opts = undefined; + } else if (typeof opts === 'function') { + cb = opts; + opts = undefined; + } + if (wndopts && (wndopts.x11 !== undefined || wndopts.env !== undefined)) { + opts = wndopts; + wndopts = undefined; + } + + openChannel(this, 'session', (err, chan) => { + if (err) { + cb(err); + return; + } + + const todo = []; + + function reqCb(err) { + if (err) { + chan.close(); + cb(err); + return; + } + if (todo.length) + todo.shift()(); + } + + if (this.config.allowAgentFwd === true + || (opts + && opts.agentForward === true + && this._agent !== undefined)) { + todo.push(() => reqAgentFwd(chan, reqCb)); + } + + if (wndopts !== false) + todo.push(() => reqPty(chan, wndopts, reqCb)); + + if (typeof opts === 'object' && opts !== null) { + if (typeof opts.env === 'object' && opts.env !== null) + reqEnv(chan, opts.env); + if ((typeof opts.x11 === 'object' && opts.x11 !== null) + || opts.x11 === 'number' + || opts.x11 === true) { + todo.push(() => reqX11(chan, opts.x11, reqCb)); + } + } + + todo.push(() => reqShell(chan, cb)); + todo.shift()(); + }); + + return this; + } + + subsys(name, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + openChannel(this, 'session', (err, chan) => { + if (err) { + cb(err); + return; + } + + reqSubsystem(chan, name, (err, stream) => { + if (err) { + cb(err); + return; + } + + cb(undefined, stream); + }); + }); + + return this; + } + + forwardIn(bindAddr, bindPort, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + // Send a request for the server to start forwarding TCP connections to us + // on a particular address and port + + const wantReply = (typeof cb === 'function'); + + if (wantReply) { + this._callbacks.push((had_err, data) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error(`Unable to bind to ${bindAddr}:${bindPort}`)); + return; + } + + let realPort = bindPort; + if (bindPort === 0 && data && data.length >= 4) { + realPort = readUInt32BE(data, 0); + if (!(this._protocol._compatFlags & COMPAT.DYN_RPORT_BUG)) + bindPort = realPort; + } + + this._forwarding[`${bindAddr}:${bindPort}`] = realPort; + + cb(undefined, realPort); + }); + } + + this._protocol.tcpipForward(bindAddr, bindPort, wantReply); + + return this; + } + + unforwardIn(bindAddr, bindPort, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + // Send a request to stop forwarding us new connections for a particular + // address and port + + const wantReply = (typeof cb === 'function'); + + if (wantReply) { + this._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error(`Unable to unbind from ${bindAddr}:${bindPort}`)); + return; + } + + delete this._forwarding[`${bindAddr}:${bindPort}`]; + + cb(); + }); + } + + this._protocol.cancelTcpipForward(bindAddr, bindPort, wantReply); + + return this; + } + + forwardOut(srcIP, srcPort, dstIP, dstPort, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + // Send a request to forward a TCP connection to the server + + const cfg = { + srcIP: srcIP, + srcPort: srcPort, + dstIP: dstIP, + dstPort: dstPort + }; + + if (typeof cb !== 'function') + cb = noop; + + openChannel(this, 'direct-tcpip', cfg, cb); + + return this; + } + + openssh_noMoreSessions(cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + const wantReply = (typeof cb === 'function'); + + if (!this.config.strictVendor + || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { + if (wantReply) { + this._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error('Unable to disable future sessions')); + return; + } + + cb(); + }); + } + + this._protocol.openssh_noMoreSessions(wantReply); + return this; + } + + if (!wantReply) + return this; + + process.nextTick( + cb, + new Error( + 'strictVendor enabled and server is not OpenSSH or compatible version' + ) + ); + + return this; + } + + openssh_forwardInStreamLocal(socketPath, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + const wantReply = (typeof cb === 'function'); + + if (!this.config.strictVendor + || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { + if (wantReply) { + this._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error(`Unable to bind to ${socketPath}`)); + return; + } + this._forwardingUnix[socketPath] = true; + cb(); + }); + } + + this._protocol.openssh_streamLocalForward(socketPath, wantReply); + return this; + } + + if (!wantReply) + return this; + + process.nextTick( + cb, + new Error( + 'strictVendor enabled and server is not OpenSSH or compatible version' + ) + ); + + return this; + } + + openssh_unforwardInStreamLocal(socketPath, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + const wantReply = (typeof cb === 'function'); + + if (!this.config.strictVendor + || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { + if (wantReply) { + this._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error(`Unable to unbind from ${socketPath}`)); + return; + } + delete this._forwardingUnix[socketPath]; + cb(); + }); + } + + this._protocol.openssh_cancelStreamLocalForward(socketPath, wantReply); + return this; + } + + if (!wantReply) + return this; + + process.nextTick( + cb, + new Error( + 'strictVendor enabled and server is not OpenSSH or compatible version' + ) + ); + + return this; + } + + openssh_forwardOutStreamLocal(socketPath, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + if (typeof cb !== 'function') + cb = noop; + + if (!this.config.strictVendor + || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { + openChannel(this, 'direct-streamlocal@openssh.com', { socketPath }, cb); + return this; + } + process.nextTick( + cb, + new Error( + 'strictVendor enabled and server is not OpenSSH or compatible version' + ) + ); + + return this; + } + + sftp(env, cb) { + if (!this._sock || !isWritable(this._sock)) + throw new Error('Not connected'); + + if (typeof env === 'function') { + cb = env; + env = undefined; + } + + openChannel(this, 'sftp', (err, sftp) => { + if (err) { + cb(err); + return; + } + + const reqSubsystemCb = (err, sftp_) => { + if (err) { + cb(err); + return; + } + + function removeListeners() { + sftp.removeListener('ready', onReady); + sftp.removeListener('error', onError); + sftp.removeListener('exit', onExit); + sftp.removeListener('close', onExit); + } + + function onReady() { + // TODO: do not remove exit/close in case remote end closes the + // channel abruptly and we need to notify outstanding callbacks + removeListeners(); + cb(undefined, sftp); + } + + function onError(err) { + removeListeners(); + cb(err); + } + + function onExit(code, signal) { + removeListeners(); + let msg; + if (typeof code === 'number') + msg = `Received exit code ${code} while establishing SFTP session`; + else if (signal !== undefined) + msg = `Received signal ${signal} while establishing SFTP session`; + else + msg = 'Received unexpected SFTP session termination'; + const err = new Error(msg); + err.code = code; + err.signal = signal; + cb(err); + } + + sftp.on('ready', onReady) + .on('error', onError) + .on('exit', onExit) + .on('close', onExit); + + sftp._init(); + }; + + if (typeof env === 'object' && env !== null) { + reqEnv(sftp, env, (err) => { + if (err) { + cb(err); + return; + } + + reqSubsystem(sftp, 'sftp', reqSubsystemCb); + }); + } else { + reqSubsystem(sftp, 'sftp', reqSubsystemCb); + } + }); + + return this; + } + + setNoDelay(noDelay) { + if (this._sock && typeof this._sock.setNoDelay === 'function') + this._sock.setNoDelay(noDelay); + + return this; + } +} + +function openChannel(self, type, opts, cb) { + // Ask the server to open a channel for some purpose + // (e.g. session (sftp, exec, shell), or forwarding a TCP connection + const initWindow = MAX_WINDOW; + const maxPacket = PACKET_SIZE; + + if (typeof opts === 'function') { + cb = opts; + opts = {}; + } + + const wrapper = (err, stream) => { + cb(err, stream); + }; + wrapper.type = type; + + const localChan = self._chanMgr.add(wrapper); + + if (localChan === -1) { + cb(new Error('No free channels available')); + return; + } + + switch (type) { + case 'session': + case 'sftp': + self._protocol.session(localChan, initWindow, maxPacket); + break; + case 'direct-tcpip': + self._protocol.directTcpip(localChan, initWindow, maxPacket, opts); + break; + case 'direct-streamlocal@openssh.com': + self._protocol.openssh_directStreamLocal( + localChan, initWindow, maxPacket, opts + ); + break; + default: + throw new Error(`Unsupported channel type: ${type}`); + } +} + +function reqX11(chan, screen, cb) { + // Asks server to start sending us X11 connections + const cfg = { + single: false, + protocol: 'MIT-MAGIC-COOKIE-1', + cookie: undefined, + screen: 0 + }; + + if (typeof screen === 'function') { + cb = screen; + } else if (typeof screen === 'object' && screen !== null) { + if (typeof screen.single === 'boolean') + cfg.single = screen.single; + if (typeof screen.screen === 'number') + cfg.screen = screen.screen; + if (typeof screen.protocol === 'string') + cfg.protocol = screen.protocol; + if (typeof screen.cookie === 'string') + cfg.cookie = screen.cookie; + else if (Buffer.isBuffer(screen.cookie)) + cfg.cookie = screen.cookie.hexSlice(0, screen.cookie.length); + } + if (cfg.cookie === undefined) + cfg.cookie = randomCookie(); + + const wantReply = (typeof cb === 'function'); + + if (chan.outgoing.state !== 'open') { + if (wantReply) + cb(new Error('Channel is not open')); + return; + } + + if (wantReply) { + chan._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true ? had_err : new Error('Unable to request X11')); + return; + } + + chan._hasX11 = true; + ++chan._client._acceptX11; + chan.once('close', () => { + if (chan._client._acceptX11) + --chan._client._acceptX11; + }); + + cb(); + }); + } + + chan._client._protocol.x11Forward(chan.outgoing.id, cfg, wantReply); +} + +function reqPty(chan, opts, cb) { + let rows = 24; + let cols = 80; + let width = 640; + let height = 480; + let term = 'vt100'; + let modes = null; + + if (typeof opts === 'function') { + cb = opts; + } else if (typeof opts === 'object' && opts !== null) { + if (typeof opts.rows === 'number') + rows = opts.rows; + if (typeof opts.cols === 'number') + cols = opts.cols; + if (typeof opts.width === 'number') + width = opts.width; + if (typeof opts.height === 'number') + height = opts.height; + if (typeof opts.term === 'string') + term = opts.term; + if (typeof opts.modes === 'object') + modes = opts.modes; + } + + const wantReply = (typeof cb === 'function'); + + if (chan.outgoing.state !== 'open') { + if (wantReply) + cb(new Error('Channel is not open')); + return; + } + + if (wantReply) { + chan._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error('Unable to request a pseudo-terminal')); + return; + } + cb(); + }); + } + + chan._client._protocol.pty(chan.outgoing.id, + rows, + cols, + height, + width, + term, + modes, + wantReply); +} + +function reqAgentFwd(chan, cb) { + const wantReply = (typeof cb === 'function'); + + if (chan.outgoing.state !== 'open') { + wantReply && cb(new Error('Channel is not open')); + return; + } + if (chan._client._agentFwdEnabled) { + wantReply && cb(false); + return; + } + + chan._client._agentFwdEnabled = true; + + chan._callbacks.push((had_err) => { + if (had_err) { + chan._client._agentFwdEnabled = false; + if (wantReply) { + cb(had_err !== true + ? had_err + : new Error('Unable to request agent forwarding')); + } + return; + } + + if (wantReply) + cb(); + }); + + chan._client._protocol.openssh_agentForward(chan.outgoing.id, true); +} + +function reqShell(chan, cb) { + if (chan.outgoing.state !== 'open') { + cb(new Error('Channel is not open')); + return; + } + + chan._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true ? had_err : new Error('Unable to open shell')); + return; + } + chan.subtype = 'shell'; + cb(undefined, chan); + }); + + chan._client._protocol.shell(chan.outgoing.id, true); +} + +function reqExec(chan, cmd, opts, cb) { + if (chan.outgoing.state !== 'open') { + cb(new Error('Channel is not open')); + return; + } + + chan._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true ? had_err : new Error('Unable to exec')); + return; + } + chan.subtype = 'exec'; + chan.allowHalfOpen = (opts.allowHalfOpen !== false); + cb(undefined, chan); + }); + + chan._client._protocol.exec(chan.outgoing.id, cmd, true); +} + +function reqEnv(chan, env, cb) { + const wantReply = (typeof cb === 'function'); + + if (chan.outgoing.state !== 'open') { + if (wantReply) + cb(new Error('Channel is not open')); + return; + } + + if (wantReply) { + chan._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error('Unable to set environment')); + return; + } + cb(); + }); + } + + const keys = Object.keys(env || {}); + + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + const val = env[key]; + chan._client._protocol.env(chan.outgoing.id, key, val, wantReply); + } +} + +function reqSubsystem(chan, name, cb) { + if (chan.outgoing.state !== 'open') { + cb(new Error('Channel is not open')); + return; + } + + chan._callbacks.push((had_err) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error(`Unable to start subsystem: ${name}`)); + return; + } + chan.subtype = 'subsystem'; + cb(undefined, chan); + }); + + chan._client._protocol.subsystem(chan.outgoing.id, name, true); +} + +// TODO: inline implementation into single call site +function onCHANNEL_OPEN(self, info) { + // The server is trying to open a channel with us, this is usually when + // we asked the server to forward us connections on some port and now they + // are asking us to accept/deny an incoming connection on their side + + let localChan = -1; + let reason; + + const accept = () => { + const chanInfo = { + type: info.type, + incoming: { + id: localChan, + window: MAX_WINDOW, + packetSize: PACKET_SIZE, + state: 'open' + }, + outgoing: { + id: info.sender, + window: info.window, + packetSize: info.packetSize, + state: 'open' + } + }; + const stream = new Channel(self, chanInfo); + self._chanMgr.update(localChan, stream); + + self._protocol.channelOpenConfirm(info.sender, + localChan, + MAX_WINDOW, + PACKET_SIZE); + return stream; + }; + const reject = () => { + if (reason === undefined) { + if (localChan === -1) + reason = CHANNEL_OPEN_FAILURE.RESOURCE_SHORTAGE; + else + reason = CHANNEL_OPEN_FAILURE.CONNECT_FAILED; + } + + if (localChan !== -1) + self._chanMgr.remove(localChan); + + self._protocol.channelOpenFail(info.sender, reason, ''); + }; + const reserveChannel = () => { + localChan = self._chanMgr.add(); + + if (localChan === -1) { + reason = CHANNEL_OPEN_FAILURE.RESOURCE_SHORTAGE; + if (self.config.debug) { + self.config.debug( + 'Client: Automatic rejection of incoming channel open: ' + + 'no channels available' + ); + } + } + + return (localChan !== -1); + }; + + const data = info.data; + switch (info.type) { + case 'forwarded-tcpip': { + const val = self._forwarding[`${data.destIP}:${data.destPort}`]; + if (val !== undefined && reserveChannel()) { + if (data.destPort === 0) + data.destPort = val; + self.emit('tcp connection', data, accept, reject); + return; + } + break; + } + case 'forwarded-streamlocal@openssh.com': + if (self._forwardingUnix[data.socketPath] !== undefined + && reserveChannel()) { + self.emit('unix connection', data, accept, reject); + return; + } + break; + case 'auth-agent@openssh.com': + if (self._agentFwdEnabled + && typeof self._agent.getStream === 'function' + && reserveChannel()) { + self._agent.getStream((err, stream) => { + if (err) + return reject(); + + const upstream = accept(); + upstream.pipe(stream).pipe(upstream); + }); + return; + } + break; + case 'x11': + if (self._acceptX11 !== 0 && reserveChannel()) { + self.emit('x11', data, accept, reject); + return; + } + break; + default: + // Automatically reject any unsupported channel open requests + reason = CHANNEL_OPEN_FAILURE.UNKNOWN_CHANNEL_TYPE; + if (self.config.debug) { + self.config.debug( + 'Client: Automatic rejection of unsupported incoming channel open ' + + `type: ${info.type}` + ); + } + } + + if (reason === undefined) { + reason = CHANNEL_OPEN_FAILURE.ADMINISTRATIVELY_PROHIBITED; + if (self.config.debug) { + self.config.debug( + 'Client: Automatic rejection of unexpected incoming channel open for: ' + + info.type + ); + } + } + + reject(); +} + +const randomCookie = (() => { + const buffer = Buffer.allocUnsafe(16); + return () => { + randomFillSync(buffer, 0, 16); + return buffer.hexSlice(0, 16); + }; +})(); + +function makeSimpleAuthHandler(authList) { + if (!Array.isArray(authList)) + throw new Error('authList must be an array'); + + let a = 0; + return (authsLeft, partialSuccess, cb) => { + if (a === authList.length) + return false; + return authList[a++]; + }; +} + +function hostKeysProve(client, keys_, cb) { + if (!client._sock || !isWritable(client._sock)) + return; + + if (typeof cb !== 'function') + cb = noop; + + if (!Array.isArray(keys_)) + throw new TypeError('Invalid keys argument type'); + + const keys = []; + for (const key of keys_) { + const parsed = parseKey(key); + if (parsed instanceof Error) + throw parsed; + keys.push(parsed); + } + + if (!client.config.strictVendor + || (client.config.strictVendor && RE_OPENSSH.test(client._remoteVer))) { + client._callbacks.push((had_err, data) => { + if (had_err) { + cb(had_err !== true + ? had_err + : new Error('Server failed to prove supplied keys')); + return; + } + + // TODO: move all of this parsing/verifying logic out of the client? + const ret = []; + let keyIdx = 0; + bufferParser.init(data, 0); + while (bufferParser.avail()) { + if (keyIdx === keys.length) + break; + const key = keys[keyIdx++]; + const keyPublic = key.getPublicSSH(); + + const sigEntry = bufferParser.readString(); + sigParser.init(sigEntry, 0); + const type = sigParser.readString(true); + let value = sigParser.readString(); + + let algo; + if (type !== key.type) { + if (key.type === 'ssh-rsa') { + switch (type) { + case 'rsa-sha2-256': + algo = 'sha256'; + break; + case 'rsa-sha2-512': + algo = 'sha512'; + break; + default: + continue; + } + } else { + continue; + } + } + + const sessionID = client._protocol._kex.sessionID; + const verifyData = Buffer.allocUnsafe( + 4 + 29 + 4 + sessionID.length + 4 + keyPublic.length + ); + let p = 0; + writeUInt32BE(verifyData, 29, p); + verifyData.utf8Write('hostkeys-prove-00@openssh.com', p += 4, 29); + writeUInt32BE(verifyData, sessionID.length, p += 29); + bufferCopy(sessionID, verifyData, 0, sessionID.length, p += 4); + writeUInt32BE(verifyData, keyPublic.length, p += sessionID.length); + bufferCopy(keyPublic, verifyData, 0, keyPublic.length, p += 4); + + if (!(value = sigSSHToASN1(value, type))) + continue; + if (key.verify(verifyData, value, algo) === true) + ret.push(key); + } + sigParser.clear(); + bufferParser.clear(); + + cb(null, ret); + }); + + client._protocol.openssh_hostKeysProve(keys); + return; + } + + process.nextTick( + cb, + new Error( + 'strictVendor enabled and server is not OpenSSH or compatible version' + ) + ); +} + +function getKeyAlgos(client, key, serverSigAlgs) { + switch (key.type) { + case 'ssh-rsa': + if (client._protocol._compatFlags & COMPAT.IMPLY_RSA_SHA2_SIGALGS) { + if (!Array.isArray(serverSigAlgs)) + serverSigAlgs = ['rsa-sha2-256', 'rsa-sha2-512']; + else + serverSigAlgs = ['rsa-sha2-256', 'rsa-sha2-512', ...serverSigAlgs]; + } + if (Array.isArray(serverSigAlgs)) { + if (serverSigAlgs.indexOf('rsa-sha2-256') !== -1) + return [['rsa-sha2-256', 'sha256']]; + if (serverSigAlgs.indexOf('rsa-sha2-512') !== -1) + return [['rsa-sha2-512', 'sha512']]; + if (serverSigAlgs.indexOf('ssh-rsa') === -1) + return []; + } + return [['ssh-rsa', 'sha1']]; + } +} + +module.exports = Client; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/http-agents.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/http-agents.js new file mode 100644 index 0000000..770a0e6 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/http-agents.js @@ -0,0 +1,84 @@ +'use strict'; + +const { Agent: HttpAgent } = require('http'); +const { Agent: HttpsAgent } = require('https'); +const { connect: tlsConnect } = require('tls'); + +let Client; + +for (const ctor of [HttpAgent, HttpsAgent]) { + class SSHAgent extends ctor { + constructor(connectCfg, agentOptions) { + super(agentOptions); + + this._connectCfg = connectCfg; + this._defaultSrcIP = (agentOptions && agentOptions.srcIP) || 'localhost'; + } + + createConnection(options, cb) { + const srcIP = (options && options.localAddress) || this._defaultSrcIP; + const srcPort = (options && options.localPort) || 0; + const dstIP = options.host; + const dstPort = options.port; + + if (Client === undefined) + Client = require('./client.js'); + + const client = new Client(); + let triedForward = false; + client.on('ready', () => { + client.forwardOut(srcIP, srcPort, dstIP, dstPort, (err, stream) => { + triedForward = true; + if (err) { + client.end(); + return cb(err); + } + stream.once('close', () => client.end()); + cb(null, decorateStream(stream, ctor, options)); + }); + }).on('error', cb).on('close', () => { + if (!triedForward) + cb(new Error('Unexpected connection close')); + }).connect(this._connectCfg); + } + } + + exports[ctor === HttpAgent ? 'SSHTTPAgent' : 'SSHTTPSAgent'] = SSHAgent; +} + +function noop() {} + +function decorateStream(stream, ctor, options) { + if (ctor === HttpAgent) { + // HTTP + stream.setKeepAlive = noop; + stream.setNoDelay = noop; + stream.setTimeout = noop; + stream.ref = noop; + stream.unref = noop; + stream.destroySoon = stream.destroy; + return stream; + } + + // HTTPS + options.socket = stream; + const wrapped = tlsConnect(options); + + // This is a workaround for a regression in node v12.16.3+ + // https://github.com/nodejs/node/issues/35904 + const onClose = (() => { + let called = false; + return () => { + if (called) + return; + called = true; + if (stream.isPaused()) + stream.resume(); + }; + })(); + // 'end' listener is needed because 'close' is not emitted in some scenarios + // in node v12.x for some unknown reason + wrapped.on('end', onClose).on('close', onClose); + + return wrapped; +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/index.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/index.js new file mode 100644 index 0000000..82c2c93 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/index.js @@ -0,0 +1,44 @@ +'use strict'; + +const { + AgentProtocol, + BaseAgent, + createAgent, + CygwinAgent, + OpenSSHAgent, + PageantAgent, +} = require('./agent.js'); +const { + SSHTTPAgent: HTTPAgent, + SSHTTPSAgent: HTTPSAgent, +} = require('./http-agents.js'); +const { parseKey } = require('./protocol/keyParser.js'); +const { + flagsToString, + OPEN_MODE, + STATUS_CODE, + stringToFlags, +} = require('./protocol/SFTP.js'); + +module.exports = { + AgentProtocol, + BaseAgent, + createAgent, + Client: require('./client.js'), + CygwinAgent, + HTTPAgent, + HTTPSAgent, + OpenSSHAgent, + PageantAgent, + Server: require('./server.js'), + utils: { + parseKey, + ...require('./keygen.js'), + sftp: { + flagsToString, + OPEN_MODE, + STATUS_CODE, + stringToFlags, + }, + }, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/keygen.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/keygen.js new file mode 100644 index 0000000..570c90e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/keygen.js @@ -0,0 +1,582 @@ +'use strict'; + +const { + createCipheriv, + generateKeyPair: generateKeyPair_, + generateKeyPairSync: generateKeyPairSync_, + getCurves, + randomBytes, +} = require('crypto'); + +const { Ber } = require('asn1'); +const bcrypt_pbkdf = require('bcrypt-pbkdf').pbkdf; + +const { CIPHER_INFO } = require('./protocol/crypto.js'); + +const SALT_LEN = 16; +const DEFAULT_ROUNDS = 16; + +const curves = getCurves(); +const ciphers = new Map(Object.entries(CIPHER_INFO)); + +function makeArgs(type, opts) { + if (typeof type !== 'string') + throw new TypeError('Key type must be a string'); + + const publicKeyEncoding = { type: 'spki', format: 'der' }; + const privateKeyEncoding = { type: 'pkcs8', format: 'der' }; + + switch (type.toLowerCase()) { + case 'rsa': { + if (typeof opts !== 'object' || opts === null) + throw new TypeError('Missing options object for RSA key'); + const modulusLength = opts.bits; + if (!Number.isInteger(modulusLength)) + throw new TypeError('RSA bits must be an integer'); + if (modulusLength <= 0 || modulusLength > 16384) + throw new RangeError('RSA bits must be non-zero and <= 16384'); + return ['rsa', { modulusLength, publicKeyEncoding, privateKeyEncoding }]; + } + case 'ecdsa': { + if (typeof opts !== 'object' || opts === null) + throw new TypeError('Missing options object for ECDSA key'); + if (!Number.isInteger(opts.bits)) + throw new TypeError('ECDSA bits must be an integer'); + let namedCurve; + switch (opts.bits) { + case 256: + namedCurve = 'prime256v1'; + break; + case 384: + namedCurve = 'secp384r1'; + break; + case 521: + namedCurve = 'secp521r1'; + break; + default: + throw new Error('ECDSA bits must be 256, 384, or 521'); + } + if (!curves.includes(namedCurve)) + throw new Error('Unsupported ECDSA bits value'); + return ['ec', { namedCurve, publicKeyEncoding, privateKeyEncoding }]; + } + case 'ed25519': + return ['ed25519', { publicKeyEncoding, privateKeyEncoding }]; + default: + throw new Error(`Unsupported key type: ${type}`); + } +} + +function parseDERs(keyType, pub, priv) { + switch (keyType) { + case 'rsa': { + // Note: we don't need to parse the public key since the PKCS8 private key + // already includes the public key parameters + + // Parse private key + let reader = new Ber.Reader(priv); + reader.readSequence(); + + // - Version + if (reader.readInt() !== 0) + throw new Error('Unsupported version in RSA private key'); + + // - Algorithm + reader.readSequence(); + if (reader.readOID() !== '1.2.840.113549.1.1.1') + throw new Error('Bad RSA private OID'); + // - Algorithm parameters (RSA has none) + if (reader.readByte() !== Ber.Null) + throw new Error('Malformed RSA private key (expected null)'); + if (reader.readByte() !== 0x00) { + throw new Error( + 'Malformed RSA private key (expected zero-length null)' + ); + } + + reader = new Ber.Reader(reader.readString(Ber.OctetString, true)); + reader.readSequence(); + if (reader.readInt() !== 0) + throw new Error('Unsupported version in RSA private key'); + const n = reader.readString(Ber.Integer, true); + const e = reader.readString(Ber.Integer, true); + const d = reader.readString(Ber.Integer, true); + const p = reader.readString(Ber.Integer, true); + const q = reader.readString(Ber.Integer, true); + reader.readString(Ber.Integer, true); // dmp1 + reader.readString(Ber.Integer, true); // dmq1 + const iqmp = reader.readString(Ber.Integer, true); + + /* + OpenSSH RSA private key: + string "ssh-rsa" + string n -- public + string e -- public + string d -- private + string iqmp -- private + string p -- private + string q -- private + */ + const keyName = Buffer.from('ssh-rsa'); + const privBuf = Buffer.allocUnsafe( + 4 + keyName.length + + 4 + n.length + + 4 + e.length + + 4 + d.length + + 4 + iqmp.length + + 4 + p.length + + 4 + q.length + ); + let pos = 0; + + privBuf.writeUInt32BE(keyName.length, pos += 0); + privBuf.set(keyName, pos += 4); + privBuf.writeUInt32BE(n.length, pos += keyName.length); + privBuf.set(n, pos += 4); + privBuf.writeUInt32BE(e.length, pos += n.length); + privBuf.set(e, pos += 4); + privBuf.writeUInt32BE(d.length, pos += e.length); + privBuf.set(d, pos += 4); + privBuf.writeUInt32BE(iqmp.length, pos += d.length); + privBuf.set(iqmp, pos += 4); + privBuf.writeUInt32BE(p.length, pos += iqmp.length); + privBuf.set(p, pos += 4); + privBuf.writeUInt32BE(q.length, pos += p.length); + privBuf.set(q, pos += 4); + + /* + OpenSSH RSA public key: + string "ssh-rsa" + string e -- public + string n -- public + */ + const pubBuf = Buffer.allocUnsafe( + 4 + keyName.length + + 4 + e.length + + 4 + n.length + ); + pos = 0; + + pubBuf.writeUInt32BE(keyName.length, pos += 0); + pubBuf.set(keyName, pos += 4); + pubBuf.writeUInt32BE(e.length, pos += keyName.length); + pubBuf.set(e, pos += 4); + pubBuf.writeUInt32BE(n.length, pos += e.length); + pubBuf.set(n, pos += 4); + + return { sshName: keyName.toString(), priv: privBuf, pub: pubBuf }; + } + case 'ec': { + // Parse public key + let reader = new Ber.Reader(pub); + reader.readSequence(); + + reader.readSequence(); + if (reader.readOID() !== '1.2.840.10045.2.1') + throw new Error('Bad ECDSA public OID'); + // Skip curve OID, we'll get it from the private key + reader.readOID(); + let pubBin = reader.readString(Ber.BitString, true); + { + // Remove leading zero bytes + let i = 0; + for (; i < pubBin.length && pubBin[i] === 0x00; ++i); + if (i > 0) + pubBin = pubBin.slice(i); + } + + // Parse private key + reader = new Ber.Reader(priv); + reader.readSequence(); + + // - Version + if (reader.readInt() !== 0) + throw new Error('Unsupported version in ECDSA private key'); + + reader.readSequence(); + if (reader.readOID() !== '1.2.840.10045.2.1') + throw new Error('Bad ECDSA private OID'); + const curveOID = reader.readOID(); + let sshCurveName; + switch (curveOID) { + case '1.2.840.10045.3.1.7': + // prime256v1/secp256r1 + sshCurveName = 'nistp256'; + break; + case '1.3.132.0.34': + // secp384r1 + sshCurveName = 'nistp384'; + break; + case '1.3.132.0.35': + // secp521r1 + sshCurveName = 'nistp521'; + break; + default: + throw new Error('Unsupported curve in ECDSA private key'); + } + + reader = new Ber.Reader(reader.readString(Ber.OctetString, true)); + reader.readSequence(); + + // - Version + if (reader.readInt() !== 1) + throw new Error('Unsupported version in ECDSA private key'); + + // Add leading zero byte to prevent negative bignum in private key + const privBin = Buffer.concat([ + Buffer.from([0x00]), + reader.readString(Ber.OctetString, true) + ]); + + /* + OpenSSH ECDSA private key: + string "ecdsa-sha2-" + string curve name + string Q -- public + string d -- private + */ + const keyName = Buffer.from(`ecdsa-sha2-${sshCurveName}`); + sshCurveName = Buffer.from(sshCurveName); + const privBuf = Buffer.allocUnsafe( + 4 + keyName.length + + 4 + sshCurveName.length + + 4 + pubBin.length + + 4 + privBin.length + ); + let pos = 0; + + privBuf.writeUInt32BE(keyName.length, pos += 0); + privBuf.set(keyName, pos += 4); + privBuf.writeUInt32BE(sshCurveName.length, pos += keyName.length); + privBuf.set(sshCurveName, pos += 4); + privBuf.writeUInt32BE(pubBin.length, pos += sshCurveName.length); + privBuf.set(pubBin, pos += 4); + privBuf.writeUInt32BE(privBin.length, pos += pubBin.length); + privBuf.set(privBin, pos += 4); + + /* + OpenSSH ECDSA public key: + string "ecdsa-sha2-" + string curve name + string Q -- public + */ + const pubBuf = Buffer.allocUnsafe( + 4 + keyName.length + + 4 + sshCurveName.length + + 4 + pubBin.length + ); + pos = 0; + + pubBuf.writeUInt32BE(keyName.length, pos += 0); + pubBuf.set(keyName, pos += 4); + pubBuf.writeUInt32BE(sshCurveName.length, pos += keyName.length); + pubBuf.set(sshCurveName, pos += 4); + pubBuf.writeUInt32BE(pubBin.length, pos += sshCurveName.length); + pubBuf.set(pubBin, pos += 4); + + return { sshName: keyName.toString(), priv: privBuf, pub: pubBuf }; + } + case 'ed25519': { + // Parse public key + let reader = new Ber.Reader(pub); + reader.readSequence(); + + // - Algorithm + reader.readSequence(); + if (reader.readOID() !== '1.3.101.112') + throw new Error('Bad ED25519 public OID'); + // - Attributes (absent for ED25519) + + let pubBin = reader.readString(Ber.BitString, true); + { + // Remove leading zero bytes + let i = 0; + for (; i < pubBin.length && pubBin[i] === 0x00; ++i); + if (i > 0) + pubBin = pubBin.slice(i); + } + + // Parse private key + reader = new Ber.Reader(priv); + reader.readSequence(); + + // - Version + if (reader.readInt() !== 0) + throw new Error('Unsupported version in ED25519 private key'); + + // - Algorithm + reader.readSequence(); + if (reader.readOID() !== '1.3.101.112') + throw new Error('Bad ED25519 private OID'); + // - Attributes (absent) + + reader = new Ber.Reader(reader.readString(Ber.OctetString, true)); + const privBin = reader.readString(Ber.OctetString, true); + + /* + OpenSSH ed25519 private key: + string "ssh-ed25519" + string public key + string private key + public key + */ + const keyName = Buffer.from('ssh-ed25519'); + const privBuf = Buffer.allocUnsafe( + 4 + keyName.length + + 4 + pubBin.length + + 4 + (privBin.length + pubBin.length) + ); + let pos = 0; + + privBuf.writeUInt32BE(keyName.length, pos += 0); + privBuf.set(keyName, pos += 4); + privBuf.writeUInt32BE(pubBin.length, pos += keyName.length); + privBuf.set(pubBin, pos += 4); + privBuf.writeUInt32BE( + privBin.length + pubBin.length, + pos += pubBin.length + ); + privBuf.set(privBin, pos += 4); + privBuf.set(pubBin, pos += privBin.length); + + /* + OpenSSH ed25519 public key: + string "ssh-ed25519" + string public key + */ + const pubBuf = Buffer.allocUnsafe( + 4 + keyName.length + + 4 + pubBin.length + ); + pos = 0; + + pubBuf.writeUInt32BE(keyName.length, pos += 0); + pubBuf.set(keyName, pos += 4); + pubBuf.writeUInt32BE(pubBin.length, pos += keyName.length); + pubBuf.set(pubBin, pos += 4); + + return { sshName: keyName.toString(), priv: privBuf, pub: pubBuf }; + } + } +} + +function convertKeys(keyType, pub, priv, opts) { + let format = 'new'; + let encrypted; + let comment = ''; + if (typeof opts === 'object' && opts !== null) { + if (typeof opts.comment === 'string' && opts.comment) + comment = opts.comment; + if (typeof opts.format === 'string' && opts.format) + format = opts.format; + if (opts.passphrase) { + let passphrase; + if (typeof opts.passphrase === 'string') + passphrase = Buffer.from(opts.passphrase); + else if (Buffer.isBuffer(opts.passphrase)) + passphrase = opts.passphrase; + else + throw new Error('Invalid passphrase'); + + if (opts.cipher === undefined) + throw new Error('Missing cipher name'); + const cipher = ciphers.get(opts.cipher); + if (cipher === undefined) + throw new Error('Invalid cipher name'); + + if (format === 'new') { + let rounds = DEFAULT_ROUNDS; + if (opts.rounds !== undefined) { + if (!Number.isInteger(opts.rounds)) + throw new TypeError('rounds must be an integer'); + if (opts.rounds > 0) + rounds = opts.rounds; + } + + const gen = Buffer.allocUnsafe(cipher.keyLen + cipher.ivLen); + const salt = randomBytes(SALT_LEN); + const r = bcrypt_pbkdf( + passphrase, + passphrase.length, + salt, + salt.length, + gen, + gen.length, + rounds + ); + if (r !== 0) + return new Error('Failed to generate information to encrypt key'); + + /* + string salt + uint32 rounds + */ + const kdfOptions = Buffer.allocUnsafe(4 + salt.length + 4); + { + let pos = 0; + kdfOptions.writeUInt32BE(salt.length, pos += 0); + kdfOptions.set(salt, pos += 4); + kdfOptions.writeUInt32BE(rounds, pos += salt.length); + } + + encrypted = { + cipher, + cipherName: opts.cipher, + kdfName: 'bcrypt', + kdfOptions, + key: gen.slice(0, cipher.keyLen), + iv: gen.slice(cipher.keyLen), + }; + } + } + } + + switch (format) { + case 'new': { + let privateB64 = '-----BEGIN OPENSSH PRIVATE KEY-----\n'; + let publicB64; + /* + byte[] "openssh-key-v1\0" + string ciphername + string kdfname + string kdfoptions + uint32 number of keys N + string publickey1 + string encrypted, padded list of private keys + uint32 checkint + uint32 checkint + byte[] privatekey1 + string comment1 + byte 1 + byte 2 + byte 3 + ... + byte padlen % 255 + */ + const cipherName = Buffer.from(encrypted ? encrypted.cipherName : 'none'); + const kdfName = Buffer.from(encrypted ? encrypted.kdfName : 'none'); + const kdfOptions = (encrypted ? encrypted.kdfOptions : Buffer.alloc(0)); + const blockLen = (encrypted ? encrypted.cipher.blockLen : 8); + + const parsed = parseDERs(keyType, pub, priv); + + const checkInt = randomBytes(4); + const commentBin = Buffer.from(comment); + const privBlobLen = (4 + 4 + parsed.priv.length + 4 + commentBin.length); + let padding = []; + for (let i = 1; ((privBlobLen + padding.length) % blockLen); ++i) + padding.push(i & 0xFF); + padding = Buffer.from(padding); + + let privBlob = Buffer.allocUnsafe(privBlobLen + padding.length); + let extra; + { + let pos = 0; + privBlob.set(checkInt, pos += 0); + privBlob.set(checkInt, pos += 4); + privBlob.set(parsed.priv, pos += 4); + privBlob.writeUInt32BE(commentBin.length, pos += parsed.priv.length); + privBlob.set(commentBin, pos += 4); + privBlob.set(padding, pos += commentBin.length); + } + + if (encrypted) { + const options = { authTagLength: encrypted.cipher.authLen }; + const cipher = createCipheriv( + encrypted.cipher.sslName, + encrypted.key, + encrypted.iv, + options + ); + cipher.setAutoPadding(false); + privBlob = Buffer.concat([ cipher.update(privBlob), cipher.final() ]); + if (encrypted.cipher.authLen > 0) + extra = cipher.getAuthTag(); + else + extra = Buffer.alloc(0); + encrypted.key.fill(0); + encrypted.iv.fill(0); + } else { + extra = Buffer.alloc(0); + } + + const magicBytes = Buffer.from('openssh-key-v1\0'); + const privBin = Buffer.allocUnsafe( + magicBytes.length + + 4 + cipherName.length + + 4 + kdfName.length + + 4 + kdfOptions.length + + 4 + + 4 + parsed.pub.length + + 4 + privBlob.length + + extra.length + ); + { + let pos = 0; + privBin.set(magicBytes, pos += 0); + privBin.writeUInt32BE(cipherName.length, pos += magicBytes.length); + privBin.set(cipherName, pos += 4); + privBin.writeUInt32BE(kdfName.length, pos += cipherName.length); + privBin.set(kdfName, pos += 4); + privBin.writeUInt32BE(kdfOptions.length, pos += kdfName.length); + privBin.set(kdfOptions, pos += 4); + privBin.writeUInt32BE(1, pos += kdfOptions.length); + privBin.writeUInt32BE(parsed.pub.length, pos += 4); + privBin.set(parsed.pub, pos += 4); + privBin.writeUInt32BE(privBlob.length, pos += parsed.pub.length); + privBin.set(privBlob, pos += 4); + privBin.set(extra, pos += privBlob.length); + } + + { + const b64 = privBin.base64Slice(0, privBin.length); + let formatted = b64.replace(/.{64}/g, '$&\n'); + if (b64.length & 63) + formatted += '\n'; + privateB64 += formatted; + } + + { + const b64 = parsed.pub.base64Slice(0, parsed.pub.length); + publicB64 = `${parsed.sshName} ${b64}${comment ? ` ${comment}` : ''}`; + } + + privateB64 += '-----END OPENSSH PRIVATE KEY-----\n'; + return { + private: privateB64, + public: publicB64, + }; + } + default: + throw new Error('Invalid output key format'); + } +} + +function noop() {} + +module.exports = { + generateKeyPair: (keyType, opts, cb) => { + if (typeof opts === 'function') { + cb = opts; + opts = undefined; + } + if (typeof cb !== 'function') + cb = noop; + const args = makeArgs(keyType, opts); + generateKeyPair_(...args, (err, pub, priv) => { + if (err) + return cb(err); + let ret; + try { + ret = convertKeys(args[0], pub, priv, opts); + } catch (ex) { + return cb(ex); + } + cb(null, ret); + }); + }, + generateKeyPairSync: (keyType, opts) => { + const args = makeArgs(keyType, opts); + const { publicKey: pub, privateKey: priv } = generateKeyPairSync_(...args); + return convertKeys(args[0], pub, priv, opts); + } +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/Protocol.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/Protocol.js new file mode 100644 index 0000000..7302488 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/Protocol.js @@ -0,0 +1,2136 @@ +/* + TODO: + * Replace `buffer._pos` usage in keyParser.js and elsewhere + * Utilize optional "writev" support when writing packets from + cipher.encrypt() + * Built-in support for automatic re-keying, on by default + * Revisit receiving unexpected/unknown packets + * Error (fatal or otherwise) or ignore or pass on to user (in some or all + cases)? + * Including server/client check for single directional packet types? + * Check packets for validity or bail as early as possible? + * Automatic re-key every 2**31 packets after the last key exchange (sent or + received), as suggested by RFC4344. OpenSSH currently does this. + * Automatic re-key every so many blocks depending on cipher. RFC4344: + Because of a birthday property of block ciphers and some modes of + operation, implementations must be careful not to encrypt too many + blocks with the same encryption key. + + Let L be the block length (in bits) of an SSH encryption method's + block cipher (e.g., 128 for AES). If L is at least 128, then, after + rekeying, an SSH implementation SHOULD NOT encrypt more than 2**(L/4) + blocks before rekeying again. If L is at least 128, then SSH + implementations should also attempt to force a rekey before receiving + more than 2**(L/4) blocks. If L is less than 128 (which is the case + for older ciphers such as 3DES, Blowfish, CAST-128, and IDEA), then, + although it may be too expensive to rekey every 2**(L/4) blocks, it + is still advisable for SSH implementations to follow the original + recommendation in [RFC4253]: rekey at least once for every gigabyte + of transmitted data. + + Note that if L is less than or equal to 128, then the recommendation + in this subsection supersedes the recommendation in Section 3.1. If + an SSH implementation uses a block cipher with a larger block size + (e.g., Rijndael with 256-bit blocks), then the recommendations in + Section 3.1 may supersede the recommendations in this subsection + (depending on the lengths of the packets). +*/ + +'use strict'; + +const { inspect } = require('util'); + +const { bindingAvailable, NullCipher, NullDecipher } = require('./crypto.js'); +const { + COMPAT_CHECKS, + DISCONNECT_REASON, + eddsaSupported, + MESSAGE, + SIGNALS, + TERMINAL_MODE, +} = require('./constants.js'); +const { + DEFAULT_KEXINIT_CLIENT, + DEFAULT_KEXINIT_SERVER, + KexInit, + kexinit, + onKEXPayload, +} = require('./kex.js'); +const { + parseKey, +} = require('./keyParser.js'); +const MESSAGE_HANDLERS = require('./handlers.js'); +const { + bufferCopy, + bufferFill, + bufferSlice, + convertSignature, + sendPacket, + writeUInt32BE, +} = require('./utils.js'); +const { + PacketReader, + PacketWriter, + ZlibPacketReader, + ZlibPacketWriter, +} = require('./zlib.js'); + +const MODULE_VER = require('../../package.json').version; + +const VALID_DISCONNECT_REASONS = new Map( + Object.values(DISCONNECT_REASON).map((n) => [n, 1]) +); +const IDENT_RAW = Buffer.from(`SSH-2.0-ssh2js${MODULE_VER}`); +const IDENT = Buffer.from(`${IDENT_RAW}\r\n`); +const MAX_LINE_LEN = 8192; +const MAX_LINES = 1024; +const PING_PAYLOAD = Buffer.from([ + MESSAGE.GLOBAL_REQUEST, + // "keepalive@openssh.com" + 0, 0, 0, 21, + 107, 101, 101, 112, 97, 108, 105, 118, 101, 64, 111, 112, 101, 110, 115, + 115, 104, 46, 99, 111, 109, + // Request a reply + 1, +]); +const NO_TERMINAL_MODES_BUFFER = Buffer.from([ TERMINAL_MODE.TTY_OP_END ]); + +function noop() {} + +/* + Inbound: + * kexinit payload (needed only until exchange hash is generated) + * raw ident + * rekey packet queue + * expected packet (implemented as separate _parse() function?) + Outbound: + * kexinit payload (needed only until exchange hash is generated) + * rekey packet queue + * kex secret (needed only until NEWKEYS) + * exchange hash (needed only until NEWKEYS) + * session ID (set to exchange hash from initial handshake) +*/ +class Protocol { + constructor(config) { + const onWrite = config.onWrite; + if (typeof onWrite !== 'function') + throw new Error('Missing onWrite function'); + this._onWrite = (data) => { onWrite(data); }; + + const onError = config.onError; + if (typeof onError !== 'function') + throw new Error('Missing onError function'); + this._onError = (err) => { onError(err); }; + + const debug = config.debug; + this._debug = (typeof debug === 'function' + ? (msg) => { debug(msg); } + : undefined); + + const onHeader = config.onHeader; + this._onHeader = (typeof onHeader === 'function' + ? (...args) => { onHeader(...args); } + : noop); + + const onPacket = config.onPacket; + this._onPacket = (typeof onPacket === 'function' + ? () => { onPacket(); } + : noop); + + let onHandshakeComplete = config.onHandshakeComplete; + if (typeof onHandshakeComplete !== 'function') + onHandshakeComplete = noop; + let firstHandshake; + this._onHandshakeComplete = (...args) => { + this._debug && this._debug('Handshake completed'); + if (firstHandshake === undefined) + firstHandshake = true; + else + firstHandshake = false; + + // Process packets queued during a rekey where necessary + const oldQueue = this._queue; + if (oldQueue) { + this._queue = undefined; + this._debug && this._debug( + `Draining outbound queue (${oldQueue.length}) ...` + ); + for (let i = 0; i < oldQueue.length; ++i) { + const data = oldQueue[i]; + // data === payload only + + // XXX: hacky + let finalized = this._packetRW.write.finalize(data); + if (finalized === data) { + const packet = this._cipher.allocPacket(data.length); + packet.set(data, 5); + finalized = packet; + } + + sendPacket(this, finalized); + } + this._debug && this._debug('... finished draining outbound queue'); + } + + if (firstHandshake && this._server && this._kex.remoteExtInfoEnabled) + sendExtInfo(this); + + onHandshakeComplete(...args); + }; + this._queue = undefined; + + const messageHandlers = config.messageHandlers; + if (typeof messageHandlers === 'object' && messageHandlers !== null) + this._handlers = messageHandlers; + else + this._handlers = {}; + + this._onPayload = onPayload.bind(this); + + this._server = !!config.server; + this._banner = undefined; + let greeting; + if (this._server) { + if (typeof config.hostKeys !== 'object' || config.hostKeys === null) + throw new Error('Missing server host key(s)'); + this._hostKeys = config.hostKeys; + + // Greeting displayed before the ssh identification string is sent, this + // is usually ignored by most clients + if (typeof config.greeting === 'string' && config.greeting.length) { + greeting = (config.greeting.slice(-2) === '\r\n' + ? config.greeting + : `${config.greeting}\r\n`); + } + + // Banner shown after the handshake completes, but before user + // authentication begins + if (typeof config.banner === 'string' && config.banner.length) { + this._banner = (config.banner.slice(-2) === '\r\n' + ? config.banner + : `${config.banner}\r\n`); + } + } else { + this._hostKeys = undefined; + } + + let offer = config.offer; + if (typeof offer !== 'object' || offer === null) { + offer = (this._server ? DEFAULT_KEXINIT_SERVER : DEFAULT_KEXINIT_CLIENT); + } else if (offer.constructor !== KexInit) { + if (this._server) { + offer.kex = offer.kex.concat(['kex-strict-s-v00@openssh.com']); + } else { + offer.kex = offer.kex.concat([ + 'ext-info-c', + 'kex-strict-c-v00@openssh.com', + ]); + } + offer = new KexInit(offer); + } + this._kex = undefined; + this._strictMode = undefined; + this._kexinit = undefined; + this._offer = offer; + this._cipher = new NullCipher(0, this._onWrite); + this._decipher = undefined; + this._skipNextInboundPacket = false; + this._packetRW = { + read: new PacketReader(), + write: new PacketWriter(this), + }; + this._hostVerifier = (!this._server + && typeof config.hostVerifier === 'function' + ? config.hostVerifier + : undefined); + + this._parse = parseHeader; + this._buffer = undefined; + this._authsQueue = []; + this._authenticated = false; + this._remoteIdentRaw = undefined; + let sentIdent; + if (typeof config.ident === 'string') { + this._identRaw = Buffer.from(`SSH-2.0-${config.ident}`); + + sentIdent = Buffer.allocUnsafe(this._identRaw.length + 2); + sentIdent.set(this._identRaw, 0); + sentIdent[sentIdent.length - 2] = 13; // '\r' + sentIdent[sentIdent.length - 1] = 10; // '\n' + } else if (Buffer.isBuffer(config.ident)) { + const fullIdent = Buffer.allocUnsafe(8 + config.ident.length); + fullIdent.latin1Write('SSH-2.0-', 0, 8); + fullIdent.set(config.ident, 8); + this._identRaw = fullIdent; + + sentIdent = Buffer.allocUnsafe(fullIdent.length + 2); + sentIdent.set(fullIdent, 0); + sentIdent[sentIdent.length - 2] = 13; // '\r' + sentIdent[sentIdent.length - 1] = 10; // '\n' + } else { + this._identRaw = IDENT_RAW; + sentIdent = IDENT; + } + this._compatFlags = 0; + + if (this._debug) { + if (bindingAvailable) + this._debug('Custom crypto binding available'); + else + this._debug('Custom crypto binding not available'); + } + + this._debug && this._debug( + `Local ident: ${inspect(this._identRaw.toString())}` + ); + this.start = () => { + this.start = undefined; + if (greeting) + this._onWrite(greeting); + this._onWrite(sentIdent); + }; + } + _destruct(reason) { + this._packetRW.read.cleanup(); + this._packetRW.write.cleanup(); + this._cipher && this._cipher.free(); + this._decipher && this._decipher.free(); + if (typeof reason !== 'string' || reason.length === 0) + reason = 'fatal error'; + this.parse = () => { + throw new Error(`Instance unusable after ${reason}`); + }; + this._onWrite = () => { + throw new Error(`Instance unusable after ${reason}`); + }; + this._destruct = undefined; + } + cleanup() { + this._destruct && this._destruct(); + } + parse(chunk, i, len) { + while (i < len) + i = this._parse(chunk, i, len); + } + + // Protocol message API + + // =========================================================================== + // Common/Shared ============================================================= + // =========================================================================== + + // Global + // ------ + disconnect(reason) { + const pktLen = 1 + 4 + 4 + 4; + // We don't use _packetRW.write.* here because we need to make sure that + // we always get a full packet allocated because this message can be sent + // at any time -- even during a key exchange + let p = this._packetRW.write.allocStartKEX; + const packet = this._packetRW.write.alloc(pktLen, true); + const end = p + pktLen; + + if (!VALID_DISCONNECT_REASONS.has(reason)) + reason = DISCONNECT_REASON.PROTOCOL_ERROR; + + packet[p] = MESSAGE.DISCONNECT; + writeUInt32BE(packet, reason, ++p); + packet.fill(0, p += 4, end); + + this._debug && this._debug(`Outbound: Sending DISCONNECT (${reason})`); + sendPacket(this, this._packetRW.write.finalize(packet, true), true); + } + ping() { + const p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(PING_PAYLOAD.length); + + packet.set(PING_PAYLOAD, p); + + this._debug && this._debug( + 'Outbound: Sending ping (GLOBAL_REQUEST: keepalive@openssh.com)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + rekey() { + if (this._kexinit === undefined) { + this._debug && this._debug('Outbound: Initiated explicit rekey'); + this._queue = []; + kexinit(this); + } else { + this._debug && this._debug('Outbound: Ignoring rekey during handshake'); + } + } + + // 'ssh-connection' service-specific + // --------------------------------- + requestSuccess(data) { + let p = this._packetRW.write.allocStart; + let packet; + if (Buffer.isBuffer(data)) { + packet = this._packetRW.write.alloc(1 + data.length); + + packet[p] = MESSAGE.REQUEST_SUCCESS; + + packet.set(data, ++p); + } else { + packet = this._packetRW.write.alloc(1); + + packet[p] = MESSAGE.REQUEST_SUCCESS; + } + + this._debug && this._debug('Outbound: Sending REQUEST_SUCCESS'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + requestFailure() { + const p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1); + + packet[p] = MESSAGE.REQUEST_FAILURE; + + this._debug && this._debug('Outbound: Sending REQUEST_FAILURE'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelSuccess(chan) { + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4); + + packet[p] = MESSAGE.CHANNEL_SUCCESS; + + writeUInt32BE(packet, chan, ++p); + + this._debug && this._debug(`Outbound: Sending CHANNEL_SUCCESS (r:${chan})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelFailure(chan) { + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4); + + packet[p] = MESSAGE.CHANNEL_FAILURE; + + writeUInt32BE(packet, chan, ++p); + + this._debug && this._debug(`Outbound: Sending CHANNEL_FAILURE (r:${chan})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelEOF(chan) { + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4); + + packet[p] = MESSAGE.CHANNEL_EOF; + + writeUInt32BE(packet, chan, ++p); + + this._debug && this._debug(`Outbound: Sending CHANNEL_EOF (r:${chan})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelClose(chan) { + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4); + + packet[p] = MESSAGE.CHANNEL_CLOSE; + + writeUInt32BE(packet, chan, ++p); + + this._debug && this._debug(`Outbound: Sending CHANNEL_CLOSE (r:${chan})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelWindowAdjust(chan, amount) { + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4); + + packet[p] = MESSAGE.CHANNEL_WINDOW_ADJUST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, amount, p += 4); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_WINDOW_ADJUST (r:${chan}, ${amount})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelData(chan, data) { + const isBuffer = Buffer.isBuffer(data); + const dataLen = (isBuffer ? data.length : Buffer.byteLength(data)); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + dataLen); + + packet[p] = MESSAGE.CHANNEL_DATA; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, dataLen, p += 4); + + if (isBuffer) + packet.set(data, p += 4); + else + packet.utf8Write(data, p += 4, dataLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_DATA (r:${chan}, ${dataLen})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelExtData(chan, data, type) { + const isBuffer = Buffer.isBuffer(data); + const dataLen = (isBuffer ? data.length : Buffer.byteLength(data)); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + dataLen); + + packet[p] = MESSAGE.CHANNEL_EXTENDED_DATA; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, type, p += 4); + + writeUInt32BE(packet, dataLen, p += 4); + + if (isBuffer) + packet.set(data, p += 4); + else + packet.utf8Write(data, p += 4, dataLen); + + this._debug + && this._debug(`Outbound: Sending CHANNEL_EXTENDED_DATA (r:${chan})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelOpenConfirm(remote, local, initWindow, maxPacket) { + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + 4); + + packet[p] = MESSAGE.CHANNEL_OPEN_CONFIRMATION; + + writeUInt32BE(packet, remote, ++p); + + writeUInt32BE(packet, local, p += 4); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_OPEN_CONFIRMATION (r:${remote}, l:${local})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + channelOpenFail(remote, reason, desc) { + if (typeof desc !== 'string') + desc = ''; + + const descLen = Buffer.byteLength(desc); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + descLen + 4); + + packet[p] = MESSAGE.CHANNEL_OPEN_FAILURE; + + writeUInt32BE(packet, remote, ++p); + + writeUInt32BE(packet, reason, p += 4); + + writeUInt32BE(packet, descLen, p += 4); + + p += 4; + if (descLen) { + packet.utf8Write(desc, p, descLen); + p += descLen; + } + + writeUInt32BE(packet, 0, p); // Empty language tag + + this._debug + && this._debug(`Outbound: Sending CHANNEL_OPEN_FAILURE (r:${remote})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + + // =========================================================================== + // Client-specific =========================================================== + // =========================================================================== + + // Global + // ------ + service(name) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const nameLen = Buffer.byteLength(name); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + nameLen); + + packet[p] = MESSAGE.SERVICE_REQUEST; + + writeUInt32BE(packet, nameLen, ++p); + packet.utf8Write(name, p += 4, nameLen); + + this._debug && this._debug(`Outbound: Sending SERVICE_REQUEST (${name})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + + // 'ssh-userauth' service-specific + // ------------------------------- + authPassword(username, password, newPassword) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const userLen = Buffer.byteLength(username); + const passLen = Buffer.byteLength(password); + const newPassLen = (newPassword ? Buffer.byteLength(newPassword) : 0); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + userLen + 4 + 14 + 4 + 8 + 1 + 4 + passLen + + (newPassword ? 4 + newPassLen : 0) + ); + + packet[p] = MESSAGE.USERAUTH_REQUEST; + + writeUInt32BE(packet, userLen, ++p); + packet.utf8Write(username, p += 4, userLen); + + writeUInt32BE(packet, 14, p += userLen); + packet.utf8Write('ssh-connection', p += 4, 14); + + writeUInt32BE(packet, 8, p += 14); + packet.utf8Write('password', p += 4, 8); + + packet[p += 8] = (newPassword ? 1 : 0); + + writeUInt32BE(packet, passLen, ++p); + if (Buffer.isBuffer(password)) + bufferCopy(password, packet, 0, passLen, p += 4); + else + packet.utf8Write(password, p += 4, passLen); + + if (newPassword) { + writeUInt32BE(packet, newPassLen, p += passLen); + if (Buffer.isBuffer(newPassword)) + bufferCopy(newPassword, packet, 0, newPassLen, p += 4); + else + packet.utf8Write(newPassword, p += 4, newPassLen); + this._debug && this._debug( + 'Outbound: Sending USERAUTH_REQUEST (changed password)' + ); + } else { + this._debug && this._debug( + 'Outbound: Sending USERAUTH_REQUEST (password)' + ); + } + + this._authsQueue.push('password'); + + sendPacket(this, this._packetRW.write.finalize(packet)); + } + authPK(username, pubKey, keyAlgo, cbSign) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + pubKey = parseKey(pubKey); + if (pubKey instanceof Error) + throw new Error('Invalid key'); + + const keyType = pubKey.type; + pubKey = pubKey.getPublicSSH(); + + if (typeof keyAlgo === 'function') { + cbSign = keyAlgo; + keyAlgo = undefined; + } + if (!keyAlgo) + keyAlgo = keyType; + + const userLen = Buffer.byteLength(username); + const algoLen = Buffer.byteLength(keyAlgo); + const pubKeyLen = pubKey.length; + const sessionID = this._kex.sessionID; + const sesLen = sessionID.length; + const payloadLen = + (cbSign ? 4 + sesLen : 0) + + 1 + 4 + userLen + 4 + 14 + 4 + 9 + 1 + 4 + algoLen + 4 + pubKeyLen; + let packet; + let p; + if (cbSign) { + packet = Buffer.allocUnsafe(payloadLen); + p = 0; + writeUInt32BE(packet, sesLen, p); + packet.set(sessionID, p += 4); + p += sesLen; + } else { + packet = this._packetRW.write.alloc(payloadLen); + p = this._packetRW.write.allocStart; + } + + packet[p] = MESSAGE.USERAUTH_REQUEST; + + writeUInt32BE(packet, userLen, ++p); + packet.utf8Write(username, p += 4, userLen); + + writeUInt32BE(packet, 14, p += userLen); + packet.utf8Write('ssh-connection', p += 4, 14); + + writeUInt32BE(packet, 9, p += 14); + packet.utf8Write('publickey', p += 4, 9); + + packet[p += 9] = (cbSign ? 1 : 0); + + writeUInt32BE(packet, algoLen, ++p); + packet.utf8Write(keyAlgo, p += 4, algoLen); + + writeUInt32BE(packet, pubKeyLen, p += algoLen); + packet.set(pubKey, p += 4); + + if (!cbSign) { + this._authsQueue.push('publickey'); + + this._debug && this._debug( + 'Outbound: Sending USERAUTH_REQUEST (publickey -- check)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + return; + } + + cbSign(packet, (signature) => { + signature = convertSignature(signature, keyType); + if (signature === false) + throw new Error('Error while converting handshake signature'); + + const sigLen = signature.length; + p = this._packetRW.write.allocStart; + packet = this._packetRW.write.alloc( + 1 + 4 + userLen + 4 + 14 + 4 + 9 + 1 + 4 + algoLen + 4 + pubKeyLen + 4 + + 4 + algoLen + 4 + sigLen + ); + + // TODO: simply copy from original "packet" to new `packet` to avoid + // having to write each individual field a second time? + packet[p] = MESSAGE.USERAUTH_REQUEST; + + writeUInt32BE(packet, userLen, ++p); + packet.utf8Write(username, p += 4, userLen); + + writeUInt32BE(packet, 14, p += userLen); + packet.utf8Write('ssh-connection', p += 4, 14); + + writeUInt32BE(packet, 9, p += 14); + packet.utf8Write('publickey', p += 4, 9); + + packet[p += 9] = 1; + + writeUInt32BE(packet, algoLen, ++p); + packet.utf8Write(keyAlgo, p += 4, algoLen); + + writeUInt32BE(packet, pubKeyLen, p += algoLen); + packet.set(pubKey, p += 4); + + writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += pubKeyLen); + + writeUInt32BE(packet, algoLen, p += 4); + packet.utf8Write(keyAlgo, p += 4, algoLen); + + writeUInt32BE(packet, sigLen, p += algoLen); + packet.set(signature, p += 4); + + // Servers shouldn't send packet type 60 in response to signed publickey + // attempts, but if they do, interpret as type 60. + this._authsQueue.push('publickey'); + + this._debug && this._debug( + 'Outbound: Sending USERAUTH_REQUEST (publickey)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + }); + } + authHostbased(username, pubKey, hostname, userlocal, keyAlgo, cbSign) { + // TODO: Make DRY by sharing similar code with authPK() + if (this._server) + throw new Error('Client-only method called in server mode'); + + pubKey = parseKey(pubKey); + if (pubKey instanceof Error) + throw new Error('Invalid key'); + + const keyType = pubKey.type; + pubKey = pubKey.getPublicSSH(); + + if (typeof keyAlgo === 'function') { + cbSign = keyAlgo; + keyAlgo = undefined; + } + if (!keyAlgo) + keyAlgo = keyType; + + const userLen = Buffer.byteLength(username); + const algoLen = Buffer.byteLength(keyAlgo); + const pubKeyLen = pubKey.length; + const sessionID = this._kex.sessionID; + const sesLen = sessionID.length; + const hostnameLen = Buffer.byteLength(hostname); + const userlocalLen = Buffer.byteLength(userlocal); + const data = Buffer.allocUnsafe( + 4 + sesLen + 1 + 4 + userLen + 4 + 14 + 4 + 9 + 4 + algoLen + + 4 + pubKeyLen + 4 + hostnameLen + 4 + userlocalLen + ); + let p = 0; + + writeUInt32BE(data, sesLen, p); + data.set(sessionID, p += 4); + + data[p += sesLen] = MESSAGE.USERAUTH_REQUEST; + + writeUInt32BE(data, userLen, ++p); + data.utf8Write(username, p += 4, userLen); + + writeUInt32BE(data, 14, p += userLen); + data.utf8Write('ssh-connection', p += 4, 14); + + writeUInt32BE(data, 9, p += 14); + data.utf8Write('hostbased', p += 4, 9); + + writeUInt32BE(data, algoLen, p += 9); + data.utf8Write(keyAlgo, p += 4, algoLen); + + writeUInt32BE(data, pubKeyLen, p += algoLen); + data.set(pubKey, p += 4); + + writeUInt32BE(data, hostnameLen, p += pubKeyLen); + data.utf8Write(hostname, p += 4, hostnameLen); + + writeUInt32BE(data, userlocalLen, p += hostnameLen); + data.utf8Write(userlocal, p += 4, userlocalLen); + + cbSign(data, (signature) => { + signature = convertSignature(signature, keyType); + if (!signature) + throw new Error('Error while converting handshake signature'); + + const sigLen = signature.length; + const reqDataLen = (data.length - sesLen - 4); + p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + reqDataLen + 4 + 4 + algoLen + 4 + sigLen + ); + + bufferCopy(data, packet, 4 + sesLen, data.length, p); + + writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += reqDataLen); + writeUInt32BE(packet, algoLen, p += 4); + packet.utf8Write(keyAlgo, p += 4, algoLen); + writeUInt32BE(packet, sigLen, p += algoLen); + packet.set(signature, p += 4); + + this._authsQueue.push('hostbased'); + + this._debug && this._debug( + 'Outbound: Sending USERAUTH_REQUEST (hostbased)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + }); + } + authKeyboard(username) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const userLen = Buffer.byteLength(username); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + userLen + 4 + 14 + 4 + 20 + 4 + 4 + ); + + packet[p] = MESSAGE.USERAUTH_REQUEST; + + writeUInt32BE(packet, userLen, ++p); + packet.utf8Write(username, p += 4, userLen); + + writeUInt32BE(packet, 14, p += userLen); + packet.utf8Write('ssh-connection', p += 4, 14); + + writeUInt32BE(packet, 20, p += 14); + packet.utf8Write('keyboard-interactive', p += 4, 20); + + writeUInt32BE(packet, 0, p += 20); + + writeUInt32BE(packet, 0, p += 4); + + this._authsQueue.push('keyboard-interactive'); + + this._debug && this._debug( + 'Outbound: Sending USERAUTH_REQUEST (keyboard-interactive)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + authNone(username) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const userLen = Buffer.byteLength(username); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + userLen + 4 + 14 + 4 + 4); + + packet[p] = MESSAGE.USERAUTH_REQUEST; + + writeUInt32BE(packet, userLen, ++p); + packet.utf8Write(username, p += 4, userLen); + + writeUInt32BE(packet, 14, p += userLen); + packet.utf8Write('ssh-connection', p += 4, 14); + + writeUInt32BE(packet, 4, p += 14); + packet.utf8Write('none', p += 4, 4); + + this._authsQueue.push('none'); + + this._debug && this._debug('Outbound: Sending USERAUTH_REQUEST (none)'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + authInfoRes(responses) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + let responsesTotalLen = 0; + let responseLens; + + if (responses) { + responseLens = new Array(responses.length); + for (let i = 0; i < responses.length; ++i) { + const len = Buffer.byteLength(responses[i]); + responseLens[i] = len; + responsesTotalLen += 4 + len; + } + } + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + responsesTotalLen); + + packet[p] = MESSAGE.USERAUTH_INFO_RESPONSE; + + if (responses) { + writeUInt32BE(packet, responses.length, ++p); + p += 4; + for (let i = 0; i < responses.length; ++i) { + const len = responseLens[i]; + writeUInt32BE(packet, len, p); + p += 4; + if (len) { + packet.utf8Write(responses[i], p, len); + p += len; + } + } + } else { + writeUInt32BE(packet, 0, ++p); + } + + this._debug && this._debug('Outbound: Sending USERAUTH_INFO_RESPONSE'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + + // 'ssh-connection' service-specific + // --------------------------------- + tcpipForward(bindAddr, bindPort, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const addrLen = Buffer.byteLength(bindAddr); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 13 + 1 + 4 + addrLen + 4); + + packet[p] = MESSAGE.GLOBAL_REQUEST; + + writeUInt32BE(packet, 13, ++p); + packet.utf8Write('tcpip-forward', p += 4, 13); + + packet[p += 13] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, addrLen, ++p); + packet.utf8Write(bindAddr, p += 4, addrLen); + + writeUInt32BE(packet, bindPort, p += addrLen); + + this._debug + && this._debug('Outbound: Sending GLOBAL_REQUEST (tcpip-forward)'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + cancelTcpipForward(bindAddr, bindPort, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const addrLen = Buffer.byteLength(bindAddr); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 20 + 1 + 4 + addrLen + 4); + + packet[p] = MESSAGE.GLOBAL_REQUEST; + + writeUInt32BE(packet, 20, ++p); + packet.utf8Write('cancel-tcpip-forward', p += 4, 20); + + packet[p += 20] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, addrLen, ++p); + packet.utf8Write(bindAddr, p += 4, addrLen); + + writeUInt32BE(packet, bindPort, p += addrLen); + + this._debug + && this._debug('Outbound: Sending GLOBAL_REQUEST (cancel-tcpip-forward)'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_streamLocalForward(socketPath, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const socketPathLen = Buffer.byteLength(socketPath); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 31 + 1 + 4 + socketPathLen + ); + + packet[p] = MESSAGE.GLOBAL_REQUEST; + + writeUInt32BE(packet, 31, ++p); + packet.utf8Write('streamlocal-forward@openssh.com', p += 4, 31); + + packet[p += 31] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, socketPathLen, ++p); + packet.utf8Write(socketPath, p += 4, socketPathLen); + + this._debug && this._debug( + 'Outbound: Sending GLOBAL_REQUEST (streamlocal-forward@openssh.com)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_cancelStreamLocalForward(socketPath, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const socketPathLen = Buffer.byteLength(socketPath); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 38 + 1 + 4 + socketPathLen + ); + + packet[p] = MESSAGE.GLOBAL_REQUEST; + + writeUInt32BE(packet, 38, ++p); + packet.utf8Write('cancel-streamlocal-forward@openssh.com', p += 4, 38); + + packet[p += 38] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, socketPathLen, ++p); + packet.utf8Write(socketPath, p += 4, socketPathLen); + + if (this._debug) { + this._debug( + 'Outbound: Sending GLOBAL_REQUEST ' + + '(cancel-streamlocal-forward@openssh.com)' + ); + } + sendPacket(this, this._packetRW.write.finalize(packet)); + } + directTcpip(chan, initWindow, maxPacket, cfg) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const srcLen = Buffer.byteLength(cfg.srcIP); + const dstLen = Buffer.byteLength(cfg.dstIP); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 12 + 4 + 4 + 4 + 4 + srcLen + 4 + 4 + dstLen + 4 + ); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 12, ++p); + packet.utf8Write('direct-tcpip', p += 4, 12); + + writeUInt32BE(packet, chan, p += 12); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + writeUInt32BE(packet, dstLen, p += 4); + packet.utf8Write(cfg.dstIP, p += 4, dstLen); + + writeUInt32BE(packet, cfg.dstPort, p += dstLen); + + writeUInt32BE(packet, srcLen, p += 4); + packet.utf8Write(cfg.srcIP, p += 4, srcLen); + + writeUInt32BE(packet, cfg.srcPort, p += srcLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_OPEN (r:${chan}, direct-tcpip)` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_directStreamLocal(chan, initWindow, maxPacket, cfg) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + const pathLen = Buffer.byteLength(cfg.socketPath); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 30 + 4 + 4 + 4 + 4 + pathLen + 4 + 4 + ); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 30, ++p); + packet.utf8Write('direct-streamlocal@openssh.com', p += 4, 30); + + writeUInt32BE(packet, chan, p += 30); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + writeUInt32BE(packet, pathLen, p += 4); + packet.utf8Write(cfg.socketPath, p += 4, pathLen); + + // zero-fill reserved fields (string and uint32) + bufferFill(packet, 0, p += pathLen, p + 8); + + if (this._debug) { + this._debug( + 'Outbound: Sending CHANNEL_OPEN ' + + `(r:${chan}, direct-streamlocal@openssh.com)` + ); + } + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_noMoreSessions(wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 28 + 1); + + packet[p] = MESSAGE.GLOBAL_REQUEST; + + writeUInt32BE(packet, 28, ++p); + packet.utf8Write('no-more-sessions@openssh.com', p += 4, 28); + + packet[p += 28] = (wantReply === undefined || wantReply === true ? 1 : 0); + + this._debug && this._debug( + 'Outbound: Sending GLOBAL_REQUEST (no-more-sessions@openssh.com)' + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + session(chan, initWindow, maxPacket) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 7 + 4 + 4 + 4); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 7, ++p); + packet.utf8Write('session', p += 4, 7); + + writeUInt32BE(packet, chan, p += 7); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + this._debug + && this._debug(`Outbound: Sending CHANNEL_OPEN (r:${chan}, session)`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + windowChange(chan, rows, cols, height, width) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 4 + 13 + 1 + 4 + 4 + 4 + 4 + ); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 13, p += 4); + packet.utf8Write('window-change', p += 4, 13); + + packet[p += 13] = 0; + + writeUInt32BE(packet, cols, ++p); + + writeUInt32BE(packet, rows, p += 4); + + writeUInt32BE(packet, width, p += 4); + + writeUInt32BE(packet, height, p += 4); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, window-change)` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + pty(chan, rows, cols, height, width, term, modes, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + if (!term || !term.length) + term = 'vt100'; + if (modes + && !Buffer.isBuffer(modes) + && !Array.isArray(modes) + && typeof modes === 'object' + && modes !== null) { + modes = modesToBytes(modes); + } + if (!modes || !modes.length) + modes = NO_TERMINAL_MODES_BUFFER; + + const termLen = term.length; + const modesLen = modes.length; + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 4 + 7 + 1 + 4 + termLen + 4 + 4 + 4 + 4 + 4 + modesLen + ); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 7, p += 4); + packet.utf8Write('pty-req', p += 4, 7); + + packet[p += 7] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, termLen, ++p); + packet.utf8Write(term, p += 4, termLen); + + writeUInt32BE(packet, cols, p += termLen); + + writeUInt32BE(packet, rows, p += 4); + + writeUInt32BE(packet, width, p += 4); + + writeUInt32BE(packet, height, p += 4); + + writeUInt32BE(packet, modesLen, p += 4); + p += 4; + if (Array.isArray(modes)) { + for (let i = 0; i < modesLen; ++i) + packet[p++] = modes[i]; + } else if (Buffer.isBuffer(modes)) { + packet.set(modes, p); + } + + this._debug + && this._debug(`Outbound: Sending CHANNEL_REQUEST (r:${chan}, pty-req)`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + shell(chan, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 5 + 1); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 5, p += 4); + packet.utf8Write('shell', p += 4, 5); + + packet[p += 5] = (wantReply === undefined || wantReply === true ? 1 : 0); + + this._debug + && this._debug(`Outbound: Sending CHANNEL_REQUEST (r:${chan}, shell)`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + exec(chan, cmd, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + const isBuf = Buffer.isBuffer(cmd); + const cmdLen = (isBuf ? cmd.length : Buffer.byteLength(cmd)); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + 1 + 4 + cmdLen); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 4, p += 4); + packet.utf8Write('exec', p += 4, 4); + + packet[p += 4] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, cmdLen, ++p); + if (isBuf) + packet.set(cmd, p += 4); + else + packet.utf8Write(cmd, p += 4, cmdLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, exec: ${cmd})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + signal(chan, signal) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + const origSignal = signal; + + signal = signal.toUpperCase(); + if (signal.slice(0, 3) === 'SIG') + signal = signal.slice(3); + + if (SIGNALS[signal] !== 1) + throw new Error(`Invalid signal: ${origSignal}`); + + const signalLen = signal.length; + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 4 + 6 + 1 + 4 + signalLen + ); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 6, p += 4); + packet.utf8Write('signal', p += 4, 6); + + packet[p += 6] = 0; + + writeUInt32BE(packet, signalLen, ++p); + packet.utf8Write(signal, p += 4, signalLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, signal: ${signal})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + env(chan, key, val, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + const keyLen = Buffer.byteLength(key); + const isBuf = Buffer.isBuffer(val); + const valLen = (isBuf ? val.length : Buffer.byteLength(val)); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 4 + 3 + 1 + 4 + keyLen + 4 + valLen + ); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 3, p += 4); + packet.utf8Write('env', p += 4, 3); + + packet[p += 3] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, keyLen, ++p); + packet.utf8Write(key, p += 4, keyLen); + + writeUInt32BE(packet, valLen, p += keyLen); + if (isBuf) + packet.set(val, p += 4); + else + packet.utf8Write(val, p += 4, valLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, env: ${key}=${val})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + x11Forward(chan, cfg, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + const protocol = cfg.protocol; + const cookie = cfg.cookie; + const isBufProto = Buffer.isBuffer(protocol); + const protoLen = (isBufProto + ? protocol.length + : Buffer.byteLength(protocol)); + const isBufCookie = Buffer.isBuffer(cookie); + const cookieLen = (isBufCookie + ? cookie.length + : Buffer.byteLength(cookie)); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 4 + 7 + 1 + 1 + 4 + protoLen + 4 + cookieLen + 4 + ); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 7, p += 4); + packet.utf8Write('x11-req', p += 4, 7); + + packet[p += 7] = (wantReply === undefined || wantReply === true ? 1 : 0); + + packet[++p] = (cfg.single ? 1 : 0); + + writeUInt32BE(packet, protoLen, ++p); + if (isBufProto) + packet.set(protocol, p += 4); + else + packet.utf8Write(protocol, p += 4, protoLen); + + writeUInt32BE(packet, cookieLen, p += protoLen); + if (isBufCookie) + packet.set(cookie, p += 4); + else + packet.latin1Write(cookie, p += 4, cookieLen); + + writeUInt32BE(packet, (cfg.screen || 0), p += cookieLen); + + this._debug + && this._debug(`Outbound: Sending CHANNEL_REQUEST (r:${chan}, x11-req)`); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + subsystem(chan, name, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + const nameLen = Buffer.byteLength(name); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 9 + 1 + 4 + nameLen); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 9, p += 4); + packet.utf8Write('subsystem', p += 4, 9); + + packet[p += 9] = (wantReply === undefined || wantReply === true ? 1 : 0); + + writeUInt32BE(packet, nameLen, ++p); + packet.utf8Write(name, p += 4, nameLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, subsystem: ${name})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_agentForward(chan, wantReply) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + // Does not consume window space + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 26 + 1); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 26, p += 4); + packet.utf8Write('auth-agent-req@openssh.com', p += 4, 26); + + packet[p += 26] = (wantReply === undefined || wantReply === true ? 1 : 0); + + if (this._debug) { + this._debug( + 'Outbound: Sending CHANNEL_REQUEST ' + + `(r:${chan}, auth-agent-req@openssh.com)` + ); + } + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_hostKeysProve(keys) { + if (this._server) + throw new Error('Client-only method called in server mode'); + + let keysTotal = 0; + const publicKeys = []; + for (const key of keys) { + const publicKey = key.getPublicSSH(); + keysTotal += 4 + publicKey.length; + publicKeys.push(publicKey); + } + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 29 + 1 + keysTotal); + + packet[p] = MESSAGE.GLOBAL_REQUEST; + + writeUInt32BE(packet, 29, ++p); + packet.utf8Write('hostkeys-prove-00@openssh.com', p += 4, 29); + + packet[p += 29] = 1; // want reply + + ++p; + for (const buf of publicKeys) { + writeUInt32BE(packet, buf.length, p); + bufferCopy(buf, packet, 0, buf.length, p += 4); + p += buf.length; + } + + if (this._debug) { + this._debug( + 'Outbound: Sending GLOBAL_REQUEST (hostkeys-prove-00@openssh.com)' + ); + } + sendPacket(this, this._packetRW.write.finalize(packet)); + } + + // =========================================================================== + // Server-specific =========================================================== + // =========================================================================== + + // Global + // ------ + serviceAccept(svcName) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + const svcNameLen = Buffer.byteLength(svcName); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + svcNameLen); + + packet[p] = MESSAGE.SERVICE_ACCEPT; + + writeUInt32BE(packet, svcNameLen, ++p); + packet.utf8Write(svcName, p += 4, svcNameLen); + + this._debug && this._debug(`Outbound: Sending SERVICE_ACCEPT (${svcName})`); + sendPacket(this, this._packetRW.write.finalize(packet)); + + if (this._server && this._banner && svcName === 'ssh-userauth') { + const banner = this._banner; + this._banner = undefined; // Prevent banner from being displayed again + const bannerLen = Buffer.byteLength(banner); + p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + bannerLen + 4); + + packet[p] = MESSAGE.USERAUTH_BANNER; + + writeUInt32BE(packet, bannerLen, ++p); + packet.utf8Write(banner, p += 4, bannerLen); + + writeUInt32BE(packet, 0, p += bannerLen); // Empty language tag + + this._debug && this._debug('Outbound: Sending USERAUTH_BANNER'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + } + // 'ssh-connection' service-specific + forwardedTcpip(chan, initWindow, maxPacket, cfg) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + const boundAddrLen = Buffer.byteLength(cfg.boundAddr); + const remoteAddrLen = Buffer.byteLength(cfg.remoteAddr); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 15 + 4 + 4 + 4 + 4 + boundAddrLen + 4 + 4 + remoteAddrLen + 4 + ); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 15, ++p); + packet.utf8Write('forwarded-tcpip', p += 4, 15); + + writeUInt32BE(packet, chan, p += 15); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + writeUInt32BE(packet, boundAddrLen, p += 4); + packet.utf8Write(cfg.boundAddr, p += 4, boundAddrLen); + + writeUInt32BE(packet, cfg.boundPort, p += boundAddrLen); + + writeUInt32BE(packet, remoteAddrLen, p += 4); + packet.utf8Write(cfg.remoteAddr, p += 4, remoteAddrLen); + + writeUInt32BE(packet, cfg.remotePort, p += remoteAddrLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_OPEN (r:${chan}, forwarded-tcpip)` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + x11(chan, initWindow, maxPacket, cfg) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + const addrLen = Buffer.byteLength(cfg.originAddr); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 3 + 4 + 4 + 4 + 4 + addrLen + 4 + ); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 3, ++p); + packet.utf8Write('x11', p += 4, 3); + + writeUInt32BE(packet, chan, p += 3); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + writeUInt32BE(packet, addrLen, p += 4); + packet.utf8Write(cfg.originAddr, p += 4, addrLen); + + writeUInt32BE(packet, cfg.originPort, p += addrLen); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_OPEN (r:${chan}, x11)` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_authAgent(chan, initWindow, maxPacket) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 22 + 4 + 4 + 4); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 22, ++p); + packet.utf8Write('auth-agent@openssh.com', p += 4, 22); + + writeUInt32BE(packet, chan, p += 22); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_OPEN (r:${chan}, auth-agent@openssh.com)` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + openssh_forwardedStreamLocal(chan, initWindow, maxPacket, cfg) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + const pathLen = Buffer.byteLength(cfg.socketPath); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 33 + 4 + 4 + 4 + 4 + pathLen + 4 + ); + + packet[p] = MESSAGE.CHANNEL_OPEN; + + writeUInt32BE(packet, 33, ++p); + packet.utf8Write('forwarded-streamlocal@openssh.com', p += 4, 33); + + writeUInt32BE(packet, chan, p += 33); + + writeUInt32BE(packet, initWindow, p += 4); + + writeUInt32BE(packet, maxPacket, p += 4); + + writeUInt32BE(packet, pathLen, p += 4); + packet.utf8Write(cfg.socketPath, p += 4, pathLen); + + writeUInt32BE(packet, 0, p += pathLen); + + if (this._debug) { + this._debug( + 'Outbound: Sending CHANNEL_OPEN ' + + `(r:${chan}, forwarded-streamlocal@openssh.com)` + ); + } + sendPacket(this, this._packetRW.write.finalize(packet)); + } + exitStatus(chan, status) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + // Does not consume window space + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + 4 + 11 + 1 + 4); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 11, p += 4); + packet.utf8Write('exit-status', p += 4, 11); + + packet[p += 11] = 0; + + writeUInt32BE(packet, status, ++p); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, exit-status: ${status})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + exitSignal(chan, name, coreDumped, msg) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + // Does not consume window space + + const origSignal = name; + + if (typeof origSignal !== 'string' || !origSignal) + throw new Error(`Invalid signal: ${origSignal}`); + + let signal = name.toUpperCase(); + if (signal.slice(0, 3) === 'SIG') + signal = signal.slice(3); + + if (SIGNALS[signal] !== 1) + throw new Error(`Invalid signal: ${origSignal}`); + + const nameLen = Buffer.byteLength(signal); + const msgLen = (msg ? Buffer.byteLength(msg) : 0); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + 4 + 11 + 1 + 4 + nameLen + 1 + 4 + msgLen + 4 + ); + + packet[p] = MESSAGE.CHANNEL_REQUEST; + + writeUInt32BE(packet, chan, ++p); + + writeUInt32BE(packet, 11, p += 4); + packet.utf8Write('exit-signal', p += 4, 11); + + packet[p += 11] = 0; + + writeUInt32BE(packet, nameLen, ++p); + packet.utf8Write(signal, p += 4, nameLen); + + packet[p += nameLen] = (coreDumped ? 1 : 0); + + writeUInt32BE(packet, msgLen, ++p); + + p += 4; + if (msgLen) { + packet.utf8Write(msg, p, msgLen); + p += msgLen; + } + + writeUInt32BE(packet, 0, p); + + this._debug && this._debug( + `Outbound: Sending CHANNEL_REQUEST (r:${chan}, exit-signal: ${name})` + ); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + // 'ssh-userauth' service-specific + authFailure(authMethods, isPartial) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + if (this._authsQueue.length === 0) + throw new Error('No auth in progress'); + + let methods; + + if (typeof authMethods === 'boolean') { + isPartial = authMethods; + authMethods = undefined; + } + + if (authMethods) { + methods = []; + for (let i = 0; i < authMethods.length; ++i) { + if (authMethods[i].toLowerCase() === 'none') + continue; + methods.push(authMethods[i]); + } + methods = methods.join(','); + } else { + methods = ''; + } + + const methodsLen = methods.length; + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + methodsLen + 1); + + packet[p] = MESSAGE.USERAUTH_FAILURE; + + writeUInt32BE(packet, methodsLen, ++p); + packet.utf8Write(methods, p += 4, methodsLen); + + packet[p += methodsLen] = (isPartial === true ? 1 : 0); + + this._authsQueue.shift(); + + this._debug && this._debug('Outbound: Sending USERAUTH_FAILURE'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + authSuccess() { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + if (this._authsQueue.length === 0) + throw new Error('No auth in progress'); + + const p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1); + + packet[p] = MESSAGE.USERAUTH_SUCCESS; + + this._authsQueue.shift(); + this._authenticated = true; + + this._debug && this._debug('Outbound: Sending USERAUTH_SUCCESS'); + sendPacket(this, this._packetRW.write.finalize(packet)); + + if (this._kex.negotiated.cs.compress === 'zlib@openssh.com') + this._packetRW.read = new ZlibPacketReader(); + if (this._kex.negotiated.sc.compress === 'zlib@openssh.com') + this._packetRW.write = new ZlibPacketWriter(this); + } + authPKOK(keyAlgo, key) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + if (this._authsQueue.length === 0 || this._authsQueue[0] !== 'publickey') + throw new Error('"publickey" auth not in progress'); + + // TODO: support parsed key for `key` + + const keyAlgoLen = Buffer.byteLength(keyAlgo); + const keyLen = key.length; + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + keyAlgoLen + 4 + keyLen); + + packet[p] = MESSAGE.USERAUTH_PK_OK; + + writeUInt32BE(packet, keyAlgoLen, ++p); + packet.utf8Write(keyAlgo, p += 4, keyAlgoLen); + + writeUInt32BE(packet, keyLen, p += keyAlgoLen); + packet.set(key, p += 4); + + this._authsQueue.shift(); + + this._debug && this._debug('Outbound: Sending USERAUTH_PK_OK'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + authPasswdChg(prompt) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + const promptLen = Buffer.byteLength(prompt); + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc(1 + 4 + promptLen + 4); + + packet[p] = MESSAGE.USERAUTH_PASSWD_CHANGEREQ; + + writeUInt32BE(packet, promptLen, ++p); + packet.utf8Write(prompt, p += 4, promptLen); + + writeUInt32BE(packet, 0, p += promptLen); // Empty language tag + + this._debug && this._debug('Outbound: Sending USERAUTH_PASSWD_CHANGEREQ'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } + authInfoReq(name, instructions, prompts) { + if (!this._server) + throw new Error('Server-only method called in client mode'); + + let promptsLen = 0; + const nameLen = name ? Buffer.byteLength(name) : 0; + const instrLen = instructions ? Buffer.byteLength(instructions) : 0; + + for (let i = 0; i < prompts.length; ++i) + promptsLen += 4 + Buffer.byteLength(prompts[i].prompt) + 1; + + let p = this._packetRW.write.allocStart; + const packet = this._packetRW.write.alloc( + 1 + 4 + nameLen + 4 + instrLen + 4 + 4 + promptsLen + ); + + packet[p] = MESSAGE.USERAUTH_INFO_REQUEST; + + writeUInt32BE(packet, nameLen, ++p); + p += 4; + if (name) { + packet.utf8Write(name, p, nameLen); + p += nameLen; + } + + writeUInt32BE(packet, instrLen, p); + p += 4; + if (instructions) { + packet.utf8Write(instructions, p, instrLen); + p += instrLen; + } + + writeUInt32BE(packet, 0, p); + + writeUInt32BE(packet, prompts.length, p += 4); + p += 4; + for (let i = 0; i < prompts.length; ++i) { + const prompt = prompts[i]; + const promptLen = Buffer.byteLength(prompt.prompt); + + writeUInt32BE(packet, promptLen, p); + p += 4; + if (promptLen) { + packet.utf8Write(prompt.prompt, p, promptLen); + p += promptLen; + } + packet[p++] = (prompt.echo ? 1 : 0); + } + + this._debug && this._debug('Outbound: Sending USERAUTH_INFO_REQUEST'); + sendPacket(this, this._packetRW.write.finalize(packet)); + } +} + +// SSH-protoversion-softwareversion (SP comments) CR LF +const RE_IDENT = /^SSH-(2\.0|1\.99)-([^ ]+)(?: (.*))?$/; + +// TODO: optimize this by starting n bytes from the end of this._buffer instead +// of the beginning +function parseHeader(chunk, p, len) { + let data; + let chunkOffset; + if (this._buffer) { + data = Buffer.allocUnsafe(this._buffer.length + (len - p)); + data.set(this._buffer, 0); + if (p === 0) { + data.set(chunk, this._buffer.length); + } else { + data.set(new Uint8Array(chunk.buffer, + chunk.byteOffset + p, + (len - p)), + this._buffer.length); + } + chunkOffset = this._buffer.length; + p = 0; + } else { + data = chunk; + chunkOffset = 0; + } + const op = p; + let start = p; + let end = p; + let needNL = false; + let lineLen = 0; + let lines = 0; + for (; p < data.length; ++p) { + const ch = data[p]; + + if (ch === 13 /* '\r' */) { + needNL = true; + continue; + } + + if (ch === 10 /* '\n' */) { + if (end > start + && end - start > 4 + && data[start] === 83 /* 'S' */ + && data[start + 1] === 83 /* 'S' */ + && data[start + 2] === 72 /* 'H' */ + && data[start + 3] === 45 /* '-' */) { + + const full = data.latin1Slice(op, end + 1); + const identRaw = (start === op ? full : full.slice(start - op)); + const m = RE_IDENT.exec(identRaw); + if (!m) + throw new Error('Invalid identification string'); + + const header = { + greeting: (start === op ? '' : full.slice(0, start - op)), + identRaw, + versions: { + protocol: m[1], + software: m[2], + }, + comments: m[3] + }; + + // Needed during handshake + this._remoteIdentRaw = Buffer.from(identRaw); + + this._debug && this._debug(`Remote ident: ${inspect(identRaw)}`); + this._compatFlags = getCompatFlags(header); + + this._buffer = undefined; + this._decipher = + new NullDecipher(0, onKEXPayload.bind(this, { firstPacket: true })); + this._parse = parsePacket; + + this._onHeader(header); + if (!this._destruct) { + // We disconnected inside _onHeader + return len; + } + + kexinit(this); + + return p + 1 - chunkOffset; + } + + // Only allow pre-ident greetings when we're a client + if (this._server) + throw new Error('Greetings from clients not permitted'); + + if (++lines > MAX_LINES) + throw new Error('Max greeting lines exceeded'); + + needNL = false; + start = p + 1; + lineLen = 0; + } else if (needNL) { + throw new Error('Invalid header: expected newline'); + } else if (++lineLen >= MAX_LINE_LEN) { + throw new Error('Header line too long'); + } + + end = p; + } + if (!this._buffer) + this._buffer = bufferSlice(data, op); + + return p - chunkOffset; +} + +function parsePacket(chunk, p, len) { + return this._decipher.decrypt(chunk, p, len); +} + +function onPayload(payload) { + // XXX: move this to the Decipher implementations? + + this._onPacket(); + + if (payload.length === 0) { + this._debug && this._debug('Inbound: Skipping empty packet payload'); + return; + } + + payload = this._packetRW.read.read(payload); + + const type = payload[0]; + if (type === MESSAGE.USERAUTH_SUCCESS + && !this._server + && !this._authenticated) { + this._authenticated = true; + if (this._kex.negotiated.cs.compress === 'zlib@openssh.com') + this._packetRW.write = new ZlibPacketWriter(this); + if (this._kex.negotiated.sc.compress === 'zlib@openssh.com') + this._packetRW.read = new ZlibPacketReader(); + } + const handler = MESSAGE_HANDLERS[type]; + if (handler === undefined) { + this._debug && this._debug(`Inbound: Unsupported message type: ${type}`); + return; + } + + return handler(this, payload); +} + +function getCompatFlags(header) { + const software = header.versions.software; + + let flags = 0; + + for (const rule of COMPAT_CHECKS) { + if (typeof rule[0] === 'string') { + if (software === rule[0]) + flags |= rule[1]; + } else if (rule[0].test(software)) { + flags |= rule[1]; + } + } + + return flags; +} + +function modesToBytes(modes) { + const keys = Object.keys(modes); + const bytes = Buffer.allocUnsafe((5 * keys.length) + 1); + let b = 0; + + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + if (key === 'TTY_OP_END') + continue; + + const opcode = TERMINAL_MODE[key]; + if (opcode === undefined) + continue; + + const val = modes[key]; + if (typeof val === 'number' && isFinite(val)) { + bytes[b++] = opcode; + bytes[b++] = val >>> 24; + bytes[b++] = val >>> 16; + bytes[b++] = val >>> 8; + bytes[b++] = val; + } + } + + bytes[b++] = TERMINAL_MODE.TTY_OP_END; + + if (b < bytes.length) + return bufferSlice(bytes, 0, b); + + return bytes; +} + +function sendExtInfo(proto) { + let serverSigAlgs = + 'ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521' + + 'rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss'; + if (eddsaSupported) + serverSigAlgs = `ssh-ed25519,${serverSigAlgs}`; + const algsLen = Buffer.byteLength(serverSigAlgs); + + let p = proto._packetRW.write.allocStart; + const packet = proto._packetRW.write.alloc(1 + 4 + 4 + 15 + 4 + algsLen); + + packet[p] = MESSAGE.EXT_INFO; + + writeUInt32BE(packet, 1, ++p); + + writeUInt32BE(packet, 15, p += 4); + packet.utf8Write('server-sig-algs', p += 4, 15); + + writeUInt32BE(packet, algsLen, p += 15); + packet.utf8Write(serverSigAlgs, p += 4, algsLen); + + proto._debug && proto._debug('Outbound: Sending EXT_INFO'); + sendPacket(proto, proto._packetRW.write.finalize(packet)); +} + +module.exports = Protocol; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/SFTP.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/SFTP.js new file mode 100644 index 0000000..9f33c02 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/SFTP.js @@ -0,0 +1,4052 @@ +'use strict'; + +const EventEmitter = require('events'); +const fs = require('fs'); +const { constants } = fs; +const { + Readable: ReadableStream, + Writable: WritableStream +} = require('stream'); +const { inherits, types: { isDate } } = require('util'); + +const FastBuffer = Buffer[Symbol.species]; + +const { + bufferCopy, + bufferSlice, + makeBufferParser, + writeUInt32BE, +} = require('./utils.js'); + +const ATTR = { + SIZE: 0x00000001, + UIDGID: 0x00000002, + PERMISSIONS: 0x00000004, + ACMODTIME: 0x00000008, + EXTENDED: 0x80000000, +}; + +// Large enough to store all possible attributes +const ATTRS_BUF = Buffer.alloc(28); + +const STATUS_CODE = { + OK: 0, + EOF: 1, + NO_SUCH_FILE: 2, + PERMISSION_DENIED: 3, + FAILURE: 4, + BAD_MESSAGE: 5, + NO_CONNECTION: 6, + CONNECTION_LOST: 7, + OP_UNSUPPORTED: 8 +}; + +const VALID_STATUS_CODES = new Map( + Object.values(STATUS_CODE).map((n) => [n, 1]) +); + +const STATUS_CODE_STR = { + [STATUS_CODE.OK]: 'No error', + [STATUS_CODE.EOF]: 'End of file', + [STATUS_CODE.NO_SUCH_FILE]: 'No such file or directory', + [STATUS_CODE.PERMISSION_DENIED]: 'Permission denied', + [STATUS_CODE.FAILURE]: 'Failure', + [STATUS_CODE.BAD_MESSAGE]: 'Bad message', + [STATUS_CODE.NO_CONNECTION]: 'No connection', + [STATUS_CODE.CONNECTION_LOST]: 'Connection lost', + [STATUS_CODE.OP_UNSUPPORTED]: 'Operation unsupported', +}; + +const REQUEST = { + INIT: 1, + OPEN: 3, + CLOSE: 4, + READ: 5, + WRITE: 6, + LSTAT: 7, + FSTAT: 8, + SETSTAT: 9, + FSETSTAT: 10, + OPENDIR: 11, + READDIR: 12, + REMOVE: 13, + MKDIR: 14, + RMDIR: 15, + REALPATH: 16, + STAT: 17, + RENAME: 18, + READLINK: 19, + SYMLINK: 20, + EXTENDED: 200 +}; + +const RESPONSE = { + VERSION: 2, + STATUS: 101, + HANDLE: 102, + DATA: 103, + NAME: 104, + ATTRS: 105, + EXTENDED: 201 +}; + +const OPEN_MODE = { + READ: 0x00000001, + WRITE: 0x00000002, + APPEND: 0x00000004, + CREAT: 0x00000008, + TRUNC: 0x00000010, + EXCL: 0x00000020 +}; + +const PKT_RW_OVERHEAD = 2 * 1024; +const MAX_REQID = 2 ** 32 - 1; +const CLIENT_VERSION_BUFFER = Buffer.from([ + 0, 0, 0, 5 /* length */, + REQUEST.INIT, + 0, 0, 0, 3 /* version */ +]); +const SERVER_VERSION_BUFFER = Buffer.from([ + 0, 0, 0, 5 /* length */, + RESPONSE.VERSION, + 0, 0, 0, 3 /* version */ +]); + +const RE_OPENSSH = /^SSH-2.0-(?:OpenSSH|dropbear)/; +const OPENSSH_MAX_PKT_LEN = 256 * 1024; + +const bufferParser = makeBufferParser(); + +const fakeStderr = { + readable: false, + writable: false, + push: (data) => {}, + once: () => {}, + on: () => {}, + emit: () => {}, + end: () => {}, +}; + +function noop() {} + +// Emulates enough of `Channel` to be able to be used as a drop-in replacement +// in order to process incoming data with as little overhead as possible +class SFTP extends EventEmitter { + constructor(client, chanInfo, cfg) { + super(); + + if (typeof cfg !== 'object' || !cfg) + cfg = {}; + + const remoteIdentRaw = client._protocol._remoteIdentRaw; + + this.server = !!cfg.server; + this._debug = (typeof cfg.debug === 'function' ? cfg.debug : undefined); + this._isOpenSSH = (remoteIdentRaw && RE_OPENSSH.test(remoteIdentRaw)); + + this._version = -1; + this._extensions = {}; + this._biOpt = cfg.biOpt; + this._pktLenBytes = 0; + this._pktLen = 0; + this._pktPos = 0; + this._pktType = 0; + this._pktData = undefined; + this._writeReqid = -1; + this._requests = {}; + this._maxInPktLen = OPENSSH_MAX_PKT_LEN; + this._maxOutPktLen = 34000; + this._maxReadLen = + (this._isOpenSSH ? OPENSSH_MAX_PKT_LEN : 34000) - PKT_RW_OVERHEAD; + this._maxWriteLen = + (this._isOpenSSH ? OPENSSH_MAX_PKT_LEN : 34000) - PKT_RW_OVERHEAD; + + this.maxOpenHandles = undefined; + + // Channel compatibility + this._client = client; + this._protocol = client._protocol; + this._callbacks = []; + this._hasX11 = false; + this._exit = { + code: undefined, + signal: undefined, + dump: undefined, + desc: undefined, + }; + this._waitWindow = false; // SSH-level backpressure + this._chunkcb = undefined; + this._buffer = []; + this.type = chanInfo.type; + this.subtype = undefined; + this.incoming = chanInfo.incoming; + this.outgoing = chanInfo.outgoing; + this.stderr = fakeStderr; + this.readable = true; + } + + // This handles incoming data to parse + push(data) { + if (data === null) { + cleanupRequests(this); + if (!this.readable) + return; + // No more incoming data from the remote side + this.readable = false; + this.emit('end'); + return; + } + /* + uint32 length + byte type + byte[length - 1] data payload + */ + let p = 0; + + while (p < data.length) { + if (this._pktLenBytes < 4) { + let nb = Math.min(4 - this._pktLenBytes, data.length - p); + this._pktLenBytes += nb; + + while (nb--) + this._pktLen = (this._pktLen << 8) + data[p++]; + + if (this._pktLenBytes < 4) + return; + if (this._pktLen === 0) + return doFatalSFTPError(this, 'Invalid packet length'); + if (this._pktLen > this._maxInPktLen) { + const max = this._maxInPktLen; + return doFatalSFTPError( + this, + `Packet length ${this._pktLen} exceeds max length of ${max}` + ); + } + if (p >= data.length) + return; + } + if (this._pktPos < this._pktLen) { + const nb = Math.min(this._pktLen - this._pktPos, data.length - p); + if (p !== 0 || nb !== data.length) { + if (nb === this._pktLen) { + this._pkt = new FastBuffer(data.buffer, data.byteOffset + p, nb); + } else { + if (!this._pkt) + this._pkt = Buffer.allocUnsafe(this._pktLen); + this._pkt.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._pktPos + ); + } + } else if (nb === this._pktLen) { + this._pkt = data; + } else { + if (!this._pkt) + this._pkt = Buffer.allocUnsafe(this._pktLen); + this._pkt.set(data, this._pktPos); + } + p += nb; + this._pktPos += nb; + if (this._pktPos < this._pktLen) + return; + } + + const type = this._pkt[0]; + const payload = this._pkt; + + // Prepare for next packet + this._pktLen = 0; + this._pktLenBytes = 0; + this._pkt = undefined; + this._pktPos = 0; + + const handler = (this.server + ? SERVER_HANDLERS[type] + : CLIENT_HANDLERS[type]); + if (!handler) + return doFatalSFTPError(this, `Unknown packet type ${type}`); + + if (this._version === -1) { + if (this.server) { + if (type !== REQUEST.INIT) + return doFatalSFTPError(this, `Expected INIT packet, got ${type}`); + } else if (type !== RESPONSE.VERSION) { + return doFatalSFTPError(this, `Expected VERSION packet, got ${type}`); + } + } + + if (handler(this, payload) === false) + return; + } + } + + end() { + this.destroy(); + } + destroy() { + if (this.outgoing.state === 'open' || this.outgoing.state === 'eof') { + this.outgoing.state = 'closing'; + this._protocol.channelClose(this.outgoing.id); + } + } + _init() { + this._init = noop; + if (!this.server) + sendOrBuffer(this, CLIENT_VERSION_BUFFER); + } + + // =========================================================================== + // Client-specific =========================================================== + // =========================================================================== + createReadStream(path, options) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + return new ReadStream(this, path, options); + } + createWriteStream(path, options) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + return new WriteStream(this, path, options); + } + open(path, flags_, attrs, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (typeof attrs === 'function') { + cb = attrs; + attrs = undefined; + } + + const flags = (typeof flags_ === 'number' ? flags_ : stringToFlags(flags_)); + if (flags === null) + throw new Error(`Unknown flags string: ${flags_}`); + + let attrsFlags = 0; + let attrsLen = 0; + if (typeof attrs === 'string' || typeof attrs === 'number') + attrs = { mode: attrs }; + if (typeof attrs === 'object' && attrs !== null) { + attrs = attrsToBytes(attrs); + attrsFlags = attrs.flags; + attrsLen = attrs.nb; + } + + /* + uint32 id + string filename + uint32 pflags + ATTRS attrs + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + 4 + attrsLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.OPEN; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + writeUInt32BE(buf, flags, p += pathLen); + writeUInt32BE(buf, attrsFlags, p += 4); + if (attrsLen) { + p += 4; + + if (attrsLen === ATTRS_BUF.length) + buf.set(ATTRS_BUF, p); + else + bufferCopy(ATTRS_BUF, buf, 0, attrsLen, p); + + p += attrsLen; + } + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} OPEN` + ); + } + close(handle, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + + /* + uint32 id + string handle + */ + const handleLen = handle.length; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.CLOSE; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, handleLen, p); + buf.set(handle, p += 4); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} CLOSE` + ); + } + read(handle, buf, off, len, position, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + if (!Buffer.isBuffer(buf)) + throw new Error('buffer is not a Buffer'); + if (off >= buf.length) + throw new Error('offset is out of bounds'); + if (off + len > buf.length) + throw new Error('length extends beyond buffer'); + if (position === null) + throw new Error('null position currently unsupported'); + + read_(this, handle, buf, off, len, position, cb); + } + readData(handle, buf, off, len, position, cb) { + // Backwards compatibility + this.read(handle, buf, off, len, position, cb); + } + write(handle, buf, off, len, position, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + if (!Buffer.isBuffer(buf)) + throw new Error('buffer is not a Buffer'); + if (off > buf.length) + throw new Error('offset is out of bounds'); + if (off + len > buf.length) + throw new Error('length extends beyond buffer'); + if (position === null) + throw new Error('null position currently unsupported'); + + if (!len) { + cb && process.nextTick(cb, undefined, 0); + return; + } + + const maxDataLen = this._maxWriteLen; + const overflow = Math.max(len - maxDataLen, 0); + const origPosition = position; + + if (overflow) + len = maxDataLen; + + /* + uint32 id + string handle + uint64 offset + string data + */ + const handleLen = handle.length; + let p = 9; + const out = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen + 8 + 4 + len); + + writeUInt32BE(out, out.length - 4, 0); + out[4] = REQUEST.WRITE; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(out, reqid, 5); + + writeUInt32BE(out, handleLen, p); + out.set(handle, p += 4); + p += handleLen; + for (let i = 7; i >= 0; --i) { + out[p + i] = position & 0xFF; + position /= 256; + } + writeUInt32BE(out, len, p += 8); + bufferCopy(buf, out, off, off + len, p += 4); + + this._requests[reqid] = { + cb: (err) => { + if (err) { + if (typeof cb === 'function') + cb(err); + } else if (overflow) { + this.write(handle, + buf, + off + len, + overflow, + origPosition + len, + cb); + } else if (typeof cb === 'function') { + cb(undefined, off + len); + } + } + }; + + const isSent = sendOrBuffer(this, out); + if (this._debug) { + const how = (isSent ? 'Sent' : 'Buffered'); + this._debug(`SFTP: Outbound: ${how} WRITE (id:${reqid})`); + } + } + writeData(handle, buf, off, len, position, cb) { + // Backwards compatibility + this.write(handle, buf, off, len, position, cb); + } + fastGet(remotePath, localPath, opts, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + fastXfer(this, fs, remotePath, localPath, opts, cb); + } + fastPut(localPath, remotePath, opts, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + fastXfer(fs, this, localPath, remotePath, opts, cb); + } + readFile(path, options, callback_) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + let callback; + if (typeof callback_ === 'function') { + callback = callback_; + } else if (typeof options === 'function') { + callback = options; + options = undefined; + } + + if (typeof options === 'string') + options = { encoding: options, flag: 'r' }; + else if (!options) + options = { encoding: null, flag: 'r' }; + else if (typeof options !== 'object') + throw new TypeError('Bad arguments'); + + const encoding = options.encoding; + if (encoding && !Buffer.isEncoding(encoding)) + throw new Error(`Unknown encoding: ${encoding}`); + + // First stat the file, so we know the size. + let size; + let buffer; // Single buffer with file data + let buffers; // List for when size is unknown + let pos = 0; + let handle; + + // SFTPv3 does not support using -1 for read position, so we have to track + // read position manually + let bytesRead = 0; + + const flag = options.flag || 'r'; + + const read = () => { + if (size === 0) { + buffer = Buffer.allocUnsafe(8192); + this.read(handle, buffer, 0, 8192, bytesRead, afterRead); + } else { + this.read(handle, buffer, pos, size - pos, bytesRead, afterRead); + } + }; + + const afterRead = (er, nbytes) => { + let eof; + if (er) { + eof = (er.code === STATUS_CODE.EOF); + if (!eof) { + return this.close(handle, () => { + return callback && callback(er); + }); + } + } else { + eof = false; + } + + if (eof || (size === 0 && nbytes === 0)) + return close(); + + bytesRead += nbytes; + pos += nbytes; + if (size !== 0) { + if (pos === size) + close(); + else + read(); + } else { + // Unknown size, just read until we don't get bytes. + buffers.push(bufferSlice(buffer, 0, nbytes)); + read(); + } + }; + afterRead._wantEOFError = true; + + const close = () => { + this.close(handle, (er) => { + if (size === 0) { + // Collect the data into the buffers list. + buffer = Buffer.concat(buffers, pos); + } else if (pos < size) { + buffer = bufferSlice(buffer, 0, pos); + } + + if (encoding) + buffer = buffer.toString(encoding); + return callback && callback(er, buffer); + }); + }; + + this.open(path, flag, 0o666, (er, handle_) => { + if (er) + return callback && callback(er); + handle = handle_; + + const tryStat = (er, st) => { + if (er) { + // Try stat() for sftp servers that may not support fstat() for + // whatever reason + this.stat(path, (er_, st_) => { + if (er_) { + return this.close(handle, () => { + callback && callback(er); + }); + } + tryStat(null, st_); + }); + return; + } + + size = st.size || 0; + if (size === 0) { + // The kernel lies about many files. + // Go ahead and try to read some bytes. + buffers = []; + return read(); + } + + buffer = Buffer.allocUnsafe(size); + read(); + }; + this.fstat(handle, tryStat); + }); + } + writeFile(path, data, options, callback_) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + let callback; + if (typeof callback_ === 'function') { + callback = callback_; + } else if (typeof options === 'function') { + callback = options; + options = undefined; + } + + if (typeof options === 'string') + options = { encoding: options, mode: 0o666, flag: 'w' }; + else if (!options) + options = { encoding: 'utf8', mode: 0o666, flag: 'w' }; + else if (typeof options !== 'object') + throw new TypeError('Bad arguments'); + + if (options.encoding && !Buffer.isEncoding(options.encoding)) + throw new Error(`Unknown encoding: ${options.encoding}`); + + const flag = options.flag || 'w'; + this.open(path, flag, options.mode, (openErr, handle) => { + if (openErr) { + callback && callback(openErr); + } else { + const buffer = (Buffer.isBuffer(data) + ? data + : Buffer.from('' + data, options.encoding || 'utf8')); + const position = (/a/.test(flag) ? null : 0); + + // SFTPv3 does not support the notion of 'current position' + // (null position), so we just attempt to append to the end of the file + // instead + if (position === null) { + const tryStat = (er, st) => { + if (er) { + // Try stat() for sftp servers that may not support fstat() for + // whatever reason + this.stat(path, (er_, st_) => { + if (er_) { + return this.close(handle, () => { + callback && callback(er); + }); + } + tryStat(null, st_); + }); + return; + } + writeAll(this, handle, buffer, 0, buffer.length, st.size, callback); + }; + this.fstat(handle, tryStat); + return; + } + writeAll(this, handle, buffer, 0, buffer.length, position, callback); + } + }); + } + appendFile(path, data, options, callback_) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + let callback; + if (typeof callback_ === 'function') { + callback = callback_; + } else if (typeof options === 'function') { + callback = options; + options = undefined; + } + + if (typeof options === 'string') + options = { encoding: options, mode: 0o666, flag: 'a' }; + else if (!options) + options = { encoding: 'utf8', mode: 0o666, flag: 'a' }; + else if (typeof options !== 'object') + throw new TypeError('Bad arguments'); + + if (!options.flag) + options = Object.assign({ flag: 'a' }, options); + this.writeFile(path, data, options, callback); + } + exists(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + this.stat(path, (err) => { + cb && cb(err ? false : true); + }); + } + unlink(filename, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string filename + */ + const fnameLen = Buffer.byteLength(filename); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + fnameLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.REMOVE; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, fnameLen, p); + buf.utf8Write(filename, p += 4, fnameLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} REMOVE` + ); + } + rename(oldPath, newPath, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string oldpath + string newpath + */ + const oldLen = Buffer.byteLength(oldPath); + const newLen = Buffer.byteLength(newPath); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + oldLen + 4 + newLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.RENAME; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, oldLen, p); + buf.utf8Write(oldPath, p += 4, oldLen); + writeUInt32BE(buf, newLen, p += oldLen); + buf.utf8Write(newPath, p += 4, newLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} RENAME` + ); + } + mkdir(path, attrs, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + let flags = 0; + let attrsLen = 0; + + if (typeof attrs === 'function') { + cb = attrs; + attrs = undefined; + } + if (typeof attrs === 'object' && attrs !== null) { + attrs = attrsToBytes(attrs); + flags = attrs.flags; + attrsLen = attrs.nb; + } + + /* + uint32 id + string path + ATTRS attrs + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + attrsLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.MKDIR; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + writeUInt32BE(buf, flags, p += pathLen); + if (attrsLen) { + p += 4; + + if (attrsLen === ATTRS_BUF.length) + buf.set(ATTRS_BUF, p); + else + bufferCopy(ATTRS_BUF, buf, 0, attrsLen, p); + + p += attrsLen; + } + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} MKDIR` + ); + } + rmdir(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.RMDIR; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} RMDIR` + ); + } + readdir(where, opts, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (typeof opts === 'function') { + cb = opts; + opts = {}; + } + if (typeof opts !== 'object' || opts === null) + opts = {}; + + const doFilter = (opts && opts.full ? false : true); + + if (!Buffer.isBuffer(where) && typeof where !== 'string') + throw new Error('missing directory handle or path'); + + if (typeof where === 'string') { + const entries = []; + let e = 0; + + const reread = (err, handle) => { + if (err) + return cb(err); + + this.readdir(handle, opts, (err, list) => { + const eof = (err && err.code === STATUS_CODE.EOF); + + if (err && !eof) + return this.close(handle, () => cb(err)); + + if (eof) { + return this.close(handle, (err) => { + if (err) + return cb(err); + cb(undefined, entries); + }); + } + + for (let i = 0; i < list.length; ++i, ++e) + entries[e] = list[i]; + + reread(undefined, handle); + }); + }; + return this.opendir(where, reread); + } + + /* + uint32 id + string handle + */ + const handleLen = where.length; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.READDIR; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, handleLen, p); + buf.set(where, p += 4); + + this._requests[reqid] = { + cb: (doFilter + ? (err, list) => { + if (typeof cb !== 'function') + return; + if (err) + return cb(err); + + for (let i = list.length - 1; i >= 0; --i) { + if (list[i].filename === '.' || list[i].filename === '..') + list.splice(i, 1); + } + + cb(undefined, list); + } + : cb) + }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} READDIR` + ); + } + fstat(handle, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + + /* + uint32 id + string handle + */ + const handleLen = handle.length; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.FSTAT; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, handleLen, p); + buf.set(handle, p += 4); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} FSTAT` + ); + } + stat(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.STAT; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} STAT` + ); + } + lstat(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.LSTAT; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} LSTAT` + ); + } + opendir(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.OPENDIR; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} OPENDIR` + ); + } + setstat(path, attrs, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + let flags = 0; + let attrsLen = 0; + + if (typeof attrs === 'object' && attrs !== null) { + attrs = attrsToBytes(attrs); + flags = attrs.flags; + attrsLen = attrs.nb; + } else if (typeof attrs === 'function') { + cb = attrs; + } + + /* + uint32 id + string path + ATTRS attrs + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen + 4 + attrsLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.SETSTAT; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + writeUInt32BE(buf, flags, p += pathLen); + if (attrsLen) { + p += 4; + + if (attrsLen === ATTRS_BUF.length) + buf.set(ATTRS_BUF, p); + else + bufferCopy(ATTRS_BUF, buf, 0, attrsLen, p); + + p += attrsLen; + } + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} SETSTAT` + ); + } + fsetstat(handle, attrs, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + + let flags = 0; + let attrsLen = 0; + + if (typeof attrs === 'object' && attrs !== null) { + attrs = attrsToBytes(attrs); + flags = attrs.flags; + attrsLen = attrs.nb; + } else if (typeof attrs === 'function') { + cb = attrs; + } + + /* + uint32 id + string handle + ATTRS attrs + */ + const handleLen = handle.length; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen + 4 + attrsLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.FSETSTAT; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, handleLen, p); + buf.set(handle, p += 4); + writeUInt32BE(buf, flags, p += handleLen); + if (attrsLen) { + p += 4; + + if (attrsLen === ATTRS_BUF.length) + buf.set(ATTRS_BUF, p); + else + bufferCopy(ATTRS_BUF, buf, 0, attrsLen, p); + + p += attrsLen; + } + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} FSETSTAT` + ); + } + futimes(handle, atime, mtime, cb) { + return this.fsetstat(handle, { + atime: toUnixTimestamp(atime), + mtime: toUnixTimestamp(mtime) + }, cb); + } + utimes(path, atime, mtime, cb) { + return this.setstat(path, { + atime: toUnixTimestamp(atime), + mtime: toUnixTimestamp(mtime) + }, cb); + } + fchown(handle, uid, gid, cb) { + return this.fsetstat(handle, { + uid: uid, + gid: gid + }, cb); + } + chown(path, uid, gid, cb) { + return this.setstat(path, { + uid: uid, + gid: gid + }, cb); + } + fchmod(handle, mode, cb) { + return this.fsetstat(handle, { + mode: mode + }, cb); + } + chmod(path, mode, cb) { + return this.setstat(path, { + mode: mode + }, cb); + } + readlink(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.READLINK; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { + cb: (err, names) => { + if (typeof cb !== 'function') + return; + if (err) + return cb(err); + if (!names || !names.length) + return cb(new Error('Response missing link info')); + cb(undefined, names[0].filename); + } + }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} READLINK` + ); + } + symlink(targetPath, linkPath, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string linkpath + string targetpath + */ + const linkLen = Buffer.byteLength(linkPath); + const targetLen = Buffer.byteLength(targetPath); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + linkLen + 4 + targetLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.SYMLINK; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + if (this._isOpenSSH) { + // OpenSSH has linkpath and targetpath positions switched + writeUInt32BE(buf, targetLen, p); + buf.utf8Write(targetPath, p += 4, targetLen); + writeUInt32BE(buf, linkLen, p += targetLen); + buf.utf8Write(linkPath, p += 4, linkLen); + } else { + writeUInt32BE(buf, linkLen, p); + buf.utf8Write(linkPath, p += 4, linkLen); + writeUInt32BE(buf, targetLen, p += linkLen); + buf.utf8Write(targetPath, p += 4, targetLen); + } + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} SYMLINK` + ); + } + realpath(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + /* + uint32 id + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.REALPATH; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, pathLen, p); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { + cb: (err, names) => { + if (typeof cb !== 'function') + return; + if (err) + return cb(err); + if (!names || !names.length) + return cb(new Error('Response missing path info')); + cb(undefined, names[0].filename); + } + }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} REALPATH` + ); + } + // extended requests + ext_openssh_rename(oldPath, newPath, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['posix-rename@openssh.com']; + if (!ext || ext !== '1') + throw new Error('Server does not support this extended request'); + + /* + uint32 id + string "posix-rename@openssh.com" + string oldpath + string newpath + */ + const oldLen = Buffer.byteLength(oldPath); + const newLen = Buffer.byteLength(newPath); + let p = 9; + const buf = + Buffer.allocUnsafe(4 + 1 + 4 + 4 + 24 + 4 + oldLen + 4 + newLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 24, p); + buf.utf8Write('posix-rename@openssh.com', p += 4, 24); + writeUInt32BE(buf, oldLen, p += 24); + buf.utf8Write(oldPath, p += 4, oldLen); + writeUInt32BE(buf, newLen, p += oldLen); + buf.utf8Write(newPath, p += 4, newLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const which = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${which} posix-rename@openssh.com`); + } + } + ext_openssh_statvfs(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['statvfs@openssh.com']; + if (!ext || ext !== '2') + throw new Error('Server does not support this extended request'); + + /* + uint32 id + string "statvfs@openssh.com" + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 19 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 19, p); + buf.utf8Write('statvfs@openssh.com', p += 4, 19); + writeUInt32BE(buf, pathLen, p += 19); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { extended: 'statvfs@openssh.com', cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const which = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${which} statvfs@openssh.com`); + } + } + ext_openssh_fstatvfs(handle, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['fstatvfs@openssh.com']; + if (!ext || ext !== '2') + throw new Error('Server does not support this extended request'); + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + + /* + uint32 id + string "fstatvfs@openssh.com" + string handle + */ + const handleLen = handle.length; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 20 + 4 + handleLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 20, p); + buf.utf8Write('fstatvfs@openssh.com', p += 4, 20); + writeUInt32BE(buf, handleLen, p += 20); + buf.set(handle, p += 4); + + this._requests[reqid] = { extended: 'fstatvfs@openssh.com', cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const which = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${which} fstatvfs@openssh.com`); + } + } + ext_openssh_hardlink(oldPath, newPath, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['hardlink@openssh.com']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + + /* + uint32 id + string "hardlink@openssh.com" + string oldpath + string newpath + */ + const oldLen = Buffer.byteLength(oldPath); + const newLen = Buffer.byteLength(newPath); + let p = 9; + const buf = + Buffer.allocUnsafe(4 + 1 + 4 + 4 + 20 + 4 + oldLen + 4 + newLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 20, p); + buf.utf8Write('hardlink@openssh.com', p += 4, 20); + writeUInt32BE(buf, oldLen, p += 20); + buf.utf8Write(oldPath, p += 4, oldLen); + writeUInt32BE(buf, newLen, p += oldLen); + buf.utf8Write(newPath, p += 4, newLen); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const which = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${which} hardlink@openssh.com`); + } + } + ext_openssh_fsync(handle, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['fsync@openssh.com']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + + /* + uint32 id + string "fsync@openssh.com" + string handle + */ + const handleLen = handle.length; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 17 + 4 + handleLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 17, p); + buf.utf8Write('fsync@openssh.com', p += 4, 17); + writeUInt32BE(buf, handleLen, p += 17); + buf.set(handle, p += 4); + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} fsync@openssh.com` + ); + } + ext_openssh_lsetstat(path, attrs, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['lsetstat@openssh.com']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + + let flags = 0; + let attrsLen = 0; + + if (typeof attrs === 'object' && attrs !== null) { + attrs = attrsToBytes(attrs); + flags = attrs.flags; + attrsLen = attrs.nb; + } else if (typeof attrs === 'function') { + cb = attrs; + } + + /* + uint32 id + string "lsetstat@openssh.com" + string path + ATTRS attrs + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = + Buffer.allocUnsafe(4 + 1 + 4 + 4 + 20 + 4 + pathLen + 4 + attrsLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 20, p); + buf.utf8Write('lsetstat@openssh.com', p += 4, 20); + + writeUInt32BE(buf, pathLen, p += 20); + buf.utf8Write(path, p += 4, pathLen); + + writeUInt32BE(buf, flags, p += pathLen); + if (attrsLen) { + p += 4; + + if (attrsLen === ATTRS_BUF.length) + buf.set(ATTRS_BUF, p); + else + bufferCopy(ATTRS_BUF, buf, 0, attrsLen, p); + + p += attrsLen; + } + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const status = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${status} lsetstat@openssh.com`); + } + } + ext_openssh_expandPath(path, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['expand-path@openssh.com']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + + /* + uint32 id + string "expand-path@openssh.com" + string path + */ + const pathLen = Buffer.byteLength(path); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 23 + 4 + pathLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 23, p); + buf.utf8Write('expand-path@openssh.com', p += 4, 23); + + writeUInt32BE(buf, pathLen, p += 20); + buf.utf8Write(path, p += 4, pathLen); + + this._requests[reqid] = { + cb: (err, names) => { + if (typeof cb !== 'function') + return; + if (err) + return cb(err); + if (!names || !names.length) + return cb(new Error('Response missing expanded path')); + cb(undefined, names[0].filename); + } + }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const status = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${status} expand-path@openssh.com`); + } + } + ext_copy_data(srcHandle, srcOffset, len, dstHandle, dstOffset, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['copy-data']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + + if (!Buffer.isBuffer(srcHandle)) + throw new Error('Source handle is not a Buffer'); + + if (!Buffer.isBuffer(dstHandle)) + throw new Error('Destination handle is not a Buffer'); + + /* + uint32 id + string "copy-data" + string read-from-handle + uint64 read-from-offset + uint64 read-data-length + string write-to-handle + uint64 write-to-offset + */ + let p = 0; + const buf = Buffer.allocUnsafe( + 4 + 1 + + 4 + + 4 + 9 + + 4 + srcHandle.length + + 8 + + 8 + + 4 + dstHandle.length + + 8 + ); + + writeUInt32BE(buf, buf.length - 4, p); + p += 4; + + buf[p] = REQUEST.EXTENDED; + ++p; + + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, p); + p += 4; + + writeUInt32BE(buf, 9, p); + p += 4; + buf.utf8Write('copy-data', p, 9); + p += 9; + + writeUInt32BE(buf, srcHandle.length, p); + p += 4; + buf.set(srcHandle, p); + p += srcHandle.length; + + for (let i = 7; i >= 0; --i) { + buf[p + i] = srcOffset & 0xFF; + srcOffset /= 256; + } + p += 8; + + for (let i = 7; i >= 0; --i) { + buf[p + i] = len & 0xFF; + len /= 256; + } + p += 8; + + writeUInt32BE(buf, dstHandle.length, p); + p += 4; + buf.set(dstHandle, p); + p += dstHandle.length; + + for (let i = 7; i >= 0; --i) { + buf[p + i] = dstOffset & 0xFF; + dstOffset /= 256; + } + + this._requests[reqid] = { cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const status = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${status} copy-data`); + } + } + ext_home_dir(username, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['home-directory']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + + if (typeof username !== 'string') + throw new TypeError('username is not a string'); + + /* + uint32 id + string "home-directory" + string username + */ + let p = 0; + const usernameLen = Buffer.byteLength(username); + const buf = Buffer.allocUnsafe( + 4 + 1 + + 4 + + 4 + 14 + + 4 + usernameLen + ); + + writeUInt32BE(buf, buf.length - 4, p); + p += 4; + + buf[p] = REQUEST.EXTENDED; + ++p; + + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, p); + p += 4; + + writeUInt32BE(buf, 14, p); + p += 4; + buf.utf8Write('home-directory', p, 14); + p += 14; + + writeUInt32BE(buf, usernameLen, p); + p += 4; + buf.utf8Write(username, p, usernameLen); + p += usernameLen; + + this._requests[reqid] = { + cb: (err, names) => { + if (typeof cb !== 'function') + return; + if (err) + return cb(err); + if (!names || !names.length) + return cb(new Error('Response missing home directory')); + cb(undefined, names[0].filename); + } + }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const status = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${status} home-directory`); + } + } + ext_users_groups(uids, gids, cb) { + if (this.server) + throw new Error('Client-only method called in server mode'); + + const ext = this._extensions['users-groups-by-id@openssh.com']; + if (ext !== '1') + throw new Error('Server does not support this extended request'); + + if (!Array.isArray(uids)) + throw new TypeError('uids is not an array'); + for (const val of uids) { + if (!Number.isInteger(val) || val < 0 || val > (2 ** 32 - 1)) + throw new Error('uid values must all be 32-bit unsigned integers'); + } + if (!Array.isArray(gids)) + throw new TypeError('gids is not an array'); + for (const val of gids) { + if (!Number.isInteger(val) || val < 0 || val > (2 ** 32 - 1)) + throw new Error('gid values must all be 32-bit unsigned integers'); + } + + /* + uint32 id + string "users-groups-by-id@openssh.com" + string uids + uint32 uid1 + ... + string gids + uint32 gid1 + ... + */ + let p = 0; + const buf = Buffer.allocUnsafe( + 4 + 1 + + 4 + + 4 + 30 + + 4 + (4 * uids.length) + + 4 + (4 * gids.length) + ); + + writeUInt32BE(buf, buf.length - 4, p); + p += 4; + + buf[p] = REQUEST.EXTENDED; + ++p; + + const reqid = this._writeReqid = (this._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, p); + p += 4; + + writeUInt32BE(buf, 30, p); + p += 4; + buf.utf8Write('users-groups-by-id@openssh.com', p, 30); + p += 30; + + writeUInt32BE(buf, 4 * uids.length, p); + p += 4; + for (const val of uids) { + writeUInt32BE(buf, val, p); + p += 4; + } + + writeUInt32BE(buf, 4 * gids.length, p); + p += 4; + for (const val of gids) { + writeUInt32BE(buf, val, p); + p += 4; + } + + this._requests[reqid] = { extended: 'users-groups-by-id@openssh.com', cb }; + + const isBuffered = sendOrBuffer(this, buf); + if (this._debug) { + const status = (isBuffered ? 'Buffered' : 'Sending'); + this._debug(`SFTP: Outbound: ${status} users-groups-by-id@openssh.com`); + } + } + // =========================================================================== + // Server-specific =========================================================== + // =========================================================================== + handle(reqid, handle) { + if (!this.server) + throw new Error('Server-only method called in client mode'); + + if (!Buffer.isBuffer(handle)) + throw new Error('handle is not a Buffer'); + + const handleLen = handle.length; + + if (handleLen > 256) + throw new Error('handle too large (> 256 bytes)'); + + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = RESPONSE.HANDLE; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, handleLen, p); + if (handleLen) + buf.set(handle, p += 4); + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} HANDLE` + ); + } + status(reqid, code, message) { + if (!this.server) + throw new Error('Server-only method called in client mode'); + + if (!VALID_STATUS_CODES.has(code)) + throw new Error(`Bad status code: ${code}`); + + message || (message = ''); + + const msgLen = Buffer.byteLength(message); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 4 + msgLen + 4); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = RESPONSE.STATUS; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, code, p); + + writeUInt32BE(buf, msgLen, p += 4); + p += 4; + if (msgLen) { + buf.utf8Write(message, p, msgLen); + p += msgLen; + } + + writeUInt32BE(buf, 0, p); // Empty language tag + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} STATUS` + ); + } + data(reqid, data, encoding) { + if (!this.server) + throw new Error('Server-only method called in client mode'); + + const isBuffer = Buffer.isBuffer(data); + + if (!isBuffer && typeof data !== 'string') + throw new Error('data is not a Buffer or string'); + + let isUTF8; + if (!isBuffer && !encoding) { + encoding = undefined; + isUTF8 = true; + } + + const dataLen = ( + isBuffer + ? data.length + : Buffer.byteLength(data, encoding) + ); + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + dataLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = RESPONSE.DATA; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, dataLen, p); + if (dataLen) { + if (isBuffer) + buf.set(data, p += 4); + else if (isUTF8) + buf.utf8Write(data, p += 4, dataLen); + else + buf.write(data, p += 4, dataLen, encoding); + } + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} DATA` + ); + } + name(reqid, names) { + if (!this.server) + throw new Error('Server-only method called in client mode'); + + if (!Array.isArray(names)) { + if (typeof names !== 'object' || names === null) + throw new Error('names is not an object or array'); + names = [ names ]; + } + + const count = names.length; + let namesLen = 0; + let nameAttrs; + const attrs = []; + + for (let i = 0; i < count; ++i) { + const name = names[i]; + const filename = ( + !name || !name.filename || typeof name.filename !== 'string' + ? '' + : name.filename + ); + namesLen += 4 + Buffer.byteLength(filename); + const longname = ( + !name || !name.longname || typeof name.longname !== 'string' + ? '' + : name.longname + ); + namesLen += 4 + Buffer.byteLength(longname); + + if (typeof name.attrs === 'object' && name.attrs !== null) { + nameAttrs = attrsToBytes(name.attrs); + namesLen += 4 + nameAttrs.nb; + + if (nameAttrs.nb) { + let bytes; + + if (nameAttrs.nb === ATTRS_BUF.length) { + bytes = new Uint8Array(ATTRS_BUF); + } else { + bytes = new Uint8Array(nameAttrs.nb); + bufferCopy(ATTRS_BUF, bytes, 0, nameAttrs.nb, 0); + } + + nameAttrs.bytes = bytes; + } + + attrs.push(nameAttrs); + } else { + namesLen += 4; + attrs.push(null); + } + } + + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + namesLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = RESPONSE.NAME; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, count, p); + + p += 4; + + for (let i = 0; i < count; ++i) { + const name = names[i]; + + { + const filename = ( + !name || !name.filename || typeof name.filename !== 'string' + ? '' + : name.filename + ); + const len = Buffer.byteLength(filename); + writeUInt32BE(buf, len, p); + p += 4; + if (len) { + buf.utf8Write(filename, p, len); + p += len; + } + } + + { + const longname = ( + !name || !name.longname || typeof name.longname !== 'string' + ? '' + : name.longname + ); + const len = Buffer.byteLength(longname); + writeUInt32BE(buf, len, p); + p += 4; + if (len) { + buf.utf8Write(longname, p, len); + p += len; + } + } + + const attr = attrs[i]; + if (attr) { + writeUInt32BE(buf, attr.flags, p); + p += 4; + if (attr.flags && attr.bytes) { + buf.set(attr.bytes, p); + p += attr.nb; + } + } else { + writeUInt32BE(buf, 0, p); + p += 4; + } + } + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} NAME` + ); + } + attrs(reqid, attrs) { + if (!this.server) + throw new Error('Server-only method called in client mode'); + + if (typeof attrs !== 'object' || attrs === null) + throw new Error('attrs is not an object'); + + attrs = attrsToBytes(attrs); + const flags = attrs.flags; + const attrsLen = attrs.nb; + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + attrsLen); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = RESPONSE.ATTRS; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, flags, p); + if (attrsLen) { + p += 4; + + if (attrsLen === ATTRS_BUF.length) + buf.set(ATTRS_BUF, p); + else + bufferCopy(ATTRS_BUF, buf, 0, attrsLen, p); + + p += attrsLen; + } + + const isBuffered = sendOrBuffer(this, buf); + this._debug && this._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} ATTRS` + ); + } +} + +function tryCreateBuffer(size) { + try { + return Buffer.allocUnsafe(size); + } catch (ex) { + return ex; + } +} + +function read_(self, handle, buf, off, len, position, cb, req_) { + const maxDataLen = self._maxReadLen; + const overflow = Math.max(len - maxDataLen, 0); + + if (overflow) + len = maxDataLen; + + /* + uint32 id + string handle + uint64 offset + uint32 len + */ + const handleLen = handle.length; + let p = 9; + let pos = position; + const out = Buffer.allocUnsafe(4 + 1 + 4 + 4 + handleLen + 8 + 4); + + writeUInt32BE(out, out.length - 4, 0); + out[4] = REQUEST.READ; + const reqid = self._writeReqid = (self._writeReqid + 1) & MAX_REQID; + writeUInt32BE(out, reqid, 5); + + writeUInt32BE(out, handleLen, p); + out.set(handle, p += 4); + p += handleLen; + for (let i = 7; i >= 0; --i) { + out[p + i] = pos & 0xFF; + pos /= 256; + } + writeUInt32BE(out, len, p += 8); + + if (typeof cb !== 'function') + cb = noop; + + const req = (req_ || { + nb: 0, + position, + off, + origOff: off, + len: undefined, + overflow: undefined, + cb: (err, data, nb) => { + const len = req.len; + const overflow = req.overflow; + + if (err) { + if (cb._wantEOFError || err.code !== STATUS_CODE.EOF) + return cb(err); + } else if (nb > len) { + return cb(new Error('Received more data than requested')); + } else if (nb === len && overflow) { + req.nb += nb; + req.position += nb; + req.off += nb; + read_(self, handle, buf, req.off, overflow, req.position, cb, req); + return; + } + + nb = (nb || 0); + if (req.origOff === 0 && buf.length === req.nb) + data = buf; + else + data = bufferSlice(buf, req.origOff, req.origOff + req.nb + nb); + cb(undefined, req.nb + nb, data, req.position); + }, + buffer: undefined, + }); + + req.len = len; + req.overflow = overflow; + + // TODO: avoid creating multiple buffer slices when we need to re-call read_() + // because of overflow + req.buffer = bufferSlice(buf, off, off + len); + + self._requests[reqid] = req; + + const isBuffered = sendOrBuffer(self, out); + self._debug && self._debug( + `SFTP: Outbound: ${isBuffered ? 'Buffered' : 'Sending'} READ` + ); +} + +function fastXfer(src, dst, srcPath, dstPath, opts, cb) { + let concurrency = 64; + let chunkSize = 32768; + let onstep; + let mode; + let fileSize; + + if (typeof opts === 'function') { + cb = opts; + } else if (typeof opts === 'object' && opts !== null) { + if (typeof opts.concurrency === 'number' + && opts.concurrency > 0 + && !isNaN(opts.concurrency)) { + concurrency = opts.concurrency; + } + if (typeof opts.chunkSize === 'number' + && opts.chunkSize > 0 + && !isNaN(opts.chunkSize)) { + chunkSize = opts.chunkSize; + } + if (typeof opts.fileSize === 'number' + && opts.fileSize > 0 + && !isNaN(opts.fileSize)) { + fileSize = opts.fileSize; + } + if (typeof opts.step === 'function') + onstep = opts.step; + + if (typeof opts.mode === 'string' || typeof opts.mode === 'number') + mode = modeNum(opts.mode); + } + + // Internal state variables + let fsize; + let pdst = 0; + let total = 0; + let hadError = false; + let srcHandle; + let dstHandle; + let readbuf; + let bufsize = chunkSize * concurrency; + + function onerror(err) { + if (hadError) + return; + + hadError = true; + + let left = 0; + let cbfinal; + + if (srcHandle || dstHandle) { + cbfinal = () => { + if (--left === 0) + cb(err); + }; + if (srcHandle && (src === fs || src.outgoing.state === 'open')) + ++left; + if (dstHandle && (dst === fs || dst.outgoing.state === 'open')) + ++left; + if (srcHandle && (src === fs || src.outgoing.state === 'open')) + src.close(srcHandle, cbfinal); + if (dstHandle && (dst === fs || dst.outgoing.state === 'open')) + dst.close(dstHandle, cbfinal); + } else { + cb(err); + } + } + + src.open(srcPath, 'r', (err, sourceHandle) => { + if (err) + return onerror(err); + + srcHandle = sourceHandle; + + if (fileSize === undefined) + src.fstat(srcHandle, tryStat); + else + tryStat(null, { size: fileSize }); + + function tryStat(err, attrs) { + if (err) { + if (src !== fs) { + // Try stat() for sftp servers that may not support fstat() for + // whatever reason + src.stat(srcPath, (err_, attrs_) => { + if (err_) + return onerror(err); + tryStat(null, attrs_); + }); + return; + } + return onerror(err); + } + fsize = attrs.size; + + dst.open(dstPath, 'w', (err, destHandle) => { + if (err) + return onerror(err); + + dstHandle = destHandle; + + if (fsize <= 0) + return onerror(); + + // Use less memory where possible + while (bufsize > fsize) { + if (concurrency === 1) { + bufsize = fsize; + break; + } + bufsize -= chunkSize; + --concurrency; + } + + readbuf = tryCreateBuffer(bufsize); + if (readbuf instanceof Error) + return onerror(readbuf); + + if (mode !== undefined) { + dst.fchmod(dstHandle, mode, function tryAgain(err) { + if (err) { + // Try chmod() for sftp servers that may not support fchmod() + // for whatever reason + dst.chmod(dstPath, mode, (err_) => tryAgain()); + return; + } + startReads(); + }); + } else { + startReads(); + } + + function onread(err, nb, data, dstpos, datapos, origChunkLen) { + if (err) + return onerror(err); + + datapos = datapos || 0; + + dst.write(dstHandle, readbuf, datapos, nb, dstpos, writeCb); + + function writeCb(err) { + if (err) + return onerror(err); + + total += nb; + onstep && onstep(total, nb, fsize); + + if (nb < origChunkLen) + return singleRead(datapos, dstpos + nb, origChunkLen - nb); + + if (total === fsize) { + dst.close(dstHandle, (err) => { + dstHandle = undefined; + if (err) + return onerror(err); + src.close(srcHandle, (err) => { + srcHandle = undefined; + if (err) + return onerror(err); + cb(); + }); + }); + return; + } + + if (pdst >= fsize) + return; + + const chunk = + (pdst + chunkSize > fsize ? fsize - pdst : chunkSize); + singleRead(datapos, pdst, chunk); + pdst += chunk; + } + } + + function makeCb(psrc, pdst, chunk) { + return (err, nb, data) => { + onread(err, nb, data, pdst, psrc, chunk); + }; + } + + function singleRead(psrc, pdst, chunk) { + src.read(srcHandle, + readbuf, + psrc, + chunk, + pdst, + makeCb(psrc, pdst, chunk)); + } + + function startReads() { + let reads = 0; + let psrc = 0; + while (pdst < fsize && reads < concurrency) { + const chunk = + (pdst + chunkSize > fsize ? fsize - pdst : chunkSize); + singleRead(psrc, pdst, chunk); + psrc += chunk; + pdst += chunk; + ++reads; + } + } + }); + } + }); +} + +function writeAll(sftp, handle, buffer, offset, length, position, callback_) { + const callback = (typeof callback_ === 'function' ? callback_ : undefined); + + sftp.write(handle, + buffer, + offset, + length, + position, + (writeErr, written) => { + if (writeErr) { + return sftp.close(handle, () => { + callback && callback(writeErr); + }); + } + if (written === length) { + sftp.close(handle, callback); + } else { + offset += written; + length -= written; + position += written; + writeAll(sftp, handle, buffer, offset, length, position, callback); + } + }); +} + +class Stats { + constructor(initial) { + this.mode = (initial && initial.mode); + this.uid = (initial && initial.uid); + this.gid = (initial && initial.gid); + this.size = (initial && initial.size); + this.atime = (initial && initial.atime); + this.mtime = (initial && initial.mtime); + this.extended = (initial && initial.extended); + } + isDirectory() { + return ((this.mode & constants.S_IFMT) === constants.S_IFDIR); + } + isFile() { + return ((this.mode & constants.S_IFMT) === constants.S_IFREG); + } + isBlockDevice() { + return ((this.mode & constants.S_IFMT) === constants.S_IFBLK); + } + isCharacterDevice() { + return ((this.mode & constants.S_IFMT) === constants.S_IFCHR); + } + isSymbolicLink() { + return ((this.mode & constants.S_IFMT) === constants.S_IFLNK); + } + isFIFO() { + return ((this.mode & constants.S_IFMT) === constants.S_IFIFO); + } + isSocket() { + return ((this.mode & constants.S_IFMT) === constants.S_IFSOCK); + } +} + +function attrsToBytes(attrs) { + let flags = 0; + let nb = 0; + + if (typeof attrs === 'object' && attrs !== null) { + if (typeof attrs.size === 'number') { + flags |= ATTR.SIZE; + const val = attrs.size; + // Big Endian + ATTRS_BUF[nb++] = val / 72057594037927940; // 2**56 + ATTRS_BUF[nb++] = val / 281474976710656; // 2**48 + ATTRS_BUF[nb++] = val / 1099511627776; // 2**40 + ATTRS_BUF[nb++] = val / 4294967296; // 2**32 + ATTRS_BUF[nb++] = val / 16777216; // 2**24 + ATTRS_BUF[nb++] = val / 65536; // 2**16 + ATTRS_BUF[nb++] = val / 256; // 2**8 + ATTRS_BUF[nb++] = val; + } + if (typeof attrs.uid === 'number' && typeof attrs.gid === 'number') { + flags |= ATTR.UIDGID; + const uid = attrs.uid; + const gid = attrs.gid; + // Big Endian + ATTRS_BUF[nb++] = uid >>> 24; + ATTRS_BUF[nb++] = uid >>> 16; + ATTRS_BUF[nb++] = uid >>> 8; + ATTRS_BUF[nb++] = uid; + ATTRS_BUF[nb++] = gid >>> 24; + ATTRS_BUF[nb++] = gid >>> 16; + ATTRS_BUF[nb++] = gid >>> 8; + ATTRS_BUF[nb++] = gid; + } + if (typeof attrs.mode === 'number' || typeof attrs.mode === 'string') { + const mode = modeNum(attrs.mode); + flags |= ATTR.PERMISSIONS; + // Big Endian + ATTRS_BUF[nb++] = mode >>> 24; + ATTRS_BUF[nb++] = mode >>> 16; + ATTRS_BUF[nb++] = mode >>> 8; + ATTRS_BUF[nb++] = mode; + } + if ((typeof attrs.atime === 'number' || isDate(attrs.atime)) + && (typeof attrs.mtime === 'number' || isDate(attrs.mtime))) { + const atime = toUnixTimestamp(attrs.atime); + const mtime = toUnixTimestamp(attrs.mtime); + + flags |= ATTR.ACMODTIME; + // Big Endian + ATTRS_BUF[nb++] = atime >>> 24; + ATTRS_BUF[nb++] = atime >>> 16; + ATTRS_BUF[nb++] = atime >>> 8; + ATTRS_BUF[nb++] = atime; + ATTRS_BUF[nb++] = mtime >>> 24; + ATTRS_BUF[nb++] = mtime >>> 16; + ATTRS_BUF[nb++] = mtime >>> 8; + ATTRS_BUF[nb++] = mtime; + } + // TODO: extended attributes + } + + return { flags, nb }; +} + +function toUnixTimestamp(time) { + // eslint-disable-next-line no-self-compare + if (typeof time === 'number' && time === time) // Valid, non-NaN number + return time; + if (isDate(time)) + return parseInt(time.getTime() / 1000, 10); + throw new Error(`Cannot parse time: ${time}`); +} + +function modeNum(mode) { + // eslint-disable-next-line no-self-compare + if (typeof mode === 'number' && mode === mode) // Valid, non-NaN number + return mode; + if (typeof mode === 'string') + return modeNum(parseInt(mode, 8)); + throw new Error(`Cannot parse mode: ${mode}`); +} + +const stringFlagMap = { + 'r': OPEN_MODE.READ, + 'r+': OPEN_MODE.READ | OPEN_MODE.WRITE, + 'w': OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.WRITE, + 'wx': OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.WRITE | OPEN_MODE.EXCL, + 'xw': OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.WRITE | OPEN_MODE.EXCL, + 'w+': OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.READ | OPEN_MODE.WRITE, + 'wx+': OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.READ | OPEN_MODE.WRITE + | OPEN_MODE.EXCL, + 'xw+': OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.READ | OPEN_MODE.WRITE + | OPEN_MODE.EXCL, + 'a': OPEN_MODE.APPEND | OPEN_MODE.CREAT | OPEN_MODE.WRITE, + 'ax': OPEN_MODE.APPEND | OPEN_MODE.CREAT | OPEN_MODE.WRITE | OPEN_MODE.EXCL, + 'xa': OPEN_MODE.APPEND | OPEN_MODE.CREAT | OPEN_MODE.WRITE | OPEN_MODE.EXCL, + 'a+': OPEN_MODE.APPEND | OPEN_MODE.CREAT | OPEN_MODE.READ | OPEN_MODE.WRITE, + 'ax+': OPEN_MODE.APPEND | OPEN_MODE.CREAT | OPEN_MODE.READ | OPEN_MODE.WRITE + | OPEN_MODE.EXCL, + 'xa+': OPEN_MODE.APPEND | OPEN_MODE.CREAT | OPEN_MODE.READ | OPEN_MODE.WRITE + | OPEN_MODE.EXCL +}; + +function stringToFlags(str) { + const flags = stringFlagMap[str]; + return (flags !== undefined ? flags : null); +} + +const flagsToString = (() => { + const stringFlagMapKeys = Object.keys(stringFlagMap); + return (flags) => { + for (let i = 0; i < stringFlagMapKeys.length; ++i) { + const key = stringFlagMapKeys[i]; + if (stringFlagMap[key] === flags) + return key; + } + return null; + }; +})(); + +function readAttrs(biOpt) { + /* + uint32 flags + uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE + uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS + uint32 atime present only if flag SSH_FILEXFER_ACMODTIME + uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME + uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + */ + const flags = bufferParser.readUInt32BE(); + if (flags === undefined) + return; + + const attrs = new Stats(); + if (flags & ATTR.SIZE) { + const size = bufferParser.readUInt64BE(biOpt); + if (size === undefined) + return; + attrs.size = size; + } + + if (flags & ATTR.UIDGID) { + const uid = bufferParser.readUInt32BE(); + const gid = bufferParser.readUInt32BE(); + if (gid === undefined) + return; + attrs.uid = uid; + attrs.gid = gid; + } + + if (flags & ATTR.PERMISSIONS) { + const mode = bufferParser.readUInt32BE(); + if (mode === undefined) + return; + attrs.mode = mode; + } + + if (flags & ATTR.ACMODTIME) { + const atime = bufferParser.readUInt32BE(); + const mtime = bufferParser.readUInt32BE(); + if (mtime === undefined) + return; + attrs.atime = atime; + attrs.mtime = mtime; + } + + if (flags & ATTR.EXTENDED) { + const count = bufferParser.readUInt32BE(); + if (count === undefined) + return; + const extended = {}; + for (let i = 0; i < count; ++i) { + const type = bufferParser.readString(true); + const data = bufferParser.readString(); + if (data === undefined) + return; + extended[type] = data; + } + attrs.extended = extended; + } + + return attrs; +} + +function sendOrBuffer(sftp, payload) { + const ret = tryWritePayload(sftp, payload); + if (ret !== undefined) { + sftp._buffer.push(ret); + return false; + } + return true; +} + +function tryWritePayload(sftp, payload) { + const outgoing = sftp.outgoing; + if (outgoing.state !== 'open') + return; + + if (outgoing.window === 0) { + sftp._waitWindow = true; + sftp._chunkcb = drainBuffer; + return payload; + } + + let ret; + const len = payload.length; + let p = 0; + + while (len - p > 0 && outgoing.window > 0) { + const actualLen = Math.min(len - p, outgoing.window, outgoing.packetSize); + outgoing.window -= actualLen; + if (outgoing.window === 0) { + sftp._waitWindow = true; + sftp._chunkcb = drainBuffer; + } + + if (p === 0 && actualLen === len) { + sftp._protocol.channelData(sftp.outgoing.id, payload); + } else { + sftp._protocol.channelData(sftp.outgoing.id, + bufferSlice(payload, p, p + actualLen)); + } + + p += actualLen; + } + + if (len - p > 0) { + if (p > 0) + ret = bufferSlice(payload, p, len); + else + ret = payload; // XXX: should never get here? + } + + return ret; +} + +function drainBuffer() { + this._chunkcb = undefined; + const buffer = this._buffer; + let i = 0; + while (i < buffer.length) { + const payload = buffer[i]; + const ret = tryWritePayload(this, payload); + if (ret !== undefined) { + if (ret !== payload) + buffer[i] = ret; + if (i > 0) + this._buffer = buffer.slice(i); + return; + } + ++i; + } + if (i > 0) + this._buffer = []; +} + +function doFatalSFTPError(sftp, msg, noDebug) { + const err = new Error(msg); + err.level = 'sftp-protocol'; + if (!noDebug && sftp._debug) + sftp._debug(`SFTP: Inbound: ${msg}`); + sftp.emit('error', err); + sftp.destroy(); + cleanupRequests(sftp); + return false; +} + +function cleanupRequests(sftp) { + const keys = Object.keys(sftp._requests); + if (keys.length === 0) + return; + + const reqs = sftp._requests; + sftp._requests = {}; + const err = new Error('No response from server'); + for (let i = 0; i < keys.length; ++i) { + const req = reqs[keys[i]]; + if (typeof req.cb === 'function') + req.cb(err); + } +} + +function requestLimits(sftp, cb) { + /* + uint32 id + string "limits@openssh.com" + */ + let p = 9; + const buf = Buffer.allocUnsafe(4 + 1 + 4 + 4 + 18); + + writeUInt32BE(buf, buf.length - 4, 0); + buf[4] = REQUEST.EXTENDED; + const reqid = sftp._writeReqid = (sftp._writeReqid + 1) & MAX_REQID; + writeUInt32BE(buf, reqid, 5); + + writeUInt32BE(buf, 18, p); + buf.utf8Write('limits@openssh.com', p += 4, 18); + + sftp._requests[reqid] = { extended: 'limits@openssh.com', cb }; + + const isBuffered = sendOrBuffer(sftp, buf); + if (sftp._debug) { + const which = (isBuffered ? 'Buffered' : 'Sending'); + sftp._debug(`SFTP: Outbound: ${which} limits@openssh.com`); + } +} + +const CLIENT_HANDLERS = { + [RESPONSE.VERSION]: (sftp, payload) => { + if (sftp._version !== -1) + return doFatalSFTPError(sftp, 'Duplicate VERSION packet'); + + const extensions = {}; + + /* + uint32 version + + */ + bufferParser.init(payload, 1); + let version = bufferParser.readUInt32BE(); + while (bufferParser.avail()) { + const extName = bufferParser.readString(true); + const extData = bufferParser.readString(true); + if (extData === undefined) { + version = undefined; + break; + } + extensions[extName] = extData; + } + bufferParser.clear(); + + if (version === undefined) + return doFatalSFTPError(sftp, 'Malformed VERSION packet'); + + if (sftp._debug) { + const names = Object.keys(extensions); + if (names.length) { + sftp._debug( + `SFTP: Inbound: Received VERSION (v${version}, exts:${names})` + ); + } else { + sftp._debug(`SFTP: Inbound: Received VERSION (v${version})`); + } + } + + sftp._version = version; + sftp._extensions = extensions; + + if (extensions['limits@openssh.com'] === '1') { + return requestLimits(sftp, (err, limits) => { + if (!err) { + if (limits.maxPktLen > 0) + sftp._maxOutPktLen = limits.maxPktLen; + if (limits.maxReadLen > 0) + sftp._maxReadLen = limits.maxReadLen; + if (limits.maxWriteLen > 0) + sftp._maxWriteLen = limits.maxWriteLen; + sftp.maxOpenHandles = ( + limits.maxOpenHandles > 0 ? limits.maxOpenHandles : Infinity + ); + } + sftp.emit('ready'); + }); + } + + sftp.emit('ready'); + }, + [RESPONSE.STATUS]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + uint32 error/status code + string error message (ISO-10646 UTF-8) + string language tag + */ + const errorCode = bufferParser.readUInt32BE(); + const errorMsg = bufferParser.readString(true); + bufferParser.clear(); + + // Note: we avoid checking that the error message and language tag are in + // the packet because there are some broken implementations that incorrectly + // omit them. The language tag in general was never really used amongst ssh + // implementations, so in the case of a missing error message we just + // default to something sensible. + + if (sftp._debug) { + const jsonMsg = JSON.stringify(errorMsg); + sftp._debug( + `SFTP: Inbound: Received STATUS (id:${reqID}, ${errorCode}, ${jsonMsg})` + ); + } + const req = sftp._requests[reqID]; + delete sftp._requests[reqID]; + if (req && typeof req.cb === 'function') { + if (errorCode === STATUS_CODE.OK) { + req.cb(); + return; + } + const err = new Error(errorMsg + || STATUS_CODE_STR[errorCode] + || 'Unknown status'); + err.code = errorCode; + req.cb(err); + } + }, + [RESPONSE.HANDLE]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + */ + const handle = bufferParser.readString(); + bufferParser.clear(); + + if (handle === undefined) { + if (reqID !== undefined) + delete sftp._requests[reqID]; + return doFatalSFTPError(sftp, 'Malformed HANDLE packet'); + } + + sftp._debug && sftp._debug(`SFTP: Inbound: Received HANDLE (id:${reqID})`); + + const req = sftp._requests[reqID]; + delete sftp._requests[reqID]; + if (req && typeof req.cb === 'function') + req.cb(undefined, handle); + }, + [RESPONSE.DATA]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + let req; + if (reqID !== undefined) { + req = sftp._requests[reqID]; + delete sftp._requests[reqID]; + } + /* + string data + */ + if (req && typeof req.cb === 'function') { + if (req.buffer) { + // We have already pre-allocated space to store the data + + const nb = bufferParser.readString(req.buffer); + bufferParser.clear(); + + if (nb !== undefined) { + sftp._debug && sftp._debug( + `SFTP: Inbound: Received DATA (id:${reqID}, ${nb})` + ); + req.cb(undefined, req.buffer, nb); + return; + } + } else { + const data = bufferParser.readString(); + bufferParser.clear(); + + if (data !== undefined) { + sftp._debug && sftp._debug( + `SFTP: Inbound: Received DATA (id:${reqID}, ${data.length})` + ); + req.cb(undefined, data); + return; + } + } + } else { + const nb = bufferParser.skipString(); + bufferParser.clear(); + if (nb !== undefined) { + sftp._debug && sftp._debug( + `SFTP: Inbound: Received DATA (id:${reqID}, ${nb})` + ); + return; + } + } + + return doFatalSFTPError(sftp, 'Malformed DATA packet'); + }, + [RESPONSE.NAME]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + let req; + if (reqID !== undefined) { + req = sftp._requests[reqID]; + delete sftp._requests[reqID]; + } + /* + uint32 count + repeats count times: + string filename + string longname + ATTRS attrs + */ + const count = bufferParser.readUInt32BE(); + if (count !== undefined) { + let names = []; + for (let i = 0; i < count; ++i) { + // We are going to assume UTF-8 for filenames despite the SFTPv3 + // spec not specifying an encoding because the specs for newer + // versions of the protocol all explicitly specify UTF-8 for + // filenames + const filename = bufferParser.readString(true); + + // `longname` only exists in SFTPv3 and since it typically will + // contain the filename, we assume it is also UTF-8 + const longname = bufferParser.readString(true); + + const attrs = readAttrs(sftp._biOpt); + if (attrs === undefined) { + names = undefined; + break; + } + names.push({ filename, longname, attrs }); + } + if (names !== undefined) { + sftp._debug && sftp._debug( + `SFTP: Inbound: Received NAME (id:${reqID}, ${names.length})` + ); + bufferParser.clear(); + if (req && typeof req.cb === 'function') + req.cb(undefined, names); + return; + } + } + + bufferParser.clear(); + return doFatalSFTPError(sftp, 'Malformed NAME packet'); + }, + [RESPONSE.ATTRS]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + let req; + if (reqID !== undefined) { + req = sftp._requests[reqID]; + delete sftp._requests[reqID]; + } + /* + ATTRS attrs + */ + const attrs = readAttrs(sftp._biOpt); + bufferParser.clear(); + if (attrs !== undefined) { + sftp._debug && sftp._debug(`SFTP: Inbound: Received ATTRS (id:${reqID})`); + if (req && typeof req.cb === 'function') + req.cb(undefined, attrs); + return; + } + + return doFatalSFTPError(sftp, 'Malformed ATTRS packet'); + }, + [RESPONSE.EXTENDED]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + if (reqID !== undefined) { + const req = sftp._requests[reqID]; + if (req) { + delete sftp._requests[reqID]; + switch (req.extended) { + case 'statvfs@openssh.com': + case 'fstatvfs@openssh.com': { + /* + uint64 f_bsize // file system block size + uint64 f_frsize // fundamental fs block size + uint64 f_blocks // number of blocks (unit f_frsize) + uint64 f_bfree // free blocks in file system + uint64 f_bavail // free blocks for non-root + uint64 f_files // total file inodes + uint64 f_ffree // free file inodes + uint64 f_favail // free file inodes for to non-root + uint64 f_fsid // file system id + uint64 f_flag // bit mask of f_flag values + uint64 f_namemax // maximum filename length + */ + const biOpt = sftp._biOpt; + const stats = { + f_bsize: bufferParser.readUInt64BE(biOpt), + f_frsize: bufferParser.readUInt64BE(biOpt), + f_blocks: bufferParser.readUInt64BE(biOpt), + f_bfree: bufferParser.readUInt64BE(biOpt), + f_bavail: bufferParser.readUInt64BE(biOpt), + f_files: bufferParser.readUInt64BE(biOpt), + f_ffree: bufferParser.readUInt64BE(biOpt), + f_favail: bufferParser.readUInt64BE(biOpt), + f_sid: bufferParser.readUInt64BE(biOpt), + f_flag: bufferParser.readUInt64BE(biOpt), + f_namemax: bufferParser.readUInt64BE(biOpt), + }; + if (stats.f_namemax === undefined) + break; + if (sftp._debug) { + sftp._debug( + 'SFTP: Inbound: Received EXTENDED_REPLY ' + + `(id:${reqID}, ${req.extended})` + ); + } + bufferParser.clear(); + if (typeof req.cb === 'function') + req.cb(undefined, stats); + return; + } + case 'limits@openssh.com': { + /* + uint64 max-packet-length + uint64 max-read-length + uint64 max-write-length + uint64 max-open-handles + */ + const limits = { + maxPktLen: bufferParser.readUInt64BE(), + maxReadLen: bufferParser.readUInt64BE(), + maxWriteLen: bufferParser.readUInt64BE(), + maxOpenHandles: bufferParser.readUInt64BE(), + }; + if (limits.maxOpenHandles === undefined) + break; + if (sftp._debug) { + sftp._debug( + 'SFTP: Inbound: Received EXTENDED_REPLY ' + + `(id:${reqID}, ${req.extended})` + ); + } + bufferParser.clear(); + if (typeof req.cb === 'function') + req.cb(undefined, limits); + return; + } + case 'users-groups-by-id@openssh.com': { + /* + string usernames + string username1 + ... + string groupnames + string groupname1 + ... + */ + const usernameCount = bufferParser.readUInt32BE(); + if (usernameCount === undefined) + break; + const usernames = new Array(usernameCount); + for (let i = 0; i < usernames.length; ++i) + usernames[i] = bufferParser.readString(true); + + const groupnameCount = bufferParser.readUInt32BE(); + if (groupnameCount === undefined) + break; + const groupnames = new Array(groupnameCount); + for (let i = 0; i < groupnames.length; ++i) + groupnames[i] = bufferParser.readString(true); + if (groupnames.length > 0 + && groupnames[groupnames.length - 1] === undefined) { + break; + } + + if (sftp._debug) { + sftp._debug( + 'SFTP: Inbound: Received EXTENDED_REPLY ' + + `(id:${reqID}, ${req.extended})` + ); + } + bufferParser.clear(); + if (typeof req.cb === 'function') + req.cb(undefined, usernames, groupnames); + return; + } + default: + // Unknown extended request + sftp._debug && sftp._debug( + `SFTP: Inbound: Received EXTENDED_REPLY (id:${reqID}, ???)` + ); + bufferParser.clear(); + if (typeof req.cb === 'function') + req.cb(); + return; + } + } else { + sftp._debug && sftp._debug( + `SFTP: Inbound: Received EXTENDED_REPLY (id:${reqID}, ???)` + ); + bufferParser.clear(); + return; + } + } + + bufferParser.clear(); + return doFatalSFTPError(sftp, 'Malformed EXTENDED_REPLY packet'); + }, +}; +const SERVER_HANDLERS = { + [REQUEST.INIT]: (sftp, payload) => { + if (sftp._version !== -1) + return doFatalSFTPError(sftp, 'Duplicate INIT packet'); + + const extensions = {}; + + /* + uint32 version + + */ + bufferParser.init(payload, 1); + let version = bufferParser.readUInt32BE(); + while (bufferParser.avail()) { + const extName = bufferParser.readString(true); + const extData = bufferParser.readString(true); + if (extData === undefined) { + version = undefined; + break; + } + extensions[extName] = extData; + } + bufferParser.clear(); + + if (version === undefined) + return doFatalSFTPError(sftp, 'Malformed INIT packet'); + + if (sftp._debug) { + const names = Object.keys(extensions); + if (names.length) { + sftp._debug( + `SFTP: Inbound: Received INIT (v${version}, exts:${names})` + ); + } else { + sftp._debug(`SFTP: Inbound: Received INIT (v${version})`); + } + } + + sendOrBuffer(sftp, SERVER_VERSION_BUFFER); + + sftp._version = version; + sftp._extensions = extensions; + sftp.emit('ready'); + }, + [REQUEST.OPEN]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string filename + uint32 pflags + ATTRS attrs + */ + const filename = bufferParser.readString(true); + const pflags = bufferParser.readUInt32BE(); + const attrs = readAttrs(sftp._biOpt); + bufferParser.clear(); + + if (attrs === undefined) + return doFatalSFTPError(sftp, 'Malformed OPEN packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received OPEN (id:${reqID})`); + + if (!sftp.emit('OPEN', reqID, filename, pflags, attrs)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.CLOSE]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + */ + const handle = bufferParser.readString(); + bufferParser.clear(); + + if (handle === undefined || handle.length > 256) + return doFatalSFTPError(sftp, 'Malformed CLOSE packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received CLOSE (id:${reqID})`); + + if (!sftp.emit('CLOSE', reqID, handle)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.READ]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + uint64 offset + uint32 len + */ + const handle = bufferParser.readString(); + const offset = bufferParser.readUInt64BE(sftp._biOpt); + const len = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (len === undefined || handle.length > 256) + return doFatalSFTPError(sftp, 'Malformed READ packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received READ (id:${reqID})`); + + if (!sftp.emit('READ', reqID, handle, offset, len)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.WRITE]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + uint64 offset + string data + */ + const handle = bufferParser.readString(); + const offset = bufferParser.readUInt64BE(sftp._biOpt); + const data = bufferParser.readString(); + bufferParser.clear(); + + if (data === undefined || handle.length > 256) + return doFatalSFTPError(sftp, 'Malformed WRITE packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received WRITE (id:${reqID})`); + + if (!sftp.emit('WRITE', reqID, handle, offset, data)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.LSTAT]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed LSTAT packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received LSTAT (id:${reqID})`); + + if (!sftp.emit('LSTAT', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.FSTAT]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + */ + const handle = bufferParser.readString(); + bufferParser.clear(); + + if (handle === undefined || handle.length > 256) + return doFatalSFTPError(sftp, 'Malformed FSTAT packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received FSTAT (id:${reqID})`); + + if (!sftp.emit('FSTAT', reqID, handle)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.SETSTAT]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + ATTRS attrs + */ + const path = bufferParser.readString(true); + const attrs = readAttrs(sftp._biOpt); + bufferParser.clear(); + + if (attrs === undefined) + return doFatalSFTPError(sftp, 'Malformed SETSTAT packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received SETSTAT (id:${reqID})`); + + if (!sftp.emit('SETSTAT', reqID, path, attrs)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.FSETSTAT]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + ATTRS attrs + */ + const handle = bufferParser.readString(); + const attrs = readAttrs(sftp._biOpt); + bufferParser.clear(); + + if (attrs === undefined || handle.length > 256) + return doFatalSFTPError(sftp, 'Malformed FSETSTAT packet'); + + sftp._debug && sftp._debug( + `SFTP: Inbound: Received FSETSTAT (id:${reqID})` + ); + + if (!sftp.emit('FSETSTAT', reqID, handle, attrs)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.OPENDIR]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed OPENDIR packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received OPENDIR (id:${reqID})`); + + if (!sftp.emit('OPENDIR', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.READDIR]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string handle + */ + const handle = bufferParser.readString(); + bufferParser.clear(); + + if (handle === undefined || handle.length > 256) + return doFatalSFTPError(sftp, 'Malformed READDIR packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received READDIR (id:${reqID})`); + + if (!sftp.emit('READDIR', reqID, handle)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.REMOVE]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed REMOVE packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received REMOVE (id:${reqID})`); + + if (!sftp.emit('REMOVE', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.MKDIR]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + ATTRS attrs + */ + const path = bufferParser.readString(true); + const attrs = readAttrs(sftp._biOpt); + bufferParser.clear(); + + if (attrs === undefined) + return doFatalSFTPError(sftp, 'Malformed MKDIR packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received MKDIR (id:${reqID})`); + + if (!sftp.emit('MKDIR', reqID, path, attrs)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.RMDIR]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed RMDIR packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received RMDIR (id:${reqID})`); + + if (!sftp.emit('RMDIR', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.REALPATH]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed REALPATH packet'); + + sftp._debug && sftp._debug( + `SFTP: Inbound: Received REALPATH (id:${reqID})` + ); + + if (!sftp.emit('REALPATH', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.STAT]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed STAT packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received STAT (id:${reqID})`); + + if (!sftp.emit('STAT', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.RENAME]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string oldpath + string newpath + */ + const oldPath = bufferParser.readString(true); + const newPath = bufferParser.readString(true); + bufferParser.clear(); + + if (newPath === undefined) + return doFatalSFTPError(sftp, 'Malformed RENAME packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received RENAME (id:${reqID})`); + + if (!sftp.emit('RENAME', reqID, oldPath, newPath)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.READLINK]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string path + */ + const path = bufferParser.readString(true); + bufferParser.clear(); + + if (path === undefined) + return doFatalSFTPError(sftp, 'Malformed READLINK packet'); + + sftp._debug && sftp._debug( + `SFTP: Inbound: Received READLINK (id:${reqID})` + ); + + if (!sftp.emit('READLINK', reqID, path)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.SYMLINK]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string linkpath + string targetpath + */ + const linkPath = bufferParser.readString(true); + const targetPath = bufferParser.readString(true); + bufferParser.clear(); + + if (targetPath === undefined) + return doFatalSFTPError(sftp, 'Malformed SYMLINK packet'); + + sftp._debug && sftp._debug(`SFTP: Inbound: Received SYMLINK (id:${reqID})`); + + let handled; + if (sftp._isOpenSSH) { + // OpenSSH has linkpath and targetpath positions switched + handled = sftp.emit('SYMLINK', reqID, targetPath, linkPath); + } else { + handled = sftp.emit('SYMLINK', reqID, linkPath, targetPath); + } + if (!handled) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, + [REQUEST.EXTENDED]: (sftp, payload) => { + bufferParser.init(payload, 1); + const reqID = bufferParser.readUInt32BE(); + /* + string extended-request + ... any request-specific data ... + */ + const extName = bufferParser.readString(true); + if (extName === undefined) { + bufferParser.clear(); + return doFatalSFTPError(sftp, 'Malformed EXTENDED packet'); + } + + let extData; + if (bufferParser.avail()) + extData = bufferParser.readRaw(); + bufferParser.clear(); + + sftp._debug && sftp._debug( + `SFTP: Inbound: Received EXTENDED (id:${reqID})` + ); + + if (!sftp.emit('EXTENDED', reqID, extName, extData)) { + // Automatically reject request if no handler for request type + sftp.status(reqID, STATUS_CODE.OP_UNSUPPORTED); + } + }, +}; + +// ============================================================================= +// ReadStream/WriteStream-related ============================================== +// ============================================================================= +const { + ERR_INVALID_ARG_TYPE, + ERR_OUT_OF_RANGE, + validateNumber +} = require('./node-fs-compat'); + +const kMinPoolSpace = 128; + +let pool; +// It can happen that we expect to read a large chunk of data, and reserve +// a large chunk of the pool accordingly, but the read() call only filled +// a portion of it. If a concurrently executing read() then uses the same pool, +// the "reserved" portion cannot be used, so we allow it to be re-used as a +// new pool later. +const poolFragments = []; + +function allocNewPool(poolSize) { + if (poolFragments.length > 0) + pool = poolFragments.pop(); + else + pool = Buffer.allocUnsafe(poolSize); + pool.used = 0; +} + +// Check the `this.start` and `this.end` of stream. +function checkPosition(pos, name) { + if (!Number.isSafeInteger(pos)) { + validateNumber(pos, name); + if (!Number.isInteger(pos)) + throw new ERR_OUT_OF_RANGE(name, 'an integer', pos); + throw new ERR_OUT_OF_RANGE(name, '>= 0 and <= 2 ** 53 - 1', pos); + } + if (pos < 0) + throw new ERR_OUT_OF_RANGE(name, '>= 0 and <= 2 ** 53 - 1', pos); +} + +function roundUpToMultipleOf8(n) { + return (n + 7) & ~7; // Align to 8 byte boundary. +} + +function ReadStream(sftp, path, options) { + if (options === undefined) + options = {}; + else if (typeof options === 'string') + options = { encoding: options }; + else if (options === null || typeof options !== 'object') + throw new TypeError('"options" argument must be a string or an object'); + else + options = Object.create(options); + + // A little bit bigger buffer and water marks by default + if (options.highWaterMark === undefined) + options.highWaterMark = 64 * 1024; + + // For backwards compat do not emit close on destroy. + options.emitClose = false; + options.autoDestroy = false; // Node 14 major change. + + ReadableStream.call(this, options); + + this.path = path; + this.flags = options.flags === undefined ? 'r' : options.flags; + this.mode = options.mode === undefined ? 0o666 : options.mode; + + this.start = options.start; + this.end = options.end; + this.autoClose = options.autoClose === undefined ? true : options.autoClose; + this.pos = 0; + this.bytesRead = 0; + this.isClosed = false; + + this.handle = options.handle === undefined ? null : options.handle; + this.sftp = sftp; + this._opening = false; + + if (this.start !== undefined) { + checkPosition(this.start, 'start'); + + this.pos = this.start; + } + + if (this.end === undefined) { + this.end = Infinity; + } else if (this.end !== Infinity) { + checkPosition(this.end, 'end'); + + if (this.start !== undefined && this.start > this.end) { + throw new ERR_OUT_OF_RANGE( + 'start', + `<= "end" (here: ${this.end})`, + this.start + ); + } + } + + this.on('end', function() { + if (this.autoClose) + this.destroy(); + }); + + if (!Buffer.isBuffer(this.handle)) + this.open(); +} +inherits(ReadStream, ReadableStream); + +ReadStream.prototype.open = function() { + if (this._opening) + return; + + this._opening = true; + + this.sftp.open(this.path, this.flags, this.mode, (er, handle) => { + this._opening = false; + + if (er) { + this.emit('error', er); + if (this.autoClose) + this.destroy(); + return; + } + + this.handle = handle; + this.emit('open', handle); + this.emit('ready'); + // Start the flow of data. + this.read(); + }); +}; + +ReadStream.prototype._read = function(n) { + if (!Buffer.isBuffer(this.handle)) + return this.once('open', () => this._read(n)); + + // XXX: safe to remove this? + if (this.destroyed) + return; + + if (!pool || pool.length - pool.used < kMinPoolSpace) { + // Discard the old pool. + allocNewPool(this.readableHighWaterMark + || this._readableState.highWaterMark); + } + + // Grab another reference to the pool in the case that while we're + // in the thread pool another read() finishes up the pool, and + // allocates a new one. + const thisPool = pool; + let toRead = Math.min(pool.length - pool.used, n); + const start = pool.used; + + if (this.end !== undefined) + toRead = Math.min(this.end - this.pos + 1, toRead); + + // Already read everything we were supposed to read! + // treat as EOF. + if (toRead <= 0) + return this.push(null); + + // the actual read. + this.sftp.read(this.handle, + pool, + pool.used, + toRead, + this.pos, + (er, bytesRead) => { + if (er) { + this.emit('error', er); + if (this.autoClose) + this.destroy(); + return; + } + let b = null; + + // Now that we know how much data we have actually read, re-wind the + // 'used' field if we can, and otherwise allow the remainder of our + // reservation to be used as a new pool later. + if (start + toRead === thisPool.used && thisPool === pool) { + thisPool.used = roundUpToMultipleOf8(thisPool.used + bytesRead - toRead); + } else { + // Round down to the next lowest multiple of 8 to ensure the new pool + // fragment start and end positions are aligned to an 8 byte boundary. + const alignedEnd = (start + toRead) & ~7; + const alignedStart = roundUpToMultipleOf8(start + bytesRead); + if (alignedEnd - alignedStart >= kMinPoolSpace) + poolFragments.push(thisPool.slice(alignedStart, alignedEnd)); + } + + if (bytesRead > 0) { + this.bytesRead += bytesRead; + b = thisPool.slice(start, start + bytesRead); + } + + // Move the pool positions, and internal position for reading. + this.pos += bytesRead; + + this.push(b); + }); + + pool.used = roundUpToMultipleOf8(pool.used + toRead); +}; + +ReadStream.prototype._destroy = function(err, cb) { + if (this._opening && !Buffer.isBuffer(this.handle)) { + this.once('open', closeStream.bind(null, this, cb, err)); + return; + } + + closeStream(this, cb, err); + this.handle = null; + this._opening = false; +}; + +function closeStream(stream, cb, err) { + if (!stream.handle) + return onclose(); + + stream.sftp.close(stream.handle, onclose); + + function onclose(er) { + er = er || err; + cb(er); + stream.isClosed = true; + if (!er) + stream.emit('close'); + } +} + +ReadStream.prototype.close = function(cb) { + this.destroy(null, cb); +}; + +Object.defineProperty(ReadStream.prototype, 'pending', { + get() { + return this.handle === null; + }, + configurable: true +}); + +// TODO: add `concurrency` setting to allow more than one in-flight WRITE +// request to server to improve throughput +function WriteStream(sftp, path, options) { + if (options === undefined) + options = {}; + else if (typeof options === 'string') + options = { encoding: options }; + else if (options === null || typeof options !== 'object') + throw new TypeError('"options" argument must be a string or an object'); + else + options = Object.create(options); + + // For backwards compat do not emit close on destroy. + options.emitClose = false; + options.autoDestroy = false; // Node 14 major change. + + WritableStream.call(this, options); + + this.path = path; + this.flags = options.flags === undefined ? 'w' : options.flags; + this.mode = options.mode === undefined ? 0o666 : options.mode; + + this.start = options.start; + this.autoClose = options.autoClose === undefined ? true : options.autoClose; + this.pos = 0; + this.bytesWritten = 0; + this.isClosed = false; + + this.handle = options.handle === undefined ? null : options.handle; + this.sftp = sftp; + this._opening = false; + + if (this.start !== undefined) { + checkPosition(this.start, 'start'); + + this.pos = this.start; + } + + if (options.encoding) + this.setDefaultEncoding(options.encoding); + + // Node v6.x only + this.on('finish', function() { + if (this._writableState.finalCalled) + return; + if (this.autoClose) + this.destroy(); + }); + + if (!Buffer.isBuffer(this.handle)) + this.open(); +} +inherits(WriteStream, WritableStream); + +WriteStream.prototype._final = function(cb) { + if (this.autoClose) + this.destroy(); + cb(); +}; + +WriteStream.prototype.open = function() { + if (this._opening) + return; + + this._opening = true; + + this.sftp.open(this.path, this.flags, this.mode, (er, handle) => { + this._opening = false; + + if (er) { + this.emit('error', er); + if (this.autoClose) + this.destroy(); + return; + } + + this.handle = handle; + + const tryAgain = (err) => { + if (err) { + // Try chmod() for sftp servers that may not support fchmod() for + // whatever reason + this.sftp.chmod(this.path, this.mode, (err_) => tryAgain()); + return; + } + + // SFTPv3 requires absolute offsets, no matter the open flag used + if (this.flags[0] === 'a') { + const tryStat = (err, st) => { + if (err) { + // Try stat() for sftp servers that may not support fstat() for + // whatever reason + this.sftp.stat(this.path, (err_, st_) => { + if (err_) { + this.destroy(); + this.emit('error', err); + return; + } + tryStat(null, st_); + }); + return; + } + + this.pos = st.size; + this.emit('open', handle); + this.emit('ready'); + }; + + this.sftp.fstat(handle, tryStat); + return; + } + + this.emit('open', handle); + this.emit('ready'); + }; + + this.sftp.fchmod(handle, this.mode, tryAgain); + }); +}; + +WriteStream.prototype._write = function(data, encoding, cb) { + if (!Buffer.isBuffer(data)) { + const err = new ERR_INVALID_ARG_TYPE('data', 'Buffer', data); + return this.emit('error', err); + } + + if (!Buffer.isBuffer(this.handle)) { + return this.once('open', function() { + this._write(data, encoding, cb); + }); + } + + this.sftp.write(this.handle, + data, + 0, + data.length, + this.pos, + (er, bytes) => { + if (er) { + if (this.autoClose) + this.destroy(); + return cb(er); + } + this.bytesWritten += bytes; + cb(); + }); + + this.pos += data.length; +}; + +WriteStream.prototype._writev = function(data, cb) { + if (!Buffer.isBuffer(this.handle)) { + return this.once('open', function() { + this._writev(data, cb); + }); + } + + const sftp = this.sftp; + const handle = this.handle; + let writesLeft = data.length; + + const onwrite = (er, bytes) => { + if (er) { + this.destroy(); + return cb(er); + } + this.bytesWritten += bytes; + if (--writesLeft === 0) + cb(); + }; + + // TODO: try to combine chunks to reduce number of requests to the server? + for (let i = 0; i < data.length; ++i) { + const chunk = data[i].chunk; + + sftp.write(handle, chunk, 0, chunk.length, this.pos, onwrite); + this.pos += chunk.length; + } +}; + +if (typeof WritableStream.prototype.destroy !== 'function') + WriteStream.prototype.destroy = ReadStream.prototype.destroy; + +WriteStream.prototype._destroy = ReadStream.prototype._destroy; +WriteStream.prototype.close = function(cb) { + if (cb) { + if (this.isClosed) { + process.nextTick(cb); + return; + } + this.on('close', cb); + } + + // If we are not autoClosing, we should call + // destroy on 'finish'. + if (!this.autoClose) + this.on('finish', this.destroy.bind(this)); + + this.end(); +}; + +// There is no shutdown() for files. +WriteStream.prototype.destroySoon = WriteStream.prototype.end; + +Object.defineProperty(WriteStream.prototype, 'pending', { + get() { + return this.handle === null; + }, + configurable: true +}); +// ============================================================================= + +module.exports = { + flagsToString, + OPEN_MODE, + SFTP, + Stats, + STATUS_CODE, + stringToFlags, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/constants.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/constants.js new file mode 100644 index 0000000..ad77592 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/constants.js @@ -0,0 +1,356 @@ +'use strict'; + +const crypto = require('crypto'); + +let cpuInfo; +try { + cpuInfo = require('cpu-features')(); +} catch {} + +const { bindingAvailable, CIPHER_INFO, MAC_INFO } = require('./crypto.js'); + +const eddsaSupported = (() => { + if (typeof crypto.sign === 'function' + && typeof crypto.verify === 'function') { + const key = + '-----BEGIN PRIVATE KEY-----\r\nMC4CAQAwBQYDK2VwBCIEIHKj+sVa9WcD' + + '/q2DJUJaf43Kptc8xYuUQA4bOFj9vC8T\r\n-----END PRIVATE KEY-----'; + const data = Buffer.from('a'); + let sig; + let verified; + try { + sig = crypto.sign(null, data, key); + verified = crypto.verify(null, data, key, sig); + } catch {} + return (Buffer.isBuffer(sig) && sig.length === 64 && verified === true); + } + + return false; +})(); + +const curve25519Supported = (typeof crypto.diffieHellman === 'function' + && typeof crypto.generateKeyPairSync === 'function' + && typeof crypto.createPublicKey === 'function'); + +const DEFAULT_KEX = [ + // https://tools.ietf.org/html/rfc5656#section-10.1 + 'ecdh-sha2-nistp256', + 'ecdh-sha2-nistp384', + 'ecdh-sha2-nistp521', + + // https://tools.ietf.org/html/rfc4419#section-4 + 'diffie-hellman-group-exchange-sha256', + + // https://tools.ietf.org/html/rfc8268 + 'diffie-hellman-group14-sha256', + 'diffie-hellman-group15-sha512', + 'diffie-hellman-group16-sha512', + 'diffie-hellman-group17-sha512', + 'diffie-hellman-group18-sha512', +]; +if (curve25519Supported) { + DEFAULT_KEX.unshift('curve25519-sha256'); + DEFAULT_KEX.unshift('curve25519-sha256@libssh.org'); +} +const SUPPORTED_KEX = DEFAULT_KEX.concat([ + // https://tools.ietf.org/html/rfc4419#section-4 + 'diffie-hellman-group-exchange-sha1', + + 'diffie-hellman-group14-sha1', // REQUIRED + 'diffie-hellman-group1-sha1', // REQUIRED +]); + + +const DEFAULT_SERVER_HOST_KEY = [ + 'ecdsa-sha2-nistp256', + 'ecdsa-sha2-nistp384', + 'ecdsa-sha2-nistp521', + 'rsa-sha2-512', // RFC 8332 + 'rsa-sha2-256', // RFC 8332 + 'ssh-rsa', +]; +if (eddsaSupported) + DEFAULT_SERVER_HOST_KEY.unshift('ssh-ed25519'); +const SUPPORTED_SERVER_HOST_KEY = DEFAULT_SERVER_HOST_KEY.concat([ + 'ssh-dss', +]); + + +const canUseCipher = (() => { + const ciphers = crypto.getCiphers(); + return (name) => ciphers.includes(CIPHER_INFO[name].sslName); +})(); +let DEFAULT_CIPHER = [ + // http://tools.ietf.org/html/rfc5647 + 'aes128-gcm@openssh.com', + 'aes256-gcm@openssh.com', + + // http://tools.ietf.org/html/rfc4344#section-4 + 'aes128-ctr', + 'aes192-ctr', + 'aes256-ctr', +]; +if (cpuInfo && cpuInfo.flags && !cpuInfo.flags.aes) { + // We know for sure the CPU does not support AES acceleration + if (bindingAvailable) + DEFAULT_CIPHER.unshift('chacha20-poly1305@openssh.com'); + else + DEFAULT_CIPHER.push('chacha20-poly1305@openssh.com'); +} else if (bindingAvailable && cpuInfo && cpuInfo.arch === 'x86') { + // Places chacha20-poly1305 immediately after GCM ciphers since GCM ciphers + // seem to outperform it on x86, but it seems to be faster than CTR ciphers + DEFAULT_CIPHER.splice(4, 0, 'chacha20-poly1305@openssh.com'); +} else { + DEFAULT_CIPHER.push('chacha20-poly1305@openssh.com'); +} +DEFAULT_CIPHER = DEFAULT_CIPHER.filter(canUseCipher); +const SUPPORTED_CIPHER = DEFAULT_CIPHER.concat([ + 'aes256-cbc', + 'aes192-cbc', + 'aes128-cbc', + 'blowfish-cbc', + '3des-cbc', + 'aes128-gcm', + 'aes256-gcm', + + // http://tools.ietf.org/html/rfc4345#section-4: + 'arcfour256', + 'arcfour128', + + 'cast128-cbc', + 'arcfour', +].filter(canUseCipher)); + + +const canUseMAC = (() => { + const hashes = crypto.getHashes(); + return (name) => hashes.includes(MAC_INFO[name].sslName); +})(); +const DEFAULT_MAC = [ + 'hmac-sha2-256-etm@openssh.com', + 'hmac-sha2-512-etm@openssh.com', + 'hmac-sha1-etm@openssh.com', + 'hmac-sha2-256', + 'hmac-sha2-512', + 'hmac-sha1', +].filter(canUseMAC); +const SUPPORTED_MAC = DEFAULT_MAC.concat([ + 'hmac-md5', + 'hmac-sha2-256-96', // first 96 bits of HMAC-SHA256 + 'hmac-sha2-512-96', // first 96 bits of HMAC-SHA512 + 'hmac-ripemd160', + 'hmac-sha1-96', // first 96 bits of HMAC-SHA1 + 'hmac-md5-96', // first 96 bits of HMAC-MD5 +].filter(canUseMAC)); + +const DEFAULT_COMPRESSION = [ + 'none', + 'zlib@openssh.com', // ZLIB (LZ77) compression, except + // compression/decompression does not start until after + // successful user authentication + 'zlib', // ZLIB (LZ77) compression +]; +const SUPPORTED_COMPRESSION = DEFAULT_COMPRESSION.concat([ +]); + + +const COMPAT = { + BAD_DHGEX: 1 << 0, + OLD_EXIT: 1 << 1, + DYN_RPORT_BUG: 1 << 2, + BUG_DHGEX_LARGE: 1 << 3, + IMPLY_RSA_SHA2_SIGALGS: 1 << 4, +}; + +module.exports = { + MESSAGE: { + // Transport layer protocol -- generic (1-19) + DISCONNECT: 1, + IGNORE: 2, + UNIMPLEMENTED: 3, + DEBUG: 4, + SERVICE_REQUEST: 5, + SERVICE_ACCEPT: 6, + EXT_INFO: 7, // RFC 8308 + + // Transport layer protocol -- algorithm negotiation (20-29) + KEXINIT: 20, + NEWKEYS: 21, + + // Transport layer protocol -- key exchange method-specific (30-49) + KEXDH_INIT: 30, + KEXDH_REPLY: 31, + + KEXDH_GEX_GROUP: 31, + KEXDH_GEX_INIT: 32, + KEXDH_GEX_REPLY: 33, + KEXDH_GEX_REQUEST: 34, + + KEXECDH_INIT: 30, + KEXECDH_REPLY: 31, + + // User auth protocol -- generic (50-59) + USERAUTH_REQUEST: 50, + USERAUTH_FAILURE: 51, + USERAUTH_SUCCESS: 52, + USERAUTH_BANNER: 53, + + // User auth protocol -- user auth method-specific (60-79) + USERAUTH_PASSWD_CHANGEREQ: 60, + + USERAUTH_PK_OK: 60, + + USERAUTH_INFO_REQUEST: 60, + USERAUTH_INFO_RESPONSE: 61, + + // Connection protocol -- generic (80-89) + GLOBAL_REQUEST: 80, + REQUEST_SUCCESS: 81, + REQUEST_FAILURE: 82, + + // Connection protocol -- channel-related (90-127) + CHANNEL_OPEN: 90, + CHANNEL_OPEN_CONFIRMATION: 91, + CHANNEL_OPEN_FAILURE: 92, + CHANNEL_WINDOW_ADJUST: 93, + CHANNEL_DATA: 94, + CHANNEL_EXTENDED_DATA: 95, + CHANNEL_EOF: 96, + CHANNEL_CLOSE: 97, + CHANNEL_REQUEST: 98, + CHANNEL_SUCCESS: 99, + CHANNEL_FAILURE: 100 + + // Reserved for client protocols (128-191) + + // Local extensions (192-155) + }, + DISCONNECT_REASON: { + HOST_NOT_ALLOWED_TO_CONNECT: 1, + PROTOCOL_ERROR: 2, + KEY_EXCHANGE_FAILED: 3, + RESERVED: 4, + MAC_ERROR: 5, + COMPRESSION_ERROR: 6, + SERVICE_NOT_AVAILABLE: 7, + PROTOCOL_VERSION_NOT_SUPPORTED: 8, + HOST_KEY_NOT_VERIFIABLE: 9, + CONNECTION_LOST: 10, + BY_APPLICATION: 11, + TOO_MANY_CONNECTIONS: 12, + AUTH_CANCELED_BY_USER: 13, + NO_MORE_AUTH_METHODS_AVAILABLE: 14, + ILLEGAL_USER_NAME: 15, + }, + DISCONNECT_REASON_STR: undefined, + CHANNEL_OPEN_FAILURE: { + ADMINISTRATIVELY_PROHIBITED: 1, + CONNECT_FAILED: 2, + UNKNOWN_CHANNEL_TYPE: 3, + RESOURCE_SHORTAGE: 4 + }, + TERMINAL_MODE: { + TTY_OP_END: 0, // Indicates end of options. + VINTR: 1, // Interrupt character; 255 if none. Similarly for the + // other characters. Not all of these characters are + // supported on all systems. + VQUIT: 2, // The quit character (sends SIGQUIT signal on POSIX + // systems). + VERASE: 3, // Erase the character to left of the cursor. + VKILL: 4, // Kill the current input line. + VEOF: 5, // End-of-file character (sends EOF from the + // terminal). + VEOL: 6, // End-of-line character in addition to carriage + // return and/or linefeed. + VEOL2: 7, // Additional end-of-line character. + VSTART: 8, // Continues paused output (normally control-Q). + VSTOP: 9, // Pauses output (normally control-S). + VSUSP: 10, // Suspends the current program. + VDSUSP: 11, // Another suspend character. + VREPRINT: 12, // Reprints the current input line. + VWERASE: 13, // Erases a word left of cursor. + VLNEXT: 14, // Enter the next character typed literally, even if + // it is a special character + VFLUSH: 15, // Character to flush output. + VSWTCH: 16, // Switch to a different shell layer. + VSTATUS: 17, // Prints system status line (load, command, pid, + // etc). + VDISCARD: 18, // Toggles the flushing of terminal output. + IGNPAR: 30, // The ignore parity flag. The parameter SHOULD be 0 + // if this flag is FALSE, and 1 if it is TRUE. + PARMRK: 31, // Mark parity and framing errors. + INPCK: 32, // Enable checking of parity errors. + ISTRIP: 33, // Strip 8th bit off characters. + INLCR: 34, // Map NL into CR on input. + IGNCR: 35, // Ignore CR on input. + ICRNL: 36, // Map CR to NL on input. + IUCLC: 37, // Translate uppercase characters to lowercase. + IXON: 38, // Enable output flow control. + IXANY: 39, // Any char will restart after stop. + IXOFF: 40, // Enable input flow control. + IMAXBEL: 41, // Ring bell on input queue full. + ISIG: 50, // Enable signals INTR, QUIT, [D]SUSP. + ICANON: 51, // Canonicalize input lines. + XCASE: 52, // Enable input and output of uppercase characters by + // preceding their lowercase equivalents with "\". + ECHO: 53, // Enable echoing. + ECHOE: 54, // Visually erase chars. + ECHOK: 55, // Kill character discards current line. + ECHONL: 56, // Echo NL even if ECHO is off. + NOFLSH: 57, // Don't flush after interrupt. + TOSTOP: 58, // Stop background jobs from output. + IEXTEN: 59, // Enable extensions. + ECHOCTL: 60, // Echo control characters as ^(Char). + ECHOKE: 61, // Visual erase for line kill. + PENDIN: 62, // Retype pending input. + OPOST: 70, // Enable output processing. + OLCUC: 71, // Convert lowercase to uppercase. + ONLCR: 72, // Map NL to CR-NL. + OCRNL: 73, // Translate carriage return to newline (output). + ONOCR: 74, // Translate newline to carriage return-newline + // (output). + ONLRET: 75, // Newline performs a carriage return (output). + CS7: 90, // 7 bit mode. + CS8: 91, // 8 bit mode. + PARENB: 92, // Parity enable. + PARODD: 93, // Odd parity, else even. + TTY_OP_ISPEED: 128, // Specifies the input baud rate in bits per second. + TTY_OP_OSPEED: 129, // Specifies the output baud rate in bits per second. + }, + CHANNEL_EXTENDED_DATATYPE: { + STDERR: 1, + }, + + SIGNALS: [ + 'ABRT', 'ALRM', 'FPE', 'HUP', 'ILL', 'INT', 'QUIT', 'SEGV', 'TERM', 'USR1', + 'USR2', 'KILL', 'PIPE' + ].reduce((cur, val) => ({ ...cur, [val]: 1 }), {}), + + COMPAT, + COMPAT_CHECKS: [ + [ 'Cisco-1.25', COMPAT.BAD_DHGEX ], + [ /^Cisco-1[.]/, COMPAT.BUG_DHGEX_LARGE ], + [ /^[0-9.]+$/, COMPAT.OLD_EXIT ], // old SSH.com implementations + [ /^OpenSSH_5[.][0-9]+/, COMPAT.DYN_RPORT_BUG ], + [ /^OpenSSH_7[.]4/, COMPAT.IMPLY_RSA_SHA2_SIGALGS ], + ], + + // KEX proposal-related + DEFAULT_KEX, + SUPPORTED_KEX, + DEFAULT_SERVER_HOST_KEY, + SUPPORTED_SERVER_HOST_KEY, + DEFAULT_CIPHER, + SUPPORTED_CIPHER, + DEFAULT_MAC, + SUPPORTED_MAC, + DEFAULT_COMPRESSION, + SUPPORTED_COMPRESSION, + + curve25519Supported, + eddsaSupported, +}; + +module.exports.DISCONNECT_REASON_BY_VALUE = + Array.from(Object.entries(module.exports.DISCONNECT_REASON)) + .reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {}); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto.js new file mode 100644 index 0000000..851cc73 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto.js @@ -0,0 +1,1602 @@ +// TODO: +// * make max packet size configurable +// * if decompression is enabled, use `._packet` in decipher instances as +// input to (sync) zlib inflater with appropriate offset and length to +// avoid an additional copy of payload data before inflation +// * factor decompression status into packet length checks +'use strict'; + +const { + createCipheriv, createDecipheriv, createHmac, randomFillSync, timingSafeEqual +} = require('crypto'); + +const { readUInt32BE, writeUInt32BE } = require('./utils.js'); + +const FastBuffer = Buffer[Symbol.species]; +const MAX_SEQNO = 2 ** 32 - 1; +const EMPTY_BUFFER = Buffer.alloc(0); +const BUF_INT = Buffer.alloc(4); +const DISCARD_CACHE = new Map(); +const MAX_PACKET_SIZE = 35000; + +let binding; +let AESGCMCipher; +let ChaChaPolyCipher; +let GenericCipher; +let AESGCMDecipher; +let ChaChaPolyDecipher; +let GenericDecipher; +try { + binding = require('./crypto/build/Release/sshcrypto.node'); + ({ AESGCMCipher, ChaChaPolyCipher, GenericCipher, + AESGCMDecipher, ChaChaPolyDecipher, GenericDecipher } = binding); +} catch {} + +const CIPHER_STREAM = 1 << 0; +const CIPHER_INFO = (() => { + function info(sslName, blockLen, keyLen, ivLen, authLen, discardLen, flags) { + return { + sslName, + blockLen, + keyLen, + ivLen: (ivLen !== 0 || (flags & CIPHER_STREAM) + ? ivLen + : blockLen), + authLen, + discardLen, + stream: !!(flags & CIPHER_STREAM), + }; + } + + return { + 'chacha20-poly1305@openssh.com': + info('chacha20', 8, 64, 0, 16, 0, CIPHER_STREAM), + + 'aes128-gcm': info('aes-128-gcm', 16, 16, 12, 16, 0, CIPHER_STREAM), + 'aes256-gcm': info('aes-256-gcm', 16, 32, 12, 16, 0, CIPHER_STREAM), + 'aes128-gcm@openssh.com': + info('aes-128-gcm', 16, 16, 12, 16, 0, CIPHER_STREAM), + 'aes256-gcm@openssh.com': + info('aes-256-gcm', 16, 32, 12, 16, 0, CIPHER_STREAM), + + 'aes128-cbc': info('aes-128-cbc', 16, 16, 0, 0, 0, 0), + 'aes192-cbc': info('aes-192-cbc', 16, 24, 0, 0, 0, 0), + 'aes256-cbc': info('aes-256-cbc', 16, 32, 0, 0, 0, 0), + 'rijndael-cbc@lysator.liu.se': info('aes-256-cbc', 16, 32, 0, 0, 0, 0), + '3des-cbc': info('des-ede3-cbc', 8, 24, 0, 0, 0, 0), + 'blowfish-cbc': info('bf-cbc', 8, 16, 0, 0, 0, 0), + 'idea-cbc': info('idea-cbc', 8, 16, 0, 0, 0, 0), + 'cast128-cbc': info('cast-cbc', 8, 16, 0, 0, 0, 0), + + 'aes128-ctr': info('aes-128-ctr', 16, 16, 16, 0, 0, CIPHER_STREAM), + 'aes192-ctr': info('aes-192-ctr', 16, 24, 16, 0, 0, CIPHER_STREAM), + 'aes256-ctr': info('aes-256-ctr', 16, 32, 16, 0, 0, CIPHER_STREAM), + '3des-ctr': info('des-ede3', 8, 24, 8, 0, 0, CIPHER_STREAM), + 'blowfish-ctr': info('bf-ecb', 8, 16, 8, 0, 0, CIPHER_STREAM), + 'cast128-ctr': info('cast5-ecb', 8, 16, 8, 0, 0, CIPHER_STREAM), + + /* The "arcfour128" algorithm is the RC4 cipher, as described in + [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream + generated by the cipher MUST be discarded, and the first byte of the + first encrypted packet MUST be encrypted using the 1537th byte of + keystream. + + -- http://tools.ietf.org/html/rfc4345#section-4 */ + 'arcfour': info('rc4', 8, 16, 0, 0, 1536, CIPHER_STREAM), + 'arcfour128': info('rc4', 8, 16, 0, 0, 1536, CIPHER_STREAM), + 'arcfour256': info('rc4', 8, 32, 0, 0, 1536, CIPHER_STREAM), + 'arcfour512': info('rc4', 8, 64, 0, 0, 1536, CIPHER_STREAM), + }; +})(); + +const MAC_INFO = (() => { + function info(sslName, len, actualLen, isETM) { + return { + sslName, + len, + actualLen, + isETM, + }; + } + + return { + 'hmac-md5': info('md5', 16, 16, false), + 'hmac-md5-96': info('md5', 16, 12, false), + 'hmac-ripemd160': info('ripemd160', 20, 20, false), + 'hmac-sha1': info('sha1', 20, 20, false), + 'hmac-sha1-etm@openssh.com': info('sha1', 20, 20, true), + 'hmac-sha1-96': info('sha1', 20, 12, false), + 'hmac-sha2-256': info('sha256', 32, 32, false), + 'hmac-sha2-256-etm@openssh.com': info('sha256', 32, 32, true), + 'hmac-sha2-256-96': info('sha256', 32, 12, false), + 'hmac-sha2-512': info('sha512', 64, 64, false), + 'hmac-sha2-512-etm@openssh.com': info('sha512', 64, 64, true), + 'hmac-sha2-512-96': info('sha512', 64, 12, false), + }; +})(); + + +// Should only_be used during the initial handshake +class NullCipher { + constructor(seqno, onWrite) { + this.outSeqno = seqno; + this._onWrite = onWrite; + this._dead = false; + } + free() { + this._dead = true; + } + allocPacket(payloadLen) { + let pktLen = 4 + 1 + payloadLen; + let padLen = 8 - (pktLen & (8 - 1)); + if (padLen < 4) + padLen += 8; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + this._onWrite(packet); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + + +const POLY1305_ZEROS = Buffer.alloc(32); +const POLY1305_OUT_COMPUTE = Buffer.alloc(16); +let POLY1305_WASM_MODULE; +let POLY1305_RESULT_MALLOC; +let poly1305_auth; +class ChaChaPolyCipherNative { + constructor(config) { + const enc = config.outbound; + this.outSeqno = enc.seqno; + this._onWrite = enc.onWrite; + this._encKeyMain = enc.cipherKey.slice(0, 32); + this._encKeyPktLen = enc.cipherKey.slice(32); + this._dead = false; + } + free() { + this._dead = true; + } + allocPacket(payloadLen) { + let pktLen = 4 + 1 + payloadLen; + let padLen = 8 - ((pktLen - 4) & (8 - 1)); + if (padLen < 4) + padLen += 8; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + // Generate Poly1305 key + POLY1305_OUT_COMPUTE[0] = 0; // Set counter to 0 (little endian) + writeUInt32BE(POLY1305_OUT_COMPUTE, this.outSeqno, 12); + const polyKey = + createCipheriv('chacha20', this._encKeyMain, POLY1305_OUT_COMPUTE) + .update(POLY1305_ZEROS); + + // Encrypt packet length + const pktLenEnc = + createCipheriv('chacha20', this._encKeyPktLen, POLY1305_OUT_COMPUTE) + .update(packet.slice(0, 4)); + this._onWrite(pktLenEnc); + + // Encrypt rest of packet + POLY1305_OUT_COMPUTE[0] = 1; // Set counter to 1 (little endian) + const payloadEnc = + createCipheriv('chacha20', this._encKeyMain, POLY1305_OUT_COMPUTE) + .update(packet.slice(4)); + this._onWrite(payloadEnc); + + // Calculate Poly1305 MAC + poly1305_auth(POLY1305_RESULT_MALLOC, + pktLenEnc, + pktLenEnc.length, + payloadEnc, + payloadEnc.length, + polyKey); + const mac = Buffer.allocUnsafe(16); + mac.set( + new Uint8Array(POLY1305_WASM_MODULE.HEAPU8.buffer, + POLY1305_RESULT_MALLOC, + 16), + 0 + ); + this._onWrite(mac); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + +class ChaChaPolyCipherBinding { + constructor(config) { + const enc = config.outbound; + this.outSeqno = enc.seqno; + this._onWrite = enc.onWrite; + this._instance = new ChaChaPolyCipher(enc.cipherKey); + this._dead = false; + } + free() { + this._dead = true; + this._instance.free(); + } + allocPacket(payloadLen) { + let pktLen = 4 + 1 + payloadLen; + let padLen = 8 - ((pktLen - 4) & (8 - 1)); + if (padLen < 4) + padLen += 8; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen + 16/* MAC */); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + // Encrypts in-place + this._instance.encrypt(packet, this.outSeqno); + + this._onWrite(packet); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + + +class AESGCMCipherNative { + constructor(config) { + const enc = config.outbound; + this.outSeqno = enc.seqno; + this._onWrite = enc.onWrite; + this._encSSLName = enc.cipherInfo.sslName; + this._encKey = enc.cipherKey; + this._encIV = enc.cipherIV; + this._dead = false; + } + free() { + this._dead = true; + } + allocPacket(payloadLen) { + let pktLen = 4 + 1 + payloadLen; + let padLen = 16 - ((pktLen - 4) & (16 - 1)); + if (padLen < 4) + padLen += 16; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + const cipher = createCipheriv(this._encSSLName, this._encKey, this._encIV); + cipher.setAutoPadding(false); + + const lenData = packet.slice(0, 4); + cipher.setAAD(lenData); + this._onWrite(lenData); + + // Encrypt pad length, payload, and padding + const encrypted = cipher.update(packet.slice(4)); + this._onWrite(encrypted); + const final = cipher.final(); + // XXX: final.length === 0 always? + if (final.length) + this._onWrite(final); + + // Generate MAC + const tag = cipher.getAuthTag(); + this._onWrite(tag); + + // Increment counter in IV by 1 for next packet + ivIncrement(this._encIV); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + +class AESGCMCipherBinding { + constructor(config) { + const enc = config.outbound; + this.outSeqno = enc.seqno; + this._onWrite = enc.onWrite; + this._instance = new AESGCMCipher(enc.cipherInfo.sslName, + enc.cipherKey, + enc.cipherIV); + this._dead = false; + } + free() { + this._dead = true; + this._instance.free(); + } + allocPacket(payloadLen) { + let pktLen = 4 + 1 + payloadLen; + let padLen = 16 - ((pktLen - 4) & (16 - 1)); + if (padLen < 4) + padLen += 16; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen + 16/* authTag */); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + // Encrypts in-place + this._instance.encrypt(packet); + + this._onWrite(packet); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + + +class GenericCipherNative { + constructor(config) { + const enc = config.outbound; + this.outSeqno = enc.seqno; + this._onWrite = enc.onWrite; + this._encBlockLen = enc.cipherInfo.blockLen; + this._cipherInstance = createCipheriv(enc.cipherInfo.sslName, + enc.cipherKey, + enc.cipherIV); + this._macSSLName = enc.macInfo.sslName; + this._macKey = enc.macKey; + this._macActualLen = enc.macInfo.actualLen; + this._macETM = enc.macInfo.isETM; + this._aadLen = (this._macETM ? 4 : 0); + this._dead = false; + + const discardLen = enc.cipherInfo.discardLen; + if (discardLen) { + let discard = DISCARD_CACHE.get(discardLen); + if (discard === undefined) { + discard = Buffer.alloc(discardLen); + DISCARD_CACHE.set(discardLen, discard); + } + this._cipherInstance.update(discard); + } + } + free() { + this._dead = true; + } + allocPacket(payloadLen) { + const blockLen = this._encBlockLen; + + let pktLen = 4 + 1 + payloadLen; + let padLen = blockLen - ((pktLen - this._aadLen) & (blockLen - 1)); + if (padLen < 4) + padLen += blockLen; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + let mac; + if (this._macETM) { + // Encrypt pad length, payload, and padding + const lenBytes = new Uint8Array(packet.buffer, packet.byteOffset, 4); + const encrypted = this._cipherInstance.update( + new Uint8Array(packet.buffer, + packet.byteOffset + 4, + packet.length - 4) + ); + + this._onWrite(lenBytes); + this._onWrite(encrypted); + + // TODO: look into storing seqno as 4-byte buffer and incrementing like we + // do for AES-GCM IVs to avoid having to (re)write all 4 bytes every time + mac = createHmac(this._macSSLName, this._macKey); + writeUInt32BE(BUF_INT, this.outSeqno, 0); + mac.update(BUF_INT); + mac.update(lenBytes); + mac.update(encrypted); + } else { + // Encrypt length field, pad length, payload, and padding + const encrypted = this._cipherInstance.update(packet); + this._onWrite(encrypted); + + // TODO: look into storing seqno as 4-byte buffer and incrementing like we + // do for AES-GCM IVs to avoid having to (re)write all 4 bytes every time + mac = createHmac(this._macSSLName, this._macKey); + writeUInt32BE(BUF_INT, this.outSeqno, 0); + mac.update(BUF_INT); + mac.update(packet); + } + + let digest = mac.digest(); + if (digest.length > this._macActualLen) + digest = digest.slice(0, this._macActualLen); + this._onWrite(digest); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + +class GenericCipherBinding { + constructor(config) { + const enc = config.outbound; + this.outSeqno = enc.seqno; + this._onWrite = enc.onWrite; + this._encBlockLen = enc.cipherInfo.blockLen; + this._macLen = enc.macInfo.len; + this._macActualLen = enc.macInfo.actualLen; + this._aadLen = (enc.macInfo.isETM ? 4 : 0); + this._instance = new GenericCipher(enc.cipherInfo.sslName, + enc.cipherKey, + enc.cipherIV, + enc.macInfo.sslName, + enc.macKey, + enc.macInfo.isETM); + this._dead = false; + } + free() { + this._dead = true; + this._instance.free(); + } + allocPacket(payloadLen) { + const blockLen = this._encBlockLen; + + let pktLen = 4 + 1 + payloadLen; + let padLen = blockLen - ((pktLen - this._aadLen) & (blockLen - 1)); + if (padLen < 4) + padLen += blockLen; + pktLen += padLen; + + const packet = Buffer.allocUnsafe(pktLen + this._macLen); + + writeUInt32BE(packet, pktLen - 4, 0); + packet[4] = padLen; + + randomFillSync(packet, 5 + payloadLen, padLen); + + return packet; + } + encrypt(packet) { + // `packet` === unencrypted packet + + if (this._dead) + return; + + // Encrypts in-place + this._instance.encrypt(packet, this.outSeqno); + + if (this._macActualLen < this._macLen) { + packet = new FastBuffer(packet.buffer, + packet.byteOffset, + (packet.length + - (this._macLen - this._macActualLen))); + } + this._onWrite(packet); + + this.outSeqno = (this.outSeqno + 1) >>> 0; + } +} + + +class NullDecipher { + constructor(seqno, onPayload) { + this.inSeqno = seqno; + this._onPayload = onPayload; + this._len = 0; + this._lenBytes = 0; + this._packet = null; + this._packetPos = 0; + } + free() {} + decrypt(data, p, dataLen) { + while (p < dataLen) { + // Read packet length + if (this._lenBytes < 4) { + let nb = Math.min(4 - this._lenBytes, dataLen - p); + + this._lenBytes += nb; + while (nb--) + this._len = (this._len << 8) + data[p++]; + + if (this._lenBytes < 4) + return; + + if (this._len > MAX_PACKET_SIZE + || this._len < 8 + || (4 + this._len & 7) !== 0) { + throw new Error('Bad packet length'); + } + if (p >= dataLen) + return; + } + + // Read padding length, payload, and padding + if (this._packetPos < this._len) { + const nb = Math.min(this._len - this._packetPos, dataLen - p); + let chunk; + if (p !== 0 || nb !== dataLen) + chunk = new Uint8Array(data.buffer, data.byteOffset + p, nb); + else + chunk = data; + if (nb === this._len) { + this._packet = chunk; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(chunk, this._packetPos); + } + p += nb; + this._packetPos += nb; + if (this._packetPos < this._len) + return; + } + + const payload = (!this._packet + ? EMPTY_BUFFER + : new FastBuffer(this._packet.buffer, + this._packet.byteOffset + 1, + this._packet.length + - this._packet[0] - 1)); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + this._len = 0; + this._lenBytes = 0; + this._packet = null; + this._packetPos = 0; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +class ChaChaPolyDecipherNative { + constructor(config) { + const dec = config.inbound; + this.inSeqno = dec.seqno; + this._onPayload = dec.onPayload; + this._decKeyMain = dec.decipherKey.slice(0, 32); + this._decKeyPktLen = dec.decipherKey.slice(32); + this._len = 0; + this._lenBuf = Buffer.alloc(4); + this._lenPos = 0; + this._packet = null; + this._pktLen = 0; + this._mac = Buffer.allocUnsafe(16); + this._calcMac = Buffer.allocUnsafe(16); + this._macPos = 0; + } + free() {} + decrypt(data, p, dataLen) { + // `data` === encrypted data + + while (p < dataLen) { + // Read packet length + if (this._lenPos < 4) { + let nb = Math.min(4 - this._lenPos, dataLen - p); + while (nb--) + this._lenBuf[this._lenPos++] = data[p++]; + if (this._lenPos < 4) + return; + + POLY1305_OUT_COMPUTE[0] = 0; // Set counter to 0 (little endian) + writeUInt32BE(POLY1305_OUT_COMPUTE, this.inSeqno, 12); + + const decLenBytes = + createDecipheriv('chacha20', this._decKeyPktLen, POLY1305_OUT_COMPUTE) + .update(this._lenBuf); + this._len = readUInt32BE(decLenBytes, 0); + + if (this._len > MAX_PACKET_SIZE + || this._len < 8 + || (this._len & 7) !== 0) { + throw new Error('Bad packet length'); + } + } + + // Read padding length, payload, and padding + if (this._pktLen < this._len) { + if (p >= dataLen) + return; + const nb = Math.min(this._len - this._pktLen, dataLen - p); + let encrypted; + if (p !== 0 || nb !== dataLen) + encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb); + else + encrypted = data; + if (nb === this._len) { + this._packet = encrypted; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(encrypted, this._pktLen); + } + p += nb; + this._pktLen += nb; + if (this._pktLen < this._len || p >= dataLen) + return; + } + + // Read Poly1305 MAC + { + const nb = Math.min(16 - this._macPos, dataLen - p); + // TODO: avoid copying if entire MAC is in current chunk + if (p !== 0 || nb !== dataLen) { + this._mac.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._macPos + ); + } else { + this._mac.set(data, this._macPos); + } + p += nb; + this._macPos += nb; + if (this._macPos < 16) + return; + } + + // Generate Poly1305 key + POLY1305_OUT_COMPUTE[0] = 0; // Set counter to 0 (little endian) + writeUInt32BE(POLY1305_OUT_COMPUTE, this.inSeqno, 12); + const polyKey = + createCipheriv('chacha20', this._decKeyMain, POLY1305_OUT_COMPUTE) + .update(POLY1305_ZEROS); + + // Calculate and compare Poly1305 MACs + poly1305_auth(POLY1305_RESULT_MALLOC, + this._lenBuf, + 4, + this._packet, + this._packet.length, + polyKey); + + this._calcMac.set( + new Uint8Array(POLY1305_WASM_MODULE.HEAPU8.buffer, + POLY1305_RESULT_MALLOC, + 16), + 0 + ); + if (!timingSafeEqual(this._calcMac, this._mac)) + throw new Error('Invalid MAC'); + + // Decrypt packet + POLY1305_OUT_COMPUTE[0] = 1; // Set counter to 1 (little endian) + const packet = + createDecipheriv('chacha20', this._decKeyMain, POLY1305_OUT_COMPUTE) + .update(this._packet); + + const payload = new FastBuffer(packet.buffer, + packet.byteOffset + 1, + packet.length - packet[0] - 1); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + this._len = 0; + this._lenPos = 0; + this._packet = null; + this._pktLen = 0; + this._macPos = 0; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +class ChaChaPolyDecipherBinding { + constructor(config) { + const dec = config.inbound; + this.inSeqno = dec.seqno; + this._onPayload = dec.onPayload; + this._instance = new ChaChaPolyDecipher(dec.decipherKey); + this._len = 0; + this._lenBuf = Buffer.alloc(4); + this._lenPos = 0; + this._packet = null; + this._pktLen = 0; + this._mac = Buffer.allocUnsafe(16); + this._macPos = 0; + } + free() { + this._instance.free(); + } + decrypt(data, p, dataLen) { + // `data` === encrypted data + + while (p < dataLen) { + // Read packet length + if (this._lenPos < 4) { + let nb = Math.min(4 - this._lenPos, dataLen - p); + while (nb--) + this._lenBuf[this._lenPos++] = data[p++]; + if (this._lenPos < 4) + return; + + this._len = this._instance.decryptLen(this._lenBuf, this.inSeqno); + + if (this._len > MAX_PACKET_SIZE + || this._len < 8 + || (this._len & 7) !== 0) { + throw new Error('Bad packet length'); + } + + if (p >= dataLen) + return; + } + + // Read padding length, payload, and padding + if (this._pktLen < this._len) { + const nb = Math.min(this._len - this._pktLen, dataLen - p); + let encrypted; + if (p !== 0 || nb !== dataLen) + encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb); + else + encrypted = data; + if (nb === this._len) { + this._packet = encrypted; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(encrypted, this._pktLen); + } + p += nb; + this._pktLen += nb; + if (this._pktLen < this._len || p >= dataLen) + return; + } + + // Read Poly1305 MAC + { + const nb = Math.min(16 - this._macPos, dataLen - p); + // TODO: avoid copying if entire MAC is in current chunk + if (p !== 0 || nb !== dataLen) { + this._mac.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._macPos + ); + } else { + this._mac.set(data, this._macPos); + } + p += nb; + this._macPos += nb; + if (this._macPos < 16) + return; + } + + this._instance.decrypt(this._packet, this._mac, this.inSeqno); + + const payload = new FastBuffer(this._packet.buffer, + this._packet.byteOffset + 1, + this._packet.length - this._packet[0] - 1); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + this._len = 0; + this._lenPos = 0; + this._packet = null; + this._pktLen = 0; + this._macPos = 0; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +class AESGCMDecipherNative { + constructor(config) { + const dec = config.inbound; + this.inSeqno = dec.seqno; + this._onPayload = dec.onPayload; + this._decipherInstance = null; + this._decipherSSLName = dec.decipherInfo.sslName; + this._decipherKey = dec.decipherKey; + this._decipherIV = dec.decipherIV; + this._len = 0; + this._lenBytes = 0; + this._packet = null; + this._packetPos = 0; + this._pktLen = 0; + this._tag = Buffer.allocUnsafe(16); + this._tagPos = 0; + } + free() {} + decrypt(data, p, dataLen) { + // `data` === encrypted data + + while (p < dataLen) { + // Read packet length (unencrypted, but AAD) + if (this._lenBytes < 4) { + let nb = Math.min(4 - this._lenBytes, dataLen - p); + this._lenBytes += nb; + while (nb--) + this._len = (this._len << 8) + data[p++]; + if (this._lenBytes < 4) + return; + + if ((this._len + 20) > MAX_PACKET_SIZE + || this._len < 16 + || (this._len & 15) !== 0) { + throw new Error('Bad packet length'); + } + + this._decipherInstance = createDecipheriv( + this._decipherSSLName, + this._decipherKey, + this._decipherIV + ); + this._decipherInstance.setAutoPadding(false); + this._decipherInstance.setAAD(intToBytes(this._len)); + } + + // Read padding length, payload, and padding + if (this._pktLen < this._len) { + if (p >= dataLen) + return; + const nb = Math.min(this._len - this._pktLen, dataLen - p); + let decrypted; + if (p !== 0 || nb !== dataLen) { + decrypted = this._decipherInstance.update( + new Uint8Array(data.buffer, data.byteOffset + p, nb) + ); + } else { + decrypted = this._decipherInstance.update(data); + } + if (decrypted.length) { + if (nb === this._len) { + this._packet = decrypted; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(decrypted, this._packetPos); + } + this._packetPos += decrypted.length; + } + p += nb; + this._pktLen += nb; + if (this._pktLen < this._len || p >= dataLen) + return; + } + + // Read authentication tag + { + const nb = Math.min(16 - this._tagPos, dataLen - p); + if (p !== 0 || nb !== dataLen) { + this._tag.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._tagPos + ); + } else { + this._tag.set(data, this._tagPos); + } + p += nb; + this._tagPos += nb; + if (this._tagPos < 16) + return; + } + + { + // Verify authentication tag + this._decipherInstance.setAuthTag(this._tag); + + const decrypted = this._decipherInstance.final(); + + // XXX: this should never output any data since stream ciphers always + // return data from .update() and block ciphers must end on a multiple + // of the block length, which would have caused an exception to be + // thrown if the total input was not... + if (decrypted.length) { + if (this._packet) + this._packet.set(decrypted, this._packetPos); + else + this._packet = decrypted; + } + } + + const payload = (!this._packet + ? EMPTY_BUFFER + : new FastBuffer(this._packet.buffer, + this._packet.byteOffset + 1, + this._packet.length + - this._packet[0] - 1)); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + ivIncrement(this._decipherIV); + this._len = 0; + this._lenBytes = 0; + this._packet = null; + this._packetPos = 0; + this._pktLen = 0; + this._tagPos = 0; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +class AESGCMDecipherBinding { + constructor(config) { + const dec = config.inbound; + this.inSeqno = dec.seqno; + this._onPayload = dec.onPayload; + this._instance = new AESGCMDecipher(dec.decipherInfo.sslName, + dec.decipherKey, + dec.decipherIV); + this._len = 0; + this._lenBytes = 0; + this._packet = null; + this._pktLen = 0; + this._tag = Buffer.allocUnsafe(16); + this._tagPos = 0; + } + free() {} + decrypt(data, p, dataLen) { + // `data` === encrypted data + + while (p < dataLen) { + // Read packet length (unencrypted, but AAD) + if (this._lenBytes < 4) { + let nb = Math.min(4 - this._lenBytes, dataLen - p); + this._lenBytes += nb; + while (nb--) + this._len = (this._len << 8) + data[p++]; + if (this._lenBytes < 4) + return; + + if ((this._len + 20) > MAX_PACKET_SIZE + || this._len < 16 + || (this._len & 15) !== 0) { + throw new Error(`Bad packet length: ${this._len}`); + } + } + + // Read padding length, payload, and padding + if (this._pktLen < this._len) { + if (p >= dataLen) + return; + const nb = Math.min(this._len - this._pktLen, dataLen - p); + let encrypted; + if (p !== 0 || nb !== dataLen) + encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb); + else + encrypted = data; + if (nb === this._len) { + this._packet = encrypted; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(encrypted, this._pktLen); + } + p += nb; + this._pktLen += nb; + if (this._pktLen < this._len || p >= dataLen) + return; + } + + // Read authentication tag + { + const nb = Math.min(16 - this._tagPos, dataLen - p); + if (p !== 0 || nb !== dataLen) { + this._tag.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._tagPos + ); + } else { + this._tag.set(data, this._tagPos); + } + p += nb; + this._tagPos += nb; + if (this._tagPos < 16) + return; + } + + this._instance.decrypt(this._packet, this._len, this._tag); + + const payload = new FastBuffer(this._packet.buffer, + this._packet.byteOffset + 1, + this._packet.length - this._packet[0] - 1); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + this._len = 0; + this._lenBytes = 0; + this._packet = null; + this._pktLen = 0; + this._tagPos = 0; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +// TODO: test incremental .update()s vs. copying to _packet and doing a single +// .update() after entire packet read -- a single .update() would allow +// verifying MAC before decrypting for ETM MACs +class GenericDecipherNative { + constructor(config) { + const dec = config.inbound; + this.inSeqno = dec.seqno; + this._onPayload = dec.onPayload; + this._decipherInstance = createDecipheriv(dec.decipherInfo.sslName, + dec.decipherKey, + dec.decipherIV); + this._decipherInstance.setAutoPadding(false); + this._block = Buffer.allocUnsafe( + dec.macInfo.isETM ? 4 : dec.decipherInfo.blockLen + ); + this._blockSize = dec.decipherInfo.blockLen; + this._blockPos = 0; + this._len = 0; + this._packet = null; + this._packetPos = 0; + this._pktLen = 0; + this._mac = Buffer.allocUnsafe(dec.macInfo.actualLen); + this._macPos = 0; + this._macSSLName = dec.macInfo.sslName; + this._macKey = dec.macKey; + this._macActualLen = dec.macInfo.actualLen; + this._macETM = dec.macInfo.isETM; + this._macInstance = null; + + const discardLen = dec.decipherInfo.discardLen; + if (discardLen) { + let discard = DISCARD_CACHE.get(discardLen); + if (discard === undefined) { + discard = Buffer.alloc(discardLen); + DISCARD_CACHE.set(discardLen, discard); + } + this._decipherInstance.update(discard); + } + } + free() {} + decrypt(data, p, dataLen) { + // `data` === encrypted data + + while (p < dataLen) { + // Read first encrypted block + if (this._blockPos < this._block.length) { + const nb = Math.min(this._block.length - this._blockPos, dataLen - p); + if (p !== 0 || nb !== dataLen || nb < data.length) { + this._block.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._blockPos + ); + } else { + this._block.set(data, this._blockPos); + } + + p += nb; + this._blockPos += nb; + if (this._blockPos < this._block.length) + return; + + let decrypted; + let need; + if (this._macETM) { + this._len = need = readUInt32BE(this._block, 0); + } else { + // Decrypt first block to get packet length + decrypted = this._decipherInstance.update(this._block); + this._len = readUInt32BE(decrypted, 0); + need = 4 + this._len - this._blockSize; + } + + if (this._len > MAX_PACKET_SIZE + || this._len < 5 + || (need & (this._blockSize - 1)) !== 0) { + throw new Error('Bad packet length'); + } + + // Create MAC up front to calculate in parallel with decryption + this._macInstance = createHmac(this._macSSLName, this._macKey); + + writeUInt32BE(BUF_INT, this.inSeqno, 0); + this._macInstance.update(BUF_INT); + if (this._macETM) { + this._macInstance.update(this._block); + } else { + this._macInstance.update(new Uint8Array(decrypted.buffer, + decrypted.byteOffset, + 4)); + this._pktLen = decrypted.length - 4; + this._packetPos = this._pktLen; + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set( + new Uint8Array(decrypted.buffer, + decrypted.byteOffset + 4, + this._packetPos), + 0 + ); + } + + if (p >= dataLen) + return; + } + + // Read padding length, payload, and padding + if (this._pktLen < this._len) { + const nb = Math.min(this._len - this._pktLen, dataLen - p); + let encrypted; + if (p !== 0 || nb !== dataLen) + encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb); + else + encrypted = data; + if (this._macETM) + this._macInstance.update(encrypted); + const decrypted = this._decipherInstance.update(encrypted); + if (decrypted.length) { + if (nb === this._len) { + this._packet = decrypted; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(decrypted, this._packetPos); + } + this._packetPos += decrypted.length; + } + p += nb; + this._pktLen += nb; + if (this._pktLen < this._len || p >= dataLen) + return; + } + + // Read MAC + { + const nb = Math.min(this._macActualLen - this._macPos, dataLen - p); + if (p !== 0 || nb !== dataLen) { + this._mac.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._macPos + ); + } else { + this._mac.set(data, this._macPos); + } + p += nb; + this._macPos += nb; + if (this._macPos < this._macActualLen) + return; + } + + // Verify MAC + if (!this._macETM) + this._macInstance.update(this._packet); + let calculated = this._macInstance.digest(); + if (this._macActualLen < calculated.length) { + calculated = new Uint8Array(calculated.buffer, + calculated.byteOffset, + this._macActualLen); + } + if (!timingSafeEquals(calculated, this._mac)) + throw new Error('Invalid MAC'); + + const payload = new FastBuffer(this._packet.buffer, + this._packet.byteOffset + 1, + this._packet.length - this._packet[0] - 1); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + this._blockPos = 0; + this._len = 0; + this._packet = null; + this._packetPos = 0; + this._pktLen = 0; + this._macPos = 0; + this._macInstance = null; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +class GenericDecipherBinding { + constructor(config) { + const dec = config.inbound; + this.inSeqno = dec.seqno; + this._onPayload = dec.onPayload; + this._instance = new GenericDecipher(dec.decipherInfo.sslName, + dec.decipherKey, + dec.decipherIV, + dec.macInfo.sslName, + dec.macKey, + dec.macInfo.isETM, + dec.macInfo.actualLen); + this._block = Buffer.allocUnsafe( + dec.macInfo.isETM || dec.decipherInfo.stream + ? 4 + : dec.decipherInfo.blockLen + ); + this._blockPos = 0; + this._len = 0; + this._packet = null; + this._pktLen = 0; + this._mac = Buffer.allocUnsafe(dec.macInfo.actualLen); + this._macPos = 0; + this._macActualLen = dec.macInfo.actualLen; + this._macETM = dec.macInfo.isETM; + } + free() { + this._instance.free(); + } + decrypt(data, p, dataLen) { + // `data` === encrypted data + + while (p < dataLen) { + // Read first encrypted block + if (this._blockPos < this._block.length) { + const nb = Math.min(this._block.length - this._blockPos, dataLen - p); + if (p !== 0 || nb !== dataLen || nb < data.length) { + this._block.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._blockPos + ); + } else { + this._block.set(data, this._blockPos); + } + + p += nb; + this._blockPos += nb; + if (this._blockPos < this._block.length) + return; + + let need; + if (this._macETM) { + this._len = need = readUInt32BE(this._block, 0); + } else { + // Decrypt first block to get packet length + this._instance.decryptBlock(this._block); + this._len = readUInt32BE(this._block, 0); + need = 4 + this._len - this._block.length; + } + + if (this._len > MAX_PACKET_SIZE + || this._len < 5 + || (need & (this._block.length - 1)) !== 0) { + throw new Error('Bad packet length'); + } + + if (!this._macETM) { + this._pktLen = (this._block.length - 4); + if (this._pktLen) { + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set( + new Uint8Array(this._block.buffer, + this._block.byteOffset + 4, + this._pktLen), + 0 + ); + } + } + + if (p >= dataLen) + return; + } + + // Read padding length, payload, and padding + if (this._pktLen < this._len) { + const nb = Math.min(this._len - this._pktLen, dataLen - p); + let encrypted; + if (p !== 0 || nb !== dataLen) + encrypted = new Uint8Array(data.buffer, data.byteOffset + p, nb); + else + encrypted = data; + if (nb === this._len) { + this._packet = encrypted; + } else { + if (!this._packet) + this._packet = Buffer.allocUnsafe(this._len); + this._packet.set(encrypted, this._pktLen); + } + p += nb; + this._pktLen += nb; + if (this._pktLen < this._len || p >= dataLen) + return; + } + + // Read MAC + { + const nb = Math.min(this._macActualLen - this._macPos, dataLen - p); + if (p !== 0 || nb !== dataLen) { + this._mac.set( + new Uint8Array(data.buffer, data.byteOffset + p, nb), + this._macPos + ); + } else { + this._mac.set(data, this._macPos); + } + p += nb; + this._macPos += nb; + if (this._macPos < this._macActualLen) + return; + } + + // Decrypt and verify MAC + this._instance.decrypt(this._packet, + this.inSeqno, + this._block, + this._mac); + + const payload = new FastBuffer(this._packet.buffer, + this._packet.byteOffset + 1, + this._packet.length - this._packet[0] - 1); + + // Prepare for next packet + this.inSeqno = (this.inSeqno + 1) >>> 0; + this._blockPos = 0; + this._len = 0; + this._packet = null; + this._pktLen = 0; + this._macPos = 0; + this._macInstance = null; + + { + const ret = this._onPayload(payload); + if (ret !== undefined) + return (ret === false ? p : ret); + } + } + } +} + +// Increments unsigned, big endian counter (last 8 bytes) of AES-GCM IV +function ivIncrement(iv) { + // eslint-disable-next-line no-unused-expressions + ++iv[11] >>> 8 + && ++iv[10] >>> 8 + && ++iv[9] >>> 8 + && ++iv[8] >>> 8 + && ++iv[7] >>> 8 + && ++iv[6] >>> 8 + && ++iv[5] >>> 8 + && ++iv[4] >>> 8; +} + +const intToBytes = (() => { + const ret = Buffer.alloc(4); + return (n) => { + ret[0] = (n >>> 24); + ret[1] = (n >>> 16); + ret[2] = (n >>> 8); + ret[3] = n; + return ret; + }; +})(); + +function timingSafeEquals(a, b) { + if (a.length !== b.length) { + timingSafeEqual(a, a); + return false; + } + return timingSafeEqual(a, b); +} + +function createCipher(config) { + if (typeof config !== 'object' || config === null) + throw new Error('Invalid config'); + + if (typeof config.outbound !== 'object' || config.outbound === null) + throw new Error('Invalid outbound'); + + const outbound = config.outbound; + + if (typeof outbound.onWrite !== 'function') + throw new Error('Invalid outbound.onWrite'); + + if (typeof outbound.cipherInfo !== 'object' || outbound.cipherInfo === null) + throw new Error('Invalid outbound.cipherInfo'); + + if (!Buffer.isBuffer(outbound.cipherKey) + || outbound.cipherKey.length !== outbound.cipherInfo.keyLen) { + throw new Error('Invalid outbound.cipherKey'); + } + + if (outbound.cipherInfo.ivLen + && (!Buffer.isBuffer(outbound.cipherIV) + || outbound.cipherIV.length !== outbound.cipherInfo.ivLen)) { + throw new Error('Invalid outbound.cipherIV'); + } + + if (typeof outbound.seqno !== 'number' + || outbound.seqno < 0 + || outbound.seqno > MAX_SEQNO) { + throw new Error('Invalid outbound.seqno'); + } + + const forceNative = !!outbound.forceNative; + + switch (outbound.cipherInfo.sslName) { + case 'aes-128-gcm': + case 'aes-256-gcm': + return (AESGCMCipher && !forceNative + ? new AESGCMCipherBinding(config) + : new AESGCMCipherNative(config)); + case 'chacha20': + return (ChaChaPolyCipher && !forceNative + ? new ChaChaPolyCipherBinding(config) + : new ChaChaPolyCipherNative(config)); + default: { + if (typeof outbound.macInfo !== 'object' || outbound.macInfo === null) + throw new Error('Invalid outbound.macInfo'); + if (!Buffer.isBuffer(outbound.macKey) + || outbound.macKey.length !== outbound.macInfo.len) { + throw new Error('Invalid outbound.macKey'); + } + return (GenericCipher && !forceNative + ? new GenericCipherBinding(config) + : new GenericCipherNative(config)); + } + } +} + +function createDecipher(config) { + if (typeof config !== 'object' || config === null) + throw new Error('Invalid config'); + + if (typeof config.inbound !== 'object' || config.inbound === null) + throw new Error('Invalid inbound'); + + const inbound = config.inbound; + + if (typeof inbound.onPayload !== 'function') + throw new Error('Invalid inbound.onPayload'); + + if (typeof inbound.decipherInfo !== 'object' + || inbound.decipherInfo === null) { + throw new Error('Invalid inbound.decipherInfo'); + } + + if (!Buffer.isBuffer(inbound.decipherKey) + || inbound.decipherKey.length !== inbound.decipherInfo.keyLen) { + throw new Error('Invalid inbound.decipherKey'); + } + + if (inbound.decipherInfo.ivLen + && (!Buffer.isBuffer(inbound.decipherIV) + || inbound.decipherIV.length !== inbound.decipherInfo.ivLen)) { + throw new Error('Invalid inbound.decipherIV'); + } + + if (typeof inbound.seqno !== 'number' + || inbound.seqno < 0 + || inbound.seqno > MAX_SEQNO) { + throw new Error('Invalid inbound.seqno'); + } + + const forceNative = !!inbound.forceNative; + + switch (inbound.decipherInfo.sslName) { + case 'aes-128-gcm': + case 'aes-256-gcm': + return (AESGCMDecipher && !forceNative + ? new AESGCMDecipherBinding(config) + : new AESGCMDecipherNative(config)); + case 'chacha20': + return (ChaChaPolyDecipher && !forceNative + ? new ChaChaPolyDecipherBinding(config) + : new ChaChaPolyDecipherNative(config)); + default: { + if (typeof inbound.macInfo !== 'object' || inbound.macInfo === null) + throw new Error('Invalid inbound.macInfo'); + if (!Buffer.isBuffer(inbound.macKey) + || inbound.macKey.length !== inbound.macInfo.len) { + throw new Error('Invalid inbound.macKey'); + } + return (GenericDecipher && !forceNative + ? new GenericDecipherBinding(config) + : new GenericDecipherNative(config)); + } + } +} + +module.exports = { + CIPHER_INFO, + MAC_INFO, + bindingAvailable: !!binding, + init: (() => { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + try { + POLY1305_WASM_MODULE = await require('./crypto/poly1305.js')(); + POLY1305_RESULT_MALLOC = POLY1305_WASM_MODULE._malloc(16); + poly1305_auth = POLY1305_WASM_MODULE.cwrap( + 'poly1305_auth', + null, + ['number', 'array', 'number', 'array', 'number', 'array'] + ); + } catch (ex) { + return reject(ex); + } + resolve(); + }); + })(), + + NullCipher, + createCipher, + NullDecipher, + createDecipher, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/binding.gyp b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/binding.gyp new file mode 100644 index 0000000..236a25f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/binding.gyp @@ -0,0 +1,23 @@ +{ + 'variables': { + 'real_openssl_major%': '0', + }, + 'targets': [ + { + 'target_name': 'sshcrypto', + 'include_dirs': [ + "> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) -o $@ $< $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) -o $@ $< $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") + +quiet_cmd_symlink = SYMLINK $@ +cmd_symlink = ln -sf "$<" "$@" + +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) + +# Due to circular dependencies between libraries :(, we wrap the +# special "figure out circular dependencies" flags around the entire +# input list during linking. +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) -o $@ $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,--start-group $(LD_INPUTS) $(LIBS) -Wl,--end-group + +# Note: this does not handle spaces in paths +define xargs + $(1) $(word 1,$(2)) +$(if $(word 2,$(2)),$(call xargs,$(1),$(wordlist 2,$(words $(2)),$(2)))) +endef + +define write-to-file + @: >$(1) +$(call xargs,@printf "%s\n" >>$(1),$(2)) +endef + +OBJ_FILE_LIST := ar-file-list + +define create_archive + rm -f $(1) $(1).$(OBJ_FILE_LIST); mkdir -p `dirname $(1)` + $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2))) + $(AR.$(TOOLSET)) crs $(1) @$(1).$(OBJ_FILE_LIST) +endef + +define create_thin_archive + rm -f $(1) $(OBJ_FILE_LIST); mkdir -p `dirname $(1)` + $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2))) + $(AR.$(TOOLSET)) crsT $(1) @$(1).$(OBJ_FILE_LIST) +endef + +# We support two kinds of shared objects (.so): +# 1) shared_library, which is just bundling together many dependent libraries +# into a link line. +# 2) loadable_module, which is generating a module intended for dlopen(). +# +# They differ only slightly: +# In the former case, we want to package all dependent code into the .so. +# In the latter case, we want to package just the API exposed by the +# outermost module. +# This means shared_library uses --whole-archive, while loadable_module doesn't. +# (Note that --whole-archive is incompatible with the --start-group used in +# normal linking.) + +# Other shared-object link notes: +# - Set SONAME to the library filename so our binaries don't reference +# the local, absolute paths used on the link command-line. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 1,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,sshcrypto.target.mk)))),) + include sshcrypto.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = cd $(srcdir); /usr/local/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/home/node/.cache/node-gyp/24.14.0" "-Dnode_gyp_dir=/usr/local/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/home/node/.cache/node-gyp/24.14.0/<(target_arch)/node.lib" "-Dmodule_root_dir=/home/node/.openclaw/workspace/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/home/node/.openclaw/workspace/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/config.gypi -I/usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/home/node/.cache/node-gyp/24.14.0/include/node/common.gypi "--toplevel-dir=." binding.gyp +Makefile: $(srcdir)/../../../../../../../../../../../../usr/local/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/../../../../../../../../../../.cache/node-gyp/24.14.0/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/binding.Makefile b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/binding.Makefile new file mode 100644 index 0000000..64db433 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= ./build/. +.PHONY: all +all: + $(MAKE) sshcrypto diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/config.gypi b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/config.gypi new file mode 100644 index 0000000..8a01439 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/config.gypi @@ -0,0 +1,532 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "variables": { + "use_ccache_win": 0, + "clang": 0, + "llvm_version": "0.0", + "gas_version": "2.38", + "node_prefix": "/", + "node_install_npm": "true", + "node_install_corepack": "true", + "control_flow_guard": "false", + "node_use_amaro": "true", + "debug_node": "false", + "error_on_warn": "false", + "suppress_all_error_on_warn": "false", + "use_prefix_to_find_headers": "false", + "host_arch": "x64", + "target_arch": "x64", + "node_byteorder": "little", + "want_separate_host_toolset": 0, + "node_use_node_snapshot": "true", + "node_use_node_code_cache": "true", + "node_write_snapshot_as_array_literals": "false", + "node_enable_v8_vtunejit": "false", + "enable_pgo_generate": "false", + "enable_pgo_use": "false", + "enable_lto": "false", + "single_executable_application": "true", + "node_with_ltcg": "false", + "node_tag": "", + "node_release_urlbase": "https://nodejs.org/download/release/", + "node_debug_lib": "false", + "debug_nghttp2": "false", + "node_no_browser_globals": "false", + "node_shared": "false", + "libdir": "lib", + "node_module_version": 137, + "shlib_suffix": "so.137", + "asan": 0, + "ubsan": 0, + "coverage": "false", + "node_target_type": "executable", + "node_library_files": [ + "lib/_http_agent.js", + "lib/_http_client.js", + "lib/_http_common.js", + "lib/_http_incoming.js", + "lib/_http_outgoing.js", + "lib/_http_server.js", + "lib/_stream_duplex.js", + "lib/_stream_passthrough.js", + "lib/_stream_readable.js", + "lib/_stream_transform.js", + "lib/_stream_wrap.js", + "lib/_stream_writable.js", + "lib/_tls_common.js", + "lib/_tls_wrap.js", + "lib/assert.js", + "lib/assert/strict.js", + "lib/async_hooks.js", + "lib/buffer.js", + "lib/child_process.js", + "lib/cluster.js", + "lib/console.js", + "lib/constants.js", + "lib/crypto.js", + "lib/dgram.js", + "lib/diagnostics_channel.js", + "lib/dns.js", + "lib/dns/promises.js", + "lib/domain.js", + "lib/events.js", + "lib/fs.js", + "lib/fs/promises.js", + "lib/http.js", + "lib/http2.js", + "lib/https.js", + "lib/inspector.js", + "lib/inspector/promises.js", + "lib/internal/abort_controller.js", + "lib/internal/assert.js", + "lib/internal/assert/assertion_error.js", + "lib/internal/assert/calltracker.js", + "lib/internal/assert/myers_diff.js", + "lib/internal/assert/utils.js", + "lib/internal/async_context_frame.js", + "lib/internal/async_hooks.js", + "lib/internal/async_local_storage/async_context_frame.js", + "lib/internal/async_local_storage/async_hooks.js", + "lib/internal/blob.js", + "lib/internal/blocklist.js", + "lib/internal/bootstrap/node.js", + "lib/internal/bootstrap/realm.js", + "lib/internal/bootstrap/shadow_realm.js", + "lib/internal/bootstrap/switches/does_not_own_process_state.js", + "lib/internal/bootstrap/switches/does_own_process_state.js", + "lib/internal/bootstrap/switches/is_main_thread.js", + "lib/internal/bootstrap/switches/is_not_main_thread.js", + "lib/internal/bootstrap/web/exposed-wildcard.js", + "lib/internal/bootstrap/web/exposed-window-or-worker.js", + "lib/internal/buffer.js", + "lib/internal/child_process.js", + "lib/internal/child_process/serialization.js", + "lib/internal/cli_table.js", + "lib/internal/cluster/child.js", + "lib/internal/cluster/primary.js", + "lib/internal/cluster/round_robin_handle.js", + "lib/internal/cluster/shared_handle.js", + "lib/internal/cluster/utils.js", + "lib/internal/cluster/worker.js", + "lib/internal/console/constructor.js", + "lib/internal/console/global.js", + "lib/internal/constants.js", + "lib/internal/crypto/aes.js", + "lib/internal/crypto/argon2.js", + "lib/internal/crypto/certificate.js", + "lib/internal/crypto/cfrg.js", + "lib/internal/crypto/chacha20_poly1305.js", + "lib/internal/crypto/cipher.js", + "lib/internal/crypto/diffiehellman.js", + "lib/internal/crypto/ec.js", + "lib/internal/crypto/hash.js", + "lib/internal/crypto/hashnames.js", + "lib/internal/crypto/hkdf.js", + "lib/internal/crypto/kem.js", + "lib/internal/crypto/keygen.js", + "lib/internal/crypto/keys.js", + "lib/internal/crypto/mac.js", + "lib/internal/crypto/ml_dsa.js", + "lib/internal/crypto/ml_kem.js", + "lib/internal/crypto/pbkdf2.js", + "lib/internal/crypto/random.js", + "lib/internal/crypto/rsa.js", + "lib/internal/crypto/scrypt.js", + "lib/internal/crypto/sig.js", + "lib/internal/crypto/util.js", + "lib/internal/crypto/webcrypto.js", + "lib/internal/crypto/webidl.js", + "lib/internal/crypto/x509.js", + "lib/internal/data_url.js", + "lib/internal/debugger/inspect.js", + "lib/internal/debugger/inspect_client.js", + "lib/internal/debugger/inspect_repl.js", + "lib/internal/dgram.js", + "lib/internal/dns/callback_resolver.js", + "lib/internal/dns/promises.js", + "lib/internal/dns/utils.js", + "lib/internal/encoding.js", + "lib/internal/encoding/single-byte.js", + "lib/internal/encoding/util.js", + "lib/internal/error_serdes.js", + "lib/internal/errors.js", + "lib/internal/errors/error_source.js", + "lib/internal/event_target.js", + "lib/internal/events/abort_listener.js", + "lib/internal/events/symbols.js", + "lib/internal/file.js", + "lib/internal/fixed_queue.js", + "lib/internal/freelist.js", + "lib/internal/freeze_intrinsics.js", + "lib/internal/fs/cp/cp-sync.js", + "lib/internal/fs/cp/cp.js", + "lib/internal/fs/dir.js", + "lib/internal/fs/glob.js", + "lib/internal/fs/promises.js", + "lib/internal/fs/read/context.js", + "lib/internal/fs/recursive_watch.js", + "lib/internal/fs/rimraf.js", + "lib/internal/fs/streams.js", + "lib/internal/fs/sync_write_stream.js", + "lib/internal/fs/utils.js", + "lib/internal/fs/watchers.js", + "lib/internal/heap_utils.js", + "lib/internal/histogram.js", + "lib/internal/http.js", + "lib/internal/http2/compat.js", + "lib/internal/http2/core.js", + "lib/internal/http2/util.js", + "lib/internal/inspector/network.js", + "lib/internal/inspector/network_http.js", + "lib/internal/inspector/network_http2.js", + "lib/internal/inspector/network_resources.js", + "lib/internal/inspector/network_undici.js", + "lib/internal/inspector_async_hook.js", + "lib/internal/inspector_network_tracking.js", + "lib/internal/js_stream_socket.js", + "lib/internal/legacy/processbinding.js", + "lib/internal/linkedlist.js", + "lib/internal/locks.js", + "lib/internal/main/check_syntax.js", + "lib/internal/main/embedding.js", + "lib/internal/main/eval_stdin.js", + "lib/internal/main/eval_string.js", + "lib/internal/main/inspect.js", + "lib/internal/main/mksnapshot.js", + "lib/internal/main/print_help.js", + "lib/internal/main/prof_process.js", + "lib/internal/main/repl.js", + "lib/internal/main/run_main_module.js", + "lib/internal/main/test_runner.js", + "lib/internal/main/watch_mode.js", + "lib/internal/main/worker_thread.js", + "lib/internal/mime.js", + "lib/internal/modules/cjs/loader.js", + "lib/internal/modules/customization_hooks.js", + "lib/internal/modules/esm/assert.js", + "lib/internal/modules/esm/create_dynamic_module.js", + "lib/internal/modules/esm/formats.js", + "lib/internal/modules/esm/get_format.js", + "lib/internal/modules/esm/hooks.js", + "lib/internal/modules/esm/initialize_import_meta.js", + "lib/internal/modules/esm/load.js", + "lib/internal/modules/esm/loader.js", + "lib/internal/modules/esm/module_job.js", + "lib/internal/modules/esm/module_map.js", + "lib/internal/modules/esm/resolve.js", + "lib/internal/modules/esm/shared_constants.js", + "lib/internal/modules/esm/translators.js", + "lib/internal/modules/esm/utils.js", + "lib/internal/modules/esm/worker.js", + "lib/internal/modules/helpers.js", + "lib/internal/modules/package_json_reader.js", + "lib/internal/modules/run_main.js", + "lib/internal/modules/typescript.js", + "lib/internal/navigator.js", + "lib/internal/net.js", + "lib/internal/options.js", + "lib/internal/per_context/domexception.js", + "lib/internal/per_context/messageport.js", + "lib/internal/per_context/primordials.js", + "lib/internal/perf/event_loop_delay.js", + "lib/internal/perf/event_loop_utilization.js", + "lib/internal/perf/nodetiming.js", + "lib/internal/perf/observe.js", + "lib/internal/perf/performance.js", + "lib/internal/perf/performance_entry.js", + "lib/internal/perf/resource_timing.js", + "lib/internal/perf/timerify.js", + "lib/internal/perf/usertiming.js", + "lib/internal/perf/utils.js", + "lib/internal/priority_queue.js", + "lib/internal/process/execution.js", + "lib/internal/process/finalization.js", + "lib/internal/process/per_thread.js", + "lib/internal/process/permission.js", + "lib/internal/process/pre_execution.js", + "lib/internal/process/promises.js", + "lib/internal/process/report.js", + "lib/internal/process/signal.js", + "lib/internal/process/task_queues.js", + "lib/internal/process/warning.js", + "lib/internal/process/worker_thread_only.js", + "lib/internal/promise_hooks.js", + "lib/internal/querystring.js", + "lib/internal/quic/quic.js", + "lib/internal/quic/state.js", + "lib/internal/quic/stats.js", + "lib/internal/quic/symbols.js", + "lib/internal/readline/callbacks.js", + "lib/internal/readline/emitKeypressEvents.js", + "lib/internal/readline/interface.js", + "lib/internal/readline/promises.js", + "lib/internal/readline/utils.js", + "lib/internal/repl.js", + "lib/internal/repl/await.js", + "lib/internal/repl/completion.js", + "lib/internal/repl/history.js", + "lib/internal/repl/utils.js", + "lib/internal/socket_list.js", + "lib/internal/socketaddress.js", + "lib/internal/source_map/prepare_stack_trace.js", + "lib/internal/source_map/source_map.js", + "lib/internal/source_map/source_map_cache.js", + "lib/internal/source_map/source_map_cache_map.js", + "lib/internal/stream_base_commons.js", + "lib/internal/streams/add-abort-signal.js", + "lib/internal/streams/compose.js", + "lib/internal/streams/destroy.js", + "lib/internal/streams/duplex.js", + "lib/internal/streams/duplexify.js", + "lib/internal/streams/duplexpair.js", + "lib/internal/streams/end-of-stream.js", + "lib/internal/streams/fast-utf8-stream.js", + "lib/internal/streams/from.js", + "lib/internal/streams/lazy_transform.js", + "lib/internal/streams/legacy.js", + "lib/internal/streams/operators.js", + "lib/internal/streams/passthrough.js", + "lib/internal/streams/pipeline.js", + "lib/internal/streams/readable.js", + "lib/internal/streams/state.js", + "lib/internal/streams/transform.js", + "lib/internal/streams/utils.js", + "lib/internal/streams/writable.js", + "lib/internal/test/binding.js", + "lib/internal/test/transfer.js", + "lib/internal/test_runner/assert.js", + "lib/internal/test_runner/coverage.js", + "lib/internal/test_runner/harness.js", + "lib/internal/test_runner/mock/loader.js", + "lib/internal/test_runner/mock/mock.js", + "lib/internal/test_runner/mock/mock_timers.js", + "lib/internal/test_runner/reporter/dot.js", + "lib/internal/test_runner/reporter/junit.js", + "lib/internal/test_runner/reporter/lcov.js", + "lib/internal/test_runner/reporter/rerun.js", + "lib/internal/test_runner/reporter/spec.js", + "lib/internal/test_runner/reporter/tap.js", + "lib/internal/test_runner/reporter/utils.js", + "lib/internal/test_runner/reporter/v8-serializer.js", + "lib/internal/test_runner/runner.js", + "lib/internal/test_runner/snapshot.js", + "lib/internal/test_runner/test.js", + "lib/internal/test_runner/tests_stream.js", + "lib/internal/test_runner/utils.js", + "lib/internal/timers.js", + "lib/internal/tls/common.js", + "lib/internal/tls/secure-context.js", + "lib/internal/tls/wrap.js", + "lib/internal/trace_events_async_hooks.js", + "lib/internal/tty.js", + "lib/internal/url.js", + "lib/internal/util.js", + "lib/internal/util/colors.js", + "lib/internal/util/comparisons.js", + "lib/internal/util/debuglog.js", + "lib/internal/util/diff.js", + "lib/internal/util/inspect.js", + "lib/internal/util/inspector.js", + "lib/internal/util/parse_args/parse_args.js", + "lib/internal/util/parse_args/utils.js", + "lib/internal/util/trace_sigint.js", + "lib/internal/util/types.js", + "lib/internal/v8/startup_snapshot.js", + "lib/internal/v8_prof_polyfill.js", + "lib/internal/v8_prof_processor.js", + "lib/internal/validators.js", + "lib/internal/vm.js", + "lib/internal/vm/module.js", + "lib/internal/wasm_web_api.js", + "lib/internal/watch_mode/files_watcher.js", + "lib/internal/watchdog.js", + "lib/internal/webidl.js", + "lib/internal/webstorage.js", + "lib/internal/webstreams/adapters.js", + "lib/internal/webstreams/compression.js", + "lib/internal/webstreams/encoding.js", + "lib/internal/webstreams/queuingstrategies.js", + "lib/internal/webstreams/readablestream.js", + "lib/internal/webstreams/transfer.js", + "lib/internal/webstreams/transformstream.js", + "lib/internal/webstreams/util.js", + "lib/internal/webstreams/writablestream.js", + "lib/internal/worker.js", + "lib/internal/worker/clone_dom_exception.js", + "lib/internal/worker/io.js", + "lib/internal/worker/js_transferable.js", + "lib/internal/worker/messaging.js", + "lib/module.js", + "lib/net.js", + "lib/os.js", + "lib/path.js", + "lib/path/posix.js", + "lib/path/win32.js", + "lib/perf_hooks.js", + "lib/process.js", + "lib/punycode.js", + "lib/querystring.js", + "lib/quic.js", + "lib/readline.js", + "lib/readline/promises.js", + "lib/repl.js", + "lib/sea.js", + "lib/sqlite.js", + "lib/stream.js", + "lib/stream/consumers.js", + "lib/stream/promises.js", + "lib/stream/web.js", + "lib/string_decoder.js", + "lib/sys.js", + "lib/test.js", + "lib/test/reporters.js", + "lib/timers.js", + "lib/timers/promises.js", + "lib/tls.js", + "lib/trace_events.js", + "lib/tty.js", + "lib/url.js", + "lib/util.js", + "lib/util/types.js", + "lib/v8.js", + "lib/vm.js", + "lib/wasi.js", + "lib/worker_threads.js", + "lib/zlib.js" + ], + "node_cctest_sources": [ + "src/node_snapshot_stub.cc", + "test/cctest/inspector/test_network_requests_buffer.cc", + "test/cctest/inspector/test_node_protocol.cc", + "test/cctest/node_test_fixture.cc", + "test/cctest/test_aliased_buffer.cc", + "test/cctest/test_base64.cc", + "test/cctest/test_base_object_ptr.cc", + "test/cctest/test_cppgc.cc", + "test/cctest/test_crypto_clienthello.cc", + "test/cctest/test_dataqueue.cc", + "test/cctest/test_environment.cc", + "test/cctest/test_inspector_socket.cc", + "test/cctest/test_inspector_socket_server.cc", + "test/cctest/test_json_utils.cc", + "test/cctest/test_linked_binding.cc", + "test/cctest/test_lru_cache.cc", + "test/cctest/test_node_api.cc", + "test/cctest/test_node_crypto.cc", + "test/cctest/test_node_crypto_env.cc", + "test/cctest/test_node_postmortem_metadata.cc", + "test/cctest/test_node_task_runner.cc", + "test/cctest/test_path.cc", + "test/cctest/test_per_process.cc", + "test/cctest/test_platform.cc", + "test/cctest/test_quic_cid.cc", + "test/cctest/test_quic_error.cc", + "test/cctest/test_quic_tokens.cc", + "test/cctest/test_report.cc", + "test/cctest/test_sockaddr.cc", + "test/cctest/test_string_bytes.cc", + "test/cctest/test_traced_value.cc", + "test/cctest/test_util.cc", + "test/cctest/node_test_fixture.h" + ], + "napi_build_version": "10", + "node_shared_zlib": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_ada": "false", + "node_shared_simdjson": "false", + "node_shared_simdutf": "false", + "node_shared_brotli": "false", + "node_shared_cares": "false", + "node_shared_gtest": "false", + "node_shared_hdr_histogram": "false", + "node_shared_merve": "false", + "node_shared_nbytes": "false", + "node_shared_nghttp2": "false", + "node_shared_nghttp3": "false", + "node_shared_ngtcp2": "false", + "node_use_sqlite": "true", + "node_shared_sqlite": "false", + "node_shared_uvwasi": "false", + "node_shared_zstd": "false", + "v8_enable_webassembly": 1, + "v8_enable_javascript_promise_hooks": 1, + "v8_enable_lite_mode": 0, + "v8_enable_gdbjit": 0, + "v8_optimized_debug": 1, + "dcheck_always_on": 0, + "v8_enable_object_print": 1, + "v8_random_seed": 0, + "v8_promise_internal_field_count": 1, + "v8_use_siphash": 1, + "v8_enable_maglev": 1, + "v8_enable_pointer_compression": 0, + "v8_enable_sandbox": 0, + "v8_enable_pointer_compression_shared_cage": 0, + "v8_enable_external_code_space": 0, + "v8_enable_31bit_smis_on_64bit_arch": 0, + "v8_enable_extensible_ro_snapshot": 0, + "v8_trace_maps": 0, + "node_use_v8_platform": "true", + "node_use_bundled_v8": "true", + "force_dynamic_crt": 0, + "node_enable_d8": "false", + "node_enable_v8windbg": "false", + "v8_enable_hugepage": 0, + "v8_enable_short_builtin_calls": 1, + "v8_enable_wasm_simd256_revec": 1, + "node_use_openssl": "true", + "node_shared_openssl": "false", + "openssl_is_fips": "false", + "node_quic": "false", + "node_fipsinstall": "false", + "node_without_node_options": "false", + "openssl_quic": "false", + "icu_small": "false", + "v8_enable_i18n_support": 1, + "icu_gyp_path": "tools/icu/icu-generic.gyp", + "icu_path": "deps/icu-small", + "icu_ver_major": "78", + "icu_endianness": "l", + "icu_data_in": "../../deps/icu-tmp/icudt78l.dat", + "v8_enable_inspector": 1, + "node_section_ordering_info": "", + "node_builtin_shareable_builtins": [ + "deps/undici/undici.js", + "deps/amaro/dist/index.js" + ], + "ossfuzz": "false", + "nodedir": "/home/node/.cache/node-gyp/24.14.0", + "python": "/usr/bin/python3", + "standalone_static_library": 1, + "target": "v24.14.0", + "real_openssl_major": "3", + "global_prefix": "/usr/local", + "init_module": "/home/node/.npm-init.js", + "globalconfig": "/usr/local/etc/npmrc", + "node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", + "cache": "/home/node/.npm", + "npm_version": "11.9.0", + "prefix": "/usr/local", + "local_prefix": "/home/node/.openclaw/workspace/tasks/enduro-trails/prototype", + "userconfig": "/home/node/.npmrc", + "user_agent": "npm/11.9.0 node/v24.14.0 linux x64 workspaces/false" + }, + "target_defaults": { + "include_dirs": [], + "libraries": [], + "defines": [], + "cflags": [], + "default_configuration": "Release", + "configurations": { + "Release": { + "variables": {}, + "v8_enable_v8_checks": 1 + }, + "Debug": { + "variables": {}, + "v8_enable_v8_checks": 0 + } + } + } +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk new file mode 100644 index 0000000..4a329c5 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk @@ -0,0 +1,164 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := sshcrypto +DEFS_Debug := \ + '-DNODE_GYP_MODULE_NAME=sshcrypto' \ + '-DUSING_UV_SHARED=1' \ + '-DUSING_V8_SHARED=1' \ + '-DV8_DEPRECATION_WARNINGS=1' \ + '-D_GLIBCXX_USE_CXX11_ABI=1' \ + '-D_FILE_OFFSET_BITS=64' \ + '-D_LARGEFILE_SOURCE' \ + '-D__STDC_FORMAT_MACROS' \ + '-DOPENSSL_NO_PINSHARED' \ + '-DOPENSSL_THREADS' \ + '-DOPENSSL_API_COMPAT=0x10100000L' \ + '-DREAL_OPENSSL_MAJOR=3' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -fPIC \ + -pthread \ + -Wall \ + -Wextra \ + -Wno-unused-parameter \ + -O3 \ + -m64 \ + -g \ + -O0 + +# Flags passed to only C files. +CFLAGS_C_Debug := + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -fno-rtti \ + -fno-exceptions \ + -fno-strict-aliasing \ + -std=gnu++20 + +INCS_Debug := \ + -I/home/node/.cache/node-gyp/24.14.0/include/node \ + -I/home/node/.cache/node-gyp/24.14.0/src \ + -I/home/node/.cache/node-gyp/24.14.0/deps/openssl/config \ + -I/home/node/.cache/node-gyp/24.14.0/deps/openssl/openssl/include \ + -I/home/node/.cache/node-gyp/24.14.0/deps/uv/include \ + -I/home/node/.cache/node-gyp/24.14.0/deps/zlib \ + -I/home/node/.cache/node-gyp/24.14.0/deps/v8/include \ + -I$(srcdir)/../../../../nan + +DEFS_Release := \ + '-DNODE_GYP_MODULE_NAME=sshcrypto' \ + '-DUSING_UV_SHARED=1' \ + '-DUSING_V8_SHARED=1' \ + '-DV8_DEPRECATION_WARNINGS=1' \ + '-D_GLIBCXX_USE_CXX11_ABI=1' \ + '-D_FILE_OFFSET_BITS=64' \ + '-D_LARGEFILE_SOURCE' \ + '-D__STDC_FORMAT_MACROS' \ + '-DOPENSSL_NO_PINSHARED' \ + '-DOPENSSL_THREADS' \ + '-DOPENSSL_API_COMPAT=0x10100000L' \ + '-DREAL_OPENSSL_MAJOR=3' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -fPIC \ + -pthread \ + -Wall \ + -Wextra \ + -Wno-unused-parameter \ + -O3 \ + -m64 \ + -O3 \ + -fno-omit-frame-pointer + +# Flags passed to only C files. +CFLAGS_C_Release := + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -fno-rtti \ + -fno-exceptions \ + -fno-strict-aliasing \ + -std=gnu++20 + +INCS_Release := \ + -I/home/node/.cache/node-gyp/24.14.0/include/node \ + -I/home/node/.cache/node-gyp/24.14.0/src \ + -I/home/node/.cache/node-gyp/24.14.0/deps/openssl/config \ + -I/home/node/.cache/node-gyp/24.14.0/deps/openssl/openssl/include \ + -I/home/node/.cache/node-gyp/24.14.0/deps/uv/include \ + -I/home/node/.cache/node-gyp/24.14.0/deps/zlib \ + -I/home/node/.cache/node-gyp/24.14.0/deps/v8/include \ + -I$(srcdir)/../../../../nan + +OBJS := \ + $(obj).target/$(TARGET)/src/binding.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -pthread \ + -rdynamic \ + -m64 + +LDFLAGS_Release := \ + -pthread \ + -rdynamic \ + -m64 + +LIBS := + +$(obj).target/sshcrypto.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/sshcrypto.node: LIBS := $(LIBS) +$(obj).target/sshcrypto.node: TOOLSET := $(TOOLSET) +$(obj).target/sshcrypto.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(obj).target/sshcrypto.node +# Add target alias +.PHONY: sshcrypto +sshcrypto: $(builddir)/sshcrypto.node + +# Copy this to the executable output path. +$(builddir)/sshcrypto.node: TOOLSET := $(TOOLSET) +$(builddir)/sshcrypto.node: $(obj).target/sshcrypto.node FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/sshcrypto.node +# Short alias for building this executable. +.PHONY: sshcrypto.node +sshcrypto.node: $(obj).target/sshcrypto.node $(builddir)/sshcrypto.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/sshcrypto.node + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/poly1305.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/poly1305.js new file mode 100644 index 0000000..a6953fe --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/crypto/poly1305.js @@ -0,0 +1,43 @@ + +var createPoly1305 = (function() { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; + return ( +function(createPoly1305) { + createPoly1305 = createPoly1305 || {}; + + +var b;b||(b=typeof createPoly1305 !== 'undefined' ? createPoly1305 : {});var q,r;b.ready=new Promise(function(a,c){q=a;r=c});var u={},w;for(w in b)b.hasOwnProperty(w)&&(u[w]=b[w]);var x="object"===typeof window,y="function"===typeof importScripts,z="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node,B="",C,D,E,F,G; +if(z)B=y?require("path").dirname(B)+"/":__dirname+"/",C=function(a,c){var d=H(a);if(d)return c?d:d.toString();F||(F=require("fs"));G||(G=require("path"));a=G.normalize(a);return F.readFileSync(a,c?null:"utf8")},E=function(a){a=C(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a},D=function(a,c,d){var e=H(a);e&&c(e);F||(F=require("fs"));G||(G=require("path"));a=G.normalize(a);F.readFile(a,function(f,l){f?d(f):c(l.buffer)})},1=m){var oa=g.charCodeAt(++v);m=65536+((m&1023)<<10)|oa&1023}if(127>=m){if(k>=n)break;h[k++]=m}else{if(2047>=m){if(k+1>=n)break;h[k++]=192|m>>6}else{if(65535>=m){if(k+2>=n)break;h[k++]=224|m>>12}else{if(k+3>=n)break;h[k++]=240|m>>18;h[k++]=128|m>>12&63}h[k++]=128|m>>6&63}h[k++]=128|m&63}}h[k]= +0}}return p},array:function(g){var p=O(g.length);Q.set(g,p);return p}},l=N(a),A=[];a=0;if(e)for(var t=0;t=n);)++k;if(16h?n+=String.fromCharCode(h):(h-=65536,n+=String.fromCharCode(55296|h>>10,56320|h&1023))}}else n+=String.fromCharCode(h)}g=n}}else g="";else g="boolean"===c?!!g:g;return g}(d);0!==a&&fa(a);return d}var ea="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0,ha,Q,P; +function ia(){var a=L.buffer;ha=a;b.HEAP8=Q=new Int8Array(a);b.HEAP16=new Int16Array(a);b.HEAP32=new Int32Array(a);b.HEAPU8=P=new Uint8Array(a);b.HEAPU16=new Uint16Array(a);b.HEAPU32=new Uint32Array(a);b.HEAPF32=new Float32Array(a);b.HEAPF64=new Float64Array(a)}var R,ja=[],ka=[],la=[];function ma(){var a=b.preRun.shift();ja.unshift(a)}var S=0,T=null,U=null;b.preloadedImages={};b.preloadedAudios={}; +function K(a){if(b.onAbort)b.onAbort(a);I(a);M=!0;a=new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");r(a);throw a;}var V="data:application/octet-stream;base64,",W;W="data:application/octet-stream;base64,AGFzbQEAAAABIAZgAX8Bf2ADf39/AGABfwBgAABgAAF/YAZ/f39/f38AAgcBAWEBYQAAAwsKAAEDAQAAAgQFAgQFAXABAQEFBwEBgAKAgAIGCQF/AUGAjMACCwclCQFiAgABYwADAWQACQFlAAgBZgAHAWcABgFoAAUBaQAKAWoBAAqGTQpPAQJ/QYAIKAIAIgEgAEEDakF8cSICaiEAAkAgAkEAIAAgAU0bDQAgAD8AQRB0SwRAIAAQAEUNAQtBgAggADYCACABDwtBhAhBMDYCAEF/C4wFAg5+Cn8gACgCJCEUIAAoAiAhFSAAKAIcIREgACgCGCESIAAoAhQhEyACQRBPBEAgAC0ATEVBGHQhFyAAKAIEIhZBBWytIQ8gACgCCCIYQQVsrSENIAAoAgwiGUEFbK0hCyAAKAIQIhpBBWytIQkgADUCACEIIBqtIRAgGa0hDiAYrSEMIBatIQoDQCASIAEtAAMiEiABLQAEQQh0ciABLQAFQRB0ciABLQAGIhZBGHRyQQJ2Qf///x9xaq0iAyAOfiABLwAAIAEtAAJBEHRyIBNqIBJBGHRBgICAGHFqrSIEIBB+fCARIAEtAAdBCHQgFnIgAS0ACEEQdHIgAS0ACSIRQRh0ckEEdkH///8fcWqtIgUgDH58IAEtAApBCHQgEXIgAS0AC0EQdHIgAS0ADEEYdHJBBnYgFWqtIgYgCn58IBQgF2ogAS8ADSABLQAPQRB0cmqtIgcgCH58IAMgDH4gBCAOfnwgBSAKfnwgBiAIfnwgByAJfnwgAyAKfiAEIAx+fCAFIAh+fCAGIAl+fCAHIAt+fCADIAh+IAQgCn58IAUgCX58IAYgC358IAcgDX58IAMgCX4gBCAIfnwgBSALfnwgBiANfnwgByAPfnwiA0IaiEL/////D4N8IgRCGohC/////w+DfCIFQhqIQv////8Pg3wiBkIaiEL/////D4N8IgdCGoinQQVsIAOnQf///x9xaiITQRp2IASnQf///x9xaiESIAWnQf///x9xIREgBqdB////H3EhFSAHp0H///8fcSEUIBNB////H3EhEyABQRBqIQEgAkEQayICQQ9LDQALCyAAIBQ2AiQgACAVNgIgIAAgETYCHCAAIBI2AhggACATNgIUCwMAAQu2BAEGfwJAIAAoAjgiBARAIABBPGohBQJAIAJBECAEayIDIAIgA0kbIgZFDQAgBkEDcSEHAkAgBkEBa0EDSQRAQQAhAwwBCyAGQXxxIQhBACEDA0AgBSADIARqaiABIANqLQAAOgAAIAUgA0EBciIEIAAoAjhqaiABIARqLQAAOgAAIAUgA0ECciIEIAAoAjhqaiABIARqLQAAOgAAIAUgA0EDciIEIAAoAjhqaiABIARqLQAAOgAAIANBBGohAyAAKAI4IQQgCEEEayIIDQALCyAHRQ0AA0AgBSADIARqaiABIANqLQAAOgAAIANBAWohAyAAKAI4IQQgB0EBayIHDQALCyAAIAQgBmoiAzYCOCADQRBJDQEgACAFQRAQAiAAQQA2AjggAiAGayECIAEgBmohAQsgAkEQTwRAIAAgASACQXBxIgMQAiACQQ9xIQIgASADaiEBCyACRQ0AIAJBA3EhBCAAQTxqIQVBACEDIAJBAWtBA08EQCACQXxxIQcDQCAFIAAoAjggA2pqIAEgA2otAAA6AAAgBSADQQFyIgYgACgCOGpqIAEgBmotAAA6AAAgBSADQQJyIgYgACgCOGpqIAEgBmotAAA6AAAgBSADQQNyIgYgACgCOGpqIAEgBmotAAA6AAAgA0EEaiEDIAdBBGsiBw0ACwsgBARAA0AgBSAAKAI4IANqaiABIANqLQAAOgAAIANBAWohAyAEQQFrIgQNAAsLIAAgACgCOCACajYCOAsLoS0BDH8jAEEQayIMJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEH0AU0EQEGICCgCACIFQRAgAEELakF4cSAAQQtJGyIIQQN2IgJ2IgFBA3EEQCABQX9zQQFxIAJqIgNBA3QiAUG4CGooAgAiBEEIaiEAAkAgBCgCCCICIAFBsAhqIgFGBEBBiAggBUF+IAN3cTYCAAwBCyACIAE2AgwgASACNgIICyAEIANBA3QiAUEDcjYCBCABIARqIgEgASgCBEEBcjYCBAwNCyAIQZAIKAIAIgpNDQEgAQRAAkBBAiACdCIAQQAgAGtyIAEgAnRxIgBBACAAa3FBAWsiACAAQQx2QRBxIgJ2IgFBBXZBCHEiACACciABIAB2IgFBAnZBBHEiAHIgASAAdiIBQQF2QQJxIgByIAEgAHYiAUEBdkEBcSIAciABIAB2aiIDQQN0IgBBuAhqKAIAIgQoAggiASAAQbAIaiIARgRAQYgIIAVBfiADd3EiBTYCAAwBCyABIAA2AgwgACABNgIICyAEQQhqIQAgBCAIQQNyNgIEIAQgCGoiAiADQQN0IgEgCGsiA0EBcjYCBCABIARqIAM2AgAgCgRAIApBA3YiAUEDdEGwCGohB0GcCCgCACEEAn8gBUEBIAF0IgFxRQRAQYgIIAEgBXI2AgAgBwwBCyAHKAIICyEBIAcgBDYCCCABIAQ2AgwgBCAHNgIMIAQgATYCCAtBnAggAjYCAEGQCCADNgIADA0LQYwIKAIAIgZFDQEgBkEAIAZrcUEBayIAIABBDHZBEHEiAnYiAUEFdkEIcSIAIAJyIAEgAHYiAUECdkEEcSIAciABIAB2IgFBAXZBAnEiAHIgASAAdiIBQQF2QQFxIgByIAEgAHZqQQJ0QbgKaigCACIBKAIEQXhxIAhrIQMgASECA0ACQCACKAIQIgBFBEAgAigCFCIARQ0BCyAAKAIEQXhxIAhrIgIgAyACIANJIgIbIQMgACABIAIbIQEgACECDAELCyABIAhqIgkgAU0NAiABKAIYIQsgASABKAIMIgRHBEAgASgCCCIAQZgIKAIASRogACAENgIMIAQgADYCCAwMCyABQRRqIgIoAgAiAEUEQCABKAIQIgBFDQQgAUEQaiECCwNAIAIhByAAIgRBFGoiAigCACIADQAgBEEQaiECIAQoAhAiAA0ACyAHQQA2AgAMCwtBfyEIIABBv39LDQAgAEELaiIAQXhxIQhBjAgoAgAiCUUNAEEAIAhrIQMCQAJAAkACf0EAIAhBgAJJDQAaQR8gCEH///8HSw0AGiAAQQh2IgAgAEGA/j9qQRB2QQhxIgJ0IgAgAEGA4B9qQRB2QQRxIgF0IgAgAEGAgA9qQRB2QQJxIgB0QQ92IAEgAnIgAHJrIgBBAXQgCCAAQRVqdkEBcXJBHGoLIgVBAnRBuApqKAIAIgJFBEBBACEADAELQQAhACAIQQBBGSAFQQF2ayAFQR9GG3QhAQNAAkAgAigCBEF4cSAIayIHIANPDQAgAiEEIAciAw0AQQAhAyACIQAMAwsgACACKAIUIgcgByACIAFBHXZBBHFqKAIQIgJGGyAAIAcbIQAgAUEBdCEBIAINAAsLIAAgBHJFBEBBACEEQQIgBXQiAEEAIABrciAJcSIARQ0DIABBACAAa3FBAWsiACAAQQx2QRBxIgJ2IgFBBXZBCHEiACACciABIAB2IgFBAnZBBHEiAHIgASAAdiIBQQF2QQJxIgByIAEgAHYiAUEBdkEBcSIAciABIAB2akECdEG4CmooAgAhAAsgAEUNAQsDQCAAKAIEQXhxIAhrIgEgA0khAiABIAMgAhshAyAAIAQgAhshBCAAKAIQIgEEfyABBSAAKAIUCyIADQALCyAERQ0AIANBkAgoAgAgCGtPDQAgBCAIaiIGIARNDQEgBCgCGCEFIAQgBCgCDCIBRwRAIAQoAggiAEGYCCgCAEkaIAAgATYCDCABIAA2AggMCgsgBEEUaiICKAIAIgBFBEAgBCgCECIARQ0EIARBEGohAgsDQCACIQcgACIBQRRqIgIoAgAiAA0AIAFBEGohAiABKAIQIgANAAsgB0EANgIADAkLIAhBkAgoAgAiAk0EQEGcCCgCACEDAkAgAiAIayIBQRBPBEBBkAggATYCAEGcCCADIAhqIgA2AgAgACABQQFyNgIEIAIgA2ogATYCACADIAhBA3I2AgQMAQtBnAhBADYCAEGQCEEANgIAIAMgAkEDcjYCBCACIANqIgAgACgCBEEBcjYCBAsgA0EIaiEADAsLIAhBlAgoAgAiBkkEQEGUCCAGIAhrIgE2AgBBoAhBoAgoAgAiAiAIaiIANgIAIAAgAUEBcjYCBCACIAhBA3I2AgQgAkEIaiEADAsLQQAhACAIQS9qIgkCf0HgCygCAARAQegLKAIADAELQewLQn83AgBB5AtCgKCAgICABDcCAEHgCyAMQQxqQXBxQdiq1aoFczYCAEH0C0EANgIAQcQLQQA2AgBBgCALIgFqIgVBACABayIHcSICIAhNDQpBwAsoAgAiBARAQbgLKAIAIgMgAmoiASADTQ0LIAEgBEsNCwtBxAstAABBBHENBQJAAkBBoAgoAgAiAwRAQcgLIQADQCADIAAoAgAiAU8EQCABIAAoAgRqIANLDQMLIAAoAggiAA0ACwtBABABIgFBf0YNBiACIQVB5AsoAgAiA0EBayIAIAFxBEAgAiABayAAIAFqQQAgA2txaiEFCyAFIAhNDQYgBUH+////B0sNBkHACygCACIEBEBBuAsoAgAiAyAFaiIAIANNDQcgACAESw0HCyAFEAEiACABRw0BDAgLIAUgBmsgB3EiBUH+////B0sNBSAFEAEiASAAKAIAIAAoAgRqRg0EIAEhAAsCQCAAQX9GDQAgCEEwaiAFTQ0AQegLKAIAIgEgCSAFa2pBACABa3EiAUH+////B0sEQCAAIQEMCAsgARABQX9HBEAgASAFaiEFIAAhAQwIC0EAIAVrEAEaDAULIAAiAUF/Rw0GDAQLAAtBACEEDAcLQQAhAQwFCyABQX9HDQILQcQLQcQLKAIAQQRyNgIACyACQf7///8HSw0BIAIQASEBQQAQASEAIAFBf0YNASAAQX9GDQEgACABTQ0BIAAgAWsiBSAIQShqTQ0BC0G4C0G4CygCACAFaiIANgIAQbwLKAIAIABJBEBBvAsgADYCAAsCQAJAAkBBoAgoAgAiBwRAQcgLIQADQCABIAAoAgAiAyAAKAIEIgJqRg0CIAAoAggiAA0ACwwCC0GYCCgCACIAQQAgACABTRtFBEBBmAggATYCAAtBACEAQcwLIAU2AgBByAsgATYCAEGoCEF/NgIAQawIQeALKAIANgIAQdQLQQA2AgADQCAAQQN0IgNBuAhqIANBsAhqIgI2AgAgA0G8CGogAjYCACAAQQFqIgBBIEcNAAtBlAggBUEoayIDQXggAWtBB3FBACABQQhqQQdxGyIAayICNgIAQaAIIAAgAWoiADYCACAAIAJBAXI2AgQgASADakEoNgIEQaQIQfALKAIANgIADAILIAAtAAxBCHENACADIAdLDQAgASAHTQ0AIAAgAiAFajYCBEGgCCAHQXggB2tBB3FBACAHQQhqQQdxGyIAaiICNgIAQZQIQZQIKAIAIAVqIgEgAGsiADYCACACIABBAXI2AgQgASAHakEoNgIEQaQIQfALKAIANgIADAELQZgIKAIAIAFLBEBBmAggATYCAAsgASAFaiECQcgLIQACQAJAAkACQAJAAkADQCACIAAoAgBHBEAgACgCCCIADQEMAgsLIAAtAAxBCHFFDQELQcgLIQADQCAHIAAoAgAiAk8EQCACIAAoAgRqIgQgB0sNAwsgACgCCCEADAALAAsgACABNgIAIAAgACgCBCAFajYCBCABQXggAWtBB3FBACABQQhqQQdxG2oiCSAIQQNyNgIEIAJBeCACa0EHcUEAIAJBCGpBB3EbaiIFIAggCWoiBmshAiAFIAdGBEBBoAggBjYCAEGUCEGUCCgCACACaiIANgIAIAYgAEEBcjYCBAwDCyAFQZwIKAIARgRAQZwIIAY2AgBBkAhBkAgoAgAgAmoiADYCACAGIABBAXI2AgQgACAGaiAANgIADAMLIAUoAgQiAEEDcUEBRgRAIABBeHEhBwJAIABB/wFNBEAgBSgCCCIDIABBA3YiAEEDdEGwCGpGGiADIAUoAgwiAUYEQEGICEGICCgCAEF+IAB3cTYCAAwCCyADIAE2AgwgASADNgIIDAELIAUoAhghCAJAIAUgBSgCDCIBRwRAIAUoAggiACABNgIMIAEgADYCCAwBCwJAIAVBFGoiACgCACIDDQAgBUEQaiIAKAIAIgMNAEEAIQEMAQsDQCAAIQQgAyIBQRRqIgAoAgAiAw0AIAFBEGohACABKAIQIgMNAAsgBEEANgIACyAIRQ0AAkAgBSAFKAIcIgNBAnRBuApqIgAoAgBGBEAgACABNgIAIAENAUGMCEGMCCgCAEF+IAN3cTYCAAwCCyAIQRBBFCAIKAIQIAVGG2ogATYCACABRQ0BCyABIAg2AhggBSgCECIABEAgASAANgIQIAAgATYCGAsgBSgCFCIARQ0AIAEgADYCFCAAIAE2AhgLIAUgB2ohBSACIAdqIQILIAUgBSgCBEF+cTYCBCAGIAJBAXI2AgQgAiAGaiACNgIAIAJB/wFNBEAgAkEDdiIAQQN0QbAIaiECAn9BiAgoAgAiAUEBIAB0IgBxRQRAQYgIIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBjYCCCAAIAY2AgwgBiACNgIMIAYgADYCCAwDC0EfIQAgAkH///8HTQRAIAJBCHYiACAAQYD+P2pBEHZBCHEiA3QiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASADciAAcmsiAEEBdCACIABBFWp2QQFxckEcaiEACyAGIAA2AhwgBkIANwIQIABBAnRBuApqIQQCQEGMCCgCACIDQQEgAHQiAXFFBEBBjAggASADcjYCACAEIAY2AgAgBiAENgIYDAELIAJBAEEZIABBAXZrIABBH0YbdCEAIAQoAgAhAQNAIAEiAygCBEF4cSACRg0DIABBHXYhASAAQQF0IQAgAyABQQRxaiIEKAIQIgENAAsgBCAGNgIQIAYgAzYCGAsgBiAGNgIMIAYgBjYCCAwCC0GUCCAFQShrIgNBeCABa0EHcUEAIAFBCGpBB3EbIgBrIgI2AgBBoAggACABaiIANgIAIAAgAkEBcjYCBCABIANqQSg2AgRBpAhB8AsoAgA2AgAgByAEQScgBGtBB3FBACAEQSdrQQdxG2pBL2siACAAIAdBEGpJGyICQRs2AgQgAkHQCykCADcCECACQcgLKQIANwIIQdALIAJBCGo2AgBBzAsgBTYCAEHICyABNgIAQdQLQQA2AgAgAkEYaiEAA0AgAEEHNgIEIABBCGohASAAQQRqIQAgASAESQ0ACyACIAdGDQMgAiACKAIEQX5xNgIEIAcgAiAHayIEQQFyNgIEIAIgBDYCACAEQf8BTQRAIARBA3YiAEEDdEGwCGohAgJ/QYgIKAIAIgFBASAAdCIAcUUEQEGICCAAIAFyNgIAIAIMAQsgAigCCAshACACIAc2AgggACAHNgIMIAcgAjYCDCAHIAA2AggMBAtBHyEAIAdCADcCECAEQf///wdNBEAgBEEIdiIAIABBgP4/akEQdkEIcSICdCIAIABBgOAfakEQdkEEcSIBdCIAIABBgIAPakEQdkECcSIAdEEPdiABIAJyIAByayIAQQF0IAQgAEEVanZBAXFyQRxqIQALIAcgADYCHCAAQQJ0QbgKaiEDAkBBjAgoAgAiAkEBIAB0IgFxRQRAQYwIIAEgAnI2AgAgAyAHNgIAIAcgAzYCGAwBCyAEQQBBGSAAQQF2ayAAQR9GG3QhACADKAIAIQEDQCABIgIoAgRBeHEgBEYNBCAAQR12IQEgAEEBdCEAIAIgAUEEcWoiAygCECIBDQALIAMgBzYCECAHIAI2AhgLIAcgBzYCDCAHIAc2AggMAwsgAygCCCIAIAY2AgwgAyAGNgIIIAZBADYCGCAGIAM2AgwgBiAANgIICyAJQQhqIQAMBQsgAigCCCIAIAc2AgwgAiAHNgIIIAdBADYCGCAHIAI2AgwgByAANgIIC0GUCCgCACIAIAhNDQBBlAggACAIayIBNgIAQaAIQaAIKAIAIgIgCGoiADYCACAAIAFBAXI2AgQgAiAIQQNyNgIEIAJBCGohAAwDC0GECEEwNgIAQQAhAAwCCwJAIAVFDQACQCAEKAIcIgJBAnRBuApqIgAoAgAgBEYEQCAAIAE2AgAgAQ0BQYwIIAlBfiACd3EiCTYCAAwCCyAFQRBBFCAFKAIQIARGG2ogATYCACABRQ0BCyABIAU2AhggBCgCECIABEAgASAANgIQIAAgATYCGAsgBCgCFCIARQ0AIAEgADYCFCAAIAE2AhgLAkAgA0EPTQRAIAQgAyAIaiIAQQNyNgIEIAAgBGoiACAAKAIEQQFyNgIEDAELIAQgCEEDcjYCBCAGIANBAXI2AgQgAyAGaiADNgIAIANB/wFNBEAgA0EDdiIAQQN0QbAIaiECAn9BiAgoAgAiAUEBIAB0IgBxRQRAQYgIIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBjYCCCAAIAY2AgwgBiACNgIMIAYgADYCCAwBC0EfIQAgA0H///8HTQRAIANBCHYiACAAQYD+P2pBEHZBCHEiAnQiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASACciAAcmsiAEEBdCADIABBFWp2QQFxckEcaiEACyAGIAA2AhwgBkIANwIQIABBAnRBuApqIQICQAJAIAlBASAAdCIBcUUEQEGMCCABIAlyNgIAIAIgBjYCACAGIAI2AhgMAQsgA0EAQRkgAEEBdmsgAEEfRht0IQAgAigCACEIA0AgCCIBKAIEQXhxIANGDQIgAEEddiECIABBAXQhACABIAJBBHFqIgIoAhAiCA0ACyACIAY2AhAgBiABNgIYCyAGIAY2AgwgBiAGNgIIDAELIAEoAggiACAGNgIMIAEgBjYCCCAGQQA2AhggBiABNgIMIAYgADYCCAsgBEEIaiEADAELAkAgC0UNAAJAIAEoAhwiAkECdEG4CmoiACgCACABRgRAIAAgBDYCACAEDQFBjAggBkF+IAJ3cTYCAAwCCyALQRBBFCALKAIQIAFGG2ogBDYCACAERQ0BCyAEIAs2AhggASgCECIABEAgBCAANgIQIAAgBDYCGAsgASgCFCIARQ0AIAQgADYCFCAAIAQ2AhgLAkAgA0EPTQRAIAEgAyAIaiIAQQNyNgIEIAAgAWoiACAAKAIEQQFyNgIEDAELIAEgCEEDcjYCBCAJIANBAXI2AgQgAyAJaiADNgIAIAoEQCAKQQN2IgBBA3RBsAhqIQRBnAgoAgAhAgJ/QQEgAHQiACAFcUUEQEGICCAAIAVyNgIAIAQMAQsgBCgCCAshACAEIAI2AgggACACNgIMIAIgBDYCDCACIAA2AggLQZwIIAk2AgBBkAggAzYCAAsgAUEIaiEACyAMQRBqJAAgAAsQACMAIABrQXBxIgAkACAACwYAIAAkAAsEACMAC4AJAgh/BH4jAEGQAWsiBiQAIAYgBS0AA0EYdEGAgIAYcSAFLwAAIAUtAAJBEHRycjYCACAGIAUoAANBAnZBg/7/H3E2AgQgBiAFKAAGQQR2Qf+B/x9xNgIIIAYgBSgACUEGdkH//8AfcTYCDCAFLwANIQggBS0ADyEJIAZCADcCFCAGQgA3AhwgBkEANgIkIAYgCCAJQRB0QYCAPHFyNgIQIAYgBSgAEDYCKCAGIAUoABQ2AiwgBiAFKAAYNgIwIAUoABwhBSAGQQA6AEwgBkEANgI4IAYgBTYCNCAGIAEgAhAEIAQEQCAGIAMgBBAECyAGKAI4IgEEQCAGQTxqIgIgAWpBAToAACABQQFqQQ9NBEAgASAGakE9aiEEAkBBDyABayIDRQ0AIAMgBGoiAUEBa0EAOgAAIARBADoAACADQQNJDQAgAUECa0EAOgAAIARBADoAASABQQNrQQA6AAAgBEEAOgACIANBB0kNACABQQRrQQA6AAAgBEEAOgADIANBCUkNACAEQQAgBGtBA3EiAWoiBEEANgIAIAQgAyABa0F8cSIBaiIDQQRrQQA2AgAgAUEJSQ0AIARBADYCCCAEQQA2AgQgA0EIa0EANgIAIANBDGtBADYCACABQRlJDQAgBEEANgIYIARBADYCFCAEQQA2AhAgBEEANgIMIANBEGtBADYCACADQRRrQQA2AgAgA0EYa0EANgIAIANBHGtBADYCACABIARBBHFBGHIiAWsiA0EgSQ0AIAEgBGohAQNAIAFCADcDGCABQgA3AxAgAUIANwMIIAFCADcDACABQSBqIQEgA0EgayIDQR9LDQALCwsgBkEBOgBMIAYgAkEQEAILIAY1AjQhECAGNQIwIREgBjUCLCEOIAAgBjUCKCAGKAIkIAYoAiAgBigCHCAGKAIYIgNBGnZqIgJBGnZqIgFBGnZqIgtBgICAYHIgAUH///8fcSINIAJB////H3EiCCAGKAIUIAtBGnZBBWxqIgFB////H3EiCUEFaiIFQRp2IANB////H3EgAUEadmoiA2oiAUEadmoiAkEadmoiBEEadmoiDEEfdSIHIANxIAEgDEEfdkEBayIDQf///x9xIgpxciIBQRp0IAUgCnEgByAJcXJyrXwiDzwAACAAIA9CGIg8AAMgACAPQhCIPAACIAAgD0IIiDwAASAAIA4gByAIcSACIApxciICQRR0IAFBBnZyrXwgD0IgiHwiDjwABCAAIA5CGIg8AAcgACAOQhCIPAAGIAAgDkIIiDwABSAAIBEgByANcSAEIApxciIBQQ50IAJBDHZyrXwgDkIgiHwiDjwACCAAIA5CGIg8AAsgACAOQhCIPAAKIAAgDkIIiDwACSAAIBAgAyAMcSAHIAtxckEIdCABQRJ2cq18IA5CIIh8Ig48AAwgACAOQhiIPAAPIAAgDkIQiDwADiAAIA5CCIg8AA0gBkIANwIwIAZCADcCKCAGQgA3AiAgBkIANwIYIAZCADcCECAGQgA3AgggBkIANwIAIAZBkAFqJAALpwwBB38CQCAARQ0AIABBCGsiAyAAQQRrKAIAIgFBeHEiAGohBQJAIAFBAXENACABQQNxRQ0BIAMgAygCACIBayIDQZgIKAIASQ0BIAAgAWohACADQZwIKAIARwRAIAFB/wFNBEAgAygCCCICIAFBA3YiBEEDdEGwCGpGGiACIAMoAgwiAUYEQEGICEGICCgCAEF+IAR3cTYCAAwDCyACIAE2AgwgASACNgIIDAILIAMoAhghBgJAIAMgAygCDCIBRwRAIAMoAggiAiABNgIMIAEgAjYCCAwBCwJAIANBFGoiAigCACIEDQAgA0EQaiICKAIAIgQNAEEAIQEMAQsDQCACIQcgBCIBQRRqIgIoAgAiBA0AIAFBEGohAiABKAIQIgQNAAsgB0EANgIACyAGRQ0BAkAgAyADKAIcIgJBAnRBuApqIgQoAgBGBEAgBCABNgIAIAENAUGMCEGMCCgCAEF+IAJ3cTYCAAwDCyAGQRBBFCAGKAIQIANGG2ogATYCACABRQ0CCyABIAY2AhggAygCECICBEAgASACNgIQIAIgATYCGAsgAygCFCICRQ0BIAEgAjYCFCACIAE2AhgMAQsgBSgCBCIBQQNxQQNHDQBBkAggADYCACAFIAFBfnE2AgQgAyAAQQFyNgIEIAAgA2ogADYCAA8LIAMgBU8NACAFKAIEIgFBAXFFDQACQCABQQJxRQRAIAVBoAgoAgBGBEBBoAggAzYCAEGUCEGUCCgCACAAaiIANgIAIAMgAEEBcjYCBCADQZwIKAIARw0DQZAIQQA2AgBBnAhBADYCAA8LIAVBnAgoAgBGBEBBnAggAzYCAEGQCEGQCCgCACAAaiIANgIAIAMgAEEBcjYCBCAAIANqIAA2AgAPCyABQXhxIABqIQACQCABQf8BTQRAIAUoAggiAiABQQN2IgRBA3RBsAhqRhogAiAFKAIMIgFGBEBBiAhBiAgoAgBBfiAEd3E2AgAMAgsgAiABNgIMIAEgAjYCCAwBCyAFKAIYIQYCQCAFIAUoAgwiAUcEQCAFKAIIIgJBmAgoAgBJGiACIAE2AgwgASACNgIIDAELAkAgBUEUaiICKAIAIgQNACAFQRBqIgIoAgAiBA0AQQAhAQwBCwNAIAIhByAEIgFBFGoiAigCACIEDQAgAUEQaiECIAEoAhAiBA0ACyAHQQA2AgALIAZFDQACQCAFIAUoAhwiAkECdEG4CmoiBCgCAEYEQCAEIAE2AgAgAQ0BQYwIQYwIKAIAQX4gAndxNgIADAILIAZBEEEUIAYoAhAgBUYbaiABNgIAIAFFDQELIAEgBjYCGCAFKAIQIgIEQCABIAI2AhAgAiABNgIYCyAFKAIUIgJFDQAgASACNgIUIAIgATYCGAsgAyAAQQFyNgIEIAAgA2ogADYCACADQZwIKAIARw0BQZAIIAA2AgAPCyAFIAFBfnE2AgQgAyAAQQFyNgIEIAAgA2ogADYCAAsgAEH/AU0EQCAAQQN2IgFBA3RBsAhqIQACf0GICCgCACICQQEgAXQiAXFFBEBBiAggASACcjYCACAADAELIAAoAggLIQIgACADNgIIIAIgAzYCDCADIAA2AgwgAyACNgIIDwtBHyECIANCADcCECAAQf///wdNBEAgAEEIdiIBIAFBgP4/akEQdkEIcSIBdCICIAJBgOAfakEQdkEEcSICdCIEIARBgIAPakEQdkECcSIEdEEPdiABIAJyIARyayIBQQF0IAAgAUEVanZBAXFyQRxqIQILIAMgAjYCHCACQQJ0QbgKaiEBAkACQAJAQYwIKAIAIgRBASACdCIHcUUEQEGMCCAEIAdyNgIAIAEgAzYCACADIAE2AhgMAQsgAEEAQRkgAkEBdmsgAkEfRht0IQIgASgCACEBA0AgASIEKAIEQXhxIABGDQIgAkEddiEBIAJBAXQhAiAEIAFBBHFqIgdBEGooAgAiAQ0ACyAHIAM2AhAgAyAENgIYCyADIAM2AgwgAyADNgIIDAELIAQoAggiACADNgIMIAQgAzYCCCADQQA2AhggAyAENgIMIAMgADYCCAtBqAhBqAgoAgBBAWsiAEF/IAAbNgIACwsLCQEAQYEICwIGUA==";if(!W.startsWith(V)){var na=W;W=b.locateFile?b.locateFile(na,B):B+na}function pa(){var a=W;try{if(a==W&&J)return new Uint8Array(J);var c=H(a);if(c)return c;if(E)return E(a);throw"both async and sync fetching of the wasm failed";}catch(d){K(d)}} +function qa(){if(!J&&(x||y)){if("function"===typeof fetch&&!W.startsWith("file://"))return fetch(W,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+W+"'";return a.arrayBuffer()}).catch(function(){return pa()});if(D)return new Promise(function(a,c){D(W,function(d){a(new Uint8Array(d))},c)})}return Promise.resolve().then(function(){return pa()})} +function X(a){for(;0>4;f=(f&15)<<4|l>>2;var t=(l&3)<<6|A;c+=String.fromCharCode(e);64!==l&&(c+=String.fromCharCode(f));64!==A&&(c+=String.fromCharCode(t))}while(d>>=0;if(2147483648=d;d*=2){var e=c*(1+.2/d);e=Math.min(e,a+100663296);e=Math.max(a,e);0>>16);ia();var f=1;break a}catch(l){}f=void 0}if(f)return!0}return!1}}; +(function(){function a(f){b.asm=f.exports;L=b.asm.b;ia();R=b.asm.j;ka.unshift(b.asm.c);S--;b.monitorRunDependencies&&b.monitorRunDependencies(S);0==S&&(null!==T&&(clearInterval(T),T=null),U&&(f=U,U=null,f()))}function c(f){a(f.instance)}function d(f){return qa().then(function(l){return WebAssembly.instantiate(l,e)}).then(f,function(l){I("failed to asynchronously prepare wasm: "+l);K(l)})}var e={a:sa};S++;b.monitorRunDependencies&&b.monitorRunDependencies(S);if(b.instantiateWasm)try{return b.instantiateWasm(e, +a)}catch(f){return I("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return J||"function"!==typeof WebAssembly.instantiateStreaming||W.startsWith(V)||W.startsWith("file://")||"function"!==typeof fetch?d(c):fetch(W,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,e).then(c,function(l){I("wasm streaming compile failed: "+l);I("falling back to ArrayBuffer instantiation");return d(c)})})})().catch(r);return{}})(); +b.___wasm_call_ctors=function(){return(b.___wasm_call_ctors=b.asm.c).apply(null,arguments)};b._poly1305_auth=function(){return(b._poly1305_auth=b.asm.d).apply(null,arguments)};var da=b.stackSave=function(){return(da=b.stackSave=b.asm.e).apply(null,arguments)},fa=b.stackRestore=function(){return(fa=b.stackRestore=b.asm.f).apply(null,arguments)},O=b.stackAlloc=function(){return(O=b.stackAlloc=b.asm.g).apply(null,arguments)};b._malloc=function(){return(b._malloc=b.asm.h).apply(null,arguments)}; +b._free=function(){return(b._free=b.asm.i).apply(null,arguments)};b.cwrap=function(a,c,d,e){d=d||[];var f=d.every(function(l){return"number"===l});return"string"!==c&&f&&!e?N(a):function(){return ca(a,c,d,arguments)}};var Y;U=function ta(){Y||Z();Y||(U=ta)}; +function Z(){function a(){if(!Y&&(Y=!0,b.calledRun=!0,!M)){X(ka);q(b);if(b.onRuntimeInitialized)b.onRuntimeInitialized();if(b.postRun)for("function"==typeof b.postRun&&(b.postRun=[b.postRun]);b.postRun.length;){var c=b.postRun.shift();la.unshift(c)}X(la)}}if(!(0= 8 +#define DISABLE_WCAST_FUNCTION_TYPE _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"") +#define DISABLE_WCAST_FUNCTION_TYPE_END _Pragma("GCC diagnostic pop") +#else +#define DISABLE_WCAST_FUNCTION_TYPE +#define DISABLE_WCAST_FUNCTION_TYPE_END +#endif + +#include +#include +#include + +DISABLE_WCAST_FUNCTION_TYPE +#include +#include +#include +DISABLE_WCAST_FUNCTION_TYPE_END + +#if NODE_MAJOR_VERSION >= 17 +# include +#endif + +#include +#include +#include + +#ifndef _WIN32 +# include +#endif + +typedef int (*ctx_iv_len_func)(const EVP_CIPHER_CTX*); +typedef int (*ctx_key_len_func)(const EVP_CIPHER_CTX*); +typedef int (*ctx_get_block_size_func)(const EVP_CIPHER_CTX*); +typedef int (*cipher_flags_func)(const EVP_CIPHER*); +ctx_iv_len_func ctx_iv_len = nullptr; +ctx_key_len_func ctx_key_len = nullptr; +ctx_get_block_size_func ctx_get_block_size = nullptr; +cipher_flags_func cipher_flags = nullptr; + +#if REAL_OPENSSL_MAJOR < 3 +# undef EVP_DigestSignUpdate +# define EVP_DigestSignUpdate EVP_DigestUpdate +# undef EVP_PKEY_OP_SIGNCTX +# define EVP_PKEY_OP_SIGNCTX (1 << 6) +#endif + +using namespace node; +using namespace v8; +using namespace std; + +struct MarkPopErrorOnReturn { + MarkPopErrorOnReturn() { ERR_set_mark(); } + ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); } +}; + +enum ErrorType { + kErrNone, + kErrOpenSSL, + kErrBadIVLen, + kErrBadKeyLen, + kErrAADFailure, + kErrTagFailure, + kErrPartialEncrypt, + kErrBadCipherName, + kErrBadHMACName, + kErrBadHMACLen, + kErrBadInit, + kErrPartialDecrypt, + kErrInvalidMAC, + kErrBadBlockLen +}; + +#define MAX_MAC_LEN 64 + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 +class ChaChaPolyCipher : public ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("ChaChaPolyCipher").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + SetPrototypeMethod(tpl, "encrypt", Encrypt); + SetPrototypeMethod(tpl, "free", Free); + + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); + + Nan::Set(target, + Nan::New("ChaChaPolyCipher").ToLocalChecked(), + func); + } + + private: + explicit ChaChaPolyCipher() + : ctx_main_(nullptr), + ctx_pktlen_(nullptr), +#if REAL_OPENSSL_MAJOR >= 3 + mac_(nullptr), + mac_ctx_(nullptr) {} +#else + md_ctx_(nullptr), + polykey_(nullptr), + polykey_ctx_(nullptr) {} +#endif + + ~ChaChaPolyCipher() { + clear(); + } + + void clear() { + if (ctx_pktlen_) { + EVP_CIPHER_CTX_free(ctx_pktlen_); + ctx_pktlen_ = nullptr; + } + if (ctx_main_) { + EVP_CIPHER_CTX_free(ctx_main_); + ctx_main_ = nullptr; + } +#if REAL_OPENSSL_MAJOR >= 3 + if (mac_ctx_) { + EVP_MAC_CTX_free(mac_ctx_); + mac_ctx_ = nullptr; + } + if (mac_) { + EVP_MAC_free(mac_); + mac_ = nullptr; + } +#else + if (polykey_) { + EVP_PKEY_free(polykey_); + polykey_ = nullptr; + } + if (md_ctx_) { + EVP_MD_CTX_free(md_ctx_); + md_ctx_ = nullptr; + } + // `polykey_ctx_` is not explicitly freed as it is freed implicitly when + // `md_ctx_` is freed +#endif + } + + ErrorType init(unsigned char* keys, size_t keys_len) { + ErrorType r = kErrNone; + const EVP_CIPHER* const cipher = EVP_get_cipherbyname("chacha20"); + + if (keys_len != 64) { + r = kErrBadKeyLen; + goto out; + } + + if (cipher == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr + || (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr +#if REAL_OPENSSL_MAJOR >= 3 + || (mac_ = EVP_MAC_fetch(nullptr, + "POLY1305", + "provider=default")) == nullptr + || (mac_ctx_ = EVP_MAC_CTX_new(mac_)) == nullptr +#else + || (md_ctx_ = EVP_MD_CTX_new()) == nullptr +#endif + || EVP_EncryptInit_ex(ctx_pktlen_, + cipher, + nullptr, + keys + 32, + nullptr) != 1 + || EVP_EncryptInit_ex(ctx_main_, + cipher, + nullptr, + keys, + nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + if (ctx_iv_len(ctx_pktlen_) != 16) { + r = kErrBadIVLen; + goto out; + } + +out: + return r; + } + + ErrorType encrypt(unsigned char* packet, + uint32_t packet_len, + uint32_t seqno) { + ErrorType r = kErrNone; + size_t sig_len = 16; + int outlen = 0; + + // `packet` layout: + // + uint32_t data_len = packet_len - POLY1305_TAGLEN; + + unsigned char polykey[POLY1305_KEYLEN] = {0}; + + uint8_t seqbuf[16] = {0}; + ((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff; + ((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff; + ((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff; + ((uint8_t*)(seqbuf))[15] = seqno & 0xff; + + // Generate Poly1305 key + if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_EncryptUpdate(ctx_main_, + polykey, + &outlen, + polykey, + sizeof(polykey)) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != sizeof(polykey)) { + r = kErrPartialEncrypt; + goto out; + } + + // Encrypt packet length + if (EVP_EncryptInit_ex(ctx_pktlen_, + nullptr, + nullptr, + nullptr, + seqbuf) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_EncryptUpdate(ctx_pktlen_, packet, &outlen, packet, 4) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != 4) { + r = kErrPartialEncrypt; + goto out; + } + + // Encrypt rest of packet + seqbuf[0] = 1; + if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_EncryptUpdate(ctx_main_, + packet + 4, + &outlen, + packet + 4, + data_len - 4) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != data_len - 4) { + r = kErrPartialEncrypt; + goto out; + } + + // Poly1305 over ciphertext +#if REAL_OPENSSL_MAJOR >= 3 + // TODO: check if dup()'ing a "base" context instead of calling init() with + // the key each time is faster + if (EVP_MAC_init(mac_ctx_, polykey, sizeof(polykey), nullptr) != 1 + || EVP_MAC_update(mac_ctx_, packet, data_len) != 1 + || EVP_MAC_final(mac_ctx_, packet + data_len, &sig_len, sig_len) != 1) { + r = kErrOpenSSL; + goto out; + } +#else + if (polykey_) { + if (EVP_PKEY_CTX_ctrl(polykey_ctx_, + -1, + EVP_PKEY_OP_SIGNCTX, + EVP_PKEY_CTRL_SET_MAC_KEY, + sizeof(polykey), + (void*)polykey) <= 0) { + r = kErrOpenSSL; + goto out; + } + } else { + polykey_ = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, + nullptr, + polykey, + sizeof(polykey)); + if (polykey_ == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if (!EVP_DigestSignInit(md_ctx_, + &polykey_ctx_, + nullptr, + nullptr, + polykey_)) { + r = kErrOpenSSL; + goto out; + } + } + + // Generate and write Poly1305 tag + if (EVP_DigestSign(md_ctx_, + packet + data_len, + &sig_len, + packet, + data_len) != 1) { + r = kErrOpenSSL; + goto out; + } +#endif + + out: + return r; + } + + static NAN_METHOD(New) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid keys"); + + ChaChaPolyCipher* obj = new ChaChaPolyCipher(); + ErrorType r = obj->init( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]) + ); + if (r != kErrNone) { + if (r == kErrOpenSSL) { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + obj->clear(); + delete obj; + return Nan::ThrowError(msg_buf); + } + obj->clear(); + delete obj; + switch (r) { + case kErrBadKeyLen: + return Nan::ThrowError("Invalid keys length"); + case kErrBadIVLen: + return Nan::ThrowError("Invalid IV length"); + default: + return Nan::ThrowError("Unknown init failure"); + } + } + + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(Encrypt) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + ChaChaPolyCipher* obj = ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid packet"); + + if (!info[1]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid sequence number"); + + ErrorType r = obj->encrypt( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]), + Nan::To(info[1]).FromJust() + ); + switch (r) { + case kErrNone: + return; + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown encrypt failure"); + } + } + + static NAN_METHOD(Free) { + ChaChaPolyCipher* obj = ObjectWrap::Unwrap(info.Holder()); + obj->clear(); + } + + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; + return my_constructor; + } + + EVP_CIPHER_CTX* ctx_main_; + EVP_CIPHER_CTX* ctx_pktlen_; +#if REAL_OPENSSL_MAJOR >= 3 + EVP_MAC* mac_; + EVP_MAC_CTX* mac_ctx_; +#else + EVP_MD_CTX* md_ctx_; + EVP_PKEY* polykey_; + EVP_PKEY_CTX* polykey_ctx_; +#endif +}; + +class AESGCMCipher : public ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("AESGCMCipher").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + SetPrototypeMethod(tpl, "encrypt", Encrypt); + SetPrototypeMethod(tpl, "free", Free); + + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); + + Nan::Set(target, + Nan::New("AESGCMCipher").ToLocalChecked(), + func); + } + + private: + explicit AESGCMCipher() : ctx_(nullptr) {} + + ~AESGCMCipher() { + clear(); + } + + void clear() { + if (ctx_) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; + } + } + + ErrorType init(const char* name, + unsigned char* key, + size_t key_len, + unsigned char* iv, + size_t iv_len) { + ErrorType r = kErrNone; + + const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name); + if (cipher == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if (cipher != EVP_aes_128_gcm() && cipher != EVP_aes_256_gcm()) { + r = kErrBadCipherName; + goto out; + } + + if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr + || EVP_EncryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr)) { + r = kErrOpenSSL; + goto out; + } + + if (key_len != static_cast(ctx_key_len(ctx_))) { + if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) { + r = kErrBadKeyLen; + goto out; + } + } + + // Set key and IV + if (EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) { + r = kErrOpenSSL; + goto out; + } + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IV_FIXED, -1, iv)) { + r = kErrOpenSSL; + goto out; + } + + // Disable padding + EVP_CIPHER_CTX_set_padding(ctx_, 0); + +out: + return r; + } + + ErrorType encrypt(unsigned char* packet, uint32_t packet_len) { + ErrorType r = kErrNone; + + // `packet` layout: + // + uint32_t data_len = packet_len - 16; + + int outlen = 0; + + // Increment IV + unsigned char lastiv[1]; + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_IV_GEN, 1, lastiv)) { + r = kErrOpenSSL; + goto out; + } + + // Set AAD (the packet length) + if (!EVP_EncryptUpdate(ctx_, nullptr, &outlen, packet, 4)) { + r = kErrOpenSSL; + goto out; + } + if (outlen != 4) { + r = kErrAADFailure; + goto out; + } + + // Encrypt everything but the packet length + if (EVP_EncryptUpdate(ctx_, + packet + 4, + &outlen, + packet + 4, + data_len - 4) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != data_len - 4) { + r = kErrPartialEncrypt; + goto out; + } + + // Generate authentication tag + if (!EVP_EncryptFinal_ex(ctx_, nullptr, &outlen)) { + r = kErrOpenSSL; + goto out; + } + + // Write authentication tag + if (EVP_CIPHER_CTX_ctrl(ctx_, + EVP_CTRL_AEAD_GET_TAG, + 16, + packet + data_len) != 1) { + r = kErrOpenSSL; + goto out; + } + +out: + return r; + } + + static NAN_METHOD(New) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + if (!info[0]->IsString()) + return Nan::ThrowTypeError("Missing/Invalid OpenSSL cipher name"); + + if (!Buffer::HasInstance(info[1])) + return Nan::ThrowTypeError("Missing/Invalid key"); + + if (!Buffer::HasInstance(info[2])) + return Nan::ThrowTypeError("Missing/Invalid iv"); + + const Nan::Utf8String cipher_name(info[0]); + + AESGCMCipher* obj = new AESGCMCipher(); + ErrorType r = obj->init( + *cipher_name, + reinterpret_cast(Buffer::Data(info[1])), + Buffer::Length(info[1]), + reinterpret_cast(Buffer::Data(info[2])), + Buffer::Length(info[2]) + ); + if (r != kErrNone) { + if (r == kErrOpenSSL) { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + obj->clear(); + delete obj; + return Nan::ThrowError(msg_buf); + } + obj->clear(); + delete obj; + switch (r) { + case kErrBadKeyLen: + return Nan::ThrowError("Invalid keys length"); + case kErrBadIVLen: + return Nan::ThrowError("Invalid IV length"); + case kErrBadCipherName: + return Nan::ThrowError("Invalid AES GCM cipher name"); + default: + return Nan::ThrowError("Unknown init failure"); + } + } + + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(Encrypt) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + AESGCMCipher* obj = ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid packet"); + + ErrorType r = obj->encrypt( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]) + ); + switch (r) { + case kErrNone: + return; + case kErrAADFailure: + return Nan::ThrowError("Error setting AAD"); + case kErrPartialEncrypt: + return Nan::ThrowError("Failed to completely encrypt packet"); + case kErrTagFailure: + return Nan::ThrowError("Error generating authentication tag"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown encrypt failure"); + } + } + + static NAN_METHOD(Free) { + AESGCMCipher* obj = ObjectWrap::Unwrap(info.Holder()); + obj->clear(); + } + + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; + return my_constructor; + } + + EVP_CIPHER_CTX* ctx_; +}; + +class GenericCipher : public ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("GenericCipher").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + SetPrototypeMethod(tpl, "encrypt", Encrypt); + SetPrototypeMethod(tpl, "free", Free); + + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); + + Nan::Set(target, + Nan::New("GenericCipher").ToLocalChecked(), + func); + } + + private: + explicit GenericCipher() + : ctx_(nullptr), +#if REAL_OPENSSL_MAJOR >= 3 + mac_(nullptr), + mac_ctx_base_(nullptr), +#else + ctx_hmac_(nullptr), +#endif + hmac_len_(0), + is_etm_(0) {} + + ~GenericCipher() { + clear(); + } + + void clear() { + if (ctx_) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; + } +#if REAL_OPENSSL_MAJOR >= 3 + if (mac_ctx_base_) { + EVP_MAC_CTX_free(mac_ctx_base_); + mac_ctx_base_ = nullptr; + } + if (mac_) { + EVP_MAC_free(mac_); + mac_ = nullptr; + } +#else + if (ctx_hmac_) { + HMAC_CTX_free(ctx_hmac_); + ctx_hmac_ = nullptr; + } +#endif + } + + ErrorType init(const char* name, + unsigned char* key, + size_t key_len, + unsigned char* iv, + size_t iv_len, + const char* hmac_name, + unsigned char* hmac_key, + size_t hmac_key_len, + int is_etm) { + ErrorType r = kErrNone; + +#if REAL_OPENSSL_MAJOR >= 3 + OSSL_PARAM params[2]; +#else + const EVP_MD* md; +#endif + const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name); + if (cipher == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr + || EVP_EncryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + + if (iv_len != static_cast(ctx_iv_len(ctx_))) { + r = kErrBadIVLen; + goto out; + } + + if (key_len != static_cast(ctx_key_len(ctx_))) { + if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) { + r = kErrBadKeyLen; + goto out; + } + } + + // Set key and IV + if (EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) { + r = kErrOpenSSL; + goto out; + } + + // Disable padding + EVP_CIPHER_CTX_set_padding(ctx_, 0); + + if (cipher == EVP_rc4()) { + /* The "arcfour128" algorithm is the RC4 cipher, as described in + [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream + generated by the cipher MUST be discarded, and the first byte of the + first encrypted packet MUST be encrypted using the 1537th byte of + keystream. + + -- http://tools.ietf.org/html/rfc4345#section-4 */ + unsigned char zeros[1536] = {0}; + int outlen = sizeof(zeros); + if (EVP_EncryptUpdate(ctx_, + zeros, + &outlen, + zeros, + sizeof(zeros)) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != sizeof(zeros)) { + r = kErrBadInit; + goto out; + } + } + +#if REAL_OPENSSL_MAJOR >= 3 + if ((mac_ = EVP_MAC_fetch(nullptr, + "HMAC", + "provider=default")) == nullptr) { + r = kErrOpenSSL; + goto out; + } + if ((mac_ctx_base_ = EVP_MAC_CTX_new(mac_)) == nullptr) { + r = kErrOpenSSL; + goto out; + } + params[0] = OSSL_PARAM_construct_utf8_string("digest", + const_cast(hmac_name), + 0); + params[1] = OSSL_PARAM_END; + if (EVP_MAC_init(mac_ctx_base_, hmac_key, hmac_key_len, params) != 1) { + EVP_MAC_CTX_free(mac_ctx_base_); + r = kErrOpenSSL; + goto out; + } + hmac_len_ = EVP_MAC_CTX_get_mac_size(mac_ctx_base_); +#else + md = EVP_get_digestbyname(hmac_name); + if (md == nullptr) { + r = kErrBadHMACName; + goto out; + } + + if ((ctx_hmac_ = HMAC_CTX_new()) == nullptr + || HMAC_Init_ex(ctx_hmac_, hmac_key, hmac_key_len, md, nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + + hmac_len_ = HMAC_size(ctx_hmac_); +#endif + is_etm_ = is_etm; + +out: + return r; + } + + ErrorType encrypt(unsigned char* packet, + uint32_t packet_len, + uint32_t seqno) { + ErrorType r = kErrNone; + + // `packet` layout: + // + uint32_t data_len = packet_len - hmac_len_; + + int outlen; + + uint8_t seqbuf[4] = {0}; + ((uint8_t*)(seqbuf))[0] = (seqno >> 24) & 0xff; + ((uint8_t*)(seqbuf))[1] = (seqno >> 16) & 0xff; + ((uint8_t*)(seqbuf))[2] = (seqno >> 8) & 0xff; + ((uint8_t*)(seqbuf))[3] = seqno & 0xff; + + if (is_etm_) { + // Encrypt everything but packet length + if (EVP_EncryptUpdate(ctx_, + packet + 4, + &outlen, + packet + 4, + data_len - 4) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != data_len - 4) { + r = kErrPartialEncrypt; + goto out; + } + } + + // Calculate HMAC + { +#if REAL_OPENSSL_MAJOR >= 3 + size_t outlen = hmac_len_; + + EVP_MAC_CTX* mac_ctx = EVP_MAC_CTX_dup(mac_ctx_base_); + if (mac_ctx == nullptr) { + r = kErrOpenSSL; + goto out; + } + if (EVP_MAC_update(mac_ctx, seqbuf, sizeof(seqbuf)) != 1 + || EVP_MAC_update(mac_ctx, packet, data_len) != 1 + || EVP_MAC_final(mac_ctx, + packet + data_len, + reinterpret_cast(&outlen), + outlen) != 1) { + EVP_MAC_CTX_free(mac_ctx); + r = kErrOpenSSL; + goto out; + } + if (outlen != hmac_len_) { + EVP_MAC_CTX_free(mac_ctx); + r = kErrBadHMACLen; + goto out; + } + EVP_MAC_CTX_free(mac_ctx); +#else + unsigned int outlen = hmac_len_; + if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1 + || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1 + || HMAC_Update(ctx_hmac_, packet, data_len) != 1 + || HMAC_Final(ctx_hmac_, packet + data_len, &outlen) != 1) { + r = kErrOpenSSL; + goto out; + } + if (outlen != hmac_len_) { + r = kErrBadHMACLen; + goto out; + } +#endif + } + + if (!is_etm_) { + // Encrypt packet + if (EVP_EncryptUpdate(ctx_, + packet, + &outlen, + packet, + data_len) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != data_len) { + + r = kErrPartialEncrypt; + goto out; + } + } + +out: + return r; + } + + static NAN_METHOD(New) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + if (!info[0]->IsString()) + return Nan::ThrowTypeError("Missing/Invalid cipher name"); + + if (!Buffer::HasInstance(info[1])) + return Nan::ThrowTypeError("Missing/Invalid cipher key"); + + if (!Buffer::HasInstance(info[2])) + return Nan::ThrowTypeError("Missing/Invalid cipher IV"); + + if (!info[3]->IsString()) + return Nan::ThrowTypeError("Missing/Invalid HMAC name"); + + if (!Buffer::HasInstance(info[4])) + return Nan::ThrowTypeError("Missing/Invalid HMAC key"); + + if (!info[5]->IsBoolean()) + return Nan::ThrowTypeError("Missing/Invalid HMAC ETM flag"); + + const Nan::Utf8String cipher_name(info[0]); + const Nan::Utf8String mac_name(info[3]); + int is_etm = (Nan::To(info[5]).FromJust() ? 1 : 0); + + GenericCipher* obj = new GenericCipher(); + ErrorType r = obj->init( + *cipher_name, + reinterpret_cast(Buffer::Data(info[1])), + Buffer::Length(info[1]), + reinterpret_cast(Buffer::Data(info[2])), + Buffer::Length(info[2]), + *mac_name, + reinterpret_cast(Buffer::Data(info[4])), + Buffer::Length(info[4]), + is_etm + ); + if (r != kErrNone) { + if (r == kErrOpenSSL) { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + obj->clear(); + delete obj; + return Nan::ThrowError(msg_buf); + } + obj->clear(); + delete obj; + switch (r) { + case kErrBadKeyLen: + return Nan::ThrowError("Invalid keys length"); + case kErrBadIVLen: + return Nan::ThrowError("Invalid IV length"); + case kErrBadCipherName: + return Nan::ThrowError("Invalid cipher name"); + case kErrBadHMACName: + return Nan::ThrowError("Invalid MAC name"); + case kErrBadInit: + return Nan::ThrowError("Failed to properly initialize cipher"); + default: + return Nan::ThrowError("Unknown init failure"); + } + } + + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(Encrypt) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + GenericCipher* obj = ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid packet"); + + if (!info[1]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid sequence number"); + + ErrorType r = obj->encrypt( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]), + Nan::To(info[1]).FromJust() + ); + switch (r) { + case kErrNone: + return; + case kErrPartialEncrypt: + return Nan::ThrowError("Failed to completely encrypt packet"); + case kErrBadHMACLen: + return Nan::ThrowError("Unexpected HMAC length"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown encrypt failure"); + } + } + + static NAN_METHOD(Free) { + GenericCipher* obj = ObjectWrap::Unwrap(info.Holder()); + obj->clear(); + } + + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; + return my_constructor; + } + + EVP_CIPHER_CTX* ctx_; +#if REAL_OPENSSL_MAJOR >= 3 + EVP_MAC* mac_; + EVP_MAC_CTX* mac_ctx_base_; + size_t hmac_len_; +#else + HMAC_CTX* ctx_hmac_; + unsigned int hmac_len_; +#endif + int is_etm_; +}; + +// ============================================================================= + +class ChaChaPolyDecipher : public ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("ChaChaPolyDecipher").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + SetPrototypeMethod(tpl, "decrypt", Decrypt); + SetPrototypeMethod(tpl, "decryptLen", DecryptLen); + SetPrototypeMethod(tpl, "free", Free); + + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); + + Nan::Set(target, + Nan::New("ChaChaPolyDecipher").ToLocalChecked(), + func); + } + + private: + explicit ChaChaPolyDecipher() + : ctx_main_(nullptr), + ctx_pktlen_(nullptr), +#if REAL_OPENSSL_MAJOR >= 3 + mac_(nullptr), + mac_ctx_(nullptr) {} +#else + md_ctx_(nullptr), + polykey_(nullptr), + polykey_ctx_(nullptr) {} +#endif + + ~ChaChaPolyDecipher() { + clear(); + } + + void clear() { + if (ctx_pktlen_) { + EVP_CIPHER_CTX_free(ctx_pktlen_); + ctx_pktlen_ = nullptr; + } + if (ctx_main_) { + EVP_CIPHER_CTX_free(ctx_main_); + ctx_main_ = nullptr; + } +#if REAL_OPENSSL_MAJOR >= 3 + if (mac_ctx_) { + EVP_MAC_CTX_free(mac_ctx_); + mac_ctx_ = nullptr; + } + if (mac_) { + EVP_MAC_free(mac_); + mac_ = nullptr; + } +#else + if (polykey_) { + EVP_PKEY_free(polykey_); + polykey_ = nullptr; + } + if (md_ctx_) { + EVP_MD_CTX_free(md_ctx_); + md_ctx_ = nullptr; + } + // `polykey_ctx_` is not explicitly freed as it is freed implicitly when + // `md_ctx_` is freed +#endif + } + + ErrorType init(unsigned char* keys, size_t keys_len) { + ErrorType r = kErrNone; + const EVP_CIPHER* const cipher = EVP_get_cipherbyname("chacha20"); + + if (keys_len != 64) { + r = kErrBadKeyLen; + goto out; + } + + if (cipher == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr + || (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr +#if REAL_OPENSSL_MAJOR >= 3 + || (mac_ = EVP_MAC_fetch(nullptr, + "POLY1305", + "provider=default")) == nullptr + || (mac_ctx_ = EVP_MAC_CTX_new(mac_)) == nullptr +#else + || (md_ctx_ = EVP_MD_CTX_new()) == nullptr +#endif + || EVP_DecryptInit_ex(ctx_pktlen_, + cipher, + nullptr, + keys + 32, + nullptr) != 1 + || EVP_DecryptInit_ex(ctx_main_, + cipher, + nullptr, + keys, + nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + if (ctx_iv_len(ctx_pktlen_) != 16) { + r = kErrBadIVLen; + goto out; + } + +out: + return r; + } + + ErrorType decrypt_length(unsigned char* data, + size_t data_len, + uint32_t seqno, + uint32_t* packet_length) { + ErrorType r = kErrNone; + int outlen; + + unsigned char dec_length_bytes[4]; + + uint8_t seqbuf[16] = {0}; + ((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff; + ((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff; + ((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff; + ((uint8_t*)(seqbuf))[15] = seqno & 0xff; + + if (EVP_DecryptInit_ex(ctx_pktlen_, + nullptr, + nullptr, + nullptr, + seqbuf) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_DecryptUpdate(ctx_pktlen_, + dec_length_bytes, + &outlen, + data, + data_len) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != 4) { + r = kErrPartialDecrypt; + goto out; + } + + *packet_length = (uint32_t)dec_length_bytes[0] << 24 + | (uint32_t)dec_length_bytes[1] << 16 + | (uint32_t)dec_length_bytes[2] << 8 + | (uint32_t)dec_length_bytes[3]; + memcpy(length_bytes, data, data_len); +out: + return r; + } + + ErrorType decrypt(unsigned char* packet, + uint32_t packet_len, + unsigned char* mac, + uint32_t seqno) { + ErrorType r = kErrNone; + size_t sig_len = 16; + int outlen = 0; + + // `packet` layout: + // + + unsigned char polykey[POLY1305_KEYLEN] = {0}; + unsigned char calc_mac[POLY1305_TAGLEN] = {0}; + + uint8_t seqbuf[16] = {0}; + ((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff; + ((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff; + ((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff; + ((uint8_t*)(seqbuf))[15] = seqno & 0xff; + + // Generate Poly1305 key + if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_EncryptUpdate(ctx_main_, + polykey, + &outlen, + polykey, + sizeof(polykey)) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != sizeof(polykey)) { + r = kErrPartialEncrypt; + goto out; + } + + // Poly1305 over ciphertext +#if REAL_OPENSSL_MAJOR >= 3 + // TODO: check if dup()'ing a "base" context instead of calling init() with + // the key each time is faster + if (EVP_MAC_init(mac_ctx_, polykey, sizeof(polykey), nullptr) != 1 + || EVP_MAC_update(mac_ctx_, length_bytes, sizeof(length_bytes)) != 1 + || EVP_MAC_update(mac_ctx_, packet, packet_len) != 1 + || EVP_MAC_final(mac_ctx_, calc_mac, &sig_len, sig_len) != 1) { + r = kErrOpenSSL; + goto out; + } +#else + if (polykey_) { + if (EVP_PKEY_CTX_ctrl(polykey_ctx_, + -1, + EVP_PKEY_OP_SIGNCTX, + EVP_PKEY_CTRL_SET_MAC_KEY, + sizeof(polykey), + (void*)polykey) <= 0) { + r = kErrOpenSSL; + goto out; + } + } else { + polykey_ = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, + nullptr, + polykey, + sizeof(polykey)); + if (polykey_ == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if (!EVP_DigestSignInit(md_ctx_, + &polykey_ctx_, + nullptr, + nullptr, + polykey_)) { + r = kErrOpenSSL; + goto out; + } + } + if (EVP_DigestSignUpdate(md_ctx_, + length_bytes, + sizeof(length_bytes)) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_DigestSignUpdate(md_ctx_, packet, packet_len) != 1) { + r = kErrOpenSSL; + goto out; + } + + // Generate Poly1305 MAC + if (EVP_DigestSignFinal(md_ctx_, calc_mac, &sig_len) != 1) { + r = kErrOpenSSL; + goto out; + } +#endif + + // Compare MACs + if (CRYPTO_memcmp(mac, calc_mac, sizeof(calc_mac))) { + r = kErrInvalidMAC; + goto out; + } + + // Decrypt packet + seqbuf[0] = 1; + if (EVP_DecryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) { + r = kErrOpenSSL; + goto out; + } + if (EVP_DecryptUpdate(ctx_main_, + packet, + &outlen, + packet, + packet_len) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != packet_len) { + r = kErrPartialDecrypt; + goto out; + } + + out: + return r; + } + + static NAN_METHOD(New) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid keys"); + + ChaChaPolyDecipher* obj = new ChaChaPolyDecipher(); + ErrorType r = obj->init( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]) + ); + if (r != kErrNone) { + if (r == kErrOpenSSL) { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + obj->clear(); + delete obj; + return Nan::ThrowError(msg_buf); + } + obj->clear(); + delete obj; + switch (r) { + case kErrBadKeyLen: + return Nan::ThrowError("Invalid keys length"); + case kErrBadIVLen: + return Nan::ThrowError("Invalid IV length"); + default: + return Nan::ThrowError("Unknown init failure"); + } + } + + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(DecryptLen) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + ChaChaPolyDecipher* obj = + ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0]) || Buffer::Length(info[0]) != 4) + return Nan::ThrowTypeError("Missing/Invalid length bytes"); + + if (!info[1]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid sequence number"); + + unsigned char* length_bytes = + reinterpret_cast(Buffer::Data(info[0])); + + uint32_t dec_packet_length; + ErrorType r = obj->decrypt_length( + length_bytes, + Buffer::Length(info[0]), + Nan::To(info[1]).FromJust(), + &dec_packet_length + ); + + switch (r) { + case kErrNone: + return info.GetReturnValue().Set(dec_packet_length); + case kErrPartialDecrypt: + return Nan::ThrowError("Failed to completely decrypt packet length"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown decrypt failure"); + } + } + + static NAN_METHOD(Decrypt) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + ChaChaPolyDecipher* obj = + ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid packet"); + + if (!Buffer::HasInstance(info[1]) + || Buffer::Length(info[1]) != POLY1305_TAGLEN) { + return Nan::ThrowTypeError("Missing/Invalid mac"); + } + + if (!info[2]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid sequence number"); + + ErrorType r = obj->decrypt( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]), + reinterpret_cast(Buffer::Data(info[1])), + Nan::To(info[2]).FromJust() + ); + + switch (r) { + case kErrNone: + return; + case kErrInvalidMAC: + return Nan::ThrowError("Invalid MAC"); + case kErrPartialDecrypt: + return Nan::ThrowError("Failed to completely decrypt packet length"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown decrypt failure"); + } + } + + static NAN_METHOD(Free) { + ChaChaPolyDecipher* obj = + ObjectWrap::Unwrap(info.Holder()); + obj->clear(); + } + + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; + return my_constructor; + } + + unsigned char length_bytes[4]; + EVP_CIPHER_CTX* ctx_main_; + EVP_CIPHER_CTX* ctx_pktlen_; +#if REAL_OPENSSL_MAJOR >= 3 + EVP_MAC* mac_; + EVP_MAC_CTX* mac_ctx_; +#else + EVP_MD_CTX* md_ctx_; + EVP_PKEY* polykey_; + EVP_PKEY_CTX* polykey_ctx_; +#endif +}; + +class AESGCMDecipher : public ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("AESGCMDecipher").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + SetPrototypeMethod(tpl, "decrypt", Decrypt); + SetPrototypeMethod(tpl, "free", Free); + + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); + + Nan::Set(target, + Nan::New("AESGCMDecipher").ToLocalChecked(), + func); + } + + private: + explicit AESGCMDecipher() : ctx_(nullptr) {} + + ~AESGCMDecipher() { + clear(); + } + + void clear() { + if (ctx_) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; + } + } + + ErrorType init(const char* name, + unsigned char* key, + size_t key_len, + unsigned char* iv, + size_t iv_len) { + ErrorType r = kErrNone; + + const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name); + if (cipher == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if (cipher != EVP_aes_128_gcm() && cipher != EVP_aes_256_gcm()) { + r = kErrBadCipherName; + goto out; + } + + if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr + || EVP_DecryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr)) { + r = kErrOpenSSL; + goto out; + } + + if (key_len != static_cast(ctx_key_len(ctx_))) { + if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) { + r = kErrBadKeyLen; + goto out; + } + } + + // Set key and IV + if (EVP_DecryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) { + r = kErrOpenSSL; + goto out; + } + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IV_FIXED, -1, iv)) { + r = kErrOpenSSL; + goto out; + } + + // Disable padding + EVP_CIPHER_CTX_set_padding(ctx_, 0); + +out: + return r; + } + + ErrorType decrypt(unsigned char* packet, + uint32_t packet_len, + unsigned char* length_bytes, + unsigned char* tag) { + ErrorType r = kErrNone; + + // `packet` layout: + // + + int outlen; + + // Increment IV + unsigned char lastiv[1]; + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_IV_GEN, 1, lastiv)) { + r = kErrOpenSSL; + goto out; + } + + // Set AAD (the packet length) + if (!EVP_DecryptUpdate(ctx_, nullptr, &outlen, length_bytes, 4)) { + r = kErrOpenSSL; + goto out; + } + if (outlen != 4) { + r = kErrAADFailure; + goto out; + } + + // Decrypt everything but the packet length + if (EVP_DecryptUpdate(ctx_, packet, &outlen, packet, packet_len) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != packet_len) { + r = kErrPartialDecrypt; + goto out; + } + + // Set authentication tag + if (EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_TAG, 16, tag) != 1) { + r = kErrOpenSSL; + goto out; + } + + // Verify authentication tag + if (!EVP_DecryptFinal_ex(ctx_, nullptr, &outlen)) { + r = kErrOpenSSL; + goto out; + } + +out: + return r; + } + + static NAN_METHOD(New) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + if (!info[0]->IsString()) + return Nan::ThrowTypeError("Missing/Invalid OpenSSL cipher name"); + + if (!Buffer::HasInstance(info[1])) + return Nan::ThrowTypeError("Missing/Invalid key"); + + if (!Buffer::HasInstance(info[2])) + return Nan::ThrowTypeError("Missing/Invalid iv"); + + const Nan::Utf8String cipher_name(info[0]); + + AESGCMDecipher* obj = new AESGCMDecipher(); + ErrorType r = obj->init( + *cipher_name, + reinterpret_cast(Buffer::Data(info[1])), + Buffer::Length(info[1]), + reinterpret_cast(Buffer::Data(info[2])), + Buffer::Length(info[2]) + ); + if (r != kErrNone) { + if (r == kErrOpenSSL) { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + obj->clear(); + delete obj; + return Nan::ThrowError(msg_buf); + } + obj->clear(); + delete obj; + switch (r) { + case kErrBadKeyLen: + return Nan::ThrowError("Invalid keys length"); + case kErrBadIVLen: + return Nan::ThrowError("Invalid IV length"); + case kErrBadCipherName: + return Nan::ThrowError("Invalid AES GCM cipher name"); + default: + return Nan::ThrowError("Unknown init failure"); + } + } + + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(Decrypt) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + AESGCMDecipher* obj = ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid packet"); + + if (!info[1]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid length"); + + if (!Buffer::HasInstance(info[2]) || Buffer::Length(info[2]) != 16) + return Nan::ThrowTypeError("Missing/Invalid tag"); + + uint32_t length = Nan::To(info[1]).FromJust(); + unsigned char length_bytes[4]; + length_bytes[0] = (length >> 24) & 0xFF; + length_bytes[1] = (length >> 16) & 0xFF; + length_bytes[2] = (length >> 8) & 0xFF; + length_bytes[3] = length & 0xFF; + + ErrorType r = obj->decrypt( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]), + length_bytes, + reinterpret_cast(Buffer::Data(info[2])) + ); + switch (r) { + case kErrNone: + return; + case kErrAADFailure: + return Nan::ThrowError("Error setting AAD"); + case kErrPartialDecrypt: + return Nan::ThrowError("Failed to completely decrypt packet"); + case kErrTagFailure: + return Nan::ThrowError("Error generating authentication tag"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown decrypt failure"); + } + } + + static NAN_METHOD(Free) { + AESGCMDecipher* obj = ObjectWrap::Unwrap(info.Holder()); + obj->clear(); + } + + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; + return my_constructor; + } + + EVP_CIPHER_CTX* ctx_; +}; + +class GenericDecipher : public ObjectWrap { + public: + static NAN_MODULE_INIT(Init) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("GenericDecipher").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + SetPrototypeMethod(tpl, "decryptBlock", DecryptBlock); + SetPrototypeMethod(tpl, "decrypt", Decrypt); + SetPrototypeMethod(tpl, "free", Free); + + Local func = Nan::GetFunction(tpl).ToLocalChecked(); + Local context = Nan::GetCurrentContext(); + v8::Isolate* isolate = context->GetIsolate(); + + constructor().Set(isolate, func); + + Nan::Set(target, + Nan::New("GenericDecipher").ToLocalChecked(), + func); + } + + private: + explicit GenericDecipher() + : ctx_(nullptr), +#if REAL_OPENSSL_MAJOR >= 3 + mac_(nullptr), + mac_ctx_base_(nullptr), +#else + ctx_hmac_(nullptr), +#endif + hmac_len_(0), + is_etm_(0) {} + + ~GenericDecipher() { + clear(); + } + + void clear() { + if (ctx_) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; + } +#if REAL_OPENSSL_MAJOR >= 3 + if (mac_ctx_base_) { + EVP_MAC_CTX_free(mac_ctx_base_); + mac_ctx_base_ = nullptr; + } + if (mac_) { + EVP_MAC_free(mac_); + mac_ = nullptr; + } +#else + if (ctx_hmac_) { + HMAC_CTX_free(ctx_hmac_); + ctx_hmac_ = nullptr; + } +#endif + } + + ErrorType init(const char* name, + unsigned char* key, + size_t key_len, + unsigned char* iv, + size_t iv_len, + const char* hmac_name, + unsigned char* hmac_key, + size_t hmac_key_len, + int is_etm, + size_t hmac_actual_len) { + ErrorType r = kErrNone; + +#if REAL_OPENSSL_MAJOR >= 3 + OSSL_PARAM params[2]; +#else + const EVP_MD* md; +#endif + const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name); + if (cipher == nullptr) { + r = kErrOpenSSL; + goto out; + } + + if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr + || EVP_DecryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + + if (iv_len != static_cast(ctx_iv_len(ctx_))) { + r = kErrBadIVLen; + goto out; + } + + if (key_len != static_cast(ctx_key_len(ctx_))) { + if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) { + r = kErrBadKeyLen; + goto out; + } + } + + // Set key and IV + if (EVP_DecryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) { + r = kErrOpenSSL; + goto out; + } + + // Disable padding + EVP_CIPHER_CTX_set_padding(ctx_, 0); + + if (cipher == EVP_rc4()) { + /* The "arcfour128" algorithm is the RC4 cipher, as described in + [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream + generated by the cipher MUST be discarded, and the first byte of the + first encrypted packet MUST be encrypted using the 1537th byte of + keystream. + + -- http://tools.ietf.org/html/rfc4345#section-4 */ + unsigned char zeros[1536] = {0}; + int outlen = sizeof(zeros); + if (EVP_DecryptUpdate(ctx_, + zeros, + &outlen, + zeros, + sizeof(zeros)) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != sizeof(zeros)) { + r = kErrBadInit; + goto out; + } + } + +#if REAL_OPENSSL_MAJOR >= 3 + if ((mac_ = EVP_MAC_fetch(nullptr, + "HMAC", + "provider=default")) == nullptr) { + r = kErrOpenSSL; + goto out; + } + if ((mac_ctx_base_ = EVP_MAC_CTX_new(mac_)) == nullptr) { + r = kErrOpenSSL; + goto out; + } + params[0] = OSSL_PARAM_construct_utf8_string("digest", + const_cast(hmac_name), + 0); + params[1] = OSSL_PARAM_END; + if (EVP_MAC_init(mac_ctx_base_, hmac_key, hmac_key_len, params) != 1) { + EVP_MAC_CTX_free(mac_ctx_base_); + r = kErrOpenSSL; + goto out; + } + hmac_len_ = EVP_MAC_CTX_get_mac_size(mac_ctx_base_); +#else + md = EVP_get_digestbyname(hmac_name); + if (md == nullptr) { + r = kErrBadHMACName; + goto out; + } + + if ((ctx_hmac_ = HMAC_CTX_new()) == nullptr + || HMAC_Init_ex(ctx_hmac_, hmac_key, hmac_key_len, md, nullptr) != 1) { + r = kErrOpenSSL; + goto out; + } + + hmac_len_ = HMAC_size(ctx_hmac_); +#endif + hmac_actual_len_ = hmac_actual_len; + is_etm_ = is_etm; +#if REAL_OPENSSL_MAJOR >= 3 + switch (EVP_CIPHER_CTX_mode(ctx_)) { +#else + switch (cipher_flags(EVP_CIPHER_CTX_cipher(ctx_)) & EVP_CIPH_MODE) { +#endif + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_CTR_MODE: + is_stream_ = 1; + break; + default: + is_stream_ = 0; + } + block_size_ = ctx_get_block_size(ctx_); + +out: + return r; + } + + ErrorType decrypt_block(unsigned char* data, uint32_t data_len) { + ErrorType r = kErrNone; + + int outlen; + + if (!is_stream_ && data_len != block_size_) { + r = kErrBadBlockLen; + goto out; + } + + // Decrypt block + if (EVP_DecryptUpdate(ctx_, data, &outlen, data, data_len) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != data_len) { + r = kErrPartialDecrypt; + goto out; + } + +out: + return r; + } + + ErrorType decrypt(unsigned char* packet, + uint32_t packet_len, + uint32_t seqno, + unsigned char* first_block, + uint32_t first_block_len, + unsigned char* mac, + uint32_t mac_len) { + ErrorType r = kErrNone; + + int outlen; + unsigned char calc_mac[MAX_MAC_LEN] = {0}; + + uint8_t seqbuf[4] = {0}; + ((uint8_t*)(seqbuf))[0] = (seqno >> 24) & 0xff; + ((uint8_t*)(seqbuf))[1] = (seqno >> 16) & 0xff; + ((uint8_t*)(seqbuf))[2] = (seqno >> 8) & 0xff; + ((uint8_t*)(seqbuf))[3] = seqno & 0xff; + + if (!is_etm_) { + // `first_block` for non-ETM should be a completely decrypted first block + if (!is_stream_ && first_block_len != block_size_) { + r = kErrBadBlockLen; + goto out; + } + + const int offset = (is_stream_ ? 0 : block_size_ - 4); + // Decrypt the rest of the packet + if (EVP_DecryptUpdate(ctx_, + packet + offset, + &outlen, + packet + offset, + packet_len - offset) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != packet_len - offset) { + r = kErrPartialDecrypt; + goto out; + } + } + + // Calculate and compare HMAC + { +#if REAL_OPENSSL_MAJOR >= 3 + size_t outlen = hmac_len_; + + EVP_MAC_CTX* mac_ctx = EVP_MAC_CTX_dup(mac_ctx_base_); + if (mac_ctx == nullptr) { + r = kErrOpenSSL; + goto out; + } + if (EVP_MAC_update(mac_ctx, seqbuf, sizeof(seqbuf)) != 1 + || EVP_MAC_update(mac_ctx, first_block, 4) != 1 + || EVP_MAC_update(mac_ctx, packet, packet_len) != 1 + || EVP_MAC_final(mac_ctx, + calc_mac, + &outlen, + outlen) != 1) { + EVP_MAC_CTX_free(mac_ctx); + r = kErrOpenSSL; + goto out; + } + if (outlen != hmac_len_ || mac_len != hmac_actual_len_) { + EVP_MAC_CTX_free(mac_ctx); + r = kErrBadHMACLen; + goto out; + } + EVP_MAC_CTX_free(mac_ctx); +#else + unsigned int outlen = hmac_len_; + if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1 + || HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1 + || HMAC_Update(ctx_hmac_, first_block, 4) != 1 + || HMAC_Update(ctx_hmac_, packet, packet_len) != 1 + || HMAC_Final(ctx_hmac_, calc_mac, &outlen) != 1) { + r = kErrOpenSSL; + goto out; + } + if (outlen != hmac_len_ || mac_len != hmac_actual_len_) { + r = kErrBadHMACLen; + goto out; + } +#endif + + // Compare MACs + if (CRYPTO_memcmp(mac, calc_mac, hmac_actual_len_)) { + r = kErrInvalidMAC; + goto out; + } + } + + if (is_etm_) { + // `first_block` for ETM should just be the unencrypted packet length + if (first_block_len != 4) { + r = kErrBadBlockLen; + goto out; + } + + // Decrypt packet + if (EVP_DecryptUpdate(ctx_, packet, &outlen, packet, packet_len) != 1) { + r = kErrOpenSSL; + goto out; + } + if (static_cast(outlen) != packet_len) { + r = kErrPartialDecrypt; + goto out; + } + } + +out: + return r; + } + + static NAN_METHOD(New) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + if (!info[0]->IsString()) + return Nan::ThrowTypeError("Missing/Invalid decipher name"); + + if (!Buffer::HasInstance(info[1])) + return Nan::ThrowTypeError("Missing/Invalid decipher key"); + + if (!Buffer::HasInstance(info[2])) + return Nan::ThrowTypeError("Missing/Invalid decipher IV"); + + if (!info[3]->IsString()) + return Nan::ThrowTypeError("Missing/Invalid HMAC name"); + + if (!Buffer::HasInstance(info[4])) + return Nan::ThrowTypeError("Missing/Invalid HMAC key"); + + if (!info[5]->IsBoolean()) + return Nan::ThrowTypeError("Missing/Invalid HMAC ETM flag"); + + if (!info[6]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid HMAC ETM flag"); + + const Nan::Utf8String cipher_name(info[0]); + const Nan::Utf8String mac_name(info[3]); + int is_etm = (Nan::To(info[5]).FromJust() ? 1 : 0); + + GenericDecipher* obj = new GenericDecipher(); + ErrorType r = obj->init( + *cipher_name, + reinterpret_cast(Buffer::Data(info[1])), + Buffer::Length(info[1]), + reinterpret_cast(Buffer::Data(info[2])), + Buffer::Length(info[2]), + *mac_name, + reinterpret_cast(Buffer::Data(info[4])), + Buffer::Length(info[4]), + is_etm, + Nan::To(info[6]).FromJust() + ); + if (r != kErrNone) { + if (r == kErrOpenSSL) { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + obj->clear(); + delete obj; + return Nan::ThrowError(msg_buf); + } + obj->clear(); + delete obj; + switch (r) { + case kErrBadKeyLen: + return Nan::ThrowError("Invalid decipher key length"); + case kErrBadIVLen: + return Nan::ThrowError("Invalid decipher IV length"); + case kErrBadCipherName: + return Nan::ThrowError("Invalid decipher name"); + case kErrBadHMACName: + return Nan::ThrowError("Invalid MAC name"); + case kErrBadInit: + return Nan::ThrowError("Failed to properly initialize decipher"); + default: + return Nan::ThrowError("Unknown init failure"); + } + } + + obj->Wrap(info.This()); + info.GetReturnValue().Set(info.This()); + } + + static NAN_METHOD(DecryptBlock) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + GenericDecipher* obj = ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid block"); + + ErrorType r = obj->decrypt_block( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]) + ); + switch (r) { + case kErrNone: + return; + case kErrBadBlockLen: + return Nan::ThrowError("Invalid block length"); + case kErrPartialDecrypt: + return Nan::ThrowError("Failed to completely decrypt packet"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown decrypt failure"); + } + } + + static NAN_METHOD(Decrypt) { + MarkPopErrorOnReturn mark_pop_error_on_return; + + GenericDecipher* obj = ObjectWrap::Unwrap(info.Holder()); + + if (!Buffer::HasInstance(info[0])) + return Nan::ThrowTypeError("Missing/Invalid packet"); + + if (!info[1]->IsUint32()) + return Nan::ThrowTypeError("Missing/Invalid sequence number"); + + if (!Buffer::HasInstance(info[2])) + return Nan::ThrowTypeError("Missing/Invalid first block"); + + if (!Buffer::HasInstance(info[3])) + return Nan::ThrowTypeError("Missing/Invalid MAC"); + + ErrorType r = obj->decrypt( + reinterpret_cast(Buffer::Data(info[0])), + Buffer::Length(info[0]), + Nan::To(info[1]).FromJust(), + reinterpret_cast(Buffer::Data(info[2])), + Buffer::Length(info[2]), + reinterpret_cast(Buffer::Data(info[3])), + Buffer::Length(info[3]) + ); + switch (r) { + case kErrNone: + return; + case kErrBadBlockLen: + return Nan::ThrowError("Invalid block length"); + case kErrPartialDecrypt: + return Nan::ThrowError("Failed to completely decrypt packet"); + case kErrBadHMACLen: + return Nan::ThrowError("Unexpected HMAC length"); + case kErrInvalidMAC: + return Nan::ThrowError("Invalid MAC"); + case kErrOpenSSL: { + char msg_buf[128] = {0}; + ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf)); + ERR_clear_error(); + return Nan::ThrowError(msg_buf); + } + default: + return Nan::ThrowError("Unknown decrypt failure"); + } + } + + static NAN_METHOD(Free) { + GenericDecipher* obj = ObjectWrap::Unwrap(info.Holder()); + obj->clear(); + } + + static inline v8::Eternal & constructor() { + static v8::Eternal my_constructor; + return my_constructor; + } + + EVP_CIPHER_CTX* ctx_; +#if REAL_OPENSSL_MAJOR >= 3 + EVP_MAC* mac_; + EVP_MAC_CTX* mac_ctx_base_; + size_t hmac_len_; +#else + HMAC_CTX* ctx_hmac_; + unsigned int hmac_len_; +#endif + unsigned int hmac_actual_len_; + uint8_t is_etm_; + uint8_t is_stream_; + uint32_t block_size_; +}; + + +NAN_MODULE_INIT(init) { + // These are needed because node-gyp (as of this writing) does not use the + // proper (OpenSSL) system headers when node was built against a shared + // version of OpenSSL. Usually this isn't an issue because OSes that build + // node in this way typically use the same version of OpenSSL as was bundled + // with node for a particular node version for the best compatibility. However + // with the inclusion of OpenSSL 3.x in node v17.x, some OSes are still + // linking with a shared OpenSSL 1.x, which can cause both compilation and + // runtime errors because of changes in OpenSSL's code. + // + // For that reason, we need to make sure we need to resolve some specific + // symbols at runtime to workaround these buggy situations. +#ifdef _WIN32 +# define load_sym(name) GetProcAddress(GetModuleHandle(NULL), name) +#else +# define load_sym(name) dlsym(RTLD_DEFAULT, name) +#endif + if (!ctx_iv_len) { + ctx_iv_len = reinterpret_cast( + load_sym("EVP_CIPHER_CTX_get_iv_length") + ); + if (!ctx_iv_len) { + ctx_iv_len = reinterpret_cast( + load_sym("EVP_CIPHER_CTX_iv_length") + ); + } + } + if (!ctx_key_len) { + ctx_key_len = reinterpret_cast( + load_sym("EVP_CIPHER_CTX_get_key_length") + ); + if (!ctx_key_len) { + ctx_key_len = reinterpret_cast( + load_sym("EVP_CIPHER_CTX_key_length") + ); + } + } + if (!cipher_flags) { + cipher_flags = reinterpret_cast( + load_sym("EVP_CIPHER_get_flags") + ); + if (!cipher_flags) { + cipher_flags = reinterpret_cast( + load_sym("EVP_CIPHER_flags") + ); + } + } + if (!ctx_get_block_size) { + ctx_get_block_size = reinterpret_cast( + load_sym("EVP_CIPHER_CTX_get_block_size") + ); + if (!ctx_get_block_size) { + ctx_get_block_size = reinterpret_cast( + load_sym("EVP_CIPHER_CTX_block_size") + ); + } + } + + ChaChaPolyCipher::Init(target); + AESGCMCipher::Init(target); + GenericCipher::Init(target); + + ChaChaPolyDecipher::Init(target); + AESGCMDecipher::Init(target); + GenericDecipher::Init(target); +} + +DISABLE_WCAST_FUNCTION_TYPE +NAN_MODULE_WORKER_ENABLED(sshcrypto, init) +DISABLE_WCAST_FUNCTION_TYPE_END diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.js new file mode 100644 index 0000000..35fb9f2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.js @@ -0,0 +1,16 @@ +'use strict'; + +const MESSAGE_HANDLERS = new Array(256); +[ + require('./kex.js').HANDLERS, + require('./handlers.misc.js'), +].forEach((handlers) => { + // eslint-disable-next-line prefer-const + for (let [type, handler] of Object.entries(handlers)) { + type = +type; + if (isFinite(type) && type >= 0 && type < MESSAGE_HANDLERS.length) + MESSAGE_HANDLERS[type] = handler; + } +}); + +module.exports = MESSAGE_HANDLERS; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.misc.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.misc.js new file mode 100644 index 0000000..24580be --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/handlers.misc.js @@ -0,0 +1,1285 @@ +'use strict'; + +const { + bufferSlice, + bufferParser, + doFatalError, + sigSSHToASN1, + writeUInt32BE, +} = require('./utils.js'); + +const { + CHANNEL_OPEN_FAILURE, + COMPAT, + MESSAGE, + TERMINAL_MODE, +} = require('./constants.js'); + +const { + parseKey, +} = require('./keyParser.js'); + +const TERMINAL_MODE_BY_VALUE = + Array.from(Object.entries(TERMINAL_MODE)) + .reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {}); + +module.exports = { + // Transport layer protocol ================================================== + [MESSAGE.DISCONNECT]: (self, payload) => { + /* + byte SSH_MSG_DISCONNECT + uint32 reason code + string description in ISO-10646 UTF-8 encoding + string language tag + */ + bufferParser.init(payload, 1); + const reason = bufferParser.readUInt32BE(); + const desc = bufferParser.readString(true); + const lang = bufferParser.readString(); + bufferParser.clear(); + + if (lang === undefined) { + return doFatalError( + self, + 'Inbound: Malformed DISCONNECT packet' + ); + } + + self._debug && self._debug( + `Inbound: Received DISCONNECT (${reason}, "${desc}")` + ); + + const handler = self._handlers.DISCONNECT; + handler && handler(self, reason, desc); + }, + [MESSAGE.IGNORE]: (self, payload) => { + /* + byte SSH_MSG_IGNORE + string data + */ + self._debug && self._debug('Inbound: Received IGNORE'); + }, + [MESSAGE.UNIMPLEMENTED]: (self, payload) => { + /* + byte SSH_MSG_UNIMPLEMENTED + uint32 packet sequence number of rejected message + */ + bufferParser.init(payload, 1); + const seqno = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (seqno === undefined) { + return doFatalError( + self, + 'Inbound: Malformed UNIMPLEMENTED packet' + ); + } + + self._debug + && self._debug(`Inbound: Received UNIMPLEMENTED (seqno ${seqno})`); + }, + [MESSAGE.DEBUG]: (self, payload) => { + /* + byte SSH_MSG_DEBUG + boolean always_display + string message in ISO-10646 UTF-8 encoding [RFC3629] + string language tag [RFC3066] + */ + bufferParser.init(payload, 1); + const display = bufferParser.readBool(); + const msg = bufferParser.readString(true); + const lang = bufferParser.readString(); + bufferParser.clear(); + + if (lang === undefined) { + return doFatalError( + self, + 'Inbound: Malformed DEBUG packet' + ); + } + + self._debug && self._debug('Inbound: Received DEBUG'); + + const handler = self._handlers.DEBUG; + handler && handler(self, display, msg); + }, + [MESSAGE.SERVICE_REQUEST]: (self, payload) => { + /* + byte SSH_MSG_SERVICE_REQUEST + string service name + */ + bufferParser.init(payload, 1); + const name = bufferParser.readString(true); + bufferParser.clear(); + + if (name === undefined) { + return doFatalError( + self, + 'Inbound: Malformed SERVICE_REQUEST packet' + ); + } + + self._debug && self._debug(`Inbound: Received SERVICE_REQUEST (${name})`); + + const handler = self._handlers.SERVICE_REQUEST; + handler && handler(self, name); + }, + [MESSAGE.SERVICE_ACCEPT]: (self, payload) => { + // S->C + /* + byte SSH_MSG_SERVICE_ACCEPT + string service name + */ + bufferParser.init(payload, 1); + const name = bufferParser.readString(true); + bufferParser.clear(); + + if (name === undefined) { + return doFatalError( + self, + 'Inbound: Malformed SERVICE_ACCEPT packet' + ); + } + + self._debug && self._debug(`Inbound: Received SERVICE_ACCEPT (${name})`); + + const handler = self._handlers.SERVICE_ACCEPT; + handler && handler(self, name); + }, + [MESSAGE.EXT_INFO]: (self, payload) => { + /* + byte SSH_MSG_EXT_INFO + uint32 nr-extensions + repeat the following 2 fields "nr-extensions" times: + string extension-name + string extension-value (binary) + */ + bufferParser.init(payload, 1); + const numExts = bufferParser.readUInt32BE(); + let exts; + if (numExts !== undefined) { + exts = []; + for (let i = 0; i < numExts; ++i) { + const name = bufferParser.readString(true); + const data = bufferParser.readString(); + if (data !== undefined) { + switch (name) { + case 'server-sig-algs': { + const algs = data.latin1Slice(0, data.length).split(','); + exts.push({ name, algs }); + continue; + } + default: + continue; + } + } + // Malformed + exts = undefined; + break; + } + } + bufferParser.clear(); + + if (exts === undefined) + return doFatalError(self, 'Inbound: Malformed EXT_INFO packet'); + + self._debug && self._debug('Inbound: Received EXT_INFO'); + + const handler = self._handlers.EXT_INFO; + handler && handler(self, exts); + }, + + // User auth protocol -- generic ============================================= + [MESSAGE.USERAUTH_REQUEST]: (self, payload) => { + /* + byte SSH_MSG_USERAUTH_REQUEST + string user name in ISO-10646 UTF-8 encoding [RFC3629] + string service name in US-ASCII + string method name in US-ASCII + .... method specific fields + */ + bufferParser.init(payload, 1); + const user = bufferParser.readString(true); + const service = bufferParser.readString(true); + const method = bufferParser.readString(true); + let methodData; + let methodDesc; + switch (method) { + case 'none': + methodData = null; + break; + case 'password': { + /* + boolean + string plaintext password in ISO-10646 UTF-8 encoding [RFC3629] + [string new password] + */ + const isChange = bufferParser.readBool(); + if (isChange !== undefined) { + methodData = bufferParser.readString(true); + if (methodData !== undefined && isChange) { + const newPassword = bufferParser.readString(true); + if (newPassword !== undefined) + methodData = { oldPassword: methodData, newPassword }; + else + methodData = undefined; + } + } + break; + } + case 'publickey': { + /* + boolean + string public key algorithm name + string public key blob + [string signature] + */ + const hasSig = bufferParser.readBool(); + if (hasSig !== undefined) { + const keyAlgo = bufferParser.readString(true); + let realKeyAlgo = keyAlgo; + const key = bufferParser.readString(); + + let hashAlgo; + switch (keyAlgo) { + case 'rsa-sha2-256': + realKeyAlgo = 'ssh-rsa'; + hashAlgo = 'sha256'; + break; + case 'rsa-sha2-512': + realKeyAlgo = 'ssh-rsa'; + hashAlgo = 'sha512'; + break; + } + + if (hasSig) { + const blobEnd = bufferParser.pos(); + let signature = bufferParser.readString(); + if (signature !== undefined) { + if (signature.length > (4 + keyAlgo.length + 4) + && signature.utf8Slice(4, 4 + keyAlgo.length) === keyAlgo) { + // Skip algoLen + algo + sigLen + signature = bufferSlice(signature, 4 + keyAlgo.length + 4); + } + + signature = sigSSHToASN1(signature, realKeyAlgo); + if (signature) { + const sessionID = self._kex.sessionID; + const blob = Buffer.allocUnsafe(4 + sessionID.length + blobEnd); + writeUInt32BE(blob, sessionID.length, 0); + blob.set(sessionID, 4); + blob.set( + new Uint8Array(payload.buffer, payload.byteOffset, blobEnd), + 4 + sessionID.length + ); + methodData = { + keyAlgo: realKeyAlgo, + key, + signature, + blob, + hashAlgo, + }; + } + } + } else { + methodData = { keyAlgo: realKeyAlgo, key, hashAlgo }; + methodDesc = 'publickey -- check'; + } + } + break; + } + case 'hostbased': { + /* + string public key algorithm for host key + string public host key and certificates for client host + string client host name expressed as the FQDN in US-ASCII + string user name on the client host in ISO-10646 UTF-8 encoding + [RFC3629] + string signature + */ + const keyAlgo = bufferParser.readString(true); + let realKeyAlgo = keyAlgo; + const key = bufferParser.readString(); + const localHostname = bufferParser.readString(true); + const localUsername = bufferParser.readString(true); + + let hashAlgo; + switch (keyAlgo) { + case 'rsa-sha2-256': + realKeyAlgo = 'ssh-rsa'; + hashAlgo = 'sha256'; + break; + case 'rsa-sha2-512': + realKeyAlgo = 'ssh-rsa'; + hashAlgo = 'sha512'; + break; + } + + const blobEnd = bufferParser.pos(); + let signature = bufferParser.readString(); + if (signature !== undefined) { + if (signature.length > (4 + keyAlgo.length + 4) + && signature.utf8Slice(4, 4 + keyAlgo.length) === keyAlgo) { + // Skip algoLen + algo + sigLen + signature = bufferSlice(signature, 4 + keyAlgo.length + 4); + } + + signature = sigSSHToASN1(signature, realKeyAlgo); + if (signature !== undefined) { + const sessionID = self._kex.sessionID; + const blob = Buffer.allocUnsafe(4 + sessionID.length + blobEnd); + writeUInt32BE(blob, sessionID.length, 0); + blob.set(sessionID, 4); + blob.set( + new Uint8Array(payload.buffer, payload.byteOffset, blobEnd), + 4 + sessionID.length + ); + methodData = { + keyAlgo: realKeyAlgo, + key, + signature, + blob, + localHostname, + localUsername, + hashAlgo + }; + } + } + break; + } + case 'keyboard-interactive': + /* + string language tag (as defined in [RFC-3066]) + string submethods (ISO-10646 UTF-8) + */ + // Skip/ignore language field -- it's deprecated in RFC 4256 + bufferParser.skipString(); + + methodData = bufferParser.readList(); + break; + default: + if (method !== undefined) + methodData = bufferParser.readRaw(); + } + bufferParser.clear(); + + if (methodData === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_REQUEST packet' + ); + } + + if (methodDesc === undefined) + methodDesc = method; + + self._authsQueue.push(method); + + self._debug + && self._debug(`Inbound: Received USERAUTH_REQUEST (${methodDesc})`); + + const handler = self._handlers.USERAUTH_REQUEST; + handler && handler(self, user, service, method, methodData); + }, + [MESSAGE.USERAUTH_FAILURE]: (self, payload) => { + // S->C + /* + byte SSH_MSG_USERAUTH_FAILURE + name-list authentications that can continue + boolean partial success + */ + bufferParser.init(payload, 1); + const authMethods = bufferParser.readList(); + const partialSuccess = bufferParser.readBool(); + bufferParser.clear(); + + if (partialSuccess === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_FAILURE packet' + ); + } + + self._debug + && self._debug(`Inbound: Received USERAUTH_FAILURE (${authMethods})`); + + self._authsQueue.shift(); + const handler = self._handlers.USERAUTH_FAILURE; + handler && handler(self, authMethods, partialSuccess); + }, + [MESSAGE.USERAUTH_SUCCESS]: (self, payload) => { + // S->C + /* + byte SSH_MSG_USERAUTH_SUCCESS + */ + self._debug && self._debug('Inbound: Received USERAUTH_SUCCESS'); + + self._authsQueue.shift(); + const handler = self._handlers.USERAUTH_SUCCESS; + handler && handler(self); + }, + [MESSAGE.USERAUTH_BANNER]: (self, payload) => { + // S->C + /* + byte SSH_MSG_USERAUTH_BANNER + string message in ISO-10646 UTF-8 encoding [RFC3629] + string language tag [RFC3066] + */ + bufferParser.init(payload, 1); + const msg = bufferParser.readString(true); + const lang = bufferParser.readString(); + bufferParser.clear(); + + if (lang === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_BANNER packet' + ); + } + + self._debug && self._debug('Inbound: Received USERAUTH_BANNER'); + + const handler = self._handlers.USERAUTH_BANNER; + handler && handler(self, msg); + }, + + // User auth protocol -- method-specific ===================================== + 60: (self, payload) => { + if (!self._authsQueue.length) { + self._debug + && self._debug('Inbound: Received payload type 60 without auth'); + return; + } + + switch (self._authsQueue[0]) { + case 'password': { + // S->C + /* + byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ + string prompt in ISO-10646 UTF-8 encoding [RFC3629] + string language tag [RFC3066] + */ + bufferParser.init(payload, 1); + const prompt = bufferParser.readString(true); + const lang = bufferParser.readString(); + bufferParser.clear(); + + if (lang === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_PASSWD_CHANGEREQ packet' + ); + } + + self._debug + && self._debug('Inbound: Received USERAUTH_PASSWD_CHANGEREQ'); + + const handler = self._handlers.USERAUTH_PASSWD_CHANGEREQ; + handler && handler(self, prompt); + break; + } + case 'publickey': { + // S->C + /* + byte SSH_MSG_USERAUTH_PK_OK + string public key algorithm name from the request + string public key blob from the request + */ + bufferParser.init(payload, 1); + const keyAlgo = bufferParser.readString(true); + const key = bufferParser.readString(); + bufferParser.clear(); + + if (key === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_PK_OK packet' + ); + } + + self._debug && self._debug('Inbound: Received USERAUTH_PK_OK'); + + self._authsQueue.shift(); + const handler = self._handlers.USERAUTH_PK_OK; + handler && handler(self, keyAlgo, key); + break; + } + case 'keyboard-interactive': { + // S->C + /* + byte SSH_MSG_USERAUTH_INFO_REQUEST + string name (ISO-10646 UTF-8) + string instruction (ISO-10646 UTF-8) + string language tag (as defined in [RFC-3066]) + int num-prompts + string prompt[1] (ISO-10646 UTF-8) + boolean echo[1] + ... + string prompt[num-prompts] (ISO-10646 UTF-8) + boolean echo[num-prompts] + */ + bufferParser.init(payload, 1); + const name = bufferParser.readString(true); + const instructions = bufferParser.readString(true); + bufferParser.readString(); // skip lang + const numPrompts = bufferParser.readUInt32BE(); + let prompts; + if (numPrompts !== undefined) { + prompts = new Array(numPrompts); + let i; + for (i = 0; i < numPrompts; ++i) { + const prompt = bufferParser.readString(true); + const echo = bufferParser.readBool(); + if (echo === undefined) + break; + prompts[i] = { prompt, echo }; + } + if (i !== numPrompts) + prompts = undefined; + } + bufferParser.clear(); + + if (prompts === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_INFO_REQUEST packet' + ); + } + + self._debug && self._debug('Inbound: Received USERAUTH_INFO_REQUEST'); + + const handler = self._handlers.USERAUTH_INFO_REQUEST; + handler && handler(self, name, instructions, prompts); + break; + } + default: + self._debug + && self._debug('Inbound: Received unexpected payload type 60'); + } + }, + 61: (self, payload) => { + if (!self._authsQueue.length) { + self._debug + && self._debug('Inbound: Received payload type 61 without auth'); + return; + } + /* + byte SSH_MSG_USERAUTH_INFO_RESPONSE + int num-responses + string response[1] (ISO-10646 UTF-8) + ... + string response[num-responses] (ISO-10646 UTF-8) + */ + if (self._authsQueue[0] !== 'keyboard-interactive') { + return doFatalError( + self, + 'Inbound: Received unexpected payload type 61' + ); + } + bufferParser.init(payload, 1); + const numResponses = bufferParser.readUInt32BE(); + let responses; + if (numResponses !== undefined) { + responses = new Array(numResponses); + let i; + for (i = 0; i < numResponses; ++i) { + const response = bufferParser.readString(true); + if (response === undefined) + break; + responses[i] = response; + } + if (i !== numResponses) + responses = undefined; + } + bufferParser.clear(); + + if (responses === undefined) { + return doFatalError( + self, + 'Inbound: Malformed USERAUTH_INFO_RESPONSE packet' + ); + } + + self._debug && self._debug('Inbound: Received USERAUTH_INFO_RESPONSE'); + + const handler = self._handlers.USERAUTH_INFO_RESPONSE; + handler && handler(self, responses); + }, + + // Connection protocol -- generic ============================================ + [MESSAGE.GLOBAL_REQUEST]: (self, payload) => { + /* + byte SSH_MSG_GLOBAL_REQUEST + string request name in US-ASCII only + boolean want reply + .... request-specific data follows + */ + bufferParser.init(payload, 1); + const name = bufferParser.readString(true); + const wantReply = bufferParser.readBool(); + let data; + if (wantReply !== undefined) { + switch (name) { + case 'tcpip-forward': + case 'cancel-tcpip-forward': { + /* + string address to bind (e.g., "0.0.0.0") + uint32 port number to bind + */ + const bindAddr = bufferParser.readString(true); + const bindPort = bufferParser.readUInt32BE(); + if (bindPort !== undefined) + data = { bindAddr, bindPort }; + break; + } + case 'streamlocal-forward@openssh.com': + case 'cancel-streamlocal-forward@openssh.com': { + /* + string socket path + */ + const socketPath = bufferParser.readString(true); + if (socketPath !== undefined) + data = { socketPath }; + break; + } + case 'no-more-sessions@openssh.com': + data = null; + break; + case 'hostkeys-00@openssh.com': { + data = []; + while (bufferParser.avail() > 0) { + const keyRaw = bufferParser.readString(); + if (keyRaw === undefined) { + data = undefined; + break; + } + const key = parseKey(keyRaw); + if (!(key instanceof Error)) + data.push(key); + } + break; + } + default: + data = bufferParser.readRaw(); + } + } + bufferParser.clear(); + + if (data === undefined) { + return doFatalError( + self, + 'Inbound: Malformed GLOBAL_REQUEST packet' + ); + } + + self._debug && self._debug(`Inbound: GLOBAL_REQUEST (${name})`); + + const handler = self._handlers.GLOBAL_REQUEST; + if (handler) + handler(self, name, wantReply, data); + else + self.requestFailure(); // Auto reject + }, + [MESSAGE.REQUEST_SUCCESS]: (self, payload) => { + /* + byte SSH_MSG_REQUEST_SUCCESS + .... response specific data + */ + const data = (payload.length > 1 ? bufferSlice(payload, 1) : null); + + self._debug && self._debug('Inbound: REQUEST_SUCCESS'); + + const handler = self._handlers.REQUEST_SUCCESS; + handler && handler(self, data); + }, + [MESSAGE.REQUEST_FAILURE]: (self, payload) => { + /* + byte SSH_MSG_REQUEST_FAILURE + */ + self._debug && self._debug('Inbound: Received REQUEST_FAILURE'); + + const handler = self._handlers.REQUEST_FAILURE; + handler && handler(self); + }, + + // Connection protocol -- channel-related ==================================== + [MESSAGE.CHANNEL_OPEN]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_OPEN + string channel type in US-ASCII only + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + .... channel type specific data follows + */ + bufferParser.init(payload, 1); + const type = bufferParser.readString(true); + const sender = bufferParser.readUInt32BE(); + const window = bufferParser.readUInt32BE(); + const packetSize = bufferParser.readUInt32BE(); + let channelInfo; + + switch (type) { + case 'forwarded-tcpip': // S->C + case 'direct-tcpip': { // C->S + /* + string address that was connected / host to connect + uint32 port that was connected / port to connect + string originator IP address + uint32 originator port + */ + const destIP = bufferParser.readString(true); + const destPort = bufferParser.readUInt32BE(); + const srcIP = bufferParser.readString(true); + const srcPort = bufferParser.readUInt32BE(); + if (srcPort !== undefined) { + channelInfo = { + type, + sender, + window, + packetSize, + data: { destIP, destPort, srcIP, srcPort } + }; + } + break; + } + case 'forwarded-streamlocal@openssh.com': // S->C + case 'direct-streamlocal@openssh.com': { // C->S + /* + string socket path + string reserved for future use + + (direct-streamlocal@openssh.com additionally has:) + uint32 reserved + */ + const socketPath = bufferParser.readString(true); + if (socketPath !== undefined) { + channelInfo = { + type, + sender, + window, + packetSize, + data: { socketPath } + }; + } + break; + } + case 'x11': { // S->C + /* + string originator address (e.g., "192.168.7.38") + uint32 originator port + */ + const srcIP = bufferParser.readString(true); + const srcPort = bufferParser.readUInt32BE(); + if (srcPort !== undefined) { + channelInfo = { + type, + sender, + window, + packetSize, + data: { srcIP, srcPort } + }; + } + break; + } + default: + // Includes: + // 'session' (C->S) + // 'auth-agent@openssh.com' (S->C) + channelInfo = { + type, + sender, + window, + packetSize, + data: {} + }; + } + bufferParser.clear(); + + if (channelInfo === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_OPEN packet' + ); + } + + self._debug && self._debug(`Inbound: CHANNEL_OPEN (s:${sender}, ${type})`); + + const handler = self._handlers.CHANNEL_OPEN; + if (handler) { + handler(self, channelInfo); + } else { + self.channelOpenFail( + channelInfo.sender, + CHANNEL_OPEN_FAILURE.ADMINISTRATIVELY_PROHIBITED, + '', + '' + ); + } + }, + [MESSAGE.CHANNEL_OPEN_CONFIRMATION]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION + uint32 recipient channel + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + .... channel type specific data follows + */ + // "The 'recipient channel' is the channel number given in the + // original open request, and 'sender channel' is the channel number + // allocated by the other side." + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + const sender = bufferParser.readUInt32BE(); + const window = bufferParser.readUInt32BE(); + const packetSize = bufferParser.readUInt32BE(); + const data = (bufferParser.avail() ? bufferParser.readRaw() : undefined); + bufferParser.clear(); + + if (packetSize === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_OPEN_CONFIRMATION packet' + ); + } + + self._debug && self._debug( + `Inbound: CHANNEL_OPEN_CONFIRMATION (r:${recipient}, s:${sender})` + ); + + const handler = self._handlers.CHANNEL_OPEN_CONFIRMATION; + if (handler) + handler(self, { recipient, sender, window, packetSize, data }); + }, + [MESSAGE.CHANNEL_OPEN_FAILURE]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_OPEN_FAILURE + uint32 recipient channel + uint32 reason code + string description in ISO-10646 UTF-8 encoding [RFC3629] + string language tag [RFC3066] + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + const reason = bufferParser.readUInt32BE(); + const description = bufferParser.readString(true); + const lang = bufferParser.readString(); + bufferParser.clear(); + + if (lang === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_OPEN_FAILURE packet' + ); + } + + self._debug + && self._debug(`Inbound: CHANNEL_OPEN_FAILURE (r:${recipient})`); + + const handler = self._handlers.CHANNEL_OPEN_FAILURE; + handler && handler(self, recipient, reason, description); + }, + [MESSAGE.CHANNEL_WINDOW_ADJUST]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_WINDOW_ADJUST + uint32 recipient channel + uint32 bytes to add + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + const bytesToAdd = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (bytesToAdd === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_WINDOW_ADJUST packet' + ); + } + + self._debug && self._debug( + `Inbound: CHANNEL_WINDOW_ADJUST (r:${recipient}, ${bytesToAdd})` + ); + + const handler = self._handlers.CHANNEL_WINDOW_ADJUST; + handler && handler(self, recipient, bytesToAdd); + }, + [MESSAGE.CHANNEL_DATA]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_DATA + uint32 recipient channel + string data + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + const data = bufferParser.readString(); + bufferParser.clear(); + + if (data === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_DATA packet' + ); + } + + self._debug + && self._debug(`Inbound: CHANNEL_DATA (r:${recipient}, ${data.length})`); + + const handler = self._handlers.CHANNEL_DATA; + handler && handler(self, recipient, data); + }, + [MESSAGE.CHANNEL_EXTENDED_DATA]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_EXTENDED_DATA + uint32 recipient channel + uint32 data_type_code + string data + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + const type = bufferParser.readUInt32BE(); + const data = bufferParser.readString(); + bufferParser.clear(); + + if (data === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_EXTENDED_DATA packet' + ); + } + + self._debug && self._debug( + `Inbound: CHANNEL_EXTENDED_DATA (r:${recipient}, ${data.length})` + ); + + const handler = self._handlers.CHANNEL_EXTENDED_DATA; + handler && handler(self, recipient, data, type); + }, + [MESSAGE.CHANNEL_EOF]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_EOF + uint32 recipient channel + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (recipient === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_EOF packet' + ); + } + + self._debug && self._debug(`Inbound: CHANNEL_EOF (r:${recipient})`); + + const handler = self._handlers.CHANNEL_EOF; + handler && handler(self, recipient); + }, + [MESSAGE.CHANNEL_CLOSE]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_CLOSE + uint32 recipient channel + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (recipient === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_CLOSE packet' + ); + } + + self._debug && self._debug(`Inbound: CHANNEL_CLOSE (r:${recipient})`); + + const handler = self._handlers.CHANNEL_CLOSE; + handler && handler(self, recipient); + }, + [MESSAGE.CHANNEL_REQUEST]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string request type in US-ASCII characters only + boolean want reply + .... type-specific data follows + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + const type = bufferParser.readString(true); + const wantReply = bufferParser.readBool(); + let data; + if (wantReply !== undefined) { + switch (type) { + case 'exit-status': // S->C + /* + uint32 exit_status + */ + data = bufferParser.readUInt32BE(); + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})` + ); + break; + case 'exit-signal': { // S->C + /* + string signal name (without the "SIG" prefix) + boolean core dumped + string error message in ISO-10646 UTF-8 encoding + string language tag + */ + let signal; + let coreDumped; + if (self._compatFlags & COMPAT.OLD_EXIT) { + /* + Instead of `signal name` and `core dumped`, we have just: + uint32 signal number + */ + const num = bufferParser.readUInt32BE(); + switch (num) { + case 1: + signal = 'HUP'; + break; + case 2: + signal = 'INT'; + break; + case 3: + signal = 'QUIT'; + break; + case 6: + signal = 'ABRT'; + break; + case 9: + signal = 'KILL'; + break; + case 14: + signal = 'ALRM'; + break; + case 15: + signal = 'TERM'; + break; + default: + if (num !== undefined) { + // Unknown or OS-specific + signal = `UNKNOWN (${num})`; + } + } + coreDumped = false; + } else { + signal = bufferParser.readString(true); + coreDumped = bufferParser.readBool(); + if (coreDumped === undefined) + signal = undefined; + } + const errorMessage = bufferParser.readString(true); + if (bufferParser.skipString() !== undefined) + data = { signal, coreDumped, errorMessage }; + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${signal})` + ); + break; + } + case 'pty-req': { // C->S + /* + string TERM environment variable value (e.g., vt100) + uint32 terminal width, characters (e.g., 80) + uint32 terminal height, rows (e.g., 24) + uint32 terminal width, pixels (e.g., 640) + uint32 terminal height, pixels (e.g., 480) + string encoded terminal modes + */ + const term = bufferParser.readString(true); + const cols = bufferParser.readUInt32BE(); + const rows = bufferParser.readUInt32BE(); + const width = bufferParser.readUInt32BE(); + const height = bufferParser.readUInt32BE(); + const modesBinary = bufferParser.readString(); + if (modesBinary !== undefined) { + bufferParser.init(modesBinary, 1); + let modes = {}; + while (bufferParser.avail()) { + const opcode = bufferParser.readByte(); + if (opcode === TERMINAL_MODE.TTY_OP_END) + break; + const name = TERMINAL_MODE_BY_VALUE[opcode]; + const value = bufferParser.readUInt32BE(); + if (opcode === undefined + || name === undefined + || value === undefined) { + modes = undefined; + break; + } + modes[name] = value; + } + if (modes !== undefined) + data = { term, cols, rows, width, height, modes }; + } + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})` + ); + break; + } + case 'window-change': { // C->S + /* + uint32 terminal width, columns + uint32 terminal height, rows + uint32 terminal width, pixels + uint32 terminal height, pixels + */ + const cols = bufferParser.readUInt32BE(); + const rows = bufferParser.readUInt32BE(); + const width = bufferParser.readUInt32BE(); + const height = bufferParser.readUInt32BE(); + if (height !== undefined) + data = { cols, rows, width, height }; + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})` + ); + break; + } + case 'x11-req': { // C->S + /* + boolean single connection + string x11 authentication protocol + string x11 authentication cookie + uint32 x11 screen number + */ + const single = bufferParser.readBool(); + const protocol = bufferParser.readString(true); + const cookie = bufferParser.readString(); + const screen = bufferParser.readUInt32BE(); + if (screen !== undefined) + data = { single, protocol, cookie, screen }; + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})` + ); + break; + } + case 'env': { // C->S + /* + string variable name + string variable value + */ + const name = bufferParser.readString(true); + const value = bufferParser.readString(true); + if (value !== undefined) + data = { name, value }; + if (self._debug) { + self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ` + + `${name}=${value})` + ); + } + break; + } + case 'shell': // C->S + data = null; // No extra data + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})` + ); + break; + case 'exec': // C->S + /* + string command + */ + data = bufferParser.readString(true); + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})` + ); + break; + case 'subsystem': // C->S + /* + string subsystem name + */ + data = bufferParser.readString(true); + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})` + ); + break; + case 'signal': // C->S + /* + string signal name (without the "SIG" prefix) + */ + data = bufferParser.readString(true); + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})` + ); + break; + case 'xon-xoff': // C->S + /* + boolean client can do + */ + data = bufferParser.readBool(); + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})` + ); + break; + case 'auth-agent-req@openssh.com': // C-S + data = null; // No extra data + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})` + ); + break; + default: + data = (bufferParser.avail() ? bufferParser.readRaw() : null); + self._debug && self._debug( + `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})` + ); + } + } + bufferParser.clear(); + + if (data === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_REQUEST packet' + ); + } + + const handler = self._handlers.CHANNEL_REQUEST; + handler && handler(self, recipient, type, wantReply, data); + }, + [MESSAGE.CHANNEL_SUCCESS]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_SUCCESS + uint32 recipient channel + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (recipient === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_SUCCESS packet' + ); + } + + self._debug && self._debug(`Inbound: CHANNEL_SUCCESS (r:${recipient})`); + + const handler = self._handlers.CHANNEL_SUCCESS; + handler && handler(self, recipient); + }, + [MESSAGE.CHANNEL_FAILURE]: (self, payload) => { + /* + byte SSH_MSG_CHANNEL_FAILURE + uint32 recipient channel + */ + bufferParser.init(payload, 1); + const recipient = bufferParser.readUInt32BE(); + bufferParser.clear(); + + if (recipient === undefined) { + return doFatalError( + self, + 'Inbound: Malformed CHANNEL_FAILURE packet' + ); + } + + self._debug && self._debug(`Inbound: CHANNEL_FAILURE (r:${recipient})`); + + const handler = self._handlers.CHANNEL_FAILURE; + handler && handler(self, recipient); + }, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/kex.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/kex.js new file mode 100644 index 0000000..811e631 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/kex.js @@ -0,0 +1,1908 @@ +'use strict'; + +const { + createDiffieHellman, + createDiffieHellmanGroup, + createECDH, + createHash, + createPublicKey, + diffieHellman, + generateKeyPairSync, + randomFillSync, +} = require('crypto'); + +const { Ber } = require('asn1'); + +const { + COMPAT, + curve25519Supported, + DEFAULT_KEX, + DEFAULT_SERVER_HOST_KEY, + DEFAULT_CIPHER, + DEFAULT_MAC, + DEFAULT_COMPRESSION, + DISCONNECT_REASON, + MESSAGE, +} = require('./constants.js'); +const { + CIPHER_INFO, + createCipher, + createDecipher, + MAC_INFO, +} = require('./crypto.js'); +const { parseDERKey } = require('./keyParser.js'); +const { + bufferFill, + bufferParser, + convertSignature, + doFatalError, + FastBuffer, + sigSSHToASN1, + writeUInt32BE, +} = require('./utils.js'); +const { + PacketReader, + PacketWriter, + ZlibPacketReader, + ZlibPacketWriter, +} = require('./zlib.js'); + +let MESSAGE_HANDLERS; + +const GEX_MIN_BITS = 2048; // RFC 8270 +const GEX_MAX_BITS = 8192; // RFC 8270 + +const EMPTY_BUFFER = Buffer.alloc(0); + +// Client/Server +function kexinit(self) { + /* + byte SSH_MSG_KEXINIT + byte[16] cookie (random bytes) + name-list kex_algorithms + name-list server_host_key_algorithms + name-list encryption_algorithms_client_to_server + name-list encryption_algorithms_server_to_client + name-list mac_algorithms_client_to_server + name-list mac_algorithms_server_to_client + name-list compression_algorithms_client_to_server + name-list compression_algorithms_server_to_client + name-list languages_client_to_server + name-list languages_server_to_client + boolean first_kex_packet_follows + uint32 0 (reserved for future extension) + */ + + let payload; + if (self._compatFlags & COMPAT.BAD_DHGEX) { + const entry = self._offer.lists.kex; + let kex = entry.array; + let found = false; + for (let i = 0; i < kex.length; ++i) { + if (kex[i].includes('group-exchange')) { + if (!found) { + found = true; + // Copy array lazily + kex = kex.slice(); + } + kex.splice(i--, 1); + } + } + if (found) { + let len = 1 + 16 + self._offer.totalSize + 1 + 4; + const newKexBuf = Buffer.from(kex.join(',')); + len -= (entry.buffer.length - newKexBuf.length); + + const all = self._offer.lists.all; + const rest = new Uint8Array( + all.buffer, + all.byteOffset + 4 + entry.buffer.length, + all.length - (4 + entry.buffer.length) + ); + + payload = Buffer.allocUnsafe(len); + writeUInt32BE(payload, newKexBuf.length, 17); + payload.set(newKexBuf, 17 + 4); + payload.set(rest, 17 + 4 + newKexBuf.length); + } + } + + if (payload === undefined) { + payload = Buffer.allocUnsafe(1 + 16 + self._offer.totalSize + 1 + 4); + self._offer.copyAllTo(payload, 17); + } + + self._debug && self._debug('Outbound: Sending KEXINIT'); + + payload[0] = MESSAGE.KEXINIT; + randomFillSync(payload, 1, 16); + + // Zero-fill first_kex_packet_follows and reserved bytes + bufferFill(payload, 0, payload.length - 5); + + self._kexinit = payload; + + // Needed to correct the starting position in allocated "packets" when packets + // will be buffered due to active key exchange + self._packetRW.write.allocStart = 0; + + // TODO: only create single buffer and set _kexinit as slice of packet instead + { + const p = self._packetRW.write.allocStartKEX; + const packet = self._packetRW.write.alloc(payload.length, true); + packet.set(payload, p); + self._cipher.encrypt(self._packetRW.write.finalize(packet, true)); + } +} + +function handleKexInit(self, payload) { + /* + byte SSH_MSG_KEXINIT + byte[16] cookie (random bytes) + name-list kex_algorithms + name-list server_host_key_algorithms + name-list encryption_algorithms_client_to_server + name-list encryption_algorithms_server_to_client + name-list mac_algorithms_client_to_server + name-list mac_algorithms_server_to_client + name-list compression_algorithms_client_to_server + name-list compression_algorithms_server_to_client + name-list languages_client_to_server + name-list languages_server_to_client + boolean first_kex_packet_follows + uint32 0 (reserved for future extension) + */ + const init = { + kex: undefined, + serverHostKey: undefined, + cs: { + cipher: undefined, + mac: undefined, + compress: undefined, + lang: undefined, + }, + sc: { + cipher: undefined, + mac: undefined, + compress: undefined, + lang: undefined, + }, + }; + + bufferParser.init(payload, 17); + + if ((init.kex = bufferParser.readList()) === undefined + || (init.serverHostKey = bufferParser.readList()) === undefined + || (init.cs.cipher = bufferParser.readList()) === undefined + || (init.sc.cipher = bufferParser.readList()) === undefined + || (init.cs.mac = bufferParser.readList()) === undefined + || (init.sc.mac = bufferParser.readList()) === undefined + || (init.cs.compress = bufferParser.readList()) === undefined + || (init.sc.compress = bufferParser.readList()) === undefined + || (init.cs.lang = bufferParser.readList()) === undefined + || (init.sc.lang = bufferParser.readList()) === undefined) { + bufferParser.clear(); + return doFatalError( + self, + 'Received malformed KEXINIT', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + const pos = bufferParser.pos(); + const firstFollows = (pos < payload.length && payload[pos] === 1); + bufferParser.clear(); + + const local = self._offer; + const remote = init; + + let localKex = local.lists.kex.array; + if (self._compatFlags & COMPAT.BAD_DHGEX) { + let found = false; + for (let i = 0; i < localKex.length; ++i) { + if (localKex[i].indexOf('group-exchange') !== -1) { + if (!found) { + found = true; + // Copy array lazily + localKex = localKex.slice(); + } + localKex.splice(i--, 1); + } + } + } + + let clientList; + let serverList; + let i; + const debug = self._debug; + + debug && debug('Inbound: Handshake in progress'); + + // Key exchange method ======================================================= + debug && debug(`Handshake: (local) KEX method: ${localKex}`); + debug && debug(`Handshake: (remote) KEX method: ${remote.kex}`); + let remoteExtInfoEnabled; + if (self._server) { + serverList = localKex; + clientList = remote.kex; + remoteExtInfoEnabled = (clientList.indexOf('ext-info-c') !== -1); + } else { + serverList = remote.kex; + clientList = localKex; + remoteExtInfoEnabled = (serverList.indexOf('ext-info-s') !== -1); + } + if (self._strictMode === undefined) { + if (self._server) { + self._strictMode = + (clientList.indexOf('kex-strict-c-v00@openssh.com') !== -1); + } else { + self._strictMode = + (serverList.indexOf('kex-strict-s-v00@openssh.com') !== -1); + } + // Note: We check for seqno of 1 instead of 0 since we increment before + // calling the packet handler + if (self._strictMode) { + debug && debug('Handshake: strict KEX mode enabled'); + if (self._decipher.inSeqno !== 1) { + if (debug) + debug('Handshake: KEXINIT not first packet in strict KEX mode'); + return doFatalError( + self, + 'Handshake failed: KEXINIT not first packet in strict KEX mode', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + } + } + // Check for agreeable key exchange algorithm + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: no matching key exchange algorithm'); + return doFatalError( + self, + 'Handshake failed: no matching key exchange algorithm', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.kex = clientList[i]; + debug && debug(`Handshake: KEX algorithm: ${clientList[i]}`); + if (firstFollows && (!remote.kex.length || clientList[i] !== remote.kex[0])) { + // Ignore next inbound packet, it was a wrong first guess at KEX algorithm + self._skipNextInboundPacket = true; + } + + + // Server host key format ==================================================== + const localSrvHostKey = local.lists.serverHostKey.array; + debug && debug(`Handshake: (local) Host key format: ${localSrvHostKey}`); + debug && debug( + `Handshake: (remote) Host key format: ${remote.serverHostKey}` + ); + if (self._server) { + serverList = localSrvHostKey; + clientList = remote.serverHostKey; + } else { + serverList = remote.serverHostKey; + clientList = localSrvHostKey; + } + // Check for agreeable server host key format + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching host key format'); + return doFatalError( + self, + 'Handshake failed: no matching host key format', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.serverHostKey = clientList[i]; + debug && debug(`Handshake: Host key format: ${clientList[i]}`); + + + // Client->Server cipher ===================================================== + const localCSCipher = local.lists.cs.cipher.array; + debug && debug(`Handshake: (local) C->S cipher: ${localCSCipher}`); + debug && debug(`Handshake: (remote) C->S cipher: ${remote.cs.cipher}`); + if (self._server) { + serverList = localCSCipher; + clientList = remote.cs.cipher; + } else { + serverList = remote.cs.cipher; + clientList = localCSCipher; + } + // Check for agreeable client->server cipher + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching C->S cipher'); + return doFatalError( + self, + 'Handshake failed: no matching C->S cipher', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.cs.cipher = clientList[i]; + debug && debug(`Handshake: C->S Cipher: ${clientList[i]}`); + + + // Server->Client cipher ===================================================== + const localSCCipher = local.lists.sc.cipher.array; + debug && debug(`Handshake: (local) S->C cipher: ${localSCCipher}`); + debug && debug(`Handshake: (remote) S->C cipher: ${remote.sc.cipher}`); + if (self._server) { + serverList = localSCCipher; + clientList = remote.sc.cipher; + } else { + serverList = remote.sc.cipher; + clientList = localSCCipher; + } + // Check for agreeable server->client cipher + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching S->C cipher'); + return doFatalError( + self, + 'Handshake failed: no matching S->C cipher', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.sc.cipher = clientList[i]; + debug && debug(`Handshake: S->C cipher: ${clientList[i]}`); + + + // Client->Server MAC ======================================================== + const localCSMAC = local.lists.cs.mac.array; + debug && debug(`Handshake: (local) C->S MAC: ${localCSMAC}`); + debug && debug(`Handshake: (remote) C->S MAC: ${remote.cs.mac}`); + if (CIPHER_INFO[init.cs.cipher].authLen > 0) { + init.cs.mac = ''; + debug && debug('Handshake: C->S MAC: '); + } else { + if (self._server) { + serverList = localCSMAC; + clientList = remote.cs.mac; + } else { + serverList = remote.cs.mac; + clientList = localCSMAC; + } + // Check for agreeable client->server hmac algorithm + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching C->S MAC'); + return doFatalError( + self, + 'Handshake failed: no matching C->S MAC', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.cs.mac = clientList[i]; + debug && debug(`Handshake: C->S MAC: ${clientList[i]}`); + } + + + // Server->Client MAC ======================================================== + const localSCMAC = local.lists.sc.mac.array; + debug && debug(`Handshake: (local) S->C MAC: ${localSCMAC}`); + debug && debug(`Handshake: (remote) S->C MAC: ${remote.sc.mac}`); + if (CIPHER_INFO[init.sc.cipher].authLen > 0) { + init.sc.mac = ''; + debug && debug('Handshake: S->C MAC: '); + } else { + if (self._server) { + serverList = localSCMAC; + clientList = remote.sc.mac; + } else { + serverList = remote.sc.mac; + clientList = localSCMAC; + } + // Check for agreeable server->client hmac algorithm + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching S->C MAC'); + return doFatalError( + self, + 'Handshake failed: no matching S->C MAC', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.sc.mac = clientList[i]; + debug && debug(`Handshake: S->C MAC: ${clientList[i]}`); + } + + + // Client->Server compression ================================================ + const localCSCompress = local.lists.cs.compress.array; + debug && debug(`Handshake: (local) C->S compression: ${localCSCompress}`); + debug && debug(`Handshake: (remote) C->S compression: ${remote.cs.compress}`); + if (self._server) { + serverList = localCSCompress; + clientList = remote.cs.compress; + } else { + serverList = remote.cs.compress; + clientList = localCSCompress; + } + // Check for agreeable client->server compression algorithm + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching C->S compression'); + return doFatalError( + self, + 'Handshake failed: no matching C->S compression', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.cs.compress = clientList[i]; + debug && debug(`Handshake: C->S compression: ${clientList[i]}`); + + + // Server->Client compression ================================================ + const localSCCompress = local.lists.sc.compress.array; + debug && debug(`Handshake: (local) S->C compression: ${localSCCompress}`); + debug && debug(`Handshake: (remote) S->C compression: ${remote.sc.compress}`); + if (self._server) { + serverList = localSCCompress; + clientList = remote.sc.compress; + } else { + serverList = remote.sc.compress; + clientList = localSCCompress; + } + // Check for agreeable server->client compression algorithm + for (i = 0; + i < clientList.length && serverList.indexOf(clientList[i]) === -1; + ++i); + if (i === clientList.length) { + // No suitable match found! + debug && debug('Handshake: No matching S->C compression'); + return doFatalError( + self, + 'Handshake failed: no matching S->C compression', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + init.sc.compress = clientList[i]; + debug && debug(`Handshake: S->C compression: ${clientList[i]}`); + + init.cs.lang = ''; + init.sc.lang = ''; + + // XXX: hack -- find a better way to do this + if (self._kex) { + if (!self._kexinit) { + // We received a rekey request, but we haven't sent a KEXINIT in response + // yet + kexinit(self); + } + self._decipher._onPayload = onKEXPayload.bind(self, { firstPacket: false }); + } + + self._kex = createKeyExchange(init, self, payload); + self._kex.remoteExtInfoEnabled = remoteExtInfoEnabled; + self._kex.start(); +} + +const createKeyExchange = (() => { + function convertToMpint(buf) { + let idx = 0; + let length = buf.length; + while (buf[idx] === 0x00) { + ++idx; + --length; + } + let newBuf; + if (buf[idx] & 0x80) { + newBuf = Buffer.allocUnsafe(1 + length); + newBuf[0] = 0; + buf.copy(newBuf, 1, idx); + buf = newBuf; + } else if (length !== buf.length) { + newBuf = Buffer.allocUnsafe(length); + buf.copy(newBuf, 0, idx); + buf = newBuf; + } + return buf; + } + + class KeyExchange { + constructor(negotiated, protocol, remoteKexinit) { + this._protocol = protocol; + + this.sessionID = (protocol._kex ? protocol._kex.sessionID : undefined); + this.negotiated = negotiated; + this.remoteExtInfoEnabled = false; + this._step = 1; + this._public = null; + this._dh = null; + this._sentNEWKEYS = false; + this._receivedNEWKEYS = false; + this._finished = false; + this._hostVerified = false; + + // Data needed for initializing cipher/decipher/etc. + this._kexinit = protocol._kexinit; + this._remoteKexinit = remoteKexinit; + this._identRaw = protocol._identRaw; + this._remoteIdentRaw = protocol._remoteIdentRaw; + this._hostKey = undefined; + this._dhData = undefined; + this._sig = undefined; + } + finish(scOnly) { + if (this._finished) + return false; + this._finished = true; + + const isServer = this._protocol._server; + const negotiated = this.negotiated; + + const pubKey = this.convertPublicKey(this._dhData); + let secret = this.computeSecret(this._dhData); + if (secret instanceof Error) { + secret.message = + `Error while computing DH secret (${this.type}): ${secret.message}`; + secret.level = 'handshake'; + return doFatalError( + this._protocol, + secret, + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + const hash = createHash(this.hashName); + // V_C + hashString(hash, (isServer ? this._remoteIdentRaw : this._identRaw)); + // "V_S" + hashString(hash, (isServer ? this._identRaw : this._remoteIdentRaw)); + // "I_C" + hashString(hash, (isServer ? this._remoteKexinit : this._kexinit)); + // "I_S" + hashString(hash, (isServer ? this._kexinit : this._remoteKexinit)); + // "K_S" + const serverPublicHostKey = (isServer + ? this._hostKey.getPublicSSH() + : this._hostKey); + hashString(hash, serverPublicHostKey); + + if (this.type === 'groupex') { + // Group exchange-specific + const params = this.getDHParams(); + const num = Buffer.allocUnsafe(4); + // min (uint32) + writeUInt32BE(num, this._minBits, 0); + hash.update(num); + // preferred (uint32) + writeUInt32BE(num, this._prefBits, 0); + hash.update(num); + // max (uint32) + writeUInt32BE(num, this._maxBits, 0); + hash.update(num); + // prime + hashString(hash, params.prime); + // generator + hashString(hash, params.generator); + } + + // method-specific data sent by client + hashString(hash, (isServer ? pubKey : this.getPublicKey())); + // method-specific data sent by server + const serverPublicKey = (isServer ? this.getPublicKey() : pubKey); + hashString(hash, serverPublicKey); + // shared secret ("K") + hashString(hash, secret); + + // "H" + const exchangeHash = hash.digest(); + + if (!isServer) { + bufferParser.init(this._sig, 0); + const sigType = bufferParser.readString(true); + + if (!sigType) { + return doFatalError( + this._protocol, + 'Malformed packet while reading signature', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + if (sigType !== negotiated.serverHostKey) { + return doFatalError( + this._protocol, + `Wrong signature type: ${sigType}, ` + + `expected: ${negotiated.serverHostKey}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + // "s" + let sigValue = bufferParser.readString(); + + bufferParser.clear(); + + if (sigValue === undefined) { + return doFatalError( + this._protocol, + 'Malformed packet while reading signature', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + if (!(sigValue = sigSSHToASN1(sigValue, sigType))) { + return doFatalError( + this._protocol, + 'Malformed signature', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + let parsedHostKey; + { + bufferParser.init(this._hostKey, 0); + const name = bufferParser.readString(true); + const hostKey = this._hostKey.slice(bufferParser.pos()); + bufferParser.clear(); + parsedHostKey = parseDERKey(hostKey, name); + if (parsedHostKey instanceof Error) { + parsedHostKey.level = 'handshake'; + return doFatalError( + this._protocol, + parsedHostKey, + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + } + + let hashAlgo; + // Check if we need to override the default hash algorithm + switch (this.negotiated.serverHostKey) { + case 'rsa-sha2-256': hashAlgo = 'sha256'; break; + case 'rsa-sha2-512': hashAlgo = 'sha512'; break; + } + + this._protocol._debug + && this._protocol._debug('Verifying signature ...'); + + const verified = parsedHostKey.verify(exchangeHash, sigValue, hashAlgo); + if (verified !== true) { + if (verified instanceof Error) { + this._protocol._debug && this._protocol._debug( + `Signature verification failed: ${verified.stack}` + ); + } else { + this._protocol._debug && this._protocol._debug( + 'Signature verification failed' + ); + } + return doFatalError( + this._protocol, + 'Handshake failed: signature verification failed', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug('Verified signature'); + } else { + // Server + + let hashAlgo; + // Check if we need to override the default hash algorithm + switch (this.negotiated.serverHostKey) { + case 'rsa-sha2-256': hashAlgo = 'sha256'; break; + case 'rsa-sha2-512': hashAlgo = 'sha512'; break; + } + + this._protocol._debug && this._protocol._debug( + 'Generating signature ...' + ); + + let signature = this._hostKey.sign(exchangeHash, hashAlgo); + if (signature instanceof Error) { + return doFatalError( + this._protocol, + 'Handshake failed: signature generation failed for ' + + `${this._hostKey.type} host key: ${signature.message}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + signature = convertSignature(signature, this._hostKey.type); + if (signature === false) { + return doFatalError( + this._protocol, + 'Handshake failed: signature conversion failed for ' + + `${this._hostKey.type} host key`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + // Send KEX reply + /* + byte SSH_MSG_KEXDH_REPLY + / SSH_MSG_KEX_DH_GEX_REPLY + / SSH_MSG_KEX_ECDH_REPLY + string server public host key and certificates (K_S) + string + string signature of H + */ + const sigType = this.negotiated.serverHostKey; + const sigTypeLen = Buffer.byteLength(sigType); + const sigLen = 4 + sigTypeLen + 4 + signature.length; + let p = this._protocol._packetRW.write.allocStartKEX; + const packet = this._protocol._packetRW.write.alloc( + 1 + + 4 + serverPublicHostKey.length + + 4 + serverPublicKey.length + + 4 + sigLen, + true + ); + + packet[p] = MESSAGE.KEXDH_REPLY; + + writeUInt32BE(packet, serverPublicHostKey.length, ++p); + packet.set(serverPublicHostKey, p += 4); + + writeUInt32BE(packet, + serverPublicKey.length, + p += serverPublicHostKey.length); + packet.set(serverPublicKey, p += 4); + + writeUInt32BE(packet, sigLen, p += serverPublicKey.length); + + writeUInt32BE(packet, sigTypeLen, p += 4); + packet.utf8Write(sigType, p += 4, sigTypeLen); + + writeUInt32BE(packet, signature.length, p += sigTypeLen); + packet.set(signature, p += 4); + + if (this._protocol._debug) { + let type; + switch (this.type) { + case 'group': + type = 'KEXDH_REPLY'; + break; + case 'groupex': + type = 'KEXDH_GEX_REPLY'; + break; + default: + type = 'KEXECDH_REPLY'; + } + this._protocol._debug(`Outbound: Sending ${type}`); + } + this._protocol._cipher.encrypt( + this._protocol._packetRW.write.finalize(packet, true) + ); + } + + if (isServer || !scOnly) + trySendNEWKEYS(this); + + let hsCipherConfig; + let hsWrite; + const completeHandshake = (partial) => { + if (hsCipherConfig) { + trySendNEWKEYS(this); + hsCipherConfig.outbound.seqno = this._protocol._cipher.outSeqno; + this._protocol._cipher.free(); + this._protocol._cipher = createCipher(hsCipherConfig); + this._protocol._packetRW.write = hsWrite; + hsCipherConfig = undefined; + hsWrite = undefined; + this._protocol._onHandshakeComplete(negotiated); + + return false; + } + + if (!this.sessionID) + this.sessionID = exchangeHash; + + { + const newSecret = Buffer.allocUnsafe(4 + secret.length); + writeUInt32BE(newSecret, secret.length, 0); + newSecret.set(secret, 4); + secret = newSecret; + } + + // Initialize new ciphers, deciphers, etc. + + const csCipherInfo = CIPHER_INFO[negotiated.cs.cipher]; + const scCipherInfo = CIPHER_INFO[negotiated.sc.cipher]; + + const csIV = generateKEXVal(csCipherInfo.ivLen, + this.hashName, + secret, + exchangeHash, + this.sessionID, + 'A'); + const scIV = generateKEXVal(scCipherInfo.ivLen, + this.hashName, + secret, + exchangeHash, + this.sessionID, + 'B'); + const csKey = generateKEXVal(csCipherInfo.keyLen, + this.hashName, + secret, + exchangeHash, + this.sessionID, + 'C'); + const scKey = generateKEXVal(scCipherInfo.keyLen, + this.hashName, + secret, + exchangeHash, + this.sessionID, + 'D'); + let csMacInfo; + let csMacKey; + if (!csCipherInfo.authLen) { + csMacInfo = MAC_INFO[negotiated.cs.mac]; + csMacKey = generateKEXVal(csMacInfo.len, + this.hashName, + secret, + exchangeHash, + this.sessionID, + 'E'); + } + let scMacInfo; + let scMacKey; + if (!scCipherInfo.authLen) { + scMacInfo = MAC_INFO[negotiated.sc.mac]; + scMacKey = generateKEXVal(scMacInfo.len, + this.hashName, + secret, + exchangeHash, + this.sessionID, + 'F'); + } + + const config = { + inbound: { + onPayload: this._protocol._onPayload, + seqno: this._protocol._decipher.inSeqno, + decipherInfo: (!isServer ? scCipherInfo : csCipherInfo), + decipherIV: (!isServer ? scIV : csIV), + decipherKey: (!isServer ? scKey : csKey), + macInfo: (!isServer ? scMacInfo : csMacInfo), + macKey: (!isServer ? scMacKey : csMacKey), + }, + outbound: { + onWrite: this._protocol._onWrite, + seqno: this._protocol._cipher.outSeqno, + cipherInfo: (isServer ? scCipherInfo : csCipherInfo), + cipherIV: (isServer ? scIV : csIV), + cipherKey: (isServer ? scKey : csKey), + macInfo: (isServer ? scMacInfo : csMacInfo), + macKey: (isServer ? scMacKey : csMacKey), + }, + }; + this._protocol._decipher.free(); + hsCipherConfig = config; + this._protocol._decipher = createDecipher(config); + + const rw = { + read: undefined, + write: undefined, + }; + switch (negotiated.cs.compress) { + case 'zlib': // starts immediately + if (isServer) + rw.read = new ZlibPacketReader(); + else + rw.write = new ZlibPacketWriter(this._protocol); + break; + case 'zlib@openssh.com': + // Starts after successful user authentication + + if (this._protocol._authenticated) { + // If a rekey happens and this compression method is selected and + // we already authenticated successfully, we need to start + // immediately instead + if (isServer) + rw.read = new ZlibPacketReader(); + else + rw.write = new ZlibPacketWriter(this._protocol); + break; + } + // FALLTHROUGH + default: + // none -- never any compression/decompression + + if (isServer) + rw.read = new PacketReader(); + else + rw.write = new PacketWriter(this._protocol); + } + switch (negotiated.sc.compress) { + case 'zlib': // starts immediately + if (isServer) + rw.write = new ZlibPacketWriter(this._protocol); + else + rw.read = new ZlibPacketReader(); + break; + case 'zlib@openssh.com': + // Starts after successful user authentication + + if (this._protocol._authenticated) { + // If a rekey happens and this compression method is selected and + // we already authenticated successfully, we need to start + // immediately instead + if (isServer) + rw.write = new ZlibPacketWriter(this._protocol); + else + rw.read = new ZlibPacketReader(); + break; + } + // FALLTHROUGH + default: + // none -- never any compression/decompression + + if (isServer) + rw.write = new PacketWriter(this._protocol); + else + rw.read = new PacketReader(); + } + this._protocol._packetRW.read.cleanup(); + this._protocol._packetRW.write.cleanup(); + this._protocol._packetRW.read = rw.read; + hsWrite = rw.write; + + // Cleanup/reset various state + this._public = null; + this._dh = null; + this._kexinit = this._protocol._kexinit = undefined; + this._remoteKexinit = undefined; + this._identRaw = undefined; + this._remoteIdentRaw = undefined; + this._hostKey = undefined; + this._dhData = undefined; + this._sig = undefined; + + if (!partial) + return completeHandshake(); + return false; + }; + + if (isServer || scOnly) + this.finish = completeHandshake; + + if (!isServer) + return completeHandshake(scOnly); + } + + start() { + if (!this._protocol._server) { + if (this._protocol._debug) { + let type; + switch (this.type) { + case 'group': + type = 'KEXDH_INIT'; + break; + default: + type = 'KEXECDH_INIT'; + } + this._protocol._debug(`Outbound: Sending ${type}`); + } + + const pubKey = this.getPublicKey(); + + let p = this._protocol._packetRW.write.allocStartKEX; + const packet = this._protocol._packetRW.write.alloc( + 1 + 4 + pubKey.length, + true + ); + packet[p] = MESSAGE.KEXDH_INIT; + writeUInt32BE(packet, pubKey.length, ++p); + packet.set(pubKey, p += 4); + this._protocol._cipher.encrypt( + this._protocol._packetRW.write.finalize(packet, true) + ); + } + } + getPublicKey() { + this.generateKeys(); + + const key = this._public; + + if (key) + return this.convertPublicKey(key); + } + convertPublicKey(key) { + let newKey; + let idx = 0; + let len = key.length; + while (key[idx] === 0x00) { + ++idx; + --len; + } + + if (key[idx] & 0x80) { + newKey = Buffer.allocUnsafe(1 + len); + newKey[0] = 0; + key.copy(newKey, 1, idx); + return newKey; + } + + if (len !== key.length) { + newKey = Buffer.allocUnsafe(len); + key.copy(newKey, 0, idx); + key = newKey; + } + return key; + } + computeSecret(otherPublicKey) { + this.generateKeys(); + + try { + return convertToMpint(this._dh.computeSecret(otherPublicKey)); + } catch (ex) { + return ex; + } + } + parse(payload) { + const type = payload[0]; + switch (this._step) { + case 1: + if (this._protocol._server) { + // Server + if (type !== MESSAGE.KEXDH_INIT) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ${MESSAGE.KEXDH_INIT}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Received DH Init' + ); + /* + byte SSH_MSG_KEXDH_INIT + / SSH_MSG_KEX_ECDH_INIT + string + */ + bufferParser.init(payload, 1); + const dhData = bufferParser.readString(); + bufferParser.clear(); + if (dhData === undefined) { + return doFatalError( + this._protocol, + 'Received malformed KEX*_INIT', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + // Client public key + this._dhData = dhData; + + let hostKey = + this._protocol._hostKeys[this.negotiated.serverHostKey]; + if (Array.isArray(hostKey)) + hostKey = hostKey[0]; + this._hostKey = hostKey; + + this.finish(); + } else { + // Client + if (type !== MESSAGE.KEXDH_REPLY) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ${MESSAGE.KEXDH_REPLY}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Received DH Reply' + ); + /* + byte SSH_MSG_KEXDH_REPLY + / SSH_MSG_KEX_DH_GEX_REPLY + / SSH_MSG_KEX_ECDH_REPLY + string server public host key and certificates (K_S) + string + string signature of H + */ + bufferParser.init(payload, 1); + let hostPubKey; + let dhData; + let sig; + if ((hostPubKey = bufferParser.readString()) === undefined + || (dhData = bufferParser.readString()) === undefined + || (sig = bufferParser.readString()) === undefined) { + bufferParser.clear(); + return doFatalError( + this._protocol, + 'Received malformed KEX*_REPLY', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + bufferParser.clear(); + + // Check that the host public key type matches what was negotiated + // during KEXINIT swap + bufferParser.init(hostPubKey, 0); + const hostPubKeyType = bufferParser.readString(true); + bufferParser.clear(); + if (hostPubKeyType === undefined) { + return doFatalError( + this._protocol, + 'Received malformed host public key', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + if (hostPubKeyType !== this.negotiated.serverHostKey) { + // Check if we need to make an exception + switch (this.negotiated.serverHostKey) { + case 'rsa-sha2-256': + case 'rsa-sha2-512': + if (hostPubKeyType === 'ssh-rsa') + break; + // FALLTHROUGH + default: + return doFatalError( + this._protocol, + 'Host key does not match negotiated type', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + } + + this._hostKey = hostPubKey; + this._dhData = dhData; + this._sig = sig; + + let checked = false; + let ret; + if (this._protocol._hostVerifier === undefined) { + ret = true; + this._protocol._debug && this._protocol._debug( + 'Host accepted by default (no verification)' + ); + } else { + ret = this._protocol._hostVerifier(hostPubKey, (permitted) => { + if (checked) + return; + checked = true; + if (permitted === false) { + this._protocol._debug && this._protocol._debug( + 'Host denied (verification failed)' + ); + return doFatalError( + this._protocol, + 'Host denied (verification failed)', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Host accepted (verified)' + ); + this._hostVerified = true; + if (this._receivedNEWKEYS) + this.finish(); + else + trySendNEWKEYS(this); + }); + } + if (ret === undefined) { + // Async host verification + ++this._step; + return; + } + checked = true; + if (ret === false) { + this._protocol._debug && this._protocol._debug( + 'Host denied (verification failed)' + ); + return doFatalError( + this._protocol, + 'Host denied (verification failed)', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Host accepted (verified)' + ); + this._hostVerified = true; + trySendNEWKEYS(this); + } + ++this._step; + break; + case 2: + if (type !== MESSAGE.NEWKEYS) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ${MESSAGE.NEWKEYS}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Inbound: NEWKEYS' + ); + this._receivedNEWKEYS = true; + if (this._protocol._strictMode) + this._protocol._decipher.inSeqno = 0; + ++this._step; + + return this.finish(!this._protocol._server && !this._hostVerified); + default: + return doFatalError( + this._protocol, + `Received unexpected packet ${type} after NEWKEYS`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + } + } + + class Curve25519Exchange extends KeyExchange { + constructor(hashName, ...args) { + super(...args); + + this.type = '25519'; + this.hashName = hashName; + this._keys = null; + } + generateKeys() { + if (!this._keys) + this._keys = generateKeyPairSync('x25519'); + } + getPublicKey() { + this.generateKeys(); + + const key = this._keys.publicKey.export({ type: 'spki', format: 'der' }); + return key.slice(-32); // HACK: avoids parsing DER/BER header + } + convertPublicKey(key) { + let newKey; + let idx = 0; + let len = key.length; + while (key[idx] === 0x00) { + ++idx; + --len; + } + + if (key.length === 32) + return key; + + if (len !== key.length) { + newKey = Buffer.allocUnsafe(len); + key.copy(newKey, 0, idx); + key = newKey; + } + return key; + } + computeSecret(otherPublicKey) { + this.generateKeys(); + + try { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // algorithm + asnWriter.startSequence(); + asnWriter.writeOID('1.3.101.110'); // id-X25519 + asnWriter.endSequence(); + + // PublicKey + asnWriter.startSequence(Ber.BitString); + asnWriter.writeByte(0x00); + // XXX: hack to write a raw buffer without a tag -- yuck + asnWriter._ensure(otherPublicKey.length); + otherPublicKey.copy(asnWriter._buf, + asnWriter._offset, + 0, + otherPublicKey.length); + asnWriter._offset += otherPublicKey.length; + asnWriter.endSequence(); + asnWriter.endSequence(); + + return convertToMpint(diffieHellman({ + privateKey: this._keys.privateKey, + publicKey: createPublicKey({ + key: asnWriter.buffer, + type: 'spki', + format: 'der', + }), + })); + } catch (ex) { + return ex; + } + } + } + + class ECDHExchange extends KeyExchange { + constructor(curveName, hashName, ...args) { + super(...args); + + this.type = 'ecdh'; + this.curveName = curveName; + this.hashName = hashName; + } + generateKeys() { + if (!this._dh) { + this._dh = createECDH(this.curveName); + this._public = this._dh.generateKeys(); + } + } + } + + class DHGroupExchange extends KeyExchange { + constructor(hashName, ...args) { + super(...args); + + this.type = 'groupex'; + this.hashName = hashName; + this._prime = null; + this._generator = null; + this._minBits = GEX_MIN_BITS; + this._prefBits = dhEstimate(this.negotiated); + if (this._protocol._compatFlags & COMPAT.BUG_DHGEX_LARGE) + this._prefBits = Math.min(this._prefBits, 4096); + this._maxBits = GEX_MAX_BITS; + } + start() { + if (this._protocol._server) + return; + this._protocol._debug && this._protocol._debug( + 'Outbound: Sending KEXDH_GEX_REQUEST' + ); + let p = this._protocol._packetRW.write.allocStartKEX; + const packet = this._protocol._packetRW.write.alloc( + 1 + 4 + 4 + 4, + true + ); + packet[p] = MESSAGE.KEXDH_GEX_REQUEST; + writeUInt32BE(packet, this._minBits, ++p); + writeUInt32BE(packet, this._prefBits, p += 4); + writeUInt32BE(packet, this._maxBits, p += 4); + this._protocol._cipher.encrypt( + this._protocol._packetRW.write.finalize(packet, true) + ); + } + generateKeys() { + if (!this._dh && this._prime && this._generator) { + this._dh = createDiffieHellman(this._prime, this._generator); + this._public = this._dh.generateKeys(); + } + } + setDHParams(prime, generator) { + if (!Buffer.isBuffer(prime)) + throw new Error('Invalid prime value'); + if (!Buffer.isBuffer(generator)) + throw new Error('Invalid generator value'); + this._prime = prime; + this._generator = generator; + } + getDHParams() { + if (this._dh) { + return { + prime: convertToMpint(this._dh.getPrime()), + generator: convertToMpint(this._dh.getGenerator()), + }; + } + } + parse(payload) { + const type = payload[0]; + switch (this._step) { + case 1: { + if (this._protocol._server) { + if (type !== MESSAGE.KEXDH_GEX_REQUEST) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ` + + MESSAGE.KEXDH_GEX_REQUEST, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + // TODO: allow user implementation to provide safe prime and + // generator on demand to support group exchange on server side + return doFatalError( + this._protocol, + 'Group exchange not implemented for server', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + if (type !== MESSAGE.KEXDH_GEX_GROUP) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ${MESSAGE.KEXDH_GEX_GROUP}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + + this._protocol._debug && this._protocol._debug( + 'Received DH GEX Group' + ); + + /* + byte SSH_MSG_KEX_DH_GEX_GROUP + mpint p, safe prime + mpint g, generator for subgroup in GF(p) + */ + bufferParser.init(payload, 1); + let prime; + let gen; + if ((prime = bufferParser.readString()) === undefined + || (gen = bufferParser.readString()) === undefined) { + bufferParser.clear(); + return doFatalError( + this._protocol, + 'Received malformed KEXDH_GEX_GROUP', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + bufferParser.clear(); + + // TODO: validate prime + this.setDHParams(prime, gen); + this.generateKeys(); + const pubkey = this.getPublicKey(); + + this._protocol._debug && this._protocol._debug( + 'Outbound: Sending KEXDH_GEX_INIT' + ); + + let p = this._protocol._packetRW.write.allocStartKEX; + const packet = + this._protocol._packetRW.write.alloc(1 + 4 + pubkey.length, true); + packet[p] = MESSAGE.KEXDH_GEX_INIT; + writeUInt32BE(packet, pubkey.length, ++p); + packet.set(pubkey, p += 4); + this._protocol._cipher.encrypt( + this._protocol._packetRW.write.finalize(packet, true) + ); + + ++this._step; + break; + } + case 2: + if (this._protocol._server) { + if (type !== MESSAGE.KEXDH_GEX_INIT) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ${MESSAGE.KEXDH_GEX_INIT}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Received DH GEX Init' + ); + return doFatalError( + this._protocol, + 'Group exchange not implemented for server', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } else if (type !== MESSAGE.KEXDH_GEX_REPLY) { + return doFatalError( + this._protocol, + `Received packet ${type} instead of ${MESSAGE.KEXDH_GEX_REPLY}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + this._protocol._debug && this._protocol._debug( + 'Received DH GEX Reply' + ); + this._step = 1; + payload[0] = MESSAGE.KEXDH_REPLY; + this.parse = KeyExchange.prototype.parse; + this.parse(payload); + } + } + } + + class DHExchange extends KeyExchange { + constructor(groupName, hashName, ...args) { + super(...args); + + this.type = 'group'; + this.groupName = groupName; + this.hashName = hashName; + } + start() { + if (!this._protocol._server) { + this._protocol._debug && this._protocol._debug( + 'Outbound: Sending KEXDH_INIT' + ); + const pubKey = this.getPublicKey(); + let p = this._protocol._packetRW.write.allocStartKEX; + const packet = + this._protocol._packetRW.write.alloc(1 + 4 + pubKey.length, true); + packet[p] = MESSAGE.KEXDH_INIT; + writeUInt32BE(packet, pubKey.length, ++p); + packet.set(pubKey, p += 4); + this._protocol._cipher.encrypt( + this._protocol._packetRW.write.finalize(packet, true) + ); + } + } + generateKeys() { + if (!this._dh) { + this._dh = createDiffieHellmanGroup(this.groupName); + this._public = this._dh.generateKeys(); + } + } + getDHParams() { + if (this._dh) { + return { + prime: convertToMpint(this._dh.getPrime()), + generator: convertToMpint(this._dh.getGenerator()), + }; + } + } + } + + return (negotiated, ...args) => { + if (typeof negotiated !== 'object' || negotiated === null) + throw new Error('Invalid negotiated argument'); + const kexType = negotiated.kex; + if (typeof kexType === 'string') { + args = [negotiated, ...args]; + switch (kexType) { + case 'curve25519-sha256': + case 'curve25519-sha256@libssh.org': + if (!curve25519Supported) + break; + return new Curve25519Exchange('sha256', ...args); + + case 'ecdh-sha2-nistp256': + return new ECDHExchange('prime256v1', 'sha256', ...args); + case 'ecdh-sha2-nistp384': + return new ECDHExchange('secp384r1', 'sha384', ...args); + case 'ecdh-sha2-nistp521': + return new ECDHExchange('secp521r1', 'sha512', ...args); + + case 'diffie-hellman-group1-sha1': + return new DHExchange('modp2', 'sha1', ...args); + case 'diffie-hellman-group14-sha1': + return new DHExchange('modp14', 'sha1', ...args); + case 'diffie-hellman-group14-sha256': + return new DHExchange('modp14', 'sha256', ...args); + case 'diffie-hellman-group15-sha512': + return new DHExchange('modp15', 'sha512', ...args); + case 'diffie-hellman-group16-sha512': + return new DHExchange('modp16', 'sha512', ...args); + case 'diffie-hellman-group17-sha512': + return new DHExchange('modp17', 'sha512', ...args); + case 'diffie-hellman-group18-sha512': + return new DHExchange('modp18', 'sha512', ...args); + + case 'diffie-hellman-group-exchange-sha1': + return new DHGroupExchange('sha1', ...args); + case 'diffie-hellman-group-exchange-sha256': + return new DHGroupExchange('sha256', ...args); + } + throw new Error(`Unsupported key exchange algorithm: ${kexType}`); + } + throw new Error(`Invalid key exchange type: ${kexType}`); + }; +})(); + +const KexInit = (() => { + const KEX_PROPERTY_NAMES = [ + 'kex', + 'serverHostKey', + ['cs', 'cipher' ], + ['sc', 'cipher' ], + ['cs', 'mac' ], + ['sc', 'mac' ], + ['cs', 'compress' ], + ['sc', 'compress' ], + ['cs', 'lang' ], + ['sc', 'lang' ], + ]; + return class KexInit { + constructor(obj) { + if (typeof obj !== 'object' || obj === null) + throw new TypeError('Argument must be an object'); + + const lists = { + kex: undefined, + serverHostKey: undefined, + cs: { + cipher: undefined, + mac: undefined, + compress: undefined, + lang: undefined, + }, + sc: { + cipher: undefined, + mac: undefined, + compress: undefined, + lang: undefined, + }, + + all: undefined, + }; + let totalSize = 0; + for (const prop of KEX_PROPERTY_NAMES) { + let base; + let val; + let desc; + let key; + if (typeof prop === 'string') { + base = lists; + val = obj[prop]; + desc = key = prop; + } else { + const parent = prop[0]; + base = lists[parent]; + key = prop[1]; + val = obj[parent][key]; + desc = `${parent}.${key}`; + } + const entry = { array: undefined, buffer: undefined }; + if (Buffer.isBuffer(val)) { + entry.array = ('' + val).split(','); + entry.buffer = val; + totalSize += 4 + val.length; + } else { + if (typeof val === 'string') + val = val.split(','); + if (Array.isArray(val)) { + entry.array = val; + entry.buffer = Buffer.from(val.join(',')); + } else { + throw new TypeError(`Invalid \`${desc}\` type: ${typeof val}`); + } + totalSize += 4 + entry.buffer.length; + } + base[key] = entry; + } + + const all = Buffer.allocUnsafe(totalSize); + lists.all = all; + + let allPos = 0; + for (const prop of KEX_PROPERTY_NAMES) { + let data; + if (typeof prop === 'string') + data = lists[prop].buffer; + else + data = lists[prop[0]][prop[1]].buffer; + allPos = writeUInt32BE(all, data.length, allPos); + all.set(data, allPos); + allPos += data.length; + } + + this.totalSize = totalSize; + this.lists = lists; + } + copyAllTo(buf, offset) { + const src = this.lists.all; + if (typeof offset !== 'number') + throw new TypeError(`Invalid offset value: ${typeof offset}`); + if (buf.length - offset < src.length) + throw new Error('Insufficient space to copy list'); + buf.set(src, offset); + return src.length; + } + }; +})(); + +const hashString = (() => { + const LEN = Buffer.allocUnsafe(4); + return (hash, buf) => { + writeUInt32BE(LEN, buf.length, 0); + hash.update(LEN); + hash.update(buf); + }; +})(); + +function generateKEXVal(len, hashName, secret, exchangeHash, sessionID, char) { + let ret; + if (len) { + let digest = createHash(hashName) + .update(secret) + .update(exchangeHash) + .update(char) + .update(sessionID) + .digest(); + while (digest.length < len) { + const chunk = createHash(hashName) + .update(secret) + .update(exchangeHash) + .update(digest) + .digest(); + const extended = Buffer.allocUnsafe(digest.length + chunk.length); + extended.set(digest, 0); + extended.set(chunk, digest.length); + digest = extended; + } + if (digest.length === len) + ret = digest; + else + ret = new FastBuffer(digest.buffer, digest.byteOffset, len); + } else { + ret = EMPTY_BUFFER; + } + return ret; +} + +function onKEXPayload(state, payload) { + // XXX: move this to the Decipher implementations? + if (payload.length === 0) { + this._debug && this._debug('Inbound: Skipping empty packet payload'); + return; + } + + if (this._skipNextInboundPacket) { + this._skipNextInboundPacket = false; + return; + } + + payload = this._packetRW.read.read(payload); + + const type = payload[0]; + + if (!this._strictMode) { + switch (type) { + case MESSAGE.IGNORE: + case MESSAGE.UNIMPLEMENTED: + case MESSAGE.DEBUG: + if (!MESSAGE_HANDLERS) + MESSAGE_HANDLERS = require('./handlers.js'); + return MESSAGE_HANDLERS[type](this, payload); + } + } + + switch (type) { + case MESSAGE.DISCONNECT: + if (!MESSAGE_HANDLERS) + MESSAGE_HANDLERS = require('./handlers.js'); + return MESSAGE_HANDLERS[type](this, payload); + case MESSAGE.KEXINIT: + if (!state.firstPacket) { + return doFatalError( + this, + 'Received extra KEXINIT during handshake', + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + state.firstPacket = false; + return handleKexInit(this, payload); + default: + // Ensure packet is either an algorithm negotiation or KEX + // algorithm-specific packet + if (type < 20 || type > 49) { + return doFatalError( + this, + `Received unexpected packet type ${type}`, + 'handshake', + DISCONNECT_REASON.KEY_EXCHANGE_FAILED + ); + } + } + + return this._kex.parse(payload); +} + +function dhEstimate(neg) { + const csCipher = CIPHER_INFO[neg.cs.cipher]; + const scCipher = CIPHER_INFO[neg.sc.cipher]; + // XXX: if OpenSSH's `umac-*` MACs are ever supported, their key lengths will + // also need to be considered when calculating `bits` + const bits = Math.max( + 0, + (csCipher.sslName === 'des-ede3-cbc' ? 14 : csCipher.keyLen), + csCipher.blockLen, + csCipher.ivLen, + (scCipher.sslName === 'des-ede3-cbc' ? 14 : scCipher.keyLen), + scCipher.blockLen, + scCipher.ivLen + ) * 8; + if (bits <= 112) + return 2048; + if (bits <= 128) + return 3072; + if (bits <= 192) + return 7680; + return 8192; +} + +function trySendNEWKEYS(kex) { + if (!kex._sentNEWKEYS) { + kex._protocol._debug && kex._protocol._debug( + 'Outbound: Sending NEWKEYS' + ); + const p = kex._protocol._packetRW.write.allocStartKEX; + const packet = kex._protocol._packetRW.write.alloc(1, true); + packet[p] = MESSAGE.NEWKEYS; + kex._protocol._cipher.encrypt( + kex._protocol._packetRW.write.finalize(packet, true) + ); + kex._sentNEWKEYS = true; + if (kex._protocol._strictMode) + kex._protocol._cipher.outSeqno = 0; + } +} + +module.exports = { + KexInit, + kexinit, + onKEXPayload, + DEFAULT_KEXINIT_CLIENT: new KexInit({ + kex: DEFAULT_KEX.concat(['ext-info-c', 'kex-strict-c-v00@openssh.com']), + serverHostKey: DEFAULT_SERVER_HOST_KEY, + cs: { + cipher: DEFAULT_CIPHER, + mac: DEFAULT_MAC, + compress: DEFAULT_COMPRESSION, + lang: [], + }, + sc: { + cipher: DEFAULT_CIPHER, + mac: DEFAULT_MAC, + compress: DEFAULT_COMPRESSION, + lang: [], + }, + }), + DEFAULT_KEXINIT_SERVER: new KexInit({ + kex: DEFAULT_KEX.concat(['kex-strict-s-v00@openssh.com']), + serverHostKey: DEFAULT_SERVER_HOST_KEY, + cs: { + cipher: DEFAULT_CIPHER, + mac: DEFAULT_MAC, + compress: DEFAULT_COMPRESSION, + lang: [], + }, + sc: { + cipher: DEFAULT_CIPHER, + mac: DEFAULT_MAC, + compress: DEFAULT_COMPRESSION, + lang: [], + }, + }), + HANDLERS: { + [MESSAGE.KEXINIT]: handleKexInit, + }, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/keyParser.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/keyParser.js new file mode 100644 index 0000000..a276c1a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/keyParser.js @@ -0,0 +1,1484 @@ +// TODO: +// * utilize `crypto.create(Private|Public)Key()` and `keyObject.export()` +// * handle multi-line header values (OpenSSH)? +// * more thorough validation? +'use strict'; + +const { + createDecipheriv, + createECDH, + createHash, + createHmac, + createSign, + createVerify, + getCiphers, + sign: sign_, + verify: verify_, +} = require('crypto'); +const supportedOpenSSLCiphers = getCiphers(); + +const { Ber } = require('asn1'); +const bcrypt_pbkdf = require('bcrypt-pbkdf').pbkdf; + +const { CIPHER_INFO } = require('./crypto.js'); +const { eddsaSupported, SUPPORTED_CIPHER } = require('./constants.js'); +const { + bufferSlice, + makeBufferParser, + readString, + readUInt32BE, + writeUInt32BE, +} = require('./utils.js'); + +const SYM_HASH_ALGO = Symbol('Hash Algorithm'); +const SYM_PRIV_PEM = Symbol('Private key PEM'); +const SYM_PUB_PEM = Symbol('Public key PEM'); +const SYM_PUB_SSH = Symbol('Public key SSH'); +const SYM_DECRYPTED = Symbol('Decrypted Key'); + +// Create OpenSSL cipher name -> SSH cipher name conversion table +const CIPHER_INFO_OPENSSL = Object.create(null); +{ + const keys = Object.keys(CIPHER_INFO); + for (let i = 0; i < keys.length; ++i) { + const cipherName = CIPHER_INFO[keys[i]].sslName; + if (!cipherName || CIPHER_INFO_OPENSSL[cipherName]) + continue; + CIPHER_INFO_OPENSSL[cipherName] = CIPHER_INFO[keys[i]]; + } +} + +const binaryKeyParser = makeBufferParser(); + +function makePEM(type, data) { + data = data.base64Slice(0, data.length); + let formatted = data.replace(/.{64}/g, '$&\n'); + if (data.length & 63) + formatted += '\n'; + return `-----BEGIN ${type} KEY-----\n${formatted}-----END ${type} KEY-----`; +} + +function combineBuffers(buf1, buf2) { + const result = Buffer.allocUnsafe(buf1.length + buf2.length); + result.set(buf1, 0); + result.set(buf2, buf1.length); + return result; +} + +function skipFields(buf, nfields) { + const bufLen = buf.length; + let pos = (buf._pos || 0); + for (let i = 0; i < nfields; ++i) { + const left = (bufLen - pos); + if (pos >= bufLen || left < 4) + return false; + const len = readUInt32BE(buf, pos); + if (left < 4 + len) + return false; + pos += 4 + len; + } + buf._pos = pos; + return true; +} + +function genOpenSSLRSAPub(n, e) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // algorithm + asnWriter.startSequence(); + asnWriter.writeOID('1.2.840.113549.1.1.1'); // rsaEncryption + // algorithm parameters (RSA has none) + asnWriter.writeNull(); + asnWriter.endSequence(); + + // subjectPublicKey + asnWriter.startSequence(Ber.BitString); + asnWriter.writeByte(0x00); + asnWriter.startSequence(); + asnWriter.writeBuffer(n, Ber.Integer); + asnWriter.writeBuffer(e, Ber.Integer); + asnWriter.endSequence(); + asnWriter.endSequence(); + asnWriter.endSequence(); + return makePEM('PUBLIC', asnWriter.buffer); +} + +function genOpenSSHRSAPub(n, e) { + const publicKey = Buffer.allocUnsafe(4 + 7 + 4 + e.length + 4 + n.length); + + writeUInt32BE(publicKey, 7, 0); + publicKey.utf8Write('ssh-rsa', 4, 7); + + let i = 4 + 7; + writeUInt32BE(publicKey, e.length, i); + publicKey.set(e, i += 4); + + writeUInt32BE(publicKey, n.length, i += e.length); + publicKey.set(n, i + 4); + + return publicKey; +} + +const genOpenSSLRSAPriv = (() => { + function genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + asnWriter.writeInt(0x00, Ber.Integer); + asnWriter.writeBuffer(n, Ber.Integer); + asnWriter.writeBuffer(e, Ber.Integer); + asnWriter.writeBuffer(d, Ber.Integer); + asnWriter.writeBuffer(p, Ber.Integer); + asnWriter.writeBuffer(q, Ber.Integer); + asnWriter.writeBuffer(dmp1, Ber.Integer); + asnWriter.writeBuffer(dmq1, Ber.Integer); + asnWriter.writeBuffer(iqmp, Ber.Integer); + asnWriter.endSequence(); + return asnWriter.buffer; + } + + function bigIntFromBuffer(buf) { + return BigInt(`0x${buf.hexSlice(0, buf.length)}`); + } + + function bigIntToBuffer(bn) { + let hex = bn.toString(16); + if ((hex.length & 1) !== 0) { + hex = `0${hex}`; + } else { + const sigbit = hex.charCodeAt(0); + // BER/DER integers require leading zero byte to denote a positive value + // when first byte >= 0x80 + if (sigbit === 56/* '8' */ + || sigbit === 57/* '9' */ + || (sigbit >= 97/* 'a' */ && sigbit <= 102/* 'f' */)) { + hex = `00${hex}`; + } + } + return Buffer.from(hex, 'hex'); + } + + return function genOpenSSLRSAPriv(n, e, d, iqmp, p, q) { + const bn_d = bigIntFromBuffer(d); + const dmp1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(p) - 1n)); + const dmq1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(q) - 1n)); + return makePEM('RSA PRIVATE', + genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp)); + }; +})(); + +function genOpenSSLDSAPub(p, q, g, y) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // algorithm + asnWriter.startSequence(); + asnWriter.writeOID('1.2.840.10040.4.1'); // id-dsa + // algorithm parameters + asnWriter.startSequence(); + asnWriter.writeBuffer(p, Ber.Integer); + asnWriter.writeBuffer(q, Ber.Integer); + asnWriter.writeBuffer(g, Ber.Integer); + asnWriter.endSequence(); + asnWriter.endSequence(); + + // subjectPublicKey + asnWriter.startSequence(Ber.BitString); + asnWriter.writeByte(0x00); + asnWriter.writeBuffer(y, Ber.Integer); + asnWriter.endSequence(); + asnWriter.endSequence(); + return makePEM('PUBLIC', asnWriter.buffer); +} + +function genOpenSSHDSAPub(p, q, g, y) { + const publicKey = Buffer.allocUnsafe( + 4 + 7 + 4 + p.length + 4 + q.length + 4 + g.length + 4 + y.length + ); + + writeUInt32BE(publicKey, 7, 0); + publicKey.utf8Write('ssh-dss', 4, 7); + + let i = 4 + 7; + writeUInt32BE(publicKey, p.length, i); + publicKey.set(p, i += 4); + + writeUInt32BE(publicKey, q.length, i += p.length); + publicKey.set(q, i += 4); + + writeUInt32BE(publicKey, g.length, i += q.length); + publicKey.set(g, i += 4); + + writeUInt32BE(publicKey, y.length, i += g.length); + publicKey.set(y, i + 4); + + return publicKey; +} + +function genOpenSSLDSAPriv(p, q, g, y, x) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + asnWriter.writeInt(0x00, Ber.Integer); + asnWriter.writeBuffer(p, Ber.Integer); + asnWriter.writeBuffer(q, Ber.Integer); + asnWriter.writeBuffer(g, Ber.Integer); + asnWriter.writeBuffer(y, Ber.Integer); + asnWriter.writeBuffer(x, Ber.Integer); + asnWriter.endSequence(); + return makePEM('DSA PRIVATE', asnWriter.buffer); +} + +function genOpenSSLEdPub(pub) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // algorithm + asnWriter.startSequence(); + asnWriter.writeOID('1.3.101.112'); // id-Ed25519 + asnWriter.endSequence(); + + // PublicKey + asnWriter.startSequence(Ber.BitString); + asnWriter.writeByte(0x00); + // XXX: hack to write a raw buffer without a tag -- yuck + asnWriter._ensure(pub.length); + asnWriter._buf.set(pub, asnWriter._offset); + asnWriter._offset += pub.length; + asnWriter.endSequence(); + asnWriter.endSequence(); + return makePEM('PUBLIC', asnWriter.buffer); +} + +function genOpenSSHEdPub(pub) { + const publicKey = Buffer.allocUnsafe(4 + 11 + 4 + pub.length); + + writeUInt32BE(publicKey, 11, 0); + publicKey.utf8Write('ssh-ed25519', 4, 11); + + writeUInt32BE(publicKey, pub.length, 15); + publicKey.set(pub, 19); + + return publicKey; +} + +function genOpenSSLEdPriv(priv) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // version + asnWriter.writeInt(0x00, Ber.Integer); + + // algorithm + asnWriter.startSequence(); + asnWriter.writeOID('1.3.101.112'); // id-Ed25519 + asnWriter.endSequence(); + + // PrivateKey + asnWriter.startSequence(Ber.OctetString); + asnWriter.writeBuffer(priv, Ber.OctetString); + asnWriter.endSequence(); + asnWriter.endSequence(); + return makePEM('PRIVATE', asnWriter.buffer); +} + +function genOpenSSLECDSAPub(oid, Q) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // algorithm + asnWriter.startSequence(); + asnWriter.writeOID('1.2.840.10045.2.1'); // id-ecPublicKey + // algorithm parameters (namedCurve) + asnWriter.writeOID(oid); + asnWriter.endSequence(); + + // subjectPublicKey + asnWriter.startSequence(Ber.BitString); + asnWriter.writeByte(0x00); + // XXX: hack to write a raw buffer without a tag -- yuck + asnWriter._ensure(Q.length); + asnWriter._buf.set(Q, asnWriter._offset); + asnWriter._offset += Q.length; + // end hack + asnWriter.endSequence(); + asnWriter.endSequence(); + return makePEM('PUBLIC', asnWriter.buffer); +} + +function genOpenSSHECDSAPub(oid, Q) { + let curveName; + switch (oid) { + case '1.2.840.10045.3.1.7': + // prime256v1/secp256r1 + curveName = 'nistp256'; + break; + case '1.3.132.0.34': + // secp384r1 + curveName = 'nistp384'; + break; + case '1.3.132.0.35': + // secp521r1 + curveName = 'nistp521'; + break; + default: + return; + } + + const publicKey = Buffer.allocUnsafe(4 + 19 + 4 + 8 + 4 + Q.length); + + writeUInt32BE(publicKey, 19, 0); + publicKey.utf8Write(`ecdsa-sha2-${curveName}`, 4, 19); + + writeUInt32BE(publicKey, 8, 23); + publicKey.utf8Write(curveName, 27, 8); + + writeUInt32BE(publicKey, Q.length, 35); + publicKey.set(Q, 39); + + return publicKey; +} + +function genOpenSSLECDSAPriv(oid, pub, priv) { + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + // version + asnWriter.writeInt(0x01, Ber.Integer); + // privateKey + asnWriter.writeBuffer(priv, Ber.OctetString); + // parameters (optional) + asnWriter.startSequence(0xA0); + asnWriter.writeOID(oid); + asnWriter.endSequence(); + // publicKey (optional) + asnWriter.startSequence(0xA1); + asnWriter.startSequence(Ber.BitString); + asnWriter.writeByte(0x00); + // XXX: hack to write a raw buffer without a tag -- yuck + asnWriter._ensure(pub.length); + asnWriter._buf.set(pub, asnWriter._offset); + asnWriter._offset += pub.length; + // end hack + asnWriter.endSequence(); + asnWriter.endSequence(); + asnWriter.endSequence(); + return makePEM('EC PRIVATE', asnWriter.buffer); +} + +function genOpenSSLECDSAPubFromPriv(curveName, priv) { + const tempECDH = createECDH(curveName); + tempECDH.setPrivateKey(priv); + return tempECDH.getPublicKey(); +} + +const BaseKey = { + sign: (() => { + if (typeof sign_ === 'function') { + return function sign(data, algo) { + const pem = this[SYM_PRIV_PEM]; + if (pem === null) + return new Error('No private key available'); + if (!algo || typeof algo !== 'string') + algo = this[SYM_HASH_ALGO]; + try { + return sign_(algo, data, pem); + } catch (ex) { + return ex; + } + }; + } + return function sign(data, algo) { + const pem = this[SYM_PRIV_PEM]; + if (pem === null) + return new Error('No private key available'); + if (!algo || typeof algo !== 'string') + algo = this[SYM_HASH_ALGO]; + const signature = createSign(algo); + signature.update(data); + try { + return signature.sign(pem); + } catch (ex) { + return ex; + } + }; + })(), + verify: (() => { + if (typeof verify_ === 'function') { + return function verify(data, signature, algo) { + const pem = this[SYM_PUB_PEM]; + if (pem === null) + return new Error('No public key available'); + if (!algo || typeof algo !== 'string') + algo = this[SYM_HASH_ALGO]; + try { + return verify_(algo, data, pem, signature); + } catch (ex) { + return ex; + } + }; + } + return function verify(data, signature, algo) { + const pem = this[SYM_PUB_PEM]; + if (pem === null) + return new Error('No public key available'); + if (!algo || typeof algo !== 'string') + algo = this[SYM_HASH_ALGO]; + const verifier = createVerify(algo); + verifier.update(data); + try { + return verifier.verify(pem, signature); + } catch (ex) { + return ex; + } + }; + })(), + isPrivateKey: function isPrivateKey() { + return (this[SYM_PRIV_PEM] !== null); + }, + getPrivatePEM: function getPrivatePEM() { + return this[SYM_PRIV_PEM]; + }, + getPublicPEM: function getPublicPEM() { + return this[SYM_PUB_PEM]; + }, + getPublicSSH: function getPublicSSH() { + return this[SYM_PUB_SSH]; + }, + equals: function equals(key) { + const parsed = parseKey(key); + if (parsed instanceof Error) + return false; + return ( + this.type === parsed.type + && this[SYM_PRIV_PEM] === parsed[SYM_PRIV_PEM] + && this[SYM_PUB_PEM] === parsed[SYM_PUB_PEM] + && this[SYM_PUB_SSH].equals(parsed[SYM_PUB_SSH]) + ); + }, +}; + + +function OpenSSH_Private(type, comment, privPEM, pubPEM, pubSSH, algo, + decrypted) { + this.type = type; + this.comment = comment; + this[SYM_PRIV_PEM] = privPEM; + this[SYM_PUB_PEM] = pubPEM; + this[SYM_PUB_SSH] = pubSSH; + this[SYM_HASH_ALGO] = algo; + this[SYM_DECRYPTED] = decrypted; +} +OpenSSH_Private.prototype = BaseKey; +{ + const regexp = /^-----BEGIN OPENSSH PRIVATE KEY-----(?:\r\n|\n)([\s\S]+)(?:\r\n|\n)-----END OPENSSH PRIVATE KEY-----$/; + OpenSSH_Private.parse = (str, passphrase) => { + const m = regexp.exec(str); + if (m === null) + return null; + let ret; + const data = Buffer.from(m[1], 'base64'); + if (data.length < 31) // magic (+ magic null term.) + minimum field lengths + return new Error('Malformed OpenSSH private key'); + const magic = data.utf8Slice(0, 15); + if (magic !== 'openssh-key-v1\0') + return new Error(`Unsupported OpenSSH key magic: ${magic}`); + + const cipherName = readString(data, 15, true); + if (cipherName === undefined) + return new Error('Malformed OpenSSH private key'); + if (cipherName !== 'none' && SUPPORTED_CIPHER.indexOf(cipherName) === -1) + return new Error(`Unsupported cipher for OpenSSH key: ${cipherName}`); + + const kdfName = readString(data, data._pos, true); + if (kdfName === undefined) + return new Error('Malformed OpenSSH private key'); + if (kdfName !== 'none') { + if (cipherName === 'none') + return new Error('Malformed OpenSSH private key'); + if (kdfName !== 'bcrypt') + return new Error(`Unsupported kdf name for OpenSSH key: ${kdfName}`); + if (!passphrase) { + return new Error( + 'Encrypted private OpenSSH key detected, but no passphrase given' + ); + } + } else if (cipherName !== 'none') { + return new Error('Malformed OpenSSH private key'); + } + + let encInfo; + let cipherKey; + let cipherIV; + if (cipherName !== 'none') + encInfo = CIPHER_INFO[cipherName]; + const kdfOptions = readString(data, data._pos); + if (kdfOptions === undefined) + return new Error('Malformed OpenSSH private key'); + if (kdfOptions.length) { + switch (kdfName) { + case 'none': + return new Error('Malformed OpenSSH private key'); + case 'bcrypt': { + /* + string salt + uint32 rounds + */ + const salt = readString(kdfOptions, 0); + if (salt === undefined || kdfOptions._pos + 4 > kdfOptions.length) + return new Error('Malformed OpenSSH private key'); + const rounds = readUInt32BE(kdfOptions, kdfOptions._pos); + const gen = Buffer.allocUnsafe(encInfo.keyLen + encInfo.ivLen); + const r = bcrypt_pbkdf(passphrase, + passphrase.length, + salt, + salt.length, + gen, + gen.length, + rounds); + if (r !== 0) + return new Error('Failed to generate information to decrypt key'); + cipherKey = bufferSlice(gen, 0, encInfo.keyLen); + cipherIV = bufferSlice(gen, encInfo.keyLen, gen.length); + break; + } + } + } else if (kdfName !== 'none') { + return new Error('Malformed OpenSSH private key'); + } + + if (data._pos + 3 >= data.length) + return new Error('Malformed OpenSSH private key'); + const keyCount = readUInt32BE(data, data._pos); + data._pos += 4; + + if (keyCount > 0) { + // TODO: place sensible limit on max `keyCount` + + // Read public keys first + for (let i = 0; i < keyCount; ++i) { + const pubData = readString(data, data._pos); + if (pubData === undefined) + return new Error('Malformed OpenSSH private key'); + const type = readString(pubData, 0, true); + if (type === undefined) + return new Error('Malformed OpenSSH private key'); + } + + let privBlob = readString(data, data._pos); + if (privBlob === undefined) + return new Error('Malformed OpenSSH private key'); + + if (cipherKey !== undefined) { + // Encrypted private key(s) + if (privBlob.length < encInfo.blockLen + || (privBlob.length % encInfo.blockLen) !== 0) { + return new Error('Malformed OpenSSH private key'); + } + try { + const options = { authTagLength: encInfo.authLen }; + const decipher = createDecipheriv(encInfo.sslName, + cipherKey, + cipherIV, + options); + decipher.setAutoPadding(false); + if (encInfo.authLen > 0) { + if (data.length - data._pos < encInfo.authLen) + return new Error('Malformed OpenSSH private key'); + decipher.setAuthTag( + bufferSlice(data, data._pos, data._pos += encInfo.authLen) + ); + } + privBlob = combineBuffers(decipher.update(privBlob), + decipher.final()); + } catch (ex) { + return ex; + } + } + // Nothing should we follow the private key(s), except a possible + // authentication tag for relevant ciphers + if (data._pos !== data.length) + return new Error('Malformed OpenSSH private key'); + + ret = parseOpenSSHPrivKeys(privBlob, keyCount, cipherKey !== undefined); + } else { + ret = []; + } + if (ret instanceof Error) + return ret; + // This will need to change if/when OpenSSH ever starts storing multiple + // keys in their key files + return ret[0]; + }; + + function parseOpenSSHPrivKeys(data, nkeys, decrypted) { + const keys = []; + /* + uint32 checkint + uint32 checkint + string privatekey1 + string comment1 + string privatekey2 + string comment2 + ... + string privatekeyN + string commentN + char 1 + char 2 + char 3 + ... + char padlen % 255 + */ + if (data.length < 8) + return new Error('Malformed OpenSSH private key'); + const check1 = readUInt32BE(data, 0); + const check2 = readUInt32BE(data, 4); + if (check1 !== check2) { + if (decrypted) { + return new Error( + 'OpenSSH key integrity check failed -- bad passphrase?' + ); + } + return new Error('OpenSSH key integrity check failed'); + } + data._pos = 8; + let i; + let oid; + for (i = 0; i < nkeys; ++i) { + let algo; + let privPEM; + let pubPEM; + let pubSSH; + // The OpenSSH documentation for the key format actually lies, the + // entirety of the private key content is not contained with a string + // field, it's actually the literal contents of the private key, so to be + // able to find the end of the key data you need to know the layout/format + // of each key type ... + const type = readString(data, data._pos, true); + if (type === undefined) + return new Error('Malformed OpenSSH private key'); + + switch (type) { + case 'ssh-rsa': { + /* + string n -- public + string e -- public + string d -- private + string iqmp -- private + string p -- private + string q -- private + */ + const n = readString(data, data._pos); + if (n === undefined) + return new Error('Malformed OpenSSH private key'); + const e = readString(data, data._pos); + if (e === undefined) + return new Error('Malformed OpenSSH private key'); + const d = readString(data, data._pos); + if (d === undefined) + return new Error('Malformed OpenSSH private key'); + const iqmp = readString(data, data._pos); + if (iqmp === undefined) + return new Error('Malformed OpenSSH private key'); + const p = readString(data, data._pos); + if (p === undefined) + return new Error('Malformed OpenSSH private key'); + const q = readString(data, data._pos); + if (q === undefined) + return new Error('Malformed OpenSSH private key'); + + pubPEM = genOpenSSLRSAPub(n, e); + pubSSH = genOpenSSHRSAPub(n, e); + privPEM = genOpenSSLRSAPriv(n, e, d, iqmp, p, q); + algo = 'sha1'; + break; + } + case 'ssh-dss': { + /* + string p -- public + string q -- public + string g -- public + string y -- public + string x -- private + */ + const p = readString(data, data._pos); + if (p === undefined) + return new Error('Malformed OpenSSH private key'); + const q = readString(data, data._pos); + if (q === undefined) + return new Error('Malformed OpenSSH private key'); + const g = readString(data, data._pos); + if (g === undefined) + return new Error('Malformed OpenSSH private key'); + const y = readString(data, data._pos); + if (y === undefined) + return new Error('Malformed OpenSSH private key'); + const x = readString(data, data._pos); + if (x === undefined) + return new Error('Malformed OpenSSH private key'); + + pubPEM = genOpenSSLDSAPub(p, q, g, y); + pubSSH = genOpenSSHDSAPub(p, q, g, y); + privPEM = genOpenSSLDSAPriv(p, q, g, y, x); + algo = 'sha1'; + break; + } + case 'ssh-ed25519': { + if (!eddsaSupported) + return new Error(`Unsupported OpenSSH private key type: ${type}`); + /* + * string public key + * string private key + public key + */ + const edpub = readString(data, data._pos); + if (edpub === undefined || edpub.length !== 32) + return new Error('Malformed OpenSSH private key'); + const edpriv = readString(data, data._pos); + if (edpriv === undefined || edpriv.length !== 64) + return new Error('Malformed OpenSSH private key'); + + pubPEM = genOpenSSLEdPub(edpub); + pubSSH = genOpenSSHEdPub(edpub); + privPEM = genOpenSSLEdPriv(bufferSlice(edpriv, 0, 32)); + algo = null; + break; + } + case 'ecdsa-sha2-nistp256': + algo = 'sha256'; + oid = '1.2.840.10045.3.1.7'; + // FALLTHROUGH + case 'ecdsa-sha2-nistp384': + if (algo === undefined) { + algo = 'sha384'; + oid = '1.3.132.0.34'; + } + // FALLTHROUGH + case 'ecdsa-sha2-nistp521': { + if (algo === undefined) { + algo = 'sha512'; + oid = '1.3.132.0.35'; + } + /* + string curve name + string Q -- public + string d -- private + */ + // TODO: validate curve name against type + if (!skipFields(data, 1)) // Skip curve name + return new Error('Malformed OpenSSH private key'); + const ecpub = readString(data, data._pos); + if (ecpub === undefined) + return new Error('Malformed OpenSSH private key'); + const ecpriv = readString(data, data._pos); + if (ecpriv === undefined) + return new Error('Malformed OpenSSH private key'); + + pubPEM = genOpenSSLECDSAPub(oid, ecpub); + pubSSH = genOpenSSHECDSAPub(oid, ecpub); + privPEM = genOpenSSLECDSAPriv(oid, ecpub, ecpriv); + break; + } + default: + return new Error(`Unsupported OpenSSH private key type: ${type}`); + } + + const privComment = readString(data, data._pos, true); + if (privComment === undefined) + return new Error('Malformed OpenSSH private key'); + + keys.push( + new OpenSSH_Private(type, privComment, privPEM, pubPEM, pubSSH, algo, + decrypted) + ); + } + let cnt = 0; + for (i = data._pos; i < data.length; ++i) { + if (data[i] !== (++cnt % 255)) + return new Error('Malformed OpenSSH private key'); + } + + return keys; + } +} + + +function OpenSSH_Old_Private(type, comment, privPEM, pubPEM, pubSSH, algo, + decrypted) { + this.type = type; + this.comment = comment; + this[SYM_PRIV_PEM] = privPEM; + this[SYM_PUB_PEM] = pubPEM; + this[SYM_PUB_SSH] = pubSSH; + this[SYM_HASH_ALGO] = algo; + this[SYM_DECRYPTED] = decrypted; +} +OpenSSH_Old_Private.prototype = BaseKey; +{ + const regexp = /^-----BEGIN (RSA|DSA|EC) PRIVATE KEY-----(?:\r\n|\n)((?:[^:]+:\s*[\S].*(?:\r\n|\n))*)([\s\S]+)(?:\r\n|\n)-----END (RSA|DSA|EC) PRIVATE KEY-----$/; + OpenSSH_Old_Private.parse = (str, passphrase) => { + const m = regexp.exec(str); + if (m === null) + return null; + let privBlob = Buffer.from(m[3], 'base64'); + let headers = m[2]; + let decrypted = false; + if (headers !== undefined) { + // encrypted key + headers = headers.split(/\r\n|\n/g); + for (let i = 0; i < headers.length; ++i) { + const header = headers[i]; + let sepIdx = header.indexOf(':'); + if (header.slice(0, sepIdx) === 'DEK-Info') { + const val = header.slice(sepIdx + 2); + sepIdx = val.indexOf(','); + if (sepIdx === -1) + continue; + const cipherName = val.slice(0, sepIdx).toLowerCase(); + if (supportedOpenSSLCiphers.indexOf(cipherName) === -1) { + return new Error( + `Cipher (${cipherName}) not supported ` + + 'for encrypted OpenSSH private key' + ); + } + const encInfo = CIPHER_INFO_OPENSSL[cipherName]; + if (!encInfo) { + return new Error( + `Cipher (${cipherName}) not supported ` + + 'for encrypted OpenSSH private key' + ); + } + const cipherIV = Buffer.from(val.slice(sepIdx + 1), 'hex'); + if (cipherIV.length !== encInfo.ivLen) + return new Error('Malformed encrypted OpenSSH private key'); + if (!passphrase) { + return new Error( + 'Encrypted OpenSSH private key detected, but no passphrase given' + ); + } + const ivSlice = bufferSlice(cipherIV, 0, 8); + let cipherKey = createHash('md5') + .update(passphrase) + .update(ivSlice) + .digest(); + while (cipherKey.length < encInfo.keyLen) { + cipherKey = combineBuffers( + cipherKey, + createHash('md5') + .update(cipherKey) + .update(passphrase) + .update(ivSlice) + .digest() + ); + } + if (cipherKey.length > encInfo.keyLen) + cipherKey = bufferSlice(cipherKey, 0, encInfo.keyLen); + try { + const decipher = createDecipheriv(cipherName, cipherKey, cipherIV); + decipher.setAutoPadding(false); + privBlob = combineBuffers(decipher.update(privBlob), + decipher.final()); + decrypted = true; + } catch (ex) { + return ex; + } + } + } + } + + let type; + let privPEM; + let pubPEM; + let pubSSH; + let algo; + let reader; + let errMsg = 'Malformed OpenSSH private key'; + if (decrypted) + errMsg += '. Bad passphrase?'; + switch (m[1]) { + case 'RSA': + type = 'ssh-rsa'; + privPEM = makePEM('RSA PRIVATE', privBlob); + try { + reader = new Ber.Reader(privBlob); + reader.readSequence(); + reader.readInt(); // skip version + const n = reader.readString(Ber.Integer, true); + if (n === null) + return new Error(errMsg); + const e = reader.readString(Ber.Integer, true); + if (e === null) + return new Error(errMsg); + pubPEM = genOpenSSLRSAPub(n, e); + pubSSH = genOpenSSHRSAPub(n, e); + } catch { + return new Error(errMsg); + } + algo = 'sha1'; + break; + case 'DSA': + type = 'ssh-dss'; + privPEM = makePEM('DSA PRIVATE', privBlob); + try { + reader = new Ber.Reader(privBlob); + reader.readSequence(); + reader.readInt(); // skip version + const p = reader.readString(Ber.Integer, true); + if (p === null) + return new Error(errMsg); + const q = reader.readString(Ber.Integer, true); + if (q === null) + return new Error(errMsg); + const g = reader.readString(Ber.Integer, true); + if (g === null) + return new Error(errMsg); + const y = reader.readString(Ber.Integer, true); + if (y === null) + return new Error(errMsg); + pubPEM = genOpenSSLDSAPub(p, q, g, y); + pubSSH = genOpenSSHDSAPub(p, q, g, y); + } catch { + return new Error(errMsg); + } + algo = 'sha1'; + break; + case 'EC': { + let ecSSLName; + let ecPriv; + let ecOID; + try { + reader = new Ber.Reader(privBlob); + reader.readSequence(); + reader.readInt(); // skip version + ecPriv = reader.readString(Ber.OctetString, true); + reader.readByte(); // Skip "complex" context type byte + const offset = reader.readLength(); // Skip context length + if (offset !== null) { + reader._offset = offset; + ecOID = reader.readOID(); + if (ecOID === null) + return new Error(errMsg); + switch (ecOID) { + case '1.2.840.10045.3.1.7': + // prime256v1/secp256r1 + ecSSLName = 'prime256v1'; + type = 'ecdsa-sha2-nistp256'; + algo = 'sha256'; + break; + case '1.3.132.0.34': + // secp384r1 + ecSSLName = 'secp384r1'; + type = 'ecdsa-sha2-nistp384'; + algo = 'sha384'; + break; + case '1.3.132.0.35': + // secp521r1 + ecSSLName = 'secp521r1'; + type = 'ecdsa-sha2-nistp521'; + algo = 'sha512'; + break; + default: + return new Error(`Unsupported private key EC OID: ${ecOID}`); + } + } else { + return new Error(errMsg); + } + } catch { + return new Error(errMsg); + } + privPEM = makePEM('EC PRIVATE', privBlob); + const pubBlob = genOpenSSLECDSAPubFromPriv(ecSSLName, ecPriv); + pubPEM = genOpenSSLECDSAPub(ecOID, pubBlob); + pubSSH = genOpenSSHECDSAPub(ecOID, pubBlob); + break; + } + } + + return new OpenSSH_Old_Private(type, '', privPEM, pubPEM, pubSSH, algo, + decrypted); + }; +} + + +function PPK_Private(type, comment, privPEM, pubPEM, pubSSH, algo, decrypted) { + this.type = type; + this.comment = comment; + this[SYM_PRIV_PEM] = privPEM; + this[SYM_PUB_PEM] = pubPEM; + this[SYM_PUB_SSH] = pubSSH; + this[SYM_HASH_ALGO] = algo; + this[SYM_DECRYPTED] = decrypted; +} +PPK_Private.prototype = BaseKey; +{ + const EMPTY_PASSPHRASE = Buffer.alloc(0); + const PPK_IV = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + const PPK_PP1 = Buffer.from([0, 0, 0, 0]); + const PPK_PP2 = Buffer.from([0, 0, 0, 1]); + const regexp = /^PuTTY-User-Key-File-2: (ssh-(?:rsa|dss))\r?\nEncryption: (aes256-cbc|none)\r?\nComment: ([^\r\n]*)\r?\nPublic-Lines: \d+\r?\n([\s\S]+?)\r?\nPrivate-Lines: \d+\r?\n([\s\S]+?)\r?\nPrivate-MAC: ([^\r\n]+)/; + PPK_Private.parse = (str, passphrase) => { + const m = regexp.exec(str); + if (m === null) + return null; + // m[1] = key type + // m[2] = encryption type + // m[3] = comment + // m[4] = base64-encoded public key data: + // for "ssh-rsa": + // string "ssh-rsa" + // mpint e (public exponent) + // mpint n (modulus) + // for "ssh-dss": + // string "ssh-dss" + // mpint p (modulus) + // mpint q (prime) + // mpint g (base number) + // mpint y (public key parameter: g^x mod p) + // m[5] = base64-encoded private key data: + // for "ssh-rsa": + // mpint d (private exponent) + // mpint p (prime 1) + // mpint q (prime 2) + // mpint iqmp ([inverse of q] mod p) + // for "ssh-dss": + // mpint x (private key parameter) + // m[6] = SHA1 HMAC over: + // string name of algorithm ("ssh-dss", "ssh-rsa") + // string encryption type + // string comment + // string public key data + // string private-plaintext (including the final padding) + const cipherName = m[2]; + const encrypted = (cipherName !== 'none'); + if (encrypted && !passphrase) { + return new Error( + 'Encrypted PPK private key detected, but no passphrase given' + ); + } + + let privBlob = Buffer.from(m[5], 'base64'); + + if (encrypted) { + const encInfo = CIPHER_INFO[cipherName]; + let cipherKey = combineBuffers( + createHash('sha1').update(PPK_PP1).update(passphrase).digest(), + createHash('sha1').update(PPK_PP2).update(passphrase).digest() + ); + if (cipherKey.length > encInfo.keyLen) + cipherKey = bufferSlice(cipherKey, 0, encInfo.keyLen); + try { + const decipher = createDecipheriv(encInfo.sslName, cipherKey, PPK_IV); + decipher.setAutoPadding(false); + privBlob = combineBuffers(decipher.update(privBlob), + decipher.final()); + } catch (ex) { + return ex; + } + } + + const type = m[1]; + const comment = m[3]; + const pubBlob = Buffer.from(m[4], 'base64'); + + const mac = m[6]; + const typeLen = type.length; + const cipherNameLen = cipherName.length; + const commentLen = Buffer.byteLength(comment); + const pubLen = pubBlob.length; + const privLen = privBlob.length; + const macData = Buffer.allocUnsafe(4 + typeLen + + 4 + cipherNameLen + + 4 + commentLen + + 4 + pubLen + + 4 + privLen); + let p = 0; + + writeUInt32BE(macData, typeLen, p); + macData.utf8Write(type, p += 4, typeLen); + writeUInt32BE(macData, cipherNameLen, p += typeLen); + macData.utf8Write(cipherName, p += 4, cipherNameLen); + writeUInt32BE(macData, commentLen, p += cipherNameLen); + macData.utf8Write(comment, p += 4, commentLen); + writeUInt32BE(macData, pubLen, p += commentLen); + macData.set(pubBlob, p += 4); + writeUInt32BE(macData, privLen, p += pubLen); + macData.set(privBlob, p + 4); + + if (!passphrase) + passphrase = EMPTY_PASSPHRASE; + + const calcMAC = createHmac( + 'sha1', + createHash('sha1') + .update('putty-private-key-file-mac-key') + .update(passphrase) + .digest() + ).update(macData).digest('hex'); + + if (calcMAC !== mac) { + if (encrypted) { + return new Error( + 'PPK private key integrity check failed -- bad passphrase?' + ); + } + return new Error('PPK private key integrity check failed'); + } + + let pubPEM; + let pubSSH; + let privPEM; + pubBlob._pos = 0; + skipFields(pubBlob, 1); // skip (duplicate) key type + switch (type) { + case 'ssh-rsa': { + const e = readString(pubBlob, pubBlob._pos); + if (e === undefined) + return new Error('Malformed PPK public key'); + const n = readString(pubBlob, pubBlob._pos); + if (n === undefined) + return new Error('Malformed PPK public key'); + const d = readString(privBlob, 0); + if (d === undefined) + return new Error('Malformed PPK private key'); + const p = readString(privBlob, privBlob._pos); + if (p === undefined) + return new Error('Malformed PPK private key'); + const q = readString(privBlob, privBlob._pos); + if (q === undefined) + return new Error('Malformed PPK private key'); + const iqmp = readString(privBlob, privBlob._pos); + if (iqmp === undefined) + return new Error('Malformed PPK private key'); + pubPEM = genOpenSSLRSAPub(n, e); + pubSSH = genOpenSSHRSAPub(n, e); + privPEM = genOpenSSLRSAPriv(n, e, d, iqmp, p, q); + break; + } + case 'ssh-dss': { + const p = readString(pubBlob, pubBlob._pos); + if (p === undefined) + return new Error('Malformed PPK public key'); + const q = readString(pubBlob, pubBlob._pos); + if (q === undefined) + return new Error('Malformed PPK public key'); + const g = readString(pubBlob, pubBlob._pos); + if (g === undefined) + return new Error('Malformed PPK public key'); + const y = readString(pubBlob, pubBlob._pos); + if (y === undefined) + return new Error('Malformed PPK public key'); + const x = readString(privBlob, 0); + if (x === undefined) + return new Error('Malformed PPK private key'); + + pubPEM = genOpenSSLDSAPub(p, q, g, y); + pubSSH = genOpenSSHDSAPub(p, q, g, y); + privPEM = genOpenSSLDSAPriv(p, q, g, y, x); + break; + } + } + + return new PPK_Private(type, comment, privPEM, pubPEM, pubSSH, 'sha1', + encrypted); + }; +} + + +function OpenSSH_Public(type, comment, pubPEM, pubSSH, algo) { + this.type = type; + this.comment = comment; + this[SYM_PRIV_PEM] = null; + this[SYM_PUB_PEM] = pubPEM; + this[SYM_PUB_SSH] = pubSSH; + this[SYM_HASH_ALGO] = algo; + this[SYM_DECRYPTED] = false; +} +OpenSSH_Public.prototype = BaseKey; +{ + let regexp; + if (eddsaSupported) + regexp = /^(((?:ssh-(?:rsa|dss|ed25519))|ecdsa-sha2-nistp(?:256|384|521))(?:-cert-v0[01]@openssh.com)?) ([A-Z0-9a-z/+=]+)(?:$|\s+([\S].*)?)$/; + else + regexp = /^(((?:ssh-(?:rsa|dss))|ecdsa-sha2-nistp(?:256|384|521))(?:-cert-v0[01]@openssh.com)?) ([A-Z0-9a-z/+=]+)(?:$|\s+([\S].*)?)$/; + OpenSSH_Public.parse = (str) => { + const m = regexp.exec(str); + if (m === null) + return null; + // m[1] = full type + // m[2] = base type + // m[3] = base64-encoded public key + // m[4] = comment + + const fullType = m[1]; + const baseType = m[2]; + const data = Buffer.from(m[3], 'base64'); + const comment = (m[4] || ''); + + const type = readString(data, data._pos, true); + if (type === undefined || type.indexOf(baseType) !== 0) + return new Error('Malformed OpenSSH public key'); + + return parseDER(data, baseType, comment, fullType); + }; +} + + +function RFC4716_Public(type, comment, pubPEM, pubSSH, algo) { + this.type = type; + this.comment = comment; + this[SYM_PRIV_PEM] = null; + this[SYM_PUB_PEM] = pubPEM; + this[SYM_PUB_SSH] = pubSSH; + this[SYM_HASH_ALGO] = algo; + this[SYM_DECRYPTED] = false; +} +RFC4716_Public.prototype = BaseKey; +{ + const regexp = /^---- BEGIN SSH2 PUBLIC KEY ----(?:\r?\n)((?:.{0,72}\r?\n)+)---- END SSH2 PUBLIC KEY ----$/; + const RE_DATA = /^[A-Z0-9a-z/+=\r\n]+$/; + const RE_HEADER = /^([\x21-\x39\x3B-\x7E]{1,64}): ((?:[^\\]*\\\r?\n)*[^\r\n]+)\r?\n/gm; + const RE_HEADER_ENDS = /\\\r?\n/g; + RFC4716_Public.parse = (str) => { + let m = regexp.exec(str); + if (m === null) + return null; + + const body = m[1]; + let dataStart = 0; + let comment = ''; + + while (m = RE_HEADER.exec(body)) { + const headerName = m[1]; + const headerValue = m[2].replace(RE_HEADER_ENDS, ''); + if (headerValue.length > 1024) { + RE_HEADER.lastIndex = 0; + return new Error('Malformed RFC4716 public key'); + } + + dataStart = RE_HEADER.lastIndex; + + if (headerName.toLowerCase() === 'comment') { + comment = headerValue; + if (comment.length > 1 + && comment.charCodeAt(0) === 34/* '"' */ + && comment.charCodeAt(comment.length - 1) === 34/* '"' */) { + comment = comment.slice(1, -1); + } + } + } + + let data = body.slice(dataStart); + if (!RE_DATA.test(data)) + return new Error('Malformed RFC4716 public key'); + + data = Buffer.from(data, 'base64'); + + const type = readString(data, 0, true); + if (type === undefined) + return new Error('Malformed RFC4716 public key'); + + let pubPEM = null; + let pubSSH = null; + switch (type) { + case 'ssh-rsa': { + const e = readString(data, data._pos); + if (e === undefined) + return new Error('Malformed RFC4716 public key'); + const n = readString(data, data._pos); + if (n === undefined) + return new Error('Malformed RFC4716 public key'); + pubPEM = genOpenSSLRSAPub(n, e); + pubSSH = genOpenSSHRSAPub(n, e); + break; + } + case 'ssh-dss': { + const p = readString(data, data._pos); + if (p === undefined) + return new Error('Malformed RFC4716 public key'); + const q = readString(data, data._pos); + if (q === undefined) + return new Error('Malformed RFC4716 public key'); + const g = readString(data, data._pos); + if (g === undefined) + return new Error('Malformed RFC4716 public key'); + const y = readString(data, data._pos); + if (y === undefined) + return new Error('Malformed RFC4716 public key'); + pubPEM = genOpenSSLDSAPub(p, q, g, y); + pubSSH = genOpenSSHDSAPub(p, q, g, y); + break; + } + default: + return new Error('Malformed RFC4716 public key'); + } + + return new RFC4716_Public(type, comment, pubPEM, pubSSH, 'sha1'); + }; +} + + +function parseDER(data, baseType, comment, fullType) { + if (!isSupportedKeyType(baseType)) + return new Error(`Unsupported OpenSSH public key type: ${baseType}`); + + let algo; + let oid; + let pubPEM = null; + let pubSSH = null; + + switch (baseType) { + case 'ssh-rsa': { + const e = readString(data, data._pos || 0); + if (e === undefined) + return new Error('Malformed OpenSSH public key'); + const n = readString(data, data._pos); + if (n === undefined) + return new Error('Malformed OpenSSH public key'); + pubPEM = genOpenSSLRSAPub(n, e); + pubSSH = genOpenSSHRSAPub(n, e); + algo = 'sha1'; + break; + } + case 'ssh-dss': { + const p = readString(data, data._pos || 0); + if (p === undefined) + return new Error('Malformed OpenSSH public key'); + const q = readString(data, data._pos); + if (q === undefined) + return new Error('Malformed OpenSSH public key'); + const g = readString(data, data._pos); + if (g === undefined) + return new Error('Malformed OpenSSH public key'); + const y = readString(data, data._pos); + if (y === undefined) + return new Error('Malformed OpenSSH public key'); + pubPEM = genOpenSSLDSAPub(p, q, g, y); + pubSSH = genOpenSSHDSAPub(p, q, g, y); + algo = 'sha1'; + break; + } + case 'ssh-ed25519': { + const edpub = readString(data, data._pos || 0); + if (edpub === undefined || edpub.length !== 32) + return new Error('Malformed OpenSSH public key'); + pubPEM = genOpenSSLEdPub(edpub); + pubSSH = genOpenSSHEdPub(edpub); + algo = null; + break; + } + case 'ecdsa-sha2-nistp256': + algo = 'sha256'; + oid = '1.2.840.10045.3.1.7'; + // FALLTHROUGH + case 'ecdsa-sha2-nistp384': + if (algo === undefined) { + algo = 'sha384'; + oid = '1.3.132.0.34'; + } + // FALLTHROUGH + case 'ecdsa-sha2-nistp521': { + if (algo === undefined) { + algo = 'sha512'; + oid = '1.3.132.0.35'; + } + // TODO: validate curve name against type + if (!skipFields(data, 1)) // Skip curve name + return new Error('Malformed OpenSSH public key'); + const ecpub = readString(data, data._pos || 0); + if (ecpub === undefined) + return new Error('Malformed OpenSSH public key'); + pubPEM = genOpenSSLECDSAPub(oid, ecpub); + pubSSH = genOpenSSHECDSAPub(oid, ecpub); + break; + } + default: + return new Error(`Unsupported OpenSSH public key type: ${baseType}`); + } + + return new OpenSSH_Public(fullType, comment, pubPEM, pubSSH, algo); +} + +function isSupportedKeyType(type) { + switch (type) { + case 'ssh-rsa': + case 'ssh-dss': + case 'ecdsa-sha2-nistp256': + case 'ecdsa-sha2-nistp384': + case 'ecdsa-sha2-nistp521': + return true; + case 'ssh-ed25519': + if (eddsaSupported) + return true; + // FALLTHROUGH + default: + return false; + } +} + +function isParsedKey(val) { + if (!val) + return false; + return (typeof val[SYM_DECRYPTED] === 'boolean'); +} + +function parseKey(data, passphrase) { + if (isParsedKey(data)) + return data; + + let origBuffer; + if (Buffer.isBuffer(data)) { + origBuffer = data; + data = data.utf8Slice(0, data.length).trim(); + } else if (typeof data === 'string') { + data = data.trim(); + } else { + return new Error('Key data must be a Buffer or string'); + } + + // eslint-disable-next-line eqeqeq + if (passphrase != undefined) { + if (typeof passphrase === 'string') + passphrase = Buffer.from(passphrase); + else if (!Buffer.isBuffer(passphrase)) + return new Error('Passphrase must be a string or Buffer when supplied'); + } + + let ret; + + // First try as printable string format (e.g. PEM) + + // Private keys + if ((ret = OpenSSH_Private.parse(data, passphrase)) !== null) + return ret; + if ((ret = OpenSSH_Old_Private.parse(data, passphrase)) !== null) + return ret; + if ((ret = PPK_Private.parse(data, passphrase)) !== null) + return ret; + + // Public keys + if ((ret = OpenSSH_Public.parse(data)) !== null) + return ret; + if ((ret = RFC4716_Public.parse(data)) !== null) + return ret; + + // Finally try as a binary format if we were originally passed binary data + if (origBuffer) { + binaryKeyParser.init(origBuffer, 0); + const type = binaryKeyParser.readString(true); + if (type !== undefined) { + data = binaryKeyParser.readRaw(); + if (data !== undefined) { + ret = parseDER(data, type, '', type); + // Ignore potentially useless errors in case the data was not actually + // in the binary format + if (ret instanceof Error) + ret = null; + } + } + binaryKeyParser.clear(); + } + + if (ret) + return ret; + + return new Error('Unsupported key format'); +} + +module.exports = { + isParsedKey, + isSupportedKeyType, + parseDERKey: (data, type) => parseDER(data, type, '', type), + parseKey, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/node-fs-compat.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/node-fs-compat.js new file mode 100644 index 0000000..80ed71f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/node-fs-compat.js @@ -0,0 +1,115 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +// Only use this for integers! Decimal numbers do not work with this function. +function addNumericalSeparator(val) { + let res = ''; + let i = val.length; + const start = val[0] === '-' ? 1 : 0; + for (; i >= start + 4; i -= 3) + res = `_${val.slice(i - 3, i)}${res}`; + return `${val.slice(0, i)}${res}`; +} + +function oneOf(expected, thing) { + assert(typeof thing === 'string', '`thing` has to be of type string'); + if (Array.isArray(expected)) { + const len = expected.length; + assert(len > 0, 'At least one expected value needs to be specified'); + expected = expected.map((i) => String(i)); + if (len > 2) { + return `one of ${thing} ${expected.slice(0, len - 1).join(', ')}, or ` + + expected[len - 1]; + } else if (len === 2) { + return `one of ${thing} ${expected[0]} or ${expected[1]}`; + } + return `of ${thing} ${expected[0]}`; + } + return `of ${thing} ${String(expected)}`; +} + + +exports.ERR_INTERNAL_ASSERTION = class ERR_INTERNAL_ASSERTION extends Error { + constructor(message) { + super(); + Error.captureStackTrace(this, ERR_INTERNAL_ASSERTION); + + const suffix = 'This is caused by either a bug in ssh2 ' + + 'or incorrect usage of ssh2 internals.\n' + + 'Please open an issue with this stack trace at ' + + 'https://github.com/mscdex/ssh2/issues\n'; + + this.message = (message === undefined ? suffix : `${message}\n${suffix}`); + } +}; + +const MAX_32BIT_INT = 2 ** 32; +const MAX_32BIT_BIGINT = (() => { + try { + return new Function('return 2n ** 32n')(); + } catch {} +})(); +exports.ERR_OUT_OF_RANGE = class ERR_OUT_OF_RANGE extends RangeError { + constructor(str, range, input, replaceDefaultBoolean) { + super(); + Error.captureStackTrace(this, ERR_OUT_OF_RANGE); + + assert(range, 'Missing "range" argument'); + let msg = (replaceDefaultBoolean + ? str + : `The value of "${str}" is out of range.`); + let received; + if (Number.isInteger(input) && Math.abs(input) > MAX_32BIT_INT) { + received = addNumericalSeparator(String(input)); + } else if (typeof input === 'bigint') { + received = String(input); + if (input > MAX_32BIT_BIGINT || input < -MAX_32BIT_BIGINT) + received = addNumericalSeparator(received); + received += 'n'; + } else { + received = inspect(input); + } + msg += ` It must be ${range}. Received ${received}`; + + this.message = msg; + } +}; + +class ERR_INVALID_ARG_TYPE extends TypeError { + constructor(name, expected, actual) { + super(); + Error.captureStackTrace(this, ERR_INVALID_ARG_TYPE); + + assert(typeof name === 'string', `'name' must be a string`); + + // determiner: 'must be' or 'must not be' + let determiner; + if (typeof expected === 'string' && expected.startsWith('not ')) { + determiner = 'must not be'; + expected = expected.replace(/^not /, ''); + } else { + determiner = 'must be'; + } + + let msg; + if (name.endsWith(' argument')) { + // For cases like 'first argument' + msg = `The ${name} ${determiner} ${oneOf(expected, 'type')}`; + } else { + const type = (name.includes('.') ? 'property' : 'argument'); + msg = `The "${name}" ${type} ${determiner} ${oneOf(expected, 'type')}`; + } + + msg += `. Received type ${typeof actual}`; + + this.message = msg; + } +} +exports.ERR_INVALID_ARG_TYPE = ERR_INVALID_ARG_TYPE; + +exports.validateNumber = function validateNumber(value, name) { + if (typeof value !== 'number') + throw new ERR_INVALID_ARG_TYPE(name, 'number', value); +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/utils.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/utils.js new file mode 100644 index 0000000..26f4cab --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/utils.js @@ -0,0 +1,356 @@ +'use strict'; + +const Ber = require('asn1').Ber; + +let DISCONNECT_REASON; + +const FastBuffer = Buffer[Symbol.species]; +const TypedArrayFill = Object.getPrototypeOf(Uint8Array.prototype).fill; + +function readUInt32BE(buf, offset) { + return (buf[offset++] * 16777216) + + (buf[offset++] * 65536) + + (buf[offset++] * 256) + + buf[offset]; +} + +function bufferCopy(src, dest, srcStart, srcEnd, destStart) { + if (!destStart) + destStart = 0; + if (srcEnd > src.length) + srcEnd = src.length; + let nb = srcEnd - srcStart; + const destLeft = (dest.length - destStart); + if (nb > destLeft) + nb = destLeft; + dest.set(new Uint8Array(src.buffer, src.byteOffset + srcStart, nb), + destStart); + return nb; +} + +function bufferSlice(buf, start, end) { + if (end === undefined) + end = buf.length; + return new FastBuffer(buf.buffer, buf.byteOffset + start, end - start); +} + +function makeBufferParser() { + let pos = 0; + let buffer; + + const self = { + init: (buf, start) => { + buffer = buf; + pos = (typeof start === 'number' ? start : 0); + }, + pos: () => pos, + length: () => (buffer ? buffer.length : 0), + avail: () => (buffer && pos < buffer.length ? buffer.length - pos : 0), + clear: () => { + buffer = undefined; + }, + readUInt32BE: () => { + if (!buffer || pos + 3 >= buffer.length) + return; + return (buffer[pos++] * 16777216) + + (buffer[pos++] * 65536) + + (buffer[pos++] * 256) + + buffer[pos++]; + }, + readUInt64BE: (behavior) => { + if (!buffer || pos + 7 >= buffer.length) + return; + switch (behavior) { + case 'always': + return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`); + case 'maybe': + if (buffer[pos] > 0x1F) + return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`); + // FALLTHROUGH + default: + return (buffer[pos++] * 72057594037927940) + + (buffer[pos++] * 281474976710656) + + (buffer[pos++] * 1099511627776) + + (buffer[pos++] * 4294967296) + + (buffer[pos++] * 16777216) + + (buffer[pos++] * 65536) + + (buffer[pos++] * 256) + + buffer[pos++]; + } + }, + skip: (n) => { + if (buffer && n > 0) + pos += n; + }, + skipString: () => { + const len = self.readUInt32BE(); + if (len === undefined) + return; + pos += len; + return (pos <= buffer.length ? len : undefined); + }, + readByte: () => { + if (buffer && pos < buffer.length) + return buffer[pos++]; + }, + readBool: () => { + if (buffer && pos < buffer.length) + return !!buffer[pos++]; + }, + readList: () => { + const list = self.readString(true); + if (list === undefined) + return; + return (list ? list.split(',') : []); + }, + readString: (dest, maxLen) => { + if (typeof dest === 'number') { + maxLen = dest; + dest = undefined; + } + + const len = self.readUInt32BE(); + if (len === undefined) + return; + + if ((buffer.length - pos) < len + || (typeof maxLen === 'number' && len > maxLen)) { + return; + } + + if (dest) { + if (Buffer.isBuffer(dest)) + return bufferCopy(buffer, dest, pos, pos += len); + return buffer.utf8Slice(pos, pos += len); + } + return bufferSlice(buffer, pos, pos += len); + }, + readRaw: (len) => { + if (!buffer) + return; + if (typeof len !== 'number') + return bufferSlice(buffer, pos, pos += (buffer.length - pos)); + if ((buffer.length - pos) >= len) + return bufferSlice(buffer, pos, pos += len); + }, + }; + + return self; +} + +function makeError(msg, level, fatal) { + const err = new Error(msg); + if (typeof level === 'boolean') { + fatal = level; + err.level = 'protocol'; + } else { + err.level = level || 'protocol'; + } + err.fatal = !!fatal; + return err; +} + +function writeUInt32BE(buf, value, offset) { + buf[offset++] = (value >>> 24); + buf[offset++] = (value >>> 16); + buf[offset++] = (value >>> 8); + buf[offset++] = value; + return offset; +} + +const utilBufferParser = makeBufferParser(); + +module.exports = { + bufferCopy, + bufferSlice, + FastBuffer, + bufferFill: (buf, value, start, end) => { + return TypedArrayFill.call(buf, value, start, end); + }, + makeError, + doFatalError: (protocol, msg, level, reason) => { + let err; + if (DISCONNECT_REASON === undefined) + ({ DISCONNECT_REASON } = require('./constants.js')); + if (msg instanceof Error) { + // doFatalError(protocol, err[, reason]) + err = msg; + if (typeof level !== 'number') + reason = DISCONNECT_REASON.PROTOCOL_ERROR; + else + reason = level; + } else { + // doFatalError(protocol, msg[, level[, reason]]) + err = makeError(msg, level, true); + } + if (typeof reason !== 'number') + reason = DISCONNECT_REASON.PROTOCOL_ERROR; + protocol.disconnect(reason); + protocol._destruct(); + protocol._onError(err); + return Infinity; + }, + readUInt32BE, + writeUInt32BE, + writeUInt32LE: (buf, value, offset) => { + buf[offset++] = value; + buf[offset++] = (value >>> 8); + buf[offset++] = (value >>> 16); + buf[offset++] = (value >>> 24); + return offset; + }, + makeBufferParser, + bufferParser: makeBufferParser(), + readString: (buffer, start, dest, maxLen) => { + if (typeof dest === 'number') { + maxLen = dest; + dest = undefined; + } + + if (start === undefined) + start = 0; + + const left = (buffer.length - start); + if (start < 0 || start >= buffer.length || left < 4) + return; + + const len = readUInt32BE(buffer, start); + if (left < (4 + len) || (typeof maxLen === 'number' && len > maxLen)) + return; + + start += 4; + const end = start + len; + buffer._pos = end; + + if (dest) { + if (Buffer.isBuffer(dest)) + return bufferCopy(buffer, dest, start, end); + return buffer.utf8Slice(start, end); + } + return bufferSlice(buffer, start, end); + }, + sigSSHToASN1: (sig, type) => { + switch (type) { + case 'ssh-dss': { + if (sig.length > 40) + return sig; + // Change bare signature r and s values to ASN.1 BER values for OpenSSL + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + let r = sig.slice(0, 20); + let s = sig.slice(20); + if (r[0] & 0x80) { + const rNew = Buffer.allocUnsafe(21); + rNew[0] = 0x00; + r.copy(rNew, 1); + r = rNew; + } else if (r[0] === 0x00 && !(r[1] & 0x80)) { + r = r.slice(1); + } + if (s[0] & 0x80) { + const sNew = Buffer.allocUnsafe(21); + sNew[0] = 0x00; + s.copy(sNew, 1); + s = sNew; + } else if (s[0] === 0x00 && !(s[1] & 0x80)) { + s = s.slice(1); + } + asnWriter.writeBuffer(r, Ber.Integer); + asnWriter.writeBuffer(s, Ber.Integer); + asnWriter.endSequence(); + return asnWriter.buffer; + } + case 'ecdsa-sha2-nistp256': + case 'ecdsa-sha2-nistp384': + case 'ecdsa-sha2-nistp521': { + utilBufferParser.init(sig, 0); + const r = utilBufferParser.readString(); + const s = utilBufferParser.readString(); + utilBufferParser.clear(); + if (r === undefined || s === undefined) + return; + + const asnWriter = new Ber.Writer(); + asnWriter.startSequence(); + asnWriter.writeBuffer(r, Ber.Integer); + asnWriter.writeBuffer(s, Ber.Integer); + asnWriter.endSequence(); + return asnWriter.buffer; + } + default: + return sig; + } + }, + convertSignature: (signature, keyType) => { + switch (keyType) { + case 'ssh-dss': { + if (signature.length <= 40) + return signature; + // This is a quick and dirty way to get from BER encoded r and s that + // OpenSSL gives us, to just the bare values back to back (40 bytes + // total) like OpenSSH (and possibly others) are expecting + const asnReader = new Ber.Reader(signature); + asnReader.readSequence(); + let r = asnReader.readString(Ber.Integer, true); + let s = asnReader.readString(Ber.Integer, true); + let rOffset = 0; + let sOffset = 0; + if (r.length < 20) { + const rNew = Buffer.allocUnsafe(20); + rNew.set(r, 1); + r = rNew; + r[0] = 0; + } + if (s.length < 20) { + const sNew = Buffer.allocUnsafe(20); + sNew.set(s, 1); + s = sNew; + s[0] = 0; + } + if (r.length > 20 && r[0] === 0) + rOffset = 1; + if (s.length > 20 && s[0] === 0) + sOffset = 1; + const newSig = + Buffer.allocUnsafe((r.length - rOffset) + (s.length - sOffset)); + bufferCopy(r, newSig, rOffset, r.length, 0); + bufferCopy(s, newSig, sOffset, s.length, r.length - rOffset); + return newSig; + } + case 'ecdsa-sha2-nistp256': + case 'ecdsa-sha2-nistp384': + case 'ecdsa-sha2-nistp521': { + if (signature[0] === 0) + return signature; + // Convert SSH signature parameters to ASN.1 BER values for OpenSSL + const asnReader = new Ber.Reader(signature); + asnReader.readSequence(); + const r = asnReader.readString(Ber.Integer, true); + const s = asnReader.readString(Ber.Integer, true); + if (r === null || s === null) + return; + const newSig = Buffer.allocUnsafe(4 + r.length + 4 + s.length); + writeUInt32BE(newSig, r.length, 0); + newSig.set(r, 4); + writeUInt32BE(newSig, s.length, 4 + r.length); + newSig.set(s, 4 + 4 + r.length); + return newSig; + } + } + + return signature; + }, + sendPacket: (proto, packet, bypass) => { + if (!bypass && proto._kexinit !== undefined) { + // We're currently in the middle of a handshake + + if (proto._queue === undefined) + proto._queue = []; + proto._queue.push(packet); + proto._debug && proto._debug('Outbound: ... packet queued'); + return false; + } + proto._cipher.encrypt(packet); + return true; + }, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/zlib.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/zlib.js new file mode 100644 index 0000000..f68319a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/protocol/zlib.js @@ -0,0 +1,255 @@ +'use strict'; + +const { kMaxLength } = require('buffer'); +const { + createInflate, + constants: { + DEFLATE, + INFLATE, + Z_DEFAULT_CHUNK, + Z_DEFAULT_COMPRESSION, + Z_DEFAULT_MEMLEVEL, + Z_DEFAULT_STRATEGY, + Z_DEFAULT_WINDOWBITS, + Z_PARTIAL_FLUSH, + } +} = require('zlib'); +const ZlibHandle = createInflate()._handle.constructor; + +function processCallback() { + throw new Error('Should not get here'); +} + +function zlibOnError(message, errno, code) { + const self = this._owner; + // There is no way to cleanly recover. + // Continuing only obscures problems. + + const error = new Error(message); + error.errno = errno; + error.code = code; + self._err = error; +} + +function _close(engine) { + // Caller may invoke .close after a zlib error (which will null _handle). + if (!engine._handle) + return; + + engine._handle.close(); + engine._handle = null; +} + +class Zlib { + constructor(mode) { + const windowBits = Z_DEFAULT_WINDOWBITS; + const level = Z_DEFAULT_COMPRESSION; + const memLevel = Z_DEFAULT_MEMLEVEL; + const strategy = Z_DEFAULT_STRATEGY; + const dictionary = undefined; + + this._err = undefined; + this._writeState = new Uint32Array(2); + this._chunkSize = Z_DEFAULT_CHUNK; + this._maxOutputLength = kMaxLength; + this._outBuffer = Buffer.allocUnsafe(this._chunkSize); + this._outOffset = 0; + + this._handle = new ZlibHandle(mode); + this._handle._owner = this; + this._handle.onerror = zlibOnError; + this._handle.init(windowBits, + level, + memLevel, + strategy, + this._writeState, + processCallback, + dictionary); + } + + writeSync(chunk, retChunks) { + const handle = this._handle; + if (!handle) + throw new Error('Invalid Zlib instance'); + + let availInBefore = chunk.length; + let availOutBefore = this._chunkSize - this._outOffset; + let inOff = 0; + let availOutAfter; + let availInAfter; + + let buffers; + let nread = 0; + const state = this._writeState; + let buffer = this._outBuffer; + let offset = this._outOffset; + const chunkSize = this._chunkSize; + + while (true) { + handle.writeSync(Z_PARTIAL_FLUSH, + chunk, // in + inOff, // in_off + availInBefore, // in_len + buffer, // out + offset, // out_off + availOutBefore); // out_len + if (this._err) + throw this._err; + + availOutAfter = state[0]; + availInAfter = state[1]; + + const inDelta = availInBefore - availInAfter; + const have = availOutBefore - availOutAfter; + + if (have > 0) { + const out = (offset === 0 && have === buffer.length + ? buffer + : buffer.slice(offset, offset + have)); + offset += have; + if (!buffers) + buffers = out; + else if (buffers.push === undefined) + buffers = [buffers, out]; + else + buffers.push(out); + nread += out.byteLength; + + if (nread > this._maxOutputLength) { + _close(this); + throw new Error( + `Output length exceeded maximum of ${this._maxOutputLength}` + ); + } + } else if (have !== 0) { + throw new Error('have should not go down'); + } + + // Exhausted the output buffer, or used all the input create a new one. + if (availOutAfter === 0 || offset >= chunkSize) { + availOutBefore = chunkSize; + offset = 0; + buffer = Buffer.allocUnsafe(chunkSize); + } + + if (availOutAfter === 0) { + // Not actually done. Need to reprocess. + // Also, update the availInBefore to the availInAfter value, + // so that if we have to hit it a third (fourth, etc.) time, + // it'll have the correct byte counts. + inOff += inDelta; + availInBefore = availInAfter; + } else { + break; + } + } + + this._outBuffer = buffer; + this._outOffset = offset; + + if (nread === 0) + buffers = Buffer.alloc(0); + + if (retChunks) { + buffers.totalLen = nread; + return buffers; + } + + if (buffers.push === undefined) + return buffers; + + const output = Buffer.allocUnsafe(nread); + for (let i = 0, p = 0; i < buffers.length; ++i) { + const buf = buffers[i]; + output.set(buf, p); + p += buf.length; + } + return output; + } +} + +class ZlibPacketWriter { + constructor(protocol) { + this.allocStart = 0; + this.allocStartKEX = 0; + this._protocol = protocol; + this._zlib = new Zlib(DEFLATE); + } + + cleanup() { + if (this._zlib) + _close(this._zlib); + } + + alloc(payloadSize, force) { + return Buffer.allocUnsafe(payloadSize); + } + + finalize(payload, force) { + if (this._protocol._kexinit === undefined || force) { + const output = this._zlib.writeSync(payload, true); + const packet = this._protocol._cipher.allocPacket(output.totalLen); + if (output.push === undefined) { + packet.set(output, 5); + } else { + for (let i = 0, p = 5; i < output.length; ++i) { + const chunk = output[i]; + packet.set(chunk, p); + p += chunk.length; + } + } + return packet; + } + return payload; + } +} + +class PacketWriter { + constructor(protocol) { + this.allocStart = 5; + this.allocStartKEX = 5; + this._protocol = protocol; + } + + cleanup() {} + + alloc(payloadSize, force) { + if (this._protocol._kexinit === undefined || force) + return this._protocol._cipher.allocPacket(payloadSize); + return Buffer.allocUnsafe(payloadSize); + } + + finalize(packet, force) { + return packet; + } +} + +class ZlibPacketReader { + constructor() { + this._zlib = new Zlib(INFLATE); + } + + cleanup() { + if (this._zlib) + _close(this._zlib); + } + + read(data) { + return this._zlib.writeSync(data, false); + } +} + +class PacketReader { + cleanup() {} + + read(data) { + return data; + } +} + +module.exports = { + PacketReader, + PacketWriter, + ZlibPacketReader, + ZlibPacketWriter, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/server.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/server.js new file mode 100644 index 0000000..306d658 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/server.js @@ -0,0 +1,1380 @@ +// TODO: +// * convert listenerCount() usage to emit() return value checking? +// * emit error when connection severed early (e.g. before handshake) +// * add '.connected' or similar property to connection objects to allow +// immediate connection status checking +'use strict'; + +const { Server: netServer } = require('net'); +const EventEmitter = require('events'); +const { listenerCount } = EventEmitter; + +const { + CHANNEL_OPEN_FAILURE, + DEFAULT_CIPHER, + DEFAULT_COMPRESSION, + DEFAULT_KEX, + DEFAULT_MAC, + DEFAULT_SERVER_HOST_KEY, + DISCONNECT_REASON, + DISCONNECT_REASON_BY_VALUE, + SUPPORTED_CIPHER, + SUPPORTED_COMPRESSION, + SUPPORTED_KEX, + SUPPORTED_MAC, + SUPPORTED_SERVER_HOST_KEY, +} = require('./protocol/constants.js'); +const { init: cryptoInit } = require('./protocol/crypto.js'); +const { KexInit } = require('./protocol/kex.js'); +const { parseKey } = require('./protocol/keyParser.js'); +const Protocol = require('./protocol/Protocol.js'); +const { SFTP } = require('./protocol/SFTP.js'); +const { writeUInt32BE } = require('./protocol/utils.js'); + +const { + Channel, + MAX_WINDOW, + PACKET_SIZE, + windowAdjust, + WINDOW_THRESHOLD, +} = require('./Channel.js'); + +const { + ChannelManager, + generateAlgorithmList, + isWritable, + onChannelOpenFailure, + onCHANNEL_CLOSE, +} = require('./utils.js'); + +const MAX_PENDING_AUTHS = 10; + +class AuthContext extends EventEmitter { + constructor(protocol, username, service, method, cb) { + super(); + + this.username = this.user = username; + this.service = service; + this.method = method; + this._initialResponse = false; + this._finalResponse = false; + this._multistep = false; + this._cbfinal = (allowed, methodsLeft, isPartial) => { + if (!this._finalResponse) { + this._finalResponse = true; + cb(this, allowed, methodsLeft, isPartial); + } + }; + this._protocol = protocol; + } + + accept() { + this._cleanup && this._cleanup(); + this._initialResponse = true; + this._cbfinal(true); + } + reject(methodsLeft, isPartial) { + this._cleanup && this._cleanup(); + this._initialResponse = true; + this._cbfinal(false, methodsLeft, isPartial); + } +} + + +class KeyboardAuthContext extends AuthContext { + constructor(protocol, username, service, method, submethods, cb) { + super(protocol, username, service, method, cb); + + this._multistep = true; + + this._cb = undefined; + this._onInfoResponse = (responses) => { + const callback = this._cb; + if (callback) { + this._cb = undefined; + callback(responses); + } + }; + this.submethods = submethods; + this.on('abort', () => { + this._cb && this._cb(new Error('Authentication request aborted')); + }); + } + + prompt(prompts, title, instructions, cb) { + if (!Array.isArray(prompts)) + prompts = [ prompts ]; + + if (typeof title === 'function') { + cb = title; + title = instructions = undefined; + } else if (typeof instructions === 'function') { + cb = instructions; + instructions = undefined; + } else if (typeof cb !== 'function') { + cb = undefined; + } + + for (let i = 0; i < prompts.length; ++i) { + if (typeof prompts[i] === 'string') { + prompts[i] = { + prompt: prompts[i], + echo: true + }; + } + } + + this._cb = cb; + this._initialResponse = true; + + this._protocol.authInfoReq(title, instructions, prompts); + } +} + +class PKAuthContext extends AuthContext { + constructor(protocol, username, service, method, pkInfo, cb) { + super(protocol, username, service, method, cb); + + this.key = { algo: pkInfo.keyAlgo, data: pkInfo.key }; + this.hashAlgo = pkInfo.hashAlgo; + this.signature = pkInfo.signature; + this.blob = pkInfo.blob; + } + + accept() { + if (!this.signature) { + this._initialResponse = true; + this._protocol.authPKOK(this.key.algo, this.key.data); + } else { + AuthContext.prototype.accept.call(this); + } + } +} + +class HostbasedAuthContext extends AuthContext { + constructor(protocol, username, service, method, pkInfo, cb) { + super(protocol, username, service, method, cb); + + this.key = { algo: pkInfo.keyAlgo, data: pkInfo.key }; + this.hashAlgo = pkInfo.hashAlgo; + this.signature = pkInfo.signature; + this.blob = pkInfo.blob; + this.localHostname = pkInfo.localHostname; + this.localUsername = pkInfo.localUsername; + } +} + +class PwdAuthContext extends AuthContext { + constructor(protocol, username, service, method, password, cb) { + super(protocol, username, service, method, cb); + + this.password = password; + this._changeCb = undefined; + } + + requestChange(prompt, cb) { + if (this._changeCb) + throw new Error('Change request already in progress'); + if (typeof prompt !== 'string') + throw new Error('prompt argument must be a string'); + if (typeof cb !== 'function') + throw new Error('Callback argument must be a function'); + this._changeCb = cb; + this._protocol.authPasswdChg(prompt); + } +} + + +class Session extends EventEmitter { + constructor(client, info, localChan) { + super(); + + this.type = 'session'; + this.subtype = undefined; + this.server = true; + this._ending = false; + this._channel = undefined; + this._chanInfo = { + type: 'session', + incoming: { + id: localChan, + window: MAX_WINDOW, + packetSize: PACKET_SIZE, + state: 'open' + }, + outgoing: { + id: info.sender, + window: info.window, + packetSize: info.packetSize, + state: 'open' + } + }; + } +} + + +class Server extends EventEmitter { + constructor(cfg, listener) { + super(); + + if (typeof cfg !== 'object' || cfg === null) + throw new Error('Missing configuration object'); + + const hostKeys = Object.create(null); + const hostKeyAlgoOrder = []; + + const hostKeys_ = cfg.hostKeys; + if (!Array.isArray(hostKeys_)) + throw new Error('hostKeys must be an array'); + + const cfgAlgos = ( + typeof cfg.algorithms === 'object' && cfg.algorithms !== null + ? cfg.algorithms + : {} + ); + + const hostKeyAlgos = generateAlgorithmList( + cfgAlgos.serverHostKey, + DEFAULT_SERVER_HOST_KEY, + SUPPORTED_SERVER_HOST_KEY + ); + for (let i = 0; i < hostKeys_.length; ++i) { + let privateKey; + if (Buffer.isBuffer(hostKeys_[i]) || typeof hostKeys_[i] === 'string') + privateKey = parseKey(hostKeys_[i]); + else + privateKey = parseKey(hostKeys_[i].key, hostKeys_[i].passphrase); + + if (privateKey instanceof Error) + throw new Error(`Cannot parse privateKey: ${privateKey.message}`); + + if (Array.isArray(privateKey)) { + // OpenSSH's newer format only stores 1 key for now + privateKey = privateKey[0]; + } + + if (privateKey.getPrivatePEM() === null) + throw new Error('privateKey value contains an invalid private key'); + + // Discard key if we already found a key of the same type + if (hostKeyAlgoOrder.includes(privateKey.type)) + continue; + + if (privateKey.type === 'ssh-rsa') { + // SSH supports multiple signature hashing algorithms for RSA, so we add + // the algorithms in the desired order + let sha1Pos = hostKeyAlgos.indexOf('ssh-rsa'); + const sha256Pos = hostKeyAlgos.indexOf('rsa-sha2-256'); + const sha512Pos = hostKeyAlgos.indexOf('rsa-sha2-512'); + if (sha1Pos === -1) { + // Fall back to giving SHA1 the lowest priority + sha1Pos = Infinity; + } + [sha1Pos, sha256Pos, sha512Pos].sort(compareNumbers).forEach((pos) => { + if (pos === -1) + return; + + let type; + switch (pos) { + case sha1Pos: type = 'ssh-rsa'; break; + case sha256Pos: type = 'rsa-sha2-256'; break; + case sha512Pos: type = 'rsa-sha2-512'; break; + default: return; + } + + // Store same RSA key under each hash algorithm name for convenience + hostKeys[type] = privateKey; + + hostKeyAlgoOrder.push(type); + }); + } else { + hostKeys[privateKey.type] = privateKey; + hostKeyAlgoOrder.push(privateKey.type); + } + } + + const algorithms = { + kex: generateAlgorithmList( + cfgAlgos.kex, + DEFAULT_KEX, + SUPPORTED_KEX + ).concat(['kex-strict-s-v00@openssh.com']), + serverHostKey: hostKeyAlgoOrder, + cs: { + cipher: generateAlgorithmList( + cfgAlgos.cipher, + DEFAULT_CIPHER, + SUPPORTED_CIPHER + ), + mac: generateAlgorithmList(cfgAlgos.hmac, DEFAULT_MAC, SUPPORTED_MAC), + compress: generateAlgorithmList( + cfgAlgos.compress, + DEFAULT_COMPRESSION, + SUPPORTED_COMPRESSION + ), + lang: [], + }, + sc: undefined, + }; + algorithms.sc = algorithms.cs; + + if (typeof listener === 'function') + this.on('connection', listener); + + const origDebug = (typeof cfg.debug === 'function' ? cfg.debug : undefined); + const ident = (cfg.ident ? Buffer.from(cfg.ident) : undefined); + const offer = new KexInit(algorithms); + + this._srv = new netServer((socket) => { + if (this._connections >= this.maxConnections) { + socket.destroy(); + return; + } + ++this._connections; + socket.once('close', () => { + --this._connections; + }); + + let debug; + if (origDebug) { + // Prepend debug output with a unique identifier in case there are + // multiple clients connected at the same time + const debugPrefix = `[${process.hrtime().join('.')}] `; + debug = (msg) => { + origDebug(`${debugPrefix}${msg}`); + }; + } + + // eslint-disable-next-line no-use-before-define + new Client(socket, hostKeys, ident, offer, debug, this, cfg); + }).on('error', (err) => { + this.emit('error', err); + }).on('listening', () => { + this.emit('listening'); + }).on('close', () => { + this.emit('close'); + }); + this._connections = 0; + this.maxConnections = Infinity; + } + + injectSocket(socket) { + this._srv.emit('connection', socket); + } + + listen(...args) { + this._srv.listen(...args); + return this; + } + + address() { + return this._srv.address(); + } + + getConnections(cb) { + this._srv.getConnections(cb); + return this; + } + + close(cb) { + this._srv.close(cb); + return this; + } + + ref() { + this._srv.ref(); + return this; + } + + unref() { + this._srv.unref(); + return this; + } +} +Server.KEEPALIVE_CLIENT_INTERVAL = 15000; +Server.KEEPALIVE_CLIENT_COUNT_MAX = 3; + + +class Client extends EventEmitter { + constructor(socket, hostKeys, ident, offer, debug, server, srvCfg) { + super(); + + let exchanges = 0; + let acceptedAuthSvc = false; + let pendingAuths = []; + let authCtx; + let kaTimer; + let onPacket; + const unsentGlobalRequestsReplies = []; + this._sock = socket; + this._chanMgr = new ChannelManager(this); + this._debug = debug; + this.noMoreSessions = false; + this.authenticated = false; + + // Silence pre-header errors + function onClientPreHeaderError(err) {} + this.on('error', onClientPreHeaderError); + + const DEBUG_HANDLER = (!debug ? undefined : (p, display, msg) => { + debug(`Debug output from client: ${JSON.stringify(msg)}`); + }); + + const kaIntvl = ( + typeof srvCfg.keepaliveInterval === 'number' + && isFinite(srvCfg.keepaliveInterval) + && srvCfg.keepaliveInterval > 0 + ? srvCfg.keepaliveInterval + : ( + typeof Server.KEEPALIVE_CLIENT_INTERVAL === 'number' + && isFinite(Server.KEEPALIVE_CLIENT_INTERVAL) + && Server.KEEPALIVE_CLIENT_INTERVAL > 0 + ? Server.KEEPALIVE_CLIENT_INTERVAL + : -1 + ) + ); + const kaCountMax = ( + typeof srvCfg.keepaliveCountMax === 'number' + && isFinite(srvCfg.keepaliveCountMax) + && srvCfg.keepaliveCountMax >= 0 + ? srvCfg.keepaliveCountMax + : ( + typeof Server.KEEPALIVE_CLIENT_COUNT_MAX === 'number' + && isFinite(Server.KEEPALIVE_CLIENT_COUNT_MAX) + && Server.KEEPALIVE_CLIENT_COUNT_MAX >= 0 + ? Server.KEEPALIVE_CLIENT_COUNT_MAX + : -1 + ) + ); + let kaCurCount = 0; + if (kaIntvl !== -1 && kaCountMax !== -1) { + this.once('ready', () => { + const onClose = () => { + clearInterval(kaTimer); + }; + this.on('close', onClose).on('end', onClose); + kaTimer = setInterval(() => { + if (++kaCurCount > kaCountMax) { + clearInterval(kaTimer); + const err = new Error('Keepalive timeout'); + err.level = 'client-timeout'; + this.emit('error', err); + this.end(); + } else { + // XXX: if the server ever starts sending real global requests to + // the client, we will need to add a dummy callback here to + // keep the correct reply order + proto.ping(); + } + }, kaIntvl); + }); + // TODO: re-verify keepalive behavior with OpenSSH + onPacket = () => { + kaTimer && kaTimer.refresh(); + kaCurCount = 0; + }; + } + + const proto = this._protocol = new Protocol({ + server: true, + hostKeys, + ident, + offer, + onPacket, + greeting: srvCfg.greeting, + banner: srvCfg.banner, + onWrite: (data) => { + if (isWritable(socket)) + socket.write(data); + }, + onError: (err) => { + if (!proto._destruct) + socket.removeAllListeners('data'); + this.emit('error', err); + try { + socket.end(); + } catch {} + }, + onHeader: (header) => { + this.removeListener('error', onClientPreHeaderError); + + const info = { + ip: socket.remoteAddress, + family: socket.remoteFamily, + port: socket.remotePort, + header, + }; + if (!server.emit('connection', this, info)) { + // auto reject + proto.disconnect(DISCONNECT_REASON.BY_APPLICATION); + socket.end(); + return; + } + + if (header.greeting) + this.emit('greeting', header.greeting); + }, + onHandshakeComplete: (negotiated) => { + if (++exchanges > 1) + this.emit('rekey'); + this.emit('handshake', negotiated); + }, + debug, + messageHandlers: { + DEBUG: DEBUG_HANDLER, + DISCONNECT: (p, reason, desc) => { + if (reason !== DISCONNECT_REASON.BY_APPLICATION) { + if (!desc) { + desc = DISCONNECT_REASON_BY_VALUE[reason]; + if (desc === undefined) + desc = `Unexpected disconnection reason: ${reason}`; + } + const err = new Error(desc); + err.code = reason; + this.emit('error', err); + } + socket.end(); + }, + CHANNEL_OPEN: (p, info) => { + // Handle incoming requests from client + + // Do early reject in some cases to prevent wasteful channel + // allocation + if ((info.type === 'session' && this.noMoreSessions) + || !this.authenticated) { + const reasonCode = CHANNEL_OPEN_FAILURE.ADMINISTRATIVELY_PROHIBITED; + return proto.channelOpenFail(info.sender, reasonCode); + } + + let localChan = -1; + let reason; + let replied = false; + + let accept; + const reject = () => { + if (replied) + return; + replied = true; + + if (reason === undefined) { + if (localChan === -1) + reason = CHANNEL_OPEN_FAILURE.RESOURCE_SHORTAGE; + else + reason = CHANNEL_OPEN_FAILURE.CONNECT_FAILED; + } + + if (localChan !== -1) + this._chanMgr.remove(localChan); + proto.channelOpenFail(info.sender, reason, ''); + }; + const reserveChannel = () => { + localChan = this._chanMgr.add(); + + if (localChan === -1) { + reason = CHANNEL_OPEN_FAILURE.RESOURCE_SHORTAGE; + if (debug) { + debug('Automatic rejection of incoming channel open: ' + + 'no channels available'); + } + } + + return (localChan !== -1); + }; + + const data = info.data; + switch (info.type) { + case 'session': + if (listenerCount(this, 'session') && reserveChannel()) { + accept = () => { + if (replied) + return; + replied = true; + + const instance = new Session(this, info, localChan); + this._chanMgr.update(localChan, instance); + + proto.channelOpenConfirm(info.sender, + localChan, + MAX_WINDOW, + PACKET_SIZE); + + return instance; + }; + + this.emit('session', accept, reject); + return; + } + break; + case 'direct-tcpip': + if (listenerCount(this, 'tcpip') && reserveChannel()) { + accept = () => { + if (replied) + return; + replied = true; + + const chanInfo = { + type: undefined, + incoming: { + id: localChan, + window: MAX_WINDOW, + packetSize: PACKET_SIZE, + state: 'open' + }, + outgoing: { + id: info.sender, + window: info.window, + packetSize: info.packetSize, + state: 'open' + } + }; + + const stream = new Channel(this, chanInfo, { server: true }); + this._chanMgr.update(localChan, stream); + + proto.channelOpenConfirm(info.sender, + localChan, + MAX_WINDOW, + PACKET_SIZE); + + return stream; + }; + + this.emit('tcpip', accept, reject, data); + return; + } + break; + case 'direct-streamlocal@openssh.com': + if (listenerCount(this, 'openssh.streamlocal') + && reserveChannel()) { + accept = () => { + if (replied) + return; + replied = true; + + const chanInfo = { + type: undefined, + incoming: { + id: localChan, + window: MAX_WINDOW, + packetSize: PACKET_SIZE, + state: 'open' + }, + outgoing: { + id: info.sender, + window: info.window, + packetSize: info.packetSize, + state: 'open' + } + }; + + const stream = new Channel(this, chanInfo, { server: true }); + this._chanMgr.update(localChan, stream); + + proto.channelOpenConfirm(info.sender, + localChan, + MAX_WINDOW, + PACKET_SIZE); + + return stream; + }; + + this.emit('openssh.streamlocal', accept, reject, data); + return; + } + break; + default: + // Automatically reject any unsupported channel open requests + reason = CHANNEL_OPEN_FAILURE.UNKNOWN_CHANNEL_TYPE; + if (debug) { + debug('Automatic rejection of unsupported incoming channel open' + + ` type: ${info.type}`); + } + } + + if (reason === undefined) { + reason = CHANNEL_OPEN_FAILURE.ADMINISTRATIVELY_PROHIBITED; + if (debug) { + debug('Automatic rejection of unexpected incoming channel open' + + ` for: ${info.type}`); + } + } + + reject(); + }, + CHANNEL_OPEN_CONFIRMATION: (p, info) => { + const channel = this._chanMgr.get(info.recipient); + if (typeof channel !== 'function') + return; + + const chanInfo = { + type: channel.type, + incoming: { + id: info.recipient, + window: MAX_WINDOW, + packetSize: PACKET_SIZE, + state: 'open' + }, + outgoing: { + id: info.sender, + window: info.window, + packetSize: info.packetSize, + state: 'open' + } + }; + + const instance = new Channel(this, chanInfo, { server: true }); + this._chanMgr.update(info.recipient, instance); + channel(undefined, instance); + }, + CHANNEL_OPEN_FAILURE: (p, recipient, reason, description) => { + const channel = this._chanMgr.get(recipient); + if (typeof channel !== 'function') + return; + + const info = { reason, description }; + onChannelOpenFailure(this, recipient, info, channel); + }, + CHANNEL_DATA: (p, recipient, data) => { + let channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.constructor === Session) { + channel = channel._channel; + if (!channel) + return; + } + + // The remote party should not be sending us data if there is no + // window space available ... + // TODO: raise error on data with not enough window? + if (channel.incoming.window === 0) + return; + + channel.incoming.window -= data.length; + + if (channel.push(data) === false) { + channel._waitChanDrain = true; + return; + } + + if (channel.incoming.window <= WINDOW_THRESHOLD) + windowAdjust(channel); + }, + CHANNEL_EXTENDED_DATA: (p, recipient, data, type) => { + // NOOP -- should not be sent by client + }, + CHANNEL_WINDOW_ADJUST: (p, recipient, amount) => { + let channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.constructor === Session) { + channel = channel._channel; + if (!channel) + return; + } + + // The other side is allowing us to send `amount` more bytes of data + channel.outgoing.window += amount; + + if (channel._waitWindow) { + channel._waitWindow = false; + + if (channel._chunk) { + channel._write(channel._chunk, null, channel._chunkcb); + } else if (channel._chunkcb) { + channel._chunkcb(); + } else if (channel._chunkErr) { + channel.stderr._write(channel._chunkErr, + null, + channel._chunkcbErr); + } else if (channel._chunkcbErr) { + channel._chunkcbErr(); + } + } + }, + CHANNEL_SUCCESS: (p, recipient) => { + let channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.constructor === Session) { + channel = channel._channel; + if (!channel) + return; + } + + if (channel._callbacks.length) + channel._callbacks.shift()(false); + }, + CHANNEL_FAILURE: (p, recipient) => { + let channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.constructor === Session) { + channel = channel._channel; + if (!channel) + return; + } + + if (channel._callbacks.length) + channel._callbacks.shift()(true); + }, + CHANNEL_REQUEST: (p, recipient, type, wantReply, data) => { + const session = this._chanMgr.get(recipient); + if (typeof session !== 'object' || session === null) + return; + + let replied = false; + let accept; + let reject; + + if (session.constructor !== Session) { + // normal Channel instance + if (wantReply) + proto.channelFailure(session.outgoing.id); + return; + } + + if (wantReply) { + // "real session" requests will have custom accept behaviors + if (type !== 'shell' + && type !== 'exec' + && type !== 'subsystem') { + accept = () => { + if (replied || session._ending || session._channel) + return; + replied = true; + + proto.channelSuccess(session._chanInfo.outgoing.id); + }; + } + + reject = () => { + if (replied || session._ending || session._channel) + return; + replied = true; + + proto.channelFailure(session._chanInfo.outgoing.id); + }; + } + + if (session._ending) { + reject && reject(); + return; + } + + switch (type) { + // "pre-real session start" requests + case 'env': + if (listenerCount(session, 'env')) { + session.emit('env', accept, reject, { + key: data.name, + val: data.value + }); + return; + } + break; + case 'pty-req': + if (listenerCount(session, 'pty')) { + session.emit('pty', accept, reject, data); + return; + } + break; + case 'window-change': + if (listenerCount(session, 'window-change')) + session.emit('window-change', accept, reject, data); + else + reject && reject(); + break; + case 'x11-req': + if (listenerCount(session, 'x11')) { + session.emit('x11', accept, reject, data); + return; + } + break; + // "post-real session start" requests + case 'signal': + if (listenerCount(session, 'signal')) { + session.emit('signal', accept, reject, { + name: data + }); + return; + } + break; + // XXX: is `auth-agent-req@openssh.com` really "post-real session + // start"? + case 'auth-agent-req@openssh.com': + if (listenerCount(session, 'auth-agent')) { + session.emit('auth-agent', accept, reject); + return; + } + break; + // "real session start" requests + case 'shell': + if (listenerCount(session, 'shell')) { + accept = () => { + if (replied || session._ending || session._channel) + return; + replied = true; + + if (wantReply) + proto.channelSuccess(session._chanInfo.outgoing.id); + + const channel = new Channel( + this, session._chanInfo, { server: true } + ); + + channel.subtype = session.subtype = type; + session._channel = channel; + + return channel; + }; + + session.emit('shell', accept, reject); + return; + } + break; + case 'exec': + if (listenerCount(session, 'exec')) { + accept = () => { + if (replied || session._ending || session._channel) + return; + replied = true; + + if (wantReply) + proto.channelSuccess(session._chanInfo.outgoing.id); + + const channel = new Channel( + this, session._chanInfo, { server: true } + ); + + channel.subtype = session.subtype = type; + session._channel = channel; + + return channel; + }; + + session.emit('exec', accept, reject, { + command: data + }); + return; + } + break; + case 'subsystem': { + let useSFTP = (data === 'sftp'); + accept = () => { + if (replied || session._ending || session._channel) + return; + replied = true; + + if (wantReply) + proto.channelSuccess(session._chanInfo.outgoing.id); + + let instance; + if (useSFTP) { + instance = new SFTP(this, session._chanInfo, { + server: true, + debug, + }); + } else { + instance = new Channel( + this, session._chanInfo, { server: true } + ); + instance.subtype = + session.subtype = `${type}:${data}`; + } + session._channel = instance; + + return instance; + }; + + if (data === 'sftp') { + if (listenerCount(session, 'sftp')) { + session.emit('sftp', accept, reject); + return; + } + useSFTP = false; + } + if (listenerCount(session, 'subsystem')) { + session.emit('subsystem', accept, reject, { + name: data + }); + return; + } + break; + } + } + debug && debug( + `Automatic rejection of incoming channel request: ${type}` + ); + reject && reject(); + }, + CHANNEL_EOF: (p, recipient) => { + let channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.constructor === Session) { + if (!channel._ending) { + channel._ending = true; + channel.emit('eof'); + channel.emit('end'); + } + channel = channel._channel; + if (!channel) + return; + } + + if (channel.incoming.state !== 'open') + return; + channel.incoming.state = 'eof'; + + if (channel.readable) + channel.push(null); + }, + CHANNEL_CLOSE: (p, recipient) => { + let channel = this._chanMgr.get(recipient); + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.constructor === Session) { + channel._ending = true; + channel.emit('close'); + channel = channel._channel; + if (!channel) + return; + } + + onCHANNEL_CLOSE(this, recipient, channel); + }, + // Begin service/auth-related ========================================== + SERVICE_REQUEST: (p, service) => { + if (exchanges === 0 + || acceptedAuthSvc + || this.authenticated + || service !== 'ssh-userauth') { + proto.disconnect(DISCONNECT_REASON.SERVICE_NOT_AVAILABLE); + socket.end(); + return; + } + + acceptedAuthSvc = true; + proto.serviceAccept(service); + }, + USERAUTH_REQUEST: (p, username, service, method, methodData) => { + if (exchanges === 0 + || this.authenticated + || (authCtx + && (authCtx.username !== username + || authCtx.service !== service)) + // TODO: support hostbased auth + || (method !== 'password' + && method !== 'publickey' + && method !== 'hostbased' + && method !== 'keyboard-interactive' + && method !== 'none') + || pendingAuths.length === MAX_PENDING_AUTHS) { + proto.disconnect(DISCONNECT_REASON.PROTOCOL_ERROR); + socket.end(); + return; + } else if (service !== 'ssh-connection') { + proto.disconnect(DISCONNECT_REASON.SERVICE_NOT_AVAILABLE); + socket.end(); + return; + } + + let ctx; + switch (method) { + case 'keyboard-interactive': + ctx = new KeyboardAuthContext(proto, username, service, method, + methodData, onAuthDecide); + break; + case 'publickey': + ctx = new PKAuthContext(proto, username, service, method, + methodData, onAuthDecide); + break; + case 'hostbased': + ctx = new HostbasedAuthContext(proto, username, service, method, + methodData, onAuthDecide); + break; + case 'password': + if (authCtx + && authCtx instanceof PwdAuthContext + && authCtx._changeCb) { + const cb = authCtx._changeCb; + authCtx._changeCb = undefined; + cb(methodData.newPassword); + return; + } + ctx = new PwdAuthContext(proto, username, service, method, + methodData, onAuthDecide); + break; + case 'none': + ctx = new AuthContext(proto, username, service, method, + onAuthDecide); + break; + } + + if (authCtx) { + if (!authCtx._initialResponse) { + return pendingAuths.push(ctx); + } else if (authCtx._multistep && !authCtx._finalResponse) { + // RFC 4252 says to silently abort the current auth request if a + // new auth request comes in before the final response from an + // auth method that requires additional request/response exchanges + // -- this means keyboard-interactive for now ... + authCtx._cleanup && authCtx._cleanup(); + authCtx.emit('abort'); + } + } + + authCtx = ctx; + + if (listenerCount(this, 'authentication')) + this.emit('authentication', authCtx); + else + authCtx.reject(); + }, + USERAUTH_INFO_RESPONSE: (p, responses) => { + if (authCtx && authCtx instanceof KeyboardAuthContext) + authCtx._onInfoResponse(responses); + }, + // End service/auth-related ============================================ + GLOBAL_REQUEST: (p, name, wantReply, data) => { + const reply = { + type: null, + buf: null + }; + + function setReply(type, buf) { + reply.type = type; + reply.buf = buf; + sendReplies(); + } + + if (wantReply) + unsentGlobalRequestsReplies.push(reply); + + if ((name === 'tcpip-forward' + || name === 'cancel-tcpip-forward' + || name === 'no-more-sessions@openssh.com' + || name === 'streamlocal-forward@openssh.com' + || name === 'cancel-streamlocal-forward@openssh.com') + && listenerCount(this, 'request') + && this.authenticated) { + let accept; + let reject; + + if (wantReply) { + let replied = false; + accept = (chosenPort) => { + if (replied) + return; + replied = true; + let bufPort; + if (name === 'tcpip-forward' + && data.bindPort === 0 + && typeof chosenPort === 'number') { + bufPort = Buffer.allocUnsafe(4); + writeUInt32BE(bufPort, chosenPort, 0); + } + setReply('SUCCESS', bufPort); + }; + reject = () => { + if (replied) + return; + replied = true; + setReply('FAILURE'); + }; + } + + if (name === 'no-more-sessions@openssh.com') { + this.noMoreSessions = true; + accept && accept(); + return; + } + + this.emit('request', accept, reject, name, data); + } else if (wantReply) { + setReply('FAILURE'); + } + }, + }, + }); + + socket.pause(); + cryptoInit.then(() => { + proto.start(); + socket.on('data', (data) => { + try { + proto.parse(data, 0, data.length); + } catch (ex) { + this.emit('error', ex); + try { + if (isWritable(socket)) + socket.end(); + } catch {} + } + }); + socket.resume(); + }).catch((err) => { + this.emit('error', err); + try { + if (isWritable(socket)) + socket.end(); + } catch {} + }); + socket.on('error', (err) => { + err.level = 'socket'; + this.emit('error', err); + }).once('end', () => { + debug && debug('Socket ended'); + proto.cleanup(); + this.emit('end'); + }).once('close', () => { + debug && debug('Socket closed'); + proto.cleanup(); + this.emit('close'); + + const err = new Error('No response from server'); + + // Simulate error for pending channels and close any open channels + this._chanMgr.cleanup(err); + }); + + const onAuthDecide = (ctx, allowed, methodsLeft, isPartial) => { + if (authCtx === ctx && !this.authenticated) { + if (allowed) { + authCtx = undefined; + this.authenticated = true; + proto.authSuccess(); + pendingAuths = []; + this.emit('ready'); + } else { + proto.authFailure(methodsLeft, isPartial); + if (pendingAuths.length) { + authCtx = pendingAuths.pop(); + if (listenerCount(this, 'authentication')) + this.emit('authentication', authCtx); + else + authCtx.reject(); + } + } + } + }; + + function sendReplies() { + while (unsentGlobalRequestsReplies.length > 0 + && unsentGlobalRequestsReplies[0].type) { + const reply = unsentGlobalRequestsReplies.shift(); + if (reply.type === 'SUCCESS') + proto.requestSuccess(reply.buf); + if (reply.type === 'FAILURE') + proto.requestFailure(); + } + } + } + + end() { + if (this._sock && isWritable(this._sock)) { + this._protocol.disconnect(DISCONNECT_REASON.BY_APPLICATION); + this._sock.end(); + } + return this; + } + + x11(originAddr, originPort, cb) { + const opts = { originAddr, originPort }; + openChannel(this, 'x11', opts, cb); + return this; + } + + forwardOut(boundAddr, boundPort, remoteAddr, remotePort, cb) { + const opts = { boundAddr, boundPort, remoteAddr, remotePort }; + openChannel(this, 'forwarded-tcpip', opts, cb); + return this; + } + + openssh_forwardOutStreamLocal(socketPath, cb) { + const opts = { socketPath }; + openChannel(this, 'forwarded-streamlocal@openssh.com', opts, cb); + return this; + } + + rekey(cb) { + let error; + + try { + this._protocol.rekey(); + } catch (ex) { + error = ex; + } + + // TODO: re-throw error if no callback? + + if (typeof cb === 'function') { + if (error) + process.nextTick(cb, error); + else + this.once('rekey', cb); + } + } + + setNoDelay(noDelay) { + if (this._sock && typeof this._sock.setNoDelay === 'function') + this._sock.setNoDelay(noDelay); + + return this; + } +} + + +function openChannel(self, type, opts, cb) { + // Ask the client to open a channel for some purpose (e.g. a forwarded TCP + // connection) + const initWindow = MAX_WINDOW; + const maxPacket = PACKET_SIZE; + + if (typeof opts === 'function') { + cb = opts; + opts = {}; + } + + const wrapper = (err, stream) => { + cb(err, stream); + }; + wrapper.type = type; + + const localChan = self._chanMgr.add(wrapper); + + if (localChan === -1) { + cb(new Error('No free channels available')); + return; + } + + switch (type) { + case 'forwarded-tcpip': + self._protocol.forwardedTcpip(localChan, initWindow, maxPacket, opts); + break; + case 'x11': + self._protocol.x11(localChan, initWindow, maxPacket, opts); + break; + case 'forwarded-streamlocal@openssh.com': + self._protocol.openssh_forwardedStreamLocal( + localChan, initWindow, maxPacket, opts + ); + break; + default: + throw new Error(`Unsupported channel type: ${type}`); + } +} + +function compareNumbers(a, b) { + return a - b; +} + +module.exports = Server; +module.exports.IncomingClient = Client; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/lib/utils.js b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/utils.js new file mode 100644 index 0000000..d9ca6ae --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/lib/utils.js @@ -0,0 +1,336 @@ +'use strict'; + +const { SFTP } = require('./protocol/SFTP.js'); + +const MAX_CHANNEL = 2 ** 32 - 1; + +function onChannelOpenFailure(self, recipient, info, cb) { + self._chanMgr.remove(recipient); + if (typeof cb !== 'function') + return; + + let err; + if (info instanceof Error) { + err = info; + } else if (typeof info === 'object' && info !== null) { + err = new Error(`(SSH) Channel open failure: ${info.description}`); + err.reason = info.reason; + } else { + err = new Error( + '(SSH) Channel open failure: server closed channel unexpectedly' + ); + err.reason = ''; + } + + cb(err); +} + +function onCHANNEL_CLOSE(self, recipient, channel, err, dead) { + if (typeof channel === 'function') { + // We got CHANNEL_CLOSE instead of CHANNEL_OPEN_FAILURE when + // requesting to open a channel + onChannelOpenFailure(self, recipient, err, channel); + return; + } + + if (typeof channel !== 'object' || channel === null) + return; + + if (channel.incoming && channel.incoming.state === 'closed') + return; + + self._chanMgr.remove(recipient); + + if (channel.server && channel.constructor.name === 'Session') + return; + + channel.incoming.state = 'closed'; + + if (channel.readable) + channel.push(null); + if (channel.server) { + if (channel.stderr.writable) + channel.stderr.end(); + } else if (channel.stderr.readable) { + channel.stderr.push(null); + } + + if (channel.constructor !== SFTP + && (channel.outgoing.state === 'open' + || channel.outgoing.state === 'eof') + && !dead) { + channel.close(); + } + if (channel.outgoing.state === 'closing') + channel.outgoing.state = 'closed'; + + const readState = channel._readableState; + const writeState = channel._writableState; + if (writeState && !writeState.ending && !writeState.finished && !dead) + channel.end(); + + // Take care of any outstanding channel requests + const chanCallbacks = channel._callbacks; + channel._callbacks = []; + for (let i = 0; i < chanCallbacks.length; ++i) + chanCallbacks[i](true); + + if (channel.server) { + if (!channel.readable + || channel.destroyed + || (readState && readState.endEmitted)) { + channel.emit('close'); + } else { + channel.once('end', () => channel.emit('close')); + } + } else { + let doClose; + switch (channel.type) { + case 'direct-streamlocal@openssh.com': + case 'direct-tcpip': + doClose = () => channel.emit('close'); + break; + default: { + // Align more with node child processes, where the close event gets + // the same arguments as the exit event + const exit = channel._exit; + doClose = () => { + if (exit.code === null) + channel.emit('close', exit.code, exit.signal, exit.dump, exit.desc); + else + channel.emit('close', exit.code); + }; + } + } + if (!channel.readable + || channel.destroyed + || (readState && readState.endEmitted)) { + doClose(); + } else { + channel.once('end', doClose); + } + + const errReadState = channel.stderr._readableState; + if (!channel.stderr.readable + || channel.stderr.destroyed + || (errReadState && errReadState.endEmitted)) { + channel.stderr.emit('close'); + } else { + channel.stderr.once('end', () => channel.stderr.emit('close')); + } + } +} + +class ChannelManager { + constructor(client) { + this._client = client; + this._channels = {}; + this._cur = -1; + this._count = 0; + } + add(val) { + // Attempt to reserve an id + + let id; + // Optimized paths + if (this._cur < MAX_CHANNEL) { + id = ++this._cur; + } else if (this._count === 0) { + // Revert and reset back to fast path once we no longer have any channels + // open + this._cur = 0; + id = 0; + } else { + // Slower lookup path + + // This path is triggered we have opened at least MAX_CHANNEL channels + // while having at least one channel open at any given time, so we have + // to search for a free id. + const channels = this._channels; + for (let i = 0; i < MAX_CHANNEL; ++i) { + if (channels[i] === undefined) { + id = i; + break; + } + } + } + + if (id === undefined) + return -1; + + this._channels[id] = (val || true); + ++this._count; + + return id; + } + update(id, val) { + if (typeof id !== 'number' || id < 0 || id >= MAX_CHANNEL || !isFinite(id)) + throw new Error(`Invalid channel id: ${id}`); + + if (val && this._channels[id]) + this._channels[id] = val; + } + get(id) { + if (typeof id !== 'number' || id < 0 || id >= MAX_CHANNEL || !isFinite(id)) + throw new Error(`Invalid channel id: ${id}`); + + return this._channels[id]; + } + remove(id) { + if (typeof id !== 'number' || id < 0 || id >= MAX_CHANNEL || !isFinite(id)) + throw new Error(`Invalid channel id: ${id}`); + + if (this._channels[id]) { + delete this._channels[id]; + if (this._count) + --this._count; + } + } + cleanup(err) { + const channels = this._channels; + this._channels = {}; + this._cur = -1; + this._count = 0; + + const chanIDs = Object.keys(channels); + const client = this._client; + for (let i = 0; i < chanIDs.length; ++i) { + const id = +chanIDs[i]; + const channel = channels[id]; + onCHANNEL_CLOSE(client, id, channel._channel || channel, err, true); + } + } +} + +const isRegExp = (() => { + const toString = Object.prototype.toString; + return (val) => toString.call(val) === '[object RegExp]'; +})(); + +function generateAlgorithmList(algoList, defaultList, supportedList) { + if (Array.isArray(algoList) && algoList.length > 0) { + // Exact list + for (let i = 0; i < algoList.length; ++i) { + if (supportedList.indexOf(algoList[i]) === -1) + throw new Error(`Unsupported algorithm: ${algoList[i]}`); + } + return algoList; + } + + if (typeof algoList === 'object' && algoList !== null) { + // Operations based on the default list + const keys = Object.keys(algoList); + let list = defaultList; + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + let val = algoList[key]; + switch (key) { + case 'append': + if (!Array.isArray(val)) + val = [val]; + if (Array.isArray(val)) { + for (let j = 0; j < val.length; ++j) { + const append = val[j]; + if (typeof append === 'string') { + if (!append || list.indexOf(append) !== -1) + continue; + if (supportedList.indexOf(append) === -1) + throw new Error(`Unsupported algorithm: ${append}`); + if (list === defaultList) + list = list.slice(); + list.push(append); + } else if (isRegExp(append)) { + for (let k = 0; k < supportedList.length; ++k) { + const algo = supportedList[k]; + if (append.test(algo)) { + if (list.indexOf(algo) !== -1) + continue; + if (list === defaultList) + list = list.slice(); + list.push(algo); + } + } + } + } + } + break; + case 'prepend': + if (!Array.isArray(val)) + val = [val]; + if (Array.isArray(val)) { + for (let j = val.length; j >= 0; --j) { + const prepend = val[j]; + if (typeof prepend === 'string') { + if (!prepend || list.indexOf(prepend) !== -1) + continue; + if (supportedList.indexOf(prepend) === -1) + throw new Error(`Unsupported algorithm: ${prepend}`); + if (list === defaultList) + list = list.slice(); + list.unshift(prepend); + } else if (isRegExp(prepend)) { + for (let k = supportedList.length; k >= 0; --k) { + const algo = supportedList[k]; + if (prepend.test(algo)) { + if (list.indexOf(algo) !== -1) + continue; + if (list === defaultList) + list = list.slice(); + list.unshift(algo); + } + } + } + } + } + break; + case 'remove': + if (!Array.isArray(val)) + val = [val]; + if (Array.isArray(val)) { + for (let j = 0; j < val.length; ++j) { + const search = val[j]; + if (typeof search === 'string') { + if (!search) + continue; + const idx = list.indexOf(search); + if (idx === -1) + continue; + if (list === defaultList) + list = list.slice(); + list.splice(idx, 1); + } else if (isRegExp(search)) { + for (let k = 0; k < list.length; ++k) { + if (search.test(list[k])) { + if (list === defaultList) + list = list.slice(); + list.splice(k, 1); + --k; + } + } + } + } + } + break; + } + } + + return list; + } + + return defaultList; +} + +module.exports = { + ChannelManager, + generateAlgorithmList, + onChannelOpenFailure, + onCHANNEL_CLOSE, + isWritable: (stream) => { + // XXX: hack to workaround regression in node + // See: https://github.com/nodejs/node/issues/36029 + return (stream + && stream.writable + && stream._readableState + && stream._readableState.ended === false); + }, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/package.json b/tasks/enduro-trails/prototype/node_modules/ssh2/package.json new file mode 100644 index 0000000..2e170c3 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/package.json @@ -0,0 +1,49 @@ +{ + "name": "ssh2", + "version": "1.17.0", + "author": "Brian White ", + "description": "SSH2 client and server modules written in pure JavaScript for node.js", + "main": "./lib/index.js", + "engines": { + "node": ">=10.16.0" + }, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "devDependencies": { + "@mscdex/eslint-config": "^1.1.0", + "eslint": "^7.32.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.23.0" + }, + "scripts": { + "install": "node install.js", + "rebuild": "node install.js", + "test": "node test/test.js", + "lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js examples lib test", + "lint:fix": "npm run lint -- --fix" + }, + "keywords": [ + "ssh", + "ssh2", + "sftp", + "secure", + "shell", + "exec", + "remote", + "client" + ], + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/mscdex/ssh2/raw/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/mscdex/ssh2.git" + } +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/common.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/common.js new file mode 100644 index 0000000..a531924 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/common.js @@ -0,0 +1,316 @@ +'use strict'; + +const assert = require('assert'); +const { readFileSync } = require('fs'); +const { join } = require('path'); +const { inspect } = require('util'); + +const Client = require('../lib/client.js'); +const Server = require('../lib/server.js'); +const { parseKey } = require('../lib/protocol/keyParser.js'); + +const mustCallChecks = []; + +const DEFAULT_TEST_TIMEOUT = 30 * 1000; + +function noop() {} + +function runCallChecks(exitCode) { + if (exitCode !== 0) return; + + const failed = mustCallChecks.filter((context) => { + if ('minimum' in context) { + context.messageSegment = `at least ${context.minimum}`; + return context.actual < context.minimum; + } + context.messageSegment = `exactly ${context.exact}`; + return context.actual !== context.exact; + }); + + failed.forEach((context) => { + console.error('Mismatched %s function calls. Expected %s, actual %d.', + context.name, + context.messageSegment, + context.actual); + console.error(context.stack.split('\n').slice(2).join('\n')); + }); + + if (failed.length) + process.exit(1); +} + +function mustCall(fn, exact) { + return _mustCallInner(fn, exact, 'exact'); +} + +function mustCallAtLeast(fn, minimum) { + return _mustCallInner(fn, minimum, 'minimum'); +} + +function _mustCallInner(fn, criteria = 1, field) { + if (process._exiting) + throw new Error('Cannot use common.mustCall*() in process exit handler'); + + if (typeof fn === 'number') { + criteria = fn; + fn = noop; + } else if (fn === undefined) { + fn = noop; + } + + if (typeof criteria !== 'number') + throw new TypeError(`Invalid ${field} value: ${criteria}`); + + const context = { + [field]: criteria, + actual: 0, + stack: inspect(new Error()), + name: fn.name || '' + }; + + // Add the exit listener only once to avoid listener leak warnings + if (mustCallChecks.length === 0) + process.on('exit', runCallChecks); + + mustCallChecks.push(context); + + function wrapped(...args) { + ++context.actual; + return fn.call(this, ...args); + } + // TODO: remove origFn? + wrapped.origFn = fn; + + return wrapped; +} + +function getCallSite(top) { + const originalStackFormatter = Error.prepareStackTrace; + Error.prepareStackTrace = (err, stack) => + `${stack[0].getFileName()}:${stack[0].getLineNumber()}`; + const err = new Error(); + Error.captureStackTrace(err, top); + // With the V8 Error API, the stack is not formatted until it is accessed + // eslint-disable-next-line no-unused-expressions + err.stack; + Error.prepareStackTrace = originalStackFormatter; + return err.stack; +} + +function mustNotCall(msg) { + const callSite = getCallSite(mustNotCall); + return function mustNotCall(...args) { + args = args.map(inspect).join(', '); + const argsInfo = (args.length > 0 + ? `\ncalled with arguments: ${args}` + : ''); + assert.fail( + `${msg || 'function should not have been called'} at ${callSite}` + + argsInfo); + }; +} + +function setup(title, configs) { + const { + client: clientCfg_, + server: serverCfg_, + allReady: allReady_, + timeout: timeout_, + debug, + noForceClientReady, + noForceServerReady, + noClientError, + noServerError, + } = configs; + + // Make shallow copies of client/server configs to avoid mutating them when + // multiple tests share the same config object reference + let clientCfg; + if (clientCfg_) + clientCfg = { ...clientCfg_ }; + let serverCfg; + if (serverCfg_) + serverCfg = { ...serverCfg_ }; + + let clientClose = false; + let clientReady = false; + let serverClose = false; + let serverReady = false; + const msg = (text) => { + return `${title}: ${text}`; + }; + + const timeout = (typeof timeout_ === 'number' + ? timeout_ + : DEFAULT_TEST_TIMEOUT); + + const allReady = (typeof allReady_ === 'function' ? allReady_ : undefined); + + if (debug) { + if (clientCfg) { + clientCfg.debug = (...args) => { + console.log(`[${title}][CLIENT]`, ...args); + }; + } + if (serverCfg) { + serverCfg.debug = (...args) => { + console.log(`[${title}][SERVER]`, ...args); + }; + } + } + + let timer; + let client; + let clientReadyFn; + let server; + let serverReadyFn; + if (clientCfg) { + client = new Client(); + if (!noClientError) + client.on('error', onError); + clientReadyFn = (noForceClientReady ? onReady : mustCall(onReady)); + client.on('ready', clientReadyFn) + .on('close', mustCall(onClose)); + } else { + clientReady = clientClose = true; + } + + if (serverCfg) { + server = new Server(serverCfg); + if (!noServerError) + server.on('error', onError); + serverReadyFn = (noForceServerReady ? onReady : mustCall(onReady)); + server.on('connection', mustCall((conn) => { + if (!noServerError) + conn.on('error', onError); + conn.on('ready', serverReadyFn); + server.close(); + })).on('close', mustCall(onClose)); + } else { + serverReady = serverClose = true; + } + + function onError(err) { + const which = (this === client ? 'client' : 'server'); + assert(false, msg(`Unexpected ${which} error: ${err.stack}\n`)); + } + + function onReady() { + if (this === client) { + assert(!clientReady, + msg('Received multiple ready events for client')); + clientReady = true; + } else { + assert(!serverReady, + msg('Received multiple ready events for server')); + serverReady = true; + } + clientReady && serverReady && allReady && allReady(); + } + + function onClose() { + if (this === client) { + assert(!clientClose, + msg('Received multiple close events for client')); + clientClose = true; + } else { + assert(!serverClose, + msg('Received multiple close events for server')); + serverClose = true; + } + if (clientClose && serverClose) + clearTimeout(timer); + } + + process.nextTick(mustCall(() => { + function connectClient() { + if (clientCfg.sock) { + clientCfg.sock.connect(server.address().port, 'localhost'); + } else { + clientCfg.host = 'localhost'; + clientCfg.port = server.address().port; + } + try { + client.connect(clientCfg); + } catch (ex) { + ex.message = msg(ex.message); + throw ex; + } + } + + if (server) { + server.listen(0, 'localhost', mustCall(() => { + if (timeout >= 0) { + timer = setTimeout(() => { + assert(false, msg('Test timed out')); + }, timeout); + } + if (client) + connectClient(); + })); + } + })); + + return { client, server }; +} + +const FIXTURES_DIR = join(__dirname, 'fixtures'); +const fixture = (() => { + const cache = new Map(); + return (file) => { + const existing = cache.get(file); + if (existing !== undefined) + return existing; + + const result = readFileSync(join(FIXTURES_DIR, file)); + cache.set(file, result); + return result; + }; +})(); +const fixtureKey = (() => { + const cache = new Map(); + return (file, passphrase, bypass) => { + if (typeof passphrase === 'boolean') { + bypass = passphrase; + passphrase = undefined; + } + if (typeof bypass !== 'boolean' || !bypass) { + const existing = cache.get(file); + if (existing !== undefined) + return existing; + } + const fullPath = join(FIXTURES_DIR, file); + const raw = fixture(file); + let key = parseKey(raw, passphrase); + if (Array.isArray(key)) + key = key[0]; + const result = { key, raw, fullPath }; + cache.set(file, result); + return result; + }; +})(); + +function setupSimple(debug, title) { + const { client, server } = setup(title, { + client: { username: 'Password User', password: '12345' }, + server: { hostKeys: [ fixtureKey('ssh_host_rsa_key').raw ] }, + debug, + }); + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })); + })); + return { client, server }; +} + +module.exports = { + fixture, + fixtureKey, + FIXTURES_DIR, + mustCall, + mustCallAtLeast, + mustNotCall, + setup, + setupSimple, +}; diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/bad_rsa_private_key b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/bad_rsa_private_key new file mode 100644 index 0000000..80fdc87 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/bad_rsa_private_key @@ -0,0 +1,26 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAz7MF4vhgw6HxNf3KtVf3VULTYgrRSlv+cCZdB1xxI1p/nGyu +/eekUn5C+mGeDS488DX5ulzicxVpL7pamc/tFNcp91MrR7PiIMK2l+bwbZJubbLj +DHhNcBklnFOSKxtmQRfuorGakpy/kXmIxF5of0xXGns6DlHRq9dGCJIXvrkqhcEb +k4n2y4aV4VOiMHdo6FrFQVPzA8DlbJP2SjIFZ/0VdK7O7eiyiqV1p1xlbTQQ5rAX +LdsshBn/GvoBOTCVupMXurn2582vgGh26Mmovj2QGzScMGUVttkMlnxUmKT/aQka +mC0vR54QOW7lyWPjAitOV0qgmtGm3/cl7W7NjwIDAQABAoIBAFxH0C+951BEXWV9 +s1jLEqshG8YNxFtjcDLn+KFSoznv9Y7MgxtwlgPI8X1Jbe2xQ4X+lUwGBN7Y/nkk +NSjtxwphZtXqb+pVs/yWRoZLJzunucSnnFVoBg/uPFWuk9zvOYlmVrKWcnT9i+fY +tbl5sLgOdQzg/zRpidztssIQFti3o2jnpyrEGcepPWLkfCgqPfGmNv78BAIt/6iT +zYDB4GMSq/LnPTIOFsIOvlkZg3RCcLWeAPRC+lvFQVY+M/uJL5WIbA5il1IMMKH7 +MULWpRO3lnb1JVrkZlBldK5uew6AN3tHDQOmg+C2JuIbOZ35J9dcnwsE+IptWWBj +XiFRJCECgYEA8BeuufkslureqOycaPLMkqchMTue1OxbLJFvPN+dh/cW6Lng3b8+ +xAyzZrc0vccH/jl9WVHhIZ7TcKXDzSmmrtnZ/3m1c4gANGqIPwO+emL1ZzzkIKGd +FrLeBZKP4TWry9kjg4cG1SKGpcB5ngJMPXUxMZNe74tC4Hk820PkFjcCgYEA3XXn +ngRCgH9N1eKSD2daxxlBhTTSnTgjU+dDaDFQzPIhJCcS8HwyQBQmNTOSXXK9sShC +fdXAsmiBby5WEBq/K5+cXeDG2ZlFLyPovEgTUrLgraw42PYs0+A8Ls7dFk7PuMez +3G2gUPkY039JiyXKfcog9/dIRfbWCwzQ6s7TV2kCgYEArsme81cahhgg1zvCNokk +M1Omz2/HFt2nFpAeOmPVDGnu7Kh9sxGKgTF53bpclBh0kjiKL99zFYXKCoUzQYYk +CcEhemLBnYUSGRbBb5arMfAfFfR3Y+YkNaUsC0SCqILpOfMvbo57g+ipu7ufDlA/ +7rIFiUDvaVap7j909W+8egsCgYEAsuc/0DBixMmSyHl7QwRcmkC15HVSu32RVIOb +ub01KAtmaH1EWJAMTCW64/mggOtjgI0kgeE/BSFVhsqo7eOdkhEj0db27OxbroRU +zF1xdrpYtRRO7D6a4iLgm3OzuQS72+tASo8pFqDUxG6sq8NAvLOgRJE4ioSoT07w +KvAgXRkCgYEAmWgcsX/BdNcKOteSDtPkys5NRtWCBz7Coxb+xXXoXz1FVegBolpY +wXVePvXTIbU8VJOLunMyH5wpmMUiJbTX9v2o/yfpsH0ci4GaAeVtqpA= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_cert.pem b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_cert.pem new file mode 100644 index 0000000..49e1045 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_cert.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIUPtNIRfp8v8RsObCr+9LVosWVD/QwDQYJKoZIhvcNAQEL +BQAwbTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcM +CVNvbWUtQ2l0eTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIw +EAYDVQQDDAlsb2NhbGhvc3QwHhcNMjAxMjIwMDQwNTM1WhcNMzAxMjE4MDQwNTM1 +WjBtMQswCQYDVQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTESMBAGA1UEBwwJ +U29tZS1DaXR5MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQ +BgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJ/m96/mBMFoUWUOFSvvmJjHj/XxnO89ClCcCIFA6bJNCJMFZV3m853HAhP9g3kF +M3hL0c96GKS5IsRJiNUMrIUYrWCPh1yUJCNfczyGbBJNcEoRhfqCuuzjA5U7jAil +jqLWBP+ZI0tKRuQXX4bDHp51qDESscxNHZQp0+Lho86y4XjZPnT1OYd5rl3D6D82 +AElOrGOtsj7KmHl3eYhQoKNDlCGa5ZK+L05rsClU5m/LXyGmf5QtOIF00JqJ7KS4 +mX3ZF+XE/+3gkXLJyOCOYFDLjGY7WjsJXz3Wm6pktW8NGqhMaaRfIINqtCQkDgMk +gTjF3TtEA/M2DsGU2edL3qm/ibQ4z88dMVkLGZ6DWZg5oGwZR0W8jRAauhWO01Qq +JSLF3Rhvj4VasF4Hj6sI2HQcgGlDFqPNs/ErTA91mN/+yzXzCYIGBUeF5cSbIsLL +TNo6fCHKRIYqpHYCQjwBYQh/2R4/o/BHHkePVWDN0dg2VAyrp/YhV3YTfs3M4ond +yx2CoW1FJHPlhsmGH3A6PlWe2dRgu9f0ZejOX+eefqkkJtrVbmxfVCB9KET7TrV1 +lBX/V6bnFwmT0fygeBHd0aR+h8dvIs3E/wovLp4MZjtT97p+IMcGUcH9AmbFlXgi +VOnYx4/3WLuqGpyurDaCWwJDmtdCDoclZeZ3ef+IEi3/AgMBAAGjUzBRMB0GA1Ud +DgQWBBTQsY4pBOEhu4+hJb5KqaxKNBMPLTAfBgNVHSMEGDAWgBTQsY4pBOEhu4+h +Jb5KqaxKNBMPLTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBf ++YfOSlOw79aCdtU40OH51QFJxuK54ryxpzRcpBeDE57HfnuNHAM+z+5xVu8+qaRn +jo27ylmLLmzlWV946Yb+fyxIZb37KNXiIYehPTYyiG9MYmE3kEH/kLEvU8SQ6zO5 +6CVP3RN+HP1ZdgHi4Zq6DLsngr/ma8nAXuRUgsvLogB2yrtTJTlMB5631ahdD3U8 +kInPa1FlWYjq0QvllzMJ2q/uUG8kMLZRArqKMxb6j5hqHZuA2PAhb1h2K54doOWt +26HdGPVBxZcnE7HUUqKMAxAf++vmYicDTSv6rsEONxmG9cn0SQWzUnr3G6zZ4uxF +9wlvl5/VN6jT9XtS9rpZfwOVLigmuhMFkUCxTTN0eHOh0u76QSk2nphxumIj1vc+ +I9G/KNk0R3G+7AyjDK2WIxaqUTChpBfytQoiiQCOYEL+KlJboWhYL7mfeBT2flzH +H3/LfF61Y8V2H5pjX1x+e/FghA5OFiHsrgoJVegVYu6v0JyCzNwGaSvnpu8QZcOZ +lT6d4UKS8JmIuq2w7iru6cURBRzMfBZ4qaX3Gm/NSDfi6q/8aL/mogzQHg91lrFz +AXZUkb+WGikJ6TEgL9M4qBHwgssk7ayEejBhIuLxQD654Py8P8diEt/77iY0qsS9 +EEw/onPXr9nLLeIcigQEa2+14msAb2I7a2/RhlUW+Q== +-----END CERTIFICATE----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_key.pem b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_key.pem new file mode 100644 index 0000000..3be6a97 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/https_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCf5vev5gTBaFFl +DhUr75iYx4/18ZzvPQpQnAiBQOmyTQiTBWVd5vOdxwIT/YN5BTN4S9HPehikuSLE +SYjVDKyFGK1gj4dclCQjX3M8hmwSTXBKEYX6grrs4wOVO4wIpY6i1gT/mSNLSkbk +F1+Gwx6edagxErHMTR2UKdPi4aPOsuF42T509TmHea5dw+g/NgBJTqxjrbI+yph5 +d3mIUKCjQ5QhmuWSvi9Oa7ApVOZvy18hpn+ULTiBdNCaieykuJl92RflxP/t4JFy +ycjgjmBQy4xmO1o7CV891puqZLVvDRqoTGmkXyCDarQkJA4DJIE4xd07RAPzNg7B +lNnnS96pv4m0OM/PHTFZCxmeg1mYOaBsGUdFvI0QGroVjtNUKiUixd0Yb4+FWrBe +B4+rCNh0HIBpQxajzbPxK0wPdZjf/ss18wmCBgVHheXEmyLCy0zaOnwhykSGKqR2 +AkI8AWEIf9keP6PwRx5Hj1VgzdHYNlQMq6f2IVd2E37NzOKJ3csdgqFtRSRz5YbJ +hh9wOj5VntnUYLvX9GXozl/nnn6pJCba1W5sX1QgfShE+061dZQV/1em5xcJk9H8 +oHgR3dGkfofHbyLNxP8KLy6eDGY7U/e6fiDHBlHB/QJmxZV4IlTp2MeP91i7qhqc +rqw2glsCQ5rXQg6HJWXmd3n/iBIt/wIDAQABAoICAQCb0z8o4WVc/UXkzvZ+3Hy+ +1itKp+whkECPEZ+QJiwXn85tR+LiwYBDD37M8E7BDvp7jpemMvv0+p4Q3wBDbphp +FAVRhk2JQKx+9DOelfiXVXPKGo2P9Poog4ooUeFDQ+NeeGZil1+3rWisOsLS1y7t +iQcg23D9AWGD08cy4GT7t4LWfA7Ld3ZauY/cvF+FyiA5UDva35hGbLRuGqoK11fU +ArVGkmaKvF/pcjQ38w6lf3DzoAfP5MmeDrKDB0nftC2QYJFTTsmBjUjwrgfeHaFq +2xG1Rr3FrnpsDsmgIYhV8lU6EU0Z68IJj2CBn8kv8tEi/F99s+iNiO6UY3R+XIdd +Jng5zPxHwprzKjvdfl6e4KhwkV8YJbPW0SFDj6Y0Ie0CdSysdJ8BhT7dk7LvJH1Q +DhQSAFftSna4MW5fzAogyQVL+KF3JnQ9BvFZX1swlIqBDHc6DeM+sFg0U++7qFyl +nZellskBgfLXlGCjgGEC/W5pUOaZzBk1BGa8x8Zm3vA//uaoOw/BKizfa+p0VqoU +bC4E8HEK+Rqj9oB07wVliqU9mCqrc5offhjeft9YbUAqx6GPG+1kPiKW1F4++iT2 +Yils/euv+gtK9d9JbMUCCH6mp1wIy40a14XisA8/O8NONjF63VTZX3try7rjOKxd +D0W68FGzACIkRkmTTc2NsQKCAQEAzKq7Lk/6cf2bzSQc0oH0XWxuA497czTQYj7l +k4UkGcUeEu9qOp3qU66KjmqLXLJnF233tQ2ArpiwX7tHNmhXZmIufNxa0Gue2VGx +eyRO/aTCnD1FsSayX1KcaLrwvg5gvwOPQLNCacMc47RCyI6/05irXfNtRlqKKm+R +ZgnhHxcwMzX5lLX9Rr54AWp0yuLEK+i0lcKsNnypAMl/C9GTqk3dEpao0y6SGHiW +Ih8Q2Cy4LbRD48PWuf9rBvb3iZyiLe0xemD8wuNN0j7/Xt9tcL4OuzkmkzWCyslM +Qi3yNw6eRziFhzdpDdHpJjFjEnGI94jgt1AYJtesFvSf8Tz7jQKCAQEAyAH7JQKx +mYvaRioAaUKQHiLImPxypt5cEGiyrPdiBBrU+3fBTC/EZJn/VK7ApM+7YRqvO/vz +d9orkvsWfzxpQM1xhBZ3bwTWXXWRz7g5vzKwJk4pZkXaUk+QAUwp79OrZFTcQokJ +d/l1wj5sUQCrs0l5gD5M3O6ZXPWLoSv1gBI7ktBxXY3VBrQ0uAwE9mQHjyrO+Utc +fcdFEtOqwOxyQQmcsj0vjGm385FmtuIG/pSzhvPXGyo3VYrQjTXT7pYnghu3LBgg +JJuE8kOAlSVTL0ccSO9GLqvj2bTyLlrFcKPBReXHNLwl5kij2w7WBTPGQn61u+ye ++bmSunIkjE2muwKCAQEAr/k4OcjAgJRbCpY7RfBAyLb7HIqYzWSiq2aDBEUc1h97 +DTLXNpEislLHhU4sh0ZJh4agzgZPF0/njlg7EZfDVh+i8u6QEtYF3br1C/kbBdFN +FwND0d6AzZ79JrtdVTyNiI8p86pttvvw8gPCzCiY3PlOltg/o5cjZvtIm+BwtMe+ +RLnq3ydfHx2TlzwOMYeqvko2QvIAGlUzBp85YlMPUQXjyCDMBc/sA6hjBfGKDSTe +M0XkfYicLo5jWrir+6E2fKCNwzhy+6pu9g/+iHc45RA1IFsyRK5kx7EupVRWB2rF +Ql1hyfIlnKFYguNB2NDPwG3rMRJnwbX8nDw27TfO3QKCAQEAlHAb82DnbFzGF3LO +sVBMY4FPPXOGp9+5lhgOG57SKNe9IBDF7gQ5jqxYOoIjyW2+1JeYXD1meZn64u/k +x3OPbh/LUsvVwhhl/CDoobBJc2RsJVG3GgdXu+T+rGfZa/u9ZQ4yFlNcKqWCxzHK +8+c6hypNuWcDZqjSO5KlGW3lmzJs8k4vBM7hvkL6KWoKOM8OaSvNRmmu8E53LjzX +qq0RMsGugP42DtDbTDKqd6qSpFi6ULsh9zBCtwL6OwMrEhRwp/hn3prdKC4f4ilF +Aewcq6bsEBk9DiBWT1oir1KA3FM8euLJEJNe0WUx7r85Cc1eJDWkLR+08QPQKP3T +sCllRwKCAQBQgSFFI65dlLJf/iJrZPuP3sCzZNABe4y7lxZK2Gij4FXzf2KA1SAl +dyxuUU+Hv98l52pJIWmoNYWKEXOorsu+TuadgiK11DSx/ajQ9y8OEbscOVTJwrv3 +aVbaz4f0z2AKRLrBLsln2aVLQVPF5dsPNmsYIUWOrvBJ+DFFeXQG+QWimS2VbS+P +wrDdpVej8sEaUVfCqvCAx8gWtrFtE401BmfNla1xFGHiHhcLrsqKj3uxIojQ0Met +fFCrKqxES0OQ6pY/9VlrBmfihw/Bt1LWMPUo90atFArbwGaUxXLwi4FwRafkW5Di +k77w3OGObcFv4zxCOoFxcXXc3MCyw3r8 +-----END PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_dsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_dsa new file mode 100644 index 0000000..d9c9b5b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_dsa @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQC3/2VIGHgqHuxvhPa6rryqqLy6sQmjeSIwyrIW5F/o8W4sz/mE +0noDSW4PaoXjgPQv5egj1EByws6dMOUqLaZHNWNn+Lh/jkKlwKyhbSCAjqoWH3v3 +uI1j58GO/eZ2+REijfyA0XJxdm7kqEexxbg0UpFr1F/eLBUxpLIbhhS1cwIVAKcB +B9DnAObuPJGTwYTCaIIBQDy9AoGAJicW0pIFwgoTYsIeywmUQopJ3FQ4M3eDwQ0U +T33pzWvBZFN2OsUDTFg64PNm9ow09wk042qMg168eKCUTp2iR/Y9R4xTj8dls8iv +aMGMZ/B32eURIjUREGiXYTyG1pfuB2znSvr/5pavhuz5yG9M0AJCiYiexdaQKO3N +oJp6T3ACgYEAsep79p4WljnawrJc928zGq6dLYjs+5apYhqx4vf2l3Z2u26VqVNG +i5zZkUzhWQYV3/qtEOpO43dyZTHW+d9L8ni6HbXFWRVx60WE+5WKkzkimHJ6gox2 +kDvOqPudiS34KJOCEYYLEnJmK8aUZBZzWFORXkN8QgA/h9ts8AU785UCFAVXZMWq +CteWCH2HzcY2x/65dMwL +-----END DSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_ecdsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_ecdsa new file mode 100644 index 0000000..036e3b6 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_ecdsa @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPMZuWP7fMsZeyC1XXVUALVebJOX7PTwmsPql9qG25SeoAoGCCqGSM49 +AwEHoUQDQgAEB/B6mC5lrekKPWfGEkKpnCk08+dRnzFUg2jUHpaIrOTt4jGdvq6T +yAN57asB+PYmFyVIpi35NcmicF18qX3ayg== +-----END EC PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa new file mode 100644 index 0000000..90a6f72 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDL0yFO4W4xbdrJk/i+CW3itPATvhRkS+x+gKmkdH739AqWYP6r +kTFAmFTw9gLJ/c2tN7ow0T0QUR9iUsv/3QzTuwsjBu0feo3CVxwMkaJTo5ks9XBo +OW0R3tyCcOLlAcQ1WjC7cv5Ifn4gXLLM+k8/y/m3u8ERtidNxbRqpQ/gPQIDAQAB +AoGABirSRC/ABNDdIOJQUXe5knWFGiPTPCGr+zvrZiV8PgZtV5WBvzE6e0jgsRXQ +icobMhWQla+PGHJL786vi4NlwuhwKcF7Pd908ofej1eeBOd1u/HQ/qsfxPdxI0zF +dcWPYgAOo9ydOMGcSx4v1zDIgFInELJzKbv64LJQD0/xhoUCQQD7KhJ7M8Nkwsr2 +iKCyWTFM2M8/VKltgaiSmsNKZETashk5tKOrM3EWX4RcB/DnvHe8VNyYpC6Sd1uQ +AHwPDfxDAkEAz7+7hDybH6Cfvmr8kUOlDXiJJWXp5lP37FLzMDU6a9wTKZFnh57F +e91zRmKlQTegFet93MXaFYljRkI+4lMpfwJBAPPLbNEF973Qjq4rBMDZbs9HDDRO ++35+AqD7dGC7X1Jg2bd3rf66GiU7ZgDm/GIUQK0gOlg31bT6AniO39zFGH0CQFBh +Yd9HR8nT7xrQ8EoQPzNYGNBUf0xz3rAcZCWZ4rHK48sojEMoBkbnputrzX7PU+xH +QlqCXuAIWVXc2dHd1WcCQQDIUJHPOsgeAfTLoRRRURp/m8zZ9IpbaPTyDstPVNYe +zARW3Oa/tzPqdO6NWaetCp17u7Kb6X9np7Vz17i/4KED +-----END RSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa.ppk b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa.ppk new file mode 100644 index 0000000..4504f18 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa.ppk @@ -0,0 +1,26 @@ +PuTTY-User-Key-File-2: ssh-rsa +Encryption: none +Comment: rsa-key-20150522 +Public-Lines: 6 +AAAAB3NzaC1yc2EAAAABJQAAAQB1quqP0rhl78NOLD4lj+1x5FGAqZ3aqo6GiEPz +KOaQmy86FuJMK0nHj3gUKTa/Kvaa+8PZyeu+uVseHg47YrynCOcJEEnpqvbArc8M +xMWuUnTUMrjvokGDOBBiQu4UAE4bybpgXkNHJfbrcDVgivmv3Ikn8PVIZ1rLBMLZ +6Lzn0rjPjFD0X4WqsAJW2SFiZnsjMZtVL2TWadNTyyfjjm2NCRBvd32VLohkSe9Q +BZBD6MW8YQyBKUnEF/7WNY0eehDVrfx1YqPOV1bDwFUhRaAYpLDLDR0KCAPvx7qb +8G5Cq0TIBsEr3H8ztNRcOTQoaKgn0T18M7cyS4ykoNLYW4Zx +Private-Lines: 14 +AAABACyF3DZraF3sBLXLjSL4MFSblHXfUHxAiPSiQzlpa/9dUCPRTrUJddzOgHZU +yJtcXU9mLm4VDRe7wZyxbSs6Hd5WZUGzIuLLEUH8k4hKdE/MLDSdkhV7qhX5iaij +tAeRaammRoVUGXTd7rnzGx2cXnnkvkZ22VmqkQ6MLg1DTmWNfOO9cdwFGdQawf/n +yUV0nTkWsHXy5Qrozq9wRFk8eyw+pFllxqavsNftZX8VDiQt27JLZPTU4LGkH660 +3gq1KhNS/l05TlXnMZGjlcPN8UEaBzmCWRezhJSttjs5Kgp1K3yDf4ozMR/HWOCj +Jq8fd3VIgli6ML8yjr/c0A0T9MUAAACBAL1/byxHiCvY/2C+/L5T+ZZq13jdZuYK +MmOFaNITgEdNGWSIFYRzhLKGXj7awQWOIW6chj470GNOfQjFL1TvXhbwfqW6esDa +kETOYQPYQHZijABcn7uurMUm/bu5x/z9gYkAfniOCI5vmvMvJ09JcZ0iUmFWDZZY +fAutBvrt+n/vAAAAgQCe9jrA51wn1/wzKmWF+2+OWFUG9usheIcEbHB8mxLguLfU ++x4i+2vLo0FtXEPAw+Bt7Tge4t0m6USiVZXtW/QKsh0kMj4mNVHFz+XXw4l1QOYv +n5TjnLepiP7majXv4GHI2eOcHkyly4sIkj4jNLYqvT86hMxW4IC+jtJEWhn/nwAA +AIEAlJ8cExu2WrWukTDJQHrVegtvdJUhNjol2wLucPuWwSxKuB8FHYwaPRYRkf3d +DkZ53hhjJZ0BVkAaQ28uqM09xKD+q1H4/r0nnbtlV4uHLl3cCD5mGrH8I/iDPJX4 +fFIqCa0+n1D6RzvDqs1QIu+PGSp0K6vHOOS5fP0ZpuT025E= +Private-MAC: 4ca26008c85b901f4d2766b0924c25e527678d7e diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa_enc new file mode 100644 index 0000000..75a1e95 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/id_rsa_enc @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,CCE70744FB28F2EFB1D74377281A780C + +1WiGnqpSGXFIg+WYr7T2XN72C1YrNQ1jmRISb32TB/Rh2Zo47fjyQnv9impz8b6m +91R/qF7uCLI0fswvT5oqwn1L0vUAA0YtW/E2IQJEx5GPiaexoDJYYfu2yy036Kca +e9VtCajgrV+kycg1CknCxQKMcKXNq8Czvq66PM4Bzknek5hhdmxHxOl0QAE+8EXt +pnasOGz3szTUKkD6givwWgvDXY3BnVG46fXff99Xqgb6fx5IDbAkVKaxWIN/c81E +b0rcfyoLb7yjPgNYn9vUI6Z+24NMYUYARzb3dG5geaeX0BYb/VlCtJUsP0Rp2P2P +jl+cdvBKaeOvA9gPo/jAtSOFexQRs7AzKzoOLYU1fokd8HhqxOKAljn9ujmEqif7 +qcimk2s7ff6tSSlxtRzDP+Uq9d1u5tyaONRV2lwj+GdP1gRoOmdZL5chdvoAi0I8 +5eMf58hEuN2d4h4FryO6z7K+XQ9oo6/N/xHU0U/t2Pco9oY2L6oWMDxKwbfPhaD5 +CcoEElsK4XFArYDielEq9Y1sXaEuwR5I0ksDDsANp74r9Bhcqz60gJa6hVz0ouEU +QA67wV9+TRmulKRxwANvqxQwqPuxqcTPeJjXSUN/ZCaDwYmI+d1poxMx2fQzT82M +onlgOWq+3HbCotyoeFpCameymwDQzmrYdMBr7oWLgnOrxmJ89zDc6+jkHFgQJvnU +atyeVDqe866ZvvIGWS+r/EsDjV3cTW/cJvdsC+5BpnoXoVF4LqxE3LFbEbQBvqio +4enCZpspQSMOJra37vSofbD+DyI5Wd+y8SBmfDLjyDFhT0spW9aN99uFqSc3UElA +SAmnFmpYBFEQrRGpvpu5sC0c/YjZeRXr0/F1xPpIT1SWzpRsbcsWRBDzWjLOKWQx +8ytwc2QS7eKedfqkPWpYKW0Qtps+XgnGWA6PBX42IYhLsKANRfhFXQv5LPqLNNOn +3EsG9pd+0dBpfxFQfyyAKAUuvpJNgJ6kNx8VSj8Ppj8lyUdGa9YucgB02m7gHC9U +A4YyJsIcjo6IcrjM+ez1govRRS0nE8AUb8ups9tn8mdBwqcPCrgcJhV7JkOYNJYh +NAh0vgmneOq8LSVs2SRaL3uuLNbjh1LR9iViwbIY8kMQXkiXa2/V+PFwt5oqeX5f +2x3yzCeGBiQW10InyBBnKutbPD85R4YJhQ55bOMDSFfGGqwOU1QURiO1NUzf9n/2 ++E8VE7J/IQoO0TrJpC+EV0ROKME9W6+AvEFdmdIigbq3bkdEgSixyLnrhV8V8T4N +nbKlLoqfXt8DmT+h8XPzgsu0Fq/PNi6xBaiUsaN9tK6OP2ZVjr9ihbeLTI0rcKDr +XX2cWPvTcboRLt+S4wmqchMf7Kxa2PfX5Tf+KCcdZNQO4YqS23wQZgk61kuOQCsS +uOop+ICI7yWZkjqCOzGOeHLl/7FyFeprsFDIwD1g20y9bzibbJlbQPhwXSalqDQT +MWLH3rdFuvgLH7ujtjxSakES+VzkOhbnmb/Wypbl1D7P7GT2seau16EEGQDhDzcJ +Q4d/BjR2WqqxmC79MOAvUWAu6fZQjPD30/gYPGpMaEuiLrDlzDqvf+oi4A9+EtRL +-----END RSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa new file mode 100644 index 0000000..a8722ab --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa @@ -0,0 +1,21 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH +NzAAAAgQDg+DsMAituSW/NJpWVy2w7xN6Uu/IfCqpy38CFBW+mBnOX7OzPulI+1uZxXRLy +UKiQDAegXCqSHMCo5ACZhw2BRwq74J4VA5fOFGdwcacTQo1zKDF64wvyVSgQE/E2PSFLKu +NHHtRFnjvq6WrgTQsL9aif2FBWS5q0MGahzXhNkQAAABUAn1ASRSRcIVsWqrrZubFQq4pU +OlMAAACBALcKIRLTtYG5+N/vzEULdsXSGToDRth6X5Yjb7c0UotAmy9VGrnmN5IO+//1em +2USHeSoO+5shRq92zdggdQwNaXXzU301huIETztfRwGHOfUGZbzJmIqdzLhdziFhneAzaN +zVeUFyIqvWL1Q89WgC2Uh3DY/lK/gIhRK7WD0cDAAAAAgC882WUEEig48DVyjbNi1xf8rG +svyypMHSs2rj6pja2Upfm+C5AKKU387x8Vj/Kz291ROIl7h/AhmKOlwdxwPZOG5ffDygaW +Tlo4/JagwP9HmTsK1Tyd1chuyMk9cNLdgWFsCGGHY2RcEwccq9panvvtKp57HqDaT1W7AS +g2spT9AAAB8G4oDW5uKA1uAAAAB3NzaC1kc3MAAACBAOD4OwwCK25Jb80mlZXLbDvE3pS7 +8h8KqnLfwIUFb6YGc5fs7M+6Uj7W5nFdEvJQqJAMB6BcKpIcwKjkAJmHDYFHCrvgnhUDl8 +4UZ3BxpxNCjXMoMXrjC/JVKBAT8TY9IUsq40ce1EWeO+rpauBNCwv1qJ/YUFZLmrQwZqHN +eE2RAAAAFQCfUBJFJFwhWxaqutm5sVCrilQ6UwAAAIEAtwohEtO1gbn43+/MRQt2xdIZOg +NG2HpfliNvtzRSi0CbL1UaueY3kg77//V6bZRId5Kg77myFGr3bN2CB1DA1pdfNTfTWG4g +RPO19HAYc59QZlvMmYip3MuF3OIWGd4DNo3NV5QXIiq9YvVDz1aALZSHcNj+Ur+AiFErtY +PRwMAAAACALzzZZQQSKDjwNXKNs2LXF/ysay/LKkwdKzauPqmNrZSl+b4LkAopTfzvHxWP +8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PKBpZOWjj8lqDA/0eZOwrVPJ3VyG7IyT1w0t2BYW +wIYYdjZFwTBxyr2lqe++0qnnseoNpPVbsBKDaylP0AAAAVAIoWASGAfFqckLwvtPRNCzow +TTl1AAAAEm5ldyBvcGVuc3NoIGZvcm1hdAECAwQFBgc= +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub new file mode 100644 index 0000000..d5b662d --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAOD4OwwCK25Jb80mlZXLbDvE3pS78h8KqnLfwIUFb6YGc5fs7M+6Uj7W5nFdEvJQqJAMB6BcKpIcwKjkAJmHDYFHCrvgnhUDl84UZ3BxpxNCjXMoMXrjC/JVKBAT8TY9IUsq40ce1EWeO+rpauBNCwv1qJ/YUFZLmrQwZqHNeE2RAAAAFQCfUBJFJFwhWxaqutm5sVCrilQ6UwAAAIEAtwohEtO1gbn43+/MRQt2xdIZOgNG2HpfliNvtzRSi0CbL1UaueY3kg77//V6bZRId5Kg77myFGr3bN2CB1DA1pdfNTfTWG4gRPO19HAYc59QZlvMmYip3MuF3OIWGd4DNo3NV5QXIiq9YvVDz1aALZSHcNj+Ur+AiFErtYPRwMAAAACALzzZZQQSKDjwNXKNs2LXF/ysay/LKkwdKzauPqmNrZSl+b4LkAopTfzvHxWP8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PKBpZOWjj8lqDA/0eZOwrVPJ3VyG7IyT1w0t2BYWwIYYdjZFwTBxyr2lqe++0qnnseoNpPVbsBKDaylP0= new openssh format diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result new file mode 100644 index 0000000..7b8d66e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "new openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtzCCASwGByqGSM44BAEwggEfAoGBAOD4OwwCK25Jb80mlZXLbDvE3pS78h8K\nqnLfwIUFb6YGc5fs7M+6Uj7W5nFdEvJQqJAMB6BcKpIcwKjkAJmHDYFHCrvgnhUD\nl84UZ3BxpxNCjXMoMXrjC/JVKBAT8TY9IUsq40ce1EWeO+rpauBNCwv1qJ/YUFZL\nmrQwZqHNeE2RAhUAn1ASRSRcIVsWqrrZubFQq4pUOlMCgYEAtwohEtO1gbn43+/M\nRQt2xdIZOgNG2HpfliNvtzRSi0CbL1UaueY3kg77//V6bZRId5Kg77myFGr3bN2C\nB1DA1pdfNTfTWG4gRPO19HAYc59QZlvMmYip3MuF3OIWGd4DNo3NV5QXIiq9YvVD\nz1aALZSHcNj+Ur+AiFErtYPRwMADgYQAAoGALzzZZQQSKDjwNXKNs2LXF/ysay/L\nKkwdKzauPqmNrZSl+b4LkAopTfzvHxWP8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PK\nBpZOWjj8lqDA/0eZOwrVPJ3VyG7IyT1w0t2BYWwIYYdjZFwTBxyr2lqe++0qnnse\noNpPVbsBKDaylP0=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAOD4OwwCK25Jb80mlZXLbDvE3pS78h8KqnLfwIUFb6YGc5fs7M+6Uj7W5nFdEvJQqJAMB6BcKpIcwKjkAJmHDYFHCrvgnhUDl84UZ3BxpxNCjXMoMXrjC/JVKBAT8TY9IUsq40ce1EWeO+rpauBNCwv1qJ/YUFZLmrQwZqHNeE2RAAAAFQCfUBJFJFwhWxaqutm5sVCrilQ6UwAAAIEAtwohEtO1gbn43+/MRQt2xdIZOgNG2HpfliNvtzRSi0CbL1UaueY3kg77//V6bZRId5Kg77myFGr3bN2CB1DA1pdfNTfTWG4gRPO19HAYc59QZlvMmYip3MuF3OIWGd4DNo3NV5QXIiq9YvVDz1aALZSHcNj+Ur+AiFErtYPRwMAAAACALzzZZQQSKDjwNXKNs2LXF/ysay/LKkwdKzauPqmNrZSl+b4LkAopTfzvHxWP8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PKBpZOWjj8lqDA/0eZOwrVPJ3VyG7IyT1w0t2BYWwIYYdjZFwTBxyr2lqe++0qnnseoNpPVbsBKDaylP0=", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result new file mode 100644 index 0000000..0d93248 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "new openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtzCCASwGByqGSM44BAEwggEfAoGBAOD4OwwCK25Jb80mlZXLbDvE3pS78h8K\nqnLfwIUFb6YGc5fs7M+6Uj7W5nFdEvJQqJAMB6BcKpIcwKjkAJmHDYFHCrvgnhUD\nl84UZ3BxpxNCjXMoMXrjC/JVKBAT8TY9IUsq40ce1EWeO+rpauBNCwv1qJ/YUFZL\nmrQwZqHNeE2RAhUAn1ASRSRcIVsWqrrZubFQq4pUOlMCgYEAtwohEtO1gbn43+/M\nRQt2xdIZOgNG2HpfliNvtzRSi0CbL1UaueY3kg77//V6bZRId5Kg77myFGr3bN2C\nB1DA1pdfNTfTWG4gRPO19HAYc59QZlvMmYip3MuF3OIWGd4DNo3NV5QXIiq9YvVD\nz1aALZSHcNj+Ur+AiFErtYPRwMADgYQAAoGALzzZZQQSKDjwNXKNs2LXF/ysay/L\nKkwdKzauPqmNrZSl+b4LkAopTfzvHxWP8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PK\nBpZOWjj8lqDA/0eZOwrVPJ3VyG7IyT1w0t2BYWwIYYdjZFwTBxyr2lqe++0qnnse\noNpPVbsBKDaylP0=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAOD4OwwCK25Jb80mlZXLbDvE3pS78h8KqnLfwIUFb6YGc5fs7M+6Uj7W5nFdEvJQqJAMB6BcKpIcwKjkAJmHDYFHCrvgnhUDl84UZ3BxpxNCjXMoMXrjC/JVKBAT8TY9IUsq40ce1EWeO+rpauBNCwv1qJ/YUFZLmrQwZqHNeE2RAAAAFQCfUBJFJFwhWxaqutm5sVCrilQ6UwAAAIEAtwohEtO1gbn43+/MRQt2xdIZOgNG2HpfliNvtzRSi0CbL1UaueY3kg77//V6bZRId5Kg77myFGr3bN2CB1DA1pdfNTfTWG4gRPO19HAYc59QZlvMmYip3MuF3OIWGd4DNo3NV5QXIiq9YvVDz1aALZSHcNj+Ur+AiFErtYPRwMAAAACALzzZZQQSKDjwNXKNs2LXF/ysay/LKkwdKzauPqmNrZSl+b4LkAopTfzvHxWP8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PKBpZOWjj8lqDA/0eZOwrVPJ3VyG7IyT1w0t2BYWwIYYdjZFwTBxyr2lqe++0qnnseoNpPVbsBKDaylP0=", + "private": "-----BEGIN DSA PRIVATE KEY-----\nMIIBvAIBAAKBgQDg+DsMAituSW/NJpWVy2w7xN6Uu/IfCqpy38CFBW+mBnOX7OzP\nulI+1uZxXRLyUKiQDAegXCqSHMCo5ACZhw2BRwq74J4VA5fOFGdwcacTQo1zKDF6\n4wvyVSgQE/E2PSFLKuNHHtRFnjvq6WrgTQsL9aif2FBWS5q0MGahzXhNkQIVAJ9Q\nEkUkXCFbFqq62bmxUKuKVDpTAoGBALcKIRLTtYG5+N/vzEULdsXSGToDRth6X5Yj\nb7c0UotAmy9VGrnmN5IO+//1em2USHeSoO+5shRq92zdggdQwNaXXzU301huIETz\ntfRwGHOfUGZbzJmIqdzLhdziFhneAzaNzVeUFyIqvWL1Q89WgC2Uh3DY/lK/gIhR\nK7WD0cDAAoGALzzZZQQSKDjwNXKNs2LXF/ysay/LKkwdKzauPqmNrZSl+b4LkAop\nTfzvHxWP8rPb3VE4iXuH8CGYo6XB3HA9k4bl98PKBpZOWjj8lqDA/0eZOwrVPJ3V\nyG7IyT1w0t2BYWwIYYdjZFwTBxyr2lqe++0qnnseoNpPVbsBKDaylP0CFQCKFgEh\ngHxanJC8L7T0TQs6ME05dQ==\n-----END DSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc new file mode 100644 index 0000000..392f214 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc @@ -0,0 +1,22 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBgJ5gXYn +/2IFE2+CrAxYR8AAAAEAAAAAEAAAGxAAAAB3NzaC1kc3MAAACBAPKhVnFGWb0KLibdYnJz +0RwFy/mt98KMIdByHKQWRm9UjoVJk1ypuQpnj+bqFnxCzCFSU9OUj0/Xe0Wuk+kF2BtMO0 +w+ZYfVHCqEaaIJ1D/iLqi8aBbYs552l9+P0DsFUlTE0D/AvKTQ2PsztFq7wHUTQVmnj4vy +k1bw7ske+ImLAAAAFQDnXsk6hdenasLyE8ylLHSE+0XR3QAAAIBsMerhmMT0/416hJV/pr +s7crOX0e0gF8C7kar/ILj5WULX7k143+4lgluoogrPXbd5fXgOnqdQawow8a/IjU62Sz6n +/qfHLJtQ2sJOK2Vkj5NF2UCcRHrewqJw9nDCS7yYh3c+gUfIBcIRkEJK6eRJfrZuaq0Yue +nUa9AuFwnjPAAAAIBwjDUjp9jaJu46eobNK8CWJL/Noi2fXTtFZFgUFRwkr/FXLLsOckQT +mYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuCx6dIgiOf2gRClQU5OlqhrnMW2BQXlR +hBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/C2XBGgEuRdgyqQAAAgDIGP0oYyi7sTk0HdU9 +uWZLaDhHpW4Z8xTzfgUDbxoTYQ2igO90O32vSqW/cC2QKWTFuPCFnsCerHAIGzX/eyxlCQ +VyNa7VrhbNjIKAHBF3XMcRVRbW2SdYq8tHSkeZHr5EuO5dRfJ7wsR8flkPb4O4viNlIbvF +Ake8dsZEOhcnVNiv+NMR9mTq8l91wR60tr3XiWzCMkEYrJiWOfQuZSvzYi7dUmFxQuEZfQ +vIPkZD3L6XdaAz/r6YAONFAbtUMAOaUxOGV9puSsunSosAvmi+NcJ9iUM2FpAu561gp+Tv +RRcgXHxLGuzTNASiMaTN3M+HenqUh3RWmWauL5wSR7DbrH7Vq47YTnVjtg8xcZnMCfOx2D +Wz775hD6uyLwbkxKMaNMf8p4sOcXsSpHNqKmfkUxQBpNRp6Vg5W+AVaAkyXQng2LRt6txJ +Xv5zBiSFdsobkrWko/ONfGKfG+zVP+LIVcghLpp71GZQX6Ci02vB55pvk8k0G91H3INn/c +t6Q5zY5pK9VZwxjZ29psm7V+FdeD1g8VQ1Rp9muq6zDXHKKyqkBK/oGCM9UhBHFjki0gBR +v6LY/iXsz/eG14svhLjM5zYFSX7jUOI9b/PnhhL7Mos4wguHN2EjfGWuC07PkkqDPoqSwn +cC91OKhub6yqZsqvBz9BcV+2FxVNPNKzRdzA== +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub new file mode 100644 index 0000000..c2b1190 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAPKhVnFGWb0KLibdYnJz0RwFy/mt98KMIdByHKQWRm9UjoVJk1ypuQpnj+bqFnxCzCFSU9OUj0/Xe0Wuk+kF2BtMO0w+ZYfVHCqEaaIJ1D/iLqi8aBbYs552l9+P0DsFUlTE0D/AvKTQ2PsztFq7wHUTQVmnj4vyk1bw7ske+ImLAAAAFQDnXsk6hdenasLyE8ylLHSE+0XR3QAAAIBsMerhmMT0/416hJV/prs7crOX0e0gF8C7kar/ILj5WULX7k143+4lgluoogrPXbd5fXgOnqdQawow8a/IjU62Sz6n/qfHLJtQ2sJOK2Vkj5NF2UCcRHrewqJw9nDCS7yYh3c+gUfIBcIRkEJK6eRJfrZuaq0YuenUa9AuFwnjPAAAAIBwjDUjp9jaJu46eobNK8CWJL/Noi2fXTtFZFgUFRwkr/FXLLsOckQTmYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuCx6dIgiOf2gRClQU5OlqhrnMW2BQXlRhBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/C2XBGgEuRdgyqQ== diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result new file mode 100644 index 0000000..d15133a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtjCCASsGByqGSM44BAEwggEeAoGBAPKhVnFGWb0KLibdYnJz0RwFy/mt98KM\nIdByHKQWRm9UjoVJk1ypuQpnj+bqFnxCzCFSU9OUj0/Xe0Wuk+kF2BtMO0w+ZYfV\nHCqEaaIJ1D/iLqi8aBbYs552l9+P0DsFUlTE0D/AvKTQ2PsztFq7wHUTQVmnj4vy\nk1bw7ske+ImLAhUA517JOoXXp2rC8hPMpSx0hPtF0d0CgYBsMerhmMT0/416hJV/\nprs7crOX0e0gF8C7kar/ILj5WULX7k143+4lgluoogrPXbd5fXgOnqdQawow8a/I\njU62Sz6n/qfHLJtQ2sJOK2Vkj5NF2UCcRHrewqJw9nDCS7yYh3c+gUfIBcIRkEJK\n6eRJfrZuaq0YuenUa9AuFwnjPAOBhAACgYBwjDUjp9jaJu46eobNK8CWJL/Noi2f\nXTtFZFgUFRwkr/FXLLsOckQTmYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuC\nx6dIgiOf2gRClQU5OlqhrnMW2BQXlRhBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/\nC2XBGgEuRdgyqQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAPKhVnFGWb0KLibdYnJz0RwFy/mt98KMIdByHKQWRm9UjoVJk1ypuQpnj+bqFnxCzCFSU9OUj0/Xe0Wuk+kF2BtMO0w+ZYfVHCqEaaIJ1D/iLqi8aBbYs552l9+P0DsFUlTE0D/AvKTQ2PsztFq7wHUTQVmnj4vyk1bw7ske+ImLAAAAFQDnXsk6hdenasLyE8ylLHSE+0XR3QAAAIBsMerhmMT0/416hJV/prs7crOX0e0gF8C7kar/ILj5WULX7k143+4lgluoogrPXbd5fXgOnqdQawow8a/IjU62Sz6n/qfHLJtQ2sJOK2Vkj5NF2UCcRHrewqJw9nDCS7yYh3c+gUfIBcIRkEJK6eRJfrZuaq0YuenUa9AuFwnjPAAAAIBwjDUjp9jaJu46eobNK8CWJL/Noi2fXTtFZFgUFRwkr/FXLLsOckQTmYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuCx6dIgiOf2gRClQU5OlqhrnMW2BQXlRhBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/C2XBGgEuRdgyqQ==", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result new file mode 100644 index 0000000..2271c47 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "new openssh format encrypted", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtjCCASsGByqGSM44BAEwggEeAoGBAPKhVnFGWb0KLibdYnJz0RwFy/mt98KM\nIdByHKQWRm9UjoVJk1ypuQpnj+bqFnxCzCFSU9OUj0/Xe0Wuk+kF2BtMO0w+ZYfV\nHCqEaaIJ1D/iLqi8aBbYs552l9+P0DsFUlTE0D/AvKTQ2PsztFq7wHUTQVmnj4vy\nk1bw7ske+ImLAhUA517JOoXXp2rC8hPMpSx0hPtF0d0CgYBsMerhmMT0/416hJV/\nprs7crOX0e0gF8C7kar/ILj5WULX7k143+4lgluoogrPXbd5fXgOnqdQawow8a/I\njU62Sz6n/qfHLJtQ2sJOK2Vkj5NF2UCcRHrewqJw9nDCS7yYh3c+gUfIBcIRkEJK\n6eRJfrZuaq0YuenUa9AuFwnjPAOBhAACgYBwjDUjp9jaJu46eobNK8CWJL/Noi2f\nXTtFZFgUFRwkr/FXLLsOckQTmYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuC\nx6dIgiOf2gRClQU5OlqhrnMW2BQXlRhBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/\nC2XBGgEuRdgyqQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAPKhVnFGWb0KLibdYnJz0RwFy/mt98KMIdByHKQWRm9UjoVJk1ypuQpnj+bqFnxCzCFSU9OUj0/Xe0Wuk+kF2BtMO0w+ZYfVHCqEaaIJ1D/iLqi8aBbYs552l9+P0DsFUlTE0D/AvKTQ2PsztFq7wHUTQVmnj4vyk1bw7ske+ImLAAAAFQDnXsk6hdenasLyE8ylLHSE+0XR3QAAAIBsMerhmMT0/416hJV/prs7crOX0e0gF8C7kar/ILj5WULX7k143+4lgluoogrPXbd5fXgOnqdQawow8a/IjU62Sz6n/qfHLJtQ2sJOK2Vkj5NF2UCcRHrewqJw9nDCS7yYh3c+gUfIBcIRkEJK6eRJfrZuaq0YuenUa9AuFwnjPAAAAIBwjDUjp9jaJu46eobNK8CWJL/Noi2fXTtFZFgUFRwkr/FXLLsOckQTmYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuCx6dIgiOf2gRClQU5OlqhrnMW2BQXlRhBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/C2XBGgEuRdgyqQ==", + "private": "-----BEGIN DSA PRIVATE KEY-----\nMIIBugIBAAKBgQDyoVZxRlm9Ci4m3WJyc9EcBcv5rffCjCHQchykFkZvVI6FSZNc\nqbkKZ4/m6hZ8QswhUlPTlI9P13tFrpPpBdgbTDtMPmWH1RwqhGmiCdQ/4i6ovGgW\n2LOedpffj9A7BVJUxNA/wLyk0Nj7M7Rau8B1E0FZp4+L8pNW8O7JHviJiwIVAOde\nyTqF16dqwvITzKUsdIT7RdHdAoGAbDHq4ZjE9P+NeoSVf6a7O3Kzl9HtIBfAu5Gq\n/yC4+VlC1+5NeN/uJYJbqKIKz123eX14Dp6nUGsKMPGvyI1Otks+p/6nxyybUNrC\nTitlZI+TRdlAnER63sKicPZwwku8mId3PoFHyAXCEZBCSunkSX62bmqtGLnp1GvQ\nLhcJ4zwCgYBwjDUjp9jaJu46eobNK8CWJL/Noi2fXTtFZFgUFRwkr/FXLLsOckQT\nmYxaWcxP4NwuvMyI25tOueM0RvAIR7J3Afc5pbuCx6dIgiOf2gRClQU5OlqhrnMW\n2BQXlRhBKBNMp5LjM5t46KTBkjh/30//s4Kimrp/C2XBGgEuRdgyqQIUSNLlRVPv\nMC3Q3P3ajY1DdZvi9z8=\n-----END DSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm new file mode 100644 index 0000000..38566b4 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm @@ -0,0 +1,23 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAFmFlczEyOC1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA +AAGAAAABD01pNY1+DTCAHuI6mcjB0YAAAAEAAAAAEAAAGyAAAAB3NzaC1kc3MAAACBAPLA +N0jFExSJiCvw7p2W2v5tqvXIG4YwCglrl2wnGOMBGmfaeIcxZErzW00hOxq+NvDIlK43kJ +iP98Vz0XTHIW6DpkE9DcC5GGA6nDZn9L+BSrBL8NhuBlz2ekgWOTCqnDC7Il/iyUCMi79s +ZPOEg/bMExWJlB5AosJr7v5twVftAAAAFQC5AGsioHKAc2Cd2QwKLUZSmDZAVwAAAIBxYf +EThMIXPQkSer3snKJfDz0uvc1y/6htsjXLk93TAAi3LSD2dGqYs5s0WfzO4RnFso0EovrL +OnIbqU1XApr6CPKAVX2REsXFWWF3VixEHIEF1Q9gIvHdYgAxSxtwYvOPpAwDmaPxWeV5/q +MsMu2RSKkK6f08J0vsESnKU4nmnwAAAIEAxH8NZyntzihIAHnx1Lbo7h1sPi4RhcpKK5pS +UiaKoWxkjseqUsyWENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3qhq/B3bspx1GWjL +qLfKbeVi4un8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi7GdZG8Q0tuyfXxsAAAIA +PDupGK4wMtROtFZqo7vduzkHJuDrE/tAwGqiD2pKMova7WaKM0EUznwcl3gtmhHvFeY+NJ +3Uc9sQcX/9n3y6NAYsC+eZeqe7Sy2GWVyqxOUJHpZqfsKYJidG61TBgKgx+JXAeidYdz4L +4cEapwwocOptbY3ZRFmszekq5xPomnkP9DeSQG6l4eYSv7OpeAHlFj2KCmJMVEZDOl6RyJ +KCqOpfEJIIVoCmna/hQdd9ptLVFmbX/VShgLjvUwfBggJtZNPb5jx+PMy+I0ylywaCIG5K +JQAqust6dzFBx3mBoO4kZPBHlb8XwQ4HYLYph0Ur/lINsHrpLxgmtEw7zzs73Nshl6go2V +uvBtcZ5ywAMk+8CLP5ZgpiGBxlMtFGowp/5zuJxRpc9FgdfxnnVWDyzcQ/YvX9lwzb6cNz +bXeLPsKjOSLPV7G/RFIiuCAOa97ZCM8Ho4FhdNYOGilmjuxV7FJiTc7KP2r+Wh3oxsV7AB +Q6Thj06b2mX3iE4hqLaMKIVE1zs22nMlUtFJv8YY1ZWBihUVlnR9vWgIH7ODoZOwNWBlLd +Qfyfi8w3KgJWj5oVNAM7WniNFQjfNxEbrPklfYg93deVE/LhPghs9I7fsIeHY/p8GtsO/S +amTcjkYi6pUuT8m7IeFYQ8cWvGnbaYz6/9+ni+0aoUL93GKHQw1+mBUVuswVZXBF1WVCf+ +LMgZ +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub new file mode 100644 index 0000000..d9eb1a5 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAPLAN0jFExSJiCvw7p2W2v5tqvXIG4YwCglrl2wnGOMBGmfaeIcxZErzW00hOxq+NvDIlK43kJiP98Vz0XTHIW6DpkE9DcC5GGA6nDZn9L+BSrBL8NhuBlz2ekgWOTCqnDC7Il/iyUCMi79sZPOEg/bMExWJlB5AosJr7v5twVftAAAAFQC5AGsioHKAc2Cd2QwKLUZSmDZAVwAAAIBxYfEThMIXPQkSer3snKJfDz0uvc1y/6htsjXLk93TAAi3LSD2dGqYs5s0WfzO4RnFso0EovrLOnIbqU1XApr6CPKAVX2REsXFWWF3VixEHIEF1Q9gIvHdYgAxSxtwYvOPpAwDmaPxWeV5/qMsMu2RSKkK6f08J0vsESnKU4nmnwAAAIEAxH8NZyntzihIAHnx1Lbo7h1sPi4RhcpKK5pSUiaKoWxkjseqUsyWENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3qhq/B3bspx1GWjLqLfKbeVi4un8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi7GdZG8Q0tuyfXxs= diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result new file mode 100644 index 0000000..6a918a8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtzCCASsGByqGSM44BAEwggEeAoGBAPLAN0jFExSJiCvw7p2W2v5tqvXIG4Yw\nCglrl2wnGOMBGmfaeIcxZErzW00hOxq+NvDIlK43kJiP98Vz0XTHIW6DpkE9DcC5\nGGA6nDZn9L+BSrBL8NhuBlz2ekgWOTCqnDC7Il/iyUCMi79sZPOEg/bMExWJlB5A\nosJr7v5twVftAhUAuQBrIqBygHNgndkMCi1GUpg2QFcCgYBxYfEThMIXPQkSer3s\nnKJfDz0uvc1y/6htsjXLk93TAAi3LSD2dGqYs5s0WfzO4RnFso0EovrLOnIbqU1X\nApr6CPKAVX2REsXFWWF3VixEHIEF1Q9gIvHdYgAxSxtwYvOPpAwDmaPxWeV5/qMs\nMu2RSKkK6f08J0vsESnKU4nmnwOBhQACgYEAxH8NZyntzihIAHnx1Lbo7h1sPi4R\nhcpKK5pSUiaKoWxkjseqUsyWENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3q\nhq/B3bspx1GWjLqLfKbeVi4un8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi\n7GdZG8Q0tuyfXxs=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAPLAN0jFExSJiCvw7p2W2v5tqvXIG4YwCglrl2wnGOMBGmfaeIcxZErzW00hOxq+NvDIlK43kJiP98Vz0XTHIW6DpkE9DcC5GGA6nDZn9L+BSrBL8NhuBlz2ekgWOTCqnDC7Il/iyUCMi79sZPOEg/bMExWJlB5AosJr7v5twVftAAAAFQC5AGsioHKAc2Cd2QwKLUZSmDZAVwAAAIBxYfEThMIXPQkSer3snKJfDz0uvc1y/6htsjXLk93TAAi3LSD2dGqYs5s0WfzO4RnFso0EovrLOnIbqU1XApr6CPKAVX2REsXFWWF3VixEHIEF1Q9gIvHdYgAxSxtwYvOPpAwDmaPxWeV5/qMsMu2RSKkK6f08J0vsESnKU4nmnwAAAIEAxH8NZyntzihIAHnx1Lbo7h1sPi4RhcpKK5pSUiaKoWxkjseqUsyWENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3qhq/B3bspx1GWjLqLfKbeVi4un8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi7GdZG8Q0tuyfXxs=", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result new file mode 100644 index 0000000..27ae40b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "new openssh format encrypted gcm", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtzCCASsGByqGSM44BAEwggEeAoGBAPLAN0jFExSJiCvw7p2W2v5tqvXIG4Yw\nCglrl2wnGOMBGmfaeIcxZErzW00hOxq+NvDIlK43kJiP98Vz0XTHIW6DpkE9DcC5\nGGA6nDZn9L+BSrBL8NhuBlz2ekgWOTCqnDC7Il/iyUCMi79sZPOEg/bMExWJlB5A\nosJr7v5twVftAhUAuQBrIqBygHNgndkMCi1GUpg2QFcCgYBxYfEThMIXPQkSer3s\nnKJfDz0uvc1y/6htsjXLk93TAAi3LSD2dGqYs5s0WfzO4RnFso0EovrLOnIbqU1X\nApr6CPKAVX2REsXFWWF3VixEHIEF1Q9gIvHdYgAxSxtwYvOPpAwDmaPxWeV5/qMs\nMu2RSKkK6f08J0vsESnKU4nmnwOBhQACgYEAxH8NZyntzihIAHnx1Lbo7h1sPi4R\nhcpKK5pSUiaKoWxkjseqUsyWENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3q\nhq/B3bspx1GWjLqLfKbeVi4un8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi\n7GdZG8Q0tuyfXxs=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAPLAN0jFExSJiCvw7p2W2v5tqvXIG4YwCglrl2wnGOMBGmfaeIcxZErzW00hOxq+NvDIlK43kJiP98Vz0XTHIW6DpkE9DcC5GGA6nDZn9L+BSrBL8NhuBlz2ekgWOTCqnDC7Il/iyUCMi79sZPOEg/bMExWJlB5AosJr7v5twVftAAAAFQC5AGsioHKAc2Cd2QwKLUZSmDZAVwAAAIBxYfEThMIXPQkSer3snKJfDz0uvc1y/6htsjXLk93TAAi3LSD2dGqYs5s0WfzO4RnFso0EovrLOnIbqU1XApr6CPKAVX2REsXFWWF3VixEHIEF1Q9gIvHdYgAxSxtwYvOPpAwDmaPxWeV5/qMsMu2RSKkK6f08J0vsESnKU4nmnwAAAIEAxH8NZyntzihIAHnx1Lbo7h1sPi4RhcpKK5pSUiaKoWxkjseqUsyWENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3qhq/B3bspx1GWjLqLfKbeVi4un8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi7GdZG8Q0tuyfXxs=", + "private": "-----BEGIN DSA PRIVATE KEY-----\nMIIBuwIBAAKBgQDywDdIxRMUiYgr8O6dltr+bar1yBuGMAoJa5dsJxjjARpn2niH\nMWRK81tNITsavjbwyJSuN5CYj/fFc9F0xyFug6ZBPQ3AuRhgOpw2Z/S/gUqwS/DY\nbgZc9npIFjkwqpwwuyJf4slAjIu/bGTzhIP2zBMViZQeQKLCa+7+bcFX7QIVALkA\nayKgcoBzYJ3ZDAotRlKYNkBXAoGAcWHxE4TCFz0JEnq97JyiXw89Lr3Ncv+obbI1\ny5Pd0wAIty0g9nRqmLObNFn8zuEZxbKNBKL6yzpyG6lNVwKa+gjygFV9kRLFxVlh\nd1YsRByBBdUPYCLx3WIAMUsbcGLzj6QMA5mj8Vnlef6jLDLtkUipCun9PCdL7BEp\nylOJ5p8CgYEAxH8NZyntzihIAHnx1Lbo7h1sPi4RhcpKK5pSUiaKoWxkjseqUsyW\nENt6DTByIdGhBNrOp9/vw2R5CSUkxuI0TlI8bj3qhq/B3bspx1GWjLqLfKbeVi4u\nn8CrooRRq2g8+nYLu2EWbF/56pEEzws6DptlDJQi7GdZG8Q0tuyfXxsCFG8ERflm\nOIBFUymTHP8ZeVOgNm/1\n-----END DSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa new file mode 100644 index 0000000..114e078 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTjIb0On/AzYDLFRi+g3fGdAIF72KFG +iZBpP8oKZ8bsncH9ULtVV9517cNcRNuDETQtvLqoCdIn7TipYo8Jv/lKAAAAsA6ULqEOlC +6hAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOMhvQ6f8DNgMsVG +L6Dd8Z0AgXvYoUaJkGk/ygpnxuydwf1Qu1VX3nXtw1xE24MRNC28uqgJ0iftOKlijwm/+U +oAAAAfVd3jjve28r7FhY6Uo//cKIM1rBeWZG16b8bjyVyFswAAABJuZXcgb3BlbnNzaCBm +b3JtYXQBAgMEBQYH +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub new file mode 100644 index 0000000..8ebee0f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOMhvQ6f8DNgMsVGL6Dd8Z0AgXvYoUaJkGk/ygpnxuydwf1Qu1VX3nXtw1xE24MRNC28uqgJ0iftOKlijwm/+Uo= new openssh format diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result new file mode 100644 index 0000000..b430d73 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "new openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4yG9Dp/wM2AyxUYvoN3xnQCBe9ih\nRomQaT/KCmfG7J3B/VC7VVfede3DXETbgxE0Lby6qAnSJ+04qWKPCb/5Sg==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOMhvQ6f8DNgMsVGL6Dd8Z0AgXvYoUaJkGk/ygpnxuydwf1Qu1VX3nXtw1xE24MRNC28uqgJ0iftOKlijwm/+Uo=", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result new file mode 100644 index 0000000..4affa3e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "new openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4yG9Dp/wM2AyxUYvoN3xnQCBe9ih\nRomQaT/KCmfG7J3B/VC7VVfede3DXETbgxE0Lby6qAnSJ+04qWKPCb/5Sg==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOMhvQ6f8DNgMsVGL6Dd8Z0AgXvYoUaJkGk/ygpnxuydwf1Qu1VX3nXtw1xE24MRNC28uqgJ0iftOKlijwm/+Uo=", + "private": "-----BEGIN EC PRIVATE KEY-----\nMHYCAQEEH1Xd4473tvK+xYWOlKP/3CiDNawXlmRtem/G48lchbOgCgYIKoZIzj0D\nAQehRANCAATjIb0On/AzYDLFRi+g3fGdAIF72KFGiZBpP8oKZ8bsncH9ULtVV951\n7cNcRNuDETQtvLqoCdIn7TipYo8Jv/lK\n-----END EC PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc new file mode 100644 index 0000000..08fe2d1 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc @@ -0,0 +1,10 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBqNbb13W +CKfO7B1vpwJDwbAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz +dHAyNTYAAABBBJibjz7zvP/EhMZrW/JDdKvYgiEATNUKMfg2NOVxKlf++eTRypLFc1doTp +r+04Ebm1fkyp8RgpFsmvLXLt/dKU0AAADA86k3lHnP6pfD977mwEtKxHOJm44wx8NsdBwN +mNLqxlxUE520nsXjDgpgNU0MF9JDnc1kdhSy8PcdTAAH5+k6bpf3gotPrltPUBMFQdPqst +5kVS7zOgaxv1qZnlyhOqEdNR3Hee09gJByRrAojtcs+sPI7Nba879NPMb5c5K+gKhONHsa +wLAnz66eFQH5iLjd2MwrV4gJe0x6NGCSI2kyzNlxFsoIl7IcHlJHyyuaSlEOFWQJB8cbB4 +BVZB+/8yAx +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub new file mode 100644 index 0000000..3d87cb2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJibjz7zvP/EhMZrW/JDdKvYgiEATNUKMfg2NOVxKlf++eTRypLFc1doTpr+04Ebm1fkyp8RgpFsmvLXLt/dKU0= diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result new file mode 100644 index 0000000..dcca403 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmJuPPvO8/8SExmtb8kN0q9iCIQBM\n1Qox+DY05XEqV/755NHKksVzV2hOmv7TgRubV+TKnxGCkWya8tcu390pTQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJibjz7zvP/EhMZrW/JDdKvYgiEATNUKMfg2NOVxKlf++eTRypLFc1doTpr+04Ebm1fkyp8RgpFsmvLXLt/dKU0=", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result new file mode 100644 index 0000000..9fe2c73 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "new openssh format encrypted", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmJuPPvO8/8SExmtb8kN0q9iCIQBM\n1Qox+DY05XEqV/755NHKksVzV2hOmv7TgRubV+TKnxGCkWya8tcu390pTQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJibjz7zvP/EhMZrW/JDdKvYgiEATNUKMfg2NOVxKlf++eTRypLFc1doTpr+04Ebm1fkyp8RgpFsmvLXLt/dKU0=", + "private": "-----BEGIN EC PRIVATE KEY-----\nMHgCAQEEIQDG2nALLBBmkBnw1QvdW4ClRfF3Zl3CcRHujsYz9CLvf6AKBggqhkjO\nPQMBB6FEA0IABJibjz7zvP/EhMZrW/JDdKvYgiEATNUKMfg2NOVxKlf++eTRypLF\nc1doTpr+04Ebm1fkyp8RgpFsmvLXLt/dKU0=\n-----END EC PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm new file mode 100644 index 0000000..84178ba --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm @@ -0,0 +1,10 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAFmFlczEyOC1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA +AAGAAAABAHURyWtYwqVbjholNpL6opAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlz +dHAyNTYAAAAIbmlzdHAyNTYAAABBBM+ppawNxvkdHbOaB3ygsRueTdIKiT+OQkAH/5LpDx +XcD6i5AR8T/vrCsZ9/y+8GxU8gmvg4Uszr6LDfaQBZnsUAAADAFqKM/ylVkJ/ZA40ZROrW +LNgrttf2+lpVkADwXWzhuESFPPzERKlbHVsVtbiiYmPkLnY1s5VM4zXIj7xyO9YNA9KcM5 +GHOKUL2/NmDaTyGgc9s3BGu/ibpjSeOd1rtGAB4cw1s9ifbXBQd3qDbqzaEmovs3MGaGHD +c3VagdxhsppjrPjZ+B40Pzs9QkSGutsSJDpH9wVIu4OLr89TquTU3PVACDRU03lPPENVbt +rh2IMJeEQyNINQHtfVwordj8LMOEsBjyQ1aqHNva/iKyTBiw== +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub new file mode 100644 index 0000000..61b0b99 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM+ppawNxvkdHbOaB3ygsRueTdIKiT+OQkAH/5LpDxXcD6i5AR8T/vrCsZ9/y+8GxU8gmvg4Uszr6LDfaQBZnsU= diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result new file mode 100644 index 0000000..1078648 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEz6mlrA3G+R0ds5oHfKCxG55N0gqJ\nP45CQAf/kukPFdwPqLkBHxP++sKxn3/L7wbFTyCa+DhSzOvosN9pAFmexQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM+ppawNxvkdHbOaB3ygsRueTdIKiT+OQkAH/5LpDxXcD6i5AR8T/vrCsZ9/y+8GxU8gmvg4Uszr6LDfaQBZnsU=", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result new file mode 100644 index 0000000..626aedf --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "new openssh format encrypted gcm", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEz6mlrA3G+R0ds5oHfKCxG55N0gqJ\nP45CQAf/kukPFdwPqLkBHxP++sKxn3/L7wbFTyCa+DhSzOvosN9pAFmexQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM+ppawNxvkdHbOaB3ygsRueTdIKiT+OQkAH/5LpDxXcD6i5AR8T/vrCsZ9/y+8GxU8gmvg4Uszr6LDfaQBZnsU=", + "private": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIHQfJ+4ZNcwSBaCR5kwrR6HjUsTF//R1F983RSTR8vbJoAoGCCqGSM49\nAwEHoUQDQgAEz6mlrA3G+R0ds5oHfKCxG55N0gqJP45CQAf/kukPFdwPqLkBHxP+\n+sKxn3/L7wbFTyCa+DhSzOvosN9pAFmexQ==\n-----END EC PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 new file mode 100644 index 0000000..7ae3165 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCyOMGts0WaAdug9NeXbGn2Jrt4wwiO64dumxV2a1IgKQAAAJBOfs+eTn7P +ngAAAAtzc2gtZWQyNTUxOQAAACCyOMGts0WaAdug9NeXbGn2Jrt4wwiO64dumxV2a1IgKQ +AAAEBgQKxJoToGE/Xi4UkYR+FXfin4jG8NTcZ13rJ4CDnCfLI4wa2zRZoB26D015dsafYm +u3jDCI7rh26bFXZrUiApAAAAB3Rlc3RpbmcBAgMEBQY= +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub new file mode 100644 index 0000000..c85c7d1 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILI4wa2zRZoB26D015dsafYmu3jDCI7rh26bFXZrUiAp testing diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result new file mode 100644 index 0000000..3c9ca29 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-ed25519", + "comment": "testing", + "public": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAsjjBrbNFmgHboPTXl2xp9ia7eMMIjuuHbpsVdmtSICk=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAC3NzaC1lZDI1NTE5AAAAILI4wa2zRZoB26D015dsafYmu3jDCI7rh26bFXZrUiAp", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result new file mode 100644 index 0000000..705fa99 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-ed25519", + "comment": "testing", + "public": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAsjjBrbNFmgHboPTXl2xp9ia7eMMIjuuHbpsVdmtSICk=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAC3NzaC1lZDI1NTE5AAAAILI4wa2zRZoB26D015dsafYmu3jDCI7rh26bFXZrUiAp", + "private": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIGBArEmhOgYT9eLhSRhH4Vd+KfiMbw1NxnXesngIOcJ8\n-----END PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa new file mode 100644 index 0000000..ccded2a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEA4q6eZdx7LYh46PcZNcS3CnO7GuYsEJZeTj5LQSgp21IyTelaBPpr +ijnMwKa+pLQt5TEobpKFFNecPdT6oPoOKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHM +BNkoTFeGrursPkqYRJ0HL4CqYqRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKb +zibJc64JFM7tUoK6Vl64YiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs +8zjxsf6c6N2tKXkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38 +KvTx3wjNQwAAA8hLhVBxS4VQcQAAAAdzc2gtcnNhAAABAQDirp5l3HstiHjo9xk1xLcKc7 +sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+l +fQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg6 +4MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u +2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28 +uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1DAAAAAwEAAQAAAQAmShSbZBiyYkD6KPLr +MCUy8MWED6kVzDB1yvPvN5eKYmH44xe/i4UqvgSl7gR50a2G7zzDIKC2Go1brGQBWPuXRa +ZtOjQygeD4rMHBiH/b7zfy4pQyKDfITTHOFXWE8ERiyL00bAZt09icCy92rQaq8IY/+U56 +sPPJH9UAYG9nEev8opFjAWToFDu0U2+dC+lbqLlXDqDRo75NlnDFmgUoja3y2eFr9A0Cc+ +hjecrdxyJFsCJfEfaLWtBnZb886gqzzvfbHImSQtBAKERcSxuki7uxMoP67g3iQOXa65uz +8kFWRNmbQTGQttakoUaybh1t9eLpBqvVON/4Kg0THShRAAAAgFBTz2ajBK/R/crOSL9VK1 +f7oQv2iJTRVfnUs0r+qPGgf/a/5UwkGRj0KfEWBp3qYD+keShnPr6PDPFrm8UmIdUX8AY7 +3tWT2K/JQVlzJNuINsw+DNjn4M17Z25q0LPmReRWL0nRc2w6W/hmQ/Jmqz6w8Qc4+xpeqS +/HG5feliVnAAAAgQD90a+5Ky3o/2YtueqRf/3dKoiMgGB7JAOzye4dDKGABSlWuQ4N4xEI +CW5MSTp7i/uobTF/tyFO3tTSyb5b2Xwbn/kLO0vgvFCdUGR2BQfN3mcT92T0Gn3JDF3Wym +i2mgU6qnPf+eu+RKZQ9IiyNGny61ROUQa0R0z0pgiAfA89xwAAAIEA5KE9i6hHmigJwfD7 +/AGI4ujyWIVpNyrTdXG3HAPhsdoFuG5ggHggrPuuBF9wNcosrhL20VNOQGHg15gWZIVudu +0qxky4ivQs67Sk9XUjuvTnf+VubM51rIsmh4atKJFSSZo78DEcTRt8aXLrSNvGQ4WPRweM +2Z0YGfMMDM9KJKUAAAASbmV3IG9wZW5zc2ggZm9ybWF0AQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub new file mode 100644 index 0000000..133afc9 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D new openssh format diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result new file mode 100644 index 0000000..dd8a8b4 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "new openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result new file mode 100644 index 0000000..d1ada9c --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "new openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEA4q6eZdx7LYh46PcZNcS3CnO7GuYsEJZeTj5LQSgp21IyTela\nBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoOKKMe6oH/pX0BNyAEB9KFZfZgh0v4\nJ4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYqRdINy1sgDU6jUIOuDD5XZzlpDXb1\nftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64YiPgxsNXOJYMTrelVJYebtsNrJFm\nh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKXkk9G4EDKKip4g0bzDmD/fREPQ9vL\ni59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjNQwIDAQABAoIBACZKFJtkGLJiQPoo\n8uswJTLwxYQPqRXMMHXK8+83l4piYfjjF7+LhSq+BKXuBHnRrYbvPMMgoLYajVus\nZAFY+5dFpm06NDKB4PiswcGIf9vvN/LilDIoN8hNMc4VdYTwRGLIvTRsBm3T2JwL\nL3atBqrwhj/5Tnqw88kf1QBgb2cR6/yikWMBZOgUO7RTb50L6VuouVcOoNGjvk2W\ncMWaBSiNrfLZ4Wv0DQJz6GN5yt3HIkWwIl8R9ota0GdlvzzqCrPO99sciZJC0EAo\nRFxLG6SLu7Eyg/ruDeJA5drrm7PyQVZE2ZtBMZC21qShRrJuHW314ukGq9U43/gq\nDRMdKFECgYEA/dGvuSst6P9mLbnqkX/93SqIjIBgeyQDs8nuHQyhgAUpVrkODeMR\nCAluTEk6e4v7qG0xf7chTt7U0sm+W9l8G5/5CztL4LxQnVBkdgUHzd5nE/dk9Bp9\nyQxd1spotpoFOqpz3/nrvkSmUPSIsjRp8utUTlEGtEdM9KYIgHwPPccCgYEA5KE9\ni6hHmigJwfD7/AGI4ujyWIVpNyrTdXG3HAPhsdoFuG5ggHggrPuuBF9wNcosrhL2\n0VNOQGHg15gWZIVudu0qxky4ivQs67Sk9XUjuvTnf+VubM51rIsmh4atKJFSSZo7\n8DEcTRt8aXLrSNvGQ4WPRweM2Z0YGfMMDM9KJKUCgYB7Yh0b1EOjCdQv0jqWtDNB\n+dUbB6Te92jdUwHvGR7AzsGDqL2OPp0e3QbDCq3lNO0GuN3hCbKlVmj6dpuUpqpP\n+3ni3dZKzwAZGOVdAaEDkGNnL1Hh36bZvqs3KHmymjiEhiuB60mP2mtG2zg/+H6w\nWXlIANdTd32PR87GNohqLQKBgA36ic/LJy2Wuxn/iPicg2kUQxUEey1jUfCBVmfB\nGQCNywG+xem07pKFBNvBlhPD27187VhZFpS7J0snQl89BUcCMzZSpIniagizT86u\nLdQVez4HohvG98zn6SAqLNYpJHXZl0aVShywzIeJ/jbDMTkZpmv6WzNG9p1HjfoO\nhoL9AoGAUFPPZqMEr9H9ys5Iv1UrV/uhC/aIlNFV+dSzSv6o8aB/9r/lTCQZGPQp\n8RYGnepgP6R5KGc+vo8M8WubxSYh1RfwBjve1ZPYr8lBWXMk24g2zD4M2OfgzXtn\nbmrQs+ZF5FYvSdFzbDpb+GZD8marPrDxBzj7Gl6pL8cbl96WJWc=\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc new file mode 100644 index 0000000..09aa65d --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc @@ -0,0 +1,28 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAS8H9Cyk +rueA/Ue6tOb1MOAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC8hCiCPnRs +0ucZeyn3pNYKN63dVoxbMB4Yzjs7gvo7XKDby/6GXoU/CFQ/Q9zXRxRZmFglMYh2pOD8iW +dwpLBdd+GmHb4a6xxKtoPpz1+yCPYvi6nXzKPO3B9Wbg8dtTpV23l8MZDxSRUQ9HIkYHQO +oOjJx/AaMdZyHZP+eYK7UqmX1+dtCzr5vvLyEABxrsoFxH/oW/iKO6cDmTxoMyFl9DfUhD +TS7cL1OVBulSBav3aJPxjsCEIs6OE94wLJfFtZAPe4GqWWcC7uG1uUL5Muy2N+SfXHOHLa +I5n1vozt7lIO5TqvykcqTxipKblMW4Y7Iwlhh0YKJxzH3KJ+Qkn7AAAD4GeinUMcN5H0RP +KnXzIsYGq4rG+pEYNL0WyXCOFnyHzr6cASFYa/ViRVRN5H2dDoc0i2tcQStvDt2AfBxP97 +xbTEmRhLkKW7Sxif+bRRpNt2sO1y7ThufOZ8ZSJdbUYf9nc++k5GMZZUTtkFGhFIyhdyl+ +ZReuQFrc1Fv0/JV0K72uLSMSSMvunFjnGchch98Z1t0jEuiym8AIAwFtlvRpbOOySJhHun +fClEOahNvgzkgpqvviged7Gl9Kh3Fpp57ke1087WUF4hdgG2wuLqRq3Jq2kNvTKVi6+PMv +Kz5cLl6beqAJpbkJCpujzrmffo5NHh94R/v8DbAWCyrkjB6NHjOPIVnKaDmXixkcJ489W3 +PQF0kZ9kLrNU2yP1hBLjikr1zollw6xXC5eEpUsIrNcAHrofTMCMsGKuZhlEgTNe0cEATp +ycxi4gHdA6kNSDnMPwOv9rLDZDkgqCqIzxjZCWabqRHwiyoN3CrdDsJNrk8jSqF5epuzXA +EjrPUvu+sgFHIWDJOij+HQCvCgmdO/W7NkL/xCEx6QagjoJhapGICnq6CXPO5vBQeK7AMV +KWUPB1jdxxlHdrSUYU9v11j0SPUM51AMpWA89GZmuQbe/tK14W35VjtL9aGKsz9Ubio029 +O23HJXMxM9Dd6EYXAR9xMLFDTcLT03kjRlL/4XFS4fJqbTGDtuQNqRO3QK/myVAYjgnXwz +X1s77WeIK3sOMwTIXaHReUiQ1Cw+WmkXOhefePT+HrkyDlJk3ikgPUy2s5QW5/d6Lmolwb +mcS9JUfaai0ysP3v1bew8go/IHiUD/X9AkjkKM2kfS1NcPSi18r2721e6RqZiIHxSoyKvq +yUmwiS1kUklSuhlTORBvbclbv4HTwp1iJfu/6zsMqVJc2E8H6WUw3kTeh9fhDMpTY5NArF +KD2aRIYHFvOKav+0vSbQ/KqmKeiTvyZaV7q6giRxVLxBddl4+ucD+FybPJZSebRQ+0QT1j +aUDSpp541zW0rX7sCiZ6sFUybCPVDM1uA5gTAP015OD/FS342gi+Y04K0jBSjlApuy6BQx +sMEQbR3weMmnodbhCtbcgDZDagSFNPlDud0GJl9IWV4hO/K1f9a+Ox3G27Jq4YC2PFgTDb +aYib4xAXPUHJpoWsstSjpMnfgKcS3AGRdJ/jxlKRWV/NXFf4DYIwpzITqFMF+4VqXCa2AS +JWOcSxOK92UqCcZEs8RED3x9dF9E2yBBwHeuwDvH3c9x/nsM/cjDY+EE9VcEUOxF6qMOhO +CiRtEihEAYM46XeFzcSOQrwWPcKu3WTv3IpnzTaofBxV065CUn +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub new file mode 100644 index 0000000..0e80f0f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8hCiCPnRs0ucZeyn3pNYKN63dVoxbMB4Yzjs7gvo7XKDby/6GXoU/CFQ/Q9zXRxRZmFglMYh2pOD8iWdwpLBdd+GmHb4a6xxKtoPpz1+yCPYvi6nXzKPO3B9Wbg8dtTpV23l8MZDxSRUQ9HIkYHQOoOjJx/AaMdZyHZP+eYK7UqmX1+dtCzr5vvLyEABxrsoFxH/oW/iKO6cDmTxoMyFl9DfUhDTS7cL1OVBulSBav3aJPxjsCEIs6OE94wLJfFtZAPe4GqWWcC7uG1uUL5Muy2N+SfXHOHLaI5n1vozt7lIO5TqvykcqTxipKblMW4Y7Iwlhh0YKJxzH3KJ+Qkn7 diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result new file mode 100644 index 0000000..ee0fd94 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvIQogj50bNLnGXsp96TW\nCjet3VaMWzAeGM47O4L6O1yg28v+hl6FPwhUP0Pc10cUWZhYJTGIdqTg/IlncKSw\nXXfhph2+GuscSraD6c9fsgj2L4up18yjztwfVm4PHbU6Vdt5fDGQ8UkVEPRyJGB0\nDqDoycfwGjHWch2T/nmCu1Kpl9fnbQs6+b7y8hAAca7KBcR/6Fv4ijunA5k8aDMh\nZfQ31IQ00u3C9TlQbpUgWr92iT8Y7AhCLOjhPeMCyXxbWQD3uBqllnAu7htblC+T\nLstjfkn1xzhy2iOZ9b6M7e5SDuU6r8pHKk8YqSm5TFuGOyMJYYdGCiccx9yifkJJ\n+wIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQC8hCiCPnRs0ucZeyn3pNYKN63dVoxbMB4Yzjs7gvo7XKDby/6GXoU/CFQ/Q9zXRxRZmFglMYh2pOD8iWdwpLBdd+GmHb4a6xxKtoPpz1+yCPYvi6nXzKPO3B9Wbg8dtTpV23l8MZDxSRUQ9HIkYHQOoOjJx/AaMdZyHZP+eYK7UqmX1+dtCzr5vvLyEABxrsoFxH/oW/iKO6cDmTxoMyFl9DfUhDTS7cL1OVBulSBav3aJPxjsCEIs6OE94wLJfFtZAPe4GqWWcC7uG1uUL5Muy2N+SfXHOHLaI5n1vozt7lIO5TqvykcqTxipKblMW4Y7Iwlhh0YKJxzH3KJ+Qkn7", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result new file mode 100644 index 0000000..a0f0fed --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "new openssh format encrypted", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvIQogj50bNLnGXsp96TW\nCjet3VaMWzAeGM47O4L6O1yg28v+hl6FPwhUP0Pc10cUWZhYJTGIdqTg/IlncKSw\nXXfhph2+GuscSraD6c9fsgj2L4up18yjztwfVm4PHbU6Vdt5fDGQ8UkVEPRyJGB0\nDqDoycfwGjHWch2T/nmCu1Kpl9fnbQs6+b7y8hAAca7KBcR/6Fv4ijunA5k8aDMh\nZfQ31IQ00u3C9TlQbpUgWr92iT8Y7AhCLOjhPeMCyXxbWQD3uBqllnAu7htblC+T\nLstjfkn1xzhy2iOZ9b6M7e5SDuU6r8pHKk8YqSm5TFuGOyMJYYdGCiccx9yifkJJ\n+wIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQC8hCiCPnRs0ucZeyn3pNYKN63dVoxbMB4Yzjs7gvo7XKDby/6GXoU/CFQ/Q9zXRxRZmFglMYh2pOD8iWdwpLBdd+GmHb4a6xxKtoPpz1+yCPYvi6nXzKPO3B9Wbg8dtTpV23l8MZDxSRUQ9HIkYHQOoOjJx/AaMdZyHZP+eYK7UqmX1+dtCzr5vvLyEABxrsoFxH/oW/iKO6cDmTxoMyFl9DfUhDTS7cL1OVBulSBav3aJPxjsCEIs6OE94wLJfFtZAPe4GqWWcC7uG1uUL5Muy2N+SfXHOHLaI5n1vozt7lIO5TqvykcqTxipKblMW4Y7Iwlhh0YKJxzH3KJ+Qkn7", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAvIQogj50bNLnGXsp96TWCjet3VaMWzAeGM47O4L6O1yg28v+\nhl6FPwhUP0Pc10cUWZhYJTGIdqTg/IlncKSwXXfhph2+GuscSraD6c9fsgj2L4up\n18yjztwfVm4PHbU6Vdt5fDGQ8UkVEPRyJGB0DqDoycfwGjHWch2T/nmCu1Kpl9fn\nbQs6+b7y8hAAca7KBcR/6Fv4ijunA5k8aDMhZfQ31IQ00u3C9TlQbpUgWr92iT8Y\n7AhCLOjhPeMCyXxbWQD3uBqllnAu7htblC+TLstjfkn1xzhy2iOZ9b6M7e5SDuU6\nr8pHKk8YqSm5TFuGOyMJYYdGCiccx9yifkJJ+wIDAQABAoIBAD1UXX1p5iSVRHvk\nttWLOdsfHCA7DPSJpfD5/wkwZkozq112czqxu3WzNv1SDaG3zSYMyvhmsfevUka2\nSQG7gmkWHEIXwQYu4Qhpcmb5gS+BfN4g+MNtHwmoUUWkDqTilbTi7xX5ZicpWIIo\nlI3DF16++JzUwAc1mYeMmd4bF+3quh93xW7hhrcQ31+D9kzqt6nLG1d9+IVpMbhD\nnNB9zapkZHwnz6YYhb5waMOHr6U902TyGgKyjq3Z/PkMJ0zKg01roUtQs9oQOIZF\nvueF2hwyzHqeIgpqhWJl9HMpfdym6Lh2lwguK3KYwNIMFQg+gNBWruYlH6SGfylq\n0wB5xIECgYEA8FdyEDd4TbVBKIXzzmY6zYmN/Q9uiz0IjbeYYzuRxZ4a7stE/t8n\nM5UxxkqeD8rtRAQJyFDGPAhFeeOpIfzEVPG+5s72pI69+9aE/gCGA91+sOSnLoiJ\nPW1I7SouZfCeaaRQxSSIMjsCea2s6yraujGZJyPEWSkG5TijY8+vzDsCgYEAyMxX\nCYvqlRTaT5lAkRTFLqf0/NSpRoCnG7qSPUyJjxJsVfYFLv1FZCyyrA+SaIyufjoT\nKutKE31r7wre5bkjRRenIcTkR/tdNRdkWsB/ysZ9Cp43FIPTXS5gxTQxOaJyRGvJ\n9MW0m8N1pMvPIsagzoxxvzgU9ZOejs2NQ69qXUECgYBq7DxOgp7+0zhdsto4ZLqc\nXinQ/2CKiWiYw6kD3KiJZkFNIxla2iQyiplOQjv3gqvzqmg/uc+3PWbLR0EjYbRm\npfXr8P9BTk+vDky0Q79bUNrgD5lg1lVYApqDCFUD/Pw8u2FDk3EUB7SeNWnMZZBR\nbWdZRkw/7kSnDX+DFA59qQKBgG9v0AHxT4/LEdlJEOczYrcg6TqDfyosbhFaepxg\nZJstO0h9j6TjVGZi1AnfXn59TL2q10ZjbCni2krAerF9DNDkbpG0Joi4PKMhR0WC\nPam4fF6vLZxKCLxW58epzoPQ3p+QPnWEX1ZupFR/84W2PDpFAT+BDUi40y8nbnWY\n3WvBAoGADjh0hEkq3sy6oWt0m1NjGU1yxKV+geg48BFnu2LVSFv1rw1V7X8XFEYl\nP1B3sEpOOpPGuoz+r2E9PrsdMuYNOmVlRFRpe7pm7zyhzdFYBvLE2btJqv1PmxFu\ncEkrXJS/ETxkKdMaoUbYHcKiTIMi2pDrdJtg6oHcipm0yTBZkKs=\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm new file mode 100644 index 0000000..442a4f5 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm @@ -0,0 +1,29 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAFmFlczEyOC1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA +AAGAAAABBJL2YVn88iqv/H9bFiyW2PAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQAB +AAABAQDMemjkha1c+2s58qzx4968svvvpbxt6EiLlyRHuqXCouTdBZeXGtVRlxpkqnnOE0 +ETMSQSqm1d5k1EMa7VVcTeXFQaBIc2XF0S1uIoEvNV0JXpDjiIdPmjUFuUf9oGGLKKQQMf +zpymqoiHYQNhuarYd1mSb0+a+UwKxAxGeCPd95o/JfWjKO0JTr3nnEj1eTjtu0pofmchab +9HC9YbJ3JsvbdRq7Z2ZHp8uu16SflPpP2A9l+F4HN+gPOLcGxbVkVZHsLI07OpkWdxMPBU +rzPF9OnCntRWoBhQ4LFHYHllTtd+/E90QXXhe1pxj8FktJiaitiz09GU5h4IWi3isNr/AA +AD4Ktd9gUs9KHBmWTVFnDofcB6P1dZJsYHAapQgNXZtx5SjwgfBpP5aBLtSjN1iHFE+3XC +Cofc9UJ8fbytwT7LCEQIzo3KJaOhVzgJN+lrjtFouWsw0Y1q2JONHvvNJ5A9nGjIGbp3du +4TAMSgVAvxZBEYez4ajhb2NL7TE56AjOxW4n/M2ZDJLCo11F3ON3Eq6MirHZMgGKo/lbOc +SaBld7tzqknye+1fKVlnCLyu+v0KCbATBypRsMeX1+E/D8L5cMIgRSe97swqiWeG9yBhQi +xahbWDpmU34nz1cxc9H7KnL1rbbOxrr4OEdMOHNBQjbLlpJpnSJ3XvEGP74zjfd5zMocgx +rnqreMmY+eDEObkw33+XD5ROYJT+SW/zI+r3SeIjS3UPh0ucU5nipBvXfkUezek9i/FN1X +CY7xJnAZGGKU0JSqiVW3JWXp18v8lmo3ACvXeotJfUGkwvJOeO2N4Qb7RTIzivLV5Q5Plf +zHWqHE57UqDL/Ya7SrX1FaqqhOHOlS1mqPQ+/VdsOSP5fJcXN+oKoL7jPr2WlmtFjo8PKc +rpgKC3DhUzvRXnNYotG7trbPOGJbBRgoxTQ06rlChoaBp7kUKqNNBxXhFQCeN0sCb90fHV +c+X3Yy8oUsAIxxmCymuVV8gRzLD6OdqQRBthEUQktNJLhv4mSufwSfsLDluEc7YEOrsJhx +jk57TmkFFyLj++IAKi80FnSkRfSBQF3dTSrBZ4BIHWnek8V6goxhy6lRMaFoTow2foknvr +VHgiNGvimOM3ESYVcOwt3YQqbUG/7b4jRlY3nNBJcsbxGe54B8zaoLt5pQNRxUuHc3fR4R +haWHR6IWsfey7jAlRzrJAVVEEj4d6yvJ4bLqWGmoim5QlrePRuRFyV4FNb8N6hJ9gvWY9f +HUT9TwxArDIMzu4T1khwRoFU45XN0U6xHEPcT/pZ2C5jJSSQ5W/SyBudexjMMPRKf2EIeD +gjv8vIhdtkmxHv7bapaaYeYX5gtKYl+McRollDxVC8Kr48RmOVJnK4aFBQ99Wu7SXDbwas +vcvVHI+zUiRGjU01/CU/Tf4GTodAlmZIuqKmBTX/KvVj6ZiK0BsZuEl9qom+l4rlazaahY +FdL5M4u0qt7rVirWJWgWzmPXZ+MCK0Fs70ORvqRGxVMilhQcWsng3ZXnHaYiBRhk31KqF+ +BEPEh79OknD0okKed2YYfg8vdUR+noENybrsIleP1aKBBmQCNbKU04N/9Su+wxX8YfGhYU +kPST35Wg45zER9gZGsREnON4sQTng9LHB5CrJCo/MowcZG/ycqL1mxemApZ9nYUrjA8HJi +zDwRHHUtkkLNG8Cmyg== +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub new file mode 100644 index 0000000..d5c7685 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMemjkha1c+2s58qzx4968svvvpbxt6EiLlyRHuqXCouTdBZeXGtVRlxpkqnnOE0ETMSQSqm1d5k1EMa7VVcTeXFQaBIc2XF0S1uIoEvNV0JXpDjiIdPmjUFuUf9oGGLKKQQMfzpymqoiHYQNhuarYd1mSb0+a+UwKxAxGeCPd95o/JfWjKO0JTr3nnEj1eTjtu0pofmchab9HC9YbJ3JsvbdRq7Z2ZHp8uu16SflPpP2A9l+F4HN+gPOLcGxbVkVZHsLI07OpkWdxMPBUrzPF9OnCntRWoBhQ4LFHYHllTtd+/E90QXXhe1pxj8FktJiaitiz09GU5h4IWi3isNr/ diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result new file mode 100644 index 0000000..0f00545 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHpo5IWtXPtrOfKs8ePe\nvLL776W8behIi5ckR7qlwqLk3QWXlxrVUZcaZKp5zhNBEzEkEqptXeZNRDGu1VXE\n3lxUGgSHNlxdEtbiKBLzVdCV6Q44iHT5o1BblH/aBhiyikEDH86cpqqIh2EDYbmq\n2HdZkm9PmvlMCsQMRngj3feaPyX1oyjtCU6955xI9Xk47btKaH5nIWm/RwvWGydy\nbL23Uau2dmR6fLrtekn5T6T9gPZfheBzfoDzi3BsW1ZFWR7CyNOzqZFncTDwVK8z\nxfTpwp7UVqAYUOCxR2B5ZU7XfvxPdEF14XtacY/BZLSYmorYs9PRlOYeCFot4rDa\n/wIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDMemjkha1c+2s58qzx4968svvvpbxt6EiLlyRHuqXCouTdBZeXGtVRlxpkqnnOE0ETMSQSqm1d5k1EMa7VVcTeXFQaBIc2XF0S1uIoEvNV0JXpDjiIdPmjUFuUf9oGGLKKQQMfzpymqoiHYQNhuarYd1mSb0+a+UwKxAxGeCPd95o/JfWjKO0JTr3nnEj1eTjtu0pofmchab9HC9YbJ3JsvbdRq7Z2ZHp8uu16SflPpP2A9l+F4HN+gPOLcGxbVkVZHsLI07OpkWdxMPBUrzPF9OnCntRWoBhQ4LFHYHllTtd+/E90QXXhe1pxj8FktJiaitiz09GU5h4IWi3isNr/", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result new file mode 100644 index 0000000..127ce3d --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "new openssh format encrypted gcm", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzHpo5IWtXPtrOfKs8ePe\nvLL776W8behIi5ckR7qlwqLk3QWXlxrVUZcaZKp5zhNBEzEkEqptXeZNRDGu1VXE\n3lxUGgSHNlxdEtbiKBLzVdCV6Q44iHT5o1BblH/aBhiyikEDH86cpqqIh2EDYbmq\n2HdZkm9PmvlMCsQMRngj3feaPyX1oyjtCU6955xI9Xk47btKaH5nIWm/RwvWGydy\nbL23Uau2dmR6fLrtekn5T6T9gPZfheBzfoDzi3BsW1ZFWR7CyNOzqZFncTDwVK8z\nxfTpwp7UVqAYUOCxR2B5ZU7XfvxPdEF14XtacY/BZLSYmorYs9PRlOYeCFot4rDa\n/wIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDMemjkha1c+2s58qzx4968svvvpbxt6EiLlyRHuqXCouTdBZeXGtVRlxpkqnnOE0ETMSQSqm1d5k1EMa7VVcTeXFQaBIc2XF0S1uIoEvNV0JXpDjiIdPmjUFuUf9oGGLKKQQMfzpymqoiHYQNhuarYd1mSb0+a+UwKxAxGeCPd95o/JfWjKO0JTr3nnEj1eTjtu0pofmchab9HC9YbJ3JsvbdRq7Z2ZHp8uu16SflPpP2A9l+F4HN+gPOLcGxbVkVZHsLI07OpkWdxMPBUrzPF9OnCntRWoBhQ4LFHYHllTtd+/E90QXXhe1pxj8FktJiaitiz09GU5h4IWi3isNr/", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAzHpo5IWtXPtrOfKs8ePevLL776W8behIi5ckR7qlwqLk3QWX\nlxrVUZcaZKp5zhNBEzEkEqptXeZNRDGu1VXE3lxUGgSHNlxdEtbiKBLzVdCV6Q44\niHT5o1BblH/aBhiyikEDH86cpqqIh2EDYbmq2HdZkm9PmvlMCsQMRngj3feaPyX1\noyjtCU6955xI9Xk47btKaH5nIWm/RwvWGydybL23Uau2dmR6fLrtekn5T6T9gPZf\nheBzfoDzi3BsW1ZFWR7CyNOzqZFncTDwVK8zxfTpwp7UVqAYUOCxR2B5ZU7XfvxP\ndEF14XtacY/BZLSYmorYs9PRlOYeCFot4rDa/wIDAQABAoIBAQCCb7uluxhh7gfy\niTmFfETDvrEzqFfRDJHqadm83/WJeXvg+gY/X+CgEXHGsXDN4j5qzbgjKBBoC9dS\nHxdWA0Z4ShFkH2tZZAYDVIwj4CLVpR9b8bRiZ6wvX71rtzsPFIYf52Tkz1nif3pk\nUaBkoJm5SDkdTmBLjafSXkkuUskeeAV7gx+fzWqSpcKmhTqjnQfdlmD8OSIq4jjD\nagiHmmfBhZ4NOvF/E9UBydqFV8GNyfSFC6kC2LYmiQD1hvqNhMdYVjh99V1L3ZPq\nHMSQVAOv5WgpLTLKY8MFNBbqqp0eKhatRNA8q9O23jADDp3fubKV0aUQSrRZz0y9\nPmmEJnTRAoGBAPZoL+p+AbI5yTg01LdsaQL2f3Ieb3CGudesmjAVnI3QEoC6gxGX\n4cbmBSCY+vBzh2RJNJcS+Rq6VmJZA930Tb0npHiQYOohB7BFOCbBJ2L18g/JdNpi\nVb3wqFs9NG1GFOOV6iGtV/6t4CRTKtAbd695YZAJ5S6DDvMrH9pTnAKrAoGBANRw\nVuLfBTFhSKvFz+0W0yy6Sn0koXjpp1ifC0BWLwHiA/IZjAY7qmsNQZxWdleWLP28\nRNaac3vMJO/HFD4IyL59Zli+kREGKazvZM1dvOs0mgdVMTPMsT57wcJr5OSxqCvJ\nD3NkcgFuA1e3jVC5p/wUJCi/lhyFPx3z1C5vRqj9AoGBANeyYmd5wFBcp1ktXhvm\nqZIvZ2blX5X4ScyTSjHXaUD2qIvJORz4gGqVRl2/rMM5zoYqUwAAWtFb1mynEWyF\nBFwVzLLBaCTrnwhdv4alRK4rL6dEKadVt0ra1PVxgWg6leSXgenTDRli6bfCmdKs\niLuxnIbzMozhqv+Qe4Sp9gKbAoGBALWBThsEpXEtR2PL3P0atU7P0/jcJUIjkCF9\nsaVEfWFEdE6TWTmyHMbeSqKClRX8b3BTPRWGXQj2wNBE7Zya8LkgdyN3noZHF7Bz\n0VJNtq3XAYsmVKWHTCCwqDmu6aAj0iWm4ZabyXRDRIPbhdfk6AvOQZ63IlA34Fd9\nDlqmJF8ZAoGAIJzfMDT2LvlMOHqpKgelS4ZTHEmqqJZM5rXdsZwYqcyekjz25COE\nTJwme3xIt3kSZEcOauGHCgUVeBcE6GwZbQ1WoNIvazhnUXeErOeoxQ+ZqdfC8iyT\nUn/P27yx/FcwDdubQhbgxZ5M+pu+0OQ1WPu02LQZQrX7x4a6isYtTDo=\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa new file mode 100644 index 0000000..f2ae4d4 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvQIBAAKBgQDs+n9ZKhwYNr1V2uGn0C/2MSTM4KB4puy4jR5ubRTT1yq5SbzK +RQlCjfplDN//Eqa6aiFmvGKA3RKUtPtBmD96EHW1mvr7O+Pc8z8L/4zg9tkVQR6V +WBKgBhVwZHDzzs5+Ag2j54BZfcaGMcNGhTE9DcZYeI/t6FhOxgpID3EA/QIVAMyI +czBU74xB48IMoamlEhc5Lh+3AoGBAMuy2h9K9+oQIPcTcsD/mtmhOYlw2ZPCJV2b +WFeZ3QxAujenBzEp0oqht8tdj+BE7Er+CWT2Ab/A92MrjYUaGaPjdF5+K6CSPMUX +rK8nBabSBJ+ELqTo/8vHJ2eVWIUJBwCzbw3ryitH7LD3gyEr2NuQQJE++wyWPBHK +M3SFOft6AoGBAOdrYUJ38yjc9tnrvLWsB1KlkYhc+UbTMSRKfA8Yo/Xs5QldFycz +bUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMnOzRVQXpUI7z2W3/Ie4/i2Lu/ +xXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5ciuO0ltu90L9+2YvWAhUAr/vy +ahuEz4UFGhB8IIeLWQUO5FA= +-----END DSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub new file mode 100644 index 0000000..a7fd375 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAOz6f1kqHBg2vVXa4afQL/YxJMzgoHim7LiNHm5tFNPXKrlJvMpFCUKN+mUM3/8SprpqIWa8YoDdEpS0+0GYP3oQdbWa+vs749zzPwv/jOD22RVBHpVYEqAGFXBkcPPOzn4CDaPngFl9xoYxw0aFMT0Nxlh4j+3oWE7GCkgPcQD9AAAAFQDMiHMwVO+MQePCDKGppRIXOS4ftwAAAIEAy7LaH0r36hAg9xNywP+a2aE5iXDZk8IlXZtYV5ndDEC6N6cHMSnSiqG3y12P4ETsSv4JZPYBv8D3YyuNhRoZo+N0Xn4roJI8xResrycFptIEn4QupOj/y8cnZ5VYhQkHALNvDevKK0fssPeDISvY25BAkT77DJY8EcozdIU5+3oAAACBAOdrYUJ38yjc9tnrvLWsB1KlkYhc+UbTMSRKfA8Yo/Xs5QldFyczbUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMnOzRVQXpUI7z2W3/Ie4/i2Lu/xXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5ciuO0ltu90L9+2YvW old openssh format diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result new file mode 100644 index 0000000..05f8140 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "old openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBuDCCASwGByqGSM44BAEwggEfAoGBAOz6f1kqHBg2vVXa4afQL/YxJMzgoHim\n7LiNHm5tFNPXKrlJvMpFCUKN+mUM3/8SprpqIWa8YoDdEpS0+0GYP3oQdbWa+vs7\n49zzPwv/jOD22RVBHpVYEqAGFXBkcPPOzn4CDaPngFl9xoYxw0aFMT0Nxlh4j+3o\nWE7GCkgPcQD9AhUAzIhzMFTvjEHjwgyhqaUSFzkuH7cCgYEAy7LaH0r36hAg9xNy\nwP+a2aE5iXDZk8IlXZtYV5ndDEC6N6cHMSnSiqG3y12P4ETsSv4JZPYBv8D3YyuN\nhRoZo+N0Xn4roJI8xResrycFptIEn4QupOj/y8cnZ5VYhQkHALNvDevKK0fssPeD\nISvY25BAkT77DJY8EcozdIU5+3oDgYUAAoGBAOdrYUJ38yjc9tnrvLWsB1KlkYhc\n+UbTMSRKfA8Yo/Xs5QldFyczbUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMn\nOzRVQXpUI7z2W3/Ie4/i2Lu/xXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5c\niuO0ltu90L9+2YvW\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAOz6f1kqHBg2vVXa4afQL/YxJMzgoHim7LiNHm5tFNPXKrlJvMpFCUKN+mUM3/8SprpqIWa8YoDdEpS0+0GYP3oQdbWa+vs749zzPwv/jOD22RVBHpVYEqAGFXBkcPPOzn4CDaPngFl9xoYxw0aFMT0Nxlh4j+3oWE7GCkgPcQD9AAAAFQDMiHMwVO+MQePCDKGppRIXOS4ftwAAAIEAy7LaH0r36hAg9xNywP+a2aE5iXDZk8IlXZtYV5ndDEC6N6cHMSnSiqG3y12P4ETsSv4JZPYBv8D3YyuNhRoZo+N0Xn4roJI8xResrycFptIEn4QupOj/y8cnZ5VYhQkHALNvDevKK0fssPeDISvY25BAkT77DJY8EcozdIU5+3oAAACBAOdrYUJ38yjc9tnrvLWsB1KlkYhc+UbTMSRKfA8Yo/Xs5QldFyczbUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMnOzRVQXpUI7z2W3/Ie4/i2Lu/xXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5ciuO0ltu90L9+2YvW", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result new file mode 100644 index 0000000..d21d1cb --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBuDCCASwGByqGSM44BAEwggEfAoGBAOz6f1kqHBg2vVXa4afQL/YxJMzgoHim\n7LiNHm5tFNPXKrlJvMpFCUKN+mUM3/8SprpqIWa8YoDdEpS0+0GYP3oQdbWa+vs7\n49zzPwv/jOD22RVBHpVYEqAGFXBkcPPOzn4CDaPngFl9xoYxw0aFMT0Nxlh4j+3o\nWE7GCkgPcQD9AhUAzIhzMFTvjEHjwgyhqaUSFzkuH7cCgYEAy7LaH0r36hAg9xNy\nwP+a2aE5iXDZk8IlXZtYV5ndDEC6N6cHMSnSiqG3y12P4ETsSv4JZPYBv8D3YyuN\nhRoZo+N0Xn4roJI8xResrycFptIEn4QupOj/y8cnZ5VYhQkHALNvDevKK0fssPeD\nISvY25BAkT77DJY8EcozdIU5+3oDgYUAAoGBAOdrYUJ38yjc9tnrvLWsB1KlkYhc\n+UbTMSRKfA8Yo/Xs5QldFyczbUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMn\nOzRVQXpUI7z2W3/Ie4/i2Lu/xXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5c\niuO0ltu90L9+2YvW\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAOz6f1kqHBg2vVXa4afQL/YxJMzgoHim7LiNHm5tFNPXKrlJvMpFCUKN+mUM3/8SprpqIWa8YoDdEpS0+0GYP3oQdbWa+vs749zzPwv/jOD22RVBHpVYEqAGFXBkcPPOzn4CDaPngFl9xoYxw0aFMT0Nxlh4j+3oWE7GCkgPcQD9AAAAFQDMiHMwVO+MQePCDKGppRIXOS4ftwAAAIEAy7LaH0r36hAg9xNywP+a2aE5iXDZk8IlXZtYV5ndDEC6N6cHMSnSiqG3y12P4ETsSv4JZPYBv8D3YyuNhRoZo+N0Xn4roJI8xResrycFptIEn4QupOj/y8cnZ5VYhQkHALNvDevKK0fssPeDISvY25BAkT77DJY8EcozdIU5+3oAAACBAOdrYUJ38yjc9tnrvLWsB1KlkYhc+UbTMSRKfA8Yo/Xs5QldFyczbUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMnOzRVQXpUI7z2W3/Ie4/i2Lu/xXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5ciuO0ltu90L9+2YvW", + "private": "-----BEGIN DSA PRIVATE KEY-----\nMIIBvQIBAAKBgQDs+n9ZKhwYNr1V2uGn0C/2MSTM4KB4puy4jR5ubRTT1yq5SbzK\nRQlCjfplDN//Eqa6aiFmvGKA3RKUtPtBmD96EHW1mvr7O+Pc8z8L/4zg9tkVQR6V\nWBKgBhVwZHDzzs5+Ag2j54BZfcaGMcNGhTE9DcZYeI/t6FhOxgpID3EA/QIVAMyI\nczBU74xB48IMoamlEhc5Lh+3AoGBAMuy2h9K9+oQIPcTcsD/mtmhOYlw2ZPCJV2b\nWFeZ3QxAujenBzEp0oqht8tdj+BE7Er+CWT2Ab/A92MrjYUaGaPjdF5+K6CSPMUX\nrK8nBabSBJ+ELqTo/8vHJ2eVWIUJBwCzbw3ryitH7LD3gyEr2NuQQJE++wyWPBHK\nM3SFOft6AoGBAOdrYUJ38yjc9tnrvLWsB1KlkYhc+UbTMSRKfA8Yo/Xs5QldFycz\nbUtsFGdLvqPol0pww2LqeKUQ8zVIF56Aw3SxmPMnOzRVQXpUI7z2W3/Ie4/i2Lu/\nxXos8ZHnIu+e7SLJRHe+RGNvISbsQhk+vnpNQP5ciuO0ltu90L9+2YvWAhUAr/vy\nahuEz4UFGhB8IIeLWQUO5FA=\n-----END DSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc new file mode 100644 index 0000000..57064cd --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc @@ -0,0 +1,15 @@ +-----BEGIN DSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,3239878D1E2D496289CE9CD2CB639BE8 + +k8/4Ax6UcnImNvEuybHwa9OHZHeCpKmq3Cu/q29a9AkTnktAWVmU9rQFch5CweDH +TEuRN+ZHecHrrMPR0fTpjXzZTxmU3549BQ2DfMSAdikPNKtBvhJwpT2se0rJ9M98 +p2xJQNhpxXT6f4Hy8m6QvjP5iTmlnQrrVBjV05ih9TLLQb4Y4NlydC08OyEcEoJV +w43G69sv2ws/tUVr7XSUtv8l+51ywSm42Pw6YOVlMZ7y+XB/uWmFNMz5gLN17tkc +wikhgvNnMWGLqb/AruuKPp5FrGRIC19DKRzDSPF5WlzLBdd2TQKDltknDj08AQMJ +bDsImbePteqhU+D7GiN2pVAD2b5kCZlFzYG43/Q8R3+O2l0Lvq5VBIqNB7LyJfTy +DL8XX0gzHk7FgG5MfLYin/qp7upnDXeSnIm8A2tlBYh9YzG3q/a53c5V2NomWjX0 +zvS+C7+w5NDwDRT5t+kecMhmHWNBuE/Pbvy0DaZQ/nnsC6TlkcaROJ0fiY3Da8E6 +EYvM4uKaZudsOOapwx0ZXHu2GZgLnly0p2Cd0Yf9t2UX9uySfwdL2TNw8nLVNVkh +aBE/x9LkKPWqOBV8tg/9ITGys/qgZh0A1r+RGmj/tII= +-----END DSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub new file mode 100644 index 0000000..18f5804 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAP25RC69mW4t09jpaine5ZRHmOtqNJa2nbsRrSsZkvGXxbJ7ojxsybWf4kAAI4GpsGMzlrFrlMEpHQfebJAn+zJwGS+loR7T+gNz8JoVIgPF9dabXVymcygl4FB/sNAmV4XK3OjvSW1NCKdSkwZZr/gz5JBo1qAiQDKMD/ikWqq/AAAAFQC/rPmzFozpCeLbFQykOaDGFZaqaQAAAIEAw1hJAYQzn/ZboF/xXDHzP49uRpIIoyaSfUz5W3+Lpi/CBkOIGaGOuitwcpTfzBSZIDZ9ORs9fq5oBh29JJcAdBNgVXfzThSiGvBgU4UIj41MlG4PG6St88VXCy0niEXWmjSkdcW3hZ0ai0SOlVxxEkYneg7RH9Seh+U3rRacrh4AAACAOX41OCxx8mTuxpON/uZn6GwvK/m0K9fr/UmIX8D4Mp8PgnPLC71AOwLy1HrCVi3ohCqeSY2C1uf1VWUVlSqMH85Pxc7pLtuULoQdCgiYt1agVrioFSP6bEyFdV8vGxA4YGh6cUSkeFZBJBrdNM4VmYBeT+3n/IO5uUbWoPK5iAo= diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result new file mode 100644 index 0000000..ad14260 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ssh-dss", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP25RC69mW4t09jpaine5ZRHmOtqNJa2\nnbsRrSsZkvGXxbJ7ojxsybWf4kAAI4GpsGMzlrFrlMEpHQfebJAn+zJwGS+loR7T\n+gNz8JoVIgPF9dabXVymcygl4FB/sNAmV4XK3OjvSW1NCKdSkwZZr/gz5JBo1qAi\nQDKMD/ikWqq/AhUAv6z5sxaM6Qni2xUMpDmgxhWWqmkCgYEAw1hJAYQzn/ZboF/x\nXDHzP49uRpIIoyaSfUz5W3+Lpi/CBkOIGaGOuitwcpTfzBSZIDZ9ORs9fq5oBh29\nJJcAdBNgVXfzThSiGvBgU4UIj41MlG4PG6St88VXCy0niEXWmjSkdcW3hZ0ai0SO\nlVxxEkYneg7RH9Seh+U3rRacrh4DgYQAAoGAOX41OCxx8mTuxpON/uZn6GwvK/m0\nK9fr/UmIX8D4Mp8PgnPLC71AOwLy1HrCVi3ohCqeSY2C1uf1VWUVlSqMH85Pxc7p\nLtuULoQdCgiYt1agVrioFSP6bEyFdV8vGxA4YGh6cUSkeFZBJBrdNM4VmYBeT+3n\n/IO5uUbWoPK5iAo=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAP25RC69mW4t09jpaine5ZRHmOtqNJa2nbsRrSsZkvGXxbJ7ojxsybWf4kAAI4GpsGMzlrFrlMEpHQfebJAn+zJwGS+loR7T+gNz8JoVIgPF9dabXVymcygl4FB/sNAmV4XK3OjvSW1NCKdSkwZZr/gz5JBo1qAiQDKMD/ikWqq/AAAAFQC/rPmzFozpCeLbFQykOaDGFZaqaQAAAIEAw1hJAYQzn/ZboF/xXDHzP49uRpIIoyaSfUz5W3+Lpi/CBkOIGaGOuitwcpTfzBSZIDZ9ORs9fq5oBh29JJcAdBNgVXfzThSiGvBgU4UIj41MlG4PG6St88VXCy0niEXWmjSkdcW3hZ0ai0SOlVxxEkYneg7RH9Seh+U3rRacrh4AAACAOX41OCxx8mTuxpON/uZn6GwvK/m0K9fr/UmIX8D4Mp8PgnPLC71AOwLy1HrCVi3ohCqeSY2C1uf1VWUVlSqMH85Pxc7pLtuULoQdCgiYt1agVrioFSP6bEyFdV8vGxA4YGh6cUSkeFZBJBrdNM4VmYBeT+3n/IO5uUbWoPK5iAo=", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result new file mode 100644 index 0000000..18c5271 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP25RC69mW4t09jpaine5ZRHmOtqNJa2\nnbsRrSsZkvGXxbJ7ojxsybWf4kAAI4GpsGMzlrFrlMEpHQfebJAn+zJwGS+loR7T\n+gNz8JoVIgPF9dabXVymcygl4FB/sNAmV4XK3OjvSW1NCKdSkwZZr/gz5JBo1qAi\nQDKMD/ikWqq/AhUAv6z5sxaM6Qni2xUMpDmgxhWWqmkCgYEAw1hJAYQzn/ZboF/x\nXDHzP49uRpIIoyaSfUz5W3+Lpi/CBkOIGaGOuitwcpTfzBSZIDZ9ORs9fq5oBh29\nJJcAdBNgVXfzThSiGvBgU4UIj41MlG4PG6St88VXCy0niEXWmjSkdcW3hZ0ai0SO\nlVxxEkYneg7RH9Seh+U3rRacrh4DgYQAAoGAOX41OCxx8mTuxpON/uZn6GwvK/m0\nK9fr/UmIX8D4Mp8PgnPLC71AOwLy1HrCVi3ohCqeSY2C1uf1VWUVlSqMH85Pxc7p\nLtuULoQdCgiYt1agVrioFSP6bEyFdV8vGxA4YGh6cUSkeFZBJBrdNM4VmYBeT+3n\n/IO5uUbWoPK5iAo=\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAP25RC69mW4t09jpaine5ZRHmOtqNJa2nbsRrSsZkvGXxbJ7ojxsybWf4kAAI4GpsGMzlrFrlMEpHQfebJAn+zJwGS+loR7T+gNz8JoVIgPF9dabXVymcygl4FB/sNAmV4XK3OjvSW1NCKdSkwZZr/gz5JBo1qAiQDKMD/ikWqq/AAAAFQC/rPmzFozpCeLbFQykOaDGFZaqaQAAAIEAw1hJAYQzn/ZboF/xXDHzP49uRpIIoyaSfUz5W3+Lpi/CBkOIGaGOuitwcpTfzBSZIDZ9ORs9fq5oBh29JJcAdBNgVXfzThSiGvBgU4UIj41MlG4PG6St88VXCy0niEXWmjSkdcW3hZ0ai0SOlVxxEkYneg7RH9Seh+U3rRacrh4AAACAOX41OCxx8mTuxpON/uZn6GwvK/m0K9fr/UmIX8D4Mp8PgnPLC71AOwLy1HrCVi3ohCqeSY2C1uf1VWUVlSqMH85Pxc7pLtuULoQdCgiYt1agVrioFSP6bEyFdV8vGxA4YGh6cUSkeFZBJBrdNM4VmYBeT+3n/IO5uUbWoPK5iAo=", + "private": "-----BEGIN DSA PRIVATE KEY-----\nMIIBvAIBAAKBgQD9uUQuvZluLdPY6Wop3uWUR5jrajSWtp27Ea0rGZLxl8Wye6I8\nbMm1n+JAACOBqbBjM5axa5TBKR0H3myQJ/sycBkvpaEe0/oDc/CaFSIDxfXWm11c\npnMoJeBQf7DQJleFytzo70ltTQinUpMGWa/4M+SQaNagIkAyjA/4pFqqvwIVAL+s\n+bMWjOkJ4tsVDKQ5oMYVlqppAoGBAMNYSQGEM5/2W6Bf8Vwx8z+PbkaSCKMmkn1M\n+Vt/i6YvwgZDiBmhjrorcHKU38wUmSA2fTkbPX6uaAYdvSSXAHQTYFV3804Uohrw\nYFOFCI+NTJRuDxukrfPFVwstJ4hF1po0pHXFt4WdGotEjpVccRJGJ3oO0R/Unofl\nN60WnK4eAoGAOX41OCxx8mTuxpON/uZn6GwvK/m0K9fr/UmIX8D4Mp8PgnPLC71A\nOwLy1HrCVi3ohCqeSY2C1uf1VWUVlSqMH85Pxc7pLtuULoQdCgiYt1agVrioFSP6\nbEyFdV8vGxA4YGh6cUSkeFZBJBrdNM4VmYBeT+3n/IO5uUbWoPK5iAoCFQCdYU1l\nO1pCZ3Jhf/YDAAnfQHAtMxAQEBAQEBAQEBAQEBAQEBA=\n-----END DSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa new file mode 100644 index 0000000..f4170ac --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJx7zPcbJg1zUAsBhKbmN0eOjbr+/W2qGSZTCP/c0mz4oAoGCCqGSM49 +AwEHoUQDQgAELN85t86lbEONGsyPNDxD/P2f9D9/ePBT3ZpAeVYUdyrVO00jO4JE +FPfKlVc4htC9oZbDaNeW1ssAIbn4uzigMQ== +-----END EC PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub new file mode 100644 index 0000000..8f39dd6 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCzfObfOpWxDjRrMjzQ8Q/z9n/Q/f3jwU92aQHlWFHcq1TtNIzuCRBT3ypVXOIbQvaGWw2jXltbLACG5+Ls4oDE= old openssh format diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result new file mode 100644 index 0000000..68f3c14 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "old openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELN85t86lbEONGsyPNDxD/P2f9D9/\nePBT3ZpAeVYUdyrVO00jO4JEFPfKlVc4htC9oZbDaNeW1ssAIbn4uzigMQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCzfObfOpWxDjRrMjzQ8Q/z9n/Q/f3jwU92aQHlWFHcq1TtNIzuCRBT3ypVXOIbQvaGWw2jXltbLACG5+Ls4oDE=", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result new file mode 100644 index 0000000..cfabd13 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELN85t86lbEONGsyPNDxD/P2f9D9/\nePBT3ZpAeVYUdyrVO00jO4JEFPfKlVc4htC9oZbDaNeW1ssAIbn4uzigMQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCzfObfOpWxDjRrMjzQ8Q/z9n/Q/f3jwU92aQHlWFHcq1TtNIzuCRBT3ypVXOIbQvaGWw2jXltbLACG5+Ls4oDE=", + "private": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIJx7zPcbJg1zUAsBhKbmN0eOjbr+/W2qGSZTCP/c0mz4oAoGCCqGSM49\nAwEHoUQDQgAELN85t86lbEONGsyPNDxD/P2f9D9/ePBT3ZpAeVYUdyrVO00jO4JE\nFPfKlVc4htC9oZbDaNeW1ssAIbn4uzigMQ==\n-----END EC PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc new file mode 100644 index 0000000..7e118d8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,4BE217089AE8B7311672C159E0690AB4 + +AkqjOP53cDHrdkJFRVLHYS7fSPVcIa4BgKegLwqRUqJOvEOnn5j6RYCh2CMdPjwN +rdw26Gc0V++xeMISAbrX4TGAQPWyDyiuoCffTIAfbkNq8YQR/sNJjNmZEgtCs6+O +4iBQ8TMXO+7oWRC221FDbTIhB6k4lXXph/HzdW0/Y2A= +-----END EC PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub new file mode 100644 index 0000000..8efc1fe --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA4KgjqWJj9PR55PeF7t7PTXdx7cvMDqNkq4UTMjoXA5WtQYdoC2sxJnI5Psqvtrfa13C31gY8TlFAZ1cClnoBk= diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result new file mode 100644 index 0000000..3b3064f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDgqCOpYmP09Hnk94Xu3s9Nd3Hty8\nwOo2SrhRMyOhcDla1Bh2gLazEmcjk+yq+2t9rXcLfWBjxOUUBnVwKWegGQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA4KgjqWJj9PR55PeF7t7PTXdx7cvMDqNkq4UTMjoXA5WtQYdoC2sxJnI5Psqvtrfa13C31gY8TlFAZ1cClnoBk=", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result new file mode 100644 index 0000000..423f6e2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ecdsa-sha2-nistp256", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDgqCOpYmP09Hnk94Xu3s9Nd3Hty8\nwOo2SrhRMyOhcDla1Bh2gLazEmcjk+yq+2t9rXcLfWBjxOUUBnVwKWegGQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA4KgjqWJj9PR55PeF7t7PTXdx7cvMDqNkq4UTMjoXA5WtQYdoC2sxJnI5Psqvtrfa13C31gY8TlFAZ1cClnoBk=", + "private": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIA7fGKE3wZkXb6jMcMriZujktUQ6FTC0SoTAa6fKDXY8oAoGCCqGSM49\nAwEHoUQDQgAEDgqCOpYmP09Hnk94Xu3s9Nd3Hty8wOo2SrhRMyOhcDla1Bh2gLaz\nEmcjk+yq+2t9rXcLfWBjxOUUBnVwKWegGQcHBwcHBwc=\n-----END EC PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa new file mode 100644 index 0000000..2eadbb0 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA8wISnx2xWoeZur8yn/8NPykUY2mYyxn1n0mE5WJSo+mclFFS +mnN08WCt856AO8PMPuAn9cw0j3qJe0SKTnoMYSp+4fBsq6YHOGJvlRATF9SJkSIx +wBCYsMT+cf78vzhKRJrXAfJ/LWzV7b5gThHxj+Jby+fE/yePi8+Mb39UwYWGEFf+ +uRxcQIeuDX/VjPNtNKQPuO+HRi67WNXPFoUNmFXv1Ymn61S5duvVCxL8XdHXHdnZ +gIJ87CTlLBGPV/U9HrGJfl0AQ/jvMsvAV4IhMZMlV5QS2QigK7rkfBVe7k0NIWQ7 +Vwk5iunUpmUNVhKARdznvb8CJJm0ZEx4F2n8cQIDAQABAoIBAQCtZR46cSp6qWU1 +DnamGYyvM7W7lb6TtYtAxGnSb0z+bpPudPSXBqk8DrswqTlg674SY0nAJpyegFYX +Ifn6MzYgIv10ZGR2OjrOrdZmq5ikGWCrsZWEMZNyFq5kUwivvQ+pUj72wbyjghRH +1t7K9hzCiUbtAQzc77KKlWbkrBujFSp5EPNT67j5vV29WnZFbkPdUmfkM/ca/CZc +CWwvyAx19aFGyw3BsFhWQP5C9waT+QI9QZrVOA+8wTT11OcR6PT0oKdEmSYCKgHJ +JuYDWZ2XX2R2d5YNoxiqIZbCqQ/ayJuLOjLgQ1mx17pUyMNP3PoZCQXOi4jZWHZZ ++3/jqvJNAoGBAPmoL03KPvLVtHByEdxzPPfnonpYjfjlD4FvXgSQjdAcrTy4O06t +bDf4hMgUHQmDCyUakO45wyYwP0ISapQSBWniryjR/7U7/G/dX45fKRUeNoMvpmSC +qSEMAbd31Inpzuu5k0Y8p3hvoexeYlhbRkBL1ryx1LgIvC0TkWR+e6EvAoGBAPku +pHcpi3t2wewmP6f1krxtOLyvVt5RKaRjZ/2gNtzLPXL6ulQR5hufYlLKgyyyf2gJ +HxVFhCkfRjwVHV8qdIJc+Q4mjnjOeNfvqnzWOlSfZFegyWvOPW7hTX0/jZYGOb4I +7fzYyUPHnlu73twmshJMTzE1Ju7RdJXyLtg8xpRfAoGBAKjlyELXTWjZfP4Jnd3H +NHr+gSRGHp5A0RGe9zsdVGNz0xteA/mBR9JB1grJ2K8jsXmDlIMmHskKIPGhJetQ +mcr9qcRy9Yx1rZ08ZbYa2N9JllV/+hDLeII77jlh3y8CN5Ov81u0ExReaWxQmjXu +YgODix4TLLboae4Q6+7Rxu/PAoGAOZ04N7kqX/ygb+qUE1Crgde7I51i93pKp5C4 +baMKrFhtt9UTGfcdfkuG31+lnsMSxEo/npp5KUzq319+cA+P6sh2aXguvu32cO8g +O0cJK6HDAKPTjpKcD7QWR5xXL1X3KeJErI6vUnWoPsuchsiHqcVtFhKVEujpDPZ3 +MFY1D/8CgYBvv5mBb2kBf2/2JHp3lP/Q6LepEBkZk9dvoEU6/5xLvA5gEXR0MUj8 +g97Z1duGdXD/uEVRuRuOJkk4p8YmSM7t34st3lF06wdJUGcKvmZpp2ee+CdLwESi +GDCwcP5pcii56TVr09uHITWei4jFm+3Ye3h092dvPyNoEiJOgk2lsg== +-----END RSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub new file mode 100644 index 0000000..1eaa7e0 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzAhKfHbFah5m6vzKf/w0/KRRjaZjLGfWfSYTlYlKj6ZyUUVKac3TxYK3znoA7w8w+4Cf1zDSPeol7RIpOegxhKn7h8Gyrpgc4Ym+VEBMX1ImRIjHAEJiwxP5x/vy/OEpEmtcB8n8tbNXtvmBOEfGP4lvL58T/J4+Lz4xvf1TBhYYQV/65HFxAh64Nf9WM8200pA+474dGLrtY1c8WhQ2YVe/ViafrVLl269ULEvxd0dcd2dmAgnzsJOUsEY9X9T0esYl+XQBD+O8yy8BXgiExkyVXlBLZCKAruuR8FV7uTQ0hZDtXCTmK6dSmZQ1WEoBF3Oe9vwIkmbRkTHgXafxx old openssh format diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result new file mode 100644 index 0000000..720438a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "old openssh format", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8wISnx2xWoeZur8yn/8N\nPykUY2mYyxn1n0mE5WJSo+mclFFSmnN08WCt856AO8PMPuAn9cw0j3qJe0SKTnoM\nYSp+4fBsq6YHOGJvlRATF9SJkSIxwBCYsMT+cf78vzhKRJrXAfJ/LWzV7b5gThHx\nj+Jby+fE/yePi8+Mb39UwYWGEFf+uRxcQIeuDX/VjPNtNKQPuO+HRi67WNXPFoUN\nmFXv1Ymn61S5duvVCxL8XdHXHdnZgIJ87CTlLBGPV/U9HrGJfl0AQ/jvMsvAV4Ih\nMZMlV5QS2QigK7rkfBVe7k0NIWQ7Vwk5iunUpmUNVhKARdznvb8CJJm0ZEx4F2n8\ncQIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDzAhKfHbFah5m6vzKf/w0/KRRjaZjLGfWfSYTlYlKj6ZyUUVKac3TxYK3znoA7w8w+4Cf1zDSPeol7RIpOegxhKn7h8Gyrpgc4Ym+VEBMX1ImRIjHAEJiwxP5x/vy/OEpEmtcB8n8tbNXtvmBOEfGP4lvL58T/J4+Lz4xvf1TBhYYQV/65HFxAh64Nf9WM8200pA+474dGLrtY1c8WhQ2YVe/ViafrVLl269ULEvxd0dcd2dmAgnzsJOUsEY9X9T0esYl+XQBD+O8yy8BXgiExkyVXlBLZCKAruuR8FV7uTQ0hZDtXCTmK6dSmZQ1WEoBF3Oe9vwIkmbRkTHgXafxx", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result new file mode 100644 index 0000000..affc996 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8wISnx2xWoeZur8yn/8N\nPykUY2mYyxn1n0mE5WJSo+mclFFSmnN08WCt856AO8PMPuAn9cw0j3qJe0SKTnoM\nYSp+4fBsq6YHOGJvlRATF9SJkSIxwBCYsMT+cf78vzhKRJrXAfJ/LWzV7b5gThHx\nj+Jby+fE/yePi8+Mb39UwYWGEFf+uRxcQIeuDX/VjPNtNKQPuO+HRi67WNXPFoUN\nmFXv1Ymn61S5duvVCxL8XdHXHdnZgIJ87CTlLBGPV/U9HrGJfl0AQ/jvMsvAV4Ih\nMZMlV5QS2QigK7rkfBVe7k0NIWQ7Vwk5iunUpmUNVhKARdznvb8CJJm0ZEx4F2n8\ncQIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDzAhKfHbFah5m6vzKf/w0/KRRjaZjLGfWfSYTlYlKj6ZyUUVKac3TxYK3znoA7w8w+4Cf1zDSPeol7RIpOegxhKn7h8Gyrpgc4Ym+VEBMX1ImRIjHAEJiwxP5x/vy/OEpEmtcB8n8tbNXtvmBOEfGP4lvL58T/J4+Lz4xvf1TBhYYQV/65HFxAh64Nf9WM8200pA+474dGLrtY1c8WhQ2YVe/ViafrVLl269ULEvxd0dcd2dmAgnzsJOUsEY9X9T0esYl+XQBD+O8yy8BXgiExkyVXlBLZCKAruuR8FV7uTQ0hZDtXCTmK6dSmZQ1WEoBF3Oe9vwIkmbRkTHgXafxx", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA8wISnx2xWoeZur8yn/8NPykUY2mYyxn1n0mE5WJSo+mclFFS\nmnN08WCt856AO8PMPuAn9cw0j3qJe0SKTnoMYSp+4fBsq6YHOGJvlRATF9SJkSIx\nwBCYsMT+cf78vzhKRJrXAfJ/LWzV7b5gThHxj+Jby+fE/yePi8+Mb39UwYWGEFf+\nuRxcQIeuDX/VjPNtNKQPuO+HRi67WNXPFoUNmFXv1Ymn61S5duvVCxL8XdHXHdnZ\ngIJ87CTlLBGPV/U9HrGJfl0AQ/jvMsvAV4IhMZMlV5QS2QigK7rkfBVe7k0NIWQ7\nVwk5iunUpmUNVhKARdznvb8CJJm0ZEx4F2n8cQIDAQABAoIBAQCtZR46cSp6qWU1\nDnamGYyvM7W7lb6TtYtAxGnSb0z+bpPudPSXBqk8DrswqTlg674SY0nAJpyegFYX\nIfn6MzYgIv10ZGR2OjrOrdZmq5ikGWCrsZWEMZNyFq5kUwivvQ+pUj72wbyjghRH\n1t7K9hzCiUbtAQzc77KKlWbkrBujFSp5EPNT67j5vV29WnZFbkPdUmfkM/ca/CZc\nCWwvyAx19aFGyw3BsFhWQP5C9waT+QI9QZrVOA+8wTT11OcR6PT0oKdEmSYCKgHJ\nJuYDWZ2XX2R2d5YNoxiqIZbCqQ/ayJuLOjLgQ1mx17pUyMNP3PoZCQXOi4jZWHZZ\n+3/jqvJNAoGBAPmoL03KPvLVtHByEdxzPPfnonpYjfjlD4FvXgSQjdAcrTy4O06t\nbDf4hMgUHQmDCyUakO45wyYwP0ISapQSBWniryjR/7U7/G/dX45fKRUeNoMvpmSC\nqSEMAbd31Inpzuu5k0Y8p3hvoexeYlhbRkBL1ryx1LgIvC0TkWR+e6EvAoGBAPku\npHcpi3t2wewmP6f1krxtOLyvVt5RKaRjZ/2gNtzLPXL6ulQR5hufYlLKgyyyf2gJ\nHxVFhCkfRjwVHV8qdIJc+Q4mjnjOeNfvqnzWOlSfZFegyWvOPW7hTX0/jZYGOb4I\n7fzYyUPHnlu73twmshJMTzE1Ju7RdJXyLtg8xpRfAoGBAKjlyELXTWjZfP4Jnd3H\nNHr+gSRGHp5A0RGe9zsdVGNz0xteA/mBR9JB1grJ2K8jsXmDlIMmHskKIPGhJetQ\nmcr9qcRy9Yx1rZ08ZbYa2N9JllV/+hDLeII77jlh3y8CN5Ov81u0ExReaWxQmjXu\nYgODix4TLLboae4Q6+7Rxu/PAoGAOZ04N7kqX/ygb+qUE1Crgde7I51i93pKp5C4\nbaMKrFhtt9UTGfcdfkuG31+lnsMSxEo/npp5KUzq319+cA+P6sh2aXguvu32cO8g\nO0cJK6HDAKPTjpKcD7QWR5xXL1X3KeJErI6vUnWoPsuchsiHqcVtFhKVEujpDPZ3\nMFY1D/8CgYBvv5mBb2kBf2/2JHp3lP/Q6LepEBkZk9dvoEU6/5xLvA5gEXR0MUj8\ng97Z1duGdXD/uEVRuRuOJkk4p8YmSM7t34st3lF06wdJUGcKvmZpp2ee+CdLwESi\nGDCwcP5pcii56TVr09uHITWei4jFm+3Ye3h092dvPyNoEiJOgk2lsg==\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc new file mode 100644 index 0000000..e5b6398 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,1380F5ADA0E0B636860A6BF78D47D6B2 + +ICLCebZN4+91mTQwByj210FD3D7kCxFA6kZ5fZ1TG34RzGynOSgUSdxPaXBHO4hC +DjS7lv6vrtaXPxlz5MVAhb6n0+X1pZDu5Wh5xjtkOt9yt4YPNKkvDPazSFBTHDth +jURe/aCLwXa+N5g5v1G/asb5dufA96tiPD8jjsBPm6RPq/444jAnLkid6YwTRLCk +a+IZZ+sX8onOq2xJM5NhsJxCEp5yquQCdyjvBBEBk5PExvWDHz4BIkK0WDR86IX/ +j4baAbTREiwP+EmVw1uogijvS+9nWPv3dQrtWwNQQNdWE2jJnsuDv44VAh1QQD7A +Txz2Y2A6IyzQsDxr6fL4JidVZOeeOXagYOBceZMs4IdNVJ52LJ9fqWtH1Eavj0za +c9zLgFN547l/Uqc334BQTkWhA9zGNkYJo4GCl/zjL2C6ce9gp0l6aBwSRyBmfH21 +pxFYqO/LQOSTbupeGzkNOpeNm/XtdOHe2N+2fiMO8hqEr6tOR4dsEUVBLCWt3tpD +C4jT3TtXKvx4qPV5N0w/umgXDd01Npk02k+wiQRnPBczFYLfRpceV/7MGtttV86/ +Ldl2p00q+JB6TzkHfOa4dA8oZJAwz3RPwmGYt/riJS4JOIpQGCs9lU3zgi7NTt4L +T9YAlAP3fjG1n3vy1uktKfRa+AoSqgS/pTJgB2srs6vxw3kt/V825cVyzSfGdQM/ +2oinmrbMAs0tRpTiHyqc/FjVRTW/8+LoSv/o6ZpN2x4jxkW/7cBH0Pcytvw8svd2 +Q+h92cfHuiNWi5tuiUkeDfjWEXo6ssVFA2t1ebTOk5y2wwPVAURf/jVxhEpFm4iY +PCIqwCwNSs1S05zAaIQ39ltBETj4Y46715GuYKsqLDYhv2lAIAlWXWgQ/N0tYVS6 +Oi/Qp9XFSEeyym5vzX/2ck1SJePvHvHewiABJjYzq3wlvIdWE6V3tJ3MRXRhlKNf +4bG8caItSG1n/QIeguNZI+A2Pu8AIdKjjKsnVcn3mikuKfcCAICZwf6m3Bd+Al7G +lrsJxyPqhhbPN1/t0w30tu8QuTSV+uMx4ZCKoUc6yJMQRmoM0RJ626re51IT2ikk +gB4f3Ms1VbB176it2L/zbXUAaxeE7Cbdcp/5058ksbuE0yA7JB+a2vQHFqw8Xxsb +qdKc4m4jkCdvaA5oNnGoG4milYukp1WVCGJeLD7gspTHR5dDYsOQgHvkxu+Ukor+ +0+1yvf8R6pRJWMoV0VvNkuSBUqcx94A+xLaEYCkB78Koum8xlPA1OA7VVkMVjQSk +r6c/iANbNV20IVz1TBpg9J1rQOGisbE43yRkH+aMgHnAnhk+UgK584QOH6eJpGZT +yBwes57P1kgT5VubavoJbeZLL6B70Sn/sKoLzxxruzPKmsmufJNK9klB7lu5f4gj +lvKtuNaiWbux1+fQmU+05nM1WW7s5Nm9MVUCfS5RxUq8SRqC7W17ouHEssW6mJT1 +jHK1xhoxX05X/T0NfdPzbG7S7+DG18Q6jnyHb28LeKLXv33sEUrT5z7+Nx4JS4XM +ZeMzPdRgYJw9vLQSYdksj0cNBb8UpAiG410lICrbPGWJh9d2KzhNKlfk/vLHia1V +-----END RSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub new file mode 100644 index 0000000..806ab91 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHLfm98g0aHjbQJcjbamutwkWTMY426a4IdwGrpAOv806h6wBXNcOj2VJbgeQ2/XkQ0RY78fGrHSacaadGsT9E5sRGyvkr/WtDpBokXrgpP15OvhfTaSMVTcty6qknndpu7P5nmSipdn9fQR9TyNRyAajhn+UINuquGfxyLL30W4IBqSISOcXKc0pScTdMOIOmkxxY+vQFydQpWF0a3TopKKa4b3sQJgqc0MJkREllT6U+0U4+YufoW6zZyMNIS2gxWUlGUiA5XveWSaYIXCaPQmps4WoO9AlrM7z1sTcG5yXn0kEUvTmBYUOUlffiBgXzArt4Pmm8gVklR5UH98y5 diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result new file mode 100644 index 0000000..b4aad7b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result @@ -0,0 +1,8 @@ +{ + "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxy35vfINGh420CXI22pr\nrcJFkzGONumuCHcBq6QDr/NOoesAVzXDo9lSW4HkNv15ENEWO/Hxqx0mnGmnRrE/\nRObERsr5K/1rQ6QaJF64KT9eTr4X02kjFU3LcuqpJ53abuz+Z5koqXZ/X0EfU8jU\ncgGo4Z/lCDbqrhn8ciy99FuCAakiEjnFynNKUnE3TDiDppMcWPr0BcnUKVhdGt06\nKSimuG97ECYKnNDCZERJZU+lPtFOPmLn6Fus2cjDSEtoMVlJRlIgOV73lkmmCFwm\nj0JqbOFqDvQJazO89bE3Bucl59JBFL05gWFDlJX34gYF8wK7eD5pvIFZJUeVB/fM\nuQIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHLfm98g0aHjbQJcjbamutwkWTMY426a4IdwGrpAOv806h6wBXNcOj2VJbgeQ2/XkQ0RY78fGrHSacaadGsT9E5sRGyvkr/WtDpBokXrgpP15OvhfTaSMVTcty6qknndpu7P5nmSipdn9fQR9TyNRyAajhn+UINuquGfxyLL30W4IBqSISOcXKc0pScTdMOIOmkxxY+vQFydQpWF0a3TopKKa4b3sQJgqc0MJkREllT6U+0U4+YufoW6zZyMNIS2gxWUlGUiA5XveWSaYIXCaPQmps4WoO9AlrM7z1sTcG5yXn0kEUvTmBYUOUlffiBgXzArt4Pmm8gVklR5UH98y5", + "private": null +} + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result new file mode 100644 index 0000000..fddff0f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxy35vfINGh420CXI22pr\nrcJFkzGONumuCHcBq6QDr/NOoesAVzXDo9lSW4HkNv15ENEWO/Hxqx0mnGmnRrE/\nRObERsr5K/1rQ6QaJF64KT9eTr4X02kjFU3LcuqpJ53abuz+Z5koqXZ/X0EfU8jU\ncgGo4Z/lCDbqrhn8ciy99FuCAakiEjnFynNKUnE3TDiDppMcWPr0BcnUKVhdGt06\nKSimuG97ECYKnNDCZERJZU+lPtFOPmLn6Fus2cjDSEtoMVlJRlIgOV73lkmmCFwm\nj0JqbOFqDvQJazO89bE3Bucl59JBFL05gWFDlJX34gYF8wK7eD5pvIFZJUeVB/fM\nuQIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHLfm98g0aHjbQJcjbamutwkWTMY426a4IdwGrpAOv806h6wBXNcOj2VJbgeQ2/XkQ0RY78fGrHSacaadGsT9E5sRGyvkr/WtDpBokXrgpP15OvhfTaSMVTcty6qknndpu7P5nmSipdn9fQR9TyNRyAajhn+UINuquGfxyLL30W4IBqSISOcXKc0pScTdMOIOmkxxY+vQFydQpWF0a3TopKKa4b3sQJgqc0MJkREllT6U+0U4+YufoW6zZyMNIS2gxWUlGUiA5XveWSaYIXCaPQmps4WoO9AlrM7z1sTcG5yXn0kEUvTmBYUOUlffiBgXzArt4Pmm8gVklR5UH98y5", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAxy35vfINGh420CXI22prrcJFkzGONumuCHcBq6QDr/NOoesA\nVzXDo9lSW4HkNv15ENEWO/Hxqx0mnGmnRrE/RObERsr5K/1rQ6QaJF64KT9eTr4X\n02kjFU3LcuqpJ53abuz+Z5koqXZ/X0EfU8jUcgGo4Z/lCDbqrhn8ciy99FuCAaki\nEjnFynNKUnE3TDiDppMcWPr0BcnUKVhdGt06KSimuG97ECYKnNDCZERJZU+lPtFO\nPmLn6Fus2cjDSEtoMVlJRlIgOV73lkmmCFwmj0JqbOFqDvQJazO89bE3Bucl59JB\nFL05gWFDlJX34gYF8wK7eD5pvIFZJUeVB/fMuQIDAQABAoIBAGuSfhZDGyZm+Q2T\nypYONNekW7Uyh29K5640r9dGfqNRkb9LT2TKab4dSiiXz2yPmwolEpAPjIjw9oB1\nY11/rv8Eby8YwlgqxvrCL0hDS80jJ0j5y55nYwZHfMC00eTOkUFlh8Tl6BsWH5aP\ncl7q0So9kTtCAw1bs4WSDVCQr4q/x7fZRQWeWudi4IjnCv5vn1Pgot7XxDwdFNQG\nDrkUHvYXv0M2OCdl7YN0D/bHQon5ney0YU10mtqGbkcEmu0woykW1Bc539b9AoD3\nxI6LVyY6/OEwGu5ctKolIVJjsguwfLJ9WR7SenR5nTzjJyxMdSfXtXkKPX2NZxpO\nziNYnm0CgYEA/afEFBu5Ld/TjYatdf7ezZe9iDx6vBzWmMtwkhr3OHCzVP1OIaB0\nSTsCWrTdoLFTMOizUHjj71vX5v5G4aCgaMXQnSDf13mxrFzR36w5oyJOBLjkHhol\nf0ROO7QCXK1hjBAUvnKwLPQvx1CAkDB9z+cT/BJwRCarfeLhrd/sGEMCgYEAyQVN\nOGIdRVBs3Q/8dbtaz+7LOv6IBZm2y9TKHKmfBm1txAsgkqRl7cfVTyczgAZfS/RB\nzrAje5UA+phCSPtyb5B+K1i/eHw7xDZrw8wauAKY8ILSadS9ZA0mU+7XCqsWhNqN\nrvuB5dttsTDgyXnMxCbYqCWAcyKn8jBh1cDo5VMCgYBe3iMQnjnI9YCK2wb/LZ6o\n6Aqj7HK+7k44gUYN7vXtbwEzVTWmj/tN9DryL9kAI7IIhc+i1kPxnrkGFK3v7wJv\njSRzz/rH/SS9YU3BSQmZgNgLHhd7Rq4lhid4Xt/PR61HFDCd9gj8FyvTcMFUrD4x\nxqwLx92jL49OGs/rFueXPwKBgBi46jJQ/sCTj4/wc2AXVqfT+nKa8yedK/oNhX3Y\n7pHfy2wc4jimt1JzDSza6V6JahbxR1agGv0L6j7nkt9e7UgDQUEbfRDYVpFfEAnY\nhEC1MRIDRNV3MIOpilkwOoo5WF+mcV5f2C3ouqjcFgkxTZmiHWswkYeXb4g9owqi\n2wG5AoGAb6/btpj3Ql+qYXRUH/cWPlLeFbKiGaAJ+Kn5RwlEW8D//FjKuV7fL7BN\nhvaDJUpwP9klNRny3IK6FWuFI0KDup0nyrIbS07h2rOCl/+g2erDuS5sofpu2zWU\nZDArpSmpU9EF6S8CvbbZmYvWzYUhYD/sEqIR+KSowNM4PA7g7fwKCgoKCgoKCgoK\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 new file mode 100644 index 0000000..ceed070 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,5C3291414FA514EE9647898A2D5315FD + +PaIGvR7qnyhxjz7RI4YEeua59B0XJm6cTW6xv2tbSVIC/njwljgo+UzXJLPUH1gv +suhNs8X+U9n0aCME6vFQvSJcloo6B1NLhGL1DVNhMAiGu+byCSJtq4cTFR5+7YUQ +HGB0a5vGBtHhL86TBeaBcKYfgCE4jo6/FAvzfk/eyy3S/oHXjMMUfCqo3WrBcgLu +SwhOEGd2k7vRp4gZzsCZy9xMM4Gykrgxc/hLzyvGQF8isF5Nz6xtPLNlW9xPdD48 +Fq5CTfljR4+7mM/kruJRysnbXEoYAaA8oZhZsRD5cw2tMOartA4qUieR9sKfrMo0 +Ci7OXNkdDK83OWGZs3NUYT/BzMmIPf982Ws46RHZLQOad3qTHvFdCUeQKwPJtQZM +D40xdbw462KQi+yr8+dPs9q3yxS5lr1rG+SmCAe/s+5Ta6E6VMb30Jb9FBP+91Z8 +6XxrF9jl67xaOwz/8rqUfiYm0C31YHiSsGlewe7lmvr4W+f47kn+lxEVXJD6UG+M +l/iJMZR39nr305K4GHG29NVS/9h1XC63/FZbL+50YCfavBikvEEDZoBKSKzs3Rlh +LZOTt6netyFuJtW0Z2CsYnvyyBioztD2yVGStS1MX652uDutFuqcBgm5FCdC1XDD +c5y83mH6ZWAjJSai8ap80XATO+xImb86paJ7u96mSAq7t+ziTCjlFTl3Mmtfoyrr +yy4IWSFIZ7BGdk2yeOR+kW+UNij5tS0J8s+Ug8hIh0ax9pvIB9opB0HmCVRg8reY +KUZNUwPlBtP2Y9dU63fKf0LNkzzMZduiqN8iD/lC771TxEU/tvl9cwr0rP3Shqm7 +UYkhPG+l0iXmX9fJwfJ+sfnT6zRfUKqeuN58YpoJ1zliv+4g9wDZWDzPlcktW3RU +CcZ9nKxRzQ9WppZzPoN0OMr+POt+S9hKufGfKP0D4pvIJ3KOGvk0A31iyQ5Ua6mI +emC67kES+3djSaLBeYax0AOzxnuHc/9dcC4meGzPy3RWRknxYxt0KMlo4zR42ZTR +Qh3eA1h6POEtrwsCMUD+tI3W6QwcCCmaJW6gfwZPSqPqbLwI21NVfUS++0V8qB1X +ugRUwN7gvX9rf+2jp+IjTVXai6xPkN4LqIX8jULYihKdR+tMm/sKTEGfc+peMrN9 +iljwsPztLzAIEjr4UppaLyhJJCp4BHdveVg0/uhgBqQTuMHZtKX31IHdDjeJc2n+ +iITqdh20lwLl6fwKsAl1oBf1GaRSOsd+oi2IyXqpfMpoXlo2q/r7ExPAzDXXg0bb +tA5Awa6Fndu5BR4e4UUDDVnj3AU175D4Nz6ZyXmCBC9nB6rvXXAa/gdh8+/HL1nS +7gDU9rws6dDRP3BAE7xM8QQ4VNaPikPPlikKNTY9rom32kKMmGD64dEPuZHl/i1i +gNcQfQoLDdwQJzqYcn9ZtcsE3hPJgqwO+wvK4MhnKlYXsRnGIQVNgEt9ler98Wap +eFKgl+Jf9z+T4uJka7yFzni1HQ1kvanYpI0w5ili46te/yPE96uzhRGqn1bu+/QI +e1rC5IMHu8cYV1a/baX8r9iwIXislq6fia5ivj0fmFTYbBJZ/M4LlY3zVXlJnIQj +iykB31s5faMTUE8CDdj+fr1Dc5ERPWgiI4PxXTquPUHq7B6dhsJ6RbYkgIoBhuam +Ok39LZ/R4nTiJY9VaJwQPvdrNnQEZ9lmMnh7d8jcsja4SVNFObC2ONQ2MVbr+dXd +jTHIlOF3aqWM0ZP4dh/Zg0rIy4koL1G88/vOpKAoVPZVmftqww63TPao3uny9nTK +BjwqzalPZwt0KFSoAGr3e8psQpCXwHoP98/GyE9NVBhR4X/I2IST4Sk0x62Gz1pg +ZrGpz7VDEySYAd8GBvdOuAawjmE41YwEofRrBb7ZPbwIxrO3ei/G8f5LBABRCmjO +ikzAk9mADCnfY08nfQ8mjZAIiTth6MuFG92TeJSi1W56p+krikVh0SUxEfXeR1CR +XOyshItaWQNx7OojB3P7JG7nrY046144oQuUb7mVUi4oQE+TxKLRvc0jLkWyKmjf +Ii+BZFHuU3lQiAarQ+mZEA0pXCGCT+NDZK5Eo4LBCrYBfaviWcWB6LQoovAF2T42 +zzx5qZP4ANS7l4SUCd5qS7/h3/ftCkLHTEcV0KBJ2n3blF6wdP/7C3wQD6AcRHWQ +132dnFlD/agQ6VOFjTg4hnw7BrUtIHATKlmMg36CtXtqJYnb9DQEQDo24dBNVNjM +W1Tpgw8xkyVb9kICiZoy+kXnqqkGOnLHT12h+/pgkJqZO61kfvwUeNAK0USG/h/L +TRop17tZjsg2O6R9/aS0SnyANBJ8xgxRAneWuX6ry7t9IDYOH1Ybcn4riLe+tgCM +YPpxTOCUw49dqdkTU6/n2vEXXIRPXIefxBhIk1bKelX/owIwe+3kNSL96HzEDvI9 +GwaLRxNgMLi5diI3yJmevantJJWIKUFhz3ud2viaSWNWdAvfVmEcb7APs67cJAr9 +4oKnhF4TuD2oowFnH3nykczXRqAqHn+N/XynH0QJrQDJYwnYWH/+5YFWaYwHACSK +ppOnWNqQ28zjA7w5GLI//rHRT0NBbFbVF7s0TQlBu0Rukc042eW692BX/2qVSCpZ +8aVjhBFFbnt4YmRSYlj/X7ICnddWqHSiRNy5RMokdMlZD1ELxYf2XkkZionTlT/E +hHSsA2c4HgP5Ep9svM7EWtFO7Melk2vjgXZxyELbLPZUQuYImuK2ziKqL05YH/lc +/yfAdXOKLWjrUgVBk8r6QqoAWP0iCTZDOmB7IwVu9nLClpnJDfT3kRrai2GIpg/D +1+eBAcr6aoRfpLTduW3EAit7SNzLZSkcBvaLkkqJ3tCPTq9GR05DzOaTGCf+vyve +kRNdTMSX5E6IH3xomKTIPZrEgOMEJpdsJ4wBCt2ginYZvHOFsn+YiLL212+rLOTH +qqSKZb0O5lxgQNjl62PJ9bzDEJkiuUinz83OlLAe7fSZiT3wwKG2x8PsZugRSk6K +txDqENJGzcDsX/MLNYdy6y2MnAWRYKNsmp0luX5Exw7L8ls8jUAMnd0DS0RFB0gN +14UzNa+ZO35Xr4vj8n2URnX9O2vs+A9jcDQU7TOp1/ejq3ISATrIAjeyqUHNZ+Xq +-----END RSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub new file mode 100644 index 0000000..0df674a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDOHBVYZ041e+MqbjY+oSRiNNO1nDK1l0P6blyAyi4gwWfEOGSkqBZr+vCGnSj3/BNWsCcECbsG2TBMkoxCmXLc32rgQRz76/vON0gRaAzm+oi4N1hSSN7S/xX3XEwkH5OM/g9WKJvzerGejIExT9C6jzCvznlRdSTnntJrgwuf8ubyOfffXht66X/klC5+XeDI8SORiIr/E7q8QUpjcYYjgRgJHTjjh47xDGQOkcL+ceZb1/ufbU+4r7m8Ume/+fQuOTXcD13yKd1Na7auXMHL8Orh8YHvgwbFCVPOFDDEyReNgLLEaGGHJOuWaf55N+7J4CSDRkRqjz1tFqdqqHwdRr0/pJP77mjEe89Cx4iu+BDrT72/SPKo5bwDoXBa2TxSdoVHT9idjsUPDfwshD4eHtwyhrZkEiNY8Qp+F57I9MSgRT62zdO/vZ5wzEYDJC3DBXPw3owvpGdJEjSOhTD0rOFctNs/dKlwAXnU6QUAE1qgd9P+O3GIhYiPkrw3XsbF39VeouroYIbljv4KyDb+wQMk2U2wzUE/ZV/AVjV0OK/3colr43uxEhl6D48pWejzpQ6DMFKuL5pcxzZzIlBVmwwNsNb3DoWQ+a1gepyimp1ocUlv28JPqMMiarm/Kka86KY+fzcHUUPQXpz8R4edOLA2hQSudYdTcNmcAOpwMw== diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result new file mode 100644 index 0000000..3f23304 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result @@ -0,0 +1,6 @@ +{ "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzhwVWGdONXvjKm42PqEk\nYjTTtZwytZdD+m5cgMouIMFnxDhkpKgWa/rwhp0o9/wTVrAnBAm7BtkwTJKMQply\n3N9q4EEc++v7zjdIEWgM5vqIuDdYUkje0v8V91xMJB+TjP4PViib83qxnoyBMU/Q\nuo8wr855UXUk557Sa4MLn/Lm8jn3314beul/5JQufl3gyPEjkYiK/xO6vEFKY3GG\nI4EYCR0444eO8QxkDpHC/nHmW9f7n21PuK+5vFJnv/n0Ljk13A9d8indTWu2rlzB\ny/Dq4fGB74MGxQlTzhQwxMkXjYCyxGhhhyTrlmn+eTfuyeAkg0ZEao89bRanaqh8\nHUa9P6ST++5oxHvPQseIrvgQ60+9v0jyqOW8A6FwWtk8UnaFR0/YnY7FDw38LIQ+\nHh7cMoa2ZBIjWPEKfheeyPTEoEU+ts3Tv72ecMxGAyQtwwVz8N6ML6RnSRI0joUw\n9KzhXLTbP3SpcAF51OkFABNaoHfT/jtxiIWIj5K8N17Gxd/VXqLq6GCG5Y7+Csg2\n/sEDJNlNsM1BP2VfwFY1dDiv93KJa+N7sRIZeg+PKVno86UOgzBSri+aXMc2cyJQ\nVZsMDbDW9w6FkPmtYHqcopqdaHFJb9vCT6jDImq5vypGvOimPn83B1FD0F6c/EeH\nnTiwNoUErnWHU3DZnADqcDMCAwEAAQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAACAQDOHBVYZ041e+MqbjY+oSRiNNO1nDK1l0P6blyAyi4gwWfEOGSkqBZr+vCGnSj3/BNWsCcECbsG2TBMkoxCmXLc32rgQRz76/vON0gRaAzm+oi4N1hSSN7S/xX3XEwkH5OM/g9WKJvzerGejIExT9C6jzCvznlRdSTnntJrgwuf8ubyOfffXht66X/klC5+XeDI8SORiIr/E7q8QUpjcYYjgRgJHTjjh47xDGQOkcL+ceZb1/ufbU+4r7m8Ume/+fQuOTXcD13yKd1Na7auXMHL8Orh8YHvgwbFCVPOFDDEyReNgLLEaGGHJOuWaf55N+7J4CSDRkRqjz1tFqdqqHwdRr0/pJP77mjEe89Cx4iu+BDrT72/SPKo5bwDoXBa2TxSdoVHT9idjsUPDfwshD4eHtwyhrZkEiNY8Qp+F57I9MSgRT62zdO/vZ5wzEYDJC3DBXPw3owvpGdJEjSOhTD0rOFctNs/dKlwAXnU6QUAE1qgd9P+O3GIhYiPkrw3XsbF39VeouroYIbljv4KyDb+wQMk2U2wzUE/ZV/AVjV0OK/3colr43uxEhl6D48pWejzpQ6DMFKuL5pcxzZzIlBVmwwNsNb3DoWQ+a1gepyimp1ocUlv28JPqMMiarm/Kka86KY+fzcHUUPQXpz8R4edOLA2hQSudYdTcNmcAOpwMw==", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result new file mode 100644 index 0000000..8cf3c91 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result @@ -0,0 +1,6 @@ +{ "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzhwVWGdONXvjKm42PqEk\nYjTTtZwytZdD+m5cgMouIMFnxDhkpKgWa/rwhp0o9/wTVrAnBAm7BtkwTJKMQply\n3N9q4EEc++v7zjdIEWgM5vqIuDdYUkje0v8V91xMJB+TjP4PViib83qxnoyBMU/Q\nuo8wr855UXUk557Sa4MLn/Lm8jn3314beul/5JQufl3gyPEjkYiK/xO6vEFKY3GG\nI4EYCR0444eO8QxkDpHC/nHmW9f7n21PuK+5vFJnv/n0Ljk13A9d8indTWu2rlzB\ny/Dq4fGB74MGxQlTzhQwxMkXjYCyxGhhhyTrlmn+eTfuyeAkg0ZEao89bRanaqh8\nHUa9P6ST++5oxHvPQseIrvgQ60+9v0jyqOW8A6FwWtk8UnaFR0/YnY7FDw38LIQ+\nHh7cMoa2ZBIjWPEKfheeyPTEoEU+ts3Tv72ecMxGAyQtwwVz8N6ML6RnSRI0joUw\n9KzhXLTbP3SpcAF51OkFABNaoHfT/jtxiIWIj5K8N17Gxd/VXqLq6GCG5Y7+Csg2\n/sEDJNlNsM1BP2VfwFY1dDiv93KJa+N7sRIZeg+PKVno86UOgzBSri+aXMc2cyJQ\nVZsMDbDW9w6FkPmtYHqcopqdaHFJb9vCT6jDImq5vypGvOimPn83B1FD0F6c/EeH\nnTiwNoUErnWHU3DZnADqcDMCAwEAAQ==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAACAQDOHBVYZ041e+MqbjY+oSRiNNO1nDK1l0P6blyAyi4gwWfEOGSkqBZr+vCGnSj3/BNWsCcECbsG2TBMkoxCmXLc32rgQRz76/vON0gRaAzm+oi4N1hSSN7S/xX3XEwkH5OM/g9WKJvzerGejIExT9C6jzCvznlRdSTnntJrgwuf8ubyOfffXht66X/klC5+XeDI8SORiIr/E7q8QUpjcYYjgRgJHTjjh47xDGQOkcL+ceZb1/ufbU+4r7m8Ume/+fQuOTXcD13yKd1Na7auXMHL8Orh8YHvgwbFCVPOFDDEyReNgLLEaGGHJOuWaf55N+7J4CSDRkRqjz1tFqdqqHwdRr0/pJP77mjEe89Cx4iu+BDrT72/SPKo5bwDoXBa2TxSdoVHT9idjsUPDfwshD4eHtwyhrZkEiNY8Qp+F57I9MSgRT62zdO/vZ5wzEYDJC3DBXPw3owvpGdJEjSOhTD0rOFctNs/dKlwAXnU6QUAE1qgd9P+O3GIhYiPkrw3XsbF39VeouroYIbljv4KyDb+wQMk2U2wzUE/ZV/AVjV0OK/3colr43uxEhl6D48pWejzpQ6DMFKuL5pcxzZzIlBVmwwNsNb3DoWQ+a1gepyimp1ocUlv28JPqMMiarm/Kka86KY+fzcHUUPQXpz8R4edOLA2hQSudYdTcNmcAOpwMw==", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKgIBAAKCAgEAzhwVWGdONXvjKm42PqEkYjTTtZwytZdD+m5cgMouIMFnxDhk\npKgWa/rwhp0o9/wTVrAnBAm7BtkwTJKMQply3N9q4EEc++v7zjdIEWgM5vqIuDdY\nUkje0v8V91xMJB+TjP4PViib83qxnoyBMU/Quo8wr855UXUk557Sa4MLn/Lm8jn3\n314beul/5JQufl3gyPEjkYiK/xO6vEFKY3GGI4EYCR0444eO8QxkDpHC/nHmW9f7\nn21PuK+5vFJnv/n0Ljk13A9d8indTWu2rlzBy/Dq4fGB74MGxQlTzhQwxMkXjYCy\nxGhhhyTrlmn+eTfuyeAkg0ZEao89bRanaqh8HUa9P6ST++5oxHvPQseIrvgQ60+9\nv0jyqOW8A6FwWtk8UnaFR0/YnY7FDw38LIQ+Hh7cMoa2ZBIjWPEKfheeyPTEoEU+\nts3Tv72ecMxGAyQtwwVz8N6ML6RnSRI0joUw9KzhXLTbP3SpcAF51OkFABNaoHfT\n/jtxiIWIj5K8N17Gxd/VXqLq6GCG5Y7+Csg2/sEDJNlNsM1BP2VfwFY1dDiv93KJ\na+N7sRIZeg+PKVno86UOgzBSri+aXMc2cyJQVZsMDbDW9w6FkPmtYHqcopqdaHFJ\nb9vCT6jDImq5vypGvOimPn83B1FD0F6c/EeHnTiwNoUErnWHU3DZnADqcDMCAwEA\nAQKCAgEAtDuwmr6zkGeGbYs02i2VoF8rpssxOMRPCIZLU7/4+GHH+LmLoMTv3nrw\nq/ZwZfJDgvHFHG3Z45I2/y7DglWnMOgaEII/8zgX2OtUlQwVBEKfHeAf1sysNXwk\n3EsUth36rDdad/BI93AaNFgPfWybTRh77bCzO/0hSX4D6UoN90+0jqsMS4KCq0fW\ns660vYIgV/cuMExjp8y75XV+tFkIgLGZsBaisazP3ZAFSwxBpLk7RKMpAO/Y39qi\no8C3wxOzaFxU8dtqPqJHSDVh6TVproo9C1liU2yTleejJjlXsC1c8DtTmBbi+gfa\nD40enye/Iz9jDnx6xWf+wg8mVUmCRZGxRvjvS/CjIEwNB6EX5vSCe4oM8lOg2V7f\nFynGpRYlP3vkcelNly5qf7mlb/Wkd7F8PnJ8JTHdTcGSalMJ3DKn063jn5eYFUQm\na40NkVAlDYOdeQZumCY7+v9Vontx4+0IrXlZJWr9EYyAEm80LlwenJ2s/YoTRwqV\nTfpWPaEcrNlZUq/2A9JM0m91gLktQaRLRyNnBvFap9504aWnLrD8m7tCWkzFf4wJ\nA+v9yN+lCveJPmNi5nW3Pzd1Xy3n126BN+yH7VUWVARKs8ZOUdOUMAg6ZVM0GnKe\nOt7AEAG5jsmGA5UQywtbGYOMonKBQqsqoWNKWTbbqbNbe4FyEqkCggEBAOzuRMHh\nI58/iv/TjG/t32CLdWRDM6cVvycoZL37zqObpzXo1LJHr1iCqxrEZnSzX5DCW3e5\nMbr3dq2GL02RfDb9Nta16dy/V6VzwK9bdavk9+CzJFoIvMVDqEZ6mVtTwvGrd6Aa\nnrTJjZjDG0dwfNe9LuNLmLSVE8p7WSWjU0E5XB45y1m53pIoQbqsR6cJPkiUGO2S\nUaR+xzxHeHv82zTavpf3T5+O+6UX6SRG5lx5Tk4ucUPzzwrry0PVdRERyZhJTjC3\nlG449RSrr1UOdwGE3Kkz4zEL14L661nDWogf9Yc6xsatSHSzVVdN9UY63e1pb8DN\ndEaNu0qddORTsD0CggEBAN6yxtydA+YMJ02C70PJZId3BeTLOzyk5ZCHU8kEEIFl\nRK4jW1kTXpxito2sSwDLYWnjHExnQiLFaYsVAhaxEFhS9bXrm9SWCjk7pD8XwdQ5\nBsi8uNz62W9cTNCHszwLCZ0HWKfsoQjodEbbAs3XS+F60i/e1RKAMsDm38tmO6rU\nSE1+81fgPpLTdT3cnAtwF51rxlgVQWFiohLxrSFvWS0X5eEvnoXZhqLMwdwQgUob\nuKuFDhMMleP17wbmA0QGdSWmUEgshx8g0Fx++BLqAcvSveQCkRGSn4RAfLq6I38S\n8ERJbbW9c2LjBKU2YyiuqdLcw0hVUJf0bGrOqHIFuS8CggEBAN4Z4bSJk3YGAAwf\nSGfoady7/pi1cmcvuJhBgmah9SxjjlS35SMWleX33+Pgtlaxi2VM/Kd3oImuzr6N\nqiwhtHpr1gtiTk8Tw1qi7r6zktRHeKJX7DzGMgcNjGI9LSNymq0nWqVoLtw0kJri\nUuEeLrmia6DAze6CTSIjjQb+Wt4qohLnhJug5GbIfA080JJh1NP+mHukDQqRmb0F\nFonMF8UtRTt5p1dglr9FcdUC7ZFEWcZqPN1BYRXQwiPdprcQoJU0Kqr6fJbyp7Pv\n2RV30NFItf2bWV8xxZ3QD+1+dpBivSw+SfYWnHRhZB/KQaHLLx0OGKd5MYWt+SNS\nBTDAztUCggEAEGOJvPyVJ93nGo4zO4LbshhxR5gpQNpFxrAe22FAMbWZK1OQymph\ngRLGqoBueJ1/CsLa90h2Fob+sGyYXcEkGcvpJz0yl59/Gx0nhjkiW5Liy+0Pkbuo\nOsjJImOKLjYFvBepT5pbc4Nf40ME3s8kV3CpfTph5d2nXojfGWHprDW5KHLaR7JK\nCJYlP6s3lKPoKP6gdyUBTcBrewdsHVTLdEUY9syBVwpeHScCcUaJrUGDAqRlF8PK\nWB9mOtS8ksoC3wVxTQ5x1zmb++KgMQwlm7Fjph8GPAvVT29LfpZqPFTRd8ULnN9X\nWYSpd9sbywenmcwDVxRoPPaQ7/9LaDDBowKCAQEAsoY/cxW+RrzavJYUZW8Zcdq5\n1/JHEGzr08FMRR+3UbeH8kpFQkc4/e/pobz/6ZRQkCasYGYc+5wZquYanbVsyJME\nkWBVREJ22kr3vjyueqgk1KQqYmOToOYNLYYS4TB0io84+HZTqsUKWXzJETc1TI6b\nMqslgSqd/jpK/BMTUUT9IrbAP7oGQcdcQ48R95LbjWlx/Mqe5mwmsSCex6b6ZKyk\nMGQJ7BG2Fjljs1NiHB3rwc50/wvUBsZmqMNQm/1/t3Nc9LQzJkUVe4IUSlQ56eBZ\n8k0JExiCAooRJNwUPAb8+GU+adYN7b4oPDCmAEgICojoX2PNLjAj9T1v4xPPcAIC\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc new file mode 100644 index 0000000..915508b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc @@ -0,0 +1,17 @@ +PuTTY-User-Key-File-2: ssh-dss +Encryption: aes256-cbc +Comment: dsa-key-20141202 +Public-Lines: 10 +AAAAB3NzaC1kc3MAAACBAJn2I8YefRo3BsEeinQt8KQ4cEyArAs7Y/W733oRSYOI +zWF1Ju124ysKrmg2okv+05CYcjV3Yp4AzQeomYAlgmB/7xCEnWaEnxCwAxmrrJMm +PrkwNjHOIi7yM5QOE90IM/Q+IJA4EPBfSb+Xr8fYhrp53KNHVSnc2KkOqpo2FsIj +AAAAFQC4NlP50GqyUqq2B82Vh/w5j3TzwQAAAIAeSGom9LLNdzcwCHnGfxKNnEz3 +55KITADTxiIpBvnQW+eDHwQvIw6V2Oc73bKCu5ZirZmIMW5w6KjQVwkuQBoF9Koq +/2u6VeevtL9pD6TBzSLMVw5pV3PmE4/C/eLiaUxZLIHdbzpqPkAvAUBrXKkj0ijz +cNzCp1fuF8H0pvR8yQAAAIAmvV+kqWhUgDYwNNz1qDaoS8XdsOponutZ/0stRQ66 +mKAy8kNVNNQ6oUx1XFl1WUt4iyFY/2Rz2fZhLz5/TbZRK5ygo666WgnxB/Ud4GAx +/BPQTghOJJOL00vJk+8jVCGNDc942V6nFXznDMXwqxhRCW6dm+2lTh7ntrli8mCk +5g== +Private-Lines: 1 +BytvbK+jNyMjiVxCO5lcE4YbW7q293oC+LZjkZ8Ajlw= +Private-MAC: c3da536ea28851fc32d5d1ff01498c8fcebc1170 diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result new file mode 100644 index 0000000..68edda7 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-dss", + "comment": "dsa-key-20141202", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBtjCCASsGByqGSM44BAEwggEeAoGBAJn2I8YefRo3BsEeinQt8KQ4cEyArAs7\nY/W733oRSYOIzWF1Ju124ysKrmg2okv+05CYcjV3Yp4AzQeomYAlgmB/7xCEnWaE\nnxCwAxmrrJMmPrkwNjHOIi7yM5QOE90IM/Q+IJA4EPBfSb+Xr8fYhrp53KNHVSnc\n2KkOqpo2FsIjAhUAuDZT+dBqslKqtgfNlYf8OY9088ECgYAeSGom9LLNdzcwCHnG\nfxKNnEz355KITADTxiIpBvnQW+eDHwQvIw6V2Oc73bKCu5ZirZmIMW5w6KjQVwku\nQBoF9Koq/2u6VeevtL9pD6TBzSLMVw5pV3PmE4/C/eLiaUxZLIHdbzpqPkAvAUBr\nXKkj0ijzcNzCp1fuF8H0pvR8yQOBhAACgYAmvV+kqWhUgDYwNNz1qDaoS8XdsOpo\nnutZ/0stRQ66mKAy8kNVNNQ6oUx1XFl1WUt4iyFY/2Rz2fZhLz5/TbZRK5ygo666\nWgnxB/Ud4GAx/BPQTghOJJOL00vJk+8jVCGNDc942V6nFXznDMXwqxhRCW6dm+2l\nTh7ntrli8mCk5g==\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1kc3MAAACBAJn2I8YefRo3BsEeinQt8KQ4cEyArAs7Y/W733oRSYOIzWF1Ju124ysKrmg2okv+05CYcjV3Yp4AzQeomYAlgmB/7xCEnWaEnxCwAxmrrJMmPrkwNjHOIi7yM5QOE90IM/Q+IJA4EPBfSb+Xr8fYhrp53KNHVSnc2KkOqpo2FsIjAAAAFQC4NlP50GqyUqq2B82Vh/w5j3TzwQAAAIAeSGom9LLNdzcwCHnGfxKNnEz355KITADTxiIpBvnQW+eDHwQvIw6V2Oc73bKCu5ZirZmIMW5w6KjQVwkuQBoF9Koq/2u6VeevtL9pD6TBzSLMVw5pV3PmE4/C/eLiaUxZLIHdbzpqPkAvAUBrXKkj0ijzcNzCp1fuF8H0pvR8yQAAAIAmvV+kqWhUgDYwNNz1qDaoS8XdsOponutZ/0stRQ66mKAy8kNVNNQ6oUx1XFl1WUt4iyFY/2Rz2fZhLz5/TbZRK5ygo666WgnxB/Ud4GAx/BPQTghOJJOL00vJk+8jVCGNDc942V6nFXznDMXwqxhRCW6dm+2lTh7ntrli8mCk5g==", + "private": "-----BEGIN DSA PRIVATE KEY-----\nMIIBugIBAAKBgQCZ9iPGHn0aNwbBHop0LfCkOHBMgKwLO2P1u996EUmDiM1hdSbt\nduMrCq5oNqJL/tOQmHI1d2KeAM0HqJmAJYJgf+8QhJ1mhJ8QsAMZq6yTJj65MDYx\nziIu8jOUDhPdCDP0PiCQOBDwX0m/l6/H2Ia6edyjR1Up3NipDqqaNhbCIwIVALg2\nU/nQarJSqrYHzZWH/DmPdPPBAoGAHkhqJvSyzXc3MAh5xn8SjZxM9+eSiEwA08Yi\nKQb50Fvngx8ELyMOldjnO92ygruWYq2ZiDFucOio0FcJLkAaBfSqKv9rulXnr7S/\naQ+kwc0izFcOaVdz5hOPwv3i4mlMWSyB3W86aj5ALwFAa1ypI9Io83DcwqdX7hfB\n9Kb0fMkCgYAmvV+kqWhUgDYwNNz1qDaoS8XdsOponutZ/0stRQ66mKAy8kNVNNQ6\noUx1XFl1WUt4iyFY/2Rz2fZhLz5/TbZRK5ygo666WgnxB/Ud4GAx/BPQTghOJJOL\n00vJk+8jVCGNDc942V6nFXznDMXwqxhRCW6dm+2lTh7ntrli8mCk5gIUCJZKAMAz\nkyr2vl2Pe48adi8Vs9s=\n-----END DSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa new file mode 100644 index 0000000..4504f18 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa @@ -0,0 +1,26 @@ +PuTTY-User-Key-File-2: ssh-rsa +Encryption: none +Comment: rsa-key-20150522 +Public-Lines: 6 +AAAAB3NzaC1yc2EAAAABJQAAAQB1quqP0rhl78NOLD4lj+1x5FGAqZ3aqo6GiEPz +KOaQmy86FuJMK0nHj3gUKTa/Kvaa+8PZyeu+uVseHg47YrynCOcJEEnpqvbArc8M +xMWuUnTUMrjvokGDOBBiQu4UAE4bybpgXkNHJfbrcDVgivmv3Ikn8PVIZ1rLBMLZ +6Lzn0rjPjFD0X4WqsAJW2SFiZnsjMZtVL2TWadNTyyfjjm2NCRBvd32VLohkSe9Q +BZBD6MW8YQyBKUnEF/7WNY0eehDVrfx1YqPOV1bDwFUhRaAYpLDLDR0KCAPvx7qb +8G5Cq0TIBsEr3H8ztNRcOTQoaKgn0T18M7cyS4ykoNLYW4Zx +Private-Lines: 14 +AAABACyF3DZraF3sBLXLjSL4MFSblHXfUHxAiPSiQzlpa/9dUCPRTrUJddzOgHZU +yJtcXU9mLm4VDRe7wZyxbSs6Hd5WZUGzIuLLEUH8k4hKdE/MLDSdkhV7qhX5iaij +tAeRaammRoVUGXTd7rnzGx2cXnnkvkZ22VmqkQ6MLg1DTmWNfOO9cdwFGdQawf/n +yUV0nTkWsHXy5Qrozq9wRFk8eyw+pFllxqavsNftZX8VDiQt27JLZPTU4LGkH660 +3gq1KhNS/l05TlXnMZGjlcPN8UEaBzmCWRezhJSttjs5Kgp1K3yDf4ozMR/HWOCj +Jq8fd3VIgli6ML8yjr/c0A0T9MUAAACBAL1/byxHiCvY/2C+/L5T+ZZq13jdZuYK +MmOFaNITgEdNGWSIFYRzhLKGXj7awQWOIW6chj470GNOfQjFL1TvXhbwfqW6esDa +kETOYQPYQHZijABcn7uurMUm/bu5x/z9gYkAfniOCI5vmvMvJ09JcZ0iUmFWDZZY +fAutBvrt+n/vAAAAgQCe9jrA51wn1/wzKmWF+2+OWFUG9usheIcEbHB8mxLguLfU ++x4i+2vLo0FtXEPAw+Bt7Tge4t0m6USiVZXtW/QKsh0kMj4mNVHFz+XXw4l1QOYv +n5TjnLepiP7majXv4GHI2eOcHkyly4sIkj4jNLYqvT86hMxW4IC+jtJEWhn/nwAA +AIEAlJ8cExu2WrWukTDJQHrVegtvdJUhNjol2wLucPuWwSxKuB8FHYwaPRYRkf3d +DkZ53hhjJZ0BVkAaQ28uqM09xKD+q1H4/r0nnbtlV4uHLl3cCD5mGrH8I/iDPJX4 +fFIqCa0+n1D6RzvDqs1QIu+PGSp0K6vHOOS5fP0ZpuT025E= +Private-MAC: 4ca26008c85b901f4d2766b0924c25e527678d7e diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result new file mode 100644 index 0000000..9ac4d2f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "rsa-key-20150522", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBHzANBgkqhkiG9w0BAQEFAAOCAQwAMIIBBwKCAQB1quqP0rhl78NOLD4lj+1x\n5FGAqZ3aqo6GiEPzKOaQmy86FuJMK0nHj3gUKTa/Kvaa+8PZyeu+uVseHg47Yryn\nCOcJEEnpqvbArc8MxMWuUnTUMrjvokGDOBBiQu4UAE4bybpgXkNHJfbrcDVgivmv\n3Ikn8PVIZ1rLBMLZ6Lzn0rjPjFD0X4WqsAJW2SFiZnsjMZtVL2TWadNTyyfjjm2N\nCRBvd32VLohkSe9QBZBD6MW8YQyBKUnEF/7WNY0eehDVrfx1YqPOV1bDwFUhRaAY\npLDLDR0KCAPvx7qb8G5Cq0TIBsEr3H8ztNRcOTQoaKgn0T18M7cyS4ykoNLYW4Zx\nAgEl\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAABJQAAAQB1quqP0rhl78NOLD4lj+1x5FGAqZ3aqo6GiEPzKOaQmy86FuJMK0nHj3gUKTa/Kvaa+8PZyeu+uVseHg47YrynCOcJEEnpqvbArc8MxMWuUnTUMrjvokGDOBBiQu4UAE4bybpgXkNHJfbrcDVgivmv3Ikn8PVIZ1rLBMLZ6Lzn0rjPjFD0X4WqsAJW2SFiZnsjMZtVL2TWadNTyyfjjm2NCRBvd32VLohkSe9QBZBD6MW8YQyBKUnEF/7WNY0eehDVrfx1YqPOV1bDwFUhRaAYpLDLDR0KCAPvx7qb8G5Cq0TIBsEr3H8ztNRcOTQoaKgn0T18M7cyS4ykoNLYW4Zx", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIIEoAIBAAKCAQB1quqP0rhl78NOLD4lj+1x5FGAqZ3aqo6GiEPzKOaQmy86FuJM\nK0nHj3gUKTa/Kvaa+8PZyeu+uVseHg47YrynCOcJEEnpqvbArc8MxMWuUnTUMrjv\nokGDOBBiQu4UAE4bybpgXkNHJfbrcDVgivmv3Ikn8PVIZ1rLBMLZ6Lzn0rjPjFD0\nX4WqsAJW2SFiZnsjMZtVL2TWadNTyyfjjm2NCRBvd32VLohkSe9QBZBD6MW8YQyB\nKUnEF/7WNY0eehDVrfx1YqPOV1bDwFUhRaAYpLDLDR0KCAPvx7qb8G5Cq0TIBsEr\n3H8ztNRcOTQoaKgn0T18M7cyS4ykoNLYW4ZxAgElAoIBACyF3DZraF3sBLXLjSL4\nMFSblHXfUHxAiPSiQzlpa/9dUCPRTrUJddzOgHZUyJtcXU9mLm4VDRe7wZyxbSs6\nHd5WZUGzIuLLEUH8k4hKdE/MLDSdkhV7qhX5iaijtAeRaammRoVUGXTd7rnzGx2c\nXnnkvkZ22VmqkQ6MLg1DTmWNfOO9cdwFGdQawf/nyUV0nTkWsHXy5Qrozq9wRFk8\neyw+pFllxqavsNftZX8VDiQt27JLZPTU4LGkH6603gq1KhNS/l05TlXnMZGjlcPN\n8UEaBzmCWRezhJSttjs5Kgp1K3yDf4ozMR/HWOCjJq8fd3VIgli6ML8yjr/c0A0T\n9MUCgYEAvX9vLEeIK9j/YL78vlP5lmrXeN1m5goyY4Vo0hOAR00ZZIgVhHOEsoZe\nPtrBBY4hbpyGPjvQY059CMUvVO9eFvB+pbp6wNqQRM5hA9hAdmKMAFyfu66sxSb9\nu7nH/P2BiQB+eI4Ijm+a8y8nT0lxnSJSYVYNllh8C60G+u36f+8CgYEAnvY6wOdc\nJ9f8MyplhftvjlhVBvbrIXiHBGxwfJsS4Li31PseIvtry6NBbVxDwMPgbe04HuLd\nJulEolWV7Vv0CrIdJDI+JjVRxc/l18OJdUDmL5+U45y3qYj+5mo17+BhyNnjnB5M\npcuLCJI+IzS2Kr0/OoTMVuCAvo7SRFoZ/58CgYBM0sw0i7O+v8F6P5blYFBtaZWf\ns7QYEfjAkAfmdpvJ4Px03Tkn284DL439zk5AhbqGydWO2fqJH9HTH4HkKbCF1x6W\nNtfRpLcHIzwWUMAv/nAb0oXyJDg0QD1Z8V7qBehn+UgHXCz7eVp+Q4x6FtsIWgW4\nwgWCI99DAPT98cZrNwKBgBEvYEw0sAROs3snLZHxqzH7tipENRhgDpixxvi20ZvA\n8Ud1GAPIJ1RJACd/mJ83xTxQ/yXvAybNHC05r1fuQ+V7ChHAPhH37SokUDMAYeMp\nnFgs7YBj+C4A+PZQq+KUzE0Qovwe84eLoFP0ImSrwKqsrOO7VFxrTDBGyp+bCbrF\nAoGBAJSfHBMbtlq1rpEwyUB61XoLb3SVITY6JdsC7nD7lsEsSrgfBR2MGj0WEZH9\n3Q5Ged4YYyWdAVZAGkNvLqjNPcSg/qtR+P69J527ZVeLhy5d3Ag+Zhqx/CP4gzyV\n+HxSKgmtPp9Q+kc7w6rNUCLvjxkqdCurxzjkuXz9Gabk9NuR\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc new file mode 100644 index 0000000..6f2f7f7 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc @@ -0,0 +1,18 @@ +PuTTY-User-Key-File-2: ssh-rsa +Encryption: aes256-cbc +Comment: rsa-key-20141119 +Public-Lines: 4 +AAAAB3NzaC1yc2EAAAABJQAAAIBrBWETAVAyJmuNG53jwTNDlbIcH5lrEvcx6lx5 +bM6EKg0XmOIH96VqUjS7eRRTTD9lpBA8hYhkrOjOx93/JWB/pcVN8/B3DYHshT9O +BW1DCkrNwut2pbJ2oZOBirhhAr+xqWFr3551FqbzaCIXpOKubr4EcIwCipBl6PxL +USfHgw== +Private-Lines: 8 +8O3NrBePR4+4RHHys8wrRKCmgx3Gsdz1cKoRJJDgnnrQxuAxBTVUlVTC2vzSOXrP +jlKdRP9DbtrL5YF8g9HkMPpzzTdgpiEAGikpIc+L0sJhN+S9VvMoXRRKqyuB7o1C +xZhAeRaZ68izdUUbFd7ajUwBNpGoFppOznGXyf/3/Ao9FfoTKReZzeBd/e2/JFhc +nsYkSbtWfKQBVXF1Fhr10UwRWSMaVJSDkcSuk8ghICoKBBCgRBnZFap0SR77oIJh +DKgmNFktoKzEqh111vYPhQyEEyGNxpD0aEPaGUJEjPEd3C5a46n7mIiqrNX7QJoo +xxZtkueGdXWaoe5mBf1tFc+nCA1l72nUlghJZooQhnO9NPpieu6NNZ8X+tFQ1Rq/ +xvOZHzpDOOeOgWdV7oAmRDbDjYPh0H67z2OKCFaP0Z9kgmnwqV2IJvTDrexj1VwY +6kFaPldnK+ohXl37oVIlWA== +Private-MAC: 9d09a15a122e48955682ba969d33c75ba8e4be2c diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result new file mode 100644 index 0000000..f9ff958 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "rsa-key-20141119", + "public": "-----BEGIN PUBLIC KEY-----\nMIGcMA0GCSqGSIb3DQEBAQUAA4GKADCBhgKBgGsFYRMBUDIma40bnePBM0OVshwf\nmWsS9zHqXHlszoQqDReY4gf3pWpSNLt5FFNMP2WkEDyFiGSs6M7H3f8lYH+lxU3z\n8HcNgeyFP04FbUMKSs3C63alsnahk4GKuGECv7GpYWvfnnUWpvNoIhek4q5uvgRw\njAKKkGXo/EtRJ8eDAgEl\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAABJQAAAIBrBWETAVAyJmuNG53jwTNDlbIcH5lrEvcx6lx5bM6EKg0XmOIH96VqUjS7eRRTTD9lpBA8hYhkrOjOx93/JWB/pcVN8/B3DYHshT9OBW1DCkrNwut2pbJ2oZOBirhhAr+xqWFr3551FqbzaCIXpOKubr4EcIwCipBl6PxLUSfHgw==", + "private": "-----BEGIN RSA PRIVATE KEY-----\nMIICWQIBAAKBgGsFYRMBUDIma40bnePBM0OVshwfmWsS9zHqXHlszoQqDReY4gf3\npWpSNLt5FFNMP2WkEDyFiGSs6M7H3f8lYH+lxU3z8HcNgeyFP04FbUMKSs3C63al\nsnahk4GKuGECv7GpYWvfnnUWpvNoIhek4q5uvgRwjAKKkGXo/EtRJ8eDAgElAoGA\nU+GfHLvXEozQ1mHA8MfcEmCShL7SMVQN2wPL8HfgImYl7+aHpWE8de1nmdtwy6p2\n4PY2PUYQ9PY57i3zL8NZd8WQ7Rg0RBHDlndaFeF4Ef0uLboqYd/xN0rzfy55z7hW\nOL+8VhoxTrBUvveOhZwBPkOeHfxmkVz3xbbrg3kNlo0CQQDJYPKtCs/l46KJmN3l\nUANdI4QIuWQ+Zllz7p94FfdotnkvqG++Bp1wOqJSCih6UViwLfvpNZtGMCtk46WN\nhc0zAkEAiAyN4WUs/0x4WovG956J1A+uSEKeWzuqfpGGbWgZ9XfnPnk+1Al8FOW1\ntu9WWrMPIavQnZW/dXxhkeNWTH78cQJBALkM+qzZgMVpZO0ksDqA4H8Zt5lQafQm\nsxCWFf+le5CnraFqWNghwRsFcpCTtn486bamy89hsUdqiL2S6ygaFoECQFDk3r1e\nwM8mjMA3b2LM+AGMyH3+GPf59qwfLVXPMgeTZubgTt7w4f6WbAvoQS8Crw0aDVbH\nvfLUVbCwr9p1BM0CQFSBjCa/fzeICVkPFBaKQUmXjQ3IcPTOr90mSAiPnAAppSwT\nj5SYSfE9rSVb+EhQ0hk2VKWIfocNHBD1MAN9zb4=\n-----END RSA PRIVATE KEY-----" +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub new file mode 100644 index 0000000..3bfd6e8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub @@ -0,0 +1,9 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: "2048-bit RSA" +AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKC +nbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCH +S/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1m +gJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW +61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc +9lK/C2jItA3fwq9PHfCM1D +---- END SSH2 PUBLIC KEY ---- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result new file mode 100644 index 0000000..fcc0553 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "2048-bit RSA", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub new file mode 100644 index 0000000..e42f5c1 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub @@ -0,0 +1,10 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: 2048-bit RSA +AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKC +nbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCH +S/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1m +gJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW +61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc +9lK/C2jItA3fwq9PHfCM1D +---- END SSH2 PUBLIC KEY ---- + diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result new file mode 100644 index 0000000..fcc0553 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "2048-bit RSA", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub new file mode 100644 index 0000000..24a107b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: this is a special \ +multi-line comment\ + how cool is that not? +AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKC +nbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCH +S/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1m +gJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW +61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc +9lK/C2jItA3fwq9PHfCM1D +---- END SSH2 PUBLIC KEY ---- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result new file mode 100644 index 0000000..25dae67 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "this is a special multi-line comment how cool is that not?", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub new file mode 100644 index 0000000..0454a85 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: "this is a special \ +multi-line comment\ + how cool is that not?" +AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKC +nbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCH +S/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1m +gJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW +61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc +9lK/C2jItA3fwq9PHfCM1D +---- END SSH2 PUBLIC KEY ---- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result new file mode 100644 index 0000000..25dae67 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "this is a special multi-line comment how cool is that not?", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub new file mode 100644 index 0000000..14608c1 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub @@ -0,0 +1,8 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKC +nbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCH +S/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1m +gJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW +61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc +9lK/C2jItA3fwq9PHfCM1D +---- END SSH2 PUBLIC KEY ---- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result new file mode 100644 index 0000000..a61d779 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub new file mode 100644 index 0000000..24a2261 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub @@ -0,0 +1,13 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Subject: "nodejs" +x-foo: something\ +completely\ +different +Comment: "Foo bar baz" +AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKC +nbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCH +S/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1m +gJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW +61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc +9lK/C2jItA3fwq9PHfCM1D +---- END SSH2 PUBLIC KEY ---- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result new file mode 100644 index 0000000..ed7a4f5 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result @@ -0,0 +1,7 @@ +{ + "type": "ssh-rsa", + "comment": "Foo bar baz", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4q6eZdx7LYh46PcZNcS3\nCnO7GuYsEJZeTj5LQSgp21IyTelaBPprijnMwKa+pLQt5TEobpKFFNecPdT6oPoO\nKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHMBNkoTFeGrursPkqYRJ0HL4CqYq\nRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKbzibJc64JFM7tUoK6Vl64\nYiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs8zjxsf6c6N2tKX\nkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38KvTx3wjN\nQwIDAQAB\n-----END PUBLIC KEY-----", + "publicSSH": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDirp5l3HstiHjo9xk1xLcKc7sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+lfQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg64MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1D", + "private": null +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/openssh_new_rsa b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/openssh_new_rsa new file mode 100644 index 0000000..ccded2a --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/openssh_new_rsa @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEA4q6eZdx7LYh46PcZNcS3CnO7GuYsEJZeTj5LQSgp21IyTelaBPpr +ijnMwKa+pLQt5TEobpKFFNecPdT6oPoOKKMe6oH/pX0BNyAEB9KFZfZgh0v4J4IOiO0KHM +BNkoTFeGrursPkqYRJ0HL4CqYqRdINy1sgDU6jUIOuDD5XZzlpDXb1ftZoCei9OHSWrMKb +zibJc64JFM7tUoK6Vl64YiPgxsNXOJYMTrelVJYebtsNrJFmh3XXQABDVutWMYb8I6IrNs +8zjxsf6c6N2tKXkk9G4EDKKip4g0bzDmD/fREPQ9vLi59N+ZsyjWCKKE3PZSvwtoyLQN38 +KvTx3wjNQwAAA8hLhVBxS4VQcQAAAAdzc2gtcnNhAAABAQDirp5l3HstiHjo9xk1xLcKc7 +sa5iwQll5OPktBKCnbUjJN6VoE+muKOczApr6ktC3lMShukoUU15w91Pqg+g4oox7qgf+l +fQE3IAQH0oVl9mCHS/gngg6I7QocwE2ShMV4au6uw+SphEnQcvgKpipF0g3LWyANTqNQg6 +4MPldnOWkNdvV+1mgJ6L04dJaswpvOJslzrgkUzu1SgrpWXrhiI+DGw1c4lgxOt6VUlh5u +2w2skWaHdddAAENW61Yxhvwjois2zzOPGx/pzo3a0peST0bgQMoqKniDRvMOYP99EQ9D28 +uLn035mzKNYIooTc9lK/C2jItA3fwq9PHfCM1DAAAAAwEAAQAAAQAmShSbZBiyYkD6KPLr +MCUy8MWED6kVzDB1yvPvN5eKYmH44xe/i4UqvgSl7gR50a2G7zzDIKC2Go1brGQBWPuXRa +ZtOjQygeD4rMHBiH/b7zfy4pQyKDfITTHOFXWE8ERiyL00bAZt09icCy92rQaq8IY/+U56 +sPPJH9UAYG9nEev8opFjAWToFDu0U2+dC+lbqLlXDqDRo75NlnDFmgUoja3y2eFr9A0Cc+ +hjecrdxyJFsCJfEfaLWtBnZb886gqzzvfbHImSQtBAKERcSxuki7uxMoP67g3iQOXa65uz +8kFWRNmbQTGQttakoUaybh1t9eLpBqvVON/4Kg0THShRAAAAgFBTz2ajBK/R/crOSL9VK1 +f7oQv2iJTRVfnUs0r+qPGgf/a/5UwkGRj0KfEWBp3qYD+keShnPr6PDPFrm8UmIdUX8AY7 +3tWT2K/JQVlzJNuINsw+DNjn4M17Z25q0LPmReRWL0nRc2w6W/hmQ/Jmqz6w8Qc4+xpeqS +/HG5feliVnAAAAgQD90a+5Ky3o/2YtueqRf/3dKoiMgGB7JAOzye4dDKGABSlWuQ4N4xEI +CW5MSTp7i/uobTF/tyFO3tTSyb5b2Xwbn/kLO0vgvFCdUGR2BQfN3mcT92T0Gn3JDF3Wym +i2mgU6qnPf+eu+RKZQ9IiyNGny61ROUQa0R0z0pgiAfA89xwAAAIEA5KE9i6hHmigJwfD7 +/AGI4ujyWIVpNyrTdXG3HAPhsdoFuG5ggHggrPuuBF9wNcosrhL20VNOQGHg15gWZIVudu +0qxky4ivQs67Sk9XUjuvTnf+VubM51rIsmh4atKJFSSZo78DEcTRt8aXLrSNvGQ4WPRweM +2Z0YGfMMDM9KJKUAAAASbmV3IG9wZW5zc2ggZm9ybWF0AQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_dsa_key b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_dsa_key new file mode 100644 index 0000000..5448947 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_dsa_key @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQDEK+daQ7RuajwxkmBmogb0iUSi/w2RYKuvC2EiviBu3S2s9Bfq +gROKscAnURrxpTOa+iYeI7hRzfuX0qFmnFwXIjKJBjqBdg9r76UR5UNytnWQkJ5x +lxsZThMeAMw38SvmRMw15kkgxycKGqu4yvNLGyVwN02bPVjLcEVLWLCM1wIVAK50 +5JqF0nmGXFkcmNtxR24/mNXTAoGBAIc2p8C8b08OTQPmfZI+Wq8a+CuEr5R36bMW +TAs5etqmO2aVo5zvR0MnTjoS2ZDbuznDG9RiSuIB+ivr/daEwi+K+Ha8pZfYjXCG +ldzvmr5I4x8rkH3zyn7BADnc+/q3pa8AnZvTme5eNsxn1Pu/rmC/8KKnhmzRggqP +N8ORhoQQAoGAMCvoMcsDAui2d/WVpgHZZEFlxfbf4dPUPYb5zf2xOiMG9OK+Cbv3 +NaLZwk/Hd2g4L3nwTKDASxfmRcrbuaOg/d7aDjQ2mJz18Js4IjY34QpgLspGCNX/ +6rJSQ+ov1Z2Etr95N4Tzm3qpxW5BH9TTgaC/ntb9NRqIzNPCvAHXmlcCFBxgZpyb +4GUgmqhTOMtmBkJ7QpL9 +-----END DSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key new file mode 100644 index 0000000..0476442 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEICrdbIIYmW/XTK9hxaQZZ56IGwG0NhqD2eppYUJNZsECoAoGCCqGSM49 +AwEHoUQDQgAEa+MuLv++3ft5HPFIsM2hQnmHPF12q08/MaHoGud4yqp3evyomjZN +xbsSb39fv8t6XX1u1rm5oHQcBV5Mqomaeg== +-----END EC PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_rsa_key b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_rsa_key new file mode 100644 index 0000000..9c2cc6f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/fixtures/ssh_host_rsa_key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC57UB/5H0M+t+mopksrltCCIXghryzofJjau+8tuMT9CG6ta3S +O9aKApJUUG/xtc88giVhB7HFABX/oob+jrkSthR8s/whULC8E+GhvOBjHydRUZIs +aPYOMBb42HcbOsgq3li/hwOcDk0vY00hZDKCum9BgvRAb7dPEkw2dmiCQQIDAQAB +AoGAMG+HOwoaLbR5aR64yrQNYBF6Vvii1iUdURr9o2r9kygpVUuZIcim5kMvPbnK +v+w+NaQt+q4XeJvCH1uG0W/69FwnphfaOVmCCUtsoJ6sU3fWr9x59MtKL2Llh8xR +50lz6R+eDXoYRDq245hG9BFn/bu0vtqQqx06mlZJcjaRocECQQDjdYFmr+DSww3x +VNx0G0DUkaQZZ+iqZiT3Zund2pcBB4aLiewOrqj0GFct4+YNzgxIXPejmS0eSokN +N2lC3NxZAkEA0UGjN5TG5/LEK3zcYtx2kpXryenrYORo1n2L/WPMZ0mjLQyd4LJr +ibfgVUfwX/kV3vgGYLwjpgcaTiMsecv4KQJAYMmMgZSPdz+WvD1e/WznXkyG5mSn +xXJngnrhQw0TulVodBIBR5IcxJli510VdIRcB6K/oXa5ky0mOmB8wv3WKQJBAKEF +PxE//KbzWhyUogm4180IbD4dMDCI0ltqlFRRfTJlqZi6wqnq4XFB+u/kwYU4aKoA +dPfvDgduI8HIsyqt17ECQDI/HC8PiYsDIOyVpQuQdIAsbGmoavK7X1MVEWR2nj9t +7BbUVFSnVKynL4TWIJZ6xP8WQwkDBQc5WjognHDaUTQ= +-----END RSA PRIVATE KEY----- diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-exec.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-exec.js new file mode 100644 index 0000000..86b2e31 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-exec.js @@ -0,0 +1,578 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const { + mustCall, + mustCallAtLeast, + setupSimple, +} = require('./common.js'); + +const DEBUG = false; + +const setup = setupSimple.bind(undefined, DEBUG); + +{ + const { client, server } = setup('Simple exec()'); + + const COMMAND = 'foo --bar'; + const STDOUT_DATA = 'stdout data!\n'; + const STDERR_DATA = 'stderr data!\n'; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === COMMAND, + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.stderr.write(STDERR_DATA); + stream.write(STDOUT_DATA); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let out = ''; + let outErr = ''; + const events = []; + const EXPECTED_EVENTS = [ 'exit', 'close' ]; + const EXPECTED_EXIT_CLOSE_ARGS = [ 100 ]; + client.on('close', mustCall(() => { + assert(out === STDOUT_DATA, `Wrong stdout data: ${inspect(out)}`); + assert(outErr === STDERR_DATA, `Wrong stderr data: ${inspect(outErr)}`); + assert.deepStrictEqual( + events, + EXPECTED_EVENTS, + `Wrong command event order: ${events}` + ); + })).exec(COMMAND, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.on('data', mustCallAtLeast((d) => { + out += d; + })).on('exit', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong exit args: ${inspect(args)}`); + events.push('exit'); + })).on('close', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong close args: ${inspect(args)}`); + events.push('close'); + })).stderr.on('data', mustCallAtLeast((d) => { + outErr += d; + })); + })); + })); +} + +{ + const { client, server } = setup('Simple exec() (exit signal)'); + + const COMMAND = 'foo --bar'; + const STDOUT_DATA = 'stdout data!\n'; + const STDERR_DATA = 'stderr data!\n'; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === COMMAND, + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.stderr.write(STDERR_DATA); + stream.write(STDOUT_DATA); + assert.throws(() => stream.exit('SIGFAKE')); + stream.exit('SIGKILL'); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let out = ''; + let outErr = ''; + const events = []; + const EXPECTED_EVENTS = [ 'exit', 'close' ]; + const EXPECTED_EXIT_CLOSE_ARGS = [ null, 'SIGKILL', false, '' ]; + client.on('close', mustCall(() => { + assert(out === STDOUT_DATA, `Wrong stdout data: ${inspect(out)}`); + assert(outErr === STDERR_DATA, `Wrong stderr data: ${inspect(outErr)}`); + assert.deepStrictEqual( + events, + EXPECTED_EVENTS, + `Wrong command event order: ${events}` + ); + })).exec(COMMAND, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.on('data', mustCallAtLeast((d) => { + out += d; + })).on('exit', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong exit args: ${inspect(args)}`); + events.push('exit'); + })).on('close', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong close args: ${inspect(args)}`); + events.push('close'); + })).stderr.on('data', mustCallAtLeast((d) => { + outErr += d; + })); + })); + })); +} + +{ + const { client, server } = setup('Simple exec() (exit signal -- no "SIG")'); + + const COMMAND = 'foo --bar'; + const STDOUT_DATA = 'stdout data!\n'; + const STDERR_DATA = 'stderr data!\n'; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === COMMAND, + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.stderr.write(STDERR_DATA); + stream.write(STDOUT_DATA); + assert.throws(() => stream.exit('FAKE')); + stream.exit('KILL'); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let out = ''; + let outErr = ''; + const events = []; + const EXPECTED_EVENTS = [ 'exit', 'close' ]; + const EXPECTED_EXIT_CLOSE_ARGS = [ null, 'SIGKILL', false, '' ]; + client.on('close', mustCall(() => { + assert(out === STDOUT_DATA, `Wrong stdout data: ${inspect(out)}`); + assert(outErr === STDERR_DATA, `Wrong stderr data: ${inspect(outErr)}`); + assert.deepStrictEqual( + events, + EXPECTED_EVENTS, + `Wrong command event order: ${events}` + ); + })).exec(COMMAND, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.on('data', mustCallAtLeast((d) => { + out += d; + })).on('exit', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong exit args: ${inspect(args)}`); + events.push('exit'); + })).on('close', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong close args: ${inspect(args)}`); + events.push('close'); + })).stderr.on('data', mustCallAtLeast((d) => { + outErr += d; + })); + })); + })); +} + +{ + const { client, server } = setup('Exec with signal()'); + + const COMMAND = 'foo --bar'; + const STDOUT_DATA = 'stdout data!\n'; + const STDERR_DATA = 'stderr data!\n'; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let stream; + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === COMMAND, + `Wrong exec command: ${info.command}`); + stream = accept(); + stream.stderr.write(STDERR_DATA); + stream.write(STDOUT_DATA); + })).on('signal', mustCall((accept, reject, info) => { + assert(info.name === 'INT', `Wrong client signal name: ${info.name}`); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let out = ''; + let outErr = ''; + const events = []; + const EXPECTED_EVENTS = [ 'exit', 'close' ]; + const EXPECTED_EXIT_CLOSE_ARGS = [ 100 ]; + client.on('close', mustCall(() => { + assert(out === STDOUT_DATA, `Wrong stdout data: ${inspect(out)}`); + assert(outErr === STDERR_DATA, `Wrong stderr data: ${inspect(outErr)}`); + assert.deepStrictEqual( + events, + EXPECTED_EVENTS, + `Wrong command event order: ${events}` + ); + })).exec(COMMAND, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + const sendSignal = (() => { + let sent = false; + return () => { + if (sent) + return; + sent = true; + assert.throws(() => stream.signal('FAKE')); + assert.throws(() => stream.signal('SIGFAKE')); + stream.signal('SIGINT'); + }; + })(); + stream.on('data', mustCallAtLeast((d) => { + out += d; + sendSignal(); + })).on('exit', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong exit args: ${inspect(args)}`); + events.push('exit'); + })).on('close', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong close args: ${inspect(args)}`); + events.push('close'); + })).stderr.on('data', mustCallAtLeast((d) => { + outErr += d; + })); + })); + })); +} + +{ + const { client, server } = setup('Exec with signal() -- no "SIG"'); + + const COMMAND = 'foo --bar'; + const STDOUT_DATA = 'stdout data!\n'; + const STDERR_DATA = 'stderr data!\n'; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let stream; + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === COMMAND, + `Wrong exec command: ${info.command}`); + stream = accept(); + stream.stderr.write(STDERR_DATA); + stream.write(STDOUT_DATA); + })).on('signal', mustCall((accept, reject, info) => { + assert(info.name === 'INT', `Wrong client signal name: ${info.name}`); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let out = ''; + let outErr = ''; + const events = []; + const EXPECTED_EVENTS = [ 'exit', 'close' ]; + const EXPECTED_EXIT_CLOSE_ARGS = [ 100 ]; + client.on('close', mustCall(() => { + assert(out === STDOUT_DATA, `Wrong stdout data: ${inspect(out)}`); + assert(outErr === STDERR_DATA, `Wrong stderr data: ${inspect(outErr)}`); + assert.deepStrictEqual( + events, + EXPECTED_EVENTS, + `Wrong command event order: ${events}` + ); + })).exec(COMMAND, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + const sendSignal = (() => { + let sent = false; + return () => { + if (sent) + return; + sent = true; + stream.signal('INT'); + }; + })(); + stream.on('data', mustCallAtLeast((d) => { + out += d; + sendSignal(); + })).on('exit', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong exit args: ${inspect(args)}`); + events.push('exit'); + })).on('close', mustCall((...args) => { + assert.deepStrictEqual(args, + EXPECTED_EXIT_CLOSE_ARGS, + `Wrong close args: ${inspect(args)}`); + events.push('close'); + })).stderr.on('data', mustCallAtLeast((d) => { + outErr += d; + })); + })); + })); +} + +{ + const { client, server } = setup('Exec with environment set'); + + const env = { SSH2NODETEST: 'foo' }; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('env', mustCall((accept, reject, info) => { + accept && accept(); + assert(info.key === Object.keys(env)[0], + 'Wrong env key'); + assert(info.val === Object.values(env)[0], + 'Wrong env value'); + })).on('exec', mustCall((accept, reject, info) => { + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo --bar', { env }, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.resume(); + })); + })); +} + +{ + const { client, server } = setup('Exec with setWindow()'); + + const dimensions = { + rows: 60, + cols: 115, + height: 480, + width: 640, + }; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('window-change', mustCall((accept, reject, info) => { + accept && accept(); + assert.deepStrictEqual(info, dimensions, 'Wrong dimensions'); + })).on('exec', mustCall((accept, reject, info) => { + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo --bar', mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.setWindow(...Object.values(dimensions)); + stream.resume(); + })); + })); +} + +{ + const { client, server } = setup('Exec with pty set'); + + const pty = { + rows: 2, + cols: 4, + width: 0, + height: 0, + term: 'vt220', + modes: {}, + }; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let sawPty = false; + accept().on('pty', mustCall((accept, reject, info) => { + assert.deepStrictEqual(info, pty, 'Wrong pty info'); + sawPty = true; + accept && accept(); + })).on('exec', mustCall((accept, reject, info) => { + assert(sawPty, 'Expected pty to be set up'); + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo --bar', { pty }, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.resume(); + })); + })); +} + +{ + const { client, server } = setup('Exec with X11 forwarding'); + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let sawX11 = false; + accept().on('x11', mustCall((accept, reject, info) => { + assert.strictEqual(info.single, + false, + `Wrong x11 single: ${info.single}`); + assert.strictEqual(info.screen, + 0, + `Wrong x11 screen: ${info.screen}`); + assert.strictEqual(info.protocol, + 'MIT-MAGIC-COOKIE-1', + `Wrong x11 protocol: ${info.protocol}`); + assert(Buffer.isBuffer(info.cookie), 'Expected cookie Buffer'); + assert.strictEqual( + info.cookie.length, + 32, + `Invalid x11 cookie length: ${info.cookie.length}` + ); + sawX11 = true; + accept && accept(); + })).on('exec', mustCall((accept, reject, info) => { + assert(sawX11, 'Expected x11 before exec'); + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + conn.x11('127.0.0.1', 4321, mustCall((err, xstream) => { + assert(!err, `Unexpected x11() error: ${err}`); + xstream.resume(); + xstream.on('end', mustCall(() => { + stream.exit(100); + stream.end(); + conn.end(); + })).end(); + })); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.on('x11', mustCall((info, accept, reject) => { + assert.strictEqual(info.srcIP, + '127.0.0.1', + `Invalid x11 srcIP: ${info.srcIP}`); + assert.strictEqual(info.srcPort, + 4321, + `Invalid x11 srcPort: ${info.srcPort}`); + accept(); + })).exec('foo --bar', { x11: true }, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.resume(); + })); + })); +} + +{ + const { client, server } = setup( + 'Exec with X11 forwarding (custom X11 settings)' + ); + + const x11 = { + single: true, + screen: 1234, + protocol: 'YUMMY-MAGIC-COOKIE-1', + cookie: '00112233445566778899001122334455', + }; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let sawX11 = false; + accept().on('x11', mustCall((accept, reject, info) => { + assert.strictEqual(info.single, + x11.single, + `Wrong x11 single: ${info.single}`); + assert.strictEqual(info.screen, + x11.screen, + `Wrong x11 screen: ${info.screen}`); + assert.strictEqual(info.protocol, + x11.protocol, + `Wrong x11 protocol: ${info.protocol}`); + assert(Buffer.isBuffer(info.cookie), 'Expected cookie Buffer'); + assert.strictEqual(info.cookie.toString(), + x11.cookie, + `Wrong x11 cookie: ${info.cookie}`); + sawX11 = true; + accept && accept(); + })).on('exec', mustCall((accept, reject, info) => { + assert(sawX11, 'Expected x11 before exec'); + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + conn.x11('127.0.0.1', 4321, mustCall((err, xstream) => { + assert(!err, `Unexpected x11() error: ${err}`); + xstream.resume(); + xstream.on('end', mustCall(() => { + stream.exit(100); + stream.end(); + conn.end(); + })).end(); + })); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.on('x11', mustCall((info, accept, reject) => { + assert.strictEqual(info.srcIP, + '127.0.0.1', + `Invalid x11 srcIP: ${info.srcIP}`); + assert.strictEqual(info.srcPort, + 4321, + `Invalid x11 srcPort: ${info.srcPort}`); + accept(); + })).exec('foo --bar', { x11 }, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.resume(); + })); + })); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-integration-openssh.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-integration-openssh.js new file mode 100644 index 0000000..bdfa13f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-integration-openssh.js @@ -0,0 +1,486 @@ +// TODO: add more rekey tests that at least include switching from no +// compression to compression and vice versa +'use strict'; + +const assert = require('assert'); +const { spawn, spawnSync } = require('child_process'); +const { chmodSync, readdirSync } = require('fs'); +const { join } = require('path'); +const readline = require('readline'); + +const Server = require('../lib/server.js'); + +const { + fixture, + fixtureKey, + FIXTURES_DIR, + mustCall, + mustCallAtLeast, +} = require('./common.js'); + +const SPAWN_OPTS = { windowsHide: true }; +const CLIENT_TIMEOUT = 5000; + +const debug = false; +const opensshPath = 'ssh'; +let opensshVer; + +// TODO: figure out why this test is failing on Windows +if (process.platform === 'win32') { + console.log('Skipping OpenSSH integration tests on Windows'); + process.exit(0); +} + +// Fix file modes to avoid OpenSSH client complaints about keys' permissions +for (const file of readdirSync(FIXTURES_DIR, { withFileTypes: true })) { + if (file.isFile()) + chmodSync(join(FIXTURES_DIR, file.name), 0o600); +} + +{ + // Get OpenSSH client version first + const { + error, stderr, stdout + } = spawnSync(opensshPath, ['-V'], SPAWN_OPTS); + + if (error) { + console.error('OpenSSH client is required for these tests'); + process.exitCode = 5; + return; + } + + const re = /^OpenSSH_([\d.]+)/; + let m = re.exec(stdout.toString()); + if (!m || !m[1]) { + m = re.exec(stderr.toString()); + if (!m || !m[1]) { + console.error('OpenSSH client is required for these tests'); + process.exitCode = 5; + return; + } + } + + opensshVer = m[1]; + console.log(`Testing with OpenSSH version: ${opensshVer}`); +} + + +// Key-based authentication +[ + { desc: 'RSA user key (old OpenSSH)', + clientKey: fixtureKey('id_rsa') }, + { desc: 'RSA user key (new OpenSSH)', + clientKey: fixtureKey('openssh_new_rsa') }, + { desc: 'DSA user key', + clientKey: fixtureKey('id_dsa') }, + { desc: 'ECDSA user key', + clientKey: fixtureKey('id_ecdsa') }, +].forEach((test) => { + const { desc, clientKey } = test; + const username = 'KeyUser'; + const { server } = setup( + desc, + { + client: { + username, + privateKeyPath: clientKey.fullPath, + }, + server: { hostKeys: [ fixture('ssh_host_rsa_key') ] }, + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCallAtLeast((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 2: + case 3: + if (authAttempt === 3) + assert(ctx.signature, 'Missing publickey signature'); + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + default: + assert(false, 'Unexpected number of auth attempts'); + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + // We should not expect any further auth attempts after we verify a + // signature + authAttempt = Infinity; + } + ctx.accept(); + }, 2)).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + })); + })); + })); +}); + + +// Different host key types +[ + { desc: 'RSA host key (old OpenSSH)', + hostKey: fixture('id_rsa') }, + { desc: 'RSA host key (new OpenSSH)', + hostKey: fixture('openssh_new_rsa') }, + { desc: 'DSA host key', + hostKey: fixture('ssh_host_dsa_key') }, + { desc: 'ECDSA host key', + hostKey: fixture('ssh_host_ecdsa_key') }, + { desc: 'PPK', + hostKey: fixture('id_rsa.ppk') }, +].forEach((test) => { + const { desc, hostKey } = test; + const clientKey = fixtureKey('openssh_new_rsa'); + const username = 'KeyUser'; + const { server } = setup( + desc, + { + client: { + username, + privateKeyPath: clientKey.fullPath, + }, + server: { hostKeys: [ hostKey ] }, + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCallAtLeast((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 2: + case 3: + if (authAttempt === 3) + assert(ctx.signature, 'Missing publickey signature'); + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + default: + assert(false, 'Unexpected number of auth attempts'); + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + // We should not expect any further auth attempts after we verify a + // signature + authAttempt = Infinity; + } + ctx.accept(); + }, 2)).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + })); + })); + })); +}); + + +// Various edge cases +{ + const clientKey = fixtureKey('openssh_new_rsa'); + const username = 'KeyUser'; + const { server } = setup( + 'Server closes stdin too early', + { + client: { + username, + privateKeyPath: clientKey.fullPath, + }, + server: { hostKeys: [ fixture('ssh_host_rsa_key') ] }, + debug, + } + ); + + server.on('_child', mustCall((childProc) => { + childProc.stderr.once('data', mustCall((data) => { + childProc.stdin.end(); + })); + childProc.stdin.write('ping'); + })).on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCallAtLeast((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 2: + case 3: + if (authAttempt === 3) + assert(ctx.signature, 'Missing publickey signature'); + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + default: + assert(false, 'Unexpected number of auth attempts'); + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + // We should not expect any further auth attempts after we verify a + // signature + authAttempt = Infinity; + } + ctx.accept(); + }, 2)).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject) => { + const stream = accept(); + stream.stdin.on('data', mustCallAtLeast((data) => { + stream.stdout.write('pong on stdout'); + stream.stderr.write('pong on stderr'); + })).on('end', mustCall(() => { + stream.stdout.write('pong on stdout'); + stream.stderr.write('pong on stderr'); + stream.exit(0); + stream.close(); + })); + })); + })); + })); + })); +} +{ + const clientKey = fixtureKey('openssh_new_rsa'); + const username = 'KeyUser'; + const { server } = setup( + 'Rekey', + { + client: { + username, + privateKeyPath: clientKey.fullPath, + }, + server: { hostKeys: [ fixture('ssh_host_rsa_key') ] }, + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCallAtLeast((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 2: + case 3: + if (authAttempt === 3) + assert(ctx.signature, 'Missing publickey signature'); + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + default: + assert(false, 'Unexpected number of auth attempts'); + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + // We should not expect any further auth attempts after we verify a + // signature + authAttempt = Infinity; + } + ctx.accept(); + }, 2)).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + const session = accept(); + conn.rekey(); + session.on('exec', mustCall((accept, reject) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + })); + })); + })); +} + + +function setup(title, configs) { + const { + client: clientCfg, + server: serverCfg, + allReady: allReady_, + timeout: timeout_, + debug, + noForceServerReady, + } = configs; + let clientClose = false; + let serverClose = false; + let serverReady = false; + let client; + const msg = (text) => { + return `${title}: ${text}`; + }; + + const timeout = (typeof timeout_ === 'number' + ? timeout_ + : CLIENT_TIMEOUT); + + const allReady = (typeof allReady_ === 'function' ? allReady_ : undefined); + + if (debug) { + serverCfg.debug = (...args) => { + console.log(`[${title}][SERVER]`, ...args); + }; + } + + const serverReadyFn = (noForceServerReady ? onReady : mustCall(onReady)); + const server = new Server(serverCfg); + + server.on('error', onError) + .on('connection', mustCall((conn) => { + conn.on('error', onError) + .on('ready', serverReadyFn); + server.close(); + })) + .on('close', mustCall(onClose)); + + function onError(err) { + const which = (arguments.length >= 3 ? 'client' : 'server'); + assert(false, msg(`Unexpected ${which} error: ${err}`)); + } + + function onReady() { + assert(!serverReady, msg('Received multiple ready events for server')); + serverReady = true; + allReady && allReady(); + } + + function onClose() { + if (arguments.length >= 3) { + assert(!clientClose, msg('Received multiple close events for client')); + clientClose = true; + } else { + assert(!serverClose, msg('Received multiple close events for server')); + serverClose = true; + } + } + + process.nextTick(mustCall(() => { + server.listen(0, 'localhost', mustCall(() => { + const args = [ + '-o', 'UserKnownHostsFile=/dev/null', + '-o', 'StrictHostKeyChecking=no', + '-o', 'CheckHostIP=no', + '-o', 'ConnectTimeout=3', + '-o', 'GlobalKnownHostsFile=/dev/null', + '-o', 'GSSAPIAuthentication=no', + '-o', 'IdentitiesOnly=yes', + '-o', 'BatchMode=yes', + '-o', 'VerifyHostKeyDNS=no', + + '-vvvvvv', + '-T', + '-o', 'KbdInteractiveAuthentication=no', + '-o', 'HostbasedAuthentication=no', + '-o', 'PasswordAuthentication=no', + '-o', 'PubkeyAuthentication=yes', + '-o', 'PreferredAuthentications=publickey' + ]; + + if (clientCfg.privateKeyPath) + args.push('-o', `IdentityFile=${clientCfg.privateKeyPath}`); + + if (!/^[0-6]\./.test(opensshVer)) { + // OpenSSH 7.0+ disables DSS/DSA host (and user) key support by + // default, so we explicitly enable it here + args.push('-o', 'HostKeyAlgorithms=+ssh-dss'); + args.push('-o', 'PubkeyAcceptedKeyTypes=+ssh-dss'); + args.push('-o', 'PubkeyAcceptedAlgorithms=+ssh-dss'); + } + + args.push('-p', server.address().port.toString(), + '-l', clientCfg.username, + 'localhost', + 'uptime'); + + client = spawn(opensshPath, args, SPAWN_OPTS); + server.emit('_child', client); + + if (debug) { + readline.createInterface({ + input: client.stdout + }).on('line', (line) => { + console.log(`[${title}][CLIENT][STDOUT]`, line); + }); + readline.createInterface({ + input: client.stderr + }).on('line', (line) => { + console.error(`[${title}][CLIENT][STDERR]`, line); + }); + } else { + client.stdout.resume(); + client.stderr.resume(); + } + + client.on('error', (err) => { + onError(err, null, null); + }).on('exit', (code) => { + clearTimeout(client.timer); + if (code !== 0) + return onError(new Error(`Non-zero exit code ${code}`), null, null); + onClose(null, null, null); + }); + + client.timer = setTimeout(() => { + assert(false, msg('Client timeout')); + }, timeout); + })); + })); + + return { server }; +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-keygen.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-keygen.js new file mode 100644 index 0000000..986abe1 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-keygen.js @@ -0,0 +1,60 @@ +'use strict'; + +const assert = require('assert'); + +const { + utils: { + generateKeyPair, + generateKeyPairSync, + parseKey, + }, +} = require('..'); + +const { mustCall } = require('./common.js'); + +const nodeMajor = +/(?<=^v)\d+/.exec(process.version)[0]; + +function tryParse(...args) { + const ret = parseKey(...args); + if (ret instanceof Error) + throw ret; + return ret; +} + +const inputs = [ + { args: ['rsa', { bits: 2048 }], sshType: 'ssh-rsa' }, + { args: ['ecdsa', { bits: 256 }], sshType: 'ecdsa-sha2-nistp256' }, + { args: ['ecdsa', { bits: 521 }], sshType: 'ecdsa-sha2-nistp521' }, + { args: ['ed25519'], sshType: 'ssh-ed25519' }, + { args: ['rsa', { bits: 2048, passphrase: 'foo', cipher: 'aes256-cbc' }], + sshType: 'ssh-rsa' }, + { args: ['rsa', { bits: 2048, comment: 'foobarbaz' }], sshType: 'ssh-rsa' }, +]; +(function next() { + if (inputs.length === 0) + return; + const { args, sshType } = inputs.shift(); + if (args[0] === 'ed25519' && nodeMajor < 12) { + console.log('Skipping ed25519 on node < 12'); + return; + } + const passphrase = (args[1] && args[1].passphrase); + const comment = ((args[1] && args[1].comment) || ''); + const check = (keys) => { + let parsed = tryParse(keys.private, passphrase); + assert.strictEqual(parsed.type, sshType); + assert.strictEqual(parsed.comment, comment); + + parsed = tryParse(keys.public); + assert.strictEqual(parsed.type, sshType); + assert.strictEqual(parsed.comment, comment); + }; + console.log(`Testing generateKeyPairSync(${JSON.stringify(args)}) ...`); + check(generateKeyPairSync(...args)); + console.log(`Testing generateKeyPair(${JSON.stringify(args)}) ...`); + generateKeyPair(...args, mustCall((err, keys) => { + assert.ifError(err); + check(keys); + next(); + })); +})(); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-misc-client-server.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-misc-client-server.js new file mode 100644 index 0000000..2dd5a29 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-misc-client-server.js @@ -0,0 +1,1460 @@ +'use strict'; + +const assert = require('assert'); +const { createHash } = require('crypto'); +const http = require('http'); +const https = require('https'); +const net = require('net'); +const { Transform } = require('stream'); +const { inspect } = require('util'); + +const Client = require('../lib/client.js'); +const { + SSHTTPAgent: HTTPAgent, + SSHTTPSAgent: HTTPSAgent, +} = require('../lib/http-agents.js'); +const Server = require('../lib/server.js'); +const { KexInit } = require('../lib/protocol/kex.js'); + +const { + fixture, + mustCall, + mustCallAtLeast, + mustNotCall, + setup: setup_, + setupSimple, +} = require('./common.js'); + +const KEY_RSA_BAD = fixture('bad_rsa_private_key'); +const HOST_RSA_MD5 = '64254520742d3d0792e918f3ce945a64'; +const clientCfg = { username: 'foo', password: 'bar' }; +const serverCfg = { hostKeys: [ fixture('ssh_host_rsa_key') ] }; + +const debug = false; + +const setup = setupSimple.bind(undefined, debug); + + +{ + const { server } = setup_( + 'Verify host fingerprint (sync success, hostHash set)', + { + client: { + ...clientCfg, + hostHash: 'md5', + hostVerifier: mustCall((hash) => { + assert(hash === HOST_RSA_MD5, 'Host fingerprint mismatch'); + return true; + }), + }, + server: serverCfg, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} + +{ + const { server } = setup_( + 'Verify host fingerprint (sync success, hostHash not set)', + { + client: { + ...clientCfg, + hostVerifier: mustCall((key) => { + assert(Buffer.isBuffer(key), 'Expected buffer'); + let hash = createHash('md5'); + hash.update(key); + hash = hash.digest('hex'); + assert(hash === HOST_RSA_MD5, 'Host fingerprint mismatch'); + return true; + }), + }, + server: serverCfg, + } + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} + +{ + const { server } = setup_( + 'Verify host fingerprint (async success)', + { + client: { + ...clientCfg, + hostVerifier: mustCall((key, cb) => { + assert(Buffer.isBuffer(key), 'Expected buffer'); + let hash = createHash('md5'); + hash.update(key); + hash = hash.digest('hex'); + assert(hash === HOST_RSA_MD5, 'Host fingerprint mismatch'); + process.nextTick(cb, true); + }), + }, + server: serverCfg, + } + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} + +{ + const { client, server } = setup_( + 'Verify host fingerprint (sync failure)', + { + client: { + ...clientCfg, + hostVerifier: mustCall((key) => { + return false; + }), + }, + server: serverCfg, + + noForceClientReady: true, + noForceServerReady: true, + }, + ); + + client.removeAllListeners('error'); + client.on('ready', mustNotCall()) + .on('error', mustCall((err) => { + assert(/verification failed/.test(err.message), + 'Wrong client error message'); + })); + + server.on('connection', mustCall((conn) => { + conn.removeAllListeners('error'); + + conn.on('authentication', mustNotCall()) + .on('ready', mustNotCall()) + .on('error', mustCall((err) => { + assert(/KEY_EXCHANGE_FAILED/.test(err.message), + 'Wrong server error message'); + })); + })); +} + +{ + // connect() on connected client + + const clientCfg_ = { ...clientCfg }; + const client = new Client(); + const server = new Server(serverCfg); + + server.listen(0, 'localhost', mustCall(() => { + clientCfg_.host = 'localhost'; + clientCfg_.port = server.address().port; + client.connect(clientCfg_); + })); + + let connections = 0; + server.on('connection', mustCall((conn) => { + if (++connections === 2) + server.close(); + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => {})); + }, 2)).on('close', mustCall(() => {})); + + let reconnect = false; + client.on('ready', mustCall(() => { + if (reconnect) { + client.end(); + } else { + reconnect = true; + client.connect(clientCfg_); + } + }, 2)).on('close', mustCall(() => {}, 2)); +} + +{ + // Throw when not connected + + const client = new Client({ + username: 'foo', + password: 'bar', + }); + + assert.throws(mustCall(() => { + client.exec('uptime', mustNotCall()); + })); +} + +{ + const { client, server } = setup( + 'Outstanding callbacks called on disconnect' + ); + + server.on('connection', mustCall((conn) => { + conn.on('session', mustCall(() => {}, 3)); + })); + + client.on('ready', mustCall(() => { + function callback(err, stream) { + assert(err, 'Expected error'); + assert(err.message === 'No response from server', + `Wrong error message: ${err.message}`); + } + client.exec('uptime', mustCall(callback)); + client.shell(mustCall(callback)); + client.sftp(mustCall(callback)); + client.end(); + })); +} + +{ + const { client, server } = setup('Pipelined requests'); + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + const session = accept(); + session.on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + }, 3)); + })); + })); + + client.on('ready', mustCall(() => { + let calledBack = 0; + function callback(err, stream) { + assert(!err, `Unexpected error: ${err}`); + stream.resume(); + if (++calledBack === 3) + client.end(); + } + client.exec('foo', mustCall(callback)); + client.exec('bar', mustCall(callback)); + client.exec('baz', mustCall(callback)); + })); +} + +{ + const { client, server } = setup( + 'Pipelined requests with intermediate rekeying' + ); + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + const reqs = []; + conn.on('session', mustCall((accept, reject) => { + if (reqs.length === 0) { + conn.rekey(mustCall((err) => { + assert(!err, `Unexpected rekey error: ${err}`); + reqs.forEach((accept) => { + const session = accept(); + session.on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + }); + })); + } + reqs.push(accept); + }, 3)); + })); + })); + + client.on('ready', mustCall(() => { + let calledBack = 0; + function callback(err, stream) { + assert(!err, `Unexpected error: ${err}`); + stream.resume(); + if (++calledBack === 3) + client.end(); + } + client.exec('foo', mustCall(callback)); + client.exec('bar', mustCall(callback)); + client.exec('baz', mustCall(callback)); + })); +} + +{ + const { client, server } = setup('Ignore outgoing after stream close'); + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + const session = accept(); + session.on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo', mustCall((err, stream) => { + assert(!err, `Unexpected error: ${err}`); + stream.on('exit', mustCall((code, signal) => { + client.end(); + })); + })); + })); +} + +{ + const { client, server } = setup_( + 'Double pipe on unconnected, passed in net.Socket', + { + client: { + ...clientCfg, + sock: new net.Socket(), + }, + server: serverCfg, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => {})); + })); + client.on('ready', mustCall(() => { + client.end(); + })); +} + +{ + const { client, server } = setup( + 'Client auto-rejects inbound connections to unknown bound address' + ); + + const assignedPort = 31337; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('request', mustCall((accept, reject, name, info) => { + assert(name === 'tcpip-forward', 'Wrong request name'); + assert.deepStrictEqual( + info, + { bindAddr: 'good', bindPort: 0 }, + 'Wrong request info' + ); + accept(assignedPort); + conn.forwardOut(info.bindAddr, + assignedPort, + 'remote', + 12345, + mustCall((err, ch) => { + assert(!err, `Unexpected error: ${err}`); + conn.forwardOut('bad', + assignedPort, + 'remote', + 12345, + mustCall((err, ch) => { + assert(err, 'Should receive error'); + client.end(); + })); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + // request forwarding + client.forwardIn('good', 0, mustCall((err, port) => { + assert(!err, `Unexpected error: ${err}`); + assert(port === assignedPort, 'Wrong assigned port'); + })); + })).on('tcp connection', mustCall((details, accept, reject) => { + assert.deepStrictEqual( + details, + { destIP: 'good', + destPort: assignedPort, + srcIP: 'remote', + srcPort: 12345 + }, + 'Wrong connection details' + ); + accept(); + })); +} + +{ + const { client, server } = setup( + 'Client auto-rejects inbound connections to unknown bound port' + ); + + const assignedPort = 31337; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('request', mustCall((accept, reject, name, info) => { + assert(name === 'tcpip-forward', 'Wrong request name'); + assert.deepStrictEqual( + info, + { bindAddr: 'good', bindPort: 0 }, + 'Wrong request info' + ); + accept(assignedPort); + conn.forwardOut(info.bindAddr, + assignedPort, + 'remote', + 12345, + mustCall((err, ch) => { + assert(!err, `Unexpected error: ${err}`); + conn.forwardOut(info.bindAddr, + 99999, + 'remote', + 12345, + mustCall((err, ch) => { + assert(err, 'Should receive error'); + client.end(); + })); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + // request forwarding + client.forwardIn('good', 0, mustCall((err, port) => { + assert(!err, `Unexpected error: ${err}`); + assert(port === assignedPort, 'Wrong assigned port'); + })); + })).on('tcp connection', mustCall((details, accept, reject) => { + assert.deepStrictEqual( + details, + { destIP: 'good', + destPort: assignedPort, + srcIP: 'remote', + srcPort: 12345 + }, + 'Wrong connection details' + ); + accept(); + })); +} + +{ + const GREETING = 'Hello world!'; + + const { client, server } = setup_( + 'Server greeting', + { + client: { + ...clientCfg, + ident: 'node.js rules', + }, + server: { + ...serverCfg, + greeting: GREETING, + } + }, + ); + + let sawGreeting = false; + + server.on('connection', mustCall((conn, info) => { + assert.deepStrictEqual(info.header, { + identRaw: 'SSH-2.0-node.js rules', + greeting: '', + versions: { + protocol: '2.0', + software: 'node.js' + }, + comments: 'rules' + }); + conn.on('handshake', mustCall((details) => { + assert(sawGreeting, 'Client did not see greeting before handshake'); + })).on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); + + client.on('greeting', mustCall((greeting) => { + assert.strictEqual(greeting, `${GREETING}\r\n`); + sawGreeting = true; + })).on('banner', mustNotCall()); +} + +{ + const { client, server } = setup_( + 'Correct ident parsing', + { + client: { + ...clientCfg, + ident: 'node.js rules\n', + }, + server: serverCfg, + + noServerError: true, + noClientError: true, + noForceServerReady: true, + noForceClientReady: true, + }, + ); + + server.on('connection', mustCall((conn, info) => { + assert.deepStrictEqual(info.header, { + identRaw: 'SSH-2.0-node.js rules', + greeting: '', + versions: { + protocol: '2.0', + software: 'node.js' + }, + comments: 'rules' + }); + conn.once('error', mustCall((err) => { + assert(/bad packet length/i.test(err.message), 'Wrong error message'); + })); + conn.on('handshake', mustNotCall()) + .on('authentication', mustNotCall()) + .on('ready', mustNotCall()); + })); + + client.on('greeting', mustNotCall()) + .on('banner', mustNotCall()) + .on('ready', mustNotCall()); +} + +{ + const BANNER = 'Hello world!'; + + let authCb; + const { client, server } = setup_( + 'Server banner', + { + client: { + ...clientCfg, + // This test uses a custom auth handler to avoid a race condition where + // we don't get the complete banner packet before the default auth + // handler immediately sends the initial auth method + authHandler: (authsLeft, partialSuccess, cb) => { + authCb = cb; + }, + }, + server: { + ...serverCfg, + banner: BANNER, + } + }, + ); + + let sawBanner = false; + + server.on('connection', mustCall((conn) => { + conn.on('handshake', mustCall((details) => { + assert(!sawBanner, 'Client saw banner too early'); + })).on('authentication', mustCall((ctx) => { + assert(sawBanner, 'Client did not see banner before auth'); + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); + + client.on('greeting', mustNotCall()) + .on('banner', mustCall((message) => { + assert.strictEqual(message, 'Hello world!\r\n'); + sawBanner = true; + authCb('password'); + })); +} + +{ + const { client, server } = setup( + 'Server responds to global requests in the right order' + ); + + function sendAcceptLater(accept) { + if (fastRejectSent) + accept(); + else + setImmediate(sendAcceptLater, accept); + } + + let fastRejectSent = false; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('request', mustCall((accept, reject, name, info) => { + if (info.bindAddr === 'fastReject') { + // Will call reject on 'fastReject' soon ... + reject(); + fastRejectSent = true; + } else { + // ... but accept on 'slowAccept' later + sendAcceptLater(accept); + } + }, 2)); + })); + })); + + client.on('ready', mustCall(() => { + let replyCnt = 0; + + client.forwardIn('slowAccept', 0, mustCall((err) => { + assert(!err, `Unexpected error: ${err}`); + if (++replyCnt === 2) + client.end(); + })); + + client.forwardIn('fastReject', 0, mustCall((err) => { + assert(err, 'Expected error'); + if (++replyCnt === 2) + client.end(); + })); + })); +} + +{ + const { client, server } = setup( + 'Cleanup outstanding channel requests on channel close' + ); + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + const session = accept(); + session.on('subsystem', mustCall((accept, reject, info) => { + assert(info.name === 'netconf', `Wrong subsystem name: ${info.name}`); + + // XXX: hack to prevent success reply from being sent + conn._protocol.channelSuccess = () => {}; + + accept().close(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.subsys('netconf', mustCall((err, stream) => { + assert(err, 'Expected error'); + client.end(); + })); + })); +} + +{ + const { client, server } = setup_( + 'Handshake errors are emitted', + { + client: { + ...clientCfg, + algorithms: { cipher: [ 'aes128-cbc' ] }, + }, + server: { + ...serverCfg, + algorithms: { cipher: [ 'aes128-ctr' ] }, + }, + + noForceClientReady: true, + noForceServerReady: true, + }, + ); + + client.removeAllListeners('error'); + + function onError(err) { + assert.strictEqual(err.level, 'handshake'); + assert(/handshake failed/i.test(err.message), 'Wrong error message'); + } + + server.on('connection', mustCall((conn) => { + conn.removeAllListeners('error'); + + conn.on('authentication', mustNotCall()) + .on('ready', mustNotCall()) + .on('handshake', mustNotCall()) + .on('error', mustCall(onError)) + .on('close', mustCall(() => {})); + })); + + client.on('ready', mustNotCall()) + .on('error', mustCall(onError)) + .on('close', mustCall(() => {})); +} + +{ + const { client, server } = setup_( + 'Client signing errors are caught and emitted', + { + client: { + username: 'foo', + privateKey: KEY_RSA_BAD, + }, + server: serverCfg, + + noForceClientReady: true, + noForceServerReady: true, + }, + ); + + client.removeAllListeners('error'); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(!ctx.signature, 'Unexpected signature'); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + ctx.accept(); + break; + } + }, 2)).on('ready', mustNotCall()).on('close', mustCall(() => {})); + })); + + let cliError; + client.on('ready', mustNotCall()).on('error', mustCall((err) => { + if (cliError) { + assert(/all configured/i.test(err.message), 'Wrong error message'); + } else { + cliError = err; + assert(/signing/i.test(err.message), 'Wrong error message'); + } + }, 2)).on('close', mustCall(() => {})); +} + +{ + const { client, server } = setup_( + 'Server signing errors are caught and emitted', + { + client: clientCfg, + server: { hostKeys: [KEY_RSA_BAD] }, + + noForceClientReady: true, + noForceServerReady: true, + }, + ); + + client.removeAllListeners('error'); + + server.on('connection', mustCall((conn) => { + conn.removeAllListeners('error'); + + conn.on('error', mustCall((err) => { + assert(/signature generation failed/i.test(err.message), + 'Wrong error message'); + })).on('authentication', mustNotCall()) + .on('ready', mustNotCall()) + .on('close', mustCall(() => {})); + })); + + client.on('ready', mustNotCall()).on('error', mustCall((err) => { + assert(/KEY_EXCHANGE_FAILED/.test(err.message), 'Wrong error message'); + })).on('close', mustCall(() => {})); +} + +{ + const { client, server } = setup_( + 'Rekeying with AES-GCM', + { + client: { + ...clientCfg, + algorithms: { cipher: [ 'aes128-gcm@openssh.com' ] }, + }, + server: { + ...serverCfg, + algorithms: { cipher: [ 'aes128-gcm@openssh.com' ] }, + }, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + const reqs = []; + conn.on('session', mustCall((accept, reject) => { + if (reqs.length === 0) { + conn.rekey(mustCall((err) => { + assert(!err, `Unexpected rekey error: ${err}`); + reqs.forEach((accept) => { + const session = accept(); + session.on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + }); + })); + } + reqs.push(accept); + }, 3)); + })); + })); + + client.on('ready', mustCall(() => { + let calledBack = 0; + function callback(err, stream) { + assert(!err, `Unexpected error: ${err}`); + stream.resume(); + if (++calledBack === 3) + client.end(); + } + client.exec('foo', mustCall(callback)); + client.exec('bar', mustCall(callback)); + client.exec('baz', mustCall(callback)); + })); +} + +{ + const { client, server } = setup_( + 'Switch from no compression to compression', + { + client: { + ...clientCfg, + algorithms: { compress: [ 'none' ] }, + }, + server: { + ...serverCfg, + algorithms: { compress: [ 'none', 'zlib@openssh.com' ] }, + }, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + const reqs = []; + conn.on('session', mustCall((accept, reject) => { + if (reqs.length === 0) { + // XXX: hack to change algorithms after initial handshake + client._protocol._offer = new KexInit({ + kex: [ 'ecdh-sha2-nistp256' ], + serverHostKey: [ 'rsa-sha2-256' ], + cs: { + cipher: [ 'aes128-gcm@openssh.com' ], + mac: [], + compress: [ 'zlib@openssh.com' ], + lang: [], + }, + sc: { + cipher: [ 'aes128-gcm@openssh.com' ], + mac: [], + compress: [ 'zlib@openssh.com' ], + lang: [], + }, + }); + + conn.rekey(mustCall((err) => { + assert(!err, `Unexpected rekey error: ${err}`); + reqs.forEach((accept) => { + const session = accept(); + session.on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + }); + })); + } + reqs.push(accept); + }, 3)); + })); + })); + + let handshakes = 0; + client.on('handshake', mustCall((info) => { + switch (++handshakes) { + case 1: + assert(info.cs.compress === 'none', 'wrong compress value'); + assert(info.sc.compress === 'none', 'wrong compress value'); + break; + case 2: + assert(info.cs.compress === 'zlib@openssh.com', + 'wrong compress value'); + assert(info.sc.compress === 'zlib@openssh.com', + 'wrong compress value'); + break; + } + }, 2)).on('ready', mustCall(() => { + let calledBack = 0; + function callback(err, stream) { + assert(!err, `Unexpected error: ${err}`); + stream.resume(); + if (++calledBack === 3) + client.end(); + } + client.exec('foo', mustCall(callback)); + client.exec('bar', mustCall(callback)); + client.exec('baz', mustCall(callback)); + })); +} + +{ + const { client, server } = setup_( + 'Switch from compression to no compression', + { + client: { + ...clientCfg, + algorithms: { compress: [ 'zlib' ] }, + }, + server: { + ...serverCfg, + algorithms: { compress: [ 'zlib', 'none' ] }, + } + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + const reqs = []; + conn.on('session', mustCall((accept, reject) => { + if (reqs.length === 0) { + // XXX: hack to change algorithms after initial handshake + client._protocol._offer = new KexInit({ + kex: [ 'ecdh-sha2-nistp256' ], + serverHostKey: [ 'rsa-sha2-256' ], + cs: { + cipher: [ 'aes128-gcm@openssh.com' ], + mac: [], + compress: [ 'none' ], + lang: [], + }, + sc: { + cipher: [ 'aes128-gcm@openssh.com' ], + mac: [], + compress: [ 'none' ], + lang: [], + }, + }); + + conn.rekey(mustCall((err) => { + assert(!err, `Unexpected rekey error: ${err}`); + reqs.forEach((accept) => { + const session = accept(); + session.on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + stream.exit(0); + stream.end(); + })); + }); + })); + } + reqs.push(accept); + }, 3)); + })); + })); + + let handshakes = 0; + client.on('handshake', mustCall((info) => { + switch (++handshakes) { + case 1: + assert(info.cs.compress === 'zlib', 'wrong compress value'); + assert(info.sc.compress === 'zlib', 'wrong compress value'); + break; + case 2: + assert(info.cs.compress === 'none', 'wrong compress value'); + assert(info.sc.compress === 'none', 'wrong compress value'); + break; + } + }, 2)).on('ready', mustCall(() => { + let calledBack = 0; + function callback(err, stream) { + assert(!err, `Unexpected error: ${err}`); + stream.resume(); + if (++calledBack === 3) + client.end(); + } + client.exec('foo', mustCall(callback)); + client.exec('bar', mustCall(callback)); + client.exec('baz', mustCall(callback)); + })); +} + +{ + const { client, server } = setup_( + 'Large data compression', + { + client: { + ...clientCfg, + algorithms: { compress: [ 'zlib' ] }, + }, + server: { + ...serverCfg, + algorithms: { compress: [ 'zlib' ] }, + } + }, + ); + + const chunk = Buffer.alloc(1024 * 1024, 'a'); + const chunkCount = 10; + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject, info) => { + const stream = accept(); + for (let i = 0; i < chunkCount; ++i) + stream.write(chunk); + stream.exit(0); + stream.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo', mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + let nb = 0; + stream.on('data', mustCallAtLeast((data) => { + nb += data.length; + })).on('end', mustCall(() => { + assert(nb === (chunkCount * chunk.length), + `Wrong stream byte count: ${nb}`); + client.end(); + })); + })); + })); +} + +{ + const { client, server } = setup_( + 'Debug output', + { + client: { + ...clientCfg, + debug: mustCallAtLeast((msg) => { + assert(typeof msg === 'string', + `Wrong debug argument type: ${typeof msg}`); + assert(msg.length > 0, 'Unexpected empty debug message'); + }), + }, + server: { + ...serverCfg, + debug: mustCallAtLeast((msg) => { + assert(typeof msg === 'string', + `Wrong debug argument type: ${typeof msg}`); + assert(msg.length > 0, 'Unexpected empty debug message'); + }), + }, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo --bar', mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.resume(); + })); + })); +} + +{ + const { server } = setup_( + 'HTTP agent', + { + // No automatic client, the agent will create one + + server: serverCfg, + + debug, + }, + ); + + let httpServer; + server.on('listening', () => { + httpServer = http.createServer((req, res) => { + httpServer.close(); + res.end('hello world!'); + }); + httpServer.listen(0, 'localhost', () => { + const agent = new HTTPAgent({ + host: 'localhost', + port: server.address().port, + username: 'foo', + password: 'bar', + }); + http.get({ + host: 'localhost', + port: httpServer.address().port, + agent, + headers: { Connection: 'close' }, + }, (res) => { + assert(res.statusCode === 200, + `Wrong http status code: ${res.statusCode}`); + let buf = ''; + res.on('data', mustCallAtLeast((chunk) => { + buf += chunk; + })).on('end', mustCall(() => { + assert(buf === 'hello world!', + `Wrong http response body: ${inspect(buf)}`); + })); + }); + }); + }); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('tcpip', mustCall((accept, reject, info) => { + assert(info.destIP === 'localhost', `Wrong destIP: ${info.destIP}`); + assert(info.destPort === httpServer.address().port, + `Wrong destPort: ${info.destPort}`); + assert(info.srcIP === 'localhost', `Wrong srcIP: ${info.srcIP}`); + + const stream = accept(); + const tcp = new net.Socket(); + tcp.pipe(stream).pipe(tcp); + tcp.connect(httpServer.address().port, 'localhost'); + })); + })); + })); +} + +{ + const { server } = setup_( + 'HTTPS agent', + { + // No automatic client, the agent will create one + + server: serverCfg, + + debug, + }, + ); + + let httpsServer; + server.on('listening', () => { + httpsServer = https.createServer({ + key: fixture('https_key.pem'), + cert: fixture('https_cert.pem'), + }, (req, res) => { + httpsServer.close(); + res.end('hello world!'); + }); + httpsServer.listen(0, 'localhost', () => { + const agent = new HTTPSAgent({ + host: 'localhost', + port: server.address().port, + username: 'foo', + password: 'bar', + }); + https.get({ + host: 'localhost', + port: httpsServer.address().port, + agent, + headers: { Connection: 'close' }, + ca: fixture('https_cert.pem'), + }, (res) => { + assert(res.statusCode === 200, + `Wrong http status code: ${res.statusCode}`); + let buf = ''; + res.on('data', mustCallAtLeast((chunk) => { + buf += chunk; + })).on('end', mustCall(() => { + assert(buf === 'hello world!', + `Wrong http response body: ${inspect(buf)}`); + })); + }).on('error', (err) => { + // This workaround is necessary for some reason on node < v14.x + if (!/write after end/i.test(err.message)) + throw err; + }); + }); + }); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('tcpip', mustCall((accept, reject, info) => { + assert(info.destIP === 'localhost', `Wrong destIP: ${info.destIP}`); + assert(info.destPort === httpsServer.address().port, + `Wrong destPort: ${info.destPort}`); + assert(info.srcIP === 'localhost', `Wrong srcIP: ${info.srcIP}`); + + const stream = accept(); + const tcp = new net.Socket(); + tcp.pipe(stream).pipe(tcp); + tcp.connect(httpsServer.address().port, 'localhost'); + })); + })); + })); +} + +[ + { desc: 'remove/append/prepend (regexps)', + config: { + remove: /.*/, + append: /gcm/, + prepend: /ctr/, + }, + expected: [ + 'aes128-ctr', + 'aes192-ctr', + 'aes256-ctr', + 'aes128-gcm@openssh.com', + 'aes256-gcm@openssh.com', + 'aes128-gcm', + 'aes256-gcm', + ], + }, + { desc: 'remove/append/prepend (strings)', + config: { + remove: /.*/, + append: 'aes256-ctr', + prepend: [ 'aes256-gcm@openssh.com', 'aes128-gcm@openssh.com' ], + }, + expected: [ + 'aes256-gcm@openssh.com', + 'aes128-gcm@openssh.com', + 'aes256-ctr', + ], + }, +].forEach((info) => { + const { client, server } = setup_( + `Client algorithms option (${info.desc})`, + { + client: { + ...clientCfg, + algorithms: { cipher: info.config }, + }, + server: serverCfg, + + debug, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); + client.on('ready', mustCall(() => { + // XXX: hack to easily verify computed offer + const offer = client._protocol._offer.lists; + assert.deepStrictEqual( + offer.cs.cipher.array, + info.expected, + `Wrong algorithm list: ${offer.cs.cipher.array}` + ); + })); +}); + +{ + const { client } = setup_( + `Safely end() from Client 'error' event handler`, + { + client: clientCfg, + noClientError: true, + noForceClientReady: true, + }, + ); + + const badServer = net.createServer((s) => {}); + badServer.listen(0, 'localhost', mustCall(() => { + badServer.unref(); + + client.on('error', mustCallAtLeast((err) => { + client.end(); + })).on('ready', mustNotCall()).on('close', mustCall(() => {})); + client.connect({ + host: 'localhost', + port: badServer.address().port, + user: 'foo', + password: 'bar', + readyTimeout: 1, + }); + })); +} + +{ + const { client } = setup_( + 'Client error should be emitted on bad/nonexistent greeting', + { + client: clientCfg, + noClientError: true, + noForceClientReady: true, + }, + ); + + const badServer = net.createServer(mustCall((s) => { + badServer.close(); + s.end(); + })).listen(0, 'localhost', mustCall(() => { + client.on('error', mustCall((err) => { + client.end(); + })).on('ready', mustNotCall()).on('close', mustCall(() => {})); + client.connect({ + host: 'localhost', + port: badServer.address().port, + user: 'foo', + password: 'bar', + }); + })); +} + +{ + const { client } = setup_( + 'Only one client error on connection failure', + { + client: clientCfg, + noClientError: true, + noForceClientReady: true, + }, + ); + + client.on('error', mustCall((err) => { + assert.strictEqual(err.syscall, 'getaddrinfo'); + })); + client.connect({ + host: 'blerbblubblubblerb', + port: 9999, + user: 'foo', + password: 'bar' + }); +} + +{ + const { client, server } = setup( + 'Client should remove reserved channels on incoming channel rejection' + ); + + const assignedPort = 31337; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('request', mustCall((accept, reject, name, info) => { + assert(name === 'tcpip-forward', 'Wrong request name'); + assert.deepStrictEqual( + info, + { bindAddr: 'good', bindPort: 0 }, + 'Wrong request info' + ); + accept(assignedPort); + conn.forwardOut(info.bindAddr, + assignedPort, + 'remote', + 12345, + mustCall((err, ch) => { + assert(err, 'Should receive error'); + client.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + // request forwarding + client.forwardIn('good', 0, mustCall((err, port) => { + assert(!err, `Unexpected error: ${err}`); + assert(port === assignedPort, 'Wrong assigned port'); + })); + })).on('tcp connection', mustCall((details, accept, reject) => { + assert.deepStrictEqual( + details, + { destIP: 'good', + destPort: assignedPort, + srcIP: 'remote', + srcPort: 12345 + }, + 'Wrong connection details' + ); + assert.strictEqual(Object.keys(client._chanMgr._channels).length, 1); + assert.strictEqual(client._chanMgr._count, 1); + reject(); + assert.strictEqual(Object.keys(client._chanMgr._channels).length, 0); + assert.strictEqual(client._chanMgr._count, 0); + })); +} + +{ + // Allow injected sockets + + const socket = new Transform({ + emitClose: true, + autoDestroy: true, + transform: (chunk, encoding, cb) => { + cb(); + }, + }); + socket.remoteAddress = '127.0.0.1'; + socket.remotePort = '12345'; + socket.remoteFamily = 'IPv4'; + socket.push(Buffer.from('SSH-2.0-foo\r\n')); + + const server = new Server(serverCfg); + server.on('connection', mustCall((conn, info) => { + assert.strictEqual(info.header.versions.software, 'foo'); + assert.strictEqual(info.ip, '127.0.0.1'); + assert.strictEqual(info.port, '12345'); + assert.strictEqual(info.family, 'IPv4'); + conn.on('ready', mustNotCall()); + conn.on('close', mustCall()); + socket.end(); + })); + server.injectSocket(socket); +} + +{ + const { client, server } = setup( + 'Server should not error when cleaning up client bare session channels' + ); + + server.on('connection', mustCall((conn) => { + conn.on('session', mustCall((accept, reject) => { + accept().on('exec', mustCall((accept, reject, info) => { + assert(info.command === 'uptime', + `Wrong exec command: ${info.command}`); + client.end(); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('uptime', mustCall((err) => { + assert(err instanceof Error); + })); + })); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-openssh.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-openssh.js new file mode 100644 index 0000000..67e1b86 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-openssh.js @@ -0,0 +1,261 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const { + fixture, + mustCall, + mustCallAtLeast, + setup: setup_, +} = require('./common.js'); + +const debug = false; + +const clientCfg = { username: 'foo', password: 'bar' }; +const serverCfg = { hostKeys: [ fixture('ssh_host_rsa_key') ] }; + +{ + const { client, server } = setup_( + 'Exec with OpenSSH agent forwarding', + { + client: { + ...clientCfg, + agent: '/path/to/agent', + }, + server: serverCfg, + + debug, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let sawAuthAgent = false; + accept().on('auth-agent', mustCall((accept, reject) => { + sawAuthAgent = true; + accept && accept(); + })).on('exec', mustCall((accept, reject, info) => { + assert(sawAuthAgent, 'Expected auth-agent before exec'); + assert(info.command === 'foo --bar', + `Wrong exec command: ${info.command}`); + const stream = accept(); + stream.exit(100); + stream.end(); + conn.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.exec('foo --bar', { agentForward: true }, mustCall((err, stream) => { + assert(!err, `Unexpected exec error: ${err}`); + stream.resume(); + })); + })); +} + +{ + const { client, server } = setup_( + 'OpenSSH forwarded UNIX socket connection', + { + client: clientCfg, + server: { + ...serverCfg, + ident: 'OpenSSH_7.1', + }, + + debug, + }, + ); + + const socketPath = '/foo'; + const events = []; + const expected = [ + ['client', 'openssh_forwardInStreamLocal'], + ['server', 'streamlocal-forward@openssh.com', { socketPath }], + ['client', 'forward callback'], + ['client', 'unix connection', { socketPath }], + ['client', 'socket data', '1'], + ['server', 'socket data', '2'], + ['client', 'socket end'], + ['server', 'cancel-streamlocal-forward@openssh.com', { socketPath }], + ['client', 'cancel callback'] + ]; + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.once('request', mustCall((accept, reject, name, info) => { + events.push(['server', name, info]); + assert(name === 'streamlocal-forward@openssh.com', + `Wrong request name: ${name}`); + accept(); + conn.openssh_forwardOutStreamLocal(socketPath, + mustCall((err, ch) => { + assert(!err, `Unexpected error: ${err}`); + ch.write('1'); + ch.on('data', mustCallAtLeast((data) => { + events.push(['server', 'socket data', data.toString()]); + ch.close(); + })); + })); + + conn.on('request', mustCall((accept, reject, name, info) => { + events.push(['server', name, info]); + assert(name === 'cancel-streamlocal-forward@openssh.com', + `Wrong request name: ${name}`); + accept(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + // request forwarding + events.push(['client', 'openssh_forwardInStreamLocal']); + client.openssh_forwardInStreamLocal(socketPath, mustCall((err) => { + assert(!err, `Unexpected error: ${err}`); + events.push(['client', 'forward callback']); + })); + client.on('unix connection', mustCall((info, accept, reject) => { + events.push(['client', 'unix connection', info]); + const stream = accept(); + stream.on('data', mustCallAtLeast((data) => { + events.push(['client', 'socket data', data.toString()]); + stream.write('2'); + })).on('end', mustCall(() => { + events.push(['client', 'socket end']); + client.openssh_unforwardInStreamLocal(socketPath, + mustCall((err) => { + assert(!err, `Unexpected error: ${err}`); + events.push(['client', 'cancel callback']); + client.end(); + })); + })); + })); + })).on('close', mustCall(() => { + assert.deepStrictEqual( + events, + expected, + 'Events mismatch\n' + + `Actual:\n${inspect(events)}\n` + + `Expected:\n${inspect(expected)}` + ); + })); +} + +{ + const { client, server } = setup_( + 'OpenSSH UNIX socket connection', + { + client: clientCfg, + server: { + ...serverCfg, + ident: 'OpenSSH_8.0', + }, + + debug, + }, + ); + + const socketPath = '/foo/bar/baz'; + const response = 'Hello World'; + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('openssh.streamlocal', mustCall((accept, reject, info) => { + assert.deepStrictEqual( + info, + { socketPath }, + `Wrong info: ${inspect(info)}` + ); + + const stream = accept(); + stream.on('close', mustCall(() => { + client.end(); + })).end(response); + stream.resume(); + })); + })); + })); + + client.on('ready', mustCall(() => { + client.openssh_forwardOutStreamLocal(socketPath, mustCall((err, stream) => { + assert(!err, `Unexpected error: ${err}`); + let buf = ''; + stream.on('data', mustCallAtLeast((data) => { + buf += data; + })).on('close', mustCall(() => { + assert(buf === response, `Wrong response: ${inspect(buf)}`); + })); + })); + })); +} + +{ + const { client, server } = setup_( + 'OpenSSH 5.x workaround for binding on port 0', + { + client: clientCfg, + server: { + ...serverCfg, + ident: 'OpenSSH_5.3', + }, + + debug, + }, + ); + + const boundAddr = 'good'; + const boundPort = 1337; + const tcpInfo = { + destIP: boundAddr, + destPort: boundPort, + srcIP: 'remote', + srcPort: 12345, + }; + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('request', mustCall((accept, reject, name, info) => { + assert(name === 'tcpip-forward', `Unexpected request: ${name}`); + assert(info.bindAddr === boundAddr, `Wrong addr: ${info.bindAddr}`); + assert(info.bindPort === 0, `Wrong port: ${info.bindPort}`); + accept(boundPort); + conn.forwardOut(boundAddr, + 0, + tcpInfo.srcIP, + tcpInfo.srcPort, + mustCall((err, ch) => { + assert(!err, `Unexpected error: ${err}`); + client.end(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + // request forwarding + client.forwardIn(boundAddr, 0, mustCall((err, port) => { + assert(!err, `Unexpected error: ${err}`); + assert(port === boundPort, `Bad bound port: ${port}`); + })); + })).on('tcp connection', mustCall((details, accept, reject) => { + assert.deepStrictEqual( + details, + tcpInfo, + `Wrong tcp details: ${inspect(details)}` + ); + accept(); + })); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-crypto.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-crypto.js new file mode 100644 index 0000000..2203104 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-crypto.js @@ -0,0 +1,631 @@ +'use strict'; + +const assert = require('assert'); +const { randomBytes } = require('crypto'); + +const { + CIPHER_INFO, + MAC_INFO, + bindingAvailable, + NullCipher, + createCipher, + NullDecipher, + createDecipher, + init: cryptoInit, +} = require('../lib/protocol/crypto.js'); + +(async () => { + await cryptoInit; + + console.log(`Crypto binding ${bindingAvailable ? '' : 'not '}available`); + { + const PAIRS = [ + // cipher, decipher + ['native', 'native'], + ['binding', 'native'], + ['native', 'binding'], + ['binding', 'binding'], + ].slice(0, bindingAvailable ? 4 : 1); + + [ + { cipher: null }, + { cipher: 'chacha20-poly1305@openssh.com' }, + { cipher: 'aes128-gcm@openssh.com' }, + { cipher: 'aes128-cbc', mac: 'hmac-sha1-etm@openssh.com' }, + { cipher: 'aes128-ctr', mac: 'hmac-sha1' }, + { cipher: 'arcfour', mac: 'hmac-sha2-256-96' }, + ].forEach((testConfig) => { + for (const pair of PAIRS) { + function onCipherData(data) { + ciphered = Buffer.concat([ciphered, data]); + } + + function onDecipherPayload(payload) { + deciphered.push(payload); + } + + function reset() { + ciphered = Buffer.alloc(0); + deciphered = []; + } + + function reinit() { + if (testConfig.cipher === null) { + cipher = new NullCipher(1, onCipherData); + decipher = new NullDecipher(1, onDecipherPayload); + } else { + cipher = createCipher(config); + decipher = createDecipher(config); + } + } + + let ciphered; + let deciphered; + let cipher; + let decipher; + let macSize; + let packet; + let payload; + let cipherInfo; + let config; + + console.log('Testing cipher: %s, mac: %s (%s encrypt, %s decrypt) ...', + testConfig.cipher, + testConfig.mac + || (testConfig.cipher === null ? '' : ''), + pair[0], + pair[1]); + + if (testConfig.cipher === null) { + cipher = new NullCipher(1, onCipherData); + decipher = new NullDecipher(1, onDecipherPayload); + macSize = 0; + } else { + cipherInfo = CIPHER_INFO[testConfig.cipher]; + let macInfo; + let macKey; + if (testConfig.mac) { + macInfo = MAC_INFO[testConfig.mac]; + macKey = randomBytes(macInfo.len); + macSize = macInfo.actualLen; + } else if (cipherInfo.authLen) { + macSize = cipherInfo.authLen; + } else { + throw new Error('Missing MAC for cipher'); + } + const key = randomBytes(cipherInfo.keyLen); + const iv = (cipherInfo.ivLen + ? randomBytes(cipherInfo.ivLen) + : Buffer.alloc(0)); + config = { + outbound: { + onWrite: onCipherData, + cipherInfo, + cipherKey: Buffer.from(key), + cipherIV: Buffer.from(iv), + seqno: 1, + macInfo, + macKey: (macKey && Buffer.from(macKey)), + forceNative: (pair[0] === 'native'), + }, + inbound: { + onPayload: onDecipherPayload, + decipherInfo: cipherInfo, + decipherKey: Buffer.from(key), + decipherIV: Buffer.from(iv), + seqno: 1, + macInfo, + macKey: (macKey && Buffer.from(macKey)), + forceNative: (pair[1] === 'native'), + }, + }; + try { + cipher = createCipher(config); + } catch (ex) { + if (ex.code === 'ERR_OSSL_EVP_UNSUPPORTED' + || /unsupported/i.test(ex.message)) { + console.log( + ' ... skipping because cipher is unsupported by OpenSSL' + ); + continue; + } + throw ex; + } + try { + decipher = createDecipher(config); + } catch (ex) { + if (ex.code === 'ERR_OSSL_EVP_UNSUPPORTED' + || /unsupported/i.test(ex.message)) { + console.log( + ' ... skipping because cipher is unsupported by OpenSSL' + ); + continue; + } + throw ex; + } + + if (pair[0] === 'binding') + assert(/binding/i.test(cipher.constructor.name)); + else + assert(/native/i.test(cipher.constructor.name)); + if (pair[1] === 'binding') + assert(/binding/i.test(decipher.constructor.name)); + else + assert(/native/i.test(decipher.constructor.name)); + } + + let expectedSeqno; + // Test zero-length payload ============================================ + payload = Buffer.alloc(0); + expectedSeqno = 2; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual(decipher.decrypt(ciphered, 0, ciphered.length), + undefined); + + assert.strictEqual(cipher.outSeqno, expectedSeqno); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test single byte payload ============================================ + payload = Buffer.from([ 0xEF ]); + expectedSeqno = 3; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual(decipher.decrypt(ciphered, 0, ciphered.length), + undefined); + + assert.strictEqual(cipher.outSeqno, 3); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test large payload ================================================== + payload = randomBytes(32 * 1024); + expectedSeqno = 4; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual(decipher.decrypt(ciphered, 0, ciphered.length), + undefined); + + assert.strictEqual(cipher.outSeqno, expectedSeqno); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test sequnce number rollover ======================================== + payload = randomBytes(4); + expectedSeqno = 0; + cipher.outSeqno = decipher.inSeqno = (2 ** 32) - 1; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual(decipher.decrypt(ciphered, 0, ciphered.length), + undefined); + + assert.strictEqual(cipher.outSeqno, expectedSeqno); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test chunked input -- split length bytes ============================ + payload = randomBytes(32 * 768); + expectedSeqno = 1; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual(decipher.decrypt(ciphered, 0, 2), undefined); + assert.strictEqual(decipher.decrypt(ciphered, 2, ciphered.length), + undefined); + + assert.strictEqual(cipher.outSeqno, expectedSeqno); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test chunked input -- split length from payload ===================== + payload = randomBytes(32 * 768); + expectedSeqno = 2; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual(decipher.decrypt(ciphered, 0, 4), undefined); + assert.strictEqual(decipher.decrypt(ciphered, 4, ciphered.length), + undefined); + + assert.strictEqual(cipher.outSeqno, expectedSeqno); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test chunked input -- split length and payload from MAC ============= + payload = randomBytes(32 * 768); + expectedSeqno = 3; + + reset(); + packet = cipher.allocPacket(payload.length); + payload.copy(packet, 5); + cipher.encrypt(packet); + assert.strictEqual( + decipher.decrypt(ciphered, 0, ciphered.length - macSize), + undefined + ); + assert.strictEqual( + decipher.decrypt(ciphered, + ciphered.length - macSize, + ciphered.length), + undefined + ); + + assert.strictEqual(cipher.outSeqno, expectedSeqno); + assert(ciphered.length >= 9 + macSize); + assert.strictEqual(decipher.inSeqno, cipher.outSeqno); + assert.strictEqual(deciphered.length, 1); + assert.deepStrictEqual(deciphered[0], payload); + + // Test packet length checks =========================================== + [0, 2 ** 32 - 1].forEach((n) => { + reset(); + packet = cipher.allocPacket(0); + packet.writeUInt32BE(n, 0); // Overwrite packet length field + cipher.encrypt(packet); + let threw = false; + try { + decipher.decrypt(ciphered, 0, ciphered.length); + } catch (ex) { + threw = true; + assert(ex instanceof Error); + assert(/packet length/i.test(ex.message)); + } + if (!threw) + throw new Error('Expected error'); + + // Recreate deciphers since errors leave them in an unusable state. + // We recreate the ciphers as well so that internal states of both + // ends match again. + reinit(); + }); + + // Test minimum padding length check =================================== + if (testConfig.cipher !== null) { + let payloadLen; + const blockLen = cipherInfo.blockLen; + if (/chacha|gcm/i.test(testConfig.cipher) + || /etm/i.test(testConfig.mac)) { + payloadLen = blockLen - 2; + } else { + payloadLen = blockLen - 6; + } + const minLen = 4 + 1 + payloadLen + (blockLen + 1); + // We don't do strict equality checks here since the length of the + // returned Buffer can vary due to implementation details. + assert(cipher.allocPacket(payloadLen).length >= minLen); + } + + // ===================================================================== + cipher.free(); + decipher.free(); + if (testConfig.cipher === null) + break; + } + }); + } + + // Test createCipher()/createDecipher() exceptions + { + [ + [ + [true, null], + /invalid config/i + ], + [ + [{}], + [/invalid outbound/i, /invalid inbound/i] + ], + [ + [{ outbound: {}, inbound: {} }], + [/invalid outbound\.onWrite/i, /invalid inbound\.onPayload/i] + ], + [ + [ + { outbound: { + onWrite: () => {}, + cipherInfo: true + }, + inbound: { + onPayload: () => {}, + decipherInfo: true + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: null + }, + inbound: { + onPayload: () => {}, + decipherInfo: null + }, + }, + ], + [/invalid outbound\.cipherInfo/i, /invalid inbound\.decipherInfo/i] + ], + [ + [ + { outbound: { + onWrite: () => {}, + cipherInfo: {}, + cipherKey: {}, + }, + inbound: { + onPayload: () => {}, + decipherInfo: {}, + decipherKey: {}, + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 32 }, + cipherKey: Buffer.alloc(8), + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 32 }, + decipherKey: Buffer.alloc(8), + }, + }, + ], + [/invalid outbound\.cipherKey/i, /invalid inbound\.decipherKey/i] + ], + [ + [ + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 12 }, + cipherKey: Buffer.alloc(1), + cipherIV: true + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 12 }, + decipherKey: Buffer.alloc(1), + cipherIV: true + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 12 }, + cipherKey: Buffer.alloc(1), + cipherIV: null + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 12 }, + decipherKey: Buffer.alloc(1), + cipherIV: null + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 12 }, + cipherKey: Buffer.alloc(1), + cipherIV: {} + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 12 }, + decipherKey: Buffer.alloc(1), + cipherIV: {} + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 12 }, + cipherKey: Buffer.alloc(1), + cipherIV: Buffer.alloc(1) + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 12 }, + decipherKey: Buffer.alloc(1), + cipherIV: Buffer.alloc(1) + }, + }, + ], + [/invalid outbound\.cipherIV/i, /invalid inbound\.decipherIV/i] + ], + [ + [ + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0 }, + cipherKey: Buffer.alloc(1), + seqno: true + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0 }, + decipherKey: Buffer.alloc(1), + seqno: true + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0 }, + cipherKey: Buffer.alloc(1), + seqno: -1 + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0 }, + decipherKey: Buffer.alloc(1), + seqno: -1 + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0 }, + cipherKey: Buffer.alloc(1), + seqno: 2 ** 32 + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0 }, + decipherKey: Buffer.alloc(1), + seqno: 2 ** 32 + }, + }, + ], + [/invalid outbound\.seqno/i, /invalid inbound\.seqno/i] + ], + [ + [ + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0 + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0 + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: true + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: true + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: null + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: null + }, + }, + ], + [/invalid outbound\.macInfo/i, /invalid inbound\.macInfo/i] + ], + [ + [ + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 } + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 } + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 }, + macKey: true + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 }, + macKey: true + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 }, + macKey: null + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 }, + macKey: null + }, + }, + { outbound: { + onWrite: () => {}, + cipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + cipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 }, + macKey: Buffer.alloc(1) + }, + inbound: { + onPayload: () => {}, + decipherInfo: { keyLen: 1, ivLen: 0, sslName: 'foo' }, + decipherKey: Buffer.alloc(1), + seqno: 0, + macInfo: { keyLen: 16 }, + macKey: Buffer.alloc(1) + }, + }, + ], + [/invalid outbound\.macKey/i, /invalid inbound\.macKey/i] + ], + ].forEach((testCase) => { + let errorChecks = testCase[1]; + if (!Array.isArray(errorChecks)) + errorChecks = [errorChecks[0], errorChecks[0]]; + for (const input of testCase[0]) { + assert.throws(() => createCipher(input), errorChecks[0]); + assert.throws(() => createDecipher(input), errorChecks[1]); + } + }); + } +})(); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-keyparser.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-keyparser.js new file mode 100644 index 0000000..b919bb8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-protocol-keyparser.js @@ -0,0 +1,177 @@ +'use strict'; + +const assert = require('assert'); +const { readdirSync, readFileSync } = require('fs'); +const { inspect } = require('util'); + +const { parseKey } = require('../lib/protocol/keyParser.js'); + +const { EDDSA_SUPPORTED } = require('../lib/protocol/constants.js'); + +const BASE_PATH = `${__dirname}/fixtures/keyParser`; + +function failMsg(name, message, exit) { + const msg = `[${name}] ${message}`; + if (!exit) + return msg; + console.error(msg); + process.exit(1); +} + +readdirSync(BASE_PATH).forEach((name) => { + if (/\.result$/i.test(name)) + return; + if (/ed25519/i.test(name) && !EDDSA_SUPPORTED) + return; + + const isPublic = /\.pub$/i.test(name); + const isEncrypted = /_enc/i.test(name); + const isPPK = /^ppk_/i.test(name); + const key = readFileSync(`${BASE_PATH}/${name}`); + let res; + if (isEncrypted) + res = parseKey(key, (isPPK ? 'node.js' : 'password')); + else + res = parseKey(key); + let expected = JSON.parse( + readFileSync(`${BASE_PATH}/${name}.result`, 'utf8') + ); + if (typeof expected === 'string') { + if (!(res instanceof Error)) + failMsg(name, `Expected error: ${expected}`, true); + assert.strictEqual( + expected, + res.message, + failMsg(name, + 'Error message mismatch.\n' + + `Expected: ${inspect(expected)}\n` + + `Received: ${inspect(res.message)}`) + ); + } else if (res instanceof Error) { + failMsg(name, `Unexpected error: ${res.stack}`, true); + } else { + if (Array.isArray(expected) && !Array.isArray(res)) + failMsg(name, 'Expected array but did not receive one', true); + if (!Array.isArray(expected) && Array.isArray(res)) + failMsg(name, 'Received array but did not expect one', true); + + if (!Array.isArray(res)) { + res = [res]; + expected = [expected]; + } else if (res.length !== expected.length) { + failMsg(name, + `Expected ${expected.length} keys, but received ${res.length}`, + true); + } + + res.forEach((curKey, i) => { + const details = { + type: curKey.type, + comment: curKey.comment, + public: curKey.getPublicPEM(), + publicSSH: curKey.getPublicSSH() + && curKey.getPublicSSH().toString('base64'), + private: curKey.getPrivatePEM() + }; + assert.deepStrictEqual( + details, + expected[i], + failMsg(name, + 'Parser output mismatch.\n' + + `Expected: ${inspect(expected[i])}\n\n` + + `Received: ${inspect(details)}`) + ); + }); + + // Test `equals()` + let copy; + if (isEncrypted) + copy = parseKey(key, (isPPK ? 'node.js' : 'password')); + else + copy = parseKey(key); + if (!Array.isArray(copy)) + copy = [copy]; + for (let i = 0; i < res.length; ++i) { + assert.strictEqual( + res[i].equals(copy[i]), + true, + failMsg(name, 'equals() failed with copy') + ); + } + } + + if (isEncrypted && !isPublic) { + // Make sure parsing encrypted keys without a passphrase results in an + // appropriate error + const err = parseKey(key); + if (!(err instanceof Error)) + failMsg(name, 'Expected error during parse without passphrase', true); + if (!/no passphrase/i.test(err.message)) { + failMsg(name, + `Error during parse without passphrase: ${err.message}`, + true); + } + + // Make sure parsing encrypted keys with an incorrect passphrase results in + // an appropriate error + const errIncPass = parseKey(key, 'incorrectPassphrase'); + if (!(errIncPass instanceof Error)) { + failMsg(name, + 'Expected error during parse with an incorrect passphrase', + true); + } + if (!/bad passphrase\?|unable to authenticate data/i + .test(errIncPass.message)) { + failMsg(name, + 'Error during parse with an incorrect passphrase: ' + + errIncPass.message, + true); + } + } + + if (!isPublic) { + // Try signing and verifying to make sure the private/public key PEMs are + // correct + const data = Buffer.from('hello world'); + res.forEach((curKey) => { + let result = curKey.sign(data); + if (result instanceof Error) { + failMsg(name, + `Error while signing data with key: ${result.message}`, + true); + } + result = curKey.verify(data, result); + if (result instanceof Error) { + failMsg(name, + `Error while verifying signed data with key: ${result.message}`, + true); + } + if (!result) + failMsg(name, 'Failed to verify signed data with key', true); + }); + if (res.length === 1 && !isPPK) { + const pubFile = readFileSync(`${BASE_PATH}/${name}.pub`); + const pubParsed = parseKey(pubFile); + if (!(pubParsed instanceof Error)) { + let result = res[0].sign(data); + if (result instanceof Error) { + failMsg(name, + `Error while signing data with key: ${result.message}`, + true); + } + result = pubParsed.verify(data, result); + if (result instanceof Error) { + failMsg(name, + 'Error while verifying signed data with separate public key: ' + + result.message, + true); + } + if (!result) { + failMsg(name, + 'Failed to verify signed data with separate public key', + true); + } + } + } + } +}); diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-server-hostkeys.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-server-hostkeys.js new file mode 100644 index 0000000..34bbcda --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-server-hostkeys.js @@ -0,0 +1,138 @@ +'use strict'; + +const assert = require('assert'); + +const { + fixtureKey, + mustCall, + setup, +} = require('./common.js'); + +const debug = false; + +[ + { desc: 'RSA user key (old OpenSSH)', + hostKey: fixtureKey('id_rsa') }, + { desc: 'RSA user key (new OpenSSH)', + hostKey: fixtureKey('openssh_new_rsa') }, + { desc: 'DSA host key', + hostKey: fixtureKey('ssh_host_dsa_key') }, + { desc: 'ECDSA host key', + hostKey: fixtureKey('ssh_host_ecdsa_key') }, + { desc: 'PPK', + hostKey: fixtureKey('id_rsa.ppk') }, +].forEach((test) => { + const { desc, hostKey } = test; + const clientKey = fixtureKey('openssh_new_rsa'); + const username = 'KeyUser'; + const { server } = setup( + desc, + { + client: { + username, + privateKey: clientKey.raw, + algorithms: { + serverHostKey: [ hostKey.key.type ], + } + }, + server: { hostKeys: [ hostKey.raw ] }, + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 3: + assert(ctx.signature, 'Missing publickey signature'); + // FALLTHROUGH + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + } + ctx.accept(); + }, 3)).on('ready', mustCall(() => { + conn.end(); + })); + })); +}); + + +{ + const RSA_KEY = fixtureKey('ssh_host_rsa_key'); + const ECDSA_KEY = fixtureKey('ssh_host_ecdsa_key'); + [ RSA_KEY, ECDSA_KEY ].forEach((key) => { + const selKeyType = key.key.type; + const clientKey = fixtureKey('openssh_new_rsa'); + const username = 'KeyUser'; + const { client, server } = setup( + `Multiple host key types (${key.type} selected)`, + { + client: { + username, + privateKey: clientKey.raw, + algorithms: { + serverHostKey: [ selKeyType ], + } + }, + server: { hostKeys: [ RSA_KEY.raw, ECDSA_KEY.raw ] }, + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 3: + assert(ctx.signature, 'Missing publickey signature'); + // FALLTHROUGH + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + } + ctx.accept(); + }, 3)).on('ready', mustCall(() => { + conn.end(); + })); + })); + client.on('handshake', mustCall((info) => { + assert(info.serverHostKey === selKeyType, 'Wrong host key selected'); + })); + }); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-sftp.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-sftp.js new file mode 100644 index 0000000..595e509 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-sftp.js @@ -0,0 +1,842 @@ +'use strict'; + +const assert = require('assert'); +const { constants } = require('fs'); + +const { + fixture, + mustCall, + mustCallAtLeast, + mustNotCall, + setup: setup_, + setupSimple +} = require('./common.js'); + +const { OPEN_MODE, Stats, STATUS_CODE } = require('../lib/protocol/SFTP.js'); + +const DEBUG = false; + +setup('open', mustCall((client, server) => { + const path_ = '/tmp/foo.txt'; + const handle_ = Buffer.from('node.js'); + const pflags_ = (OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.WRITE); + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert(pflags === pflags_, `Wrong flags: ${flagsToHuman(pflags)}`); + server.handle(id, handle_); + server.end(); + })); + client.open(path_, 'w', mustCall((err, handle) => { + assert(!err, `Unexpected open() error: ${err}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + })); +})); + +setup('close', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + server.on('CLOSE', mustCall((id, handle) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.close(handle_, mustCall((err) => { + assert(!err, `Unexpected close() error: ${err}`); + })); +})); + +setup('read', mustCall((client, server) => { + const expected = Buffer.from('node.jsnode.jsnode.jsnode.jsnode.jsnode.js'); + const handle_ = Buffer.from('node.js'); + const buf = Buffer.alloc(expected.length); + server.on('READ', mustCall((id, handle, offset, len) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert(offset === 5, `Wrong read offset: ${offset}`); + assert(len === buf.length, `Wrong read len: ${len}`); + server.data(id, expected); + server.end(); + })); + client.read(handle_, buf, 0, buf.length, 5, mustCall((err, nb) => { + assert(!err, `Unexpected read() error: ${err}`); + assert.deepStrictEqual(buf, expected, 'read data mismatch'); + })); +})); + +setup('read (partial)', mustCall((client, server) => { + const expected = Buffer.from('blargh'); + const handle_ = Buffer.from('node.js'); + const buf = Buffer.alloc(256); + server.on('READ', mustCall((id, handle, offset, len) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert(offset === 0, `Wrong read offset: ${offset}`); + assert(len === buf.length, `Wrong read len: ${len}`); + server.data(id, expected); + server.end(); + })); + client.read(handle_, buf, 0, buf.length, 0, mustCall((err, nb, data) => { + assert(!err, `Unexpected read() error: ${err}`); + assert.strictEqual(nb, expected.length, 'nb count mismatch'); + assert.deepStrictEqual( + buf.slice(0, expected.length), + expected, + 'read data mismatch' + ); + assert.deepStrictEqual(data, expected, 'read data mismatch'); + })); +})); + +setup('read (overflow)', mustCall((client, server) => { + const maxChunk = client._maxReadLen; + const expected = Buffer.alloc(3 * maxChunk, 'Q'); + const handle_ = Buffer.from('node.js'); + const buf = Buffer.alloc(expected.length, 0); + let reqs = 0; + server.on('READ', mustCall((id, handle, offset, len) => { + ++reqs; + assert.strictEqual(id, reqs - 1, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert.strictEqual(offset, + (reqs - 1) * maxChunk, + `Wrong read offset: ${offset}`); + server.data(id, expected.slice(offset, offset + len)); + if (reqs === 3) + server.end(); + }, 3)); + client.read(handle_, buf, 0, buf.length, 0, mustCall((err, nb) => { + assert(!err, `Unexpected read() error: ${err}`); + assert.deepStrictEqual(buf, expected); + assert.strictEqual(nb, buf.length, 'read nb mismatch'); + })); +})); + +setup('write', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + const buf = Buffer.from('node.jsnode.jsnode.jsnode.jsnode.jsnode.js'); + server.on('WRITE', mustCall((id, handle, offset, data) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert(offset === 5, `Wrong write offset: ${offset}`); + assert.deepStrictEqual(data, buf, 'write data mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.write(handle_, buf, 0, buf.length, 5, mustCall((err, nb) => { + assert(!err, `Unexpected write() error: ${err}`); + assert.strictEqual(nb, buf.length, 'wrong bytes written'); + })); +})); + +setup('write (overflow)', mustCall((client, server) => { + const maxChunk = client._maxWriteLen; + const handle_ = Buffer.from('node.js'); + const buf = Buffer.allocUnsafe(3 * maxChunk); + let reqs = 0; + server.on('WRITE', mustCall((id, handle, offset, data) => { + ++reqs; + assert.strictEqual(id, reqs - 1, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert.strictEqual(offset, + (reqs - 1) * maxChunk, + `Wrong write offset: ${offset}`); + assert((offset + data.length) <= buf.length, 'bad offset'); + assert.deepStrictEqual(data, + buf.slice(offset, offset + data.length), + 'write data mismatch'); + server.status(id, STATUS_CODE.OK); + if (reqs === 3) + server.end(); + }, 3)); + client.write(handle_, buf, 0, buf.length, 0, mustCall((err, nb) => { + assert(!err, `Unexpected write() error: ${err}`); + assert.strictEqual(nb, buf.length, 'wrote bytes written'); + })); +})); + +setup('lstat', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const attrs_ = new Stats({ + size: 10 * 1024, + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.on('LSTAT', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.attrs(id, attrs_); + server.end(); + })); + client.lstat(path_, mustCall((err, attrs) => { + assert(!err, `Unexpected lstat() error: ${err}`); + assert.deepStrictEqual(attrs, attrs_, 'attrs mismatch'); + })); +})); + +setup('fstat', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + const attrs_ = new Stats({ + size: 10 * 1024, + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.on('FSTAT', mustCall((id, handle) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.attrs(id, attrs_); + server.end(); + })); + client.fstat(handle_, mustCall((err, attrs) => { + assert(!err, `Unexpected fstat() error: ${err}`); + assert.deepStrictEqual(attrs, attrs_, 'attrs mismatch'); + })); +})); + +setup('setstat', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const attrs_ = new Stats({ + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.on('SETSTAT', mustCall((id, path, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert.deepStrictEqual(attrs, attrs_, 'attrs mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.setstat(path_, attrs_, mustCall((err) => { + assert(!err, `Unexpected setstat() error: ${err}`); + })); +})); + +setup('fsetstat', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + const attrs_ = new Stats({ + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.on('FSETSTAT', mustCall((id, handle, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert.deepStrictEqual(attrs, attrs_, 'attrs mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.fsetstat(handle_, attrs_, mustCall((err) => { + assert(!err, `Unexpected fsetstat() error: ${err}`); + })); +})); + +setup('opendir', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + const path_ = '/tmp'; + server.on('OPENDIR', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.handle(id, handle_); + server.end(); + })); + client.opendir(path_, mustCall((err, handle) => { + assert(!err, `Unexpected opendir() error: ${err}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + })); +})); + +setup('readdir', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + const list_ = [ + { filename: '.', + longname: 'drwxr-xr-x 56 nodejs nodejs 4096 Nov 10 01:05 .', + attrs: new Stats({ + mode: 0o755 | constants.S_IFDIR, + size: 4096, + uid: 9001, + gid: 8001, + atime: 1415599549, + mtime: 1415599590 + }) + }, + { filename: '..', + longname: 'drwxr-xr-x 4 root root 4096 May 16 2013 ..', + attrs: new Stats({ + mode: 0o755 | constants.S_IFDIR, + size: 4096, + uid: 0, + gid: 0, + atime: 1368729954, + mtime: 1368729999 + }) + }, + { filename: 'foo', + longname: 'drwxrwxrwx 2 nodejs nodejs 4096 Mar 8 2009 foo', + attrs: new Stats({ + mode: 0o777 | constants.S_IFDIR, + size: 4096, + uid: 9001, + gid: 8001, + atime: 1368729954, + mtime: 1368729999 + }) + }, + { filename: 'bar', + longname: '-rw-r--r-- 1 nodejs nodejs 513901992 Dec 4 2009 bar', + attrs: new Stats({ + mode: 0o644 | constants.S_IFREG, + size: 513901992, + uid: 9001, + gid: 8001, + atime: 1259972199, + mtime: 1259972199 + }) + } + ]; + server.on('READDIR', mustCall((id, handle) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.name(id, list_); + server.end(); + })); + client.readdir(handle_, mustCall((err, list) => { + assert(!err, `Unexpected readdir() error: ${err}`); + assert.deepStrictEqual(list, + list_.slice(2), + 'dir list mismatch'); + })); +})); + +setup('readdir (full)', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + const list_ = [ + { filename: '.', + longname: 'drwxr-xr-x 56 nodejs nodejs 4096 Nov 10 01:05 .', + attrs: new Stats({ + mode: 0o755 | constants.S_IFDIR, + size: 4096, + uid: 9001, + gid: 8001, + atime: 1415599549, + mtime: 1415599590 + }) + }, + { filename: '..', + longname: 'drwxr-xr-x 4 root root 4096 May 16 2013 ..', + attrs: new Stats({ + mode: 0o755 | constants.S_IFDIR, + size: 4096, + uid: 0, + gid: 0, + atime: 1368729954, + mtime: 1368729999 + }) + }, + { filename: 'foo', + longname: 'drwxrwxrwx 2 nodejs nodejs 4096 Mar 8 2009 foo', + attrs: new Stats({ + mode: 0o777 | constants.S_IFDIR, + size: 4096, + uid: 9001, + gid: 8001, + atime: 1368729954, + mtime: 1368729999 + }) + }, + { filename: 'bar', + longname: '-rw-r--r-- 1 nodejs nodejs 513901992 Dec 4 2009 bar', + attrs: new Stats({ + mode: 0o644 | constants.S_IFREG, + size: 513901992, + uid: 9001, + gid: 8001, + atime: 1259972199, + mtime: 1259972199 + }) + } + ]; + server.on('READDIR', mustCall((id, handle) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.name(id, list_); + server.end(); + })); + client.readdir(handle_, { full: true }, mustCall((err, list) => { + assert(!err, `Unexpected readdir() error: ${err}`); + assert.deepStrictEqual(list, list_, 'dir list mismatch'); + })); +})); + +setup('readdir (EOF)', mustCall((client, server) => { + const handle_ = Buffer.from('node.js'); + server.on('READDIR', mustCall((id, handle) => { + assert(id === 0, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.status(id, STATUS_CODE.EOF); + server.end(); + })); + client.readdir(handle_, mustCall((err, list) => { + assert(err && err.code === STATUS_CODE.EOF, + `Expected EOF, got: ${err}`); + })); +})); + +setup('unlink', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + server.on('REMOVE', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.unlink(path_, mustCall((err) => { + assert(!err, `Unexpected unlink() error: ${err}`); + })); +})); + +setup('mkdir', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + server.on('MKDIR', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.mkdir(path_, mustCall((err) => { + assert(!err, `Unexpected mkdir() error: ${err}`); + })); +})); + +setup('rmdir', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + server.on('RMDIR', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.rmdir(path_, mustCall((err) => { + assert(!err, `Unexpected rmdir() error: ${err}`); + })); +})); + +setup('realpath', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const name_ = { filename: '/tmp/foo' }; + server.on('REALPATH', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.name(id, name_); + server.end(); + })); + client.realpath(path_, mustCall((err, name) => { + assert(!err, `Unexpected realpath() error: ${err}`); + assert.deepStrictEqual(name, name_.filename, 'name mismatch'); + })); +})); + +setup('stat', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const attrs_ = new Stats({ + mode: 0o644 | constants.S_IFREG, + size: 10 * 1024, + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.on('STAT', mustCall((id, path) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + server.attrs(id, attrs_); + server.end(); + })); + client.stat(path_, mustCall((err, attrs) => { + assert(!err, `Unexpected stat() error: ${err}`); + assert.deepStrictEqual(attrs, attrs_, 'attrs mismatch'); + const expectedTypes = { + isDirectory: false, + isFile: true, + isBlockDevice: false, + isCharacterDevice: false, + isSymbolicLink: false, + isFIFO: false, + isSocket: false + }; + for (const [fn, expect] of Object.entries(expectedTypes)) + assert(attrs[fn]() === expect, `attrs.${fn}() failed`); + })); +})); + +setup('rename', mustCall((client, server) => { + const oldPath_ = '/foo/bar/baz'; + const newPath_ = '/tmp/foo'; + server.on('RENAME', mustCall((id, oldPath, newPath) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(oldPath === oldPath_, `Wrong old path: ${oldPath}`); + assert(newPath === newPath_, `Wrong new path: ${newPath}`); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.rename(oldPath_, newPath_, mustCall((err) => { + assert(!err, `Unexpected rename() error: ${err}`); + })); +})); + +setup('readlink', mustCall((client, server) => { + const linkPath_ = '/foo/bar/baz'; + const name = { filename: '/tmp/foo' }; + server.on('READLINK', mustCall((id, linkPath) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(linkPath === linkPath_, `Wrong link path: ${linkPath}`); + server.name(id, name); + server.end(); + })); + client.readlink(linkPath_, mustCall((err, targetPath) => { + assert(!err, `Unexpected readlink() error: ${err}`); + assert(targetPath === name.filename, + `Wrong target path: ${targetPath}`); + })); +})); + +setup('symlink', mustCall((client, server) => { + const linkPath_ = '/foo/bar/baz'; + const targetPath_ = '/tmp/foo'; + server.on('SYMLINK', mustCall((id, linkPath, targetPath) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(linkPath === linkPath_, `Wrong link path: ${linkPath}`); + assert(targetPath === targetPath_, `Wrong target path: ${targetPath}`); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.symlink(targetPath_, linkPath_, mustCall((err) => { + assert(!err, `Unexpected symlink() error: ${err}`); + })); +})); + +setup('readFile', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const handle_ = Buffer.from('hi mom!'); + const data_ = Buffer.from('hello world'); + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert(pflags === OPEN_MODE.READ, `Wrong flags: ${flagsToHuman(pflags)}`); + server.handle(id, handle_); + })).on('FSTAT', mustCall((id, handle) => { + assert(id === 1, `Wrong request id: ${id}`); + const attrs = new Stats({ + size: data_.length, + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.attrs(id, attrs); + })).on('READ', mustCall((id, handle, offset, len) => { + assert(id === 2, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert(offset === 0, `Wrong read offset: ${offset}`); + server.data(id, data_); + })).on('CLOSE', mustCall((id, handle) => { + assert(id === 3, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.readFile(path_, mustCall((err, buf) => { + assert(!err, `Unexpected error: ${err}`); + assert.deepStrictEqual(buf, data_, 'data mismatch'); + })); +})); + +setup('readFile (no size from fstat)', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const handle_ = Buffer.from('hi mom!'); + const data_ = Buffer.from('hello world'); + let reads = 0; + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert(pflags === OPEN_MODE.READ, `Wrong flags: ${flagsToHuman(pflags)}`); + server.handle(id, handle_); + })).on('FSTAT', mustCall((id, handle) => { + assert(id === 1, `Wrong request id: ${id}`); + const attrs = new Stats({ + uid: 9001, + gid: 9001, + atime: (Date.now() / 1000) | 0, + mtime: (Date.now() / 1000) | 0 + }); + server.attrs(id, attrs); + })).on('READ', mustCall((id, handle, offset, len) => { + assert(++reads + 1 === id, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + switch (id) { + case 2: + assert(offset === 0, `Wrong read offset for first read: ${offset}`); + server.data(id, data_); + break; + case 3: + assert(offset === data_.length, + `Wrong read offset for second read: ${offset}`); + server.status(id, STATUS_CODE.EOF); + break; + } + }, 2)).on('CLOSE', mustCall((id, handle) => { + assert(id === 4, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + client.readFile(path_, mustCall((err, buf) => { + assert(!err, `Unexpected error: ${err}`); + assert.deepStrictEqual(buf, data_, 'data mismatch'); + })); +})); + +setup('ReadStream', mustCall((client, server) => { + let reads = 0; + const path_ = '/foo/bar/baz'; + const handle_ = Buffer.from('hi mom!'); + const data_ = Buffer.from('hello world'); + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert(pflags === OPEN_MODE.READ, `Wrong flags: ${flagsToHuman(pflags)}`); + server.handle(id, handle_); + })).on('READ', mustCall((id, handle, offset, len) => { + assert(id === ++reads, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + if (reads === 1) { + assert(offset === 0, `Wrong read offset: ${offset}`); + server.data(id, data_); + } else { + server.status(id, STATUS_CODE.EOF); + } + }, 2)).on('CLOSE', mustCall((id, handle) => { + assert(id === 3, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + let buf = []; + client.createReadStream(path_).on('readable', mustCallAtLeast(function() { + let chunk; + while ((chunk = this.read()) !== null) + buf.push(chunk); + })).on('end', mustCall(() => { + buf = Buffer.concat(buf); + assert.deepStrictEqual(buf, data_, 'data mismatch'); + })); +})); + +setup('ReadStream (fewer bytes than requested)', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + const handle_ = Buffer.from('hi mom!'); + const data_ = Buffer.from('hello world'); + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + server.handle(id, handle_); + })).on('READ', mustCallAtLeast((id, handle, offset, len) => { + if (offset > data_.length) { + server.status(id, STATUS_CODE.EOF); + } else { + // Only read 4 bytes at a time + server.data(id, data_.slice(offset, offset + 4)); + } + })).on('CLOSE', mustCall((id, handle) => { + server.status(id, STATUS_CODE.OK); + server.end(); + })); + let buf = []; + client.createReadStream(path_).on('readable', mustCallAtLeast(function() { + let chunk; + while ((chunk = this.read()) !== null) + buf.push(chunk); + })).on('end', mustCall(() => { + buf = Buffer.concat(buf); + assert.deepStrictEqual(buf, data_, 'data mismatch'); + })); +})); + +setup('ReadStream (error)', mustCall((client, server) => { + const path_ = '/foo/bar/baz'; + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert(pflags === OPEN_MODE.READ, `Wrong flags: ${flagsToHuman(pflags)}`); + server.status(id, STATUS_CODE.NO_SUCH_FILE); + server.end(); + })); + client.createReadStream(path_).on('error', mustCall((err) => { + assert(err.code === STATUS_CODE.NO_SUCH_FILE); + })); +})); + +setup('WriteStream', mustCall((client, server) => { + let writes = 0; + const path_ = '/foo/bar/baz'; + const handle_ = Buffer.from('hi mom!'); + const data_ = Buffer.from('hello world'); + const pflags_ = OPEN_MODE.TRUNC | OPEN_MODE.CREAT | OPEN_MODE.WRITE; + server.on('OPEN', mustCall((id, path, pflags, attrs) => { + assert(id === 0, `Wrong request id: ${id}`); + assert(path === path_, `Wrong path: ${path}`); + assert(pflags === pflags_, `Wrong flags: ${flagsToHuman(pflags)}`); + server.handle(id, handle_); + })).on('FSETSTAT', mustCall((id, handle, attrs) => { + assert(id === 1, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert.strictEqual(attrs.mode, 0o666, 'Wrong file mode'); + server.status(id, STATUS_CODE.OK); + })).on('WRITE', mustCall((id, handle, offset, data) => { + assert(id === ++writes + 1, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + assert(offset === ((writes - 1) * data_.length), + `Wrong write offset: ${offset}`); + assert.deepStrictEqual(data, data_, 'Wrong data'); + server.status(id, STATUS_CODE.OK); + }, 3)).on('CLOSE', mustCall((id, handle) => { + assert(id === 5, `Wrong request id: ${id}`); + assert.deepStrictEqual(handle, handle_, 'handle mismatch'); + server.status(id, STATUS_CODE.OK); + server.end(); + })); + + const writer = client.createWriteStream(path_); + writer.cork && writer.cork(); + writer.write(data_); + writer.write(data_); + writer.write(data_); + writer.uncork && writer.uncork(); + writer.end(); +})); + +{ + const { client, server } = setup_( + 'SFTP server aborts with exit-status', + { + client: { username: 'foo', password: 'bar' }, + server: { hostKeys: [ fixture('ssh_host_rsa_key') ] }, + }, + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('sftp', mustCall((accept, reject) => { + const sftp = accept(); + + // XXX: hack + sftp._protocol.exitStatus(sftp.outgoing.id, 127); + sftp._protocol.channelClose(sftp.outgoing.id); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + const timeout = setTimeout(mustNotCall(), 1000); + client.sftp(mustCall((err, sftp) => { + clearTimeout(timeout); + assert(err, 'Expected error'); + assert(err.code === 127, `Expected exit code 127, saw: ${err.code}`); + client.end(); + })); + })); +} + +{ + const { client, server } = setup_( + 'SFTP client sets environment', + { + client: { username: 'foo', password: 'bar' }, + server: { hostKeys: [ fixture('ssh_host_rsa_key') ] }, + }, + ); + + const env = { SSH2NODETEST: 'foo' }; + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + ctx.accept(); + })).on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('env', mustCall((accept, reject, info) => { + accept && accept(); + assert(info.key === Object.keys(env)[0], 'Wrong env key'); + assert(info.val === Object.values(env)[0], 'Wrong env value'); + })).on('sftp', mustCall((accept, reject) => { + accept(); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + const timeout = setTimeout(mustNotCall(), 1000); + client.sftp(env, mustCall((err, sftp) => { + clearTimeout(timeout); + assert(!err, `Unexpected exec error: ${err}`); + client.end(); + })); + })); +} + +// ============================================================================= +function setup(title, cb) { + const { client, server } = setupSimple(DEBUG, title); + let clientSFTP; + let serverSFTP; + + const onSFTP = mustCall(() => { + if (clientSFTP && serverSFTP) + cb(clientSFTP, serverSFTP); + }, 2); + + client.on('ready', mustCall(() => { + client.sftp(mustCall((err, sftp) => { + assert(!err, `[${title}] Unexpected client sftp start error: ${err}`); + sftp.on('close', mustCall(() => { + client.end(); + })); + clientSFTP = sftp; + onSFTP(); + })); + })); + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + accept().on('sftp', mustCall((accept, reject) => { + const sftp = accept(); + sftp.on('close', mustCall(() => { + conn.end(); + })); + serverSFTP = sftp; + onSFTP(); + })); + })); + })); + })); +} + +function flagsToHuman(flags) { + const ret = []; + + for (const [name, value] of Object.entries(OPEN_MODE)) { + if (flags & value) + ret.push(name); + } + + return ret.join(' | '); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-shell.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-shell.js new file mode 100644 index 0000000..debba11 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-shell.js @@ -0,0 +1,109 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const { + mustCall, + mustCallAtLeast, + setupSimple, +} = require('./common.js'); + +const DEBUG = false; + +const setup = setupSimple.bind(undefined, DEBUG); + +{ + const { client, server } = setup('Simple shell()'); + + const OUTPUT = 'shell output!\n'; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + const session = accept(); + session.on('pty', mustCall((accept, reject, info) => { + accept(); + session.on('shell', mustCall((accept, reject) => { + let input = ''; + const stream = accept(); + stream.write(OUTPUT); + stream.on('data', mustCallAtLeast((data) => { + input += data; + if (input === 'exit\n') { + stream.end(); + conn.end(); + } + })); + })); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let output = ''; + client.on('close', mustCall(() => { + assert(output === OUTPUT, `Wrong shell output: ${inspect(output)}`); + })).shell(mustCall((err, stream) => { + assert(!err, `Unexpected shell error: ${err}`); + stream.write('exit\n'); + stream.on('data', mustCallAtLeast((d) => { + output += d; + })).on('close', mustCall(() => {})); + })); + })); +} + +{ + const { client, server } = setup('Shell with environment set'); + + const OUTPUT = 'shell output!\n'; + const clientEnv = { SSH2NODETEST: 'foo' }; + + server.on('connection', mustCall((conn) => { + conn.on('ready', mustCall(() => { + conn.on('session', mustCall((accept, reject) => { + let pty = false; + let env = false; + accept().on('pty', mustCall((accept, reject, info) => { + accept(); + pty = true; + })).on('env', mustCall((accept, reject, info) => { + accept && accept(); + env = true; + assert(info.key === Object.keys(clientEnv)[0], + `Wrong env key: ${inspect(info.key)}`); + assert(info.val === Object.values(clientEnv)[0], + `Wrong env value: ${inspect(info.val)}`); + })).on('shell', mustCall((accept, reject) => { + assert(pty, 'Expected pty before shell'); + assert(env, 'Expected env before shell'); + let input = ''; + const stream = accept(); + stream.write(OUTPUT); + stream.on('data', mustCallAtLeast((data) => { + input += data; + if (input === 'exit\n') { + stream.end(); + conn.end(); + } + })); + })); + })); + })); + })); + + client.on('ready', mustCall(() => { + let output = ''; + client.on('close', mustCall(() => { + assert(output === OUTPUT, `Wrong shell output: ${inspect(output)}`); + })).shell({ env: clientEnv }, mustCall((err, stream) => { + assert(!err, `Unexpected shell error: ${err}`); + stream.write('exit\n'); + stream.on('data', mustCallAtLeast((d) => { + output += d; + })).on('close', mustCall(() => {})); + })); + })); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent-openssh.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent-openssh.js new file mode 100644 index 0000000..cd6b224 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent-openssh.js @@ -0,0 +1,110 @@ +'use strict'; + +const assert = require('assert'); +const { spawnSync } = require('child_process'); + +const debug = false; +const SPAWN_OPTS = { windowsHide: true }; + +// TODO: figure out why this test is failing on Windows +if (process.platform === 'win32') { + console.log('Skipping ssh-agent test on Windows'); + process.exit(0); +} + +if (process.argv[2] === 'child') { + const { + fixtureKey, + mustCall, + setup, + } = require('./common.js'); + + const serverCfg = { hostKeys: [ fixtureKey('ssh_host_rsa_key').raw ] }; + + const clientKey = fixtureKey('openssh_new_rsa'); + + // Add key to the agent first + { + const { + error, status + } = spawnSync('ssh-add', [ clientKey.fullPath ], SPAWN_OPTS); + if (error || status !== 0) { + console.error('Failed to add key to agent'); + process.exit(1); + } + } + + const username = 'Agent User'; + const { server } = setup( + 'Agent authentication', + { + client: { username, agent: process.env.SSH_AUTH_SOCK }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 3: + assert(ctx.signature, 'Missing publickey signature'); + // FALLTHROUGH + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + } + ctx.accept(); + }, 3)).on('ready', mustCall(() => { + conn.end(); + })); + })); +} else { + { + const { + error, status + } = spawnSync('which', ['ssh-agent'], SPAWN_OPTS); + + if (error || status !== 0) { + console.log('No ssh-agent available, skipping agent test ...'); + process.exit(0); + } + } + + { + const { + error, status + } = spawnSync('which', ['ssh-add'], SPAWN_OPTS); + + if (error || status !== 0) { + console.log('No ssh-add available, skipping agent test ...'); + process.exit(0); + } + } + + const { + error, status + } = spawnSync('ssh-agent', + [ process.execPath, __filename, 'child' ], + { ...SPAWN_OPTS, stdio: 'inherit' }); + if (error || status !== 0) + throw new Error('Agent test failed'); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent.js new file mode 100644 index 0000000..73b64c3 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth-agent.js @@ -0,0 +1,171 @@ +'use strict'; + +const assert = require('assert'); + +const debug = false; + +const { + fixtureKey, + mustCall, + setup, +} = require('./common.js'); +const { + AgentProtocol, + BaseAgent, + utils: { parseKey }, +} = require('../lib/index.js'); + +const serverCfg = { hostKeys: [ fixtureKey('ssh_host_rsa_key').raw ] }; + +const clientKey = fixtureKey('openssh_new_rsa'); + +{ + let getIdentitiesCount = 0; + let signCount = 0; + class MyAgent extends BaseAgent { + getIdentities(cb) { + assert.strictEqual(++getIdentitiesCount, 1); + // Ensure that no private portion of the key is used by re-parsing the + // public version of the key + cb(null, [ parseKey(clientKey.key.getPublicSSH()) ]); + } + sign(pubKey, data, options, cb) { + assert.strictEqual(++signCount, 1); + assert.strictEqual(pubKey.getPublicPEM(), clientKey.key.getPublicPEM()); + const sig = clientKey.key.sign(data, options.hash); + cb(null, sig); + } + } + + const username = 'Agent User'; + const { server } = setup( + 'Custom agent authentication', + { + client: { username, agent: new MyAgent() }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 3: + assert(ctx.signature, 'Missing publickey signature'); + // FALLTHROUGH + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + } + ctx.accept(); + }, 3)).on('ready', mustCall(() => { + assert.strictEqual(getIdentitiesCount, 1); + assert.strictEqual(signCount, 1); + conn.end(); + })); + })); +} +{ + const client = new AgentProtocol(true); + const server = new AgentProtocol(false); + + server.on('identities', mustCall((req) => { + setImmediate(() => server.failureReply(req)); + })); + client.getIdentities(mustCall((err, keys) => { + assert(err, 'Missing expected error'); + })); + + client.pipe(server).pipe(client); +} +{ + const client = new AgentProtocol(true); + const server = new AgentProtocol(false); + + server.on('identities', mustCall((req) => { + const keys = [ clientKey.key ]; + server.getIdentitiesReply(req, keys); + })); + client.getIdentities(mustCall((err, keys) => { + assert(!err, 'Unexpected error'); + assert.strictEqual(keys.length, 1); + assert.strictEqual(keys[0].isPrivateKey(), false); + assert.strictEqual(keys[0].getPublicPEM(), clientKey.key.getPublicPEM()); + })); + + client.pipe(server).pipe(client); +} +{ + const client = new AgentProtocol(true); + const server = new AgentProtocol(false); + const buf = Buffer.from('data to sign'); + + server.on('sign', mustCall((req, pubKey, data, options) => { + assert.strictEqual(pubKey.getPublicPEM(), clientKey.key.getPublicPEM()); + assert.deepStrictEqual(data, buf); + assert.strictEqual(options.hash, undefined); + server.failureReply(req); + })); + client.sign(clientKey.key.getPublicSSH(), + buf, + mustCall((err, signature) => { + assert(err, 'Missing expected error'); + })); + + client.pipe(server).pipe(client); +} +{ + const client = new AgentProtocol(true); + const server = new AgentProtocol(false); + const buf = Buffer.from('data to sign'); + + server.on('sign', mustCall((req, pubKey, data, options) => { + assert.strictEqual(pubKey.getPublicPEM(), clientKey.key.getPublicPEM()); + assert.deepStrictEqual(data, buf); + assert.strictEqual(options.hash, undefined); + server.signReply(req, clientKey.key.sign(data)); + })); + client.sign(clientKey.key.getPublicSSH(), + buf, + mustCall((err, signature) => { + assert(!err, 'Unexpected error'); + const pubKey = parseKey(clientKey.key.getPublicSSH()); + assert.strictEqual(pubKey.verify(buf, signature), true); + })); + + client.pipe(server).pipe(client); +} +{ + // Test that outstanding requests are handled upon unexpected closure of the + // protocol stream + + const client = new AgentProtocol(true); + const server = new AgentProtocol(false); + + server.on('identities', mustCall((req) => { + server.destroy(); + })); + client.getIdentities(mustCall((err) => { + assert(err, 'Missing expected error'); + })); + + client.pipe(server).pipe(client); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth.js new file mode 100644 index 0000000..bbf5d8b --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-userauth.js @@ -0,0 +1,611 @@ +'use strict'; + +const assert = require('assert'); +const { inspect } = require('util'); + +const { + fixtureKey, + mustCall, + mustNotCall, + setup, +} = require('./common.js'); + +const serverCfg = { hostKeys: [ fixtureKey('ssh_host_rsa_key').raw ] }; + +const debug = false; + +// Keys ======================================================================== +[ + { desc: 'RSA (old OpenSSH)', + clientKey: fixtureKey('id_rsa') }, + { desc: 'RSA (new OpenSSH)', + clientKey: fixtureKey('openssh_new_rsa') }, + { desc: 'RSA (encrypted)', + clientKey: fixtureKey('id_rsa_enc', 'foobarbaz'), + passphrase: 'foobarbaz' }, + { desc: 'DSA', + clientKey: fixtureKey('id_dsa') }, + { desc: 'ECDSA', + clientKey: fixtureKey('id_ecdsa') }, + { desc: 'PPK', + clientKey: fixtureKey('id_rsa.ppk') }, +].forEach((test) => { + const { desc, clientKey, passphrase } = test; + const username = 'Key User'; + const { server } = setup( + desc, + { + client: { username, privateKey: clientKey.raw, passphrase }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 3: + assert(ctx.signature, 'Missing publickey signature'); + // FALLTHROUGH + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + break; + } + if (ctx.signature) { + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify publickey signature'); + } + ctx.accept(); + }, 3)).on('ready', mustCall(() => { + conn.end(); + })); + })); +}); + + +// Password ==================================================================== +{ + const username = 'Password User'; + const password = 'hi mom'; + const { server } = setup( + 'Password', + { + client: { username, password }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + if (++authAttempt === 1) { + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + } + assert(ctx.method === 'password', + `Wrong auth method: ${ctx.method}`); + assert(ctx.password === password, + `Wrong password: ${ctx.password}`); + ctx.accept(); + }, 2)).on('ready', mustCall(() => { + conn.end(); + })); + })); +} +{ + const username = ''; + const password = 'hi mom'; + const { server } = setup( + 'Password (empty username)', + { + client: { username, password }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + if (++authAttempt === 1) { + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + } + assert(ctx.method === 'password', + `Wrong auth method: ${ctx.method}`); + assert(ctx.password === password, + `Wrong password: ${ctx.password}`); + ctx.accept(); + }, 2)).on('ready', mustCall(() => { + conn.end(); + })); + })); +} +{ + const username = 'foo'; + const oldPassword = 'bar'; + const newPassword = 'baz'; + const changePrompt = 'Prithee changeth thy password'; + const { client, server } = setup( + 'Password (change requested)', + { + client: { username, password: oldPassword }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + if (++authAttempt === 1) { + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + } + assert(ctx.method === 'password', + `Wrong auth method: ${ctx.method}`); + assert(ctx.password === oldPassword, + `Wrong old password: ${ctx.password}`); + ctx.requestChange(changePrompt, mustCall((newPassword_) => { + assert(newPassword_ === newPassword, + `Wrong new password: ${newPassword_}`); + ctx.accept(); + })); + }, 2)).on('ready', mustCall(() => { + conn.end(); + })); + })); + + client.on('change password', mustCall((prompt, done) => { + assert(prompt === changePrompt, `Wrong password change prompt: ${prompt}`); + process.nextTick(done, newPassword); + })); +} + + +// Hostbased =================================================================== +{ + const localUsername = 'Local User Foo'; + const localHostname = 'Local Host Bar'; + const username = 'Hostbased User'; + const clientKey = fixtureKey('id_rsa'); + const { server } = setup( + 'Hostbased', + { + client: { + username, + privateKey: clientKey.raw, + localUsername, + localHostname, + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + switch (++authAttempt) { + case 1: + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 2: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + case 3: { + assert(ctx.method === 'hostbased', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Wrong key algo: ${ctx.key.algo}`); + assert.deepStrictEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + assert(ctx.signature, 'Expected signature'); + assert(ctx.localHostname === localHostname, 'Wrong local hostname'); + assert(ctx.localUsername === localUsername, 'Wrong local username'); + const result = + clientKey.key.verify(ctx.blob, ctx.signature, ctx.hashAlgo); + assert(result === true, 'Could not verify hostbased signature'); + + break; + } + } + ctx.accept(); + }, 3)).on('ready', mustCall(() => { + conn.end(); + })); + })); +} + + +// keyboard-interactive ======================================================== +{ + const username = 'Keyboard-Interactive User'; + const request = { + name: 'SSH2 Authentication', + instructions: 'These are instructions', + prompts: [ + { prompt: 'Password: ', echo: false }, + { prompt: 'Is the cake a lie? ', echo: true }, + ], + }; + const responses = [ + 'foobarbaz', + 'yes', + ]; + const { client, server } = setup( + 'Password (empty username)', + { + client: { + username, + tryKeyboard: true, + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let authAttempt = 0; + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, + `Wrong username: ${ctx.username}`); + if (++authAttempt === 1) { + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + return ctx.reject(); + } + assert(ctx.method === 'keyboard-interactive', + `Wrong auth method: ${ctx.method}`); + ctx.prompt(request.prompts, + request.name, + request.instructions, + mustCall((responses_) => { + assert.deepStrictEqual(responses_, responses); + ctx.accept(); + })); + }, 2)).on('ready', mustCall(() => { + conn.end(); + })); + })); + + client.on('keyboard-interactive', + mustCall((name, instructions, lang, prompts, finish) => { + assert(name === request.name, `Wrong prompt name: ${name}`); + assert(instructions === request.instructions, + `Wrong prompt instructions: ${instructions}`); + assert.deepStrictEqual( + prompts, + request.prompts, + `Wrong prompts: ${inspect(prompts)}` + ); + process.nextTick(finish, responses); + })); +} + +// authHandler() tests ========================================================= +{ + const username = 'foo'; + const password = '1234'; + const clientKey = fixtureKey('id_rsa'); + const { server } = setup( + 'authHandler() (sync)', + { + client: { + username, + password, + privateKey: clientKey.raw, + + authHandler: mustCall((methodsLeft, partial, cb) => { + assert(methodsLeft === null, 'expected null methodsLeft'); + assert(partial === null, 'expected null partial'); + return 'none'; + }), + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, `Wrong username: ${ctx.username}`); + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} +{ + const username = 'foo'; + const password = '1234'; + const clientKey = fixtureKey('id_rsa'); + const { server } = setup( + 'authHandler() (async)', + { + client: { + username, + password, + privateKey: clientKey.raw, + + authHandler: mustCall((methodsLeft, partial, cb) => { + assert(methodsLeft === null, 'expected null methodsLeft'); + assert(partial === null, 'expected null partial'); + process.nextTick(mustCall(cb), 'none'); + }), + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, `Wrong username: ${ctx.username}`); + assert(ctx.method === 'none', `Wrong auth method: ${ctx.method}`); + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} +{ + const username = 'foo'; + const password = '1234'; + const clientKey = fixtureKey('id_rsa'); + const { client, server } = setup( + 'authHandler() (no methods left -- sync)', + { + client: { + username, + password, + privateKey: clientKey.raw, + + authHandler: mustCall((methodsLeft, partial, cb) => { + assert(methodsLeft === null, 'expected null methodsLeft'); + assert(partial === null, 'expected null partial'); + return false; + }), + }, + server: serverCfg, + + debug, + noForceClientReady: true, + noForceServerReady: true, + } + ); + + // Remove default client error handler added by `setup()` since we are + // expecting an error in this case + client.removeAllListeners('error'); + + client.on('error', mustCall((err) => { + assert.strictEqual(err.level, 'client-authentication'); + assert(/configured authentication methods failed/i.test(err.message), + 'Wrong error message'); + })); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustNotCall()) + .on('ready', mustNotCall()); + })); +} +{ + const username = 'foo'; + const password = '1234'; + const clientKey = fixtureKey('id_rsa'); + const { client, server } = setup( + 'authHandler() (no methods left -- async)', + { + client: { + username, + password, + privateKey: clientKey.raw, + + authHandler: mustCall((methodsLeft, partial, cb) => { + assert(methodsLeft === null, 'expected null methodsLeft'); + assert(partial === null, 'expected null partial'); + process.nextTick(mustCall(cb), false); + }), + }, + server: serverCfg, + + debug, + noForceClientReady: true, + noForceServerReady: true, + } + ); + + // Remove default client error handler added by `setup()` since we are + // expecting an error in this case + client.removeAllListeners('error'); + + client.on('error', mustCall((err) => { + assert.strictEqual(err.level, 'client-authentication'); + assert(/configured authentication methods failed/i.test(err.message), + 'Wrong error message'); + })); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustNotCall()) + .on('ready', mustNotCall()); + })); +} +{ + const username = 'foo'; + const password = '1234'; + const clientKey = fixtureKey('id_rsa'); + const events = []; + const expectedEvents = [ + 'client', 'server', 'client', 'server' + ]; + let clientCalls = 0; + const { client, server } = setup( + 'authHandler() (multi-step)', + { + client: { + username, + password, + privateKey: clientKey.raw, + + authHandler: mustCall((methodsLeft, partial, cb) => { + events.push('client'); + switch (++clientCalls) { + case 1: + assert(methodsLeft === null, 'expected null methodsLeft'); + assert(partial === null, 'expected null partial'); + return 'publickey'; + case 2: + assert.deepStrictEqual( + methodsLeft, + ['password'], + `expected 'password' method left, saw: ${methodsLeft}` + ); + assert(partial === true, 'expected partial success'); + return 'password'; + } + }, 2), + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + let attempts = 0; + conn.on('authentication', mustCall((ctx) => { + assert(++attempts === clientCalls, 'server<->client state mismatch'); + assert(ctx.username === username, + `Unexpected username: ${ctx.username}`); + events.push('server'); + switch (attempts) { + case 1: + assert(ctx.method === 'publickey', + `Wrong auth method: ${ctx.method}`); + assert(ctx.key.algo === clientKey.key.type, + `Unexpected key algo: ${ctx.key.algo}`); + assert.deepEqual(clientKey.key.getPublicSSH(), + ctx.key.data, + 'Public key mismatch'); + ctx.reject(['password'], true); + break; + case 2: + assert(ctx.method === 'password', + `Wrong auth method: ${ctx.method}`); + assert(ctx.password === password, + `Unexpected password: ${ctx.password}`); + ctx.accept(); + break; + } + }, 2)).on('ready', mustCall(() => { + conn.end(); + })); + })); + + client.on('close', mustCall(() => { + assert.deepStrictEqual(events, expectedEvents); + })); +} +{ + const username = 'foo'; + const password = '1234'; + const { server } = setup( + 'authHandler() (custom auth configuration)', + { + client: { + username: 'bar', + password: '5678', + + authHandler: mustCall((methodsLeft, partial, cb) => { + assert(methodsLeft === null, 'expected null methodsLeft'); + assert(partial === null, 'expected null partial'); + return { + type: 'password', + username, + password, + }; + }), + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, `Wrong username: ${ctx.username}`); + assert(ctx.method === 'password', `Wrong auth method: ${ctx.method}`); + assert(ctx.password === password, `Unexpected password: ${ctx.password}`); + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} +{ + const username = 'foo'; + const password = '1234'; + const { server } = setup( + 'authHandler() (simple construction with custom auth configuration)', + { + client: { + username: 'bar', + password: '5678', + + authHandler: [{ + type: 'password', + username, + password, + }], + }, + server: serverCfg, + + debug, + } + ); + + server.on('connection', mustCall((conn) => { + conn.on('authentication', mustCall((ctx) => { + assert(ctx.username === username, `Wrong username: ${ctx.username}`); + assert(ctx.method === 'password', `Wrong auth method: ${ctx.method}`); + assert(ctx.password === password, `Unexpected password: ${ctx.password}`); + ctx.accept(); + })).on('ready', mustCall(() => { + conn.end(); + })); + })); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-worker-imports.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-worker-imports.js new file mode 100644 index 0000000..8152d9e --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test-worker-imports.js @@ -0,0 +1,25 @@ +// Test for thread-safety issues caused by subsequent imports of the module +// in worker threads: https://github.com/mscdex/ssh2/issues/1393. +// Each subsequent worker increases probability of abnormal termination. +// The probability of a false pass due to zero response becomes negligible +// for 4 consecutive workers. +'use strict'; + +let Worker, isMainThread; +try { + ({ Worker, isMainThread } = require('worker_threads')); +} catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') throw e; + process.exit(0); +} +require('../lib/index.js'); + +if (isMainThread) { + async function runWorker() { + return new Promise((r) => new Worker(__filename).on('exit', r)); + } + runWorker() + .then(runWorker) + .then(runWorker) + .then(runWorker); +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/test/test.js b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test.js new file mode 100644 index 0000000..d0380f2 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/test/test.js @@ -0,0 +1,20 @@ +'use strict'; + +const { spawnSync } = require('child_process'); +const { readdirSync } = require('fs'); +const { join } = require('path'); + +const files = readdirSync(__dirname).sort(); +for (const filename of files) { + if (filename.startsWith('test-')) { + const path = join(__dirname, filename); + console.log(`> Running ${filename} ...`); + const result = spawnSync(`${process.argv0} ${path}`, { + shell: true, + stdio: 'inherit', + windowsHide: true + }); + if (result.status !== 0) + process.exitCode = 1; + } +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/util/build_pagent.bat b/tasks/enduro-trails/prototype/node_modules/ssh2/util/build_pagent.bat new file mode 100644 index 0000000..9f5aaf8 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/util/build_pagent.bat @@ -0,0 +1,2 @@ +@cl /Ox pagent.c User32.lib +@del /Q *.obj \ No newline at end of file diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.c b/tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.c new file mode 100644 index 0000000..e900491 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#define AGENT_COPYDATA_ID 0x804e50ba +#define AGENT_MAX_MSGLEN 8192 + +#define GET_32BIT_MSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0] << 24) | \ + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ + ((unsigned long)(unsigned char)(cp)[3])) + +#define GET_32BIT(cp) GET_32BIT_MSB_FIRST(cp) + +#define RET_ERR_BADARGS 10 +#define RET_ERR_UNAVAILABLE 11 +#define RET_ERR_NOMAP 12 +#define RET_ERR_BINSTDIN 13 +#define RET_ERR_BINSTDOUT 14 +#define RET_ERR_BADLEN 15 + +#define RET_NORESPONSE 1 +#define RET_RESPONSE 0 + +int main (int argc, const char* argv[]) { + HWND hwnd; + char *mapname; + HANDLE filemap; + unsigned char *p, *ret; + int id, retlen, inlen, n, rmode, r = RET_NORESPONSE; + COPYDATASTRUCT cds; + void *in; + + if (argc < 2) + return RET_ERR_BADARGS; + + hwnd = FindWindow("Pageant", "Pageant"); + if (!hwnd) + return RET_ERR_UNAVAILABLE; + + rmode = _setmode(_fileno(stdin), _O_BINARY); + if (rmode == -1) + return RET_ERR_BINSTDIN; + + rmode = _setmode(_fileno(stdout), _O_BINARY); + if (rmode == -1) + return RET_ERR_BINSTDOUT; + + inlen = atoi(argv[1]); + in = malloc(inlen); + n = fread(in, 1, inlen, stdin); + if (n != inlen) { + free(in); + return RET_ERR_BADLEN; + } + + mapname = malloc(32); + n = sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); + + filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, AGENT_MAX_MSGLEN, mapname); + if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) { + free(in); + free(mapname); + return RET_ERR_NOMAP; + } + + p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); + memcpy(p, in, inlen); + cds.dwData = AGENT_COPYDATA_ID; + cds.cbData = 1 + n; + cds.lpData = mapname; + + id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); + if (id > 0) { + r = RET_RESPONSE; + retlen = 4 + GET_32BIT(p); + fwrite(p, 1, retlen, stdout); + } + + free(in); + free(mapname); + UnmapViewOfFile(p); + CloseHandle(filemap); + + return r; +} diff --git a/tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.exe b/tasks/enduro-trails/prototype/node_modules/ssh2/util/pagent.exe new file mode 100644 index 0000000000000000000000000000000000000000..6e8a71ca581ecd0f3ad621efffc366f9f1edf9da GIT binary patch literal 50688 zcmeFaeSB0!mOp&^B}pggguk{jJ)UwrU@oNd;wqMz&KH}TJbU(hD;J5=04w3w>t@r zv(G+%JzYv*Pe`jfrRMED-jMP^q>3z-2BwjC+G6?yH4K8<6BSGaCh)z z0o_W}-<>m3TZoz6vwWJ6_2r;*su~Ty3y6|nMu-Eik1tCGO zP{gP!P?$Oi|7?P{fdf)L%FNwSha!cH{}hC|-1iTD`UGKi(mzNW7ya0C-x-VTf{<;Z zHV$gcd!=;yCJ8~u7W@!iA$&2s;p6{u(E2Ou*4`%FCJ5^;Mij~va`83d8~4wPs;@M` zgq~SQXvIfmK8tVMKQB_Qth@d0dwvLda3Y}(Upl@xF~Lj!yn=8&_xzuq|IhS*aw1#V zoSS3qu;&t0)hF-8{1B9b*=<3g)hh%Y_%SkFKl2J|ajqlWDktwv9R&yp0=qg{5d16w zzsf2wUz*zgh=IJmZw9?2(U2LG2pOfuZWUXQ&APmYjc>$VeDF$ zk(sgGEBJ#hG^v8UXC-K7MNr5Qgj%82j?X|FXQ8zK(^&W~Vq=tW`qmH|iIM?8|5=wC znNEUOmYaXGHWa923=IR;If%(ck&z|2IpqMn!FzK@ac=%A{-q(5J6m0qTL2W$li}7a z*NeMt`{?H+{rnaAXr2j5yPX}OPC~Z@YAuzl1%sqXxwDjm zt^j)kO{icG@`gAnjZ6oy0&;dj4h2-NT*G@I!0zIJx0`^7-b<5|r)kD=?Syi|SrMqz z>YZUjnyS>h1nGQD&Ik|4=d<5jAP618B!IKU@VZ;qtX_GjO)GPR4@sXXore3}!NEeG zYvYIFi}kL-5~maRsb#}zeZTf+$)S~GslFjSslzu!>qZzI`5KDSmO2|gbpTSjN-MF4 zTcw#|(~A^;*3(sI#ef^~uyHN>8HV|?Eq2R1^l9FoE%n3tO`htZx|>jSYJfcnq^dxV z^-BE^a!SeWceS=bc_{A;We>3R81^bZ`*kKCX3(Q_oA!>UW205;w3H3!eeCI|^K13} z`emALSlllJ{A?1)wW^9BFEf0@!2L!bA8y@B=mS|Hd`t{4FbqTUxqAOLVi?L&XO7m9 z*M>fjoxPvOV|@L(Uh51B|KSzb{>kXGfkN3SU05i)q-=Lnb zvZ!y_`-o{X0UrMo=%)d=5{W)DuvBO!aj~d@g?l zYK-{0{T;p@RI|0icj9`~#L}{`i#sh#Q2$UKD9P+b#)wj7YM9Et9BAmy412E zwR#w&d4W=&AxIhFL!is_v3C3xx#M&xXN3nO=O|rfY`9Q4Ye>$DTA`f%(^Z@j01zDm z*tiRXn-M46`o2-B?I)`3k5la*(fk;YRBY00k=XQC>i!tbdg_P8pZ)<6mBzJ1zVZ;; zcx8-!E%ifre@4e$RzIxO_w|MW<*DwkTcypxhd3?hgSNc(OfIW(}4%9vE3bReE(ocwP*IIl-d0m(JhV|S4yX+Ex zQ0&c0{jeZiq?HXBzM&=y5w?LT>gy+hz68Z1tGCgNap@;O^EpKGZvfmqpvpZ&@mGP~rOONDEcpsvx`@&PRQUTQ z=FGFEHu6c3beE;_mzG;{Mi#FGDE%=upF1!HcEV4;K;A^>D$MV4deXE`}mJ+%!6gIFi$Vq#tit4t(t|_fEgjV97 zQFV1&tt;py(s(fg6UOH(;t0(y;`m%qWTFGdj@bYQNM*4r02*7Uj!Z;nbQ-~kN z8e5(0pgRPf@VeGUy)@VCrBh}vX-VS#;(WW(ZIRxq zV2#&eD3sfW1uba+u@+AL6>K}Gx~d8kri-j)v_Pe-$A~YzG;UaW*@eKP4OmsME-K2T zJFKV}|4bI-Svhg1nvKASdR^6RduO(Kg|;2tC%i(SHe)q_(REg|CDGGfpQN?7P)aR0 zq;IIus+NPt`N}!1)*evjP#XL2oP>nh3s$VgM)We3t0(Lrc-3iDqB+U|d&B8x4|s*m zU)7GR21EfMDzyXX7|m{W%o*j&>CrC}HG2}R77kClggsfds#hcX^$n*VLx#<7uW`4o zZezd0E*>iK(qxem*a_fZ%%Qqi@)>lP+4um+lef>)S9ejvNE7Pbc!BnIUT5@lf)aI= zv%>{~(6H1=qhF<`DD61`BQqCMDZc)r_mrWG`bkQw%g=rZV315hsR@t%^ErtdGPA@c z2y*b2d!lvIi+F`u4YxXtt%i{oMMHT(n}2}ns@u%GGf`bUZ<&LNJe^TLF_woTS@!qf zZ_+=^!Ai8ysg=33dWRO(j@sHiBO4r^A@TmFz$G-CMze&vY^5j!dK9FIl>y~TQTamj zjI3TGC-hp-p1}?*QG%Qi?X@bO*_6|cy30;IW8^;iRJK>pI$ohfrPp5PRJv`pP9rz` z(iH5Txsjbn-VS#*xd#!~hc5$xi;p%ZHYGKeSeh1DnoF!GwrP=7X}2jIyznLvV-T4oB<}G+nUu*@oi1VNj#@;yZ}1i^}#n zR;+_5o8`}Wi`!>D)eG}K}YevF9&xKoIbDKl~EDC-60w*e*WWw8*A>&3o?~-h00rS2W=kgBcsE zudT{Ad=#3-L2e%hhZdlPu`&DFrhG#qE8ZW#zA!Ea%I*UWL-+(B=D_E|mxV6}pBo?g zIvahR4L1vJ7TgTD8E{>2U2vUnop2p+9dPY%?dOh-*+)xI-ZFe^@ol2A<6~1|Ll2A_ z3m!&m$BhHp1{gE$oUt>R$08@z7%SG8FD}O#gT4Ez%i=roeBx^`lWQ}Ax6-C^OFHoz zg>zbudj&Z)fMXKYlYC6@y=AuuLQNr~(u)>+Z)5x3!Oj=$AZmg$J5L)bL7n=?rhjOrq1jQc1O3EXWnUx}HE$rhN zaIqFAVH3C%-W@ZMvt<^3{KlLdIL4f8D$CPHOpOzqd!gJTC;Hh&K(k-sN54|@ozNUw zvRZcBU(UXojZ&~i-_A7OaeyoJJp#d36MQ{>Vp|*ddUj(Pb~V;K4=mrK*b4cWl+&^o zU{g*ThU#-_CC;j6?*}K|h@H^fZ|OWl`}9@l(r3L=8oQGxU4$vEe_r7}_N+ykq^`C< z>k=D(ia2elL+Kt-)726xOzHkc>9oQR2(bIl(Lqw4#oil2>soU>eUg)PaKG2nC#Qjn zWb;Af#AYQ0m_8p~@aJ@QcMs?3SsOV4s~VlEm37 z6^wG3(wT!=fwz92R)&4Rkftc7N2EzwROz0s9gUtzh;}F1?2i(sr6=t5zU~zUy!IR^ zqt;qcQO+JfA6}PjVZJDkDAzuWs6Cb%piAQgW=HbnH8h83u4& zvvPIp(6qM)hiulgKoE93+l~qQI#9&!L|ba5+fc)^{~MjZuYmvNrP<|PHW)l%%;eE z{Dw|r_JvMczbUsCK-LrS_51Z3#r;t~ zdxwY&!iwv(2-TT)*jDDkdBD>tKJW|*25h((@fChn0Z2?qP=wg{uw4)q8XOUQO0A{B z1oE@1#=-m;Fz!~rzcwLK)?Z$0iA1QNa=)>Q`XrXy$Sk1t_Js$;#v){>6(YQ~{s7^q zg{e`RfUYw#X9JLWJOyAHuUd-`wb-I+m}sYP7j=`kZ2+8xvX9y?h>dT75J$@d4&w@K z_w}cpQ}AzjMk>T2Zrh1~5vKADUV5*BlIB_@`&_Ghp}5EGKBSDGr=v=nRpH23)m_v+ zH9|GV0B<&U9BT#HRMmKRPm1BiR1YuI8pBh%tTt_hU*+lS=jQ-tb3CYhCN>b$6!QAS z`%mM<*y}*Lmfk$k#Ik9bI9p3si^YQ8Z$M4%LqwVdM4CGg4DBPD5mY`9V)$8FP&lO( zmVvgu1%!6kJ&?xP!x1`DCEom4ra0saT zKX1&jd8akQeg(!?=*D<8T(<7oK);n}_1s^7w+_0lnXUH=5l$V-$6(7^VRo zhjb~@lxJu{0Cy8}B3Z(HH6g!H+%wVkiS2C@e+BqoVA(~ZTAQ}AM$OWAvuy2_T~vhm zTcf&c?G5`VVuV_@_y1|j?!>(LZp&_?xbZDpL@m3KLz;7)&v62=;zUD-oZWU7kq(!pKSEyipJm(7VUWtx4eJVVnAt02vZbIVuw9wNwh zEBiQ%bVY5#>OwvRAxZo#)(vw@XD`F6=Iirg({mq!Rr=NO)rJ;xuOw=m3_}GM$aZ(D zp3Cm#`N1;@>^^vv94=>cY8;U~zErH#%7)jt-&)PKfpI!S0)o(gcm?(#z+*@JDU4P* z@(jQ<4z5!?HXD3OZcF>94TtvRc*84=I`&)1*dJ^Xw4jXHbQK_*D5SVIh zalsK)1A%>VfXzYwROwd**k%v~?NGB+~2laN&a(QBVmNGDPe<3k#&x8h9e7A_dTl zLhz$iRql7MSC`+(=B$G3f)LXgYjip!6jkQ*T*>}|g9-7bI92Tjfwu-~ zt?YG^LUGDkh1@7)1)SAp=NfaUYmLlhyj;mvZFEDFJ1U2zliZ6y=S^aF@Q-yM0FmtI z$bjFozqR)O4r~(_D5tNeI~ghci*kCxMl9GXAh5B&^(xY;+Y*YAuQt8P(>bN};;7Q< zsBUAwx{}UNa^l{cgI)o09!DG77LUp`qnu_v0rnZPL&s3AI@ta2R%w0gRk&(C<^dP; zjQ#{eSKxqa(5&K0HTCXXR|H>PH&kYvYOeMTyI=RKw=)Rlp-YO2s(BRyOS7}i!|4P$EA2}n()HINTP>?^e; z4`f7&AAlmMPZLPRbx6w4K4KY=c%f2DxOJ0v>mtoJq;;WI`R!1>AxODe;<+fikJBWf z5a1|W#|~21*Kf8C6SJRMs~7KN#w?U-mX=z6egV`=!CnvG17XU61+96Lu*BeNjgz*_mcd+ePP1F)QVh6nIta64@ zy3UG9EP9IOK*?S^CAP1wK42FH7C609qH-TpXt~B>`=(TFLX#ED_U=~Q3DJJJpWVq< zKrEtIDHGd_M3b`1vETG*AG2>T=LZ%!y)?eVQi`(GA;@;iH2ntl0aCDm=`+#DWAf`XpZt!+Xik*EKav%b~fBsbRiAhH2ST!?Yr@ zyD(tb*z#C5Dvlj#Upos1d*4nZ3sQ;}egPik)^*1>z)pQH9z}DVo(PL zytyGUd@p*%J>VG;8}ERx`F!^wbr)aickyL^*Gs^s>CtcS+xV{7SO|<3srzVMFXUk2 zwo4EdxxRbuijAVU|A4qZ=tPw7WX$s*CAM&6dkfxso|%P4@cmi9tQsdvEv~R zAS1NqqeCBoqweCJwTpM6xxeh9?Lyr}-PijFvY`%z$&;cwtDAx!Ds>qnEUz1PAYI&--^OKG#4Bde_(R-YtXzzj#u z9|g4!^2lB?6Vdp9-_@ET?tddv>^Nc)K<`)B>D67-vfe+#OT}JtZn2a`#kL|j)(5>W z!LRW>aD0Khl*f4~i>2kEGeN01bmnd;D|BX~7;Zqk*&YGD-Z}!Cf44koQ7jTF4s*DA zE0JXOj;r^^QGZVFeE6G_=3XmL3vIQ`ma`y1kL5)V#qv%8%v?8zxWj}a_fD~~m)v{A#!tzW#m0}x-6S?1C3l6`cnGe#i|9dlhQ=0~IL#}+xch*g zoxx5AX0JI+WLE`cZ-i!BgcBV5FU*(bq!YWNBK7V?1>BXlV3;KP?lwAF&(AYT>o(S2h0F+`3VDiy)8WI1IlN#j!j!aF(P zW$I)QjtS^OIpZjkFc2G`2dD1&L{8l?8*G6ZrbvzdcJMWa8qv!SE)3mHc0y?DeR+^W zU5c`)&5zNMa1#gY z;BXXaW;C(ty$Tg+w$W(-aj*xbQJ%M@*=F;Ig2mS$r=T`S8T?>6t`VdPk1Yg$CMGw3 zw7q_|&;yF;?L@RPv`&187!9%UIDVC(+r@3WdHfyXgR_a*8@f}vR~h=TG*cP6M-2ZP z(gye_g-o=8gdp7(8x6EwU#_`Fab~-5!Xs(abx;wS*>WUjjTWXQvqnvX7?gX}#IcU) zjZz2mHOFgKffW-+eVRdoQ6WUA{u-!iHm$<0v^jd;MnIkrI&+8oLzA2k7WB$OPFhRxiiA_m^FU^=s2Cv2>K#23Gs0hyiIrN;l;2?|-jU(EV)GpYoHGGbi zL6f9#M4=#z6<2A@DUHEaRfYD^6u$$OF2}|L6psPSze1i68w|7#)1HWjCJxk<{LNU)Y0;9ek6%6tL$EHkL>9{yIQ5a{zmJd-#16mERQp z08R(r!a)Q=?-IaZw2(mz-%KU9*$1LIQkK~r15t1|;%f_sbvwkAyTaff#~K%#1=}$uf7FI#tNU22@9Lf7=->i{uf2nO89J9H zw2ss^Iq^b{bVNR7ZY2g^Ofl7eP6_PDzCjHh8X%m<(bu8e1`rL2rEf@J5-o2RT}1rjsLb=^1b@}#WjdeQd+H^ zx8+lLd__7sq|f9_)!5WEmnuDJaR~D21TSF!X2O~^Df?cLmH`L9#yeKrljyHaB$;(2ydCBHZ-io-d2y2Ei>{ob zMJO64ok=DTN8%95hiQ)-)u$@_ux{uX1~1RVQaj9kLm+0Ggw0pR@PwX+5C1r9b8cj% ze~&FKB{<0%oF!!c-G$~n!{e$n&JZ>yHSrC*u@y4A$WwsUIDhOOXg<>0fiC(UF4tTw z>3qK0{nkph1QYa78xD3axxK>gul5R`<6CfzSBT(y4BsdC#MyNC57JbGeNpDESi9VZ zuqHnmZ6U)aEgCx)n?j^awiAbo7_VIcZ|@l*hZ5(rirDxKyw7^Y@R#ITrBqXW*4u@k z(rJO5%GBIJ5EaP92BRn7xT7W-8?uZIjsW}QIJ(o%?!azO(ls*v6dN_lOS+Q#;Q{l0 zzg!+*FA*g1Q%(4CsnP9spy)$_T2mD-Y+MS zp-B$7h%H&PE6bVG42P8doPZrhPUK1Voh^;l`AqIE>VTHG5tR)Bo9wl_#?(kOG?j4ktzkH^8f3s~tEBX@U!eHa67gFH!voes1~Qs!~|8BrO(nt+uH*R?4??p^v}(U zp?OS^>bNQL-A0)!R6im#rD|eip(Q2~X)jJsNRj-S*t{ft1_Apx@cbr+CVI^r1d1US z06HT@p20ycAyC+n!o)cv4hk?ZGz4}DtnVUajD+fbEym?E^wcZ0y0h30$pWV+Lx*YLgQ3q{s;&hh4XYa?WbieGrk@ z+SF>uUiv*CygDH4CAquQ%sctgc#@@CP?$i$Su)cDrJP~jTGtSc3Ya3 z)LdpXElEt!XLzdnaYNS<9 zXtn@(s6Bjr=mrZKDTa@r71V>BaBpl*Z9KFoabfQR2tao#?mnc8%8-5QL{wgvextZM z)f;-b09>jdvF3^5?l;8!Dg|Nlo5n6ULBx1Dvg-f5z|$$)ZC$!o69?oZLK76PuQ$&seAo+2nZWl7)F)`gwz0k3-S~rM!ccPU9_u$T+XM?;Niu=MoODL0gTI6V2&7}iC!2); z|2P3%Km;@yb6QHb43Q zy|u(!4*f_B-$I_-PYAuM;DJdvnN>iu)cGF}H_is^sAlQ&UURwbggdre??zXhqgi@2 z2DW1qj1|NCf3I2EOKUQ;byHfsumY81#oWS+nS@&OJryhkYvlLqo*sshaa8v-W328g z%yPa@_w)-SnYyQ&so2r&oGx*YPVP2nM+AuXK7vTBcG7BCB>x0Htz9qWYvCl^P^g;# zyKJoJ4mSBCUccUfDPgYGbO-=O9QF@@U7yY(RMJINszW=e|E_k@in!n$cVL{_l3aWE zUFlADYjbg~qp?+<)Nm$*BI?rPR*?z4Rj|gd)J`jB>~&WUeyn_Ilbm@+o07=fu-76F zXr0k+hb>Bu3(gy`lZ5e`lz8fS6r5theMNAnU=3XvvYTxV9*6AA$Xv&lZ7DPOCW6pV z+--&v&^+Tv%m;z8;#PZ?N(lP6;#!+16@t~hij4~5NJ0b8Eq{%^Y z*~2-g5a)vwjt@muvC2GHz0E}%g1Pu%I|yCC$jbtiLDwyaS#=F=*<~Ybe-3`Cv>{LX zdQnS4F;?S<(qZ?E)SXm{UZQ%|td^z($;W2KYQpG}xsH)ZvF=u=0CR$jCQH(n7+eRt zh`NB(qgbj76H37;ijBnRwG_kK>~sB^41rJ&9v)|L zUZmCNpfg5oh_z7O$K$akFT_+c3>_s!uz!vPc}c7nHB%-GvQTB-M|cq=@Fq`nw?et% zalXFk-@FimdzGO{bzjpUYWCMRBPv#J!--)OGEO>AlnFMP#AMo#`&gB_&yG4hXT`?5 z0a$BeOWZW-Ll&_y$&Bz&1c)w8DcX6!D3DY_XG?hj{)O=^{=2OCj9MS%S%o=&$z*)^_xCa5Dc7E>8+lkFyyl)1-wd@R3C)Q61DdEt@_V9d=_51xEF- zxORhuk5-oi%;oAfPA8NN2O7GL6DjLq7A$PAnSzlgO&T>HTSqSY4K$^(1HfW^#Z)IU`$gplcg5TV&Z*Yr>vYv|OX_b*J7Uks^fVO4J`4L|agwhs8b4rP@*DGrQyv_a9bz^YzIMpW0BV zlpneASE19B5xdc*^yVnhL!PpX^%nqdN1<=HZl;{zDI3B)w6ZKaUsEpDd|5X=>yUH! z3SxtPjJiu-sVyHCUtFGHI|{oAYJT&6klog2?edgoEpn04ZIzN6aE}WIjE%`?Xp77oo+Aki_SG?*lv`~==+@~W zLs~_O#!4&# z&B-|3OJxI5hn$KoYeJU+iz00hasaIZvJSf2HQTh_UxZt%p0k@DbRW}BQ4ze`NMmk5Y=gQJLrd);{oeKxdjpQ{3AF<& z^pwa#gUdf!|AsR8f;Xf!*L5o#-(qx|kWh_+A+Qe-^_zXVgMrH`e$4Cv7p%0iV8t#C)j|D0{hc~bEq|u11uh8f^ zk9P7q0uuA)*0svqd_&5Qua;Bu4oj}Zl4G$vv7)wLcU08=O}ACl4j7pNYSWSwXClrB zdM0c8Q~VIX4#TTv0R@;b#P(0DtLQ7-415u3N{+xD83hMibsMZD93D*Nm70IMn?oJ#icHp+zTbdoFD=;>xbp{>JgY$|2obDCTuyXQB`6e3vI%2Rmq-*vleQ>%N>^Kly~Y;_O_^+;2B+3_o1oT?(l1w=x* z)GxTwwiGzDfoSR-sKkd^I=02c)#9wq6JT+qfTL?b2fK!K&uXJR^R|?4q zE+%*Ldte9FtZq|sIUpvXeo`|kw5fziU_WJsjUp!hLXXex!wVAUelNxl5msbS@>7tc)-C%W^;rKr{P|1hyJ75EEf6}NjU$Ul||O~F->VF z&6ZZ(4=P?keMD1bnw-b`0&AJMV#?=NvL#VuWq%mWgpt)#)p>eSCA*rEzT5Lx0M|B@ zdKp%*vAGe5m@QN0;iTc6%gt->N$;UusEg>xI?$%NA(1eBpZZCGZvdLwWb2V>9QBK0oCrg<{ z7m|}+bP+j8xI_H7MNVLcA)o{|3!AB6(=sBfQWP35FTk3iX)y0hTtm#j(p9i5)1sAy zE(xMCXXNGWz#K0@eA5u+zUX>8l3<1dLQc~Bj_|wudd=SerJPBCiR7&g6z=Wq;Spd! zyWoMnT7|ayR(0vE(9P4eyf8_UYICc!EvuBZg%0Qooeig{{LO#S1Z~UOq6hI{j-1?4 zvQ|N)zNH9hX1IaEKQ8)NJlsg()kQy#hr<+JS`>+g@2Bv*qKD#PlB?=h7CjsfH&b|8 z(JpJOd}I{#^rDw24CTjKAR-tW*48?VcdOJbYhh!I29{G`^{p%UK8PE$MK9p|E}*aL z&c{hgn?qOFa2pBd1KKLNn0juJWLXqo-&}xc7LgJy&54lud{t{-RLQP@f`XP@wTLdT zVJSImmQbO)18hGsgyt1hMOIj(i*P%J8K*H*s#FqS%n#r+XPJqfr-P)t2ppB|R0xx+ z)8HtuNB3bJnnBnI%B4a_!c#yKgNy;H!pkRZ#vH1U-NT{COKJ$cCw{J+`9b_3T@DF+ zg}XJNCTV}wmODF0{wfsu98xj~41Er}IuT5CXx>FK?)!kJ|NTX{H&lWseXfy&N#ww6 zu)^Hg**p!W7=H;HxfI=i7ECmfNIC)=wK8XOqTzEkSxQg=s%tzZT|=)j$j^n&=HQ;y z*<|@wD9PS_y&=$X0L_F!5YT8&oSTE2G|6&eiGFIS{y9%Lf&>!i0YPvlgrLi?xQ{J# zAJVNQ3qtc&Nv8?hOGs%noj?BIjFdosaFJ}+`t&q+E0$P1dVv8)qbqwNy`I1DBZn zU@I|_khI)c(n}Xskv*y1Do~G623K!7BGHo7E74~*@K}Z={)Px1rXd!va4L}?D6lUh zE==h9kc0_MQ;&Z{ll}=z`WiZd4L4XAZ zO%V^h;~RE<&|+t)E>p2(Z2?9QH4ZWw(t~2B?5T*k{ZFN?Ygx zrphm4VxJ*K27Kc<)WPmN4aBrASPOo_<**xT3f&S^i&kj*<)N6{SE&^h04@*+R!MChmTdnJXKH4u329U>_D`G-&>H1wmIHY4*{I9Pp=4^lcX z14iZxR6p*i$y1CuJ$!h`SOyZ*IKWN{wy$p6LCgakM<&4<=ENu@1ea-)V(g&uC_Nn< z=1a(=r12Vht1vpXj$n`&hn4SwIcR!%{i$n`MN`gC4bZr`&k9!_m#A$2@!T=cs#5enSfUkA3X#{|a2(Uy}OYWxqdmSUMEV^Vlgv?dAW1N8!m8EtA)>Kfu*F*hK z$@~JSb zWR@Aa$PCRkLm6ght{F-+LtZm9w1?*_HbY;Tp;9w++zhQMqG6&+4pRiW>$lWPTza%6 zNDuy?39V=XdR=TVXv8G2WWOZfc%N6AqqK=KB92yWZOh%rdvPUOHvxm=DdL9O84ZT_ zE#!A9^C7mVWPhQwcp=k}E5J&qTvmR>Fo>M_@Rfq`#HhjVWOGfwQ8}L2=<%0iHXBO< zCRrQyMp85c4}uyijSqu+$!+PTf%`D{0uS){@L}+29^gazp;AN;kek!AXrXBUt$Yyy z;x!qih=2tCB1i5HnprKBvV&$rM*?M>e+#Wa1jX~36S5^XbIcda%xUO1J|sQtPBfOy zfPmkaL)o=CG>>71#;0lwS;H*PMAn>|Ehe(O4))L~ZX)+Xt%zoJP*_C-&D;5raik?a ztBd3Gd^x!G7(M5oOV0oYNlYPHo;8fVK8KdUXyFB&k6@aL`$);uW~GaGR7oc%vdxPt`e>v#M5+^&bdfy>W zjH~UXWIwwRd8+hx%$wVGeq1--v5DZhno!QSBu-imTOepUGlF|*Cf|S@%3*_RNV;R< zi)_~SCSr30_5oZ|<*Bu4@Ad8gHJl^D=#0Vr=O`TW!>b?VB8k49Lh!1P#jbQixXuZ+Tq(L0`@{&C zmZWJ=z)*mM97$LuxwIdaCc|{s8@G@!`dt`(p#E7625gjraMA5SCm9e)nT6FZ$yG2- zJ`Vt3ZxY;xYE)dYAbx|BQ6F1?afe|-;ff4-nhBIB?oJ0(LG>`n?1xO5y;na>U z(+>yH9bDvDkBnN=3kWKwEn8;bmh2ar1GUMRK}07>^8{9y~|}S4}mwf~moq z2z_|KtjCvxrn=cxJcBeskHAyv#?-> z5F+Coyo3gxlcN^vXDZRb^?m#Be3RtXJQnHd3RX^WAfw}acyRNaGZ}Py)vny$gTq1( z)XeMzYJk=Sm)_oiFNW3k++-~SQl>S5{RGW7WyWS4(gl8HjUI|zmWyX%axDFAnw!#7ES?iICwPnO%^$thxka9EFE>616>H`j8^r|8E#6{n+$7}G6 z0@u|om}`qR6!14|zQH42sc33VVQH55$N}xZIae0V{Gk2PxwcMm&w`AKfVk)0MEARu zxNAeNBTj+F3HNb5r|Xh2Dz=ZIcu%=rX`Klj3gah*bBZ%n&9x)JAyBq?7m{dL@GB=A zV;3NYZ~=1kwj*vrVhJapAau3@yPS8W9jn_iEK65V9Ii-Eil3*@l6{@#&5g3@gGWH) zvGsraok@OWvW>rH<9@e+Ui4|@EvLt9V&J3=AG>5}X1L;M46byM!tB!d3WH@`sbqs_ zXs_LlA>Vr*|Ft{FKY{$joojuZ^xQ_IB)ihjuKW|NPU4xgQk_RIXOhs@%2_%{`9Ee*g5Ax#`$fMyzHkvR_ zCtn!}Gl)t2#s)00J($CH9*_L6p@27dVb`|ZxA8w z?i6?1Je?aSz$RlZ#UYm0>yNm2&4?3F{T3}TLsmzC1?>0Ci;bCM#eSXwUpfDhW z`9U&fnEO}-;t>n3wsJJN5}7L4t5ay=6~_R;v5f)nTQ3~wUpY`N_1iWdRYU5n^w5&T zsjlX22~?~;fv$UJQdAB_p`fO1iPT|wQqvRMLv4LczuD}@j&Ki(`4td$AG(bDwMQu? z(wI(}Y)2xu z{9u}#!K@cRikSzoOMOUu>d+2;qjS+Z+{4&BF~|>1IqZ&4h|OqcR{*#T#}zAV z%FLB`V-U|vdFJqIpVwlNU4Wzi=*eZoJh=o|&wl`Z2LY*zf*OZLHh_*lchcgfKd8w) zsGyV4^2?_*b~lJZDrkFK@jA3rQ~SWYV=0xVbtI4%-GCGD3D6Ghu)f$9r_WVJzLn1# z55fSVA5%t#iIwQny!Np~{owfBS!*AYW#o(_R(h8eN1{r$7UKaEk^!~e;TeHNaT|LD z0|~2u9Y6*R!?wP+8;unkAh+`m43Yrf;Kop;$k%ifKviCvA?D5n9=v)1XU0v@iT+YM?XwHP{zebVo z!55LgX-;oEBsPKoU}aE(nR2N2IrzsFvk1kQ<_LEk%EvPYk>B>wAmPQZJiJYYNp_jI zdmdfBMVECqhmIrBQS6zD(kzQSLmR$=storHNH%!{183lEt#*e}-)%<;b-h{#aO+q| zk3Iu}!smJ<$yV zRQwjY)sc@*k1U+_@(4-`IUL@_@@Z|MolQWwC{?X+=r$F%$jvp&T&jLTOO^ibg>#5b z#PBi{49;uR`XptLPlSwM0Zjxa6dp=hx4{m9rzYd7l zNkfqXj+!O((7fovbF$nZh-DT;@hbdQh{QlpZudnta?KkxOir zOwdY#Mdm#5vseEe!0PH?g;qo}!}w^RWF1V}ze2Ww1e%=|G5jY4FhjP&?8=;i3+*ie zY!bAEjutz2oh=TycoYhRH>%Ps zC*Yb>KxXl98{U9+$SC@Kz$Z|VsAx=QPH50u-=y6j)M$+VUqcJ5KnHYGd=aJdltX*q zRp8}5R*7TOJw;78mq|hG0qQYCtS-!wZ_ys0E<@;igrLfs^$aH6Zpy_RP*^|#`2e+f z3?Ow3V9R6zFm_XU?9|hv85z8kvDM62jFP?D0|ybhf~GQF!T^Bwz?<-MMO|KppS{GR zjv$Iczu|?oBE)_HFOJgM1JwUTT{K!#3Lhh!2;Ig^thT!;iPZtHsw%Q&bZobpV>>}h z0`{pu0@AlK0xDcHjMoen*~g-(W+mR9 ztEH(RV4FtaYrW%kCH#Y``mM-Ff6yY{1KLjM4hc4Y*_- zIJYg>fV0^=ie7hjY#09YLn@%1{X24yXmvB}()bc!%pp;q(tbCdxIw@3_j}KogZlw3 z!(a*u?DGs9n-DGUtFp<6X3brL~7yd)|U>6P@Ll*HGC(y}Y6ChL&!`p!ncO& z$Qu1GFB=B&9^sgng49<}9zM#OpMXvW)TywHgOK zu+RlqaF8(r7ofy&EoFhF>|tr2YSCXdkH*T-KZ{{He|S!bjqAxhD?V@+Txv=IWZ`H^ z?@G!^Qb!UIjC+Xx=d^>8u^UJsKqukUR(U1{flkFv{561+S{EHK;r8Jn_qB-c)Y{3l z9n}}XzX~yACJ&gSy+@B7{px5}>LIy*@RZgED7-y^6xZMvwxf0F9>8sM)QKLzZb)95 zhlDB1ax>h=;B&y|9Q-3L#r{#y-q7CDKBjtBA8-jZ;y113FqYy*2J%+zfb!YaC`*!l z5FNeapM5-mS z*i|YID4&T^wsydMEc%sIa;TFdi|sc+vDIyp5}PJ3D3#BwT+ya=4IWe4TzRlHxmkM; zmi$PwEVw~F6V)jXO0wT558cwc9Ni6d#3ot}!Vr_O5=f~v?hIDHFU~UhG|wy*7A=Lt{+2j5PLAIi_3jdx88{R zoNcw%s=TOl5k3b#_~nJ{3>n#itLlQ{AcN#z%dn5{Clq(kkG|a4xJrA^d}TJW&Y>mh zS89jyLaO(_40ngX$Sr2llD_XchHZXvY(o|gMMPBV_>aG zUJowJ-3s;;<_jNUd<%WuauV!~mxJmH@qiX~gv-a*-G*W)W|o$=3EheJX0^1<@Yr~;u~C3MBzYOrjg4z7jOE=`xExgN&~RCRgje`066}>@z^aX> zor@Ms{o^=c$vC1eT8lp;(1gAjBZ8Ueg|Sg@nKc%qCv*61e%!LB`wOHBc^WR=Ul<1a z1cPt!{sthYjpUt;EVAReTAf_M3MV3_3*jnH*ZR`Ef&=_O*LwVs23wn_txkj}bC_+x zv4X^_@+5Hkh@Hn{gRxlYs;FW0M`rIecb^tsIoOjTu8{diO~ic>D0o{qGCl|2FHQAw z0Dr6|hrQoLrIT8ft73V64vc*=p*9Qe!NW)k5@On7_Y$36y$f?{GHC~BGJz?lb3Z+D zA0L8bY9%bo$^h8LhDhknmp_69(Q(UAycky+>qzB9?%1&qbEyJ^MJkX=6v_UGeU|QG zDMk6{YtS5%>x11-(d6j|4VtF~7l>agx*Or(`$z)MOlQ0^ga%hjfvXH2q=XhK#Q2E9 zJ9&8aX!sExE{KO)yzpVga0NG;B_dDDT*U35A6(%y2ip^s78RxutTZ1G#vJnEbu?Ty z0ar5%mJTxs8EJB)?09)CNtGe1hfN!z5(n_-VC3Y6GM6Ca2)cU*;o|Wz=`s|A^otDK zOF2P#cMw*T0&<`fhasQfiN+k>9*Tp^8vpkgayL(;Q64>+t?Q+e86N_E;s#Td1nC`? zj!c&J`}mIi+uvbHY3CxzG8e2jutw6e8h_G0tWmBLU=n`7dXwCbR(+XwRNP~!QSB)> zY}TM|+f6cVjG(v!$iV)9a^g3-{)1NvTPZwCmJz6gd9VwnP_Dw|PWil;kdUl6Ok^gq z5M|};LoP=~{}Xa>JgoW==n3LjS@rj^7o7!fq5U=Qq=`&=44F%TjDC@JGViajwNHfF zf~+H8o052wWV=z;$wHayJaDiG-v?sE5{81Hg>csTYt-T!MppE$MRbj7WhZ|-+LB(r z`_mo{0rHceAbTeskiX`7s}gKn=>w{b^JGXtyu`C?1^v7MMdWMIs* zD|jFdjg6Esb_)g`3nQ*V7ZF>uQG~I(7V5;DftF(ht_4>+qV*03$xYB?Zm8{N$LN?$ zCQ0Wt`y92_Cj1?k>eKDMGq|9i;y%<=J=E?yEi6DuxTLf$13Xm3H|#Gb^(o2$;j=!h zZ_2?O^nk0t*H7xCK2x2fXNY@z!x#IUA^KxBP_6VS(E5POi?PYXI57ZAw%8vV%E77vbgxm0=R^qxEnJ-ua7%e*1sYOS<5PQx+!BRp=&hY6Jxax(HckA z0r9^J;|;JMn$<(DIMTi0aDb84vx*hJIMybb#LSI|vA>P<`F{ZjH1`>sa!&kVGakmT zZ}9HoGz?8MaLHhONQ}|Z&*4q&(2Mb|f+7_JSk3de`2@R@*|<3nU`u}i$uC=*PJ;{b zzAphKK*&{+4N^(RaQ)UqK-Bu$gqxX3~Rl=_V?cD{eLNXe&B4lWiEQ zc``x3;x3KeV}nwbionJ|xU~h?QPj*&Z2?9+{rGK&OF-X8u>m&i2_(gK@#PLIMB^5n zR1{=R(ii`eCaLb`!z$aGtomnIU;3IIP0mDbBcGh7FccGDbjCgaYQaLC~2uxM>INhr^(i7Sa#5#kIsRQ^Ea=B=Bo?q_vq!81tdh7XQa!u+o;$ zZ)Pd|PA#V2IbQlLnv36>ZJ9ytq^;u4)B^4#%;wIFeC}K^3(gY{CEN-}^9e1>xNC1& z0T=Jqx2&Zwf8w+w;VEom^w{VQN^Dt%5bj0dHyICtb|fs}se-_H0rNf79b_3{zJ+SO zJlgUYfS@b;9az39^a{7q4L0%S7o&+v5djF8K^FEP!33%7a~>Fttth5;Z8=@C40eXl zeVB{ar3pecj+S^=^Y8V6*I>oT&`O8hoh%2E0_X!>nt$fanm_kumVr@F4m$o$9Y{(} zoV1qvq4+w2N@DMSn%vGoe*|lo`LZXVW|D4`w3>!=9sZKyEJI54;1Bd|xB^;D&G~y3 zs~)K}H~$`b&GSvYX7TSGY%!|V$g>6>eGeVsV^4&}6r1kWwHn$5dE9+=!U0=dxl_B@ zSy=9n6S%6gt)l!7>p(VoYRp3`ta_tEU1(SDaxO3Tuc)f7S_uuNaU?c{xUA+pJOS8H z@FxgRN%-S`7`;6<2gWgU%d^buH}7qkjzhop#^Qo3TygXq#-Zjx7tqLOB6y1e4gbN=5-iS)>5U445 z?iCi3kbPJ87gqO6FW~9Pe)Hj3x^|1&h_UQO-7r4>85qh6699AGX?#d#H*Kb=)XP+5 zxXcB!PhSp2zJNT1z9I3U78CL8@frCm3tBxc9c;ON9P-x^@}B6%Ni3Z(ANHJ;f*nbO zxzgd#FYvR?KmRWBcwo%xh7dxU4{IP)(Z}&O(ZgDNQAI^zb&hPWsL&H3J2qsP)(lmm zV{=Vm2U<|cvWT5WJ|@BgAxTx__8yuQWy9{bSni)kc}Z?4!I!#pYzBrr6RKM(DOPUQ zsI0@!{+k4N2Xnt~bt^9)qZLjloC>nXQ$h9^732^V&|f|zE@qSpvWW^n0?={mTer+@ zF#6~%o7v;X{!K6*-yQoRqSexXMAVvBAq$^QdAL;BF~f%H1Wbgu8w=kGsp*wcK67 zuH^12b_sWHWz)F3mQCVrkfn3?ZkEX1b!;R;EtJ>*cQ>)Gxx1Nt0hdtN9l}gvT@<^! zk-TqlZxeYBaPKzq?%`gNIkFeH_Yv~$;NHi``!C%41bH>?eTuvx?tPlPGWR}9-dgVE z68tsX+e)#^xc4A=7jthXdFOF2Cab{Q@N$$%2G3^j1X2yK3%Iw7ydw7=C$F7*yUBZc z8#S+oykB!KBk$+jdxE@O+{=aZZ*gxQ#U9|^e)8_&-XZe7z`eud-NC)Y__KfEUb5R1{w zm;z5iYb@qIGiI(Q;b1K04l~Bk*1(S1Nvs#%s)2+az~V{4T1ya8JuhU74?jhtV>%oN;_cv@9D@h2KnwC*&3c_hz7m-( zx$ZWLJR=1cW~0n?-2$sT8IcpNyUixMptZrDRZQu@K@#Vmw(V0|k9I4qmbSqIphW!f z%4REYK`~zf0c1Kpc)&{WPuFNjpz_~FY&(_zI?CS%0f^od$LN38KF#0_bK-CG@rIp@ zl%Rj9Wn+iI0Q0nAH0b_>e+R!YKLWAUK#0~{3tkc%vC7#4-eSA~hoN)$b7Cf|5@3}`{d=?Is&?2V(={(=C3^^?UPVVhQuPtZxPn7; zc6=7`F$2jdtddA0M__Z|ju}c4lIOg|lph1j90g;0e+B9H|KhKFJVnij8%)yQ_=F)7 znU2z#6Mx^c4aNLpTgU~d&$NXcqGHDSm%oQ7O~Ye?7tnt0_^Dwu)Hnyvl4J@8c03r5 z=MB;5_`t?ovL|)q;TEN6i%vO|8m;R6w-4w~%fw=n;<1g0r7WO_%0LC=6RC%!GEg=| zZhIE|{+8W2ME94Z^fV_)mx7uu1|{I_r0c${OT6y$jaKUy*LA?x24DMi-56}VsdUtR z=(=tx`DHB3MxAx=V=cOp{*vOG#*A)^@BjJt|IZ#M{jDJU%YO;N)A)AdYsYsS-(T@r zUlfFNd>7!m2Hy?%R^h9|w*}uL_@2hM8{fP5`taFz3PJ|HTzm!imf*Vu-#UDo@jZy| z*Z6kgYsL2=K8DW)Jf`8x$F~CCt@t+Mdl=sf_}cNki?18s*Z79;{a@`}3wRXO**>`- zsp4=!E!xm>nc3`R?z2_55QHk$ z3tp(=Z){OPK~N$h#TpA!O<^v^u_9bVZxrYhgQEm^X<||M zHXwq}B>F%+R)UN1;Kye4C}5=38(cRTWgF3(I6{7WQjI27i{7>(B>);Rm^eNwlb|Xfs#7`6# zQ8a4=krRe4Z0HU3(&V}csc|DtC1-*+llKJLrQVYUdAP#b|*J?MoICutB*ltNZO^7I3}B^5S!Bo7a ztkn+R)y|Raim3F|H_^7_T>|^8Mx69QvNv-~36rddztLZdU1auy>*|NalO?w!^&pTT zZ#xsZ>XWwp#;7p+L!;|RG;D^=k={)dKMr3(_b^%I&zD>b(r3s>)&XP zMiPzDf2TcXS9?*|q^bK^pcMnnB;*%@)OwE`Yb(A#Lh}^a%)g%R`84|>{(94Cf|O~NqnbxNt@Owl0MA}3CyQ7k2WHOR-Rh)#*(c$Gm~U29hr2vH2w779*C-GgJc)9X4C3z zQnu)J>!<&8{pdvl)x(_K z%{pXV-LfFtq8;(zTksw|{PvsiED3%ie7f_n!Ow@kd8wD3Na^rTqICEtQ~FK#PjmRw z;Nx{$mIwcI_)Bl}vhTt#gg+Gi?q7M?_b44cekO+PSmFhzpa*{#{FcSIr-NS&zZJd! z|6=$<;nQhb0epJb@zC{N+<(y6p!Jc)OufdUHfMzr_G4T&%#>u=WWna$RRuz| zs7cbMRv7wd-d~Nz8ZsJj1#%4D4^`WbGioz-2Ew_i@QrEVYY`@Wko#p?_`0<4qO|b!Y2n3b;TzJz^iwky&4<#$ zblO5X2R-8{{JE?QlADOn3fvRgA(v8wDv*o&^H97zrt9Qa>523Fp`;N$CoNnY3PtLu z>^NK!WY>gGx)UT9NL?c#iOSSPGhTpEN^9z3M$Q-`eTGIdfFsoZj5x5szN^9*QS>$hNaN>qxFj11cd3n&kEE0NUqqh54w*d9?6dC zFzY}r$S2Dp3$$!&0>ZTOuu@EZEgl)}%xTWXd-(=GM4Nc9+BW@gsvY9QY};zrYLm)Q zJ4A<8Ct4|K-ZXhHM=Y2YuLieNBA%93gZ2ZUK=-v)&1#fNk5@vjbhmBMtwMg!IJHeY zQG2vsp>`NEX;Yl&5${BYc%}OEcTQ4MlSDft*aqB4TP2*00|_&d}3r)S9nrgB0|YkdNg4r7AG5$aWFO^88T>0NQMnX7Dr=2Lx=uYouNOy zHkS0q%rgG45kxx-^cm<9O$J&-2MDuDe=7qG_%T+l*Rl!zFst$>lCc0X;L2k`BUIg( zjKx!FHF_Ydry|u!GgKJ~8@W}EwErxAtV`F1p-oTb< zv^g5>v0udiPVH4|g5f}u=DEwb_PCae#kkh|A^o;MFX&d(a9}GY1>>n16_|cC?jv76NKe^z-i+(zNhQGEhpw~Av27fj))D(_He;$h` zlCzpyS}(q2_MA&EVb|nG`gd9Nd-wj!rhL%|pq2`7SuIkmJDiWNBYhc{S-yY0?Jkwiy2ECOzLCjT+uV7V zUorp6s}@{+%`X;S`^)PVUBCE-CBM4yrlmLE^6O={-gf))6)W#pwffFAYkzas-Rti8 z?Y;Ni|G@eOAA0za4ZnNzv5k-a?-T7${{9b}o_hM3&0C&*ZtJ$^x9@o2#ho25?Rt6l zD|`O9_tihW*7^FM_w9e<&A0H#@-GM8eeeAbKK$t5p^rcL>*2rs{U4wH^Rv&{S6v|b zUI6;FKz!T%|F+xz%JToB1-kEiV}bs*`#K%{O3>YnZF~We%X+o`CHTSUp>>yJ_N{F^fT*E8qqU9y*}0Z z%9FFMbanB}be_B1}Iu5eDz{LFq1_VvuqQ?O@#X8S=r zA0yXS{dc21^V8eEH-Wz}1jt$SGxfD>R?qxQ{)V*t>-?K9?U|n`pR=y@vKhYx11Wb6 z!udGp@ZDpj;5p-Zgz4bo2=3_fRO~|`pCdg_ZO*RJ!-3T9tQi00%*wIvGdFF;Y-&~6 zlp_1+KnPppDXb(EiRET3mBMJn@V>Hes3z{H+2!scPpd#o&+ z&|@XBU?N!O4^?3=N}E$A=2YnZS$ePZD~;A7O-*3BA{f?-*-nERj;zx5u#BBGpavuj zR@sRIYJvg1q|qO%j#MT?iQw4QgwAd;DTU*akY3`$^Y65HWh8*Jgq@H`qamC?SxX&` z9>5v;4t5z^or@Ox&dwPhFV$<44GntC7t`Yq4SNSYtpi*JesXW#VYU7&vcZi0TQ5;53wyoT)|-j0;Pp31Eb#ZzaX&rlcz z&2!St6a#B!>}iS_rv5(U0bS$Nbfz8{AFhk()D&ZJ>Ia>$q(;YI(#ydtta58|CMWe+ zt51&^$1~wN-H;!w=LYIkb+B$`O7c(kwiFD*RztF_aU7ae2b=WbxFK_dSUqt-G0Pm; zaC5|zM2rzp!)mh1L&$*G9=F>Y&PIFN${y=d6-6x|f+b!qcU4GS8)8(JYNLFrLB z6(yK=Oidx)VUB#*8vgXMY|6y43TtLN!jkc=CQ;}8P<)0zMgKVt3lnE?0zDvs>%>>0 zE#KUs8BuzXrI({;J6XL_yAvp%aMT@@z?YSPWmn{%3Rt#8dmRer0`zPU$J2P4X}oV` zJZHk2RK|0ryp&JRo(2K*B#!dv*_f3_bg3@+Cjdm3%$(9r1WrnU(uV<*?gS`aoQjvE z;+SlVI#W{VRVg2nghBs&_|!H%7a%%KfDMQO^b8XVy1_sFG86IB1`yA4Q~o^o)R)Tv z%D)02I=E#u-aNZ46<-0L_*(@~dusqH_Xt3JdLE$smjTKj455&G2qYKFHD2#!(}4eU z_eE!1*%>Y;W=HuMVtbWI{QY9_ls%XV6zpwPZ^1p0(i;m@6^}kJ@eIJ^AQyhN%?eu8^sXLuMO~Cf`^Y#t4 z@E>jp^y7+I*|~YEaAPoIUhBMJDbd~eni*KJ+Vtn%-bt_eFz=;phQAi&pS)ww9X2z& z*XP{N%p`Bhf2g13i&NzvM)~b4_pdyiy|MD`l^66)|I!skjmfx?nY`zxdu(j_o}cZp z_b$J4_n$id#u$I8$r+uSm7vtnVHz-%A^ga9fZ04@ZofpLHrZ~%qCaKHu>01P;E8{YlO z?cOgOKzu*27w7=C0-J!1z&c z9l%E5K429<<(I-=2+Rf=foVV~zyXDT4HyLMUxxYsxvy)jq@UnScV9J5d}i{x;Q8)0 z7OjK~)<6bpy^MZPl76m{K;uZfrhg!Qm#pfhNpb5Om%`+1`1dw5WPXl@M`!~tp+9~x zE=##9P(F(CeS!K$eOe5DvO%BvPVHpM07?Jd4y)RJNZ`AijXRrrmpjN6@Gd^eZ{>IL z=NHvGLXJxvm9Bwqms@e4>wd!BC_F2?AvB9~#GAxB#r5J7;&ySD_=fnQ_?h^9$svuE zY9zmOmGr2zMS4;CL^@0UiM&u=CEqQtmp8~8<#zf1e3X=tCecww58hP z+Oyir+CJ@l?PG1A=LFB`9>1sF6ZPEXx!3csXQKz5vzhy=5j@A=%pc}|ZGX&ucTq>t zD95jzNmrSBmV2RloBM$KYT+?qpK!dyNwV})=^k*OC%-L!B!4ce;B&H4qbyPGQ+6tE zD#KJwU95(*gtkyyqkX1{o?_2=Xcuj9^bR6pRR@WNWHdlx1J=e!BoBQ|fm)vi;M+@bGPnaphg;wDz^n0`Ls_;MJkHuzjwYXJ$ zMSM*Z6pu1pnXmjpc}V%YlBJ%iUZggl*LSI#p@E^=XzfDnGHt%LR(nj_sU6hHJz>u^ zo;y7|J@iE;FAX&AI8Nlw;TpIoH=A3}ZR9p{S^Tm5sr(q;$Dhx)@z?T;`Q`j}eiz@# zf5d;sewzIZyVrh>eTF?@zu11c{YLwv_P^UF7KMvuJLWo`bG+af?kaN4bR}I6yPkAC z=i2Lf%e6+>AhZil3(pBJ2&z~jP8Y8dcY^=-#DijiG(?i5VyRN9lBP?#6qXXw9O-K5 zI_W0qR_Qm=z0yYMX=$spOFAqaFBi#ixmCVH{*8RE{1kMPqs)O--lhCmc}FQyMRk%| ztzM|sszEiP&QfQqSE#>G7pY6t73w|e1L`B{E*%#;bvilutvCFctm(ocm~?ugPG_Z z;h^wOArE@L2)5fQx5-z^JC#?Iead9DMyp|NGs zDruecAS`whEVe`1EA5vKNQb0PrCfQCTp$mXhs&tE9N)Qww}4;BcZj>i!IB_NgVnc4 zOQj8{*(ovECVS->kkmqXt^A<8L;gS>q~t3cX5lC-VG-uI9m)qvzRKDeqhEskTsQyx?{U`A|LHYuB7l{;XUyJ4A~%6{c-IwtPWLe>Tp=@NR?9^SV5MmYt;>yt9D}~=4pepe62tmjIn6LXe`u5 zVmvxDp=%xSX$vryFVdD^MOmgT*H&R(Tc>T%HfrtKCT+8}RokI;XuGw&S|@4hs5>fw SqY^kOfuj;QDuMrK3H(1XaR1u? literal 0 HcmV?d00001 diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/.npmignore b/tasks/enduro-trails/prototype/node_modules/tweetnacl/.npmignore new file mode 100644 index 0000000..7d98dcb --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/.npmignore @@ -0,0 +1,4 @@ +.eslintrc +.travis.yml +bower.json +test diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/AUTHORS.md b/tasks/enduro-trails/prototype/node_modules/tweetnacl/AUTHORS.md new file mode 100644 index 0000000..6d74d40 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/AUTHORS.md @@ -0,0 +1,28 @@ +List of TweetNaCl.js authors +============================ + + Alphabetical order by first name. + Format: Name (GitHub username or URL) + +* AndSDev (@AndSDev) +* Devi Mandiri (@devi) +* Dmitry Chestnykh (@dchest) + +List of authors of third-party public domain code from which TweetNaCl.js code was derived +========================================================================================== + +[TweetNaCl](http://tweetnacl.cr.yp.to/) +-------------------------------------- + +* Bernard van Gastel +* Daniel J. Bernstein +* Peter Schwabe +* Sjaak Smetsers +* Tanja Lange +* Wesley Janssen + + +[Poly1305-donna](https://github.com/floodyberry/poly1305-donna) +-------------------------------------------------------------- + +* Andrew Moon (@floodyberry) diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/CHANGELOG.md b/tasks/enduro-trails/prototype/node_modules/tweetnacl/CHANGELOG.md new file mode 100644 index 0000000..92a4fdc --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/CHANGELOG.md @@ -0,0 +1,221 @@ +TweetNaCl.js Changelog +====================== + + +v0.14.5 +------- + +* Fixed incomplete return types in TypeScript typings. +* Replaced COPYING.txt with LICENSE file, which now has public domain dedication + text from The Unlicense. License fields in package.json and bower.json have + been set to "Unlicense". The project was and will be in the public domain -- + this change just makes it easier for automated tools to know about this fact by + using the widely recognized and SPDX-compatible template for public domain + dedication. + + +v0.14.4 +------- + +* Added TypeScript type definitions (contributed by @AndSDev). +* Improved benchmarking code. + + +v0.14.3 +------- + +Fixed a bug in the fast version of Poly1305 and brought it back. + +Thanks to @floodyberry for promptly responding and fixing the original C code: + +> "The issue was not properly detecting if st->h was >= 2^130 - 5, coupled with +> [testing mistake] not catching the failure. The chance of the bug affecting +> anything in the real world is essentially zero luckily, but it's good to have +> it fixed." + +https://github.com/floodyberry/poly1305-donna/issues/2#issuecomment-202698577 + + +v0.14.2 +------- + +Switched Poly1305 fast version back to original (slow) version due to a bug. + + +v0.14.1 +------- + +No code changes, just tweaked packaging and added COPYING.txt. + + +v0.14.0 +------- + +* **Breaking change!** All functions from `nacl.util` have been removed. These + functions are no longer available: + + nacl.util.decodeUTF8 + nacl.util.encodeUTF8 + nacl.util.decodeBase64 + nacl.util.encodeBase64 + + If want to continue using them, you can include + package: + + + + + or + + var nacl = require('tweetnacl'); + nacl.util = require('tweetnacl-util'); + + However it is recommended to use better packages that have wider + compatibility and better performance. Functions from `nacl.util` were never + intended to be robust solution for string conversion and were included for + convenience: cryptography library is not the right place for them. + + Currently calling these functions will throw error pointing to + `tweetnacl-util-js` (in the next version this error message will be removed). + +* Improved detection of available random number generators, making it possible + to use `nacl.randomBytes` and related functions in Web Workers without + changes. + +* Changes to testing (see README). + + +v0.13.3 +------- + +No code changes. + +* Reverted license field in package.json to "Public domain". + +* Fixed typo in README. + + +v0.13.2 +------- + +* Fixed undefined variable bug in fast version of Poly1305. No worries, this + bug was *never* triggered. + +* Specified CC0 public domain dedication. + +* Updated development dependencies. + + +v0.13.1 +------- + +* Exclude `crypto` and `buffer` modules from browserify builds. + + +v0.13.0 +------- + +* Made `nacl-fast` the default version in NPM package. Now + `require("tweetnacl")` will use fast version; to get the original version, + use `require("tweetnacl/nacl.js")`. + +* Cleanup temporary array after generating random bytes. + + +v0.12.2 +------- + +* Improved performance of curve operations, making `nacl.scalarMult`, `nacl.box`, + `nacl.sign` and related functions up to 3x faster in `nacl-fast` version. + + +v0.12.1 +------- + +* Significantly improved performance of Salsa20 (~1.5x faster) and + Poly1305 (~3.5x faster) in `nacl-fast` version. + + +v0.12.0 +------- + +* Instead of using the given secret key directly, TweetNaCl.js now copies it to + a new array in `nacl.box.keyPair.fromSecretKey` and + `nacl.sign.keyPair.fromSecretKey`. + + +v0.11.2 +------- + +* Added new constant: `nacl.sign.seedLength`. + + +v0.11.1 +------- + +* Even faster hash for both short and long inputs (in `nacl-fast`). + + +v0.11.0 +------- + +* Implement `nacl.sign.keyPair.fromSeed` to enable creation of sign key pairs + deterministically from a 32-byte seed. (It behaves like + [libsodium's](http://doc.libsodium.org/public-key_cryptography/public-key_signatures.html) + `crypto_sign_seed_keypair`: the seed becomes a secret part of the secret key.) + +* Fast version now has an improved hash implementation that is 2x-5x faster. + +* Fixed benchmarks, which may have produced incorrect measurements. + + +v0.10.1 +------- + +* Exported undocumented `nacl.lowlevel.crypto_core_hsalsa20`. + + +v0.10.0 +------- + +* **Signature API breaking change!** `nacl.sign` and `nacl.sign.open` now deal + with signed messages, and new `nacl.sign.detached` and + `nacl.sign.detached.verify` are available. + + Previously, `nacl.sign` returned a signature, and `nacl.sign.open` accepted a + message and "detached" signature. This was unlike NaCl's API, which dealt with + signed messages (concatenation of signature and message). + + The new API is: + + nacl.sign(message, secretKey) -> signedMessage + nacl.sign.open(signedMessage, publicKey) -> message | null + + Since detached signatures are common, two new API functions were introduced: + + nacl.sign.detached(message, secretKey) -> signature + nacl.sign.detached.verify(message, signature, publicKey) -> true | false + + (Note that it's `verify`, not `open`, and it returns a boolean value, unlike + `open`, which returns an "unsigned" message.) + +* NPM package now comes without `test` directory to keep it small. + + +v0.9.2 +------ + +* Improved documentation. +* Fast version: increased theoretical message size limit from 2^32-1 to 2^52 + bytes in Poly1305 (and thus, secretbox and box). However this has no impact + in practice since JavaScript arrays or ArrayBuffers are limited to 32-bit + indexes, and most implementations won't allocate more than a gigabyte or so. + (Obviously, there are no tests for the correctness of implementation.) Also, + it's not recommended to use messages that large without splitting them into + smaller packets anyway. + + +v0.9.1 +------ + +* Initial release diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/LICENSE b/tasks/enduro-trails/prototype/node_modules/tweetnacl/LICENSE new file mode 100644 index 0000000..cf1ab25 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md b/tasks/enduro-trails/prototype/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..a8eb4a9 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ +# Important! + +If your contribution is not trivial (not a typo fix, etc.), we can only accept +it if you dedicate your copyright for the contribution to the public domain. +Make sure you understand what it means (see http://unlicense.org/)! If you +agree, please add yourself to AUTHORS.md file, and include the following text +to your pull request description or a comment in it: + +------------------------------------------------------------------------------ + + I dedicate any and all copyright interest in this software to the + public domain. I make this dedication for the benefit of the public at + large and to the detriment of my heirs and successors. I intend this + dedication to be an overt act of relinquishment in perpetuity of all + present and future rights to this software under copyright law. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/README.md b/tasks/enduro-trails/prototype/node_modules/tweetnacl/README.md new file mode 100644 index 0000000..ffb6871 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/README.md @@ -0,0 +1,459 @@ +TweetNaCl.js +============ + +Port of [TweetNaCl](http://tweetnacl.cr.yp.to) / [NaCl](http://nacl.cr.yp.to/) +to JavaScript for modern browsers and Node.js. Public domain. + +[![Build Status](https://travis-ci.org/dchest/tweetnacl-js.svg?branch=master) +](https://travis-ci.org/dchest/tweetnacl-js) + +Demo: + +**:warning: The library is stable and API is frozen, however it has not been +independently reviewed. If you can help reviewing it, please [contact +me](mailto:dmitry@codingrobots.com).** + +Documentation +============= + +* [Overview](#overview) +* [Installation](#installation) +* [Usage](#usage) + * [Public-key authenticated encryption (box)](#public-key-authenticated-encryption-box) + * [Secret-key authenticated encryption (secretbox)](#secret-key-authenticated-encryption-secretbox) + * [Scalar multiplication](#scalar-multiplication) + * [Signatures](#signatures) + * [Hashing](#hashing) + * [Random bytes generation](#random-bytes-generation) + * [Constant-time comparison](#constant-time-comparison) +* [System requirements](#system-requirements) +* [Development and testing](#development-and-testing) +* [Benchmarks](#benchmarks) +* [Contributors](#contributors) +* [Who uses it](#who-uses-it) + + +Overview +-------- + +The primary goal of this project is to produce a translation of TweetNaCl to +JavaScript which is as close as possible to the original C implementation, plus +a thin layer of idiomatic high-level API on top of it. + +There are two versions, you can use either of them: + +* `nacl.js` is the port of TweetNaCl with minimum differences from the + original + high-level API. + +* `nacl-fast.js` is like `nacl.js`, but with some functions replaced with + faster versions. + + +Installation +------------ + +You can install TweetNaCl.js via a package manager: + +[Bower](http://bower.io): + + $ bower install tweetnacl + +[NPM](https://www.npmjs.org/): + + $ npm install tweetnacl + +or [download source code](https://github.com/dchest/tweetnacl-js/releases). + + +Usage +----- + +All API functions accept and return bytes as `Uint8Array`s. If you need to +encode or decode strings, use functions from + or one of the more robust codec +packages. + +In Node.js v4 and later `Buffer` objects are backed by `Uint8Array`s, so you +can freely pass them to TweetNaCl.js functions as arguments. The returned +objects are still `Uint8Array`s, so if you need `Buffer`s, you'll have to +convert them manually; make sure to convert using copying: `new Buffer(array)`, +instead of sharing: `new Buffer(array.buffer)`, because some functions return +subarrays of their buffers. + + +### Public-key authenticated encryption (box) + +Implements *curve25519-xsalsa20-poly1305*. + +#### nacl.box.keyPair() + +Generates a new random key pair for box and returns it as an object with +`publicKey` and `secretKey` members: + + { + publicKey: ..., // Uint8Array with 32-byte public key + secretKey: ... // Uint8Array with 32-byte secret key + } + + +#### nacl.box.keyPair.fromSecretKey(secretKey) + +Returns a key pair for box with public key corresponding to the given secret +key. + +#### nacl.box(message, nonce, theirPublicKey, mySecretKey) + +Encrypt and authenticates message using peer's public key, our secret key, and +the given nonce, which must be unique for each distinct message for a key pair. + +Returns an encrypted and authenticated message, which is +`nacl.box.overheadLength` longer than the original message. + +#### nacl.box.open(box, nonce, theirPublicKey, mySecretKey) + +Authenticates and decrypts the given box with peer's public key, our secret +key, and the given nonce. + +Returns the original message, or `false` if authentication fails. + +#### nacl.box.before(theirPublicKey, mySecretKey) + +Returns a precomputed shared key which can be used in `nacl.box.after` and +`nacl.box.open.after`. + +#### nacl.box.after(message, nonce, sharedKey) + +Same as `nacl.box`, but uses a shared key precomputed with `nacl.box.before`. + +#### nacl.box.open.after(box, nonce, sharedKey) + +Same as `nacl.box.open`, but uses a shared key precomputed with `nacl.box.before`. + +#### nacl.box.publicKeyLength = 32 + +Length of public key in bytes. + +#### nacl.box.secretKeyLength = 32 + +Length of secret key in bytes. + +#### nacl.box.sharedKeyLength = 32 + +Length of precomputed shared key in bytes. + +#### nacl.box.nonceLength = 24 + +Length of nonce in bytes. + +#### nacl.box.overheadLength = 16 + +Length of overhead added to box compared to original message. + + +### Secret-key authenticated encryption (secretbox) + +Implements *xsalsa20-poly1305*. + +#### nacl.secretbox(message, nonce, key) + +Encrypt and authenticates message using the key and the nonce. The nonce must +be unique for each distinct message for this key. + +Returns an encrypted and authenticated message, which is +`nacl.secretbox.overheadLength` longer than the original message. + +#### nacl.secretbox.open(box, nonce, key) + +Authenticates and decrypts the given secret box using the key and the nonce. + +Returns the original message, or `false` if authentication fails. + +#### nacl.secretbox.keyLength = 32 + +Length of key in bytes. + +#### nacl.secretbox.nonceLength = 24 + +Length of nonce in bytes. + +#### nacl.secretbox.overheadLength = 16 + +Length of overhead added to secret box compared to original message. + + +### Scalar multiplication + +Implements *curve25519*. + +#### nacl.scalarMult(n, p) + +Multiplies an integer `n` by a group element `p` and returns the resulting +group element. + +#### nacl.scalarMult.base(n) + +Multiplies an integer `n` by a standard group element and returns the resulting +group element. + +#### nacl.scalarMult.scalarLength = 32 + +Length of scalar in bytes. + +#### nacl.scalarMult.groupElementLength = 32 + +Length of group element in bytes. + + +### Signatures + +Implements [ed25519](http://ed25519.cr.yp.to). + +#### nacl.sign.keyPair() + +Generates new random key pair for signing and returns it as an object with +`publicKey` and `secretKey` members: + + { + publicKey: ..., // Uint8Array with 32-byte public key + secretKey: ... // Uint8Array with 64-byte secret key + } + +#### nacl.sign.keyPair.fromSecretKey(secretKey) + +Returns a signing key pair with public key corresponding to the given +64-byte secret key. The secret key must have been generated by +`nacl.sign.keyPair` or `nacl.sign.keyPair.fromSeed`. + +#### nacl.sign.keyPair.fromSeed(seed) + +Returns a new signing key pair generated deterministically from a 32-byte seed. +The seed must contain enough entropy to be secure. This method is not +recommended for general use: instead, use `nacl.sign.keyPair` to generate a new +key pair from a random seed. + +#### nacl.sign(message, secretKey) + +Signs the message using the secret key and returns a signed message. + +#### nacl.sign.open(signedMessage, publicKey) + +Verifies the signed message and returns the message without signature. + +Returns `null` if verification failed. + +#### nacl.sign.detached(message, secretKey) + +Signs the message using the secret key and returns a signature. + +#### nacl.sign.detached.verify(message, signature, publicKey) + +Verifies the signature for the message and returns `true` if verification +succeeded or `false` if it failed. + +#### nacl.sign.publicKeyLength = 32 + +Length of signing public key in bytes. + +#### nacl.sign.secretKeyLength = 64 + +Length of signing secret key in bytes. + +#### nacl.sign.seedLength = 32 + +Length of seed for `nacl.sign.keyPair.fromSeed` in bytes. + +#### nacl.sign.signatureLength = 64 + +Length of signature in bytes. + + +### Hashing + +Implements *SHA-512*. + +#### nacl.hash(message) + +Returns SHA-512 hash of the message. + +#### nacl.hash.hashLength = 64 + +Length of hash in bytes. + + +### Random bytes generation + +#### nacl.randomBytes(length) + +Returns a `Uint8Array` of the given length containing random bytes of +cryptographic quality. + +**Implementation note** + +TweetNaCl.js uses the following methods to generate random bytes, +depending on the platform it runs on: + +* `window.crypto.getRandomValues` (WebCrypto standard) +* `window.msCrypto.getRandomValues` (Internet Explorer 11) +* `crypto.randomBytes` (Node.js) + +If the platform doesn't provide a suitable PRNG, the following functions, +which require random numbers, will throw exception: + +* `nacl.randomBytes` +* `nacl.box.keyPair` +* `nacl.sign.keyPair` + +Other functions are deterministic and will continue working. + +If a platform you are targeting doesn't implement secure random number +generator, but you somehow have a cryptographically-strong source of entropy +(not `Math.random`!), and you know what you are doing, you can plug it into +TweetNaCl.js like this: + + nacl.setPRNG(function(x, n) { + // ... copy n random bytes into x ... + }); + +Note that `nacl.setPRNG` *completely replaces* internal random byte generator +with the one provided. + + +### Constant-time comparison + +#### nacl.verify(x, y) + +Compares `x` and `y` in constant time and returns `true` if their lengths are +non-zero and equal, and their contents are equal. + +Returns `false` if either of the arguments has zero length, or arguments have +different lengths, or their contents differ. + + +System requirements +------------------- + +TweetNaCl.js supports modern browsers that have a cryptographically secure +pseudorandom number generator and typed arrays, including the latest versions +of: + +* Chrome +* Firefox +* Safari (Mac, iOS) +* Internet Explorer 11 + +Other systems: + +* Node.js + + +Development and testing +------------------------ + +Install NPM modules needed for development: + + $ npm install + +To build minified versions: + + $ npm run build + +Tests use minified version, so make sure to rebuild it every time you change +`nacl.js` or `nacl-fast.js`. + +### Testing + +To run tests in Node.js: + + $ npm run test-node + +By default all tests described here work on `nacl.min.js`. To test other +versions, set environment variable `NACL_SRC` to the file name you want to test. +For example, the following command will test fast minified version: + + $ NACL_SRC=nacl-fast.min.js npm run test-node + +To run full suite of tests in Node.js, including comparing outputs of +JavaScript port to outputs of the original C version: + + $ npm run test-node-all + +To prepare tests for browsers: + + $ npm run build-test-browser + +and then open `test/browser/test.html` (or `test/browser/test-fast.html`) to +run them. + +To run headless browser tests with `tape-run` (powered by Electron): + + $ npm run test-browser + +(If you get `Error: spawn ENOENT`, install *xvfb*: `sudo apt-get install xvfb`.) + +To run tests in both Node and Electron: + + $ npm test + +### Benchmarking + +To run benchmarks in Node.js: + + $ npm run bench + $ NACL_SRC=nacl-fast.min.js npm run bench + +To run benchmarks in a browser, open `test/benchmark/bench.html` (or +`test/benchmark/bench-fast.html`). + + +Benchmarks +---------- + +For reference, here are benchmarks from MacBook Pro (Retina, 13-inch, Mid 2014) +laptop with 2.6 GHz Intel Core i5 CPU (Intel) in Chrome 53/OS X and Xiaomi Redmi +Note 3 smartphone with 1.8 GHz Qualcomm Snapdragon 650 64-bit CPU (ARM) in +Chrome 52/Android: + +| | nacl.js Intel | nacl-fast.js Intel | nacl.js ARM | nacl-fast.js ARM | +| ------------- |:-------------:|:-------------------:|:-------------:|:-----------------:| +| salsa20 | 1.3 MB/s | 128 MB/s | 0.4 MB/s | 43 MB/s | +| poly1305 | 13 MB/s | 171 MB/s | 4 MB/s | 52 MB/s | +| hash | 4 MB/s | 34 MB/s | 0.9 MB/s | 12 MB/s | +| secretbox 1K | 1113 op/s | 57583 op/s | 334 op/s | 14227 op/s | +| box 1K | 145 op/s | 718 op/s | 37 op/s | 368 op/s | +| scalarMult | 171 op/s | 733 op/s | 56 op/s | 380 op/s | +| sign | 77 op/s | 200 op/s | 20 op/s | 61 op/s | +| sign.open | 39 op/s | 102 op/s | 11 op/s | 31 op/s | + +(You can run benchmarks on your devices by clicking on the links at the bottom +of the [home page](https://tweetnacl.js.org)). + +In short, with *nacl-fast.js* and 1024-byte messages you can expect to encrypt and +authenticate more than 57000 messages per second on a typical laptop or more than +14000 messages per second on a $170 smartphone, sign about 200 and verify 100 +messages per second on a laptop or 60 and 30 messages per second on a smartphone, +per CPU core (with Web Workers you can do these operations in parallel), +which is good enough for most applications. + + +Contributors +------------ + +See AUTHORS.md file. + + +Third-party libraries based on TweetNaCl.js +------------------------------------------- + +* [forward-secrecy](https://github.com/alax/forward-secrecy) — Axolotl ratchet implementation +* [nacl-stream](https://github.com/dchest/nacl-stream-js) - streaming encryption +* [tweetnacl-auth-js](https://github.com/dchest/tweetnacl-auth-js) — implementation of [`crypto_auth`](http://nacl.cr.yp.to/auth.html) +* [chloride](https://github.com/dominictarr/chloride) - unified API for various NaCl modules + + +Who uses it +----------- + +Some notable users of TweetNaCl.js: + +* [miniLock](http://minilock.io/) +* [Stellar](https://www.stellar.org/) diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.js b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.js new file mode 100644 index 0000000..5e4562f --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.js @@ -0,0 +1,2388 @@ +(function(nacl) { +'use strict'; + +// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. +// Public domain. +// +// Implementation derived from TweetNaCl version 20140427. +// See for details: http://tweetnacl.cr.yp.to/ + +var gf = function(init) { + var i, r = new Float64Array(16); + if (init) for (i = 0; i < init.length; i++) r[i] = init[i]; + return r; +}; + +// Pluggable, initialized in high-level API below. +var randombytes = function(/* x, n */) { throw new Error('no PRNG'); }; + +var _0 = new Uint8Array(16); +var _9 = new Uint8Array(32); _9[0] = 9; + +var gf0 = gf(), + gf1 = gf([1]), + _121665 = gf([0xdb41, 1]), + D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]), + D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]), + X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]), + Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]), + I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); + +function ts64(x, i, h, l) { + x[i] = (h >> 24) & 0xff; + x[i+1] = (h >> 16) & 0xff; + x[i+2] = (h >> 8) & 0xff; + x[i+3] = h & 0xff; + x[i+4] = (l >> 24) & 0xff; + x[i+5] = (l >> 16) & 0xff; + x[i+6] = (l >> 8) & 0xff; + x[i+7] = l & 0xff; +} + +function vn(x, xi, y, yi, n) { + var i,d = 0; + for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i]; + return (1 & ((d - 1) >>> 8)) - 1; +} + +function crypto_verify_16(x, xi, y, yi) { + return vn(x,xi,y,yi,16); +} + +function crypto_verify_32(x, xi, y, yi) { + return vn(x,xi,y,yi,32); +} + +function core_salsa20(o, p, k, c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + x0 = x0 + j0 | 0; + x1 = x1 + j1 | 0; + x2 = x2 + j2 | 0; + x3 = x3 + j3 | 0; + x4 = x4 + j4 | 0; + x5 = x5 + j5 | 0; + x6 = x6 + j6 | 0; + x7 = x7 + j7 | 0; + x8 = x8 + j8 | 0; + x9 = x9 + j9 | 0; + x10 = x10 + j10 | 0; + x11 = x11 + j11 | 0; + x12 = x12 + j12 | 0; + x13 = x13 + j13 | 0; + x14 = x14 + j14 | 0; + x15 = x15 + j15 | 0; + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x1 >>> 0 & 0xff; + o[ 5] = x1 >>> 8 & 0xff; + o[ 6] = x1 >>> 16 & 0xff; + o[ 7] = x1 >>> 24 & 0xff; + + o[ 8] = x2 >>> 0 & 0xff; + o[ 9] = x2 >>> 8 & 0xff; + o[10] = x2 >>> 16 & 0xff; + o[11] = x2 >>> 24 & 0xff; + + o[12] = x3 >>> 0 & 0xff; + o[13] = x3 >>> 8 & 0xff; + o[14] = x3 >>> 16 & 0xff; + o[15] = x3 >>> 24 & 0xff; + + o[16] = x4 >>> 0 & 0xff; + o[17] = x4 >>> 8 & 0xff; + o[18] = x4 >>> 16 & 0xff; + o[19] = x4 >>> 24 & 0xff; + + o[20] = x5 >>> 0 & 0xff; + o[21] = x5 >>> 8 & 0xff; + o[22] = x5 >>> 16 & 0xff; + o[23] = x5 >>> 24 & 0xff; + + o[24] = x6 >>> 0 & 0xff; + o[25] = x6 >>> 8 & 0xff; + o[26] = x6 >>> 16 & 0xff; + o[27] = x6 >>> 24 & 0xff; + + o[28] = x7 >>> 0 & 0xff; + o[29] = x7 >>> 8 & 0xff; + o[30] = x7 >>> 16 & 0xff; + o[31] = x7 >>> 24 & 0xff; + + o[32] = x8 >>> 0 & 0xff; + o[33] = x8 >>> 8 & 0xff; + o[34] = x8 >>> 16 & 0xff; + o[35] = x8 >>> 24 & 0xff; + + o[36] = x9 >>> 0 & 0xff; + o[37] = x9 >>> 8 & 0xff; + o[38] = x9 >>> 16 & 0xff; + o[39] = x9 >>> 24 & 0xff; + + o[40] = x10 >>> 0 & 0xff; + o[41] = x10 >>> 8 & 0xff; + o[42] = x10 >>> 16 & 0xff; + o[43] = x10 >>> 24 & 0xff; + + o[44] = x11 >>> 0 & 0xff; + o[45] = x11 >>> 8 & 0xff; + o[46] = x11 >>> 16 & 0xff; + o[47] = x11 >>> 24 & 0xff; + + o[48] = x12 >>> 0 & 0xff; + o[49] = x12 >>> 8 & 0xff; + o[50] = x12 >>> 16 & 0xff; + o[51] = x12 >>> 24 & 0xff; + + o[52] = x13 >>> 0 & 0xff; + o[53] = x13 >>> 8 & 0xff; + o[54] = x13 >>> 16 & 0xff; + o[55] = x13 >>> 24 & 0xff; + + o[56] = x14 >>> 0 & 0xff; + o[57] = x14 >>> 8 & 0xff; + o[58] = x14 >>> 16 & 0xff; + o[59] = x14 >>> 24 & 0xff; + + o[60] = x15 >>> 0 & 0xff; + o[61] = x15 >>> 8 & 0xff; + o[62] = x15 >>> 16 & 0xff; + o[63] = x15 >>> 24 & 0xff; +} + +function core_hsalsa20(o,p,k,c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x5 >>> 0 & 0xff; + o[ 5] = x5 >>> 8 & 0xff; + o[ 6] = x5 >>> 16 & 0xff; + o[ 7] = x5 >>> 24 & 0xff; + + o[ 8] = x10 >>> 0 & 0xff; + o[ 9] = x10 >>> 8 & 0xff; + o[10] = x10 >>> 16 & 0xff; + o[11] = x10 >>> 24 & 0xff; + + o[12] = x15 >>> 0 & 0xff; + o[13] = x15 >>> 8 & 0xff; + o[14] = x15 >>> 16 & 0xff; + o[15] = x15 >>> 24 & 0xff; + + o[16] = x6 >>> 0 & 0xff; + o[17] = x6 >>> 8 & 0xff; + o[18] = x6 >>> 16 & 0xff; + o[19] = x6 >>> 24 & 0xff; + + o[20] = x7 >>> 0 & 0xff; + o[21] = x7 >>> 8 & 0xff; + o[22] = x7 >>> 16 & 0xff; + o[23] = x7 >>> 24 & 0xff; + + o[24] = x8 >>> 0 & 0xff; + o[25] = x8 >>> 8 & 0xff; + o[26] = x8 >>> 16 & 0xff; + o[27] = x8 >>> 24 & 0xff; + + o[28] = x9 >>> 0 & 0xff; + o[29] = x9 >>> 8 & 0xff; + o[30] = x9 >>> 16 & 0xff; + o[31] = x9 >>> 24 & 0xff; +} + +function crypto_core_salsa20(out,inp,k,c) { + core_salsa20(out,inp,k,c); +} + +function crypto_core_hsalsa20(out,inp,k,c) { + core_hsalsa20(out,inp,k,c); +} + +var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]); + // "expand 32-byte k" + +function crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + mpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + } + return 0; +} + +function crypto_stream_salsa20(c,cpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = x[i]; + } + return 0; +} + +function crypto_stream(c,cpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20(c,cpos,d,sn,s); +} + +function crypto_stream_xor(c,cpos,m,mpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s); +} + +/* +* Port of Andrew Moon's Poly1305-donna-16. Public domain. +* https://github.com/floodyberry/poly1305-donna +*/ + +var poly1305 = function(key) { + this.buffer = new Uint8Array(16); + this.r = new Uint16Array(10); + this.h = new Uint16Array(10); + this.pad = new Uint16Array(8); + this.leftover = 0; + this.fin = 0; + + var t0, t1, t2, t3, t4, t5, t6, t7; + + t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; + t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; + t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; + this.r[5] = ((t4 >>> 1)) & 0x1ffe; + t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; + t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + this.r[9] = ((t7 >>> 5)) & 0x007f; + + this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; + this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; + this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; + this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; + this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; + this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; + this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; + this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; +}; + +poly1305.prototype.blocks = function(m, mpos, bytes) { + var hibit = this.fin ? 0 : (1 << 11); + var t0, t1, t2, t3, t4, t5, t6, t7, c; + var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; + + var h0 = this.h[0], + h1 = this.h[1], + h2 = this.h[2], + h3 = this.h[3], + h4 = this.h[4], + h5 = this.h[5], + h6 = this.h[6], + h7 = this.h[7], + h8 = this.h[8], + h9 = this.h[9]; + + var r0 = this.r[0], + r1 = this.r[1], + r2 = this.r[2], + r3 = this.r[3], + r4 = this.r[4], + r5 = this.r[5], + r6 = this.r[6], + r7 = this.r[7], + r8 = this.r[8], + r9 = this.r[9]; + + while (bytes >= 16) { + t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; + t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; + t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; + h5 += ((t4 >>> 1)) & 0x1fff; + t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; + t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + h9 += ((t7 >>> 5)) | hibit; + + c = 0; + + d0 = c; + d0 += h0 * r0; + d0 += h1 * (5 * r9); + d0 += h2 * (5 * r8); + d0 += h3 * (5 * r7); + d0 += h4 * (5 * r6); + c = (d0 >>> 13); d0 &= 0x1fff; + d0 += h5 * (5 * r5); + d0 += h6 * (5 * r4); + d0 += h7 * (5 * r3); + d0 += h8 * (5 * r2); + d0 += h9 * (5 * r1); + c += (d0 >>> 13); d0 &= 0x1fff; + + d1 = c; + d1 += h0 * r1; + d1 += h1 * r0; + d1 += h2 * (5 * r9); + d1 += h3 * (5 * r8); + d1 += h4 * (5 * r7); + c = (d1 >>> 13); d1 &= 0x1fff; + d1 += h5 * (5 * r6); + d1 += h6 * (5 * r5); + d1 += h7 * (5 * r4); + d1 += h8 * (5 * r3); + d1 += h9 * (5 * r2); + c += (d1 >>> 13); d1 &= 0x1fff; + + d2 = c; + d2 += h0 * r2; + d2 += h1 * r1; + d2 += h2 * r0; + d2 += h3 * (5 * r9); + d2 += h4 * (5 * r8); + c = (d2 >>> 13); d2 &= 0x1fff; + d2 += h5 * (5 * r7); + d2 += h6 * (5 * r6); + d2 += h7 * (5 * r5); + d2 += h8 * (5 * r4); + d2 += h9 * (5 * r3); + c += (d2 >>> 13); d2 &= 0x1fff; + + d3 = c; + d3 += h0 * r3; + d3 += h1 * r2; + d3 += h2 * r1; + d3 += h3 * r0; + d3 += h4 * (5 * r9); + c = (d3 >>> 13); d3 &= 0x1fff; + d3 += h5 * (5 * r8); + d3 += h6 * (5 * r7); + d3 += h7 * (5 * r6); + d3 += h8 * (5 * r5); + d3 += h9 * (5 * r4); + c += (d3 >>> 13); d3 &= 0x1fff; + + d4 = c; + d4 += h0 * r4; + d4 += h1 * r3; + d4 += h2 * r2; + d4 += h3 * r1; + d4 += h4 * r0; + c = (d4 >>> 13); d4 &= 0x1fff; + d4 += h5 * (5 * r9); + d4 += h6 * (5 * r8); + d4 += h7 * (5 * r7); + d4 += h8 * (5 * r6); + d4 += h9 * (5 * r5); + c += (d4 >>> 13); d4 &= 0x1fff; + + d5 = c; + d5 += h0 * r5; + d5 += h1 * r4; + d5 += h2 * r3; + d5 += h3 * r2; + d5 += h4 * r1; + c = (d5 >>> 13); d5 &= 0x1fff; + d5 += h5 * r0; + d5 += h6 * (5 * r9); + d5 += h7 * (5 * r8); + d5 += h8 * (5 * r7); + d5 += h9 * (5 * r6); + c += (d5 >>> 13); d5 &= 0x1fff; + + d6 = c; + d6 += h0 * r6; + d6 += h1 * r5; + d6 += h2 * r4; + d6 += h3 * r3; + d6 += h4 * r2; + c = (d6 >>> 13); d6 &= 0x1fff; + d6 += h5 * r1; + d6 += h6 * r0; + d6 += h7 * (5 * r9); + d6 += h8 * (5 * r8); + d6 += h9 * (5 * r7); + c += (d6 >>> 13); d6 &= 0x1fff; + + d7 = c; + d7 += h0 * r7; + d7 += h1 * r6; + d7 += h2 * r5; + d7 += h3 * r4; + d7 += h4 * r3; + c = (d7 >>> 13); d7 &= 0x1fff; + d7 += h5 * r2; + d7 += h6 * r1; + d7 += h7 * r0; + d7 += h8 * (5 * r9); + d7 += h9 * (5 * r8); + c += (d7 >>> 13); d7 &= 0x1fff; + + d8 = c; + d8 += h0 * r8; + d8 += h1 * r7; + d8 += h2 * r6; + d8 += h3 * r5; + d8 += h4 * r4; + c = (d8 >>> 13); d8 &= 0x1fff; + d8 += h5 * r3; + d8 += h6 * r2; + d8 += h7 * r1; + d8 += h8 * r0; + d8 += h9 * (5 * r9); + c += (d8 >>> 13); d8 &= 0x1fff; + + d9 = c; + d9 += h0 * r9; + d9 += h1 * r8; + d9 += h2 * r7; + d9 += h3 * r6; + d9 += h4 * r5; + c = (d9 >>> 13); d9 &= 0x1fff; + d9 += h5 * r4; + d9 += h6 * r3; + d9 += h7 * r2; + d9 += h8 * r1; + d9 += h9 * r0; + c += (d9 >>> 13); d9 &= 0x1fff; + + c = (((c << 2) + c)) | 0; + c = (c + d0) | 0; + d0 = c & 0x1fff; + c = (c >>> 13); + d1 += c; + + h0 = d0; + h1 = d1; + h2 = d2; + h3 = d3; + h4 = d4; + h5 = d5; + h6 = d6; + h7 = d7; + h8 = d8; + h9 = d9; + + mpos += 16; + bytes -= 16; + } + this.h[0] = h0; + this.h[1] = h1; + this.h[2] = h2; + this.h[3] = h3; + this.h[4] = h4; + this.h[5] = h5; + this.h[6] = h6; + this.h[7] = h7; + this.h[8] = h8; + this.h[9] = h9; +}; + +poly1305.prototype.finish = function(mac, macpos) { + var g = new Uint16Array(10); + var c, mask, f, i; + + if (this.leftover) { + i = this.leftover; + this.buffer[i++] = 1; + for (; i < 16; i++) this.buffer[i] = 0; + this.fin = 1; + this.blocks(this.buffer, 0, 16); + } + + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + for (i = 2; i < 10; i++) { + this.h[i] += c; + c = this.h[i] >>> 13; + this.h[i] &= 0x1fff; + } + this.h[0] += (c * 5); + c = this.h[0] >>> 13; + this.h[0] &= 0x1fff; + this.h[1] += c; + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + this.h[2] += c; + + g[0] = this.h[0] + 5; + c = g[0] >>> 13; + g[0] &= 0x1fff; + for (i = 1; i < 10; i++) { + g[i] = this.h[i] + c; + c = g[i] >>> 13; + g[i] &= 0x1fff; + } + g[9] -= (1 << 13); + + mask = (c ^ 1) - 1; + for (i = 0; i < 10; i++) g[i] &= mask; + mask = ~mask; + for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; + + this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; + this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; + this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; + this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; + this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; + this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; + this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; + this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; + + f = this.h[0] + this.pad[0]; + this.h[0] = f & 0xffff; + for (i = 1; i < 8; i++) { + f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; + this.h[i] = f & 0xffff; + } + + mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff; + mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff; + mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff; + mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff; + mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff; + mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff; + mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff; + mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff; + mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff; + mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff; + mac[macpos+10] = (this.h[5] >>> 0) & 0xff; + mac[macpos+11] = (this.h[5] >>> 8) & 0xff; + mac[macpos+12] = (this.h[6] >>> 0) & 0xff; + mac[macpos+13] = (this.h[6] >>> 8) & 0xff; + mac[macpos+14] = (this.h[7] >>> 0) & 0xff; + mac[macpos+15] = (this.h[7] >>> 8) & 0xff; +}; + +poly1305.prototype.update = function(m, mpos, bytes) { + var i, want; + + if (this.leftover) { + want = (16 - this.leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + bytes -= want; + mpos += want; + this.leftover += want; + if (this.leftover < 16) + return; + this.blocks(this.buffer, 0, 16); + this.leftover = 0; + } + + if (bytes >= 16) { + want = bytes - (bytes % 16); + this.blocks(m, mpos, want); + mpos += want; + bytes -= want; + } + + if (bytes) { + for (i = 0; i < bytes; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + this.leftover += bytes; + } +}; + +function crypto_onetimeauth(out, outpos, m, mpos, n, k) { + var s = new poly1305(k); + s.update(m, mpos, n); + s.finish(out, outpos); + return 0; +} + +function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) { + var x = new Uint8Array(16); + crypto_onetimeauth(x,0,m,mpos,n,k); + return crypto_verify_16(h,hpos,x,0); +} + +function crypto_secretbox(c,m,d,n,k) { + var i; + if (d < 32) return -1; + crypto_stream_xor(c,0,m,0,d,n,k); + crypto_onetimeauth(c, 16, c, 32, d - 32, c); + for (i = 0; i < 16; i++) c[i] = 0; + return 0; +} + +function crypto_secretbox_open(m,c,d,n,k) { + var i; + var x = new Uint8Array(32); + if (d < 32) return -1; + crypto_stream(x,0,32,n,k); + if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1; + crypto_stream_xor(m,0,c,0,d,n,k); + for (i = 0; i < 32; i++) m[i] = 0; + return 0; +} + +function set25519(r, a) { + var i; + for (i = 0; i < 16; i++) r[i] = a[i]|0; +} + +function car25519(o) { + var i, v, c = 1; + for (i = 0; i < 16; i++) { + v = o[i] + c + 65535; + c = Math.floor(v / 65536); + o[i] = v - c * 65536; + } + o[0] += c-1 + 37 * (c-1); +} + +function sel25519(p, q, b) { + var t, c = ~(b-1); + for (var i = 0; i < 16; i++) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } +} + +function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for (i = 0; i < 16; i++) t[i] = n[i]; + car25519(t); + car25519(t); + car25519(t); + for (j = 0; j < 2; j++) { + m[0] = t[0] - 0xffed; + for (i = 1; i < 15; i++) { + m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); + b = (m[15]>>16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1-b); + } + for (i = 0; i < 16; i++) { + o[2*i] = t[i] & 0xff; + o[2*i+1] = t[i]>>8; + } +} + +function neq25519(a, b) { + var c = new Uint8Array(32), d = new Uint8Array(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); +} + +function par25519(a) { + var d = new Uint8Array(32); + pack25519(d, a); + return d[0] & 1; +} + +function unpack25519(o, n) { + var i; + for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); + o[15] &= 0x7fff; +} + +function A(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] + b[i]; +} + +function Z(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] - b[i]; +} + +function M(o, a, b) { + var v, c, + t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, + t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, + t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, + t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11], + b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + + v = a[0]; + t0 += v * b0; + t1 += v * b1; + t2 += v * b2; + t3 += v * b3; + t4 += v * b4; + t5 += v * b5; + t6 += v * b6; + t7 += v * b7; + t8 += v * b8; + t9 += v * b9; + t10 += v * b10; + t11 += v * b11; + t12 += v * b12; + t13 += v * b13; + t14 += v * b14; + t15 += v * b15; + v = a[1]; + t1 += v * b0; + t2 += v * b1; + t3 += v * b2; + t4 += v * b3; + t5 += v * b4; + t6 += v * b5; + t7 += v * b6; + t8 += v * b7; + t9 += v * b8; + t10 += v * b9; + t11 += v * b10; + t12 += v * b11; + t13 += v * b12; + t14 += v * b13; + t15 += v * b14; + t16 += v * b15; + v = a[2]; + t2 += v * b0; + t3 += v * b1; + t4 += v * b2; + t5 += v * b3; + t6 += v * b4; + t7 += v * b5; + t8 += v * b6; + t9 += v * b7; + t10 += v * b8; + t11 += v * b9; + t12 += v * b10; + t13 += v * b11; + t14 += v * b12; + t15 += v * b13; + t16 += v * b14; + t17 += v * b15; + v = a[3]; + t3 += v * b0; + t4 += v * b1; + t5 += v * b2; + t6 += v * b3; + t7 += v * b4; + t8 += v * b5; + t9 += v * b6; + t10 += v * b7; + t11 += v * b8; + t12 += v * b9; + t13 += v * b10; + t14 += v * b11; + t15 += v * b12; + t16 += v * b13; + t17 += v * b14; + t18 += v * b15; + v = a[4]; + t4 += v * b0; + t5 += v * b1; + t6 += v * b2; + t7 += v * b3; + t8 += v * b4; + t9 += v * b5; + t10 += v * b6; + t11 += v * b7; + t12 += v * b8; + t13 += v * b9; + t14 += v * b10; + t15 += v * b11; + t16 += v * b12; + t17 += v * b13; + t18 += v * b14; + t19 += v * b15; + v = a[5]; + t5 += v * b0; + t6 += v * b1; + t7 += v * b2; + t8 += v * b3; + t9 += v * b4; + t10 += v * b5; + t11 += v * b6; + t12 += v * b7; + t13 += v * b8; + t14 += v * b9; + t15 += v * b10; + t16 += v * b11; + t17 += v * b12; + t18 += v * b13; + t19 += v * b14; + t20 += v * b15; + v = a[6]; + t6 += v * b0; + t7 += v * b1; + t8 += v * b2; + t9 += v * b3; + t10 += v * b4; + t11 += v * b5; + t12 += v * b6; + t13 += v * b7; + t14 += v * b8; + t15 += v * b9; + t16 += v * b10; + t17 += v * b11; + t18 += v * b12; + t19 += v * b13; + t20 += v * b14; + t21 += v * b15; + v = a[7]; + t7 += v * b0; + t8 += v * b1; + t9 += v * b2; + t10 += v * b3; + t11 += v * b4; + t12 += v * b5; + t13 += v * b6; + t14 += v * b7; + t15 += v * b8; + t16 += v * b9; + t17 += v * b10; + t18 += v * b11; + t19 += v * b12; + t20 += v * b13; + t21 += v * b14; + t22 += v * b15; + v = a[8]; + t8 += v * b0; + t9 += v * b1; + t10 += v * b2; + t11 += v * b3; + t12 += v * b4; + t13 += v * b5; + t14 += v * b6; + t15 += v * b7; + t16 += v * b8; + t17 += v * b9; + t18 += v * b10; + t19 += v * b11; + t20 += v * b12; + t21 += v * b13; + t22 += v * b14; + t23 += v * b15; + v = a[9]; + t9 += v * b0; + t10 += v * b1; + t11 += v * b2; + t12 += v * b3; + t13 += v * b4; + t14 += v * b5; + t15 += v * b6; + t16 += v * b7; + t17 += v * b8; + t18 += v * b9; + t19 += v * b10; + t20 += v * b11; + t21 += v * b12; + t22 += v * b13; + t23 += v * b14; + t24 += v * b15; + v = a[10]; + t10 += v * b0; + t11 += v * b1; + t12 += v * b2; + t13 += v * b3; + t14 += v * b4; + t15 += v * b5; + t16 += v * b6; + t17 += v * b7; + t18 += v * b8; + t19 += v * b9; + t20 += v * b10; + t21 += v * b11; + t22 += v * b12; + t23 += v * b13; + t24 += v * b14; + t25 += v * b15; + v = a[11]; + t11 += v * b0; + t12 += v * b1; + t13 += v * b2; + t14 += v * b3; + t15 += v * b4; + t16 += v * b5; + t17 += v * b6; + t18 += v * b7; + t19 += v * b8; + t20 += v * b9; + t21 += v * b10; + t22 += v * b11; + t23 += v * b12; + t24 += v * b13; + t25 += v * b14; + t26 += v * b15; + v = a[12]; + t12 += v * b0; + t13 += v * b1; + t14 += v * b2; + t15 += v * b3; + t16 += v * b4; + t17 += v * b5; + t18 += v * b6; + t19 += v * b7; + t20 += v * b8; + t21 += v * b9; + t22 += v * b10; + t23 += v * b11; + t24 += v * b12; + t25 += v * b13; + t26 += v * b14; + t27 += v * b15; + v = a[13]; + t13 += v * b0; + t14 += v * b1; + t15 += v * b2; + t16 += v * b3; + t17 += v * b4; + t18 += v * b5; + t19 += v * b6; + t20 += v * b7; + t21 += v * b8; + t22 += v * b9; + t23 += v * b10; + t24 += v * b11; + t25 += v * b12; + t26 += v * b13; + t27 += v * b14; + t28 += v * b15; + v = a[14]; + t14 += v * b0; + t15 += v * b1; + t16 += v * b2; + t17 += v * b3; + t18 += v * b4; + t19 += v * b5; + t20 += v * b6; + t21 += v * b7; + t22 += v * b8; + t23 += v * b9; + t24 += v * b10; + t25 += v * b11; + t26 += v * b12; + t27 += v * b13; + t28 += v * b14; + t29 += v * b15; + v = a[15]; + t15 += v * b0; + t16 += v * b1; + t17 += v * b2; + t18 += v * b3; + t19 += v * b4; + t20 += v * b5; + t21 += v * b6; + t22 += v * b7; + t23 += v * b8; + t24 += v * b9; + t25 += v * b10; + t26 += v * b11; + t27 += v * b12; + t28 += v * b13; + t29 += v * b14; + t30 += v * b15; + + t0 += 38 * t16; + t1 += 38 * t17; + t2 += 38 * t18; + t3 += 38 * t19; + t4 += 38 * t20; + t5 += 38 * t21; + t6 += 38 * t22; + t7 += 38 * t23; + t8 += 38 * t24; + t9 += 38 * t25; + t10 += 38 * t26; + t11 += 38 * t27; + t12 += 38 * t28; + t13 += 38 * t29; + t14 += 38 * t30; + // t15 left as is + + // first car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + // second car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + o[ 0] = t0; + o[ 1] = t1; + o[ 2] = t2; + o[ 3] = t3; + o[ 4] = t4; + o[ 5] = t5; + o[ 6] = t6; + o[ 7] = t7; + o[ 8] = t8; + o[ 9] = t9; + o[10] = t10; + o[11] = t11; + o[12] = t12; + o[13] = t13; + o[14] = t14; + o[15] = t15; +} + +function S(o, a) { + M(o, a, a); +} + +function inv25519(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 253; a >= 0; a--) { + S(c, c); + if(a !== 2 && a !== 4) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function pow2523(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 250; a >= 0; a--) { + S(c, c); + if(a !== 1) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function crypto_scalarmult(q, n, p) { + var z = new Uint8Array(32); + var x = new Float64Array(80), r, i; + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(); + for (i = 0; i < 31; i++) z[i] = n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + for (i = 0; i < 16; i++) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for (i=254; i>=0; --i) { + r=(z[i>>>3]>>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + for (i = 0; i < 16; i++) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + var x32 = x.subarray(32); + var x16 = x.subarray(16); + inv25519(x32,x32); + M(x16,x16,x32); + pack25519(q,x16); + return 0; +} + +function crypto_scalarmult_base(q, n) { + return crypto_scalarmult(q, n, _9); +} + +function crypto_box_keypair(y, x) { + randombytes(x, 32); + return crypto_scalarmult_base(y, x); +} + +function crypto_box_beforenm(k, y, x) { + var s = new Uint8Array(32); + crypto_scalarmult(s, x, y); + return crypto_core_hsalsa20(k, _0, s, sigma); +} + +var crypto_box_afternm = crypto_secretbox; +var crypto_box_open_afternm = crypto_secretbox_open; + +function crypto_box(c, m, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_afternm(c, m, d, n, k); +} + +function crypto_box_open(m, c, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_open_afternm(m, c, d, n, k); +} + +var K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +]; + +function crypto_hashblocks_hl(hh, hl, m, n) { + var wh = new Int32Array(16), wl = new Int32Array(16), + bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, + bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, + th, tl, i, j, h, l, a, b, c, d; + + var ah0 = hh[0], + ah1 = hh[1], + ah2 = hh[2], + ah3 = hh[3], + ah4 = hh[4], + ah5 = hh[5], + ah6 = hh[6], + ah7 = hh[7], + + al0 = hl[0], + al1 = hl[1], + al2 = hl[2], + al3 = hl[3], + al4 = hl[4], + al5 = hl[5], + al6 = hl[6], + al7 = hl[7]; + + var pos = 0; + while (n >= 128) { + for (i = 0; i < 16; i++) { + j = 8 * i + pos; + wh[i] = (m[j+0] << 24) | (m[j+1] << 16) | (m[j+2] << 8) | m[j+3]; + wl[i] = (m[j+4] << 24) | (m[j+5] << 16) | (m[j+6] << 8) | m[j+7]; + } + for (i = 0; i < 80; i++) { + bh0 = ah0; + bh1 = ah1; + bh2 = ah2; + bh3 = ah3; + bh4 = ah4; + bh5 = ah5; + bh6 = ah6; + bh7 = ah7; + + bl0 = al0; + bl1 = al1; + bl2 = al2; + bl3 = al3; + bl4 = al4; + bl5 = al5; + bl6 = al6; + bl7 = al7; + + // add + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma1 + h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32)))); + l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Ch + h = (ah4 & ah5) ^ (~ah4 & ah6); + l = (al4 & al5) ^ (~al4 & al6); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // K + h = K[i*2]; + l = K[i*2+1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // w + h = wh[i%16]; + l = wl[i%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + th = c & 0xffff | d << 16; + tl = a & 0xffff | b << 16; + + // add + h = th; + l = tl; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma0 + h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32)))); + l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Maj + h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); + l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh7 = (c & 0xffff) | (d << 16); + bl7 = (a & 0xffff) | (b << 16); + + // add + h = bh3; + l = bl3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = th; + l = tl; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh3 = (c & 0xffff) | (d << 16); + bl3 = (a & 0xffff) | (b << 16); + + ah1 = bh0; + ah2 = bh1; + ah3 = bh2; + ah4 = bh3; + ah5 = bh4; + ah6 = bh5; + ah7 = bh6; + ah0 = bh7; + + al1 = bl0; + al2 = bl1; + al3 = bl2; + al4 = bl3; + al5 = bl4; + al6 = bl5; + al7 = bl6; + al0 = bl7; + + if (i%16 === 15) { + for (j = 0; j < 16; j++) { + // add + h = wh[j]; + l = wl[j]; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = wh[(j+9)%16]; + l = wl[(j+9)%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma0 + th = wh[(j+1)%16]; + tl = wl[(j+1)%16]; + h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7); + l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma1 + th = wh[(j+14)%16]; + tl = wl[(j+14)%16]; + h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6); + l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + wh[j] = (c & 0xffff) | (d << 16); + wl[j] = (a & 0xffff) | (b << 16); + } + } + } + + // add + h = ah0; + l = al0; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[0]; + l = hl[0]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[0] = ah0 = (c & 0xffff) | (d << 16); + hl[0] = al0 = (a & 0xffff) | (b << 16); + + h = ah1; + l = al1; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[1]; + l = hl[1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[1] = ah1 = (c & 0xffff) | (d << 16); + hl[1] = al1 = (a & 0xffff) | (b << 16); + + h = ah2; + l = al2; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[2]; + l = hl[2]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[2] = ah2 = (c & 0xffff) | (d << 16); + hl[2] = al2 = (a & 0xffff) | (b << 16); + + h = ah3; + l = al3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[3]; + l = hl[3]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[3] = ah3 = (c & 0xffff) | (d << 16); + hl[3] = al3 = (a & 0xffff) | (b << 16); + + h = ah4; + l = al4; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[4]; + l = hl[4]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[4] = ah4 = (c & 0xffff) | (d << 16); + hl[4] = al4 = (a & 0xffff) | (b << 16); + + h = ah5; + l = al5; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[5]; + l = hl[5]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[5] = ah5 = (c & 0xffff) | (d << 16); + hl[5] = al5 = (a & 0xffff) | (b << 16); + + h = ah6; + l = al6; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[6]; + l = hl[6]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[6] = ah6 = (c & 0xffff) | (d << 16); + hl[6] = al6 = (a & 0xffff) | (b << 16); + + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[7]; + l = hl[7]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[7] = ah7 = (c & 0xffff) | (d << 16); + hl[7] = al7 = (a & 0xffff) | (b << 16); + + pos += 128; + n -= 128; + } + + return n; +} + +function crypto_hash(out, m, n) { + var hh = new Int32Array(8), + hl = new Int32Array(8), + x = new Uint8Array(256), + i, b = n; + + hh[0] = 0x6a09e667; + hh[1] = 0xbb67ae85; + hh[2] = 0x3c6ef372; + hh[3] = 0xa54ff53a; + hh[4] = 0x510e527f; + hh[5] = 0x9b05688c; + hh[6] = 0x1f83d9ab; + hh[7] = 0x5be0cd19; + + hl[0] = 0xf3bcc908; + hl[1] = 0x84caa73b; + hl[2] = 0xfe94f82b; + hl[3] = 0x5f1d36f1; + hl[4] = 0xade682d1; + hl[5] = 0x2b3e6c1f; + hl[6] = 0xfb41bd6b; + hl[7] = 0x137e2179; + + crypto_hashblocks_hl(hh, hl, m, n); + n %= 128; + + for (i = 0; i < n; i++) x[i] = m[b-n+i]; + x[n] = 128; + + n = 256-128*(n<112?1:0); + x[n-9] = 0; + ts64(x, n-8, (b / 0x20000000) | 0, b << 3); + crypto_hashblocks_hl(hh, hl, x, n); + + for (i = 0; i < 8; i++) ts64(out, 8*i, hh[i], hl[i]); + + return 0; +} + +function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +function cswap(p, q, b) { + var i; + for (i = 0; i < 4; i++) { + sel25519(p[i], q[i], b); + } +} + +function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for (i = 255; i >= 0; --i) { + b = (s[(i/8)|0] >> (i&7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } +} + +function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); +} + +function crypto_sign_keypair(pk, sk, seeded) { + var d = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()]; + var i; + + if (!seeded) randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for (i = 0; i < 32; i++) sk[i+32] = pk[i]; + return 0; +} + +var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); + +function modL(r, x) { + var carry, i, j, k; + for (i = 63; i >= 32; --i) { + carry = 0; + for (j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for (j = 0; j < 32; j++) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for (j = 0; j < 32; j++) x[j] -= carry * L[j]; + for (i = 0; i < 32; i++) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +function reduce(r) { + var x = new Float64Array(64), i; + for (i = 0; i < 64; i++) x[i] = r[i]; + for (i = 0; i < 64; i++) r[i] = 0; + modL(r, x); +} + +// Note: difference from C - smlen returned, not passed as argument. +function crypto_sign(sm, m, n, sk) { + var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for (i = 0; i < n; i++) sm[64 + i] = m[i]; + for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm.subarray(32), n+32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for (i = 32; i < 64; i++) sm[i] = sk[i]; + crypto_hash(h, sm, n + 64); + reduce(h); + + for (i = 0; i < 64; i++) x[i] = 0; + for (i = 0; i < 32; i++) x[i] = r[i]; + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + x[i+j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; +} + +function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D); + Z(num, num, r[2]); + A(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) M(r[0], r[0], I); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) return -1; + + if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]); + + M(r[3], r[0], r[1]); + return 0; +} + +function crypto_sign_open(m, sm, n, pk) { + var i, mlen; + var t = new Uint8Array(32), h = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + mlen = -1; + if (n < 64) return -1; + + if (unpackneg(q, pk)) return -1; + + for (i = 0; i < n; i++) m[i] = sm[i]; + for (i = 0; i < 32; i++) m[i+32] = pk[i]; + crypto_hash(h, m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if (crypto_verify_32(sm, 0, t, 0)) { + for (i = 0; i < n; i++) m[i] = 0; + return -1; + } + + for (i = 0; i < n; i++) m[i] = sm[i + 64]; + mlen = n; + return mlen; +} + +var crypto_secretbox_KEYBYTES = 32, + crypto_secretbox_NONCEBYTES = 24, + crypto_secretbox_ZEROBYTES = 32, + crypto_secretbox_BOXZEROBYTES = 16, + crypto_scalarmult_BYTES = 32, + crypto_scalarmult_SCALARBYTES = 32, + crypto_box_PUBLICKEYBYTES = 32, + crypto_box_SECRETKEYBYTES = 32, + crypto_box_BEFORENMBYTES = 32, + crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES, + crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES, + crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES, + crypto_sign_BYTES = 64, + crypto_sign_PUBLICKEYBYTES = 32, + crypto_sign_SECRETKEYBYTES = 64, + crypto_sign_SEEDBYTES = 32, + crypto_hash_BYTES = 64; + +nacl.lowlevel = { + crypto_core_hsalsa20: crypto_core_hsalsa20, + crypto_stream_xor: crypto_stream_xor, + crypto_stream: crypto_stream, + crypto_stream_salsa20_xor: crypto_stream_salsa20_xor, + crypto_stream_salsa20: crypto_stream_salsa20, + crypto_onetimeauth: crypto_onetimeauth, + crypto_onetimeauth_verify: crypto_onetimeauth_verify, + crypto_verify_16: crypto_verify_16, + crypto_verify_32: crypto_verify_32, + crypto_secretbox: crypto_secretbox, + crypto_secretbox_open: crypto_secretbox_open, + crypto_scalarmult: crypto_scalarmult, + crypto_scalarmult_base: crypto_scalarmult_base, + crypto_box_beforenm: crypto_box_beforenm, + crypto_box_afternm: crypto_box_afternm, + crypto_box: crypto_box, + crypto_box_open: crypto_box_open, + crypto_box_keypair: crypto_box_keypair, + crypto_hash: crypto_hash, + crypto_sign: crypto_sign, + crypto_sign_keypair: crypto_sign_keypair, + crypto_sign_open: crypto_sign_open, + + crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES, + crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES, + crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES, + crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES, + crypto_scalarmult_BYTES: crypto_scalarmult_BYTES, + crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES, + crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES, + crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES, + crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES, + crypto_box_NONCEBYTES: crypto_box_NONCEBYTES, + crypto_box_ZEROBYTES: crypto_box_ZEROBYTES, + crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES, + crypto_sign_BYTES: crypto_sign_BYTES, + crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES, + crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES, + crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES, + crypto_hash_BYTES: crypto_hash_BYTES +}; + +/* High-level API */ + +function checkLengths(k, n) { + if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size'); + if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size'); +} + +function checkBoxLengths(pk, sk) { + if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size'); + if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size'); +} + +function checkArrayTypes() { + var t, i; + for (i = 0; i < arguments.length; i++) { + if ((t = Object.prototype.toString.call(arguments[i])) !== '[object Uint8Array]') + throw new TypeError('unexpected type ' + t + ', use Uint8Array'); + } +} + +function cleanup(arr) { + for (var i = 0; i < arr.length; i++) arr[i] = 0; +} + +// TODO: Completely remove this in v0.15. +if (!nacl.util) { + nacl.util = {}; + nacl.util.decodeUTF8 = nacl.util.encodeUTF8 = nacl.util.encodeBase64 = nacl.util.decodeBase64 = function() { + throw new Error('nacl.util moved into separate package: https://github.com/dchest/tweetnacl-util-js'); + }; +} + +nacl.randomBytes = function(n) { + var b = new Uint8Array(n); + randombytes(b, n); + return b; +}; + +nacl.secretbox = function(msg, nonce, key) { + checkArrayTypes(msg, nonce, key); + checkLengths(key, nonce); + var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); + var c = new Uint8Array(m.length); + for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i]; + crypto_secretbox(c, m, m.length, nonce, key); + return c.subarray(crypto_secretbox_BOXZEROBYTES); +}; + +nacl.secretbox.open = function(box, nonce, key) { + checkArrayTypes(box, nonce, key); + checkLengths(key, nonce); + var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length); + var m = new Uint8Array(c.length); + for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i]; + if (c.length < 32) return false; + if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return false; + return m.subarray(crypto_secretbox_ZEROBYTES); +}; + +nacl.secretbox.keyLength = crypto_secretbox_KEYBYTES; +nacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES; +nacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES; + +nacl.scalarMult = function(n, p) { + checkArrayTypes(n, p); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult(q, n, p); + return q; +}; + +nacl.scalarMult.base = function(n) { + checkArrayTypes(n); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult_base(q, n); + return q; +}; + +nacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES; +nacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES; + +nacl.box = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox(msg, nonce, k); +}; + +nacl.box.before = function(publicKey, secretKey) { + checkArrayTypes(publicKey, secretKey); + checkBoxLengths(publicKey, secretKey); + var k = new Uint8Array(crypto_box_BEFORENMBYTES); + crypto_box_beforenm(k, publicKey, secretKey); + return k; +}; + +nacl.box.after = nacl.secretbox; + +nacl.box.open = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox.open(msg, nonce, k); +}; + +nacl.box.open.after = nacl.secretbox.open; + +nacl.box.keyPair = function() { + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.box.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_box_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + crypto_scalarmult_base(pk, secretKey); + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES; +nacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES; +nacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES; +nacl.box.nonceLength = crypto_box_NONCEBYTES; +nacl.box.overheadLength = nacl.secretbox.overheadLength; + +nacl.sign = function(msg, secretKey) { + checkArrayTypes(msg, secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length); + crypto_sign(signedMsg, msg, msg.length, secretKey); + return signedMsg; +}; + +nacl.sign.open = function(signedMsg, publicKey) { + if (arguments.length !== 2) + throw new Error('nacl.sign.open accepts 2 arguments; did you mean to use nacl.sign.detached.verify?'); + checkArrayTypes(signedMsg, publicKey); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var tmp = new Uint8Array(signedMsg.length); + var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey); + if (mlen < 0) return null; + var m = new Uint8Array(mlen); + for (var i = 0; i < m.length; i++) m[i] = tmp[i]; + return m; +}; + +nacl.sign.detached = function(msg, secretKey) { + var signedMsg = nacl.sign(msg, secretKey); + var sig = new Uint8Array(crypto_sign_BYTES); + for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; + return sig; +}; + +nacl.sign.detached.verify = function(msg, sig, publicKey) { + checkArrayTypes(msg, sig, publicKey); + if (sig.length !== crypto_sign_BYTES) + throw new Error('bad signature size'); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var sm = new Uint8Array(crypto_sign_BYTES + msg.length); + var m = new Uint8Array(crypto_sign_BYTES + msg.length); + var i; + for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; + for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i]; + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); +}; + +nacl.sign.keyPair = function() { + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + crypto_sign_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i]; + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.sign.keyPair.fromSeed = function(seed) { + checkArrayTypes(seed); + if (seed.length !== crypto_sign_SEEDBYTES) + throw new Error('bad seed size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + for (var i = 0; i < 32; i++) sk[i] = seed[i]; + crypto_sign_keypair(pk, sk, true); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES; +nacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES; +nacl.sign.seedLength = crypto_sign_SEEDBYTES; +nacl.sign.signatureLength = crypto_sign_BYTES; + +nacl.hash = function(msg) { + checkArrayTypes(msg); + var h = new Uint8Array(crypto_hash_BYTES); + crypto_hash(h, msg, msg.length); + return h; +}; + +nacl.hash.hashLength = crypto_hash_BYTES; + +nacl.verify = function(x, y) { + checkArrayTypes(x, y); + // Zero length arguments are considered not equal. + if (x.length === 0 || y.length === 0) return false; + if (x.length !== y.length) return false; + return (vn(x, 0, y, 0, x.length) === 0) ? true : false; +}; + +nacl.setPRNG = function(fn) { + randombytes = fn; +}; + +(function() { + // Initialize PRNG if environment provides CSPRNG. + // If not, methods calling randombytes will throw. + var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null; + if (crypto && crypto.getRandomValues) { + // Browsers. + var QUOTA = 65536; + nacl.setPRNG(function(x, n) { + var i, v = new Uint8Array(n); + for (i = 0; i < n; i += QUOTA) { + crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA))); + } + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } else if (typeof require !== 'undefined') { + // Node.js. + crypto = require('crypto'); + if (crypto && crypto.randomBytes) { + nacl.setPRNG(function(x, n) { + var i, v = crypto.randomBytes(n); + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } + } +})(); + +})(typeof module !== 'undefined' && module.exports ? module.exports : (self.nacl = self.nacl || {})); diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.min.js b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.min.js new file mode 100644 index 0000000..8bc47da --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl-fast.min.js @@ -0,0 +1,2 @@ +!function(r){"use strict";function t(r,t,n,e){r[t]=n>>24&255,r[t+1]=n>>16&255,r[t+2]=n>>8&255,r[t+3]=255&n,r[t+4]=e>>24&255,r[t+5]=e>>16&255,r[t+6]=e>>8&255,r[t+7]=255&e}function n(r,t,n,e,o){var i,h=0;for(i=0;i>>8)-1}function e(r,t,e,o){return n(r,t,e,o,16)}function o(r,t,e,o){return n(r,t,e,o,32)}function i(r,t,n,e){for(var o,i=255&e[0]|(255&e[1])<<8|(255&e[2])<<16|(255&e[3])<<24,h=255&n[0]|(255&n[1])<<8|(255&n[2])<<16|(255&n[3])<<24,a=255&n[4]|(255&n[5])<<8|(255&n[6])<<16|(255&n[7])<<24,f=255&n[8]|(255&n[9])<<8|(255&n[10])<<16|(255&n[11])<<24,s=255&n[12]|(255&n[13])<<8|(255&n[14])<<16|(255&n[15])<<24,c=255&e[4]|(255&e[5])<<8|(255&e[6])<<16|(255&e[7])<<24,u=255&t[0]|(255&t[1])<<8|(255&t[2])<<16|(255&t[3])<<24,y=255&t[4]|(255&t[5])<<8|(255&t[6])<<16|(255&t[7])<<24,l=255&t[8]|(255&t[9])<<8|(255&t[10])<<16|(255&t[11])<<24,w=255&t[12]|(255&t[13])<<8|(255&t[14])<<16|(255&t[15])<<24,p=255&e[8]|(255&e[9])<<8|(255&e[10])<<16|(255&e[11])<<24,v=255&n[16]|(255&n[17])<<8|(255&n[18])<<16|(255&n[19])<<24,b=255&n[20]|(255&n[21])<<8|(255&n[22])<<16|(255&n[23])<<24,g=255&n[24]|(255&n[25])<<8|(255&n[26])<<16|(255&n[27])<<24,_=255&n[28]|(255&n[29])<<8|(255&n[30])<<16|(255&n[31])<<24,A=255&e[12]|(255&e[13])<<8|(255&e[14])<<16|(255&e[15])<<24,d=i,U=h,E=a,x=f,M=s,m=c,B=u,S=y,K=l,T=w,Y=p,k=v,L=b,z=g,R=_,P=A,O=0;O<20;O+=2)o=d+L|0,M^=o<<7|o>>>25,o=M+d|0,K^=o<<9|o>>>23,o=K+M|0,L^=o<<13|o>>>19,o=L+K|0,d^=o<<18|o>>>14,o=m+U|0,T^=o<<7|o>>>25,o=T+m|0,z^=o<<9|o>>>23,o=z+T|0,U^=o<<13|o>>>19,o=U+z|0,m^=o<<18|o>>>14,o=Y+B|0,R^=o<<7|o>>>25,o=R+Y|0,E^=o<<9|o>>>23,o=E+R|0,B^=o<<13|o>>>19,o=B+E|0,Y^=o<<18|o>>>14,o=P+k|0,x^=o<<7|o>>>25,o=x+P|0,S^=o<<9|o>>>23,o=S+x|0,k^=o<<13|o>>>19,o=k+S|0,P^=o<<18|o>>>14,o=d+x|0,U^=o<<7|o>>>25,o=U+d|0,E^=o<<9|o>>>23,o=E+U|0,x^=o<<13|o>>>19,o=x+E|0,d^=o<<18|o>>>14,o=m+M|0,B^=o<<7|o>>>25,o=B+m|0,S^=o<<9|o>>>23,o=S+B|0,M^=o<<13|o>>>19,o=M+S|0,m^=o<<18|o>>>14,o=Y+T|0,k^=o<<7|o>>>25,o=k+Y|0,K^=o<<9|o>>>23,o=K+k|0,T^=o<<13|o>>>19,o=T+K|0,Y^=o<<18|o>>>14,o=P+R|0,L^=o<<7|o>>>25,o=L+P|0,z^=o<<9|o>>>23,o=z+L|0,R^=o<<13|o>>>19,o=R+z|0,P^=o<<18|o>>>14;d=d+i|0,U=U+h|0,E=E+a|0,x=x+f|0,M=M+s|0,m=m+c|0,B=B+u|0,S=S+y|0,K=K+l|0,T=T+w|0,Y=Y+p|0,k=k+v|0,L=L+b|0,z=z+g|0,R=R+_|0,P=P+A|0,r[0]=d>>>0&255,r[1]=d>>>8&255,r[2]=d>>>16&255,r[3]=d>>>24&255,r[4]=U>>>0&255,r[5]=U>>>8&255,r[6]=U>>>16&255,r[7]=U>>>24&255,r[8]=E>>>0&255,r[9]=E>>>8&255,r[10]=E>>>16&255,r[11]=E>>>24&255,r[12]=x>>>0&255,r[13]=x>>>8&255,r[14]=x>>>16&255,r[15]=x>>>24&255,r[16]=M>>>0&255,r[17]=M>>>8&255,r[18]=M>>>16&255,r[19]=M>>>24&255,r[20]=m>>>0&255,r[21]=m>>>8&255,r[22]=m>>>16&255,r[23]=m>>>24&255,r[24]=B>>>0&255,r[25]=B>>>8&255,r[26]=B>>>16&255,r[27]=B>>>24&255,r[28]=S>>>0&255,r[29]=S>>>8&255,r[30]=S>>>16&255,r[31]=S>>>24&255,r[32]=K>>>0&255,r[33]=K>>>8&255,r[34]=K>>>16&255,r[35]=K>>>24&255,r[36]=T>>>0&255,r[37]=T>>>8&255,r[38]=T>>>16&255,r[39]=T>>>24&255,r[40]=Y>>>0&255,r[41]=Y>>>8&255,r[42]=Y>>>16&255,r[43]=Y>>>24&255,r[44]=k>>>0&255,r[45]=k>>>8&255,r[46]=k>>>16&255,r[47]=k>>>24&255,r[48]=L>>>0&255,r[49]=L>>>8&255,r[50]=L>>>16&255,r[51]=L>>>24&255,r[52]=z>>>0&255,r[53]=z>>>8&255,r[54]=z>>>16&255,r[55]=z>>>24&255,r[56]=R>>>0&255,r[57]=R>>>8&255,r[58]=R>>>16&255,r[59]=R>>>24&255,r[60]=P>>>0&255,r[61]=P>>>8&255,r[62]=P>>>16&255,r[63]=P>>>24&255}function h(r,t,n,e){for(var o,i=255&e[0]|(255&e[1])<<8|(255&e[2])<<16|(255&e[3])<<24,h=255&n[0]|(255&n[1])<<8|(255&n[2])<<16|(255&n[3])<<24,a=255&n[4]|(255&n[5])<<8|(255&n[6])<<16|(255&n[7])<<24,f=255&n[8]|(255&n[9])<<8|(255&n[10])<<16|(255&n[11])<<24,s=255&n[12]|(255&n[13])<<8|(255&n[14])<<16|(255&n[15])<<24,c=255&e[4]|(255&e[5])<<8|(255&e[6])<<16|(255&e[7])<<24,u=255&t[0]|(255&t[1])<<8|(255&t[2])<<16|(255&t[3])<<24,y=255&t[4]|(255&t[5])<<8|(255&t[6])<<16|(255&t[7])<<24,l=255&t[8]|(255&t[9])<<8|(255&t[10])<<16|(255&t[11])<<24,w=255&t[12]|(255&t[13])<<8|(255&t[14])<<16|(255&t[15])<<24,p=255&e[8]|(255&e[9])<<8|(255&e[10])<<16|(255&e[11])<<24,v=255&n[16]|(255&n[17])<<8|(255&n[18])<<16|(255&n[19])<<24,b=255&n[20]|(255&n[21])<<8|(255&n[22])<<16|(255&n[23])<<24,g=255&n[24]|(255&n[25])<<8|(255&n[26])<<16|(255&n[27])<<24,_=255&n[28]|(255&n[29])<<8|(255&n[30])<<16|(255&n[31])<<24,A=255&e[12]|(255&e[13])<<8|(255&e[14])<<16|(255&e[15])<<24,d=i,U=h,E=a,x=f,M=s,m=c,B=u,S=y,K=l,T=w,Y=p,k=v,L=b,z=g,R=_,P=A,O=0;O<20;O+=2)o=d+L|0,M^=o<<7|o>>>25,o=M+d|0,K^=o<<9|o>>>23,o=K+M|0,L^=o<<13|o>>>19,o=L+K|0,d^=o<<18|o>>>14,o=m+U|0,T^=o<<7|o>>>25,o=T+m|0,z^=o<<9|o>>>23,o=z+T|0,U^=o<<13|o>>>19,o=U+z|0,m^=o<<18|o>>>14,o=Y+B|0,R^=o<<7|o>>>25,o=R+Y|0,E^=o<<9|o>>>23,o=E+R|0,B^=o<<13|o>>>19,o=B+E|0,Y^=o<<18|o>>>14,o=P+k|0,x^=o<<7|o>>>25,o=x+P|0,S^=o<<9|o>>>23,o=S+x|0,k^=o<<13|o>>>19,o=k+S|0,P^=o<<18|o>>>14,o=d+x|0,U^=o<<7|o>>>25,o=U+d|0,E^=o<<9|o>>>23,o=E+U|0,x^=o<<13|o>>>19,o=x+E|0,d^=o<<18|o>>>14,o=m+M|0,B^=o<<7|o>>>25,o=B+m|0,S^=o<<9|o>>>23,o=S+B|0,M^=o<<13|o>>>19,o=M+S|0,m^=o<<18|o>>>14,o=Y+T|0,k^=o<<7|o>>>25,o=k+Y|0,K^=o<<9|o>>>23,o=K+k|0,T^=o<<13|o>>>19,o=T+K|0,Y^=o<<18|o>>>14,o=P+R|0,L^=o<<7|o>>>25,o=L+P|0,z^=o<<9|o>>>23,o=z+L|0,R^=o<<13|o>>>19,o=R+z|0,P^=o<<18|o>>>14;r[0]=d>>>0&255,r[1]=d>>>8&255,r[2]=d>>>16&255,r[3]=d>>>24&255,r[4]=m>>>0&255,r[5]=m>>>8&255,r[6]=m>>>16&255,r[7]=m>>>24&255,r[8]=Y>>>0&255,r[9]=Y>>>8&255,r[10]=Y>>>16&255,r[11]=Y>>>24&255,r[12]=P>>>0&255,r[13]=P>>>8&255,r[14]=P>>>16&255,r[15]=P>>>24&255,r[16]=B>>>0&255,r[17]=B>>>8&255,r[18]=B>>>16&255,r[19]=B>>>24&255,r[20]=S>>>0&255,r[21]=S>>>8&255,r[22]=S>>>16&255,r[23]=S>>>24&255,r[24]=K>>>0&255,r[25]=K>>>8&255,r[26]=K>>>16&255,r[27]=K>>>24&255,r[28]=T>>>0&255,r[29]=T>>>8&255,r[30]=T>>>16&255,r[31]=T>>>24&255}function a(r,t,n,e){i(r,t,n,e)}function f(r,t,n,e){h(r,t,n,e)}function s(r,t,n,e,o,i,h){var f,s,c=new Uint8Array(16),u=new Uint8Array(64);for(s=0;s<16;s++)c[s]=0;for(s=0;s<8;s++)c[s]=i[s];for(;o>=64;){for(a(u,c,h,ur),s=0;s<64;s++)r[t+s]=n[e+s]^u[s];for(f=1,s=8;s<16;s++)f=f+(255&c[s])|0,c[s]=255&f,f>>>=8;o-=64,t+=64,e+=64}if(o>0)for(a(u,c,h,ur),s=0;s=64;){for(a(s,f,o,ur),h=0;h<64;h++)r[t+h]=s[h];for(i=1,h=8;h<16;h++)i=i+(255&f[h])|0,f[h]=255&i,i>>>=8;n-=64,t+=64}if(n>0)for(a(s,f,o,ur),h=0;h>16&1),i[n-1]&=65535;i[15]=h[15]-32767-(i[14]>>16&1),o=i[15]>>16&1,i[14]&=65535,_(h,i,1-o)}for(n=0;n<16;n++)r[2*n]=255&h[n],r[2*n+1]=h[n]>>8}function d(r,t){var n=new Uint8Array(32),e=new Uint8Array(32);return A(n,r),A(e,t),o(n,0,e,0)}function U(r){var t=new Uint8Array(32);return A(t,r),1&t[0]}function E(r,t){var n;for(n=0;n<16;n++)r[n]=t[2*n]+(t[2*n+1]<<8);r[15]&=32767}function x(r,t,n){for(var e=0;e<16;e++)r[e]=t[e]+n[e]}function M(r,t,n){for(var e=0;e<16;e++)r[e]=t[e]-n[e]}function m(r,t,n){var e,o,i=0,h=0,a=0,f=0,s=0,c=0,u=0,y=0,l=0,w=0,p=0,v=0,b=0,g=0,_=0,A=0,d=0,U=0,E=0,x=0,M=0,m=0,B=0,S=0,K=0,T=0,Y=0,k=0,L=0,z=0,R=0,P=n[0],O=n[1],N=n[2],C=n[3],F=n[4],I=n[5],G=n[6],Z=n[7],j=n[8],q=n[9],V=n[10],X=n[11],D=n[12],H=n[13],J=n[14],Q=n[15];e=t[0],i+=e*P,h+=e*O,a+=e*N,f+=e*C,s+=e*F,c+=e*I,u+=e*G,y+=e*Z,l+=e*j,w+=e*q,p+=e*V,v+=e*X,b+=e*D,g+=e*H,_+=e*J,A+=e*Q,e=t[1],h+=e*P,a+=e*O,f+=e*N,s+=e*C,c+=e*F,u+=e*I,y+=e*G,l+=e*Z,w+=e*j,p+=e*q,v+=e*V,b+=e*X,g+=e*D,_+=e*H,A+=e*J,d+=e*Q,e=t[2],a+=e*P,f+=e*O,s+=e*N,c+=e*C,u+=e*F,y+=e*I,l+=e*G,w+=e*Z,p+=e*j,v+=e*q,b+=e*V,g+=e*X,_+=e*D,A+=e*H,d+=e*J,U+=e*Q,e=t[3],f+=e*P,s+=e*O,c+=e*N,u+=e*C,y+=e*F,l+=e*I,w+=e*G,p+=e*Z,v+=e*j,b+=e*q,g+=e*V,_+=e*X,A+=e*D,d+=e*H,U+=e*J,E+=e*Q,e=t[4],s+=e*P,c+=e*O,u+=e*N,y+=e*C,l+=e*F,w+=e*I,p+=e*G,v+=e*Z,b+=e*j,g+=e*q,_+=e*V,A+=e*X,d+=e*D,U+=e*H,E+=e*J,x+=e*Q,e=t[5],c+=e*P,u+=e*O,y+=e*N,l+=e*C,w+=e*F,p+=e*I,v+=e*G,b+=e*Z,g+=e*j,_+=e*q,A+=e*V,d+=e*X,U+=e*D,E+=e*H,x+=e*J,M+=e*Q,e=t[6],u+=e*P,y+=e*O,l+=e*N,w+=e*C,p+=e*F,v+=e*I,b+=e*G,g+=e*Z,_+=e*j,A+=e*q,d+=e*V,U+=e*X,E+=e*D,x+=e*H,M+=e*J,m+=e*Q,e=t[7],y+=e*P,l+=e*O,w+=e*N,p+=e*C,v+=e*F,b+=e*I,g+=e*G,_+=e*Z,A+=e*j,d+=e*q,U+=e*V,E+=e*X,x+=e*D,M+=e*H,m+=e*J,B+=e*Q,e=t[8],l+=e*P,w+=e*O,p+=e*N,v+=e*C,b+=e*F,g+=e*I,_+=e*G,A+=e*Z,d+=e*j,U+=e*q,E+=e*V,x+=e*X,M+=e*D,m+=e*H,B+=e*J,S+=e*Q,e=t[9],w+=e*P,p+=e*O,v+=e*N,b+=e*C,g+=e*F,_+=e*I,A+=e*G,d+=e*Z,U+=e*j,E+=e*q,x+=e*V,M+=e*X,m+=e*D,B+=e*H,S+=e*J,K+=e*Q,e=t[10],p+=e*P,v+=e*O,b+=e*N,g+=e*C,_+=e*F,A+=e*I,d+=e*G,U+=e*Z,E+=e*j,x+=e*q,M+=e*V,m+=e*X,B+=e*D,S+=e*H,K+=e*J,T+=e*Q,e=t[11],v+=e*P,b+=e*O,g+=e*N,_+=e*C,A+=e*F,d+=e*I,U+=e*G,E+=e*Z,x+=e*j,M+=e*q,m+=e*V,B+=e*X;S+=e*D;K+=e*H,T+=e*J,Y+=e*Q,e=t[12],b+=e*P,g+=e*O,_+=e*N,A+=e*C,d+=e*F,U+=e*I,E+=e*G,x+=e*Z,M+=e*j,m+=e*q,B+=e*V,S+=e*X,K+=e*D,T+=e*H,Y+=e*J,k+=e*Q,e=t[13],g+=e*P,_+=e*O,A+=e*N,d+=e*C,U+=e*F,E+=e*I,x+=e*G,M+=e*Z,m+=e*j,B+=e*q,S+=e*V,K+=e*X,T+=e*D,Y+=e*H,k+=e*J,L+=e*Q,e=t[14],_+=e*P,A+=e*O,d+=e*N,U+=e*C,E+=e*F,x+=e*I,M+=e*G,m+=e*Z,B+=e*j,S+=e*q,K+=e*V,T+=e*X,Y+=e*D,k+=e*H,L+=e*J,z+=e*Q,e=t[15],A+=e*P,d+=e*O,U+=e*N,E+=e*C,x+=e*F,M+=e*I,m+=e*G,B+=e*Z,S+=e*j,K+=e*q,T+=e*V,Y+=e*X,k+=e*D,L+=e*H,z+=e*J,R+=e*Q,i+=38*d,h+=38*U,a+=38*E,f+=38*x,s+=38*M,c+=38*m,u+=38*B,y+=38*S,l+=38*K,w+=38*T,p+=38*Y,v+=38*k,b+=38*L,g+=38*z,_+=38*R,o=1,e=i+o+65535,o=Math.floor(e/65536),i=e-65536*o,e=h+o+65535,o=Math.floor(e/65536),h=e-65536*o,e=a+o+65535,o=Math.floor(e/65536),a=e-65536*o,e=f+o+65535,o=Math.floor(e/65536),f=e-65536*o,e=s+o+65535,o=Math.floor(e/65536),s=e-65536*o,e=c+o+65535,o=Math.floor(e/65536),c=e-65536*o,e=u+o+65535,o=Math.floor(e/65536),u=e-65536*o,e=y+o+65535,o=Math.floor(e/65536),y=e-65536*o,e=l+o+65535,o=Math.floor(e/65536),l=e-65536*o,e=w+o+65535,o=Math.floor(e/65536),w=e-65536*o,e=p+o+65535,o=Math.floor(e/65536),p=e-65536*o,e=v+o+65535,o=Math.floor(e/65536),v=e-65536*o,e=b+o+65535,o=Math.floor(e/65536),b=e-65536*o,e=g+o+65535,o=Math.floor(e/65536),g=e-65536*o,e=_+o+65535,o=Math.floor(e/65536),_=e-65536*o,e=A+o+65535,o=Math.floor(e/65536),A=e-65536*o,i+=o-1+37*(o-1),o=1,e=i+o+65535,o=Math.floor(e/65536),i=e-65536*o,e=h+o+65535,o=Math.floor(e/65536),h=e-65536*o,e=a+o+65535,o=Math.floor(e/65536),a=e-65536*o,e=f+o+65535,o=Math.floor(e/65536),f=e-65536*o,e=s+o+65535,o=Math.floor(e/65536),s=e-65536*o,e=c+o+65535,o=Math.floor(e/65536),c=e-65536*o,e=u+o+65535,o=Math.floor(e/65536),u=e-65536*o,e=y+o+65535,o=Math.floor(e/65536),y=e-65536*o,e=l+o+65535,o=Math.floor(e/65536),l=e-65536*o,e=w+o+65535,o=Math.floor(e/65536),w=e-65536*o,e=p+o+65535,o=Math.floor(e/65536),p=e-65536*o,e=v+o+65535,o=Math.floor(e/65536),v=e-65536*o,e=b+o+65535,o=Math.floor(e/65536),b=e-65536*o,e=g+o+65535,o=Math.floor(e/65536),g=e-65536*o,e=_+o+65535,o=Math.floor(e/65536),_=e-65536*o,e=A+o+65535,o=Math.floor(e/65536),A=e-65536*o,i+=o-1+37*(o-1),r[0]=i,r[1]=h,r[2]=a,r[3]=f,r[4]=s,r[5]=c,r[6]=u,r[7]=y,r[8]=l,r[9]=w,r[10]=p,r[11]=v,r[12]=b,r[13]=g;r[14]=_;r[15]=A}function B(r,t){m(r,t,t)}function S(r,t){var n,e=$();for(n=0;n<16;n++)e[n]=t[n];for(n=253;n>=0;n--)B(e,e),2!==n&&4!==n&&m(e,e,t);for(n=0;n<16;n++)r[n]=e[n]}function K(r,t){var n,e=$();for(n=0;n<16;n++)e[n]=t[n];for(n=250;n>=0;n--)B(e,e),1!==n&&m(e,e,t);for(n=0;n<16;n++)r[n]=e[n]}function T(r,t,n){var e,o,i=new Uint8Array(32),h=new Float64Array(80),a=$(),f=$(),s=$(),c=$(),u=$(),y=$();for(o=0;o<31;o++)i[o]=t[o];for(i[31]=127&t[31]|64,i[0]&=248,E(h,n),o=0;o<16;o++)f[o]=h[o],c[o]=a[o]=s[o]=0;for(a[0]=c[0]=1,o=254;o>=0;--o)e=i[o>>>3]>>>(7&o)&1,_(a,f,e),_(s,c,e),x(u,a,s),M(a,a,s),x(s,f,c),M(f,f,c),B(c,u),B(y,a),m(a,s,a),m(s,f,u),x(u,a,s),M(a,a,s),B(f,a),M(s,c,y),m(a,s,ir),x(a,a,c),m(s,s,a),m(a,c,y),m(c,f,h),B(f,u),_(a,f,e),_(s,c,e);for(o=0;o<16;o++)h[o+16]=a[o],h[o+32]=s[o],h[o+48]=f[o],h[o+64]=c[o];var l=h.subarray(32),w=h.subarray(16);return S(l,l),m(w,w,l),A(r,w),0}function Y(r,t){return T(r,t,nr)}function k(r,t){return rr(t,32),Y(r,t)}function L(r,t,n){var e=new Uint8Array(32);return T(e,n,t),f(r,tr,e,ur)}function z(r,t,n,e,o,i){var h=new Uint8Array(32);return L(h,o,i),lr(r,t,n,e,h)}function R(r,t,n,e,o,i){var h=new Uint8Array(32);return L(h,o,i),wr(r,t,n,e,h)}function P(r,t,n,e){for(var o,i,h,a,f,s,c,u,y,l,w,p,v,b,g,_,A,d,U,E,x,M,m,B,S,K,T=new Int32Array(16),Y=new Int32Array(16),k=r[0],L=r[1],z=r[2],R=r[3],P=r[4],O=r[5],N=r[6],C=r[7],F=t[0],I=t[1],G=t[2],Z=t[3],j=t[4],q=t[5],V=t[6],X=t[7],D=0;e>=128;){for(U=0;U<16;U++)E=8*U+D,T[U]=n[E+0]<<24|n[E+1]<<16|n[E+2]<<8|n[E+3],Y[U]=n[E+4]<<24|n[E+5]<<16|n[E+6]<<8|n[E+7];for(U=0;U<80;U++)if(o=k,i=L,h=z,a=R,f=P,s=O,c=N,u=C,y=F,l=I,w=G,p=Z,v=j,b=q,g=V,_=X,x=C,M=X,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=(P>>>14|j<<18)^(P>>>18|j<<14)^(j>>>9|P<<23),M=(j>>>14|P<<18)^(j>>>18|P<<14)^(P>>>9|j<<23),m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,x=P&O^~P&N,M=j&q^~j&V,m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,x=pr[2*U],M=pr[2*U+1],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,x=T[U%16],M=Y[U%16],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,A=65535&S|K<<16,d=65535&m|B<<16,x=A,M=d,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=(k>>>28|F<<4)^(F>>>2|k<<30)^(F>>>7|k<<25),M=(F>>>28|k<<4)^(k>>>2|F<<30)^(k>>>7|F<<25),m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,x=k&L^k&z^L&z,M=F&I^F&G^I&G,m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,u=65535&S|K<<16,_=65535&m|B<<16,x=a,M=p,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=A,M=d,m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,a=65535&S|K<<16,p=65535&m|B<<16,L=o,z=i,R=h,P=a,O=f,N=s,C=c,k=u,I=y,G=l,Z=w,j=p,q=v,V=b,X=g,F=_,U%16===15)for(E=0;E<16;E++)x=T[E],M=Y[E],m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=T[(E+9)%16],M=Y[(E+9)%16],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,A=T[(E+1)%16],d=Y[(E+1)%16],x=(A>>>1|d<<31)^(A>>>8|d<<24)^A>>>7,M=(d>>>1|A<<31)^(d>>>8|A<<24)^(d>>>7|A<<25),m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,A=T[(E+14)%16],d=Y[(E+14)%16],x=(A>>>19|d<<13)^(d>>>29|A<<3)^A>>>6,M=(d>>>19|A<<13)^(A>>>29|d<<3)^(d>>>6|A<<26),m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,T[E]=65535&S|K<<16,Y[E]=65535&m|B<<16;x=k,M=F,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[0],M=t[0],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[0]=k=65535&S|K<<16,t[0]=F=65535&m|B<<16,x=L,M=I,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[1],M=t[1],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[1]=L=65535&S|K<<16,t[1]=I=65535&m|B<<16,x=z,M=G,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[2],M=t[2],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[2]=z=65535&S|K<<16,t[2]=G=65535&m|B<<16,x=R,M=Z,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[3],M=t[3],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[3]=R=65535&S|K<<16,t[3]=Z=65535&m|B<<16,x=P,M=j,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[4],M=t[4],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[4]=P=65535&S|K<<16,t[4]=j=65535&m|B<<16,x=O,M=q,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[5],M=t[5],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[5]=O=65535&S|K<<16,t[5]=q=65535&m|B<<16,x=N,M=V,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[6],M=t[6],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[6]=N=65535&S|K<<16,t[6]=V=65535&m|B<<16,x=C,M=X,m=65535&M,B=M>>>16,S=65535&x,K=x>>>16,x=r[7],M=t[7],m+=65535&M,B+=M>>>16,S+=65535&x,K+=x>>>16,B+=m>>>16,S+=B>>>16,K+=S>>>16,r[7]=C=65535&S|K<<16,t[7]=X=65535&m|B<<16,D+=128,e-=128}return e}function O(r,n,e){var o,i=new Int32Array(8),h=new Int32Array(8),a=new Uint8Array(256),f=e;for(i[0]=1779033703,i[1]=3144134277,i[2]=1013904242,i[3]=2773480762,i[4]=1359893119,i[5]=2600822924,i[6]=528734635,i[7]=1541459225,h[0]=4089235720,h[1]=2227873595,h[2]=4271175723,h[3]=1595750129,h[4]=2917565137,h[5]=725511199,h[6]=4215389547,h[7]=327033209,P(i,h,n,e),e%=128,o=0;o=0;--o)e=n[o/8|0]>>(7&o)&1,C(r,t,e),N(t,r),N(r,r),C(r,t,e)}function G(r,t){var n=[$(),$(),$(),$()];b(n[0],fr),b(n[1],sr),b(n[2],or),m(n[3],fr,sr),I(r,n,t)}function Z(r,t,n){var e,o=new Uint8Array(64),i=[$(),$(),$(),$()];for(n||rr(t,32),O(o,t,32),o[0]&=248,o[31]&=127,o[31]|=64,G(i,o),F(r,i),e=0;e<32;e++)t[e+32]=r[e];return 0}function j(r,t){var n,e,o,i;for(e=63;e>=32;--e){for(n=0,o=e-32,i=e-12;o>8,t[o]-=256*n;t[o]+=n,t[e]=0}for(n=0,o=0;o<32;o++)t[o]+=n-(t[31]>>4)*vr[o],n=t[o]>>8,t[o]&=255;for(o=0;o<32;o++)t[o]-=n*vr[o];for(e=0;e<32;e++)t[e+1]+=t[e]>>8,r[e]=255&t[e]}function q(r){var t,n=new Float64Array(64);for(t=0;t<64;t++)n[t]=r[t];for(t=0;t<64;t++)r[t]=0;j(r,n)}function V(r,t,n,e){var o,i,h=new Uint8Array(64),a=new Uint8Array(64),f=new Uint8Array(64),s=new Float64Array(64),c=[$(),$(),$(),$()];O(h,e,32),h[0]&=248,h[31]&=127,h[31]|=64;var u=n+64;for(o=0;o>7&&M(r[0],er,r[0]),m(r[3],r[0],r[1]),0)}function D(r,t,n,e){var i,h,a=new Uint8Array(32),f=new Uint8Array(64),s=[$(),$(),$(),$()],c=[$(),$(),$(),$()];if(h=-1,n<64)return-1;if(X(c,e))return-1;for(i=0;i>>13|n<<3),e=255&r[4]|(255&r[5])<<8,this.r[2]=7939&(n>>>10|e<<6),o=255&r[6]|(255&r[7])<<8,this.r[3]=8191&(e>>>7|o<<9),i=255&r[8]|(255&r[9])<<8,this.r[4]=255&(o>>>4|i<<12),this.r[5]=i>>>1&8190,h=255&r[10]|(255&r[11])<<8,this.r[6]=8191&(i>>>14|h<<2),a=255&r[12]|(255&r[13])<<8,this.r[7]=8065&(h>>>11|a<<5),f=255&r[14]|(255&r[15])<<8,this.r[8]=8191&(a>>>8|f<<8),this.r[9]=f>>>5&127,this.pad[0]=255&r[16]|(255&r[17])<<8,this.pad[1]=255&r[18]|(255&r[19])<<8,this.pad[2]=255&r[20]|(255&r[21])<<8,this.pad[3]=255&r[22]|(255&r[23])<<8,this.pad[4]=255&r[24]|(255&r[25])<<8,this.pad[5]=255&r[26]|(255&r[27])<<8,this.pad[6]=255&r[28]|(255&r[29])<<8,this.pad[7]=255&r[30]|(255&r[31])<<8};yr.prototype.blocks=function(r,t,n){for(var e,o,i,h,a,f,s,c,u,y,l,w,p,v,b,g,_,A,d,U=this.fin?0:2048,E=this.h[0],x=this.h[1],M=this.h[2],m=this.h[3],B=this.h[4],S=this.h[5],K=this.h[6],T=this.h[7],Y=this.h[8],k=this.h[9],L=this.r[0],z=this.r[1],R=this.r[2],P=this.r[3],O=this.r[4],N=this.r[5],C=this.r[6],F=this.r[7],I=this.r[8],G=this.r[9];n>=16;)e=255&r[t+0]|(255&r[t+1])<<8,E+=8191&e,o=255&r[t+2]|(255&r[t+3])<<8,x+=8191&(e>>>13|o<<3),i=255&r[t+4]|(255&r[t+5])<<8,M+=8191&(o>>>10|i<<6),h=255&r[t+6]|(255&r[t+7])<<8,m+=8191&(i>>>7|h<<9),a=255&r[t+8]|(255&r[t+9])<<8,B+=8191&(h>>>4|a<<12),S+=a>>>1&8191,f=255&r[t+10]|(255&r[t+11])<<8,K+=8191&(a>>>14|f<<2),s=255&r[t+12]|(255&r[t+13])<<8,T+=8191&(f>>>11|s<<5),c=255&r[t+14]|(255&r[t+15])<<8,Y+=8191&(s>>>8|c<<8),k+=c>>>5|U,u=0,y=u,y+=E*L,y+=x*(5*G),y+=M*(5*I),y+=m*(5*F),y+=B*(5*C),u=y>>>13,y&=8191,y+=S*(5*N),y+=K*(5*O),y+=T*(5*P),y+=Y*(5*R),y+=k*(5*z),u+=y>>>13,y&=8191,l=u,l+=E*z,l+=x*L,l+=M*(5*G),l+=m*(5*I),l+=B*(5*F),u=l>>>13,l&=8191,l+=S*(5*C),l+=K*(5*N),l+=T*(5*O),l+=Y*(5*P),l+=k*(5*R),u+=l>>>13,l&=8191,w=u,w+=E*R,w+=x*z,w+=M*L,w+=m*(5*G),w+=B*(5*I),u=w>>>13,w&=8191,w+=S*(5*F),w+=K*(5*C),w+=T*(5*N),w+=Y*(5*O),w+=k*(5*P),u+=w>>>13,w&=8191,p=u,p+=E*P,p+=x*R,p+=M*z,p+=m*L,p+=B*(5*G),u=p>>>13,p&=8191,p+=S*(5*I),p+=K*(5*F),p+=T*(5*C),p+=Y*(5*N),p+=k*(5*O),u+=p>>>13,p&=8191,v=u,v+=E*O,v+=x*P,v+=M*R,v+=m*z,v+=B*L,u=v>>>13,v&=8191,v+=S*(5*G),v+=K*(5*I),v+=T*(5*F),v+=Y*(5*C),v+=k*(5*N),u+=v>>>13,v&=8191,b=u,b+=E*N,b+=x*O,b+=M*P,b+=m*R,b+=B*z,u=b>>>13,b&=8191,b+=S*L,b+=K*(5*G),b+=T*(5*I),b+=Y*(5*F),b+=k*(5*C),u+=b>>>13,b&=8191,g=u,g+=E*C,g+=x*N,g+=M*O,g+=m*P,g+=B*R,u=g>>>13,g&=8191,g+=S*z,g+=K*L,g+=T*(5*G),g+=Y*(5*I),g+=k*(5*F),u+=g>>>13,g&=8191,_=u,_+=E*F,_+=x*C,_+=M*N,_+=m*O,_+=B*P,u=_>>>13,_&=8191,_+=S*R,_+=K*z,_+=T*L,_+=Y*(5*G),_+=k*(5*I),u+=_>>>13,_&=8191,A=u,A+=E*I,A+=x*F,A+=M*C,A+=m*N,A+=B*O,u=A>>>13,A&=8191,A+=S*P,A+=K*R,A+=T*z,A+=Y*L,A+=k*(5*G),u+=A>>>13,A&=8191,d=u,d+=E*G,d+=x*I,d+=M*F,d+=m*C,d+=B*N,u=d>>>13,d&=8191,d+=S*O,d+=K*P,d+=T*R,d+=Y*z,d+=k*L,u+=d>>>13,d&=8191,u=(u<<2)+u|0,u=u+y|0,y=8191&u,u>>>=13,l+=u,E=y,x=l,M=w,m=p,B=v,S=b,K=g,T=_,Y=A,k=d,t+=16,n-=16;this.h[0]=E,this.h[1]=x,this.h[2]=M,this.h[3]=m,this.h[4]=B,this.h[5]=S,this.h[6]=K,this.h[7]=T,this.h[8]=Y,this.h[9]=k},yr.prototype.finish=function(r,t){var n,e,o,i,h=new Uint16Array(10);if(this.leftover){for(i=this.leftover,this.buffer[i++]=1;i<16;i++)this.buffer[i]=0;this.fin=1,this.blocks(this.buffer,0,16)}for(n=this.h[1]>>>13,this.h[1]&=8191,i=2;i<10;i++)this.h[i]+=n,n=this.h[i]>>>13,this.h[i]&=8191;for(this.h[0]+=5*n,n=this.h[0]>>>13,this.h[0]&=8191,this.h[1]+=n,n=this.h[1]>>>13,this.h[1]&=8191,this.h[2]+=n,h[0]=this.h[0]+5,n=h[0]>>>13,h[0]&=8191,i=1;i<10;i++)h[i]=this.h[i]+n,n=h[i]>>>13,h[i]&=8191;for(h[9]-=8192,e=(1^n)-1,i=0;i<10;i++)h[i]&=e;for(e=~e,i=0;i<10;i++)this.h[i]=this.h[i]&e|h[i];for(this.h[0]=65535&(this.h[0]|this.h[1]<<13),this.h[1]=65535&(this.h[1]>>>3|this.h[2]<<10),this.h[2]=65535&(this.h[2]>>>6|this.h[3]<<7),this.h[3]=65535&(this.h[3]>>>9|this.h[4]<<4),this.h[4]=65535&(this.h[4]>>>12|this.h[5]<<1|this.h[6]<<14),this.h[5]=65535&(this.h[6]>>>2|this.h[7]<<11),this.h[6]=65535&(this.h[7]>>>5|this.h[8]<<8),this.h[7]=65535&(this.h[8]>>>8|this.h[9]<<5),o=this.h[0]+this.pad[0],this.h[0]=65535&o,i=1;i<8;i++)o=(this.h[i]+this.pad[i]|0)+(o>>>16)|0,this.h[i]=65535&o;r[t+0]=this.h[0]>>>0&255,r[t+1]=this.h[0]>>>8&255,r[t+2]=this.h[1]>>>0&255,r[t+3]=this.h[1]>>>8&255,r[t+4]=this.h[2]>>>0&255,r[t+5]=this.h[2]>>>8&255,r[t+6]=this.h[3]>>>0&255,r[t+7]=this.h[3]>>>8&255,r[t+8]=this.h[4]>>>0&255,r[t+9]=this.h[4]>>>8&255,r[t+10]=this.h[5]>>>0&255,r[t+11]=this.h[5]>>>8&255,r[t+12]=this.h[6]>>>0&255,r[t+13]=this.h[6]>>>8&255,r[t+14]=this.h[7]>>>0&255,r[t+15]=this.h[7]>>>8&255},yr.prototype.update=function(r,t,n){var e,o;if(this.leftover){for(o=16-this.leftover,o>n&&(o=n),e=0;e=16&&(o=n-n%16,this.blocks(r,t,o),t+=o,n-=o),n){for(e=0;e=0},r.sign.keyPair=function(){var r=new Uint8Array(Tr),t=new Uint8Array(Yr);return Z(r,t),{publicKey:r,secretKey:t}},r.sign.keyPair.fromSecretKey=function(r){if(Q(r),r.length!==Yr)throw new Error("bad secret key size");for(var t=new Uint8Array(Tr),n=0;n void): void; +} diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.js b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.js new file mode 100644 index 0000000..f72dd78 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.js @@ -0,0 +1,1175 @@ +(function(nacl) { +'use strict'; + +// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. +// Public domain. +// +// Implementation derived from TweetNaCl version 20140427. +// See for details: http://tweetnacl.cr.yp.to/ + +var u64 = function(h, l) { this.hi = h|0 >>> 0; this.lo = l|0 >>> 0; }; +var gf = function(init) { + var i, r = new Float64Array(16); + if (init) for (i = 0; i < init.length; i++) r[i] = init[i]; + return r; +}; + +// Pluggable, initialized in high-level API below. +var randombytes = function(/* x, n */) { throw new Error('no PRNG'); }; + +var _0 = new Uint8Array(16); +var _9 = new Uint8Array(32); _9[0] = 9; + +var gf0 = gf(), + gf1 = gf([1]), + _121665 = gf([0xdb41, 1]), + D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]), + D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]), + X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]), + Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]), + I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); + +function L32(x, c) { return (x << c) | (x >>> (32 - c)); } + +function ld32(x, i) { + var u = x[i+3] & 0xff; + u = (u<<8)|(x[i+2] & 0xff); + u = (u<<8)|(x[i+1] & 0xff); + return (u<<8)|(x[i+0] & 0xff); +} + +function dl64(x, i) { + var h = (x[i] << 24) | (x[i+1] << 16) | (x[i+2] << 8) | x[i+3]; + var l = (x[i+4] << 24) | (x[i+5] << 16) | (x[i+6] << 8) | x[i+7]; + return new u64(h, l); +} + +function st32(x, j, u) { + var i; + for (i = 0; i < 4; i++) { x[j+i] = u & 255; u >>>= 8; } +} + +function ts64(x, i, u) { + x[i] = (u.hi >> 24) & 0xff; + x[i+1] = (u.hi >> 16) & 0xff; + x[i+2] = (u.hi >> 8) & 0xff; + x[i+3] = u.hi & 0xff; + x[i+4] = (u.lo >> 24) & 0xff; + x[i+5] = (u.lo >> 16) & 0xff; + x[i+6] = (u.lo >> 8) & 0xff; + x[i+7] = u.lo & 0xff; +} + +function vn(x, xi, y, yi, n) { + var i,d = 0; + for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i]; + return (1 & ((d - 1) >>> 8)) - 1; +} + +function crypto_verify_16(x, xi, y, yi) { + return vn(x,xi,y,yi,16); +} + +function crypto_verify_32(x, xi, y, yi) { + return vn(x,xi,y,yi,32); +} + +function core(out,inp,k,c,h) { + var w = new Uint32Array(16), x = new Uint32Array(16), + y = new Uint32Array(16), t = new Uint32Array(4); + var i, j, m; + + for (i = 0; i < 4; i++) { + x[5*i] = ld32(c, 4*i); + x[1+i] = ld32(k, 4*i); + x[6+i] = ld32(inp, 4*i); + x[11+i] = ld32(k, 16+4*i); + } + + for (i = 0; i < 16; i++) y[i] = x[i]; + + for (i = 0; i < 20; i++) { + for (j = 0; j < 4; j++) { + for (m = 0; m < 4; m++) t[m] = x[(5*j+4*m)%16]; + t[1] ^= L32((t[0]+t[3])|0, 7); + t[2] ^= L32((t[1]+t[0])|0, 9); + t[3] ^= L32((t[2]+t[1])|0,13); + t[0] ^= L32((t[3]+t[2])|0,18); + for (m = 0; m < 4; m++) w[4*j+(j+m)%4] = t[m]; + } + for (m = 0; m < 16; m++) x[m] = w[m]; + } + + if (h) { + for (i = 0; i < 16; i++) x[i] = (x[i] + y[i]) | 0; + for (i = 0; i < 4; i++) { + x[5*i] = (x[5*i] - ld32(c, 4*i)) | 0; + x[6+i] = (x[6+i] - ld32(inp, 4*i)) | 0; + } + for (i = 0; i < 4; i++) { + st32(out,4*i,x[5*i]); + st32(out,16+4*i,x[6+i]); + } + } else { + for (i = 0; i < 16; i++) st32(out, 4 * i, (x[i] + y[i]) | 0); + } +} + +function crypto_core_salsa20(out,inp,k,c) { + core(out,inp,k,c,false); + return 0; +} + +function crypto_core_hsalsa20(out,inp,k,c) { + core(out,inp,k,c,true); + return 0; +} + +var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]); + // "expand 32-byte k" + +function crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + if (!b) return 0; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = (m?m[mpos+i]:0) ^ x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + if (m) mpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = (m?m[mpos+i]:0) ^ x[i]; + } + return 0; +} + +function crypto_stream_salsa20(c,cpos,d,n,k) { + return crypto_stream_salsa20_xor(c,cpos,null,0,d,n,k); +} + +function crypto_stream(c,cpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + return crypto_stream_salsa20(c,cpos,d,n.subarray(16),s); +} + +function crypto_stream_xor(c,cpos,m,mpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,n.subarray(16),s); +} + +function add1305(h, c) { + var j, u = 0; + for (j = 0; j < 17; j++) { + u = (u + ((h[j] + c[j]) | 0)) | 0; + h[j] = u & 255; + u >>>= 8; + } +} + +var minusp = new Uint32Array([ + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 +]); + +function crypto_onetimeauth(out, outpos, m, mpos, n, k) { + var s, i, j, u; + var x = new Uint32Array(17), r = new Uint32Array(17), + h = new Uint32Array(17), c = new Uint32Array(17), + g = new Uint32Array(17); + for (j = 0; j < 17; j++) r[j]=h[j]=0; + for (j = 0; j < 16; j++) r[j]=k[j]; + r[3]&=15; + r[4]&=252; + r[7]&=15; + r[8]&=252; + r[11]&=15; + r[12]&=252; + r[15]&=15; + + while (n > 0) { + for (j = 0; j < 17; j++) c[j] = 0; + for (j = 0; (j < 16) && (j < n); ++j) c[j] = m[mpos+j]; + c[j] = 1; + mpos += j; n -= j; + add1305(h,c); + for (i = 0; i < 17; i++) { + x[i] = 0; + for (j = 0; j < 17; j++) x[i] = (x[i] + (h[j] * ((j <= i) ? r[i - j] : ((320 * r[i + 17 - j])|0))) | 0) | 0; + } + for (i = 0; i < 17; i++) h[i] = x[i]; + u = 0; + for (j = 0; j < 16; j++) { + u = (u + h[j]) | 0; + h[j] = u & 255; + u >>>= 8; + } + u = (u + h[16]) | 0; h[16] = u & 3; + u = (5 * (u >>> 2)) | 0; + for (j = 0; j < 16; j++) { + u = (u + h[j]) | 0; + h[j] = u & 255; + u >>>= 8; + } + u = (u + h[16]) | 0; h[16] = u; + } + + for (j = 0; j < 17; j++) g[j] = h[j]; + add1305(h,minusp); + s = (-(h[16] >>> 7) | 0); + for (j = 0; j < 17; j++) h[j] ^= s & (g[j] ^ h[j]); + + for (j = 0; j < 16; j++) c[j] = k[j + 16]; + c[16] = 0; + add1305(h,c); + for (j = 0; j < 16; j++) out[outpos+j] = h[j]; + return 0; +} + +function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) { + var x = new Uint8Array(16); + crypto_onetimeauth(x,0,m,mpos,n,k); + return crypto_verify_16(h,hpos,x,0); +} + +function crypto_secretbox(c,m,d,n,k) { + var i; + if (d < 32) return -1; + crypto_stream_xor(c,0,m,0,d,n,k); + crypto_onetimeauth(c, 16, c, 32, d - 32, c); + for (i = 0; i < 16; i++) c[i] = 0; + return 0; +} + +function crypto_secretbox_open(m,c,d,n,k) { + var i; + var x = new Uint8Array(32); + if (d < 32) return -1; + crypto_stream(x,0,32,n,k); + if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1; + crypto_stream_xor(m,0,c,0,d,n,k); + for (i = 0; i < 32; i++) m[i] = 0; + return 0; +} + +function set25519(r, a) { + var i; + for (i = 0; i < 16; i++) r[i] = a[i]|0; +} + +function car25519(o) { + var c; + var i; + for (i = 0; i < 16; i++) { + o[i] += 65536; + c = Math.floor(o[i] / 65536); + o[(i+1)*(i<15?1:0)] += c - 1 + 37 * (c-1) * (i===15?1:0); + o[i] -= (c * 65536); + } +} + +function sel25519(p, q, b) { + var t, c = ~(b-1); + for (var i = 0; i < 16; i++) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } +} + +function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for (i = 0; i < 16; i++) t[i] = n[i]; + car25519(t); + car25519(t); + car25519(t); + for (j = 0; j < 2; j++) { + m[0] = t[0] - 0xffed; + for (i = 1; i < 15; i++) { + m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); + b = (m[15]>>16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1-b); + } + for (i = 0; i < 16; i++) { + o[2*i] = t[i] & 0xff; + o[2*i+1] = t[i]>>8; + } +} + +function neq25519(a, b) { + var c = new Uint8Array(32), d = new Uint8Array(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); +} + +function par25519(a) { + var d = new Uint8Array(32); + pack25519(d, a); + return d[0] & 1; +} + +function unpack25519(o, n) { + var i; + for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); + o[15] &= 0x7fff; +} + +function A(o, a, b) { + var i; + for (i = 0; i < 16; i++) o[i] = (a[i] + b[i])|0; +} + +function Z(o, a, b) { + var i; + for (i = 0; i < 16; i++) o[i] = (a[i] - b[i])|0; +} + +function M(o, a, b) { + var i, j, t = new Float64Array(31); + for (i = 0; i < 31; i++) t[i] = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < 16; j++) { + t[i+j] += a[i] * b[j]; + } + } + for (i = 0; i < 15; i++) { + t[i] += 38 * t[i+16]; + } + for (i = 0; i < 16; i++) o[i] = t[i]; + car25519(o); + car25519(o); +} + +function S(o, a) { + M(o, a, a); +} + +function inv25519(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 253; a >= 0; a--) { + S(c, c); + if(a !== 2 && a !== 4) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function pow2523(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 250; a >= 0; a--) { + S(c, c); + if(a !== 1) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function crypto_scalarmult(q, n, p) { + var z = new Uint8Array(32); + var x = new Float64Array(80), r, i; + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(); + for (i = 0; i < 31; i++) z[i] = n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + for (i = 0; i < 16; i++) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for (i=254; i>=0; --i) { + r=(z[i>>>3]>>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + for (i = 0; i < 16; i++) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + var x32 = x.subarray(32); + var x16 = x.subarray(16); + inv25519(x32,x32); + M(x16,x16,x32); + pack25519(q,x16); + return 0; +} + +function crypto_scalarmult_base(q, n) { + return crypto_scalarmult(q, n, _9); +} + +function crypto_box_keypair(y, x) { + randombytes(x, 32); + return crypto_scalarmult_base(y, x); +} + +function crypto_box_beforenm(k, y, x) { + var s = new Uint8Array(32); + crypto_scalarmult(s, x, y); + return crypto_core_hsalsa20(k, _0, s, sigma); +} + +var crypto_box_afternm = crypto_secretbox; +var crypto_box_open_afternm = crypto_secretbox_open; + +function crypto_box(c, m, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_afternm(c, m, d, n, k); +} + +function crypto_box_open(m, c, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_open_afternm(m, c, d, n, k); +} + +function add64() { + var a = 0, b = 0, c = 0, d = 0, m16 = 65535, l, h, i; + for (i = 0; i < arguments.length; i++) { + l = arguments[i].lo; + h = arguments[i].hi; + a += (l & m16); b += (l >>> 16); + c += (h & m16); d += (h >>> 16); + } + + b += (a >>> 16); + c += (b >>> 16); + d += (c >>> 16); + + return new u64((c & m16) | (d << 16), (a & m16) | (b << 16)); +} + +function shr64(x, c) { + return new u64((x.hi >>> c), (x.lo >>> c) | (x.hi << (32 - c))); +} + +function xor64() { + var l = 0, h = 0, i; + for (i = 0; i < arguments.length; i++) { + l ^= arguments[i].lo; + h ^= arguments[i].hi; + } + return new u64(h, l); +} + +function R(x, c) { + var h, l, c1 = 32 - c; + if (c < 32) { + h = (x.hi >>> c) | (x.lo << c1); + l = (x.lo >>> c) | (x.hi << c1); + } else if (c < 64) { + h = (x.lo >>> c) | (x.hi << c1); + l = (x.hi >>> c) | (x.lo << c1); + } + return new u64(h, l); +} + +function Ch(x, y, z) { + var h = (x.hi & y.hi) ^ (~x.hi & z.hi), + l = (x.lo & y.lo) ^ (~x.lo & z.lo); + return new u64(h, l); +} + +function Maj(x, y, z) { + var h = (x.hi & y.hi) ^ (x.hi & z.hi) ^ (y.hi & z.hi), + l = (x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo); + return new u64(h, l); +} + +function Sigma0(x) { return xor64(R(x,28), R(x,34), R(x,39)); } +function Sigma1(x) { return xor64(R(x,14), R(x,18), R(x,41)); } +function sigma0(x) { return xor64(R(x, 1), R(x, 8), shr64(x,7)); } +function sigma1(x) { return xor64(R(x,19), R(x,61), shr64(x,6)); } + +var K = [ + new u64(0x428a2f98, 0xd728ae22), new u64(0x71374491, 0x23ef65cd), + new u64(0xb5c0fbcf, 0xec4d3b2f), new u64(0xe9b5dba5, 0x8189dbbc), + new u64(0x3956c25b, 0xf348b538), new u64(0x59f111f1, 0xb605d019), + new u64(0x923f82a4, 0xaf194f9b), new u64(0xab1c5ed5, 0xda6d8118), + new u64(0xd807aa98, 0xa3030242), new u64(0x12835b01, 0x45706fbe), + new u64(0x243185be, 0x4ee4b28c), new u64(0x550c7dc3, 0xd5ffb4e2), + new u64(0x72be5d74, 0xf27b896f), new u64(0x80deb1fe, 0x3b1696b1), + new u64(0x9bdc06a7, 0x25c71235), new u64(0xc19bf174, 0xcf692694), + new u64(0xe49b69c1, 0x9ef14ad2), new u64(0xefbe4786, 0x384f25e3), + new u64(0x0fc19dc6, 0x8b8cd5b5), new u64(0x240ca1cc, 0x77ac9c65), + new u64(0x2de92c6f, 0x592b0275), new u64(0x4a7484aa, 0x6ea6e483), + new u64(0x5cb0a9dc, 0xbd41fbd4), new u64(0x76f988da, 0x831153b5), + new u64(0x983e5152, 0xee66dfab), new u64(0xa831c66d, 0x2db43210), + new u64(0xb00327c8, 0x98fb213f), new u64(0xbf597fc7, 0xbeef0ee4), + new u64(0xc6e00bf3, 0x3da88fc2), new u64(0xd5a79147, 0x930aa725), + new u64(0x06ca6351, 0xe003826f), new u64(0x14292967, 0x0a0e6e70), + new u64(0x27b70a85, 0x46d22ffc), new u64(0x2e1b2138, 0x5c26c926), + new u64(0x4d2c6dfc, 0x5ac42aed), new u64(0x53380d13, 0x9d95b3df), + new u64(0x650a7354, 0x8baf63de), new u64(0x766a0abb, 0x3c77b2a8), + new u64(0x81c2c92e, 0x47edaee6), new u64(0x92722c85, 0x1482353b), + new u64(0xa2bfe8a1, 0x4cf10364), new u64(0xa81a664b, 0xbc423001), + new u64(0xc24b8b70, 0xd0f89791), new u64(0xc76c51a3, 0x0654be30), + new u64(0xd192e819, 0xd6ef5218), new u64(0xd6990624, 0x5565a910), + new u64(0xf40e3585, 0x5771202a), new u64(0x106aa070, 0x32bbd1b8), + new u64(0x19a4c116, 0xb8d2d0c8), new u64(0x1e376c08, 0x5141ab53), + new u64(0x2748774c, 0xdf8eeb99), new u64(0x34b0bcb5, 0xe19b48a8), + new u64(0x391c0cb3, 0xc5c95a63), new u64(0x4ed8aa4a, 0xe3418acb), + new u64(0x5b9cca4f, 0x7763e373), new u64(0x682e6ff3, 0xd6b2b8a3), + new u64(0x748f82ee, 0x5defb2fc), new u64(0x78a5636f, 0x43172f60), + new u64(0x84c87814, 0xa1f0ab72), new u64(0x8cc70208, 0x1a6439ec), + new u64(0x90befffa, 0x23631e28), new u64(0xa4506ceb, 0xde82bde9), + new u64(0xbef9a3f7, 0xb2c67915), new u64(0xc67178f2, 0xe372532b), + new u64(0xca273ece, 0xea26619c), new u64(0xd186b8c7, 0x21c0c207), + new u64(0xeada7dd6, 0xcde0eb1e), new u64(0xf57d4f7f, 0xee6ed178), + new u64(0x06f067aa, 0x72176fba), new u64(0x0a637dc5, 0xa2c898a6), + new u64(0x113f9804, 0xbef90dae), new u64(0x1b710b35, 0x131c471b), + new u64(0x28db77f5, 0x23047d84), new u64(0x32caab7b, 0x40c72493), + new u64(0x3c9ebe0a, 0x15c9bebc), new u64(0x431d67c4, 0x9c100d4c), + new u64(0x4cc5d4be, 0xcb3e42b6), new u64(0x597f299c, 0xfc657e2a), + new u64(0x5fcb6fab, 0x3ad6faec), new u64(0x6c44198c, 0x4a475817) +]; + +function crypto_hashblocks(x, m, n) { + var z = [], b = [], a = [], w = [], t, i, j; + + for (i = 0; i < 8; i++) z[i] = a[i] = dl64(x, 8*i); + + var pos = 0; + while (n >= 128) { + for (i = 0; i < 16; i++) w[i] = dl64(m, 8*i+pos); + for (i = 0; i < 80; i++) { + for (j = 0; j < 8; j++) b[j] = a[j]; + t = add64(a[7], Sigma1(a[4]), Ch(a[4], a[5], a[6]), K[i], w[i%16]); + b[7] = add64(t, Sigma0(a[0]), Maj(a[0], a[1], a[2])); + b[3] = add64(b[3], t); + for (j = 0; j < 8; j++) a[(j+1)%8] = b[j]; + if (i%16 === 15) { + for (j = 0; j < 16; j++) { + w[j] = add64(w[j], w[(j+9)%16], sigma0(w[(j+1)%16]), sigma1(w[(j+14)%16])); + } + } + } + + for (i = 0; i < 8; i++) { + a[i] = add64(a[i], z[i]); + z[i] = a[i]; + } + + pos += 128; + n -= 128; + } + + for (i = 0; i < 8; i++) ts64(x, 8*i, z[i]); + return n; +} + +var iv = new Uint8Array([ + 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, + 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, + 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, + 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, + 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, + 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, + 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, + 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +]); + +function crypto_hash(out, m, n) { + var h = new Uint8Array(64), x = new Uint8Array(256); + var i, b = n; + + for (i = 0; i < 64; i++) h[i] = iv[i]; + + crypto_hashblocks(h, m, n); + n %= 128; + + for (i = 0; i < 256; i++) x[i] = 0; + for (i = 0; i < n; i++) x[i] = m[b-n+i]; + x[n] = 128; + + n = 256-128*(n<112?1:0); + x[n-9] = 0; + ts64(x, n-8, new u64((b / 0x20000000) | 0, b << 3)); + crypto_hashblocks(h, x, n); + + for (i = 0; i < 64; i++) out[i] = h[i]; + + return 0; +} + +function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +function cswap(p, q, b) { + var i; + for (i = 0; i < 4; i++) { + sel25519(p[i], q[i], b); + } +} + +function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for (i = 255; i >= 0; --i) { + b = (s[(i/8)|0] >> (i&7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } +} + +function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); +} + +function crypto_sign_keypair(pk, sk, seeded) { + var d = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()]; + var i; + + if (!seeded) randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for (i = 0; i < 32; i++) sk[i+32] = pk[i]; + return 0; +} + +var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); + +function modL(r, x) { + var carry, i, j, k; + for (i = 63; i >= 32; --i) { + carry = 0; + for (j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for (j = 0; j < 32; j++) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for (j = 0; j < 32; j++) x[j] -= carry * L[j]; + for (i = 0; i < 32; i++) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +function reduce(r) { + var x = new Float64Array(64), i; + for (i = 0; i < 64; i++) x[i] = r[i]; + for (i = 0; i < 64; i++) r[i] = 0; + modL(r, x); +} + +// Note: difference from C - smlen returned, not passed as argument. +function crypto_sign(sm, m, n, sk) { + var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for (i = 0; i < n; i++) sm[64 + i] = m[i]; + for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm.subarray(32), n+32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for (i = 32; i < 64; i++) sm[i] = sk[i]; + crypto_hash(h, sm, n + 64); + reduce(h); + + for (i = 0; i < 64; i++) x[i] = 0; + for (i = 0; i < 32; i++) x[i] = r[i]; + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + x[i+j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; +} + +function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D); + Z(num, num, r[2]); + A(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) M(r[0], r[0], I); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) return -1; + + if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]); + + M(r[3], r[0], r[1]); + return 0; +} + +function crypto_sign_open(m, sm, n, pk) { + var i, mlen; + var t = new Uint8Array(32), h = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + mlen = -1; + if (n < 64) return -1; + + if (unpackneg(q, pk)) return -1; + + for (i = 0; i < n; i++) m[i] = sm[i]; + for (i = 0; i < 32; i++) m[i+32] = pk[i]; + crypto_hash(h, m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if (crypto_verify_32(sm, 0, t, 0)) { + for (i = 0; i < n; i++) m[i] = 0; + return -1; + } + + for (i = 0; i < n; i++) m[i] = sm[i + 64]; + mlen = n; + return mlen; +} + +var crypto_secretbox_KEYBYTES = 32, + crypto_secretbox_NONCEBYTES = 24, + crypto_secretbox_ZEROBYTES = 32, + crypto_secretbox_BOXZEROBYTES = 16, + crypto_scalarmult_BYTES = 32, + crypto_scalarmult_SCALARBYTES = 32, + crypto_box_PUBLICKEYBYTES = 32, + crypto_box_SECRETKEYBYTES = 32, + crypto_box_BEFORENMBYTES = 32, + crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES, + crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES, + crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES, + crypto_sign_BYTES = 64, + crypto_sign_PUBLICKEYBYTES = 32, + crypto_sign_SECRETKEYBYTES = 64, + crypto_sign_SEEDBYTES = 32, + crypto_hash_BYTES = 64; + +nacl.lowlevel = { + crypto_core_hsalsa20: crypto_core_hsalsa20, + crypto_stream_xor: crypto_stream_xor, + crypto_stream: crypto_stream, + crypto_stream_salsa20_xor: crypto_stream_salsa20_xor, + crypto_stream_salsa20: crypto_stream_salsa20, + crypto_onetimeauth: crypto_onetimeauth, + crypto_onetimeauth_verify: crypto_onetimeauth_verify, + crypto_verify_16: crypto_verify_16, + crypto_verify_32: crypto_verify_32, + crypto_secretbox: crypto_secretbox, + crypto_secretbox_open: crypto_secretbox_open, + crypto_scalarmult: crypto_scalarmult, + crypto_scalarmult_base: crypto_scalarmult_base, + crypto_box_beforenm: crypto_box_beforenm, + crypto_box_afternm: crypto_box_afternm, + crypto_box: crypto_box, + crypto_box_open: crypto_box_open, + crypto_box_keypair: crypto_box_keypair, + crypto_hash: crypto_hash, + crypto_sign: crypto_sign, + crypto_sign_keypair: crypto_sign_keypair, + crypto_sign_open: crypto_sign_open, + + crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES, + crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES, + crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES, + crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES, + crypto_scalarmult_BYTES: crypto_scalarmult_BYTES, + crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES, + crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES, + crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES, + crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES, + crypto_box_NONCEBYTES: crypto_box_NONCEBYTES, + crypto_box_ZEROBYTES: crypto_box_ZEROBYTES, + crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES, + crypto_sign_BYTES: crypto_sign_BYTES, + crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES, + crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES, + crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES, + crypto_hash_BYTES: crypto_hash_BYTES +}; + +/* High-level API */ + +function checkLengths(k, n) { + if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size'); + if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size'); +} + +function checkBoxLengths(pk, sk) { + if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size'); + if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size'); +} + +function checkArrayTypes() { + var t, i; + for (i = 0; i < arguments.length; i++) { + if ((t = Object.prototype.toString.call(arguments[i])) !== '[object Uint8Array]') + throw new TypeError('unexpected type ' + t + ', use Uint8Array'); + } +} + +function cleanup(arr) { + for (var i = 0; i < arr.length; i++) arr[i] = 0; +} + +// TODO: Completely remove this in v0.15. +if (!nacl.util) { + nacl.util = {}; + nacl.util.decodeUTF8 = nacl.util.encodeUTF8 = nacl.util.encodeBase64 = nacl.util.decodeBase64 = function() { + throw new Error('nacl.util moved into separate package: https://github.com/dchest/tweetnacl-util-js'); + }; +} + +nacl.randomBytes = function(n) { + var b = new Uint8Array(n); + randombytes(b, n); + return b; +}; + +nacl.secretbox = function(msg, nonce, key) { + checkArrayTypes(msg, nonce, key); + checkLengths(key, nonce); + var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); + var c = new Uint8Array(m.length); + for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i]; + crypto_secretbox(c, m, m.length, nonce, key); + return c.subarray(crypto_secretbox_BOXZEROBYTES); +}; + +nacl.secretbox.open = function(box, nonce, key) { + checkArrayTypes(box, nonce, key); + checkLengths(key, nonce); + var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length); + var m = new Uint8Array(c.length); + for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i]; + if (c.length < 32) return false; + if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return false; + return m.subarray(crypto_secretbox_ZEROBYTES); +}; + +nacl.secretbox.keyLength = crypto_secretbox_KEYBYTES; +nacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES; +nacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES; + +nacl.scalarMult = function(n, p) { + checkArrayTypes(n, p); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult(q, n, p); + return q; +}; + +nacl.scalarMult.base = function(n) { + checkArrayTypes(n); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult_base(q, n); + return q; +}; + +nacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES; +nacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES; + +nacl.box = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox(msg, nonce, k); +}; + +nacl.box.before = function(publicKey, secretKey) { + checkArrayTypes(publicKey, secretKey); + checkBoxLengths(publicKey, secretKey); + var k = new Uint8Array(crypto_box_BEFORENMBYTES); + crypto_box_beforenm(k, publicKey, secretKey); + return k; +}; + +nacl.box.after = nacl.secretbox; + +nacl.box.open = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox.open(msg, nonce, k); +}; + +nacl.box.open.after = nacl.secretbox.open; + +nacl.box.keyPair = function() { + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.box.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_box_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + crypto_scalarmult_base(pk, secretKey); + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES; +nacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES; +nacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES; +nacl.box.nonceLength = crypto_box_NONCEBYTES; +nacl.box.overheadLength = nacl.secretbox.overheadLength; + +nacl.sign = function(msg, secretKey) { + checkArrayTypes(msg, secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length); + crypto_sign(signedMsg, msg, msg.length, secretKey); + return signedMsg; +}; + +nacl.sign.open = function(signedMsg, publicKey) { + if (arguments.length !== 2) + throw new Error('nacl.sign.open accepts 2 arguments; did you mean to use nacl.sign.detached.verify?'); + checkArrayTypes(signedMsg, publicKey); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var tmp = new Uint8Array(signedMsg.length); + var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey); + if (mlen < 0) return null; + var m = new Uint8Array(mlen); + for (var i = 0; i < m.length; i++) m[i] = tmp[i]; + return m; +}; + +nacl.sign.detached = function(msg, secretKey) { + var signedMsg = nacl.sign(msg, secretKey); + var sig = new Uint8Array(crypto_sign_BYTES); + for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; + return sig; +}; + +nacl.sign.detached.verify = function(msg, sig, publicKey) { + checkArrayTypes(msg, sig, publicKey); + if (sig.length !== crypto_sign_BYTES) + throw new Error('bad signature size'); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var sm = new Uint8Array(crypto_sign_BYTES + msg.length); + var m = new Uint8Array(crypto_sign_BYTES + msg.length); + var i; + for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; + for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i]; + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); +}; + +nacl.sign.keyPair = function() { + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + crypto_sign_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i]; + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.sign.keyPair.fromSeed = function(seed) { + checkArrayTypes(seed); + if (seed.length !== crypto_sign_SEEDBYTES) + throw new Error('bad seed size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + for (var i = 0; i < 32; i++) sk[i] = seed[i]; + crypto_sign_keypair(pk, sk, true); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES; +nacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES; +nacl.sign.seedLength = crypto_sign_SEEDBYTES; +nacl.sign.signatureLength = crypto_sign_BYTES; + +nacl.hash = function(msg) { + checkArrayTypes(msg); + var h = new Uint8Array(crypto_hash_BYTES); + crypto_hash(h, msg, msg.length); + return h; +}; + +nacl.hash.hashLength = crypto_hash_BYTES; + +nacl.verify = function(x, y) { + checkArrayTypes(x, y); + // Zero length arguments are considered not equal. + if (x.length === 0 || y.length === 0) return false; + if (x.length !== y.length) return false; + return (vn(x, 0, y, 0, x.length) === 0) ? true : false; +}; + +nacl.setPRNG = function(fn) { + randombytes = fn; +}; + +(function() { + // Initialize PRNG if environment provides CSPRNG. + // If not, methods calling randombytes will throw. + var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null; + if (crypto && crypto.getRandomValues) { + // Browsers. + var QUOTA = 65536; + nacl.setPRNG(function(x, n) { + var i, v = new Uint8Array(n); + for (i = 0; i < n; i += QUOTA) { + crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA))); + } + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } else if (typeof require !== 'undefined') { + // Node.js. + crypto = require('crypto'); + if (crypto && crypto.randomBytes) { + nacl.setPRNG(function(x, n) { + var i, v = crypto.randomBytes(n); + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } + } +})(); + +})(typeof module !== 'undefined' && module.exports ? module.exports : (self.nacl = self.nacl || {})); diff --git a/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.min.js b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.min.js new file mode 100644 index 0000000..4484974 --- /dev/null +++ b/tasks/enduro-trails/prototype/node_modules/tweetnacl/nacl.min.js @@ -0,0 +1 @@ +!function(r){"use strict";function n(r,n){return r<>>32-n}function e(r,n){var e=255&r[n+3];return e=e<<8|255&r[n+2],e=e<<8|255&r[n+1],e<<8|255&r[n+0]}function t(r,n){var e=r[n]<<24|r[n+1]<<16|r[n+2]<<8|r[n+3],t=r[n+4]<<24|r[n+5]<<16|r[n+6]<<8|r[n+7];return new sr(e,t)}function o(r,n,e){var t;for(t=0;t<4;t++)r[n+t]=255&e,e>>>=8}function i(r,n,e){r[n]=e.hi>>24&255,r[n+1]=e.hi>>16&255,r[n+2]=e.hi>>8&255,r[n+3]=255&e.hi,r[n+4]=e.lo>>24&255,r[n+5]=e.lo>>16&255,r[n+6]=e.lo>>8&255,r[n+7]=255&e.lo}function a(r,n,e,t,o){var i,a=0;for(i=0;i>>8)-1}function f(r,n,e,t){return a(r,n,e,t,16)}function u(r,n,e,t){return a(r,n,e,t,32)}function c(r,t,i,a,f){var u,c,w,y=new Uint32Array(16),l=new Uint32Array(16),s=new Uint32Array(16),h=new Uint32Array(4);for(u=0;u<4;u++)l[5*u]=e(a,4*u),l[1+u]=e(i,4*u),l[6+u]=e(t,4*u),l[11+u]=e(i,16+4*u);for(u=0;u<16;u++)s[u]=l[u];for(u=0;u<20;u++){for(c=0;c<4;c++){for(w=0;w<4;w++)h[w]=l[(5*c+4*w)%16];for(h[1]^=n(h[0]+h[3]|0,7),h[2]^=n(h[1]+h[0]|0,9),h[3]^=n(h[2]+h[1]|0,13),h[0]^=n(h[3]+h[2]|0,18),w=0;w<4;w++)y[4*c+(c+w)%4]=h[w]}for(w=0;w<16;w++)l[w]=y[w]}if(f){for(u=0;u<16;u++)l[u]=l[u]+s[u]|0;for(u=0;u<4;u++)l[5*u]=l[5*u]-e(a,4*u)|0,l[6+u]=l[6+u]-e(t,4*u)|0;for(u=0;u<4;u++)o(r,4*u,l[5*u]),o(r,16+4*u,l[6+u])}else for(u=0;u<16;u++)o(r,4*u,l[u]+s[u]|0)}function w(r,n,e,t){return c(r,n,e,t,!1),0}function y(r,n,e,t){return c(r,n,e,t,!0),0}function l(r,n,e,t,o,i,a){var f,u,c=new Uint8Array(16),y=new Uint8Array(64);if(!o)return 0;for(u=0;u<16;u++)c[u]=0;for(u=0;u<8;u++)c[u]=i[u];for(;o>=64;){for(w(y,c,a,Br),u=0;u<64;u++)r[n+u]=(e?e[t+u]:0)^y[u];for(f=1,u=8;u<16;u++)f=f+(255&c[u])|0,c[u]=255&f,f>>>=8;o-=64,n+=64,e&&(t+=64)}if(o>0)for(w(y,c,a,Br),u=0;u>>=8}function b(r,n,e,t,o,i){var a,f,u,c,w=new Uint32Array(17),y=new Uint32Array(17),l=new Uint32Array(17),s=new Uint32Array(17),h=new Uint32Array(17);for(u=0;u<17;u++)y[u]=l[u]=0;for(u=0;u<16;u++)y[u]=i[u];for(y[3]&=15,y[4]&=252,y[7]&=15,y[8]&=252,y[11]&=15,y[12]&=252,y[15]&=15;o>0;){for(u=0;u<17;u++)s[u]=0;for(u=0;u<16&&u>>=8;for(c=c+l[16]|0,l[16]=3&c,c=5*(c>>>2)|0,u=0;u<16;u++)c=c+l[u]|0,l[u]=255&c,c>>>=8;c=c+l[16]|0,l[16]=c}for(u=0;u<17;u++)h[u]=l[u];for(v(l,Sr),a=0|-(l[16]>>>7),u=0;u<17;u++)l[u]^=a&(h[u]^l[u]);for(u=0;u<16;u++)s[u]=i[u+16];for(s[16]=0,v(l,s),u=0;u<16;u++)r[n+u]=l[u];return 0}function p(r,n,e,t,o,i){var a=new Uint8Array(16);return b(a,0,e,t,o,i),f(r,n,a,0)}function _(r,n,e,t,o){var i;if(e<32)return-1;for(g(r,0,n,0,e,t,o),b(r,16,r,32,e-32,r),i=0;i<16;i++)r[i]=0;return 0}function A(r,n,e,t,o){var i,a=new Uint8Array(32);if(e<32)return-1;if(h(a,0,32,t,o),0!==p(n,16,n,32,e-32,a))return-1;for(g(r,0,n,0,e,t,o),i=0;i<32;i++)r[i]=0;return 0}function U(r,n){var e;for(e=0;e<16;e++)r[e]=0|n[e]}function E(r){var n,e;for(e=0;e<16;e++)r[e]+=65536,n=Math.floor(r[e]/65536),r[(e+1)*(e<15?1:0)]+=n-1+37*(n-1)*(15===e?1:0),r[e]-=65536*n}function d(r,n,e){for(var t,o=~(e-1),i=0;i<16;i++)t=o&(r[i]^n[i]),r[i]^=t,n[i]^=t}function x(r,n){var e,t,o,i=hr(),a=hr();for(e=0;e<16;e++)a[e]=n[e];for(E(a),E(a),E(a),t=0;t<2;t++){for(i[0]=a[0]-65517,e=1;e<15;e++)i[e]=a[e]-65535-(i[e-1]>>16&1),i[e-1]&=65535;i[15]=a[15]-32767-(i[14]>>16&1),o=i[15]>>16&1,i[14]&=65535,d(a,i,1-o)}for(e=0;e<16;e++)r[2*e]=255&a[e],r[2*e+1]=a[e]>>8}function m(r,n){var e=new Uint8Array(32),t=new Uint8Array(32);return x(e,r),x(t,n),u(e,0,t,0)}function B(r){var n=new Uint8Array(32);return x(n,r),1&n[0]}function S(r,n){var e;for(e=0;e<16;e++)r[e]=n[2*e]+(n[2*e+1]<<8);r[15]&=32767}function K(r,n,e){var t;for(t=0;t<16;t++)r[t]=n[t]+e[t]|0}function T(r,n,e){var t;for(t=0;t<16;t++)r[t]=n[t]-e[t]|0}function Y(r,n,e){var t,o,i=new Float64Array(31);for(t=0;t<31;t++)i[t]=0;for(t=0;t<16;t++)for(o=0;o<16;o++)i[t+o]+=n[t]*e[o];for(t=0;t<15;t++)i[t]+=38*i[t+16];for(t=0;t<16;t++)r[t]=i[t];E(r),E(r)}function L(r,n){Y(r,n,n)}function k(r,n){var e,t=hr();for(e=0;e<16;e++)t[e]=n[e];for(e=253;e>=0;e--)L(t,t),2!==e&&4!==e&&Y(t,t,n);for(e=0;e<16;e++)r[e]=t[e]}function z(r,n){var e,t=hr();for(e=0;e<16;e++)t[e]=n[e];for(e=250;e>=0;e--)L(t,t),1!==e&&Y(t,t,n);for(e=0;e<16;e++)r[e]=t[e]}function R(r,n,e){var t,o,i=new Uint8Array(32),a=new Float64Array(80),f=hr(),u=hr(),c=hr(),w=hr(),y=hr(),l=hr();for(o=0;o<31;o++)i[o]=n[o];for(i[31]=127&n[31]|64,i[0]&=248,S(a,e),o=0;o<16;o++)u[o]=a[o],w[o]=f[o]=c[o]=0;for(f[0]=w[0]=1,o=254;o>=0;--o)t=i[o>>>3]>>>(7&o)&1,d(f,u,t),d(c,w,t),K(y,f,c),T(f,f,c),K(c,u,w),T(u,u,w),L(w,y),L(l,f),Y(f,c,f),Y(c,u,y),K(y,f,c),T(f,f,c),L(u,f),T(c,w,l),Y(f,c,Ar),K(f,f,w),Y(c,c,f),Y(f,w,l),Y(w,u,a),L(u,y),d(f,u,t),d(c,w,t);for(o=0;o<16;o++)a[o+16]=f[o],a[o+32]=c[o],a[o+48]=u[o],a[o+64]=w[o];var s=a.subarray(32),h=a.subarray(16);return k(s,s),Y(h,h,s),x(r,h),0}function P(r,n){return R(r,n,br)}function O(r,n){return gr(n,32),P(r,n)}function F(r,n,e){var t=new Uint8Array(32);return R(t,e,n),y(r,vr,t,Br)}function N(r,n,e,t,o,i){var a=new Uint8Array(32);return F(a,o,i),Kr(r,n,e,t,a)}function C(r,n,e,t,o,i){var a=new Uint8Array(32);return F(a,o,i),Tr(r,n,e,t,a)}function M(){var r,n,e,t=0,o=0,i=0,a=0,f=65535;for(e=0;e>>16,i+=n&f,a+=n>>>16;return o+=t>>>16,i+=o>>>16,a+=i>>>16,new sr(i&f|a<<16,t&f|o<<16)}function G(r,n){return new sr(r.hi>>>n,r.lo>>>n|r.hi<<32-n)}function Z(){var r,n=0,e=0;for(r=0;r>>n|r.lo<>>n|r.hi<>>n|r.hi<>>n|r.lo<=128;){for(a=0;a<16;a++)y[a]=t(n,8*a+l);for(a=0;a<80;a++){for(f=0;f<8;f++)c[f]=w[f];for(o=M(w[7],X(w[4]),q(w[4],w[5],w[6]),Yr[a],y[a%16]),c[7]=M(o,V(w[0]),I(w[0],w[1],w[2])),c[3]=M(c[3],o),f=0;f<8;f++)w[(f+1)%8]=c[f];if(a%16===15)for(f=0;f<16;f++)y[f]=M(y[f],y[(f+9)%16],D(y[(f+1)%16]),H(y[(f+14)%16]))}for(a=0;a<8;a++)w[a]=M(w[a],u[a]),u[a]=w[a];l+=128,e-=128}for(a=0;a<8;a++)i(r,8*a,u[a]);return e}function Q(r,n,e){var t,o=new Uint8Array(64),a=new Uint8Array(256),f=e;for(t=0;t<64;t++)o[t]=Lr[t];for(J(o,n,e),e%=128,t=0;t<256;t++)a[t]=0;for(t=0;t=0;--o)t=e[o/8|0]>>(7&o)&1,$(r,n,t),W(n,r),W(r,r),$(r,n,t)}function er(r,n){var e=[hr(),hr(),hr(),hr()];U(e[0],dr),U(e[1],xr),U(e[2],_r),Y(e[3],dr,xr),nr(r,e,n)}function tr(r,n,e){var t,o=new Uint8Array(64),i=[hr(),hr(),hr(),hr()];for(e||gr(n,32),Q(o,n,32),o[0]&=248,o[31]&=127,o[31]|=64,er(i,o),rr(r,i),t=0;t<32;t++)n[t+32]=r[t];return 0}function or(r,n){var e,t,o,i;for(t=63;t>=32;--t){for(e=0,o=t-32,i=t-12;o>8,n[o]-=256*e;n[o]+=e,n[t]=0}for(e=0,o=0;o<32;o++)n[o]+=e-(n[31]>>4)*kr[o],e=n[o]>>8,n[o]&=255;for(o=0;o<32;o++)n[o]-=e*kr[o];for(t=0;t<32;t++)n[t+1]+=n[t]>>8,r[t]=255&n[t]}function ir(r){var n,e=new Float64Array(64);for(n=0;n<64;n++)e[n]=r[n];for(n=0;n<64;n++)r[n]=0;or(r,e)}function ar(r,n,e,t){var o,i,a=new Uint8Array(64),f=new Uint8Array(64),u=new Uint8Array(64),c=new Float64Array(64),w=[hr(),hr(),hr(),hr()];Q(a,t,32),a[0]&=248,a[31]&=127,a[31]|=64;var y=e+64;for(o=0;o>7&&T(r[0],pr,r[0]),Y(r[3],r[0],r[1]),0)}function ur(r,n,e,t){var o,i,a=new Uint8Array(32),f=new Uint8Array(64),c=[hr(),hr(),hr(),hr()],w=[hr(),hr(),hr(),hr()];if(i=-1,e<64)return-1;if(fr(w,t))return-1;for(o=0;o=0},r.sign.keyPair=function(){var r=new Uint8Array(Vr),n=new Uint8Array(Xr);return tr(r,n),{publicKey:r,secretKey:n}},r.sign.keyPair.fromSecretKey=function(r){if(yr(r),r.length!==Xr)throw new Error("bad secret key size");for(var n=new Uint8Array(Vr),e=0;e/dev/null && browserify test/browser/init.js test/*.quick.js | uglifyjs -c -m -o test/browser/_bundle-quick.js 2>/dev/null", + "test": "npm run test-node-all && npm run test-browser", + "bench": "node test/benchmark/bench.js", + "lint": "eslint nacl.js nacl-fast.js test/*.js test/benchmark/*.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/dchest/tweetnacl-js.git" + }, + "keywords": [ + "crypto", + "cryptography", + "curve25519", + "ed25519", + "encrypt", + "hash", + "key", + "nacl", + "poly1305", + "public", + "salsa20", + "signatures" + ], + "author": "TweetNaCl-js contributors", + "license": "Unlicense", + "bugs": { + "url": "https://github.com/dchest/tweetnacl-js/issues" + }, + "homepage": "https://tweetnacl.js.org", + "devDependencies": { + "browserify": "^13.0.0", + "eslint": "^2.2.0", + "faucet": "^0.0.1", + "tap-browser-color": "^0.1.2", + "tape": "^4.4.0", + "tape-run": "^2.1.3", + "tweetnacl-util": "^0.13.3", + "uglify-js": "^2.6.1" + }, + "browser": { + "buffer": false, + "crypto": false + } +} diff --git a/tasks/enduro-trails/prototype/package-lock.json b/tasks/enduro-trails/prototype/package-lock.json new file mode 100644 index 0000000..ccbfe3b --- /dev/null +++ b/tasks/enduro-trails/prototype/package-lock.json @@ -0,0 +1,89 @@ +{ + "name": "prototype", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "ssh2": "^1.17.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/buildcheck": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz", + "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==", + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/cpu-features": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", + "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.19.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/nan": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", + "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", + "license": "MIT", + "optional": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/ssh2": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.17.0.tgz", + "integrity": "sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==", + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.23.0" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" + } + } +} diff --git a/tasks/enduro-trails/prototype/package.json b/tasks/enduro-trails/prototype/package.json new file mode 100644 index 0000000..6cc60ad --- /dev/null +++ b/tasks/enduro-trails/prototype/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "ssh2": "^1.17.0" + } +} diff --git a/tasks/enduro-trails/prototype/static/app.js b/tasks/enduro-trails/prototype/static/app.js index 244fe8e..330a490 100644 --- a/tasks/enduro-trails/prototype/static/app.js +++ b/tasks/enduro-trails/prototype/static/app.js @@ -1627,21 +1627,57 @@ let rulerTotal = 0; function toggleRuler() { const btn = document.getElementById('tb-ruler'); - if (!rulerMode && rulerPoints.length === 0) { - // Enter ruler mode fresh + + if (rulerMode) { + // Режим активен → выйти из режима, скрыть линейку (точки сохраняются в rulerPoints) + rulerMode = false; + btn.classList.remove('active'); + window._map.getCanvas().style.cursor = ''; + // Убрать маркеры с карты + удалить DOM-элементы + rulerMarkers.forEach(m => { + const el = m.getElement(); + if (el && el.parentNode) el.parentNode.removeChild(el); + m.remove(); + }); + rulerMarkers = []; + const map = window._map; + try { if (map.getLayer('ruler-line')) map.removeLayer('ruler-line'); } catch(e) {} + try { if (map.getSource('ruler')) map.removeSource('ruler'); } catch(e) {} + document.getElementById('ruler-info').classList.remove('visible'); + updateMapModeClass(); + + } else if (rulerPoints.length > 0) { + // Линейка скрыта, точки есть → восстановить и войти в режим рисования deactivateAllModes(); rulerMode = true; btn.classList.add('active'); window._map.getCanvas().style.cursor = 'crosshair'; - // Fix 4: do NOT show panel yet — show only after first point - showRulerToast(); - } else if (rulerMode) { - // Bug 1: toolbar button = "Завершить" (exit mode, keep points) - exitRulerMode(); - } else { - // rulerMode=false but points exist — just show the panel + const pts = [...rulerPoints]; + rulerPoints = []; + rulerTotal = 0; + rulerMarkers = []; + pts.forEach(pt => addRulerPoint({ lng: pt[0], lat: pt[1] })); document.getElementById('ruler-info').classList.add('visible'); + updateMapModeClass(); + + } else { + // Нет линейки → войти в режим рисования + deactivateAllModes(); + rulerMode = true; + btn.classList.add('active'); + window._map.getCanvas().style.cursor = 'crosshair'; + showRulerToast(); + updateMapModeClass(); } +} + +function deleteRuler() { + rulerMode = false; + const btn = document.getElementById('tb-ruler'); + if (btn) btn.classList.remove('active'); + window._map.getCanvas().style.cursor = ''; + clearRuler(); + document.getElementById('ruler-info').classList.remove('visible'); updateMapModeClass(); } diff --git a/tasks/enduro-trails/prototype/static/index.html b/tasks/enduro-trails/prototype/static/index.html index 0313058..a208551 100644 --- a/tasks/enduro-trails/prototype/static/index.html +++ b/tasks/enduro-trails/prototype/static/index.html @@ -24,7 +24,7 @@

0 км - +
Тапни на карту чтобы добавить точку