From 2da68ec34ff42626f46f5bbbab3116d50172a1e0 Mon Sep 17 00:00:00 2001
From: Ivan Dimov <78815270+idimov-keeper@users.noreply.github.com>
Date: Mon, 11 Dec 2023 18:29:56 -0600
Subject: [PATCH] Added Keeper Secrets Manager provider
---
Makefile | 1 +
README.md | 31 +
go.mod | 4 +-
go.sum | 17 +-
pkg/providers/keeper_secretsmanager.go | 234 ++
pkg/providers/keeper_secretsmanager_test.go | 60 +
.../keeper_secretsmanager_mock.go | 65 +
pkg/wizard_template.go | 16 +
.../secrets-manager-go/core/LICENSE.txt | 21 +
.../secrets-manager-go/core/README.md | 197 ++
.../secrets-manager-go/core/cache.go | 87 +
.../secrets-manager-go/core/config_keys.go | 62 +
.../secrets-manager-go/core/core.go | 2371 +++++++++++++++++
.../secrets-manager-go/core/crypto.go | 475 ++++
.../secrets-manager-go/core/dtos.go | 1685 ++++++++++++
.../secrets-manager-go/core/helpers.go | 66 +
.../secrets-manager-go/core/keeper_globals.go | 69 +
.../secrets-manager-go/core/logger/logger.go | 227 ++
.../secrets-manager-go/core/payload.go | 337 +++
.../secrets-manager-go/core/record_data.go | 783 ++++++
.../secrets-manager-go/core/storage.go | 298 +++
.../secrets-manager-go/core/utils.go | 715 +++++
.../x/crypto/curve25519/curve25519.go | 99 +-
.../x/crypto/curve25519/curve25519_compat.go | 105 +
.../x/crypto/curve25519/curve25519_go120.go | 46 +
.../x/crypto/openpgp/packet/compressed.go | 2 +-
vendor/golang.org/x/crypto/ssh/cipher.go | 3 +-
vendor/golang.org/x/crypto/ssh/common.go | 9 +-
vendor/golang.org/x/crypto/ssh/connection.go | 2 +-
vendor/golang.org/x/crypto/ssh/keys.go | 6 +-
vendor/golang.org/x/crypto/ssh/transport.go | 3 +-
vendor/golang.org/x/net/http2/frame.go | 11 +-
vendor/golang.org/x/net/http2/hpack/hpack.go | 79 +-
vendor/golang.org/x/net/http2/pipe.go | 6 +-
vendor/golang.org/x/net/http2/server.go | 25 +-
vendor/golang.org/x/net/http2/transport.go | 11 +-
vendor/golang.org/x/sys/cpu/hwcap_linux.go | 15 +
vendor/golang.org/x/sys/cpu/runtime_auxv.go | 16 +
.../x/sys/cpu/runtime_auxv_go121.go | 19 +
vendor/golang.org/x/sys/execabs/execabs.go | 2 +-
.../golang.org/x/sys/execabs/execabs_go118.go | 6 +
.../golang.org/x/sys/execabs/execabs_go119.go | 4 +
vendor/golang.org/x/sys/unix/ioctl_signed.go | 70 +
.../sys/unix/{ioctl.go => ioctl_unsigned.go} | 21 +-
vendor/golang.org/x/sys/unix/ioctl_zos.go | 20 +-
vendor/golang.org/x/sys/unix/mkerrors.sh | 2 +
vendor/golang.org/x/sys/unix/ptrace_darwin.go | 6 +
vendor/golang.org/x/sys/unix/ptrace_ios.go | 6 +
vendor/golang.org/x/sys/unix/syscall_aix.go | 7 +-
.../golang.org/x/sys/unix/syscall_aix_ppc.go | 1 -
.../x/sys/unix/syscall_aix_ppc64.go | 1 -
vendor/golang.org/x/sys/unix/syscall_bsd.go | 3 +-
.../golang.org/x/sys/unix/syscall_darwin.go | 15 +-
.../x/sys/unix/syscall_darwin_amd64.go | 1 +
.../x/sys/unix/syscall_darwin_arm64.go | 1 +
.../x/sys/unix/syscall_dragonfly.go | 2 +-
.../golang.org/x/sys/unix/syscall_freebsd.go | 44 +-
.../x/sys/unix/syscall_freebsd_386.go | 17 +-
.../x/sys/unix/syscall_freebsd_amd64.go | 17 +-
.../x/sys/unix/syscall_freebsd_arm.go | 15 +-
.../x/sys/unix/syscall_freebsd_arm64.go | 15 +-
.../x/sys/unix/syscall_freebsd_riscv64.go | 15 +-
vendor/golang.org/x/sys/unix/syscall_hurd.go | 8 +
vendor/golang.org/x/sys/unix/syscall_linux.go | 46 +-
.../x/sys/unix/syscall_linux_386.go | 27 -
.../x/sys/unix/syscall_linux_amd64.go | 1 -
.../x/sys/unix/syscall_linux_arm.go | 27 -
.../x/sys/unix/syscall_linux_arm64.go | 10 -
.../x/sys/unix/syscall_linux_loong64.go | 5 -
.../x/sys/unix/syscall_linux_mips64x.go | 1 -
.../x/sys/unix/syscall_linux_mipsx.go | 27 -
.../x/sys/unix/syscall_linux_ppc.go | 27 -
.../x/sys/unix/syscall_linux_ppc64x.go | 1 -
.../x/sys/unix/syscall_linux_riscv64.go | 1 -
.../x/sys/unix/syscall_linux_s390x.go | 1 -
.../x/sys/unix/syscall_linux_sparc64.go | 1 -
.../golang.org/x/sys/unix/syscall_netbsd.go | 7 +-
.../golang.org/x/sys/unix/syscall_openbsd.go | 2 +-
.../golang.org/x/sys/unix/syscall_solaris.go | 36 +-
vendor/golang.org/x/sys/unix/syscall_unix.go | 7 +
.../x/sys/unix/syscall_zos_s390x.go | 6 +-
.../x/sys/unix/zerrors_darwin_amd64.go | 19 +
.../x/sys/unix/zerrors_darwin_arm64.go | 19 +
vendor/golang.org/x/sys/unix/zerrors_linux.go | 10 +-
.../x/sys/unix/zptrace_armnn_linux.go | 8 +-
.../x/sys/unix/zptrace_linux_arm64.go | 4 +-
.../x/sys/unix/zptrace_mipsnn_linux.go | 8 +-
.../x/sys/unix/zptrace_mipsnnle_linux.go | 8 +-
.../x/sys/unix/zptrace_x86_linux.go | 8 +-
.../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 23 +-
.../x/sys/unix/zsyscall_aix_ppc64.go | 24 +-
.../x/sys/unix/zsyscall_aix_ppc64_gc.go | 17 +-
.../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 18 +-
.../x/sys/unix/zsyscall_darwin_amd64.go | 55 +-
.../x/sys/unix/zsyscall_darwin_amd64.s | 11 +-
.../x/sys/unix/zsyscall_darwin_arm64.go | 55 +-
.../x/sys/unix/zsyscall_darwin_arm64.s | 11 +-
.../x/sys/unix/zsyscall_dragonfly_amd64.go | 20 +-
.../x/sys/unix/zsyscall_freebsd_386.go | 30 +-
.../x/sys/unix/zsyscall_freebsd_amd64.go | 30 +-
.../x/sys/unix/zsyscall_freebsd_arm.go | 30 +-
.../x/sys/unix/zsyscall_freebsd_arm64.go | 30 +-
.../x/sys/unix/zsyscall_freebsd_riscv64.go | 30 +-
.../golang.org/x/sys/unix/zsyscall_linux.go | 20 +-
.../x/sys/unix/zsyscall_linux_386.go | 10 -
.../x/sys/unix/zsyscall_linux_amd64.go | 10 -
.../x/sys/unix/zsyscall_linux_arm.go | 10 -
.../x/sys/unix/zsyscall_linux_arm64.go | 10 -
.../x/sys/unix/zsyscall_linux_mips.go | 10 -
.../x/sys/unix/zsyscall_linux_mips64.go | 10 -
.../x/sys/unix/zsyscall_linux_mips64le.go | 10 -
.../x/sys/unix/zsyscall_linux_mipsle.go | 10 -
.../x/sys/unix/zsyscall_linux_ppc.go | 10 -
.../x/sys/unix/zsyscall_linux_ppc64.go | 10 -
.../x/sys/unix/zsyscall_linux_ppc64le.go | 10 -
.../x/sys/unix/zsyscall_linux_riscv64.go | 10 -
.../x/sys/unix/zsyscall_linux_s390x.go | 10 -
.../x/sys/unix/zsyscall_linux_sparc64.go | 10 -
.../x/sys/unix/zsyscall_netbsd_386.go | 20 +-
.../x/sys/unix/zsyscall_netbsd_amd64.go | 20 +-
.../x/sys/unix/zsyscall_netbsd_arm.go | 20 +-
.../x/sys/unix/zsyscall_netbsd_arm64.go | 20 +-
.../x/sys/unix/zsyscall_openbsd_386.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_386.s | 5 -
.../x/sys/unix/zsyscall_openbsd_amd64.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_amd64.s | 5 -
.../x/sys/unix/zsyscall_openbsd_arm.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_arm.s | 5 -
.../x/sys/unix/zsyscall_openbsd_arm64.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_arm64.s | 5 -
.../x/sys/unix/zsyscall_openbsd_mips64.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_mips64.s | 5 -
.../x/sys/unix/zsyscall_openbsd_ppc64.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_ppc64.s | 6 -
.../x/sys/unix/zsyscall_openbsd_riscv64.go | 22 +-
.../x/sys/unix/zsyscall_openbsd_riscv64.s | 5 -
.../x/sys/unix/zsyscall_solaris_amd64.go | 26 +-
.../x/sys/unix/zsyscall_zos_s390x.go | 12 +-
.../x/sys/unix/ztypes_darwin_amd64.go | 11 +
.../x/sys/unix/ztypes_darwin_arm64.go | 11 +
.../x/sys/unix/ztypes_freebsd_386.go | 2 +-
.../x/sys/unix/ztypes_freebsd_amd64.go | 2 +-
.../x/sys/unix/ztypes_freebsd_arm.go | 2 +-
.../x/sys/unix/ztypes_freebsd_arm64.go | 2 +-
.../x/sys/unix/ztypes_freebsd_riscv64.go | 2 +-
vendor/golang.org/x/sys/unix/ztypes_linux.go | 140 +-
.../golang.org/x/sys/unix/ztypes_linux_386.go | 2 +-
.../x/sys/unix/ztypes_linux_amd64.go | 2 +-
.../golang.org/x/sys/unix/ztypes_linux_arm.go | 2 +-
.../x/sys/unix/ztypes_linux_arm64.go | 2 +-
.../x/sys/unix/ztypes_linux_loong64.go | 2 +-
.../x/sys/unix/ztypes_linux_mips.go | 2 +-
.../x/sys/unix/ztypes_linux_mips64.go | 2 +-
.../x/sys/unix/ztypes_linux_mips64le.go | 2 +-
.../x/sys/unix/ztypes_linux_mipsle.go | 2 +-
.../golang.org/x/sys/unix/ztypes_linux_ppc.go | 2 +-
.../x/sys/unix/ztypes_linux_ppc64.go | 2 +-
.../x/sys/unix/ztypes_linux_ppc64le.go | 2 +-
.../x/sys/unix/ztypes_linux_riscv64.go | 2 +-
.../x/sys/unix/ztypes_linux_s390x.go | 2 +-
.../x/sys/unix/ztypes_linux_sparc64.go | 2 +-
.../x/sys/windows/syscall_windows.go | 6 +-
.../golang.org/x/sys/windows/types_windows.go | 89 +-
.../x/sys/windows/zsyscall_windows.go | 27 +
.../x/text/unicode/norm/forminfo.go | 2 +-
vendor/modules.txt | 6 +-
166 files changed, 9069 insertions(+), 1009 deletions(-)
create mode 100644 pkg/providers/keeper_secretsmanager.go
create mode 100644 pkg/providers/keeper_secretsmanager_test.go
create mode 100644 pkg/providers/mock_providers/keeper_secretsmanager_mock.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/LICENSE.txt
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/README.md
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/cache.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/config_keys.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/core.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/crypto.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/dtos.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/helpers.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/keeper_globals.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/logger/logger.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/payload.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/record_data.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/storage.go
create mode 100644 vendor/github.com/keeper-security/secrets-manager-go/core/utils.go
create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_compat.go
create mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_go120.go
create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv.go
create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go
create mode 100644 vendor/golang.org/x/sys/unix/ioctl_signed.go
rename vendor/golang.org/x/sys/unix/{ioctl.go => ioctl_unsigned.go} (76%)
diff --git a/Makefile b/Makefile
index 13300d15..09522042 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,7 @@ mocks:
mockgen -source pkg/providers/gopass.go -destination pkg/providers/mock_providers/gopass_mock.go
mockgen -source pkg/providers/github.go -destination pkg/providers/mock_providers/github_mock.go
mockgen -source pkg/providers/azure_keyvault.go -destination pkg/providers/mock_providers/azure_keyvault_mock.go
+ mockgen -source pkg/providers/keeper_secretsmanager.go -destination pkg/providers/mock_providers/keeper_secretsmanager_mock.go
readme:
yarn readme
lint:
diff --git a/README.md b/README.md
index ba5cf36a..a4748403 100644
--- a/README.md
+++ b/README.md
@@ -1174,6 +1174,37 @@ providers:
path: bar
```
+## Keeper Secrets Manager
+
+### Authentication
+
+Configuration is environment based - you should populate `KSM_CONFIG=base64_config` or `KSM_CONFIG_FILE=ksm_config.json` in your environment with a valid [Secrets Manager Configuration](https://docs.keeper.io/secrets-manager/secrets-manager/about/secrets-manager-configuration#creating-a-secrets-manager-configuration). If both environment variables are set then `KSM_CONFIG` is used.
+
+Note:
+- _Secrets Manager CLI configuration file format (INI) is different from KSM SDK configuration format (JSON) but the CLI [command](https://docs.keeper.io/secrets-manager/secrets-manager/secrets-manager-command-line-interface/profile-command#export) `ksm profile export profile_name` can be used to export some of the individual profiles into JSON config file compatible with the provider._
+
+### Features
+
+- Sync - `yes`
+- Mapping - `yes`
+- Modes - `read`
+- Key format
+ - `env_sync` - path is single record UID. Field labels (if empty -> field types) are used as keys, any duplicates will have a numeric suffix.
+ - `env` - any string, conforming to Keeper [Notation](https://docs.keeper.io/secrets-manager/secrets-manager/about/keeper-notation) _(`keeper://` prefix not required)_
+
+### Example Config
+
+```yaml
+keeper_secretsmanager:
+ env_sync:
+ path: ABCDEFGHIJKLMNOPQRSTUV
+ env:
+ PGUSER:
+ path: ABCDEFGHIJKLMNOPQRSTUV/field/login
+ CERT:
+ path: ABCDEFGHIJKLMNOPQRSTUV/custom_field/ssl_cert
+```
+
# Semantics
## Addressing
diff --git a/go.mod b/go.mod
index 700a7c4e..800941f8 100644
--- a/go.mod
+++ b/go.mod
@@ -119,6 +119,7 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
+ github.com/keeper-security/secrets-manager-go/core v1.6.2
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
@@ -140,7 +141,7 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
- github.com/sosedoff/ansible-vault-go v0.2.0 // indirect
+ github.com/sosedoff/ansible-vault-go v0.2.0
github.com/spf13/cobra v0.0.5 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/twpayne/go-pinentry v0.2.0 // indirect
@@ -160,7 +161,6 @@ require (
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
- golang.org/x/tools v0.6.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/grpc v1.35.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
diff --git a/go.sum b/go.sum
index a446efff..ae386b46 100644
--- a/go.sum
+++ b/go.sum
@@ -579,6 +579,8 @@ github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/keeper-security/secrets-manager-go/core v1.6.2 h1:bRZUJI/s5WwVbceSNlKyKqYuBNKkZCyNPH4lU2GYiF0=
+github.com/keeper-security/secrets-manager-go/core v1.6.2/go.mod h1:dtlaeeds9+SZsbDAZnQRsDSqEAK9a62SYtqhNql+VgQ=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -935,8 +937,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
-golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -976,7 +976,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
+golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1025,8 +1025,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1138,14 +1136,10 @@ golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1157,8 +1151,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1227,10 +1219,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
-golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/pkg/providers/keeper_secretsmanager.go b/pkg/providers/keeper_secretsmanager.go
new file mode 100644
index 00000000..6f4f4ee6
--- /dev/null
+++ b/pkg/providers/keeper_secretsmanager.go
@@ -0,0 +1,234 @@
+package providers
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+
+ ksm "github.com/keeper-security/secrets-manager-go/core"
+ "github.com/spectralops/teller/pkg/core"
+ "github.com/spectralops/teller/pkg/logging"
+)
+
+type KsmClient interface {
+ GetSecret(p core.KeyPath) (*core.EnvEntry, error)
+ GetSecrets(p core.KeyPath) ([]core.EnvEntry, error)
+}
+
+type KeeperSecretsManager struct {
+ client KsmClient
+ logger logging.Logger
+}
+
+const keeperName = "keeper_secretsmanager"
+
+//nolint
+func init() {
+ metaInto := core.MetaInfo{
+ Description: "Keeper Secrets Manager",
+ Name: keeperName,
+ Authentication: "You should populate `KSM_CONFIG=Base64ConfigString or KSM_CONFIG_FILE=ksm_config.json` in your environment.",
+ ConfigTemplate: `
+ keeper_secretsmanager:
+ env_sync:
+ path: record_uid
+ env:
+ FOO_BAR:
+ path: UID/custom_field/foo_bar
+ # use Keeper Notation to pull data from typed records
+`,
+ Ops: core.OpMatrix{Get: true, GetMapping: true},
+ }
+ RegisterProvider(metaInto, NewKeeperSecretsManager)
+}
+
+type SecretsManagerClient struct {
+ sm *ksm.SecretsManager
+}
+
+func (c SecretsManagerClient) GetSecret(p core.KeyPath) (*core.EnvEntry, error) {
+ nr, err := c.sm.GetNotationResults(p.Path)
+ if err != nil {
+ return nil, err
+ }
+
+ ent := core.EnvEntry{}
+ if len(nr) > 0 {
+ ent = p.Found(nr[0])
+ } else {
+ ent = p.Missing()
+ }
+
+ return &ent, nil
+}
+
+func (c SecretsManagerClient) GetSecrets(p core.KeyPath) ([]core.EnvEntry, error) {
+ // p.Path must be a record UID
+ // TODO: Add Path = folderUID... expect too many dulpicates, prefix key name with RUID?
+ type KeyValuePair struct {
+ key, value string
+ }
+
+ r := []core.EnvEntry{}
+
+ recs, err := c.sm.GetSecrets([]string{p.Path})
+ if err != nil {
+ return nil, err
+ }
+ if len(recs) < 1 {
+ return r, nil
+ }
+
+ entries := []KeyValuePair{}
+ rec := recs[0]
+ fields := rec.GetFieldsBySection(ksm.FieldSectionBoth)
+ for _, field := range fields {
+ fmap, ok := field.(map[string]interface{})
+ if !ok {
+ continue
+ }
+
+ iValues, ok := fmap["value"].([]interface{})
+ if !ok || len(iValues) < 1 {
+ continue
+ }
+
+ value := extractValue(iValues)
+ if value == "" {
+ continue
+ }
+
+ key := extractKey(fmap)
+ entries = append(entries, KeyValuePair{key: key, value: value})
+ }
+
+ // avoid duplicate key names
+ keymap := map[string]struct{}{}
+ for _, e := range entries {
+ key := e.key
+ if _, found := keymap[e.key]; found {
+ n := 1
+ for {
+ n++
+ mkey := key + "_" + strconv.Itoa(n)
+ if _, found := keymap[mkey]; !found {
+ key = mkey
+ break
+ }
+ }
+ }
+ keymap[key] = struct{}{}
+ ent := p.FoundWithKey(key, e.value)
+ r = append(r, ent)
+ }
+
+ return r, nil
+}
+
+func extractKey(fieldMap map[string]interface{}) string {
+ key := ""
+ if fLabel, ok := fieldMap["label"].(string); ok {
+ key = strings.TrimSpace(fLabel)
+ }
+ if key == "" {
+ if fType, ok := fieldMap["type"].(string); ok {
+ key = strings.TrimSpace(fType)
+ }
+ }
+ key = strings.ReplaceAll(key, " ", "_")
+ return key
+}
+
+func extractValue(iValues []interface{}) string {
+ value := ""
+ _, isArray := iValues[0].([]interface{})
+ _, isObject := iValues[0].(map[string]interface{})
+ isJSON := len(iValues) > 1 || isArray || isObject
+ if isJSON {
+ if len(iValues) == 1 {
+ if val, err := json.Marshal(iValues[0]); err == nil {
+ value = string(val)
+ }
+ } else if val, err := json.Marshal(iValues); err == nil {
+ value = string(val)
+ }
+ } else {
+ val := iValues[0]
+ // JavaScript number type, IEEE754 double precision float
+ if fval, ok := val.(float64); ok && fval == float64(int(fval)) {
+ val = int(fval) // convert to int
+ }
+ value = fmt.Sprintf("%v", val)
+ }
+ return value
+}
+
+func NewKsmClient() (KsmClient, error) {
+ config := os.Getenv("KSM_CONFIG")
+ configPath := os.Getenv("KSM_CONFIG_FILE")
+ if config == "" && configPath == "" {
+ return nil, fmt.Errorf("cannot find KSM_CONFIG or KSM_CONFIG_FILE for %s", keeperName)
+ }
+
+ // with both options present KSM_CONFIG overrides KSM_CONFIG_FILE
+ var options *ksm.ClientOptions = nil
+ if config != "" {
+ options = &ksm.ClientOptions{Config: ksm.NewMemoryKeyValueStorage(config)}
+ } else if stat, err := os.Stat(configPath); err == nil && stat.Size() > 2 {
+ options = &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage(configPath)}
+ }
+
+ if options == nil {
+ return nil, fmt.Errorf("failed to initialize KSM Client Options")
+ }
+
+ sm := ksm.NewSecretsManager(options)
+ if sm == nil {
+ return nil, fmt.Errorf("failed to initialize KSM Client")
+ }
+
+ return SecretsManagerClient{
+ sm: sm,
+ }, nil
+}
+
+func NewKeeperSecretsManager(logger logging.Logger) (core.Provider, error) {
+ ksmClient, err := NewKsmClient()
+ if err != nil {
+ return nil, err
+ }
+ return &KeeperSecretsManager{
+ client: ksmClient,
+ logger: logger,
+ }, nil
+}
+
+func (k *KeeperSecretsManager) Name() string {
+ return keeperName
+}
+
+func (k *KeeperSecretsManager) Get(p core.KeyPath) (*core.EnvEntry, error) {
+ return k.client.GetSecret(p)
+}
+
+func (k *KeeperSecretsManager) GetMapping(p core.KeyPath) ([]core.EnvEntry, error) {
+ return k.client.GetSecrets(p)
+}
+
+func (k *KeeperSecretsManager) Put(p core.KeyPath, val string) error {
+ return fmt.Errorf("provider %q does not implement write yet", k.Name())
+}
+
+func (k *KeeperSecretsManager) PutMapping(p core.KeyPath, m map[string]string) error {
+ return fmt.Errorf("provider %q does not implement write mapping yet", k.Name())
+}
+
+func (k *KeeperSecretsManager) Delete(kp core.KeyPath) error {
+ return fmt.Errorf("provider %s does not implement delete yet", k.Name())
+}
+
+func (k *KeeperSecretsManager) DeleteMapping(kp core.KeyPath) error {
+ return fmt.Errorf("provider %s does not implement delete mapping yet", k.Name())
+}
diff --git a/pkg/providers/keeper_secretsmanager_test.go b/pkg/providers/keeper_secretsmanager_test.go
new file mode 100644
index 00000000..dbbfbd79
--- /dev/null
+++ b/pkg/providers/keeper_secretsmanager_test.go
@@ -0,0 +1,60 @@
+package providers
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/alecthomas/assert"
+ "github.com/golang/mock/gomock"
+
+ "github.com/spectralops/teller/pkg/core"
+ "github.com/spectralops/teller/pkg/providers/mock_providers"
+)
+
+func TestKeeperSecretsManager(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+ client := mock_providers.NewMockKsmClient(ctrl)
+
+ a := KeeperSecretsManager{
+ client: client,
+ logger: GetTestLogger(),
+ }
+
+ path := core.KeyPath{Path: "settings/prod/billing-svc/all", Field: "MG_KEY", Decrypt: true}
+ key1 := core.KeyPath{Path: "settings/prod/billing-svc", Field: "MG_KEY", Decrypt: true}
+ key2 := core.KeyPath{Path: "settings/prod/billing-svc", Env: "MG_KEY", Decrypt: true}
+
+ returnSecrets := []core.EnvEntry{
+ {Key: "MM_KEY", Value: "mailman"},
+ {Key: "MG_KEY", Value: "shazam"},
+ }
+ client.EXPECT().GetSecret(key1).Return(&core.EnvEntry{Value: "shazam"}, nil).AnyTimes()
+ client.EXPECT().GetSecret(key2).Return(&core.EnvEntry{Value: "shazam"}, nil).AnyTimes()
+ client.EXPECT().GetSecrets(path).Return(returnSecrets, nil).AnyTimes()
+ client.EXPECT().GetSecrets(nil).Return(returnSecrets, nil).AnyTimes()
+
+ AssertProvider(t, &a, true)
+}
+
+func TestKeeperSecretsManagerFailures(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+ client := mock_providers.NewMockKsmClient(ctrl)
+
+ a := KeeperSecretsManager{
+ client: client,
+ logger: GetTestLogger(),
+ }
+
+ path := core.KeyPath{Path: "settings/{{stage}}/billing-svc/all"}
+ key1 := core.KeyPath{Env: "MG_KEY", Path: "settings/{{stage}}/billing-svc"}
+ client.EXPECT().GetSecret(key1).Return(&core.EnvEntry{}, errors.New("error")).AnyTimes()
+ client.EXPECT().GetSecrets(path).Return([]core.EnvEntry{}, errors.New("error")).AnyTimes()
+
+ _, err := a.Get(core.KeyPath{Env: "MG_KEY", Path: "settings/{{stage}}/billing-svc"})
+ assert.NotNil(t, err)
+
+ _, err = a.GetMapping(core.KeyPath{Path: "settings/{{stage}}/billing-svc/all"})
+ assert.NotNil(t, err)
+}
diff --git a/pkg/providers/mock_providers/keeper_secretsmanager_mock.go b/pkg/providers/mock_providers/keeper_secretsmanager_mock.go
new file mode 100644
index 00000000..4fb634f8
--- /dev/null
+++ b/pkg/providers/mock_providers/keeper_secretsmanager_mock.go
@@ -0,0 +1,65 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: pkg/providers/keeper_secretsmanager.go
+
+// Package mock_providers is a generated GoMock package.
+package mock_providers
+
+import (
+ reflect "reflect"
+
+ gomock "github.com/golang/mock/gomock"
+ core "github.com/spectralops/teller/pkg/core"
+)
+
+// MockKsmClient is a mock of KsmClient interface.
+type MockKsmClient struct {
+ ctrl *gomock.Controller
+ recorder *MockKsmClientMockRecorder
+}
+
+// MockKsmClientMockRecorder is the mock recorder for MockKsmClient.
+type MockKsmClientMockRecorder struct {
+ mock *MockKsmClient
+}
+
+// NewMockKsmClient creates a new mock instance.
+func NewMockKsmClient(ctrl *gomock.Controller) *MockKsmClient {
+ mock := &MockKsmClient{ctrl: ctrl}
+ mock.recorder = &MockKsmClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockKsmClient) EXPECT() *MockKsmClientMockRecorder {
+ return m.recorder
+}
+
+// GetSecret mocks base method.
+func (m *MockKsmClient) GetSecret(p core.KeyPath) (*core.EnvEntry, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetSecret", p)
+ ret0, _ := ret[0].(*core.EnvEntry)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetSecret indicates an expected call of GetSecret.
+func (mr *MockKsmClientMockRecorder) GetSecret(p interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecret", reflect.TypeOf((*MockKsmClient)(nil).GetSecret), p)
+}
+
+// GetSecrets mocks base method.
+func (m *MockKsmClient) GetSecrets(p core.KeyPath) ([]core.EnvEntry, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetSecrets", p)
+ ret0, _ := ret[0].([]core.EnvEntry)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetSecrets indicates an expected call of GetSecrets.
+func (mr *MockKsmClientMockRecorder) GetSecrets(p interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecrets", reflect.TypeOf((*MockKsmClient)(nil).GetSecrets), p)
+}
diff --git a/pkg/wizard_template.go b/pkg/wizard_template.go
index 62d9c8c2..cc5bd54f 100644
--- a/pkg/wizard_template.go
+++ b/pkg/wizard_template.go
@@ -283,5 +283,21 @@ providers:
NONEXIST_KEY:
path: ansible/vars/vault_{{stage}}.yml
+{{end}}
+
+{{- if index .ProviderKeys "keeper_secretsmanager" }}
+
+ # requires a configuration in: KSM_CONFIG=base64_config or file path KSM_CONFIG_FILE=ksm_config.json
+ keeper_secretsmanager:
+ env_sync:
+ path: RECORD_UID
+ # all non-empty fields are mapped by their labels, if empty then by field type, and index 1,2,...,N
+
+ env:
+ USER:
+ path: RECORD_UID/field/login
+ # use Keeper Notation to select individual field values
+ # https://docs.keeper.io/secrets-manager/secrets-manager/about/keeper-notation
+
{{end}}
`
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/LICENSE.txt b/vendor/github.com/keeper-security/secrets-manager-go/core/LICENSE.txt
new file mode 100644
index 00000000..88eb6a53
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Keeper Security
+
+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/vendor/github.com/keeper-security/secrets-manager-go/core/README.md b/vendor/github.com/keeper-security/secrets-manager-go/core/README.md
new file mode 100644
index 00000000..e29097e6
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/README.md
@@ -0,0 +1,197 @@
+# Secrets Management Go SDK
+
+![Go](https://github.com/keeper-security/secrets-manager-go/actions/workflows/test.go.yml/badge.svg)
+
+
+ View docs
+
+
+This library provides interface to Keeper® Secrets Manager and can be used to access your Keeper vault, read and update existing records, rotate passwords and more. Keeper Secrets Manager is an open source project with contributions from Keeper's engineering team and partners.
+
+## Features:
+
+## Obtain a One-Time Access Token
+Keeper Secrets Manager authenticates your API requests using advanced encryption that uses locally stored private key, device id and client id.
+To register your device and generate private key you will need to generate a One-Time Access Token via Web Vault or Keeper Commander CLI.
+
+### Via Web Vault
+**Secrets Manager > Applications > Create Application** - will let you chose application name, shared folder(s) and permissions and generate One-Time Access Token. _Note: Keeper does not store One-Time Access Tokens - save or copy the token offline for later use._
+
+One-Time Access Tokens can be generated as needed: **Secrets Manager > Applications > Application Name > Devices Tab > Edit > Add Device button** - will let you create new Device and generate its One-Time Access Token.
+
+[What is an application?](https://docs.keeper.io/secrets-manager/secrets-manager/overview/terminology)
+
+### Via Keeper Commander CLI
+Login to Keeper with Commander CLI and perform following:
+1. Create Application
+ ```bash
+ $ sm app create [NAME]
+ ```
+
+2. Share Secrets to the Application
+ ```bash
+ $ sm share add --app [NAME] --secret [UID] --editable
+ ```
+ - `--app` - Name of the Application.
+ - `--secret` - Record UID or Shared Folder UID
+ - `--editable` - if omitted defaults to false
+
+3. Create client
+ ```bash
+ $ sm client add --app [NAME] --unlock-ip --count 1
+ ```
+
+### Install
+```bash
+go get github.com/keeper-security/secrets-manager-go/core
+```
+
+### Quick Start
+
+```golang
+package main
+
+// Import Secrets Manager
+import ksm "github.com/keeper-security/secrets-manager-go/core"
+
+func main() {
+ // Establish connection
+ // One time secrets generated via Web Vault or Commander CLI
+ clientOptions := &ksm.ClientOptions{
+ Token: "US:ONE_TIME_TOKEN_BASE64",
+ Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
+ sm := ksm.NewSecretsManager(clientOptions)
+ // One time tokens can be used only once - afterwards use the generated config file
+ // sm := ksm.NewSecretsManager(&ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")})
+
+ // Retrieve all records
+ allRecords, _ := sm.GetSecrets([]string{})
+
+ // Get password from first record:
+ password := allRecords[0].Password()
+
+ // WARNING: Avoid logging sensitive data
+ print("My password from Keeper: ", password)
+}
+```
+
+## Samples
+### File Download
+```golang
+sm := ksm.NewSecretsManager(&ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")})
+
+if records, err := sm.GetSecrets([]string{}); err == nil {
+ for _, r := range records {
+ fmt.Println("\tTitle: " + r.Title())
+ for i, f := range r.Files {
+ fmt.Printf("\t\tfile #%d -> name: %s", i, f.Name)
+ f.SaveFile("/tmp/"+f.Name, true)
+ }
+ }
+}
+```
+
+### Update record
+```golang
+sm := ksm.NewSecretsManager(&ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")})
+
+if records, err := sm.GetSecrets([]string{}); err == nil && len(records) > 0 {
+ record := records[0]
+ newPassword := fmt.Sprintf("Test Password - " + time.Now().Format(time.RFC850))
+ record.SetPassword(newPassword)
+
+ if err := sm.Save(record); err != nil {
+ fmt.Println("Error saving record: " + err.Error())
+ }
+}
+```
+
+## Configuration
+
+### Types
+
+Listed in priority order
+1. Environment variable
+1. Configuration store
+1. Code
+
+### Available configurations:
+
+- `clientKey` - One Time Access Token used during initialization
+- `hostname` - Keeper Backend host. Available values:
+ - `keepersecurity.com`
+ - `keepersecurity.eu`
+ - `keepersecurity.com.au`
+ - `govcloud.keepersecurity.us`
+
+## Adding more records or shared folders to the Application
+
+### Via Web Vault
+Drag&Drop records into the shared folder or select from the record menu any of the options to CreateDuplicate/Move or create new records straight into the shared folder. As an alternative use: **Secrets Manager > Application > Application Name > Folders & Records > Edit** and use search field to add any folders or records then click Save.
+
+### Via Commander CLI
+```bash
+sm share add --app [NAME] --secret [UID2]
+sm share add --app [NAME] --secret [UID3] --editable
+```
+
+### Retrieve secret(s)
+```golang
+sm := ksm.NewSecretsManager(&ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")})
+allSecrets, _ := sm.GetSecrets([]string{})
+```
+
+### Update secret
+```golang
+secretToUpdate = allSecrets[0]
+secretToUpdate.SetPassword("NewPassword123$")
+secretsManager.Save(secretToUpdate)
+```
+
+# Change Log
+
+## 1.6.2
+
+* KSM-467 - Fixed ExpiresOn conversion from UnixTimeMilliseconds.
+
+## 1.6.1
+
+* KSM-450 - Added `folderUid` and `innerFolderUid` to Record
+* KSM-451 - Fix `subFolderUid` crash on empty string value
+
+## 1.6.0
+
+* KSM-414 - Added support for Folders
+* KSM-435 - Improved Passkey field type support
+
+## 1.5.2
+
+* KSM-409 New field type: Passkey
+* KSM-404 New filed type: script and modification to some record types
+* KSM-384 Support for record Transactions
+
+
+## 1.5.0
+
+* KSM-317 - Notation improvements
+* KSM-356 - Create custom fields
+* KSM-365 - Fixed KEY_CLINET_KEY is missing error
+* KSM-366 - Avoid exceptions/panics and return errors instead
+* KSM-367 - Fixed license not shown on pkg.go.dev
+
+## 1.4.0
+
+* KSM-288 - Record removal
+* KSM-306 - Added support for Japan and Canada data centers
+* KSM-312 - Improve password generation entropy
+
+For additional information please check our detailed [Go SDK docs](https://docs.keeper.io/secrets-manager/secrets-manager/developer-sdk-library/golang-sdk) for Keeper Secrets Manager.
+
+### Documentation
+[Secrets Manager Guide](https://docs.keeper.io/secrets-manager/secrets-manager/overview)
+
+[Enterprise Admin Guide](https://docs.keeper.io/enterprise-guide/)
+
+[Keeper Commander Guide](https://docs.keeper.io/secrets-manager/commander-cli/overview)
+
+[Keeper Security Website](https://www.keepersecurity.com/secrets-manager.html)
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/cache.go b/vendor/github.com/keeper-security/secrets-manager-go/core/cache.go
new file mode 100644
index 00000000..0a556c14
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/cache.go
@@ -0,0 +1,87 @@
+package core
+
+import (
+ "errors"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const defautFilePath = "ksm_cache.bin"
+
+type ICache interface {
+ SaveCachedValue(data []byte) error
+ GetCachedValue() ([]byte, error)
+ Purge() error
+}
+
+// File based cache
+type fileCache struct {
+ FilePath string
+}
+
+func (c *fileCache) SaveCachedValue(data []byte) error {
+ if data == nil {
+ data = []byte{}
+ }
+ return ioutil.WriteFile(c.FilePath, data, 0600)
+}
+
+func (c *fileCache) GetCachedValue() ([]byte, error) {
+ return ioutil.ReadFile(c.FilePath)
+}
+
+func (c *fileCache) Purge() error {
+ err := os.Remove(c.FilePath)
+ if errors.Is(err, os.ErrNotExist) {
+ err = nil
+ }
+ return err
+}
+
+func NewFileCache(filePath string) *fileCache {
+ path := strings.TrimSpace(filePath)
+ if path == "" {
+ path = defautFilePath
+ }
+
+ // If the file path is not absolute
+ // allow the directory that will contain the cache to be set with environment variables.
+ // If KSM_CACHE_DIR is not set, the cache will be created in the current working directory.
+ if !filepath.IsAbs(path) {
+ if ksmCacheDir := strings.TrimSpace(os.Getenv("KSM_CACHE_DIR")); ksmCacheDir != "" {
+ path = filepath.Join(ksmCacheDir, path)
+ }
+ }
+
+ return &fileCache{FilePath: path}
+}
+
+// Memory based cache
+type memoryCache struct {
+ cache []byte
+}
+
+func (c *memoryCache) SaveCachedValue(data []byte) error {
+ c.cache = []byte{} // always erase old value
+ if len(data) > 0 {
+ bytes := make([]byte, len(data))
+ copy(bytes, data)
+ c.cache = bytes
+ }
+ return nil
+}
+
+func (c *memoryCache) GetCachedValue() ([]byte, error) {
+ return c.cache, nil
+}
+
+func (c *memoryCache) Purge() error {
+ c.cache = []byte{}
+ return nil
+}
+
+func NewMemoryCache() *memoryCache {
+ return &memoryCache{cache: []byte{}}
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/config_keys.go b/vendor/github.com/keeper-security/secrets-manager-go/core/config_keys.go
new file mode 100644
index 00000000..9fef64e0
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/config_keys.go
@@ -0,0 +1,62 @@
+package core
+
+type ConfigKey string
+
+const (
+ KEY_URL ConfigKey = "url" // base URL for the Secrets Manager service
+ KEY_SERVER_PUBLIC_KEY_ID ConfigKey = "serverPublicKeyId"
+ KEY_CLIENT_ID ConfigKey = "clientId"
+ KEY_CLIENT_KEY ConfigKey = "clientKey" // The key that is used to identify the client before public key
+ KEY_APP_KEY ConfigKey = "appKey" // The application key with which all secrets are encrypted
+ KEY_OWNER_PUBLIC_KEY ConfigKey = "appOwnerPublicKey" // The application owner public key, to create records
+ KEY_PRIVATE_KEY ConfigKey = "privateKey" // The client's private key
+ KEY_PUBLIC_KEY ConfigKey = "publicKey" // The client's public key
+ KEY_HOSTNAME ConfigKey = "hostname" // base hostname for the Secrets Manager service
+ defaultOwnerPublicKeyId string = "7"
+)
+
+func GetDefaultOwnerPublicKey() string {
+ if ownerKey, found := keeperServerPublicKeys[defaultOwnerPublicKeyId]; found {
+ return ownerKey
+ }
+ return ""
+}
+
+func GetConfigKey(value string) ConfigKey {
+ switch value {
+ case string(KEY_URL):
+ return KEY_URL
+ case string(KEY_SERVER_PUBLIC_KEY_ID):
+ return KEY_SERVER_PUBLIC_KEY_ID
+ case string(KEY_CLIENT_ID):
+ return KEY_CLIENT_ID
+ case string(KEY_CLIENT_KEY):
+ return KEY_CLIENT_KEY
+ case string(KEY_APP_KEY):
+ return KEY_APP_KEY
+ case string(KEY_OWNER_PUBLIC_KEY):
+ return KEY_OWNER_PUBLIC_KEY
+ case string(KEY_PRIVATE_KEY):
+ return KEY_PRIVATE_KEY
+ case string(KEY_PUBLIC_KEY):
+ return KEY_PUBLIC_KEY
+ case string(KEY_HOSTNAME):
+ return KEY_HOSTNAME
+ default:
+ return ""
+ }
+}
+
+func GetConfigKeys() []ConfigKey {
+ return []ConfigKey{
+ KEY_URL,
+ KEY_SERVER_PUBLIC_KEY_ID,
+ KEY_CLIENT_ID,
+ KEY_CLIENT_KEY,
+ KEY_APP_KEY,
+ KEY_OWNER_PUBLIC_KEY,
+ KEY_PRIVATE_KEY,
+ KEY_PUBLIC_KEY,
+ KEY_HOSTNAME,
+ }
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/core.go b/vendor/github.com/keeper-security/secrets-manager-go/core/core.go
new file mode 100644
index 00000000..a3c7fb96
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/core.go
@@ -0,0 +1,2371 @@
+package core
+
+import (
+ "bytes"
+ "crypto/tls"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "mime/multipart"
+ "net/http"
+ "os"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+const (
+ secretsManagerNotationPrefix string = "keeper"
+ defaultKeeperServerPublicKeyId string = "10"
+)
+
+type ClientOptions struct {
+ // Token specifies a One-Time Access Token used
+ // to generate the configuration to use with core.SecretsManager client
+ Token string
+
+ // InsecureSkipVerify controls whether the client verifies
+ // server's certificate chain and host name
+ InsecureSkipVerify bool
+
+ // Config specifies either one of the built-in IKeyValueStorage interfaces or a custom one
+ Config IKeyValueStorage
+
+ // LogLevel overrides the default log level for the logger
+ LogLevel klog.LogLevel
+
+ // Deprecated: Use Token instead. If both are set, hostname from the token takes priority.
+ Hostname string
+}
+
+type SecretsManager struct {
+ Token string
+ Hostname string
+ VerifySslCerts bool
+ Config IKeyValueStorage
+ context **Context
+ cache ICache
+}
+
+// NewSecretsManager returns new *SecretsManager initialized with the options provided.
+// If the configuration file cannot be initialized or parsed returns nil
+func NewSecretsManager(options *ClientOptions, arg ...interface{}) *SecretsManager {
+ // set default values
+ sm := &SecretsManager{
+ VerifySslCerts: true,
+ }
+
+ // context used in tests only
+ if len(arg) > 0 {
+ if ctx, ok := arg[0].(**Context); ok && ctx != nil {
+ sm.context = ctx
+ }
+ }
+
+ // If the config is not defined and the KSM_CONFIG env var exists,
+ // get the config from the env var.
+ if options != nil && options.Config != nil {
+ sm.Config = options.Config
+ }
+ ksmConfig := strings.TrimSpace(os.Getenv("KSM_CONFIG"))
+ if sm.Config == nil && ksmConfig != "" {
+ sm.Config = NewMemoryKeyValueStorage(ksmConfig)
+ klog.Warning("Config initialised from env var KSM_CONFIG")
+ } else if options != nil && strings.TrimSpace(options.Token) != "" {
+ token := strings.TrimSpace(options.Token)
+ hostname := strings.TrimSpace(options.Hostname)
+ if tokenParts := strings.Split(token, ":"); len(tokenParts) == 1 {
+ // token in legacy format without hostname prefix
+ if hostname == "" {
+ klog.Error("The hostname must be present in the token or provided as a parameter")
+ return nil
+ }
+ sm.Token = token
+ sm.Hostname = hostname
+ } else {
+ tokenPart0 := strings.TrimSpace(tokenParts[0])
+ tokenPart1 := strings.TrimSpace(tokenParts[1])
+ if len(tokenParts) != 2 || tokenPart0 == "" || tokenPart1 == "" {
+ klog.Warning("Expected token format 'Host:Base64Key', ex. US:ONE_TIME_TOKEN_BASE64 - got " + token)
+ }
+ if tokenHost, found := keeperServers[strings.ToUpper(tokenPart0)]; found {
+ // token contains abbreviation: ex. "US:ONE_TIME_TOKEN"
+ if hostname != "" && hostname != tokenHost {
+ klog.Warning(fmt.Sprintf("Replacing hostname '%s' with token based hostname '%s'", hostname, tokenHost))
+ }
+ sm.Hostname = tokenHost
+ } else {
+ // token contains url prefix: ex. "ksm.company.com:ONE_TIME_TOKEN"
+ if hostname != "" && hostname != tokenPart0 {
+ klog.Warning(fmt.Sprintf("Replacing hostname '%s' with token based hostname '%s'", hostname, tokenPart0))
+ }
+ sm.Hostname = tokenPart0
+ }
+ sm.Token = tokenPart1
+ }
+ }
+
+ // Init the log, set log level
+ if options != nil && options.LogLevel > 0 {
+ klog.SetLogLevel(options.LogLevel)
+ }
+
+ if options != nil && options.InsecureSkipVerify {
+ sm.VerifySslCerts = false
+ }
+ // Accept the env var KSM_SKIP_VERIFY
+ if ksv := strings.TrimSpace(os.Getenv("KSM_SKIP_VERIFY")); ksv != "" {
+ if ksvBool, err := StrToBool(ksv); err == nil {
+ // We need to flip the value of KSM_SKIP_VERIFY, if true, we want VerifySslCerts to be false.
+ sm.VerifySslCerts = !ksvBool
+ } else {
+ klog.Error("error parsing boolean value from KSM_SKIP_VERIFY=" + ksv)
+ }
+ }
+
+ if sm.Config == nil {
+ sm.Config = NewFileKeyValueStorage()
+ }
+
+ // If the hostname or client key are set in the args, make sure they make their way into the config.
+ // They will override what is already in the config if they exist.
+ if cKey := strings.TrimSpace(sm.Token); cKey != "" {
+ sm.Config.Set(KEY_CLIENT_KEY, cKey)
+ }
+ if srv := strings.TrimSpace(sm.Hostname); srv != "" {
+ sm.Config.Set(KEY_HOSTNAME, srv)
+ }
+
+ // Make sure our public key id is set and pointing an existing key.
+ pkid := strings.TrimSpace(sm.Config.Get(KEY_SERVER_PUBLIC_KEY_ID))
+ if pkid == "" {
+ klog.Debug("Setting public key id to the default: " + defaultKeeperServerPublicKeyId)
+ sm.Config.Set(KEY_SERVER_PUBLIC_KEY_ID, defaultKeeperServerPublicKeyId)
+ } else if _, found := keeperServerPublicKeys[pkid]; !found {
+ klog.Debug(fmt.Sprintf("Public key id %s does not exists, set to default: %s", pkid, defaultKeeperServerPublicKeyId))
+ sm.Config.Set(KEY_SERVER_PUBLIC_KEY_ID, defaultKeeperServerPublicKeyId)
+ }
+
+ if err := sm.init(); err != nil {
+ klog.Error(err.Error())
+ return nil
+ }
+ return sm
+}
+
+func (c *SecretsManager) NotationPrefix() string {
+ return secretsManagerNotationPrefix
+}
+
+func (c *SecretsManager) DefaultKeeperServerPublicKeyId() string {
+ return defaultKeeperServerPublicKeyId
+}
+
+func (c *SecretsManager) SetCache(cache ICache) {
+ c.cache = cache
+}
+
+func (c *SecretsManager) init() error {
+ if !c.VerifySslCerts {
+ klog.Warning("WARNING: Running without SSL cert verification. " +
+ "Set 'SecretsManager.VerifySslCerts = True' or set 'KSM_SKIP_VERIFY=FALSE' " +
+ "to enable verification.")
+ }
+
+ clientId := strings.TrimSpace(c.Config.Get(KEY_CLIENT_ID))
+
+ unboundToken := false
+ if strings.TrimSpace(c.Token) != "" {
+ unboundToken = true
+ if clientId != "" { // config is initialized
+ clientKey := c.Token
+ clientKeyBytes := UrlSafeStrToBytes(clientKey)
+ tokenClientId := Base64HmacFromString(clientKeyBytes, clientIdHashTag)
+ if tokenClientId == clientId { // with same token - check if bound
+ appKey := strings.TrimSpace(c.Config.Get(KEY_APP_KEY))
+ if appKey != "" { // and bound
+ unboundToken = false
+ klog.Warning("The storage is already initialized with same token")
+ } else { // not bound
+ klog.Warning("The storage is already initialized but not bound")
+ }
+ } else { // initialized with different token
+ return errors.New("the storage is already initialized with a different token - Client ID: " + clientId)
+ }
+ }
+ }
+
+ if clientId != "" && !unboundToken {
+ klog.Debug("Already bound")
+ if c.Config.Get(KEY_CLIENT_KEY) != "" {
+ c.Config.Delete(KEY_CLIENT_KEY)
+ }
+ } else {
+ existingSecretKey := c.LoadSecretKey()
+ if esk := strings.TrimSpace(existingSecretKey); esk == "" {
+ return errors.New("cannot locate the One Time Token")
+ }
+
+ existingSecretKeyBytes := UrlSafeStrToBytes(existingSecretKey)
+ existingSecretKeyHash := Base64HmacFromString(existingSecretKeyBytes, clientIdHashTag)
+
+ c.Config.Delete(KEY_CLIENT_ID)
+ c.Config.Delete(KEY_PRIVATE_KEY)
+ c.Config.Delete(KEY_APP_KEY)
+
+ c.Config.Set(KEY_CLIENT_ID, existingSecretKeyHash)
+
+ if privateKeyStr := strings.TrimSpace(c.Config.Get(KEY_PRIVATE_KEY)); privateKeyStr == "" {
+ if privateKeyDer, err := GeneratePrivateKeyDer(); err == nil {
+ if cfg := c.Config.Set(KEY_PRIVATE_KEY, BytesToBase64(privateKeyDer)); len(cfg) < 1 {
+ return errors.New("failed to set the private key")
+ }
+ } else {
+ return errors.New("failed to generate private key. " + err.Error())
+ }
+ }
+ }
+ return nil
+}
+
+// Returns client_id from the environment variable, config file, or in the code
+func (c *SecretsManager) LoadSecretKey() string {
+ // Case 1: Environment Variable
+ currentSecretKey := ""
+ if envSecretKey := strings.TrimSpace(os.Getenv("KSM_TOKEN")); envSecretKey != "" {
+ currentSecretKey = envSecretKey
+ klog.Info("Secret key found in environment variable")
+ }
+
+ // Case 2: Code
+ if currentSecretKey == "" && strings.TrimSpace(c.Token) != "" {
+ currentSecretKey = strings.TrimSpace(c.Token)
+ klog.Info("Secret key found in code")
+ }
+
+ // Case 3: Config storage
+ if currentSecretKey == "" {
+ if configSecretKey := strings.TrimSpace(c.Config.Get(KEY_CLIENT_KEY)); configSecretKey != "" {
+ currentSecretKey = configSecretKey
+ klog.Info("Secret key found in configuration file")
+ }
+ }
+
+ return strings.TrimSpace(currentSecretKey)
+}
+
+func (c *SecretsManager) GenerateTransmissionKey(keyId string) *TransmissionKey {
+ serverPublicKey, ok := keeperServerPublicKeys[keyId]
+ if !ok || strings.TrimSpace(serverPublicKey) == "" {
+ klog.Error(fmt.Sprintf("The public key id %s does not exist.", keyId))
+ return nil
+ }
+
+ transmissionKey, err := GenerateRandomBytes(Aes256KeySize)
+ if err != nil {
+ klog.Error("Failed to generate the transmission key. " + err.Error())
+ } else if len(transmissionKey) != Aes256KeySize {
+ klog.Error("Failed to generate the transmission key with correct length. Key length: " + strconv.Itoa(len(transmissionKey)))
+ }
+
+ serverPublicRawKeyBytes := UrlSafeStrToBytes(serverPublicKey)
+ encryptedKey, err := PublicEncrypt(transmissionKey, serverPublicRawKeyBytes, nil)
+ if err != nil {
+ klog.Error("Failed to encrypt transmission key. " + err.Error())
+ }
+
+ return &TransmissionKey{
+ PublicKeyId: keyId,
+ Key: transmissionKey,
+ EncryptedKey: encryptedKey,
+ }
+}
+
+func (c *SecretsManager) PrepareContext() *Context {
+ // Get the index of the public key we need to use.
+ // If not set, set it the default and save it back into the config.
+ keyId := strings.TrimSpace(c.Config.Get(KEY_SERVER_PUBLIC_KEY_ID))
+ if keyId == "" {
+ keyId = defaultKeeperServerPublicKeyId
+ c.Config.Set(KEY_SERVER_PUBLIC_KEY_ID, keyId)
+ }
+
+ // Generate the transmission key using the public key at the key id index
+ transmissionKey := c.GenerateTransmissionKey(keyId)
+ if transmissionKey == nil {
+ klog.Error("failed to prepare context - error(s) generating the transmission key")
+ return nil
+ }
+ clientId := strings.TrimSpace(c.Config.Get(KEY_CLIENT_ID))
+ secretKey := []byte{}
+
+ // While not used in the normal operations, it's used for mocking unit tests.
+ if appKey := c.Config.Get(KEY_APP_KEY); appKey != "" {
+ secretKey = Base64ToBytes(appKey)
+ }
+
+ if clientId == "" {
+ klog.Error("failed to prepare context - Client ID is missing from the configuration")
+ return nil
+ }
+ clientIdBytes := Base64ToBytes(clientId)
+ context := &Context{
+ TransmissionKey: *transmissionKey,
+ ClientId: clientIdBytes,
+ ClientKey: secretKey,
+ }
+ if c.context != nil {
+ *c.context = context
+ }
+
+ return context
+}
+
+func (c *SecretsManager) encryptAndSignPayload(transmissionKey *TransmissionKey, payload interface{}) (res *EncryptedPayload, err error) {
+ payloadJsonStr := ""
+ switch v := payload.(type) {
+ case nil:
+ return nil, errors.New("error converting payload - payload == nil")
+ case *CreatePayload:
+ if payloadJsonStr, err = v.CreatePayloadToJson(); err != nil {
+ return nil, errors.New("error converting create payload to JSON: " + err.Error())
+ }
+ case *GetPayload:
+ if payloadJsonStr, err = v.GetPayloadToJson(); err != nil {
+ return nil, errors.New("error converting get payload to JSON: " + err.Error())
+ }
+ case *UpdatePayload:
+ if payloadJsonStr, err = v.UpdatePayloadToJson(); err != nil {
+ return nil, errors.New("error converting update payload to JSON: " + err.Error())
+ }
+ case *DeletePayload:
+ if payloadJsonStr, err = v.DeletePayloadToJson(); err != nil {
+ return nil, errors.New("error converting delete payload to JSON: " + err.Error())
+ }
+ case *CreateFolderPayload:
+ if payloadJsonStr, err = v.CreateFolderPayloadToJson(); err != nil {
+ return nil, errors.New("error converting create folder payload to JSON: " + err.Error())
+ }
+ case *UpdateFolderPayload:
+ if payloadJsonStr, err = v.UpdateFolderPayloadToJson(); err != nil {
+ return nil, errors.New("error converting update folder payload to JSON: " + err.Error())
+ }
+ case *DeleteFolderPayload:
+ if payloadJsonStr, err = v.DeleteFolderPayloadToJson(); err != nil {
+ return nil, errors.New("error converting delete folder payload to JSON: " + err.Error())
+ }
+ case *CompleteTransactionPayload:
+ if payloadJsonStr, err = v.CompleteTransactionPayloadToJson(); err != nil {
+ return nil, errors.New("error converting complete transaction payload to JSON: " + err.Error())
+ }
+ case *FileUploadPayload:
+ if payloadJsonStr, err = v.FileUploadPayloadToJson(); err != nil {
+ return nil, errors.New("error converting file upload payload to JSON: " + err.Error())
+ }
+ default:
+ return nil, fmt.Errorf("error converting payload - unknown payload type for '%v'", v)
+ }
+
+ payloadBytes := StringToBytes(payloadJsonStr)
+
+ encryptedPayload, err := EncryptAesGcm(payloadBytes, transmissionKey.Key)
+ if err != nil {
+ return nil, errors.New("error encrypting the payload: " + err.Error())
+ }
+
+ encryptedKey := transmissionKey.EncryptedKey
+ signatureBase := make([]byte, 0, len(encryptedKey)+len(encryptedPayload))
+ signatureBase = append(signatureBase, encryptedKey...)
+ signatureBase = append(signatureBase, encryptedPayload...)
+
+ privateKey := c.Config.Get(KEY_PRIVATE_KEY)
+ pk, err := DerBase64PrivateKeyToPrivateKey(privateKey)
+ if err != nil {
+ return nil, errors.New("error loading private key: " + err.Error())
+ }
+
+ signature, err := Sign(signatureBase, pk)
+ if err != nil {
+ return nil, errors.New("error generating signature: " + err.Error())
+ }
+
+ return &EncryptedPayload{
+ EncryptedPayload: encryptedPayload,
+ Signature: signature,
+ }, nil
+}
+
+func (c *SecretsManager) prepareGetPayload(queryOptions QueryOptions) (res *GetPayload, err error) {
+ payload := GetPayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ }
+
+ if payload.ClientId == "" {
+ return nil, errors.New("client ID is missing from the configuration")
+ }
+
+ if appKeyStr := c.Config.Get(KEY_APP_KEY); strings.TrimSpace(appKeyStr) == "" {
+ if publicKeyBytes, err := extractPublicKeyBytes(c.Config.Get(KEY_PRIVATE_KEY)); err == nil {
+ publicKeyBase64 := BytesToBase64(publicKeyBytes)
+ // passed once when binding
+ payload.PublicKey = publicKeyBase64
+ } else {
+ return nil, errors.New("error extracting public key for get payload")
+ }
+ }
+
+ if len(queryOptions.RecordsFilter) > 0 {
+ payload.RequestedRecords = queryOptions.RecordsFilter
+ }
+ if len(queryOptions.FoldersFilter) > 0 {
+ payload.RequestedFolders = queryOptions.FoldersFilter
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareUpdatePayload(record *Record, transactionType UpdateTransactionType) (res *UpdatePayload, err error) {
+ payload := UpdatePayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ }
+
+ // for update, UID of the record
+ payload.RecordUid = record.Uid
+ payload.Revision = record.Revision
+
+ rawJsonBytes := StringToBytes(record.RawJson)
+ if encryptedRawJsonBytes, err := EncryptAesGcm(rawJsonBytes, record.RecordKeyBytes); err == nil {
+ payload.Data = BytesToUrlSafeStr(encryptedRawJsonBytes)
+ } else {
+ return nil, err
+ }
+
+ if transactionType != TransactionTypeNone {
+ payload.TransactionType = transactionType
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareCompleteTransactionPayload(recordUid string) (res *CompleteTransactionPayload, err error) {
+ payload := CompleteTransactionPayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ RecordUid: recordUid,
+ }
+
+ if payload.ClientId == "" {
+ return nil, errors.New("client ID is missing from the configuration")
+ }
+
+ if payload.RecordUid == "" {
+ return nil, errors.New("record UID is missing from CompleteTransactionPayload")
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareDeletePayload(recordUids []string) (res *DeletePayload, err error) {
+ clientId := c.Config.Get(KEY_CLIENT_ID)
+ if clientId == "" {
+ return nil, errors.New("client ID is missing from the configuration")
+ }
+
+ klog.Info(fmt.Sprintf("recordUIDs: %v", recordUids))
+ payload := DeletePayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ RecordUids: recordUids,
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareCreatePayload(record *Record, createOptions CreateOptions, folderKey []byte) (res *CreatePayload, err error) {
+ payload := CreatePayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ FolderUid: createOptions.FolderUid,
+ SubFolderUid: createOptions.SubFolderUid,
+ }
+
+ ownerPublicKey := strings.TrimSpace(c.Config.Get(KEY_OWNER_PUBLIC_KEY))
+ if ownerPublicKey == "" {
+ return nil, fmt.Errorf("unable to create record - App owner public key is missing. Looks like application was created using outdated client (Web Vault or Commander)")
+ }
+ ownerPublicKeyBytes := Base64ToBytes(ownerPublicKey)
+
+ if strings.TrimSpace(createOptions.FolderUid) == "" {
+ return nil, fmt.Errorf("unable to create record - missing folder UID")
+ }
+ if len(folderKey) == 0 {
+ return nil, fmt.Errorf("unable to create record - folder key for '%s' missing", createOptions.FolderUid)
+ }
+ if strings.TrimSpace(payload.ClientId) == "" {
+ return nil, fmt.Errorf("unable to create record - client Id is missing from the configuration")
+ }
+ if record == nil {
+ return nil, fmt.Errorf("unable to create record - missing record data")
+ }
+
+ // convert any record UID in Base64 encoding to UrlSafeBase64
+ recordUid := BytesToUrlSafeStr(Base64ToBytes(record.Uid))
+ payload.RecordUid = recordUid
+
+ rawJsonBytes := StringToBytes(record.RawJson)
+ if encryptedRawJsonBytes, err := EncryptAesGcm(rawJsonBytes, record.RecordKeyBytes); err == nil {
+ payload.Data = BytesToBase64(encryptedRawJsonBytes)
+ } else {
+ return nil, err
+ }
+
+ if encryptedFolderKey, err := EncryptAesGcm(record.RecordKeyBytes, folderKey); err == nil {
+ payload.FolderKey = BytesToBase64(encryptedFolderKey)
+ } else {
+ return nil, err
+ }
+
+ if encryptedRecordKey, err := PublicEncrypt(record.RecordKeyBytes, ownerPublicKeyBytes, nil); err == nil {
+ payload.RecordKey = BytesToBase64(encryptedRecordKey)
+ } else {
+ return nil, err
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareFileUploadPayload(record *Record, file *KeeperFileUpload) (res *FileUploadPayload, encFileData []byte, err error) {
+ payload := FileUploadPayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ }
+ if strings.TrimSpace(payload.ClientId) == "" {
+ return nil, nil, fmt.Errorf("unable to create record - client Id is missing from the configuration")
+ }
+ if record == nil {
+ return nil, nil, fmt.Errorf("unable to create record - missing record data")
+ }
+
+ ownerPublicKey := strings.TrimSpace(c.Config.Get(KEY_OWNER_PUBLIC_KEY))
+ if ownerPublicKey == "" {
+ return nil, nil, fmt.Errorf("unable to create record - owner key is missing. Looks like application was created using outdated client (Web Vault or Commander)")
+ }
+ ownerPublicKeyBytes := Base64ToBytes(ownerPublicKey)
+
+ fileData := KeeperFileData{
+ Title: file.Title,
+ Name: file.Name,
+ Type: file.Type,
+ Size: int64(len(file.Data)),
+ LastModified: NowMilliseconds(),
+ }
+
+ fileRecordBytes := ""
+ if fd, err := json.Marshal(fileData); err == nil {
+ fileRecordBytes = string(fd)
+ } else {
+ return nil, nil, err
+ }
+
+ fileRecordKeyBytes, _ := GetRandomBytes(32)
+ fileRecordUidBytes, _ := GetRandomBytes(16)
+ payload.FileRecordUid = BytesToUrlSafeStr(fileRecordUidBytes)
+
+ if encryptedFileRecord, err := EncryptAesGcm([]byte(fileRecordBytes), fileRecordKeyBytes); err == nil {
+ payload.FileRecordData = BytesToUrlSafeStr(encryptedFileRecord)
+ } else {
+ return nil, nil, err
+ }
+ if encryptedFileRecordKey, err := PublicEncrypt(fileRecordKeyBytes, ownerPublicKeyBytes, nil); err == nil {
+ payload.FileRecordKey = BytesToBase64(encryptedFileRecordKey)
+ } else {
+ return nil, nil, err
+ }
+ if encryptedLinkKey, err := EncryptAesGcm(fileRecordKeyBytes, record.RecordKeyBytes); err == nil {
+ payload.LinkKey = BytesToBase64(encryptedLinkKey)
+ } else {
+ return nil, nil, err
+ }
+
+ encryptedFileData, err := EncryptAesGcm(file.Data, fileRecordKeyBytes)
+ if err == nil {
+ payload.FileSize = len(encryptedFileData)
+ } else {
+ return nil, nil, err
+ }
+
+ payload.OwnerRecordUid = record.Uid
+
+ if exists := record.FieldExists("fields", "fileRef"); !exists {
+ fref := NewFileRef("")
+ fref.Value = []string{}
+ record.InsertField("fields", fref)
+ record.update()
+ }
+ fileRefs, err := record.GetStandardFieldValue("fileRef", false)
+ if err != nil {
+ return nil, nil, err
+ }
+ if len(fileRefs) > 0 {
+ fileRefs = append(fileRefs, payload.FileRecordUid)
+ record.SetStandardFieldValue("fileRef", fileRefs)
+ } else {
+ record.SetStandardFieldValue("fileRef", payload.FileRecordUid)
+ }
+
+ ownerRecordJson := DictToJson(record.RecordDict)
+ ownerRecordBytes := StringToBytes(ownerRecordJson)
+ if encryptedOwnerRecord, err := EncryptAesGcm(ownerRecordBytes, record.RecordKeyBytes); err == nil {
+ payload.OwnerRecordData = BytesToUrlSafeStr(encryptedOwnerRecord)
+ } else {
+ return nil, nil, err
+ }
+
+ return &payload, encryptedFileData, nil
+}
+
+func (c *SecretsManager) prepareCreateFolderPayload(createOptions CreateOptions, folderName string, sharedFolderKey []byte) (res *CreateFolderPayload, err error) {
+ payload := CreateFolderPayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ SharedFolderUid: createOptions.FolderUid,
+ ParentUid: createOptions.SubFolderUid,
+ }
+
+ if strings.TrimSpace(payload.ClientId) == "" {
+ return nil, fmt.Errorf("unable to update folder - client Id is missing from the configuration")
+ }
+
+ folderUid, _ := GetRandomBytes(16)
+ payload.FolderUid = BytesToUrlSafeStr(folderUid)
+
+ folderKey, _ := GetRandomBytes(32)
+ if encryptedFolderKey, err := EncryptAesCbc(folderKey, sharedFolderKey); err == nil {
+ payload.SharedFolderKey = BytesToUrlSafeStr(encryptedFolderKey)
+ } else {
+ return nil, err
+ }
+
+ keeperFolderName := map[string]interface{}{"name": folderName}
+ folderDataJson := DictToJson(keeperFolderName)
+ folderDataBytes := []byte(folderDataJson)
+ if encryptedFolderData, err := EncryptAesCbc(folderDataBytes, folderKey); err == nil {
+ payload.Data = BytesToUrlSafeStr(encryptedFolderData)
+ } else {
+ return nil, err
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareUpdateFolderPayload(folderUid string, folderName string, folderKey []byte) (res *UpdateFolderPayload, err error) {
+ payload := UpdateFolderPayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ FolderUid: folderUid,
+ }
+
+ keeperFolderName := map[string]interface{}{"name": folderName}
+ folderDataJson := DictToJson(keeperFolderName)
+ folderDataBytes := []byte(folderDataJson)
+ if encryptedFolderData, err := EncryptAesCbc(folderDataBytes, folderKey); err == nil {
+ payload.Data = BytesToUrlSafeStr(encryptedFolderData)
+ } else {
+ return nil, err
+ }
+
+ if strings.TrimSpace(payload.ClientId) == "" {
+ return nil, fmt.Errorf("unable to update folder - client Id is missing from the configuration")
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) prepareDeleteFolderPayload(folderUids []string, forceDeletion bool) (res *DeleteFolderPayload, err error) {
+ payload := DeleteFolderPayload{
+ ClientVersion: keeperSecretsManagerClientId,
+ ClientId: c.Config.Get(KEY_CLIENT_ID),
+ FolderUids: folderUids,
+ ForceDeletion: forceDeletion,
+ }
+
+ if strings.TrimSpace(payload.ClientId) == "" {
+ return nil, fmt.Errorf("unable to delete folder - client Id is missing from the configuration")
+ }
+
+ return &payload, nil
+}
+
+func (c *SecretsManager) PostQuery(path string, payload interface{}) (body []byte, err error) {
+ keeperServer := GetServerHostname(c.Hostname, c.Config)
+ url := fmt.Sprintf("https://%s/api/rest/sm/v1/%s", keeperServer, path)
+ var transmissionKey *TransmissionKey
+ var ksmRs *KsmHttpResponse
+ if c.context != nil { // context is used in tests only
+ if pc := c.PrepareContext(); pc != nil {
+ *c.context = pc
+ }
+ }
+
+ for {
+ transmissionKeyId := strings.TrimSpace(c.Config.Get(KEY_SERVER_PUBLIC_KEY_ID))
+ if transmissionKeyId == "" {
+ transmissionKeyId = defaultKeeperServerPublicKeyId
+ c.Config.Set(KEY_SERVER_PUBLIC_KEY_ID, transmissionKeyId)
+ }
+
+ transmissionKey = c.GenerateTransmissionKey(transmissionKeyId)
+ if transmissionKey == nil {
+ return nil, errors.New("error generating the transmission key")
+ }
+
+ if c.context != nil {
+ (*c.context).TransmissionKey = *transmissionKey
+ }
+ encryptedPayloadAndSignature, err := c.encryptAndSignPayload(transmissionKey, payload)
+ if err != nil {
+ return nil, errors.New("error encrypting payload: " + err.Error())
+ }
+
+ ksmRs, err = c.PostFunction(url, transmissionKey, encryptedPayloadAndSignature, c.VerifySslCerts)
+ if err != nil {
+ return nil, errors.New("error during POST request: " + err.Error())
+ }
+
+ if c.cache != nil && path == "get_secret" {
+ success := true
+ if ksmRs != nil && ksmRs.StatusCode == 200 {
+ data := make([]byte, 0, len(transmissionKey.Key)+len(ksmRs.Data))
+ data = append(data, transmissionKey.Key...)
+ data = append(data, ksmRs.Data...)
+ c.cache.SaveCachedValue(data)
+ } else {
+ if cachedData, cerr := c.cache.GetCachedValue(); cerr == nil && len(cachedData) >= Aes256KeySize {
+ transmissionKey.Key = cachedData[:Aes256KeySize]
+ data := cachedData[Aes256KeySize:]
+ ksmRs = NewKsmHttpResponse(200, data, nil)
+ } else {
+ success = false
+ }
+ }
+ if success {
+ break
+ }
+ }
+
+ // If we are ok, then break out of the while loop
+ if ksmRs.StatusCode == 200 {
+ break
+ }
+
+ // Handle the error. Handler will return a retry status if it is a recoverable error.
+ if retry, err := c.HandleHttpError(ksmRs.HttpResponse, ksmRs.Data, err); !retry {
+ errMsg := "N/A"
+ if err != nil {
+ errMsg = err.Error()
+ }
+ klog.Error("POST Error: " + errMsg)
+ return nil, errors.New("POST Error: " + errMsg)
+ }
+ }
+
+ if ksmRs != nil && len(ksmRs.Data) > 0 {
+ decryptedResponseBytes, err := Decrypt(ksmRs.Data, transmissionKey.Key)
+ return decryptedResponseBytes, err
+ }
+
+ // break out of the loop only on success - empty body/data is a valid response ex. for update
+ return []byte{}, err
+}
+
+func (c *SecretsManager) PostFunction(
+ url string,
+ transmissionKey *TransmissionKey,
+ encryptedPayloadAndSignature *EncryptedPayload,
+ verifySslCerts bool) (*KsmHttpResponse, error) {
+
+ rq, err := http.NewRequest("POST", url, bytes.NewBuffer(encryptedPayloadAndSignature.EncryptedPayload))
+ if err != nil {
+ return NewKsmHttpResponse(0, nil, nil), err
+ }
+
+ rq.Header.Set("Content-Type", "application/octet-stream")
+ rq.Header.Set("Content-Length", fmt.Sprint(len(encryptedPayloadAndSignature.EncryptedPayload)))
+ rq.Header.Set("PublicKeyId", transmissionKey.PublicKeyId)
+ rq.Header.Set("TransmissionKey", BytesToBase64(transmissionKey.EncryptedKey))
+ rq.Header.Set("Authorization", fmt.Sprintf("Signature %s", BytesToBase64(encryptedPayloadAndSignature.Signature)))
+ // klog.Debug(rq.Header)
+
+ tr := http.DefaultClient.Transport
+ if insecureSkipVerify := !verifySslCerts; insecureSkipVerify {
+ tr = &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify},
+ }
+ }
+ client := &http.Client{Transport: tr}
+
+ rs, err := client.Do(rq)
+ if err != nil {
+ return NewKsmHttpResponse(0, nil, rs), err
+ }
+ defer rs.Body.Close()
+
+ rsBody, err := ioutil.ReadAll(rs.Body)
+ return NewKsmHttpResponse(rs.StatusCode, rsBody, rs), err
+}
+
+func (c *SecretsManager) HandleHttpError(rs *http.Response, body []byte, httpError error) (retry bool, err error) {
+ retry = false
+ err = httpError
+ logMessage := fmt.Sprintf("Error: %s (http error code: %d, raw: %s)", rs.Status, rs.StatusCode, string(body))
+
+ // switch to warning for recoverable errors - ex. key rotation
+ keyRotation := false
+ if matched, err := regexp.MatchString(`"key_id"\s*:\s*\d+\s*(?:\,|\})`, string(body)); err == nil && matched {
+ if matched, err = regexp.MatchString(`"error"\s*:\s*"key"|"message"\s*:\s*"invalid key id"`, string(body)); err == nil && matched {
+ keyRotation = true
+ }
+ }
+
+ if keyRotation {
+ klog.Warning(logMessage)
+ } else {
+ klog.Error(logMessage)
+ }
+
+ responseDict := JsonToDict(string(body))
+ if len(responseDict) == 0 {
+ // This is an unknown error, not one of ours, just throw a HTTPError
+ return false, errors.New("HTTPError: " + string(body))
+ }
+
+ // Try to get the error from result_code, then from error.
+ msg := ""
+ rc, found := responseDict["result_code"]
+ if !found {
+ rc, found = responseDict["error"]
+ }
+ if found && rc.(string) == "invalid_client_version" {
+ klog.Error(fmt.Sprintf("Client version %s was not registered in the backend", keeperSecretsManagerClientId))
+ if additionalInfo, found := responseDict["additional_info"]; found {
+ msg = additionalInfo.(string)
+ }
+ } else if found && rc.(string) == "key" {
+ // The server wants us to use a different public key.
+ keyId := ""
+ if kid, ok := responseDict["key_id"]; ok {
+ keyId = fmt.Sprintf("%v", kid)
+ }
+ klog.Info(fmt.Sprintf("Server has requested we use public key %v", keyId))
+ if len(keyId) == 0 {
+ msg = "The public key is blank from the server"
+ } else if _, found := keeperServerPublicKeys[keyId]; found {
+ if cfg := c.Config.Set(KEY_SERVER_PUBLIC_KEY_ID, keyId); len(cfg) > 0 {
+ // The only normal exit from this method
+ return true, nil
+ } else {
+ // read-only or inaccessible configuration
+ return false, errors.New("failed to switch the server public key")
+ }
+ } else {
+ msg = fmt.Sprintf("The public key at %v does not exist in the SDK", keyId)
+ }
+ } else {
+ responseMsg, ok := responseDict["message"]
+ if !ok {
+ responseMsg = "N/A"
+ }
+ msg = fmt.Sprintf("Error: %v, message=%v", rc, responseMsg)
+ }
+
+ if msg != "" {
+ err = errors.New(msg)
+ } else if len(body) > 0 {
+ err = errors.New(string(body))
+ }
+
+ return
+}
+
+func GetSharedFolderKey(folders []*KeeperFolder, responseFolders []interface{}, parent string) []byte {
+ for {
+ parentFolderUid := ""
+ parentFolderParentUid := ""
+ for _, f := range responseFolders {
+ fmap := f.(map[string]interface{})
+ if iUid, found := fmap["folderUid"]; found && iUid != nil {
+ if fuid, ok := iUid.(string); ok && fuid == parent {
+ parentFolderUid = fuid
+ if iPUid, found := fmap["parent"]; found && iPUid != nil {
+ if pfuid, ok := iPUid.(string); ok && pfuid != "" {
+ parentFolderParentUid = pfuid
+ }
+ }
+ }
+ }
+ }
+ if parentFolderUid == "" {
+ return nil
+ }
+ if parentFolderParentUid == "" {
+ for _, f := range folders {
+ if f.FolderUid == parentFolderUid {
+ return f.FolderKey
+ }
+ }
+ return nil
+ }
+ parent = parentFolderParentUid
+ }
+}
+
+func (c *SecretsManager) fetchAndDecryptFolders() (folders []*KeeperFolder, err error) {
+ folders = []*KeeperFolder{}
+ payload, err := c.prepareGetPayload(QueryOptions{})
+ if err != nil {
+ return nil, err
+ }
+
+ decryptedResponseBytes, err := c.PostQuery("get_folders", payload)
+ if err != nil {
+ return nil, err
+ }
+
+ decryptedResponseStr := BytesToString(decryptedResponseBytes)
+ decryptedResponseDict := JsonToDict(decryptedResponseStr)
+
+ appKey := Base64ToBytes(c.Config.Get(KEY_APP_KEY))
+ if len(appKey) == 0 {
+ return nil, errors.New("app key is missing from the storage")
+ }
+
+ if foldersResp, found := decryptedResponseDict["folders"]; found && foldersResp != nil {
+ if siFolders, ok := foldersResp.([]interface{}); ok {
+ for _, f := range siFolders {
+ fkey := []byte{}
+ fmap := f.(map[string]interface{})
+ if iParent, found := fmap["parent"]; found && iParent != nil {
+ if parent, ok := iParent.(string); ok && parent != "" {
+ sharedFolderKey := GetSharedFolderKey(folders, siFolders, parent)
+ sKey := fmap["folderKey"].(string)
+ if folderKey, err := DecryptAesCbc(UrlSafeStrToBytes(sKey), sharedFolderKey); err == nil {
+ fkey = folderKey
+ }
+ }
+ } else {
+ // no parent - use appKey to decrypt
+ sKey := fmap["folderKey"].(string)
+ if folderKey, err := Decrypt(UrlSafeStrToBytes(sKey), appKey); err == nil {
+ fkey = folderKey
+ }
+ }
+ if len(fkey) == 0 {
+ klog.Error("failed to decrypt the folder key")
+ }
+
+ folder := NewKeeperFolder(fmap, fkey)
+ if f != nil {
+ folders = append(folders, folder)
+ } else {
+ klog.Error("error parsing folder JSON: ", f)
+ }
+ }
+ } else {
+ klog.Error("folder JSON is in incorrect format")
+ }
+ }
+
+ return
+}
+
+func (c *SecretsManager) fetchAndDecryptSecrets(queryOptions QueryOptions) (smr *SecretsManagerResponse, err error) {
+ records := []*Record{}
+ folders := []*Folder{}
+ justBound := false
+
+ payload, err := c.prepareGetPayload(queryOptions)
+ if err != nil {
+ return nil, err
+ }
+
+ decryptedResponseBytes, err := c.PostQuery("get_secret", payload)
+ if err != nil {
+ return nil, err
+ }
+
+ decryptedResponseStr := BytesToString(decryptedResponseBytes)
+ decryptedResponseDict := JsonToDict(decryptedResponseStr)
+
+ var secretKey []byte
+ if encryptedAppKey, found := decryptedResponseDict["encryptedAppKey"]; found && encryptedAppKey != nil && fmt.Sprintf("%v", encryptedAppKey) != "" {
+ justBound = true
+ clientKey := UrlSafeStrToBytes(c.Config.Get(KEY_CLIENT_KEY))
+ if len(clientKey) == 0 {
+ return nil, errors.New("client key is missing from the storage")
+ }
+ encryptedMasterKey := UrlSafeStrToBytes(encryptedAppKey.(string))
+ if secretKey, err = Decrypt(encryptedMasterKey, clientKey); err == nil {
+ if cfg := c.Config.Set(KEY_APP_KEY, BytesToBase64(secretKey)); len(cfg) < 1 {
+ klog.Error("failed to set the application key")
+ }
+ c.Config.Delete(KEY_CLIENT_KEY)
+ } else {
+ klog.Error("failed to decrypt the application key")
+ }
+ if ownerPubKey, found := decryptedResponseDict[string(KEY_OWNER_PUBLIC_KEY)]; found && ownerPubKey != nil {
+ if appOwnerPublicKey := strings.TrimSpace(fmt.Sprintf("%v", ownerPubKey)); appOwnerPublicKey != "" {
+ if cfg := c.Config.Set(KEY_OWNER_PUBLIC_KEY, appOwnerPublicKey); len(cfg) < 1 {
+ klog.Error("failed to set the app owner public key - file uploads and creating new records may fail")
+ }
+ }
+ }
+ } else {
+ secretKey = Base64ToBytes(c.Config.Get(KEY_APP_KEY))
+ if len(secretKey) == 0 {
+ return nil, errors.New("app key is missing from the storage")
+ }
+ }
+
+ recordsResp := decryptedResponseDict["records"]
+ foldersResp := decryptedResponseDict["folders"]
+
+ recordCount := 0
+ emptyInterfaceSlice := []interface{}{}
+ if recordsResp != nil {
+ if reflect.TypeOf(recordsResp) == reflect.TypeOf(emptyInterfaceSlice) {
+ for _, r := range recordsResp.([]interface{}) {
+ recordCount++
+ record := NewRecordFromJson(r.(map[string]interface{}), secretKey, "")
+ records = append(records, record)
+ }
+ } else {
+ klog.Error("record JSON is in incorrect format")
+ }
+ }
+
+ folderCount := 0
+ if foldersResp != nil {
+ if reflect.TypeOf(foldersResp) == reflect.TypeOf(emptyInterfaceSlice) {
+ for _, f := range foldersResp.([]interface{}) {
+ folderCount++
+ folder := NewFolderFromJson(f.(map[string]interface{}), secretKey)
+ if f != nil {
+ records = append(records, folder.Records()...)
+ folders = append(folders, folder)
+ } else {
+ klog.Error("error parsing folder JSON: ", f)
+ }
+ }
+ } else {
+ klog.Error("folder JSON is in incorrect format")
+ }
+ }
+
+ klog.Debug(fmt.Sprintf("Individual record count: %d", recordCount))
+ klog.Debug(fmt.Sprintf("Folder count: %d", folderCount))
+ klog.Debug(fmt.Sprintf("Total record count: %d", len(records)))
+
+ smResponse := SecretsManagerResponse{
+ Records: records,
+ Folders: folders,
+ JustBound: justBound,
+ }
+
+ if appDataB64, found := decryptedResponseDict["appData"]; found && appDataB64 != nil && fmt.Sprintf("%v", appDataB64) != "" {
+ appDataBytes := UrlSafeStrToBytes(appDataB64.(string))
+ appKey := Base64ToBytes(c.Config.Get(KEY_APP_KEY))
+ if appDataJson, err := Decrypt(appDataBytes, appKey); err == nil {
+ appData := AppData{}
+ if err := json.Unmarshal([]byte(appDataJson), &appData); err == nil {
+ smResponse.AppData = appData
+ } else {
+ klog.Error("Error deserializing appData from JSON: " + err.Error())
+ }
+ } else {
+ klog.Warning("Failed to decrypt appData - " + err.Error())
+ }
+ }
+ if expiresOn, found := decryptedResponseDict["expiresOn"]; found && expiresOn != nil && fmt.Sprintf("%v", expiresOn) != "" {
+ if n, ok := expiresOn.(float64); ok {
+ smResponse.ExpiresOn = (int64)(n)
+ } else {
+ klog.Error("Error parsing ExpiresOn - expected float64 number, got ", expiresOn)
+ }
+ }
+ if warnings, found := decryptedResponseDict["warnings"]; found && warnings != nil && fmt.Sprintf("%v", warnings) != "" {
+ smResponse.Warnings = fmt.Sprintf("%v", warnings)
+ }
+
+ return &smResponse, nil
+}
+
+func (c *SecretsManager) GetSecretsFullResponse(uids []string) (response *SecretsManagerResponse, err error) {
+ // Retrieve all records associated with the given application
+ // optionally filtered by record uids
+ queryOptions := QueryOptions{RecordsFilter: uids}
+ return c.GetSecretsFullResponseWithOptions(queryOptions)
+}
+
+func (c *SecretsManager) GetSecretsFullResponseWithOptions(queryOptions QueryOptions) (response *SecretsManagerResponse, err error) {
+ // Retrieve records associated with the given application
+ // optionally filtered by the query options
+
+ recordsResp, err := c.fetchAndDecryptSecrets(queryOptions)
+ if err != nil {
+ return nil, err
+ }
+ if recordsResp.JustBound {
+ recordsResp, err = c.fetchAndDecryptSecrets(queryOptions)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Log warnings we got from the server
+ // Will only be displayed if logging is enabled:
+ if recordsResp.Warnings != "" {
+ klog.Warning(recordsResp.Warnings)
+ }
+
+ return recordsResp, nil
+}
+
+// GetSecrets retrieves all records associated with the given application
+// optionally filtered by uids
+func (c *SecretsManager) GetSecrets(uids []string) (records []*Record, err error) {
+ resp, rerr := c.GetSecretsFullResponse(uids)
+ if rerr != nil || resp == nil {
+ return nil, rerr
+ }
+ return resp.Records, rerr
+}
+
+// GetSecretsWithOptions retrieves all records associated with the given application
+// optionally filtered by query options
+func (c *SecretsManager) GetSecretsWithOptions(queryOptions QueryOptions) (records []*Record, err error) {
+ resp, rerr := c.GetSecretsFullResponseWithOptions(queryOptions)
+ if rerr != nil || resp == nil {
+ return nil, rerr
+ }
+ return resp.Records, rerr
+}
+
+func (c *SecretsManager) GetFolders() ([]*KeeperFolder, error) {
+ return c.fetchAndDecryptFolders()
+}
+
+func (c *SecretsManager) GetSecretsByTitle(recordTitle string) (records []*Record, err error) {
+ if records, err := c.GetSecrets([]string{}); err != nil {
+ return nil, err
+ } else {
+ return FindSecretsByTitle(recordTitle, records), nil
+ }
+}
+
+func (c *SecretsManager) GetSecretByTitle(recordTitle string) (record *Record, err error) {
+ if records, err := c.GetSecrets([]string{}); err != nil {
+ return nil, err
+ } else {
+ return FindSecretByTitle(recordTitle, records), nil
+ }
+}
+
+func FindSecretByTitle(recordTitle string, records []*Record) *Record {
+ for _, r := range records {
+ if r.Title() == recordTitle {
+ return r
+ }
+ }
+ return nil
+}
+
+func FindSecretsByTitle(recordTitle string, records []*Record) []*Record {
+ recordsByTitle := []*Record{}
+ for _, r := range records {
+ if r.Title() == recordTitle {
+ recordsByTitle = append(recordsByTitle, r)
+ }
+ }
+ return recordsByTitle
+}
+
+func (c *SecretsManager) Save(record *Record) (err error) {
+ return c.updateSecret(record, TransactionTypeNone)
+}
+
+// SaveBeginTransaction requires corresponding call to CompleteTransaction to either commit or rollback
+func (c *SecretsManager) SaveBeginTransaction(record *Record, transactionType UpdateTransactionType) (err error) {
+ return c.updateSecret(record, transactionType)
+}
+
+func (c *SecretsManager) updateSecret(record *Record, transactionType UpdateTransactionType) (err error) {
+ // Save updated secret values
+ if record == nil {
+ return errors.New("update secret - missing record data")
+ }
+
+ klog.Info("Updating record uid: " + record.Uid)
+ payload, err := c.prepareUpdatePayload(record, transactionType)
+ if err != nil {
+ return err
+ }
+
+ _, err = c.PostQuery("update_secret", payload)
+ return err
+}
+
+func (c *SecretsManager) CompleteTransaction(recordUid string, rollback bool) (err error) {
+ payload, err := c.prepareCompleteTransactionPayload(recordUid)
+ if err != nil {
+ return err
+ }
+
+ route := "finalize_secret_update"
+ if rollback {
+ route = "rollback_secret_update"
+ }
+
+ _, err = c.PostQuery(route, payload)
+ return err
+}
+
+func (c *SecretsManager) UploadFilePath(record *Record, filePath string) (uid string, err error) {
+ // Upload file using provided file path
+ if fileToUpload, err := GetFileForUpload(filePath, "", "", ""); err != nil {
+ return "", err
+ } else {
+ return c.UploadFile(record, fileToUpload)
+ }
+}
+
+func (c *SecretsManager) UploadFile(record *Record, file *KeeperFileUpload) (uid string, err error) {
+ if record == nil {
+ return "", errors.New("UploadFile - missing record data")
+ } else if file == nil {
+ return "", errors.New("UploadFile - missing file upload data")
+ }
+
+ klog.Info(fmt.Sprintf("Uploading file: %s to record UID: %s", file.Name, record.Uid))
+ klog.Debug(fmt.Sprintf("Preparing upload payload. Record UID: [%s], file name: [%s], file size: [%d]", record.Uid, file.Name, len(file.Data)))
+ payload, encryptedFileData, err := c.prepareFileUploadPayload(record, file)
+ if err != nil {
+ return "", err
+ }
+
+ klog.Debug("Sending file metadata")
+ responseData, err := c.PostQuery("add_file", payload)
+ if err != nil {
+ return "", err
+ }
+
+ response, err := AddFileResponseFromJson(string(responseData))
+ if err != nil {
+ return "", err
+ }
+
+ klog.Debug(fmt.Sprintf("Uploading file data. Upload URL: [%s], file name: [%s], encrypted file size: [%d]", response.Url, file.Name, len(encryptedFileData)))
+ if err := c.fileUpload(response.Url, response.Parameters, response.SuccessStatusCode, encryptedFileData); err != nil {
+ return "", err
+ }
+
+ return payload.FileRecordUid, nil
+}
+
+func (c *SecretsManager) fileUpload(url, parameters string, successStatusCode int, fileData []byte) error {
+ body := new(bytes.Buffer)
+ w := multipart.NewWriter(body)
+
+ var jsParams map[string]string
+ err := json.Unmarshal([]byte(parameters), &jsParams)
+ if err != nil {
+ return err
+ }
+ for key, val := range jsParams {
+ if err := w.WriteField(key, val); err != nil {
+ return err
+ }
+ }
+
+ fw, err := w.CreateFormFile("file", "")
+ if err != nil {
+ return err
+ }
+ if _, err = fw.Write(fileData); err != nil {
+ return err
+ }
+
+ // create terminating boundary
+ if err := w.Close(); err != nil {
+ return err
+ }
+
+ rq, err := http.NewRequest("POST", url, body)
+ if err != nil {
+ return err
+ }
+
+ rq.Header.Set("Content-Type", w.FormDataContentType())
+
+ tr := http.DefaultClient.Transport
+ if insecureSkipVerify := !c.VerifySslCerts; insecureSkipVerify {
+ tr = &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify},
+ }
+ }
+ client := &http.Client{Transport: tr}
+
+ rs, err := client.Do(rq)
+ if err != nil {
+ return err
+ }
+ defer rs.Body.Close()
+
+ if rs.StatusCode != successStatusCode {
+ return fmt.Errorf("upload failed, status code %v", rs.StatusCode)
+ }
+
+ // PostResponse XML is ignored - verify status code for success
+ // rs.Header["Content-Type"][0] == "application/xml"
+ rsBody, err := ioutil.ReadAll(rs.Body)
+ if err != nil {
+ return err
+ }
+ if len(rsBody) == 0 {
+ return fmt.Errorf("upload failed - XML response was expected but not received")
+ }
+ klog.Debug(fmt.Sprintf("Finished uploading file data. Status code: %d, response data: %s", rs.StatusCode, string(rsBody)))
+
+ return nil
+}
+
+func (c *SecretsManager) DeleteSecrets(recordUids []string) (statuses map[string]string, err error) {
+ statuses = map[string]string{}
+ if len(recordUids) == 0 {
+ return statuses, nil
+ }
+
+ payload, err := c.prepareDeletePayload(recordUids)
+ if err != nil {
+ return statuses, err
+ }
+
+ resp, err := c.PostQuery("delete_secret", payload)
+ if err != nil {
+ return statuses, err
+ }
+
+ if respJson := string(resp); respJson != "" {
+ dsr, err := DeleteSecretsResponseFromJson(respJson)
+ if err != nil {
+ return statuses, err
+ }
+ if dsr != nil && len(dsr.Records) > 0 {
+ for _, v := range dsr.Records {
+ message := v.ResponseCode
+ if v.ErrorMessage != "" {
+ message += ": " + v.ErrorMessage
+ }
+ statuses[v.RecordUid] = message
+ // Success - "UID": "ok", Error - "UID": "code: description"
+ }
+ }
+ }
+
+ return statuses, err
+}
+
+// CreateSecret creates new record from a cloned record found by NewRecord
+// and the new record will be placed into the same shared folder as the original
+func (c *SecretsManager) CreateSecret(record *Record) (recordUid string, err error) {
+ // Records shared directly to the application cannot be used as template records
+ // only records in a shared folder (shared to the application) should be used as templates
+ if strings.TrimSpace(record.folderUid) == "" || len(record.folderKeyBytes) == 0 {
+ return "", fmt.Errorf("record %s is not in a shared folder - cannot create secret", record.Uid)
+ }
+
+ createOptions := CreateOptions{FolderUid: record.folderUid}
+ payload, err := c.prepareCreatePayload(record, createOptions, record.folderKeyBytes)
+ if err != nil {
+ return "", err
+ }
+
+ _, err = c.PostQuery("create_secret", payload)
+ return payload.RecordUid, err
+}
+
+// CreateSecretWithRecordData creates new record using recordUID, folderUID and record data provided
+// Note: if param recUid is empty - new auto generated record UID will be used
+func (c *SecretsManager) CreateSecretWithRecordData(recUid, folderUid string, recordData *RecordCreate) (recordUid string, err error) {
+ // Backend only needs a JSON string of the record, so we have different ways of handing data:
+ // - providing data as JSON string
+ // - providing data as map[string]interface{}
+ // - providing data as CreateRecord struct
+ // Here we will use CreateRecord objects
+
+ if recordData == nil || recordData.RecordType == "" {
+ return "", errors.New("new record data has to be a valid 'RecordCreate' object")
+ }
+
+ // Since we don't know folder's key where this record will be placed in,
+ // currently we have to retrieve all data that is shared to this device/client
+ // and look for the folder's key in the returned folder data
+
+ resp, err := c.GetSecretsFullResponse([]string{})
+ if err != nil {
+ return "", err
+ }
+
+ folders := []*Folder{}
+ if resp != nil && resp.Folders != nil {
+ folders = resp.Folders
+ }
+
+ foundFolder := GetFolderByKey(folderUid, folders)
+ if foundFolder == nil {
+ return "", fmt.Errorf("folder uid='%s' was not retrieved. If you are creating a record in a "+
+ "shared folder that you know exists, make sure that at least one record is present in "+
+ "the folder prior to adding a new record", folderUid)
+ }
+
+ record := NewRecordFromRecordDataWithUid(recUid, recordData, foundFolder)
+ if record == nil {
+ return "", fmt.Errorf("failed to create new record from record data: %v", recordData)
+ }
+ createOptions := CreateOptions{FolderUid: folderUid}
+ payload, err := c.prepareCreatePayload(record, createOptions, foundFolder.key)
+ if err != nil {
+ return "", err
+ }
+
+ _, err = c.PostQuery("create_secret", payload)
+ return payload.RecordUid, err
+}
+
+// CreateSecretWithRecordDataAndOptions creates new record using CreateOptions and record data provided
+func (c *SecretsManager) CreateSecretWithRecordDataAndOptions(createOptions CreateOptions, recordData *RecordCreate, folders []*KeeperFolder) (recordUid string, err error) {
+ if recordData == nil || recordData.RecordType == "" {
+ return "", errors.New("new record data has to be a valid 'RecordCreate' object")
+ }
+
+ if len(folders) == 0 {
+ if folders, err = c.GetFolders(); err != nil {
+ return "", err
+ }
+ }
+
+ folderKey := []byte{}
+ for _, fldr := range folders {
+ if fldr.FolderUid == createOptions.FolderUid {
+ folderKey = fldr.FolderKey
+ break
+ }
+ }
+
+ if len(folderKey) == 0 {
+ return "", errors.New("unable to update folder - folder key for " + createOptions.FolderUid + " not found")
+ }
+
+ folder := &Folder{key: folderKey, uid: createOptions.FolderUid}
+ record := NewRecordFromRecordData(recordData, folder)
+ if record == nil {
+ return "", fmt.Errorf("failed to create new record from record data: %v", recordData)
+ }
+
+ payload, err := c.prepareCreatePayload(record, createOptions, folderKey)
+ if err != nil {
+ return "", err
+ }
+
+ _, err = c.PostQuery("create_secret", payload)
+ return payload.RecordUid, err
+}
+
+// CreateFolder creates new folder using the provided options.
+//
+// folders == nil will force downloading all folders metadata with every request.
+// Folders metadata could be retrieved from GetFolders() and cached and reused
+// as long as it is not modified externally or internally
+//
+// createOptions.FolderUid is required and must be a parent shared folder
+//
+// createOptions.SubFolderUid could be many levels deep under its parent.
+// If SubFolderUid is empty - new folder is created under parent FolderUid
+func (c *SecretsManager) CreateFolder(createOptions CreateOptions, folderName string, folders []*KeeperFolder) (folderUid string, err error) {
+ if len(folders) == 0 {
+ if folders, err = c.GetFolders(); err != nil {
+ return "", err
+ }
+ }
+
+ folderKey := []byte{}
+ for _, fldr := range folders {
+ if fldr.FolderUid == createOptions.FolderUid {
+ folderKey = fldr.FolderKey
+ break
+ }
+ }
+
+ if len(folderKey) == 0 {
+ return "", errors.New("Unable to create folder - folder key for " + createOptions.FolderUid + " not found")
+ }
+
+ payload, err := c.prepareCreateFolderPayload(createOptions, folderName, folderKey)
+ if err != nil {
+ return "", err
+ }
+
+ if _, err = c.PostQuery("create_folder", payload); err != nil {
+ return "", err
+ }
+
+ return payload.FolderUid, nil
+}
+
+// UpdateFolder changes the folder metadata - currently folder name only
+// folders == nil will force downloading all folders metadata with every request
+func (c *SecretsManager) UpdateFolder(folderUid, folderName string, folders []*KeeperFolder) (err error) {
+ if len(folders) == 0 {
+ if folders, err = c.GetFolders(); err != nil {
+ return err
+ }
+ }
+
+ folderKey := []byte{}
+ for _, fldr := range folders {
+ if fldr.FolderUid == folderUid {
+ folderKey = fldr.FolderKey
+ break
+ }
+ }
+
+ if len(folderKey) == 0 {
+ return errors.New("Unable to update folder - folder key for " + folderUid + " not found")
+ }
+
+ payload, err := c.prepareUpdateFolderPayload(folderUid, folderName, folderKey)
+ if err != nil {
+ return err
+ }
+
+ _, err = c.PostQuery("update_folder", payload)
+ return err
+}
+
+// DeleteFolder removes the selected folders.
+// Use forceDeletion flag to remove non-empty folders
+// Note! When using forceDeletion avoid sending parent with its children folder UIDs.
+// Depending on the delete order you may get an error ex. if parent force-deleted child first.
+// There's no guarantee that list will always be processed in FIFO order.
+// Note! Any folders UIDs missing from the vault or not shared to the KSM Application
+// will not result in error.
+func (c *SecretsManager) DeleteFolder(folderUids []string, forceDeletion bool) (statuses map[string]string, err error) {
+ statuses = map[string]string{}
+ if len(folderUids) == 0 {
+ return statuses, nil
+ }
+
+ payload, err := c.prepareDeleteFolderPayload(folderUids, forceDeletion)
+ if err != nil {
+ return statuses, err
+ }
+
+ resp, err := c.PostQuery("delete_folder", payload)
+ if err != nil {
+ return statuses, err
+ }
+
+ if respJson := string(resp); respJson != "" {
+ dsr, err := DeleteFoldersResponseFromJson(respJson)
+ if err != nil {
+ return statuses, err
+ }
+ if dsr != nil && len(dsr.Folders) > 0 {
+ for _, v := range dsr.Folders {
+ message := v.ResponseCode
+ if v.ErrorMessage != "" {
+ message += ": " + v.ErrorMessage
+ }
+ statuses[v.FolderUid] = message
+ // Success - "UID": "ok", Error - "UID": "code: description"
+ }
+ }
+ }
+
+ return statuses, err
+}
+
+// Legacy notation
+func (c *SecretsManager) extractNotation(records []*Record, parsedNotation []*NotationSection) (fieldValue []interface{}, err error) {
+ fieldValue = []interface{}{}
+
+ recordToken := "" // UID or Title
+ recordTokenIsValid := parsedNotation[1] != nil && parsedNotation[1].IsPresent && parsedNotation[1].Text != nil
+ if recordTokenIsValid {
+ recordToken = parsedNotation[1].Text.Text
+ } else {
+ return fieldValue, fmt.Errorf("invalid notation - missing record UID or Title")
+ }
+
+ matchingRecords := []*Record{}
+ for _, r := range records {
+ if recordToken == r.Uid || recordToken == r.Title() {
+ matchingRecords = append(matchingRecords, r)
+ }
+ }
+
+ if len(matchingRecords) < 1 {
+ return fieldValue, fmt.Errorf("notation error - no records match record '%s'", recordToken)
+ }
+ if len(matchingRecords) > 1 {
+ klog.Warning(fmt.Sprintf("notation warning - multiple records match record '%s'. Notation will inspect only the first record!", recordToken))
+ }
+
+ record := matchingRecords[0]
+
+ selector := "" // type|title|notes or file|field|custom_field
+ if parsedNotation[2].IsPresent && parsedNotation[2].Text != nil {
+ selector = parsedNotation[2].Text.Text
+ }
+ if selector == "" {
+ return fieldValue, fmt.Errorf("invalid notation - missing selector (type|title|notes or file|field|custom_field)")
+ }
+
+ parameter := ""
+ index1 := ""
+ index2 := ""
+ if parsedNotation[2] != nil && parsedNotation[2].IsPresent {
+ if parsedNotation[2].Parameter != nil {
+ parameter = parsedNotation[2].Parameter.Text
+ }
+ if parsedNotation[2].Index1 != nil {
+ index1 = parsedNotation[2].Index1.Text
+ }
+ if parsedNotation[2].Index2 != nil {
+ index2 = parsedNotation[2].Index2.Text
+ }
+ }
+ // legacy compat mode
+ if parsedNotation[2].Index1 == nil && parsedNotation[2].Index2 == nil {
+ index1 = "0" // ex. UID/field/name -> name[0]
+ } else if index2 != "" && (parsedNotation[2].Index1 == nil || parsedNotation[2].Index1.RawText == "[]") {
+ index1 = "0" // ex. UID/field/name[fist] -> name[0][first]
+ }
+
+ var iValue []interface{}
+ switch strings.ToLower(selector) {
+ case "type":
+ return []interface{}{record.Type()}, nil
+ case "title":
+ return []interface{}{record.Title()}, nil
+ case "notes":
+ return []interface{}{record.Notes()}, nil
+ case "file":
+ if parameter == "" {
+ return fieldValue, fmt.Errorf("notation error - missing required parameter: filename or file UID for files in record '%s'", recordToken)
+ }
+ if len(record.Files) < 1 {
+ return fieldValue, fmt.Errorf("notation error - record '%s' has no file attachments", recordToken)
+ }
+
+ files := []*KeeperFile{}
+ for _, f := range record.Files {
+ if parameter == f.Name || parameter == f.Title || parameter == f.Uid {
+ files = append(files, f)
+ }
+ }
+ // file searches do not use indexes and rely on unique file names or fileUid
+ if len(files) > 1 {
+ klog.Warning(fmt.Sprintf("notation warning - record '%s' has multiple files matching the search criteria '%s'. Notation will return only the first file!", recordToken, parameter))
+ }
+ if len(files) < 1 {
+ return fieldValue, fmt.Errorf("notation error - record '%s' has no files matching the search criteria '%s'", recordToken, parameter)
+ }
+ contents := files[0].GetFileData()
+ fieldValue = append(fieldValue, contents)
+ return fieldValue, nil
+ case "field", "custom_field":
+ if parsedNotation[2].Parameter == nil {
+ return fieldValue, fmt.Errorf("notation error - missing required parameter for the field (type or label): ex. /field/type or /custom_field/MyLabel")
+ }
+ fieldSection := FieldSectionCustom
+ if strings.ToLower(selector) == "field" {
+ fieldSection = FieldSectionFields
+ }
+ flds := record.GetFieldsByMask(parameter, FieldTokenBoth, fieldSection)
+ if len(flds) > 1 {
+ klog.Warning(fmt.Sprintf("notation warning - record '%s' has multiple fields matching the search criteria '%s'. Notation will return only the first field!", recordToken, parameter))
+ }
+ if len(flds) < 1 {
+ return fieldValue, fmt.Errorf("notation error - record '%s' has no fields matching the search criteria '%s'", recordToken, parameter)
+ }
+ field := flds[0]
+ iValue, _ = field["value"].([]interface{})
+ // fieldType, _ = field["type"].(string)
+ default:
+ return fieldValue, fmt.Errorf("invalid notation - unexpected selector '%s'", selector)
+ }
+
+ idx, err := strconv.ParseInt(index1, 10, 32)
+ if err != nil || idx < 0 {
+ idx = -1 // full value
+ }
+ // valid only if [] or missing - ex. /field/phone or /field/phone[]
+ if idx == -1 &&
+ !(parsedNotation[2] == nil || parsedNotation[2].Index1 == nil ||
+ parsedNotation[2].Index1.RawText == "" ||
+ parsedNotation[2].Index1.RawText == "[]") {
+ return fieldValue, fmt.Errorf("notation error - Invalid field index '%d'", idx)
+ }
+
+ if idx >= 0 { // return single value (by index)
+ if len(iValue) == 0 {
+ return fieldValue, nil
+ }
+ if len(iValue) > int(idx) {
+ iVal := iValue[idx]
+ retMap, mapOk := iVal.(map[string]interface{})
+ if mapOk && strings.TrimSpace(index2) != "" {
+ if val, ok := retMap[index2]; ok {
+ fieldValue = append(fieldValue, val)
+ } else {
+ return fieldValue, fmt.Errorf("cannot find the dictionary key %s in the value ", index2)
+ }
+ } else {
+ fieldValue = append(fieldValue, iVal)
+ }
+ if len(fieldValue) > 0 {
+ if strValue, ok := fieldValue[0].(string); ok {
+ fieldValue = []interface{}{strValue}
+ } else if mapValue, ok := fieldValue[0].(map[string]interface{}); ok {
+ if v, ok := mapValue["value"].([]interface{}); ok {
+ if len(v) > 0 {
+ fieldValue = []interface{}{fmt.Sprintf("%v", v[0])}
+ } else {
+ fieldValue = []interface{}{""}
+ }
+ }
+ }
+ }
+ } else {
+ return fieldValue, fmt.Errorf("notation error - Field index out of bounds %d >= %d for field %s", idx, len(iValue), parameter)
+ }
+ } else { // return full value
+ fieldValue = iValue
+ }
+
+ return fieldValue, nil
+}
+
+func (c *SecretsManager) FindNotation(records []*Record, notation string) (fieldValue []interface{}, err error) {
+ parsedNotation, err := ParseNotation(notation) // prefix, record, selector, footer
+ if err != nil || len(parsedNotation) < 3 {
+ return []interface{}{}, fmt.Errorf("invalid notation '%s'", notation)
+ }
+
+ return c.extractNotation(records, parsedNotation)
+}
+
+func (c *SecretsManager) GetNotation(notation string) (fieldValue []interface{}, err error) {
+ /*
+ Simple string notation to get a value
+
+ * A system of figures or symbols used in a specialized field to represent numbers, quantities, tones,
+ or values.
+
+ /
+ /file/
+ //[INDEX][PROPERTY]
+ Record title, field label, filename sections need to escape the delimiters /[]\ -> \/ \[ \] \\
+
+
+ Example:
+
+ RECORD_UID/field/password => MyPassword
+ RECORD_UID/field/password[0] => MyPassword
+ RECORD_UID/field/password[] => ["MyPassword"]
+ RECORD_UID/custom_field/name[first] => John
+ RECORD_UID/custom_field/name[last] => Smith
+ RECORD_UID/custom_field/phone[0][number] => "555-5555555"
+ RECORD_UID/custom_field/phone[1][number] => "777-7777777"
+ RECORD_UID/custom_field/phone[] => [{"number": "555-555...}, { "number": "777.....}]
+ RECORD_UID/custom_field/phone[0] => [{"number": "555-555...}]
+ */
+
+ result := []interface{}{}
+ parsedNotation, err := ParseNotationInLegacyMode(notation) // prefix, record, selector, footer
+ if err != nil || len(parsedNotation) < 3 {
+ return result, fmt.Errorf("invalid notation '%s'", notation)
+ }
+
+ recordToken := "" // UID or Title
+ recordTokenIsValid := parsedNotation[1] != nil && parsedNotation[1].IsPresent && parsedNotation[1].Text != nil
+ if recordTokenIsValid {
+ recordToken = parsedNotation[1].Text.Text
+ } else {
+ return result, fmt.Errorf("invalid notation '%s', missing record UID or Title", notation)
+ }
+
+ // to minimize traffic - if it looks like a Record UID try to pull a single record
+ records := []*Record{}
+ if matched, err := regexp.MatchString(`^[A-Za-z0-9_-]{22}$`, recordToken); err == nil && matched {
+ if secrets, err := c.GetSecrets([]string{recordToken}); err != nil {
+ return result, err
+ } else if len(secrets) > 1 {
+ return result, fmt.Errorf("notation error - found multiple records with same UID '%s'", recordToken)
+ } else {
+ records = secrets
+ }
+ }
+
+ // If RecordUID is not found - pull all records and search by title
+ if len(records) < 1 {
+ if secrets, err := c.GetSecrets([]string{}); err != nil {
+ return result, err
+ } else if len(secrets) > 0 {
+ for _, r := range secrets {
+ if recordToken == r.Title() {
+ records = append(records, r)
+ }
+ }
+ }
+ }
+
+ if len(records) > 1 {
+ return result, fmt.Errorf("notation error - multiple records match record '%s'", recordToken)
+ }
+ if len(records) < 1 {
+ return result, fmt.Errorf("notation error - no records match record '%s'", recordToken)
+ }
+
+ return c.extractNotation(records, parsedNotation)
+}
+
+// New notation parser/extractor allows to search by title/label and to escape special chars
+const EscapeChar = '\\'
+const EscapeChars = "/[]\\" // /[]\ -> \/ ,\[, \], \\
+// Escape the characters in plaintext sections only - title, label or filename
+
+type ParserTuple struct {
+ Text string // unescaped text
+ RawText string // raw text incl. delimiter(s), escape characters etc.
+}
+type NotationSection struct {
+ Section string // section name - ex. prefix
+ IsPresent bool // presence flag
+ StartPos int // section start position in URI
+ EndPos int // section end position in URI
+ Text *ParserTuple // text
+ Parameter *ParserTuple // ||
+ Index1 *ParserTuple // numeric index [N] or []
+ Index2 *ParserTuple // property index - ex. field/name[0][middle]
+}
+
+func NewNotationSection(section string) *NotationSection {
+ return &NotationSection{
+ Section: section,
+ IsPresent: false,
+ StartPos: -1,
+ EndPos: -1,
+ Text: nil,
+ Parameter: nil,
+ Index1: nil,
+ Index2: nil,
+ }
+}
+
+func ParseSubsection(text string, pos int, delimiters string, escaped bool) (*ParserTuple, error) {
+ // raw string excludes start delimiter (if '/') but includes end delimiter or both (if '[',']')
+ if text == "" || pos < 0 || pos >= len(text) {
+ return nil, nil
+ }
+ if delimiters == "" || len(delimiters) > 2 {
+ return nil, fmt.Errorf("notation parser: Internal error - Incorrect delimiters count. Delimiters: '%s'", delimiters)
+ }
+ token := ""
+ raw := ""
+ for pos < len(text) {
+ if escaped && EscapeChar == text[pos] {
+ // notation cannot end in single char incomplete escape sequence
+ // and only escape_chars should be escaped
+ if ((pos + 1) >= len(text)) || !strings.Contains(EscapeChars, text[pos+1:pos+2]) {
+ return nil, fmt.Errorf("notation parser: Incorrect escape sequence at position %d", pos)
+ }
+ // copy the properly escaped character
+ token += text[pos+1 : pos+2]
+ raw += text[pos : pos+2]
+ pos += 2
+ } else { // escaped == false || EscapeChar != text[pos]
+ raw += text[pos : pos+1] // delimiter is included in raw text
+ if len(delimiters) == 1 {
+ if text[pos] == delimiters[0] {
+ break
+ } else {
+ token += text[pos : pos+1]
+ }
+ } else { // 2 delimiters
+ if raw[0] != delimiters[0] {
+ return nil, errors.New("notation parser: Index sections must start with '['")
+ }
+ if len(raw) > 1 && text[pos] == delimiters[0] {
+ return nil, errors.New("notation parser: Index sections do not allow extra '[' inside")
+ }
+ if !strings.Contains(delimiters, text[pos:pos+1]) {
+ token += text[pos : pos+1]
+ } else if text[pos] == delimiters[1] {
+ break
+ }
+ }
+ pos++
+ }
+ }
+ // if pos >= len(text) {
+ // pos = len(text) - 1
+ // }
+ if len(delimiters) == 2 && ((len(raw) < 2 || raw[0] != delimiters[0] || raw[len(raw)-1] != delimiters[1]) ||
+ (escaped && raw[len(raw)-2] == EscapeChar)) {
+ return nil, errors.New("notation parser: Index sections must be enclosed in '[' and ']'")
+ }
+ return &ParserTuple{Text: token, RawText: raw}, nil
+}
+
+func ParseSection(notation string, section string, pos int) (*NotationSection, error) {
+ if notation == "" {
+ return nil, errors.New("keeper notation parsing error - missing notation URI")
+ }
+
+ sectionName := strings.ToLower(section)
+ sections := map[string]struct{}{"prefix": {}, "record": {}, "selector": {}, "footer": {}}
+ if _, found := sections[sectionName]; !found {
+ return nil, fmt.Errorf("keeper notation parsing error - unknown section: '%s'", sectionName)
+ }
+
+ result := NewNotationSection(section)
+ result.StartPos = pos
+
+ switch sectionName {
+ case "prefix":
+ // prefix "keeper://" is not mandatory
+ uriPrefix := "keeper://"
+ if strings.HasPrefix(strings.ToLower(notation), uriPrefix) {
+ result.IsPresent = true
+ result.StartPos = 0
+ result.EndPos = len(uriPrefix) - 1
+ result.Text = &ParserTuple{Text: notation[0:len(uriPrefix)], RawText: notation[0:len(uriPrefix)]}
+ }
+ case "footer":
+ // footer should not be present - used only for verification
+ result.IsPresent = (pos < len(notation))
+ if result.IsPresent {
+ result.StartPos = pos
+ result.EndPos = len(notation) - 1
+ result.Text = &ParserTuple{Text: notation[pos:], RawText: notation[pos:]}
+ }
+ case "record":
+ // record is always present - either UID or title
+ result.IsPresent = (pos < len(notation))
+ if result.IsPresent {
+ if parsed, _ := ParseSubsection(notation, pos, "/", true); parsed != nil {
+ result.StartPos = pos
+ result.EndPos = pos + len(parsed.RawText) - 1
+ result.Text = parsed
+ }
+ }
+ case "selector":
+ // selector is always present - type|title|notes | field|custom_field|file
+ result.IsPresent = (pos < len(notation))
+ if result.IsPresent {
+ if parsed, _ := ParseSubsection(notation, pos, "/", false); parsed != nil {
+ result.StartPos = pos
+ result.EndPos = pos + len(parsed.RawText) - 1
+ result.Text = parsed
+
+ // selector.parameter - | |
+ // field/name[0][middle], custom_field/my label[0][middle], file/my file[0]
+ longSelectors := map[string]struct{}{"field": {}, "custom_field": {}, "file": {}}
+ if _, found := longSelectors[strings.ToLower(parsed.Text)]; found {
+ // TODO: File metadata extraction: ex. filename[1][size] - that requires filename to be escaped
+ if parsed, _ = ParseSubsection(notation, result.EndPos+1, "[", true); parsed != nil {
+ result.Parameter = parsed // | |
+ plen := len(parsed.RawText)
+ if strings.HasSuffix(parsed.RawText, "[") && !strings.HasSuffix(parsed.RawText, "\\[") {
+ plen--
+ }
+ result.EndPos += plen
+ if parsed, _ = ParseSubsection(notation, result.EndPos+1, "[]", true); parsed != nil {
+ result.Index1 = parsed // selector.index1 [int] or []
+ result.EndPos += len(parsed.RawText)
+ if parsed, _ = ParseSubsection(notation, result.EndPos+1, "[]", true); parsed != nil {
+ result.Index2 = parsed // selector.index2 [str]
+ result.EndPos += len(parsed.RawText)
+ }
+ }
+ }
+ }
+ }
+ }
+ default:
+ return nil, fmt.Errorf("keeper notation parsing error - unknown section: %s", sectionName)
+ }
+ return result, nil
+}
+
+func ParseNotation(notation string) ([]*NotationSection, error) {
+ return parseNotationImpl(notation, false)
+}
+
+func ParseNotationInLegacyMode(notation string) ([]*NotationSection, error) {
+ return parseNotationImpl(notation, true)
+}
+
+func parseNotationImpl(notation string, legacyMode bool) ([]*NotationSection, error) {
+ if notation == "" {
+ return nil, errors.New("keeper notation is missing or invalid")
+ }
+
+ // Notation is either plaintext keeper URI format or URL safe base64 string (UTF8)
+ // auto detect format - '/' is not part of base64 URL safe alphabet
+ if strings.Contains(notation, "/") {
+ if decodedStr := Base64ToStringSafe(notation); len(decodedStr) > 0 {
+ notation = decodedStr
+ }
+ }
+
+ pos := 0
+ // prefix is optional
+ prefix, _ := ParseSection(notation, "prefix", 0) // keeper://
+ if prefix.IsPresent {
+ pos = prefix.EndPos + 1
+ }
+
+ // record is required
+ record, _ := ParseSection(notation, "record", pos) // or
+ if record.IsPresent {
+ pos = record.EndPos + 1
+ } else {
+ pos = len(notation)
+ }
+
+ // selector is required, indexes are optional
+ selector, _ := ParseSection(notation, "selector", pos) // type|title|notes | field|custom_field|file
+ if selector.IsPresent {
+ pos = selector.EndPos + 1
+ } else {
+ pos = len(notation)
+ }
+
+ footer, _ := ParseSection(notation, "footer", pos) // Any text after the last section
+
+ // verify parsed query
+ // prefix is optional, record UID/Title and selector are mandatory
+ shortSelectors := map[string]struct{}{"type": {}, "title": {}, "notes": {}}
+ fullSelectors := map[string]struct{}{"field": {}, "custom_field": {}, "file": {}}
+ selectors := map[string]struct{}{"type": {}, "title": {}, "notes": {}, "field": {}, "custom_field": {}, "file": {}}
+ if !record.IsPresent || !selector.IsPresent {
+ return nil, errors.New("keeper notation URI missing information about the uid, file, field type, or field key")
+ }
+ if footer.IsPresent {
+ return nil, errors.New("keeper notation is invalid - extra characters after last section")
+ }
+ selectorText := ""
+ if selector.IsPresent && selector.Text != nil {
+ selectorText = strings.ToLower(selector.Text.Text)
+ }
+ if _, found := selectors[selectorText]; !found {
+ return nil, errors.New("keeper notation is invalid - bad selector, must be one of (type, title, notes, field, custom_field, file)")
+ }
+ if _, found := shortSelectors[selectorText]; found && selector.Parameter != nil {
+ return nil, errors.New("keeper notation is invalid - selectors (type, title, notes) do not have parameters")
+ }
+ if _, found := fullSelectors[selectorText]; found {
+ if !selector.IsPresent || selector.Parameter == nil {
+ return nil, errors.New("keeper notation is invalid - selectors (field, custom_field, file) require parameters")
+ }
+ if selectorText == "file" && (selector.Index1 != nil || selector.Index2 != nil) {
+ return nil, errors.New("keeper notation is invalid - file selectors don't accept indexes")
+ }
+ if selectorText != "file" && selector.Index1 == nil && selector.Index2 != nil {
+ return nil, errors.New("keeper notation is invalid - two indexes required")
+ }
+ if selector.Index1 != nil {
+ if matched, err := regexp.MatchString(`^\[\d*\]$`, selector.Index1.RawText); err != nil || !matched {
+ if !legacyMode {
+ return nil, errors.New("keeper notation is invalid - first index must be numeric: [n] or []")
+ }
+ // in legacy mode convert /name[middle] to name[][middle]
+ if selector.Index2 == nil {
+ selector.Index2 = selector.Index1
+ selector.Index1 = &ParserTuple{Text: "", RawText: "[]"}
+ }
+ }
+ }
+ }
+
+ return []*NotationSection{prefix, record, selector, footer}, nil
+}
+
+// TryGetNotationResults returns a string list with all values specified by the notation or empty list on error.
+// It simply logs any errors and continue returning an empty string list on error.
+func (c *SecretsManager) TryGetNotationResults(notation string) []string {
+ if res, err := c.GetNotationResults(notation); err == nil {
+ return res
+ }
+ return []string{}
+}
+
+// Notation:
+// keeper:///
+// keeper:///file/
+// keeper:////[INDEX][PROPERTY]
+// Record title, field label, filename sections need to escape the delimiters /[]\ -> \/ \[ \] \\
+// The prefix "keeper://" is optional
+//
+// GetNotationResults returns selection of the value(s) from a single field as a string list.
+// Multiple records or multiple fields found results in error.
+// Use record UID or unique record titles and field labels so that notation finds a single record/field.
+//
+// If field has multiple values use indexes - numeric INDEX specifies the position in the value list
+// and PROPERTY specifies a single JSON object property to extract (see examples below for usage)
+// If no indexes are provided - whole value list is returned (same as [])
+// If PROPERTY is provided then INDEX must be provided too - even if it's empty [] which means all
+//
+// Extracting two or more but not all field values simultaneously is not supported - use multiple notation requests.
+//
+// Files are returned as URL safe base64 encoded string of the binary content
+//
+// Note: Integrations and plugins usually return single string value - result[0] or ""
+//
+// Examples:
+// RECORD_UID/file/filename.ext => ["URL Safe Base64 encoded binary content"]
+// RECORD_UID/field/url => ["127.0.0.1", "127.0.0.2"] or [] if empty
+// RECORD_UID/field/url[] => ["127.0.0.1", "127.0.0.2"] or [] if empty
+// RECORD_UID/field/url[0] => ["127.0.0.1"] or error if empty
+// RECORD_UID/custom_field/name[first] => Error, numeric index is required to access field property
+// RECORD_UID/custom_field/name[][last] => ["Smith", "Johnson"]
+// RECORD_UID/custom_field/name[0][last] => ["Smith"]
+// RECORD_UID/custom_field/phone[0][number] => "555-5555555"
+// RECORD_UID/custom_field/phone[1][number] => "777-7777777"
+// RECORD_UID/custom_field/phone[] => ["{\"number\": \"555-555...\"}", "{\"number\": \"777...\"}"]
+// RECORD_UID/custom_field/phone[0] => ["{\"number\": \"555-555...\"}"]
+
+// GetNotationResults returns a string list with all values specified by the notation or throws an error.
+// Use TryGetNotationResults to just log errors and continue returning an empty string list on error.
+func (c *SecretsManager) GetNotationResults(notation string) ([]string, error) {
+ result := []string{}
+
+ parsedNotation, err := ParseNotation(notation) // prefix, record, selector, footer
+ if err != nil || len(parsedNotation) < 3 {
+ return nil, fmt.Errorf("invalid notation '%s'", notation)
+ }
+
+ selector := "" // type|title|notes or file|field|custom_field
+ if parsedNotation[2].IsPresent && parsedNotation[2].Text != nil {
+ selector = parsedNotation[2].Text.Text
+ }
+ if selector == "" {
+ return nil, fmt.Errorf("invalid notation '%s'", notation)
+ }
+
+ recordToken := "" // UID or Title
+ recordTokenIsValid := parsedNotation[1] != nil && parsedNotation[1].IsPresent && parsedNotation[1].Text != nil
+ if recordTokenIsValid {
+ recordToken = parsedNotation[1].Text.Text
+ } else {
+ return nil, fmt.Errorf("invalid notation '%s'", notation)
+ }
+
+ // to minimize traffic - if it looks like a Record UID try to pull a single record
+ records := []*Record{}
+ if matched, err := regexp.MatchString(`^[A-Za-z0-9_-]{22}$`, recordToken); err == nil && matched {
+ if secrets, err := c.GetSecrets([]string{recordToken}); err != nil {
+ return nil, err
+ } else if len(secrets) > 1 {
+ return nil, fmt.Errorf("notation error - found multiple records with same UID '%s'", recordToken)
+ } else {
+ records = secrets
+ }
+ }
+
+ // If RecordUID is not found - pull all records and search by title
+ if len(records) < 1 {
+ if secrets, err := c.GetSecrets([]string{}); err != nil {
+ return nil, err
+ } else if len(secrets) > 0 {
+ for _, r := range secrets {
+ if recordToken == r.Title() {
+ records = append(records, r)
+ }
+ }
+ }
+ }
+
+ if len(records) > 1 {
+ return nil, fmt.Errorf("notation error - multiple records match record '%s'", recordToken)
+ }
+ if len(records) < 1 {
+ return nil, fmt.Errorf("notation error - no records match record '%s'", recordToken)
+ }
+
+ record := records[0]
+ parameter := ""
+ index1 := ""
+ index2 := ""
+ if parsedNotation[2] != nil && parsedNotation[2].IsPresent {
+ if parsedNotation[2].Parameter != nil {
+ parameter = parsedNotation[2].Parameter.Text
+ }
+ if parsedNotation[2].Index1 != nil {
+ index1 = parsedNotation[2].Index1.Text
+ }
+ if parsedNotation[2].Index2 != nil {
+ index2 = parsedNotation[2].Index2.Text
+ }
+ }
+
+ switch strings.ToLower(selector) {
+ case "type":
+ result = append(result, record.Type())
+ case "title":
+ result = append(result, record.Title())
+ case "notes":
+ result = append(result, record.Notes())
+ case "file":
+ if parameter == "" {
+ return nil, fmt.Errorf("notation error - missing required parameter: filename or file UID for files in record '%s'", recordToken)
+ }
+ if len(record.Files) < 1 {
+ return nil, fmt.Errorf("notation error - record '%s' has no file attachments", recordToken)
+ }
+
+ files := []*KeeperFile{}
+ for _, f := range record.Files {
+ if parameter == f.Name || parameter == f.Title || parameter == f.Uid {
+ files = append(files, f)
+ }
+ }
+ // file searches do not use indexes and rely on unique file names or fileUid
+ if len(files) > 1 {
+ return nil, fmt.Errorf("notation error - record '%s' has multiple files matching the search criteria '%s'", recordToken, parameter)
+ }
+ if len(files) < 1 {
+ return nil, fmt.Errorf("notation error - record '%s' has no files matching the search criteria '%s'", recordToken, parameter)
+ }
+ contents := files[0].GetFileData()
+ text := BytesToUrlSafeStr(contents)
+ result = append(result, text)
+ case "field", "custom_field":
+ if parsedNotation[2].Parameter == nil {
+ return nil, fmt.Errorf("notation error - missing required parameter for the field (type or label): ex. /field/type or /custom_field/MyLabel")
+ }
+ fieldSection := FieldSectionCustom
+ if strings.ToLower(selector) == "field" {
+ fieldSection = FieldSectionFields
+ }
+ flds := record.GetFieldsByMask(parameter, FieldTokenBoth, fieldSection)
+ if len(flds) > 1 {
+ return nil, fmt.Errorf("notation error - record '%s' has multiple fields matching the search criteria '%s'", recordToken, parameter)
+ }
+ if len(flds) < 1 {
+ return nil, fmt.Errorf("notation error - record '%s' has no fields matching the search criteria '%s'", recordToken, parameter)
+ }
+
+ field := flds[0]
+ idx, err := strconv.ParseInt(index1, 10, 32)
+ if err != nil || idx < 0 {
+ idx = -1 // full value
+ }
+ // valid only if [] or missing - ex. /field/phone or /field/phone[]
+ if idx == -1 &&
+ !(parsedNotation[2] == nil || parsedNotation[2].Index1 == nil ||
+ parsedNotation[2].Index1.RawText == "" ||
+ parsedNotation[2].Index1.RawText == "[]") {
+ return nil, fmt.Errorf("notation error - Invalid field index '%d'", idx)
+ }
+ values := getRawFieldValue(field)
+ if values == nil {
+ values = []interface{}{}
+ }
+ if idx >= int64(len(values)) {
+ return nil, fmt.Errorf("notation error - Field index out of bounds %d >= %d for field %s", idx, len(values), parameter)
+ }
+ if idx >= 0 { // single index
+ values = values[idx : idx+1]
+ }
+
+ fullObjValue := parsedNotation[2] == nil || parsedNotation[2].Index2 == nil ||
+ parsedNotation[2].Index2.RawText == "" || parsedNotation[2].Index2.RawText == "[]"
+ objPropertyName := index2
+
+ res := []string{}
+ for _, fldValue := range values {
+ // Do not throw here to allow for ex. field/name[][middle] to pull [middle] only where present
+ // NB! Not all properties of a value are always required even when the field is marked as required
+ // ex. On a required `name` field only "first" and "last" properties are required but not "middle"
+ // so missing property in a field value is not always an error
+ if fldValue == nil {
+ klog.Error("notation error - Empty field value for field " + parameter) // throw?
+ }
+
+ if fullObjValue {
+ val := ""
+ if strValue, ok := fldValue.(string); ok {
+ val = strValue
+ } else {
+ if jsonStr, err := json.Marshal(fldValue); err == nil {
+ val = string(jsonStr)
+ } else {
+ klog.Error(fmt.Sprintf("notation error - Error converting field value to JSON %v", fldValue))
+ }
+ }
+ res = append(res, val)
+ } else if fldValue != nil {
+ if objMap, ok := fldValue.(map[string]interface{}); ok {
+ if jvalue, found := objMap[objPropertyName]; found {
+ val := ""
+ if strValue, ok := jvalue.(string); ok {
+ val = strValue
+ } else {
+ if jsonStr, err := json.Marshal(jvalue); err == nil {
+ val = string(jsonStr)
+ } else {
+ klog.Error(fmt.Sprintf("notation error - Error converting field value to JSON %v", jvalue))
+ }
+ }
+ res = append(res, val)
+ } else {
+ klog.Error(fmt.Sprintf("notation error - value object has no property '%s'", objPropertyName)) // skip
+ }
+ }
+ } else {
+ klog.Error(fmt.Sprintf("notation error - Cannot extract property '%s' from null value", objPropertyName))
+ }
+ }
+ if len(res) != len(values) {
+ klog.Error(fmt.Sprintf("notation warning - extracted %d out of %d values for '%s' property", len(res), len(values), objPropertyName))
+ }
+ if len(res) > 0 {
+ result = append(result, res...)
+ }
+ default:
+ return nil, fmt.Errorf("invalid notation '%s'", notation)
+ }
+
+ return result, nil
+}
+
+// getRawFieldValue returns the field's value[] slice
+// or nil if "value" key is not in the map or not an array
+func getRawFieldValue(field map[string]interface{}) []interface{} {
+ if v, found := field["value"]; found {
+ if value, ok := v.([]interface{}); ok {
+ return value
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/crypto.go b/vendor/github.com/keeper-security/secrets-manager-go/core/crypto.go
new file mode 100644
index 00000000..5a376092
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/crypto.go
@@ -0,0 +1,475 @@
+package core
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha256"
+ "crypto/subtle"
+ "crypto/x509"
+ "encoding/asn1"
+ "encoding/hex"
+ "errors"
+ "io"
+ "math/big"
+ "strings"
+)
+
+const (
+ Aes256KeySize = 32
+ AesGcmNonceSize = 12
+ AesCbcNonceSize = 16
+ DefaultBlockSize = 16
+)
+
+type PublicKey ecdsa.PublicKey
+type PrivateKey ecdsa.PrivateKey
+
+func PadBinary(s []byte) []byte {
+ return pkcs7Pad(s)
+}
+
+func UnpadBinary(s []byte) []byte {
+ return pkcs7Unpad(s)
+}
+
+// Bytes concatenates public key x and y values
+func (pub *PublicKey) Bytes() (buf []byte) {
+ x := pub.X.Bytes()
+ y := pub.Y.Bytes()
+ buf = append(x, y...)
+ return
+}
+
+// SetBytes decodes buf and stores the values in pub X and Y
+func (pub *PublicKey) SetBytes(buf []byte) *PublicKey {
+ bigX := new(big.Int)
+ bigY := new(big.Int)
+ bigX.SetBytes(buf[:32])
+ bigY.SetBytes(buf[32:64])
+
+ pub.X = bigX
+ pub.Y = bigY
+ pub.Curve = elliptic.P256()
+ return pub
+}
+
+// Check if public key is valid for the curve
+func (pub *PublicKey) Check(curve elliptic.Curve) bool {
+ if pub.Curve != curve {
+ return false
+ }
+ if !curve.IsOnCurve(pub.X, pub.Y) {
+ return false
+ }
+ return true
+}
+
+// Bytes returns private key D value
+func (priv *PrivateKey) Bytes() []byte {
+ return priv.D.Bytes()
+}
+
+// SetBytes reconstructs the private key from D bytes
+func (priv *PrivateKey) SetBytes(d []byte) *PrivateKey {
+ bigD := new(big.Int)
+ bigD.SetBytes(d)
+ priv.D = bigD
+ priv.Curve = elliptic.P256()
+ if priv.PublicKey.X == nil {
+ priv.PublicKey.Curve = elliptic.P256()
+ priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(priv.D.Bytes())
+ }
+ return priv
+}
+
+// GetPublicKey returns the associated PublicKey for this privatekey,
+// If the key is missing then one is generated.
+func (priv *PrivateKey) GetPublicKey() *PublicKey {
+ if priv.PublicKey.X == nil {
+ priv.PublicKey.Curve = elliptic.P256()
+ priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(priv.D.Bytes())
+ }
+ return (*PublicKey)(&priv.PublicKey)
+ //return PublicKey(priv.PublicKey)
+}
+
+// Hex returns private key bytes as a hex string
+func (priv *PrivateKey) Hex() string {
+ return hex.EncodeToString(priv.Bytes())
+}
+
+// Equals compares two private keys with constant time (to resist timing attacks)
+func (priv *PrivateKey) Equals(k *PrivateKey) bool {
+ return subtle.ConstantTimeCompare(priv.D.Bytes(), k.D.Bytes()) == 1
+}
+
+// Sign signs digest with priv, reading randomness from rand.
+//
+// The opts argument is not currently used but, in keeping with the crypto.Signer interface,
+// should be the hash function used to digest the message.
+func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
+ return (*ecdsa.PrivateKey)(priv).Sign(rand, digest, opts)
+}
+
+func GenerateP256Keys() (PrivateKey, error) {
+ return GenerateKeys(elliptic.P256()) // golang suppors only SECP256R1
+}
+
+func GenerateKeys(curve elliptic.Curve) (PrivateKey, error) {
+ k, err := ecdsa.GenerateKey(curve, rand.Reader)
+ return PrivateKey(*k), err
+}
+
+func GeneratePrivateKeyEcc() (PrivateKey, error) {
+ return GenerateP256Keys()
+}
+
+func GeneratePrivateKeyDer() ([]byte, error) {
+ privateKey, err := GeneratePrivateKeyEcc()
+ if err != nil {
+ return []byte{}, err
+ }
+ // Export to DER - PKCS #8 ASN.1 DER form with NoEncryption
+ if privateKeyDer, err := x509.MarshalPKCS8PrivateKey((*ecdsa.PrivateKey)(&privateKey)); err != nil {
+ return []byte{}, err
+ } else {
+ return privateKeyDer, nil
+ }
+}
+
+func GenerateNewEccKey() (PrivateKey, error) {
+ return GenerateP256Keys()
+}
+
+func EcPublicKeyFromEncodedPoint(publicKey []byte) (crypto.PublicKey, error) {
+ // see https://tools.ietf.org/html/rfc6637#section-6
+ if x, y := elliptic.Unmarshal(elliptic.P256(), publicKey); x != nil {
+ return PublicKey{Curve: elliptic.P256(), X: x, Y: y}, nil
+ } else {
+ return PublicKey{}, errors.New("bad ECC public key")
+ }
+}
+
+func EcPublicKeyToEncodedPoint(pub *ecdsa.PublicKey) ([]byte, error) {
+ // see https://tools.ietf.org/html/rfc6637#section-6
+ if pub.Curve != elliptic.P256() {
+ return nil, errors.New("unsupported ECC curve type")
+ }
+ return elliptic.Marshal(pub.Curve, pub.X, pub.Y), nil
+}
+
+// Encrypt a message using AES-GCM.
+func EncryptAesGcm(data []byte, key []byte) ([]byte, error) {
+ return EncryptAesGcmFull(data, key, nil)
+}
+
+// Encrypt a message using AES-GCM with custom nonce.
+func EncryptAesGcmFull(data, key, nonce []byte) ([]byte, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ gcm, err := cipher.NewGCM(c)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(nonce) == 0 {
+ nonce, err = GetRandomBytes(AesGcmNonceSize)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if len(nonce) != AesGcmNonceSize {
+ return nil, errors.New("incorrect nonce size")
+ }
+
+ result := gcm.Seal(nonce, nonce, data, nil)
+ return result, nil
+}
+
+// Decrypt AES-GCM encrypted message
+func Decrypt(data, key []byte) ([]byte, error) {
+ if len(data) <= AesGcmNonceSize {
+ return nil, errors.New("error decrypting AES-GCM - message is too short")
+ }
+
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ gcm, err := cipher.NewGCM(c)
+ if err != nil {
+ return nil, err
+ }
+
+ nonce := make([]byte, AesGcmNonceSize)
+ copy(nonce, data)
+
+ result, err := gcm.Open(nil, nonce, data[AesGcmNonceSize:], nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
+
+// Encrypt a message using AES-CBC.
+func EncryptAesCbc(data []byte, key []byte) ([]byte, error) {
+ return EncryptAesCbcFull(data, key, nil)
+}
+
+// Encrypt a message using AES-CBC with custom nonce.
+func EncryptAesCbcFull(data, key, nonce []byte) ([]byte, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(nonce) == 0 {
+ nonce, err = GetRandomBytes(AesCbcNonceSize)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if len(nonce) != AesCbcNonceSize {
+ return nil, errors.New("incorrect nonce size")
+ }
+
+ cbc := cipher.NewCBCEncrypter(c, nonce)
+ data = pkcs7Pad(data)
+ encrypted := make([]byte, len(data))
+ cbc.CryptBlocks(encrypted, data)
+
+ result := append(nonce, encrypted...)
+ return result, nil
+}
+
+// Decrypt AES-CBC encrypted message
+func DecryptAesCbc(data, key []byte) ([]byte, error) {
+ if len(data) <= AesCbcNonceSize {
+ return nil, errors.New("error decrypting AES-CBC - message is too short")
+ }
+
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ nonce := make([]byte, AesCbcNonceSize)
+ copy(nonce, data)
+ cbc := cipher.NewCBCDecrypter(c, nonce)
+
+ data = data[AesCbcNonceSize:]
+ decrypted := make([]byte, len(data))
+ cbc.CryptBlocks(decrypted, data)
+
+ result := pkcs7Unpad(decrypted)
+ return result, nil
+}
+
+func PublicEncrypt(data []byte, serverPublicRawKeyBytes []byte, idz []byte) (encrypted []byte, err error) {
+ ephemeralKey2, err := GenerateNewEccKey()
+ if err != nil {
+ return nil, err
+ }
+ ephemeralKey2PublicKey := (*ecdsa.PublicKey)(ephemeralKey2.GetPublicKey())
+
+ ephemeralPublicKey, err := EcPublicKeyFromEncodedPoint(serverPublicRawKeyBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ epk, ok := ephemeralPublicKey.(PublicKey)
+ if !ok {
+ return nil, errors.New("bad format for ECC public key")
+ }
+
+ sharedKey, err := ECDH(ephemeralKey2, epk)
+ if err != nil {
+ return nil, err
+ }
+
+ encryptedData, err := EncryptAesGcm(data, sharedKey)
+ if err != nil {
+ return nil, err
+ }
+
+ ephPublicKey, err := EcPublicKeyToEncodedPoint(ephemeralKey2PublicKey)
+ if err != nil {
+ return nil, err
+ }
+ encrypted = append(ephPublicKey, encryptedData...)
+
+ return encrypted, nil
+}
+
+func DecryptRecord(data, secretKey []byte) (string, error) {
+ if record, err := Decrypt(data, secretKey); err == nil {
+ recordJson := BytesToString(record)
+ return recordJson, nil
+ } else {
+ return "", err
+ }
+}
+
+func LoadDerPrivateKeyDer(data []byte) (*PrivateKey, error) {
+ if len(data) < 1 {
+ return nil, errors.New("private key data is empty")
+ }
+ // Import private key - PKCS #8 ASN.1 DER form with NoEncryption
+ if key, err := x509.ParsePKCS8PrivateKey(data); err == nil {
+ switch k := key.(type) {
+ case *ecdsa.PrivateKey:
+ return (*PrivateKey)(k), nil
+ case *rsa.PrivateKey:
+ return nil, errors.New("private key is in an unsupported format: RSA Private Key")
+ case ed25519.PrivateKey:
+ return nil, errors.New("private key is in an unsupported format: Ed25519 Private Key")
+ default:
+ return nil, errors.New("private key is in an unsupported format")
+ }
+ } else {
+ return nil, errors.New("private key data parsing error: " + err.Error())
+ }
+}
+
+func DerBase64PrivateKeyToPrivateKey(privateKeyDerBase64 string) (*PrivateKey, error) {
+ if strings.TrimSpace(privateKeyDerBase64) != "" {
+ privateKeyDerBase64Bytes := Base64ToBytes(privateKeyDerBase64)
+ return LoadDerPrivateKeyDer(privateKeyDerBase64Bytes)
+ }
+ return nil, errors.New("private key data is empty")
+}
+
+func extractPublicKeyBytes(privateKeyDerBase64 interface{}) ([]byte, error) {
+ pkDerBase64 := ""
+ switch v := privateKeyDerBase64.(type) {
+ case string:
+ pkDerBase64 = v
+ case []byte:
+ pkDerBase64 = BytesToBase64(v)
+ default:
+ return nil, errors.New("extracting public key DER bytes failed - PK must be string or byte slice")
+ }
+
+ if ecPrivateKey, err := DerBase64PrivateKeyToPrivateKey(pkDerBase64); err == nil {
+ pubKey := ecPrivateKey.GetPublicKey()
+ if pubKeyBytes, err := EcPublicKeyToEncodedPoint((*ecdsa.PublicKey)(pubKey)); err == nil {
+ return pubKeyBytes, nil
+ } else {
+ return nil, errors.New("error extracting public key from DER: " + err.Error())
+ }
+ } else {
+ return nil, errors.New("error extracting private key from DER: " + err.Error())
+ }
+}
+
+func Sign(data []byte, privateKey *PrivateKey) ([]byte, error) {
+ msgHash := sha256.Sum256(data)
+ r, s, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(privateKey), msgHash[:])
+ if err != nil {
+ return []byte{}, errors.New("signature generation failed: " + err.Error())
+ }
+ ecdsaSig := ECDSASignature{R: r, S: s}
+ if signature, err := asn1.Marshal(ecdsaSig); err == nil {
+ return signature, nil
+ } else {
+ return []byte{}, errors.New("signature serialization failed: " + err.Error())
+ }
+}
+
+// Verify validates decrypted message against the given public key.
+// On success, returns nil, on failure returns a relevant error.
+func Verify(data []byte, signature []byte, publicKey *PublicKey) error {
+ sig := &ECDSASignature{}
+ _, err := asn1.Unmarshal(signature, sig)
+ if err != nil {
+ return err
+ }
+ h := sha256.Sum256(data)
+ valid := ecdsa.Verify(
+ (*ecdsa.PublicKey)(publicKey),
+ h[:],
+ sig.R,
+ sig.S,
+ )
+ if !valid {
+ return errors.New("signature validation failed")
+ }
+ // signature is valid
+ return nil
+}
+
+// ErrKeyExchange is returned if the key exchange fails.
+var ErrKeyExchange = errors.New("key exchange failed")
+
+// ECDH computes a shared key from a private key and a peer's public key.
+func ECDH(priv PrivateKey, pub PublicKey) ([]byte, error) {
+ privKey := (*ecdsa.PrivateKey)(&priv)
+ pubKey := (*ecdsa.PublicKey)(&pub)
+ return ECDH_Ecdsa(privKey, pubKey)
+}
+
+// ECDH computes a shared key from a private key and a peer's public key.
+func ECDH_Ecdsa(priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey) ([]byte, error) {
+ if pub == nil || priv == nil {
+ return nil, ErrKeyExchange
+ } else if priv.Curve != pub.Curve {
+ return nil, ErrKeyExchange
+ } else if !priv.Curve.IsOnCurve(pub.X, pub.Y) {
+ return nil, ErrKeyExchange
+ }
+
+ x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes())
+ if x == nil {
+ return nil, ErrKeyExchange
+ }
+
+ // x.Bytes() may return less than 32 bytes - pad with leading 0
+ buf := x.Bytes()
+ if len(buf) < 32 {
+ buf = x.FillBytes(make([]byte, 32))
+ }
+ shared := sha256.Sum256(buf)
+ return shared[:Aes256KeySize], nil
+}
+
+func pkcs7Pad(data []byte) []byte {
+ // With PKCS#7, we’re always going to pad,
+ // so if our block length was 16, and our plaintext length was 16,
+ // then it would be padded with 16 bytes of 16 at the end.
+ n := DefaultBlockSize - (len(data) % DefaultBlockSize)
+ pb := make([]byte, len(data)+n)
+ copy(pb, data)
+ copy(pb[len(data):], bytes.Repeat([]byte{byte(n)}, n))
+ return pb
+}
+
+func pkcs7Unpad(data []byte) []byte {
+ if len(data) > 0 && len(data)%DefaultBlockSize == 0 {
+ c := data[len(data)-1]
+ if n := int(c); n > 0 && n <= DefaultBlockSize {
+ ok := true
+ for i := 0; i < n; i++ {
+ if data[len(data)-n+i] != c {
+ ok = false
+ break
+ }
+ }
+ if ok {
+ return data[:len(data)-n]
+ }
+ }
+ }
+ return data
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/dtos.go b/vendor/github.com/keeper-security/secrets-manager-go/core/dtos.go
new file mode 100644
index 00000000..4a712700
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/dtos.go
@@ -0,0 +1,1685 @@
+package core
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "strings"
+ "time"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+type FieldSectionFlag byte
+
+const (
+ FieldSectionFields FieldSectionFlag = 1 << iota
+ FieldSectionCustom
+ FieldSectionBoth = FieldSectionFields | FieldSectionCustom
+)
+
+type FieldTokenFlag byte
+
+const (
+ FieldTokenType FieldTokenFlag = 1 << iota
+ FieldTokenLabel
+ FieldTokenBoth = FieldTokenType | FieldTokenLabel
+)
+
+type Record struct {
+ RecordKeyBytes []byte
+ Uid string
+ folderKeyBytes []byte
+ folderUid string
+ innerFolderUid string
+ Files []*KeeperFile
+ Revision int64
+ IsEditable bool
+ recordType string
+ RawJson string
+ RecordDict map[string]interface{}
+}
+
+func (r *Record) FolderUid() string {
+ return r.folderUid
+}
+
+func (r *Record) InnerFolderUid() string {
+ return r.innerFolderUid
+}
+
+func (r *Record) Password() string {
+ password := ""
+ // password (if `login` type)
+ if r.Type() == "login" {
+ password = r.GetFieldValueByType("password")
+ }
+ return password
+}
+
+func (r *Record) SetPassword(password string) {
+ if passwordFields := r.GetFieldsByType("password"); len(passwordFields) > 0 {
+ passwordField := passwordFields[0]
+ if vlist, ok := passwordField["value"].([]interface{}); ok && len(vlist) > 0 {
+ if _, ok := vlist[0].(string); ok {
+ vlist[0] = password
+ } else {
+ klog.Error("error changing password - expected string value")
+ }
+ } else {
+ passwordField["value"] = []string{password}
+ }
+ r.update()
+ } else {
+ klog.Error("password field not found for UID: " + r.Uid)
+ }
+}
+
+func (r *Record) SetFieldValueSingle(fieldType, value string) {
+ if fields := r.GetFieldsByType(fieldType); len(fields) > 0 {
+ field := fields[0]
+ if vlist, ok := field["value"].([]interface{}); ok && len(vlist) > 0 {
+ if _, ok := vlist[0].(string); ok {
+ vlist[0] = value
+ } else {
+ klog.Error("error changing field value - expected string value")
+ }
+ } else {
+ field["value"] = []string{value}
+ }
+ r.update()
+ } else {
+ klog.Error("field not found for UID: " + r.Uid)
+ }
+}
+
+func (r *Record) SetCustomFieldValueSingle(fieldLabel, value string) {
+ if fields := r.GetCustomFieldsByLabel(fieldLabel); len(fields) > 0 {
+ field := fields[0]
+ if vlist, ok := field["value"].([]interface{}); ok && len(vlist) > 0 {
+ if _, ok := vlist[0].(string); ok {
+ vlist[0] = value
+ } else {
+ klog.Error("error changing custom field value - expected string value")
+ }
+ } else {
+ field["value"] = []string{value}
+ }
+ r.update()
+ } else {
+ klog.Error("custom field not found for UID: " + r.Uid)
+ }
+}
+
+func (r *Record) Title() string {
+ if recordTitle, ok := r.RecordDict["title"].(string); ok {
+ return recordTitle
+ }
+ return ""
+}
+
+func (r *Record) SetTitle(title string) {
+ if _, ok := r.RecordDict["title"]; ok {
+ r.RecordDict["title"] = title
+ r.update()
+ }
+}
+
+func (r *Record) Type() string {
+ if recordType, ok := r.RecordDict["type"].(string); ok {
+ return recordType
+ }
+ return ""
+}
+
+func (r *Record) SetType(newType string) {
+ klog.Error("Changing record type is not allowed!") // not implemented
+}
+
+func (r *Record) Notes() string {
+ if recordNotes, ok := r.RecordDict["notes"].(string); ok {
+ return recordNotes
+ }
+ return ""
+}
+
+func (r *Record) SetNotes(notes string) {
+ if _, ok := r.RecordDict["notes"]; ok {
+ r.RecordDict["notes"] = notes
+ r.update()
+ }
+}
+
+func (r *Record) GetFieldsBySection(fieldSectionType FieldSectionFlag) []interface{} {
+ fields := []interface{}{}
+ if fieldSectionType&FieldSectionFields == FieldSectionFields {
+ if iFields, ok := r.RecordDict["fields"]; ok {
+ if aFields, ok := iFields.([]interface{}); ok {
+ fields = append(fields, aFields...)
+ }
+ }
+ }
+
+ if fieldSectionType&FieldSectionCustom == FieldSectionCustom {
+ if iFields, ok := r.RecordDict["custom"]; ok {
+ if aFields, ok := iFields.([]interface{}); ok {
+ fields = append(fields, aFields...)
+ }
+ }
+ }
+ return fields
+}
+
+// GetFieldsByMask returns all fields from the corresponding field section (fields, custom or both)
+// where fieldToken matches the FieldTokenFlag (type, label or both)
+func (r *Record) GetFieldsByMask(fieldToken string, fieldTokenFlag FieldTokenFlag, fieldType FieldSectionFlag) []map[string]interface{} {
+ result := []map[string]interface{}{}
+
+ fields := r.GetFieldsBySection(fieldType)
+
+ for i := range fields {
+ if fmap, ok := fields[i].(map[string]interface{}); ok {
+ val := map[string]interface{}{}
+ if fieldTokenFlag&FieldTokenType == FieldTokenType {
+ if fType, ok := fmap["type"].(string); ok && fType == fieldToken {
+ val = fmap
+ }
+ }
+ if len(val) == 0 && fieldTokenFlag&FieldTokenLabel == FieldTokenLabel {
+ if fLabel, ok := fmap["label"].(string); ok && fLabel == fieldToken {
+ val = fmap
+ }
+ }
+ if len(val) > 0 {
+ result = append(result, val)
+ }
+ }
+ }
+
+ return result
+}
+
+func (r *Record) GetFieldsByType(fieldType string) []map[string]interface{} {
+ return r.GetFieldsByMask(fieldType, FieldTokenType, FieldSectionFields)
+}
+
+func (r *Record) GetFieldsByLabel(fieldLabel string) []map[string]interface{} {
+ return r.GetFieldsByMask(fieldLabel, FieldTokenLabel, FieldSectionFields)
+}
+
+func (r *Record) GetCustomFieldsByType(fieldType string) []map[string]interface{} {
+ return r.GetFieldsByMask(fieldType, FieldTokenType, FieldSectionCustom)
+}
+
+func (r *Record) GetCustomFieldsByLabel(fieldLabel string) []map[string]interface{} {
+ return r.GetFieldsByMask(fieldLabel, FieldTokenLabel, FieldSectionCustom)
+}
+
+// GetFieldValueByType returns string value of the *first* field from fields[] that matches fieldType
+func (r *Record) GetFieldValueByType(fieldType string) string {
+ if fieldType == "" {
+ return ""
+ }
+
+ values := []string{}
+ if fields := r.GetFieldsByType(fieldType); len(fields) > 0 {
+ if iValues, ok := fields[0]["value"].([]interface{}); ok {
+ for i := range iValues {
+ val := iValues[i]
+ // JavaScript has no integers but only one number type, IEEE754 double precision float
+ if fval, ok := val.(float64); ok && fval == float64(int(fval)) {
+ val = int(fval) // convert to int
+ }
+ values = append(values, fmt.Sprintf("%v", val))
+ }
+ }
+ }
+
+ return strings.Join(values, ", ")
+}
+
+// GetFieldValueByLabel returns string value of the *first* field from fields[] that matches fieldLabel
+func (r *Record) GetFieldValueByLabel(fieldLabel string) string {
+ if fieldLabel == "" {
+ return ""
+ }
+
+ values := []string{}
+ if fields := r.GetFieldsByLabel(fieldLabel); len(fields) > 0 {
+ if iValues, ok := fields[0]["value"].([]interface{}); ok {
+ for i := range iValues {
+ values = append(values, fmt.Sprintf("%v", iValues[i]))
+ }
+ }
+ }
+
+ return strings.Join(values, ", ")
+}
+
+func (r *Record) GetFieldValuesByType(fieldType string) []string {
+ values := []string{}
+ if fieldType == "" {
+ return values
+ }
+
+ if fields := r.GetFieldsByType(fieldType); len(fields) > 0 {
+ if iValues, ok := fields[0]["value"].([]interface{}); ok {
+ for i := range iValues {
+ values = append(values, fmt.Sprintf("%v", iValues[i]))
+ }
+ }
+ }
+
+ return values
+}
+
+func (r *Record) GetCustomFieldValues(label string, fieldType string) []string {
+ values := []string{}
+ if label == "" && fieldType == "" {
+ return values
+ }
+
+ fields := []map[string]interface{}{}
+ if fieldType != "" {
+ if flds := r.GetCustomFieldsByType(fieldType); len(flds) > 0 {
+ for _, fld := range flds {
+ if iLabel, ok := fld["label"].(string); label == "" || (ok && label == iLabel) {
+ fields = append(fields, fld)
+ }
+ }
+ }
+ } else if label != "" {
+ if flds := r.GetCustomFieldsByLabel(label); len(flds) > 0 {
+ for _, fld := range flds {
+ if iType, ok := fld["type"].(string); fieldType == "" || (ok && fieldType == iType) {
+ fields = append(fields, fld)
+ }
+ }
+ }
+ }
+
+ for _, field := range fields {
+ if iValues, ok := field["value"].([]interface{}); ok {
+ for i := range iValues {
+ values = append(values, fmt.Sprintf("%v", iValues[i]))
+ }
+ }
+ }
+
+ return values
+}
+
+// GetCustomFieldValueByType returns string value of the *first* field from custom[] that matches fieldType
+func (r *Record) GetCustomFieldValueByType(fieldType string) string {
+ if fieldType == "" {
+ return ""
+ }
+
+ values := []string{}
+ if fields := r.GetCustomFieldsByType(fieldType); len(fields) > 0 {
+ if iValues, ok := fields[0]["value"].([]interface{}); ok {
+ for i := range iValues {
+ values = append(values, fmt.Sprintf("%v", iValues[i]))
+ }
+ }
+ }
+
+ result := ""
+ if len(values) == 1 {
+ result = values[0]
+ } else if len(values) > 1 {
+ result = strings.Join(values, ", ")
+ }
+ return result
+}
+
+// GetCustomFieldValueByLabel returns string value of the *first* field from custom[] that matches fieldLabel
+func (r *Record) GetCustomFieldValueByLabel(fieldLabel string) string {
+ if fieldLabel == "" {
+ return ""
+ }
+
+ values := []string{}
+ if fields := r.GetCustomFieldsByLabel(fieldLabel); len(fields) > 0 {
+ if iValues, ok := fields[0]["value"].([]interface{}); ok {
+ for i := range iValues {
+ values = append(values, fmt.Sprintf("%v", iValues[i]))
+ }
+ }
+ }
+
+ result := ""
+ if len(values) == 1 {
+ result = values[0]
+ } else if len(values) > 1 {
+ result = strings.Join(values, ", ")
+ }
+ return result
+}
+
+func NewRecordFromRecordData(recordData *RecordCreate, folder *Folder) *Record {
+ recordKey, err := GenerateRandomBytes(32)
+ if err != nil {
+ return nil
+ }
+ recordUid, err := GenerateRandomBytes(16)
+ if err != nil {
+ return nil
+ }
+
+ return &Record{
+ RecordKeyBytes: recordKey,
+ Uid: BytesToUrlSafeStr(recordUid),
+ folderKeyBytes: folder.key,
+ folderUid: folder.uid,
+ recordType: recordData.RecordType,
+ RawJson: recordData.ToJson(),
+ RecordDict: recordData.ToDict(),
+ }
+}
+
+func NewRecordFromRecordDataWithUid(recordUid string, recordData *RecordCreate, folder *Folder) *Record {
+ // recordUid must be a base64 url safe encoded string (UID binary length is 16 bytes)
+ ruid := UrlSafeStrToBytes(recordUid)
+ if len(ruid) != 16 {
+ if newUid, err := GenerateRandomBytes(16); err == nil {
+ ruid = newUid
+ } else {
+ return nil
+ }
+ }
+
+ recordKey, err := GenerateRandomBytes(32)
+ if err != nil {
+ return nil
+ }
+
+ return &Record{
+ RecordKeyBytes: recordKey,
+ Uid: BytesToUrlSafeStr(ruid),
+ folderKeyBytes: folder.key,
+ folderUid: folder.uid,
+ recordType: recordData.RecordType,
+ RawJson: recordData.ToJson(),
+ RecordDict: recordData.ToDict(),
+ }
+}
+
+func NewRecordFromJson(recordDict map[string]interface{}, secretKey []byte, folderUid string) *Record {
+ record := Record{}
+
+ // if folderUid is present then secretKey is the folder key
+ // if folderUid is empty then record is directly shared to the app and secretKey is the app key
+ if strings.TrimSpace(folderUid) != "" {
+ record.folderUid = folderUid
+ record.folderKeyBytes = secretKey
+ }
+
+ if uid, ok := recordDict["recordUid"]; ok {
+ record.Uid = strings.TrimSpace(uid.(string))
+ }
+ if innerFolderUid, ok := recordDict["innerFolderUid"]; ok {
+ if ifuid, ok := innerFolderUid.(string); ok {
+ record.innerFolderUid = strings.TrimSpace(ifuid)
+ }
+ }
+ if revision, ok := recordDict["revision"].(float64); ok {
+ record.Revision = int64(revision)
+ }
+ if isEditable, ok := recordDict["isEditable"].(bool); ok {
+ record.IsEditable = isEditable
+ }
+
+ recordKeyEncryptedStr := ""
+ if recKey, ok := recordDict["recordKey"]; ok {
+ recordKeyEncryptedStr = strings.TrimSpace(recKey.(string))
+ }
+
+ if recordKeyEncryptedStr != "" {
+ //Folder Share
+ recordKeyEncryptedBytes := Base64ToBytes(recordKeyEncryptedStr)
+ if recordKeyBytes, err := Decrypt(recordKeyEncryptedBytes, secretKey); err == nil {
+ record.RecordKeyBytes = recordKeyBytes
+ } else {
+ klog.Error("error decrypting record key: " + err.Error() + " - Record UID: " + record.Uid)
+ }
+ } else {
+ //Single Record Share
+ record.RecordKeyBytes = secretKey
+ }
+
+ if recordEncryptedData, ok := recordDict["data"]; ok && len(record.RecordKeyBytes) > 0 {
+ strRecordEncryptedData := recordEncryptedData.(string)
+ if recordDataJson, err := DecryptRecord(Base64ToBytes(strRecordEncryptedData), record.RecordKeyBytes); err == nil {
+ record.RawJson = recordDataJson
+ record.RecordDict = JsonToDict(record.RawJson)
+ } else {
+ klog.Error("error decrypting record data: " + err.Error())
+ }
+ }
+
+ if recordType, ok := record.RecordDict["type"]; ok {
+ record.recordType = recordType.(string)
+ }
+
+ // files
+ if recordFiles, ok := recordDict["files"]; ok {
+ if rfSlice, ok := recordFiles.([]interface{}); ok {
+ for i := range rfSlice {
+ if rfMap, ok := rfSlice[i].(map[string]interface{}); ok {
+ if file := NewKeeperFileFromJson(rfMap, record.RecordKeyBytes); file != nil {
+ record.Files = append(record.Files, file)
+ }
+ }
+ }
+ }
+ }
+
+ return &record
+}
+
+// FindFileByTitle finds the first file with matching title
+func (r *Record) FindFileByTitle(title string) *KeeperFile {
+ for i := range r.Files {
+ if r.Files[i].Title == title {
+ return r.Files[i]
+ }
+ }
+ return nil
+}
+
+// FindFileByName finds the first file with matching filename
+func (r *Record) FindFileByFilename(filename string) *KeeperFile {
+ for i := range r.Files {
+ if r.Files[i].Name == filename {
+ return r.Files[i]
+ }
+ }
+ return nil
+}
+
+// FindFile finds the first file with matching file UID, name or title
+func (r *Record) FindFile(name string) *KeeperFile {
+ for i := range r.Files {
+ if r.Files[i].Uid == name || r.Files[i].Name == name || r.Files[i].Title == name {
+ return r.Files[i]
+ }
+ }
+ return nil
+}
+
+// FindFiles finds all files with matching file UID, name or title
+func (r *Record) FindFiles(name string) []*KeeperFile {
+ result := []*KeeperFile{}
+ for i := range r.Files {
+ if r.Files[i].Uid == name || r.Files[i].Name == name || r.Files[i].Title == name {
+ result = append(result, r.Files[i])
+ }
+ }
+ return result
+}
+
+func (r *Record) DownloadFileByTitle(title string, path string) bool {
+ if foundFile := r.FindFileByTitle(title); foundFile != nil {
+ return foundFile.SaveFile(path, false)
+ }
+ return false
+}
+
+func (r *Record) DownloadFile(fileUid string, path string) bool {
+ for i := range r.Files {
+ if r.Files[i].Uid == fileUid {
+ return r.Files[i].SaveFile(path, false)
+ }
+ }
+ return false
+}
+
+func (r *Record) ToString() string {
+ return fmt.Sprintf("[Record: UID=%s, revision=%d, editable=%t, type: %s, title: %s, files count: %d]", r.Uid, r.Revision, r.IsEditable, r.recordType, r.Title(), len(r.Files))
+}
+
+func (r *Record) update() {
+ // Record class works directly on fields in recordDict here we only update the raw JSON
+ r.RawJson = DictToJson(r.RecordDict)
+}
+
+func (r *Record) value(values []interface{}, single bool) []interface{} {
+ if len(values) == 0 {
+ return []interface{}{}
+ }
+ if single {
+ return []interface{}{values[0]}
+ }
+ return values
+}
+
+func (r *Record) fieldSearch(fields []interface{}, fieldKey string) map[string]interface{} {
+ // This is a generic field search that returns the field
+ // It will work for for both standard and custom fields.
+ // It returns the field as a map[string]interface{}.
+
+ foundItem := map[string]interface{}{}
+ if len(fields) == 0 {
+ return foundItem
+ }
+
+ // First check in the field_key matches any labels. Label matching is case sensitive.
+ for _, item := range fields {
+ if iValue, ok := item.(map[string]interface{}); ok {
+ if iLabel, found := iValue["label"]; found {
+ if sLabel, ok := iLabel.(string); ok && strings.EqualFold(sLabel, fieldKey) {
+ foundItem = iValue
+ break
+ }
+ }
+ }
+ }
+ // If the label was not found, check the field type. Field type is case insensitive.
+ if len(foundItem) == 0 {
+ for _, item := range fields {
+ if iValue, ok := item.(map[string]interface{}); ok {
+ if iType, found := iValue["type"]; found {
+ if sType, ok := iType.(string); ok && strings.EqualFold(sType, fieldKey) {
+ foundItem = iValue
+ break
+ }
+ }
+ }
+ }
+ }
+ return foundItem
+}
+
+func (r *Record) getStandardField(fieldType string) map[string]interface{} {
+ if iFields, found := r.RecordDict["fields"]; found {
+ if sFields, ok := iFields.([]interface{}); ok {
+ return r.fieldSearch(sFields, fieldType)
+ }
+ }
+ return map[string]interface{}{}
+}
+
+func (r *Record) GetStandardFieldValue(fieldType string, single bool) ([]interface{}, error) {
+ field := r.getStandardField(fieldType)
+ if len(field) == 0 {
+ return nil, fmt.Errorf("cannot find standard field %s in record", fieldType)
+ }
+ sValue := []interface{}{}
+ if iValue, found := field["value"]; found {
+ if sVal, ok := iValue.([]interface{}); ok {
+ sValue = sVal
+ }
+ }
+ return r.value(sValue, single), nil
+}
+
+func (r *Record) SetStandardFieldValue(fieldType string, value interface{}) error {
+ field := r.getStandardField(fieldType)
+ if len(field) == 0 {
+ return fmt.Errorf("cannot find standard field %s in record", fieldType)
+ }
+ if _, ok := value.([]interface{}); !ok {
+ value = []interface{}{value}
+ }
+ field["value"] = value
+ r.update()
+ return nil
+}
+
+func (r *Record) FieldExists(section, name string) bool {
+ result := false
+ if section != "fields" && section != "custom" {
+ return result
+ }
+
+ if rfi, found := r.RecordDict[section]; found && rfi != nil {
+ if rfsi, ok := rfi.([]interface{}); ok && len(rfsi) > 0 {
+ for _, v := range rfsi {
+ if fmap, ok := v.(map[string]interface{}); ok {
+ if ftype, found := fmap["type"]; found && name == fmt.Sprint(ftype) {
+ result = true
+ break
+ }
+ }
+ }
+ }
+ }
+
+ return result
+}
+
+func (r *Record) RemoveField(section, name string, removeAll bool) int {
+ removed := 0
+ if section != "fields" && section != "custom" {
+ return removed
+ }
+
+ if rfi, found := r.RecordDict[section]; found && rfi != nil {
+ if rfsi, ok := rfi.([]interface{}); ok && len(rfsi) > 0 {
+ ix := []int{}
+ for i, v := range rfsi {
+ if fmap, ok := v.(map[string]interface{}); ok {
+ if ftype, found := fmap["type"]; found && name == fmt.Sprint(ftype) {
+ ix = append(ix, i)
+ }
+ }
+ }
+ if len(ix) > 1 && !removeAll {
+ ix = ix[:1]
+ }
+ if len(ix) > 0 {
+ // work on a copy since slices do not support in-place operations
+ rfsic := make([]interface{}, len(rfsi))
+ copy(rfsic, rfsi)
+
+ sort.Sort(sort.Reverse(sort.IntSlice(ix)))
+ for _, i := range ix {
+ removed++
+ rfsic = append(rfsic[:i], rfsic[i+1:]...)
+ }
+ r.RecordDict[section] = rfsic
+ }
+ }
+ }
+
+ return removed
+}
+
+func (r *Record) InsertField(section string, field interface{}) error {
+ if section != "fields" && section != "custom" {
+ return fmt.Errorf("unknown field section '%s'", section)
+ }
+ if !IsFieldClass(field) {
+ return fmt.Errorf("field is not a vaild field class")
+ }
+
+ if rfi, found := r.RecordDict[section]; !found || rfi == nil {
+ r.RecordDict[section] = []interface{}{}
+ }
+ if rfi, found := r.RecordDict[section]; found && rfi != nil {
+ if rfsi, ok := rfi.([]interface{}); ok {
+ // work on a copy since slices do not support in-place operations
+ rfsic := make([]interface{}, len(rfsi))
+ copy(rfsic, rfsi)
+ if fmap, err := structToMap(field); err == nil {
+ rfsic = append(rfsic, fmap)
+ } else {
+ return fmt.Errorf("error converting field %v - Error: %s", field, err.Error())
+ }
+ r.RecordDict[section] = rfsic
+ } else {
+ return fmt.Errorf("section '%s' is not in the expected format - expected []interface{}", section)
+ }
+ } else {
+ return fmt.Errorf("section '%s' not found", section)
+ }
+
+ return nil
+}
+
+func (r *Record) UpdateField(section string, field interface{}) error {
+ if section != "fields" && section != "custom" {
+ return fmt.Errorf("unknown field section '%s'", section)
+ }
+ if !IsFieldClass(field) {
+ return fmt.Errorf("field is not a vaild field class")
+ }
+
+ fieldMap, err := structToMap(field)
+ if err != nil {
+ return fmt.Errorf("error converting field %v - Error: %s", field, err.Error())
+ }
+
+ fieldType := ""
+ if fType, found := fieldMap["type"]; found {
+ fieldType = strings.TrimSpace(fmt.Sprint(fType))
+ }
+ if fieldType == "" {
+ return fmt.Errorf("error - missing field type in field: %v", field)
+ }
+
+ if rfi, found := r.RecordDict[section]; !found || rfi == nil {
+ r.RecordDict[section] = []interface{}{}
+ }
+ if rfi, found := r.RecordDict[section]; found && rfi != nil {
+ if rfsi, ok := rfi.([]interface{}); ok {
+ for _, v := range rfsi {
+ if fmap, ok := v.(map[string]interface{}); ok {
+ if ftype, found := fmap["type"]; found && fieldType == fmt.Sprint(ftype) {
+ for key := range fmap {
+ delete(fmap, key)
+ }
+ for key, val := range fieldMap {
+ fmap[key] = val
+ }
+ return nil
+ }
+ }
+ }
+ } else {
+ return fmt.Errorf("section '%s' is not in the expected format - expected []interface{}", section)
+ }
+ } else {
+ return fmt.Errorf("section '%s' not found", section)
+ }
+
+ return fmt.Errorf("field type '%s' not found", fieldType)
+}
+
+func (r *Record) getCustomField(fieldType string) map[string]interface{} {
+ if iFields, found := r.RecordDict["custom"]; found {
+ if sFields, ok := iFields.([]interface{}); ok {
+ return r.fieldSearch(sFields, fieldType)
+ }
+ }
+ return map[string]interface{}{}
+}
+
+func (r *Record) GetCustomFieldValue(fieldType string, single bool) ([]interface{}, error) {
+ field := r.getCustomField(fieldType)
+ if len(field) == 0 {
+ return nil, fmt.Errorf("cannot find custom field %s in record", fieldType)
+ }
+ sValue := []interface{}{}
+ if iValue, found := field["value"]; found {
+ if sVal, ok := iValue.([]interface{}); ok {
+ sValue = sVal
+ }
+ }
+ return r.value(sValue, single), nil
+}
+
+func (r *Record) SetCustomFieldValue(fieldType string, value interface{}) error {
+ field := r.getCustomField(fieldType)
+ if len(field) == 0 {
+ return fmt.Errorf("cannot find custom field %s in record", fieldType)
+ }
+ if _, ok := value.([]interface{}); !ok {
+ value = []interface{}{value}
+ }
+ field["value"] = value
+ r.update()
+ return nil
+}
+
+// AddCustomField adds new custom field to the record
+// The new field must satisfy the IsFieldClass function
+func (r *Record) AddCustomField(field interface{}) error {
+ if !IsFieldClass(field) {
+ return fmt.Errorf("cannot add custom field - unknown field type for %v ", field)
+ }
+
+ var iCustom interface{} = []interface{}{}
+ if iFields, found := r.RecordDict["custom"]; found {
+ iCustom = iFields
+ } else {
+ r.RecordDict["custom"] = iCustom
+ }
+
+ if sCustom, ok := iCustom.([]interface{}); ok {
+ if fmap := ObjToDict(field); fmap != nil {
+ sCustom = append(sCustom, fmap)
+ r.RecordDict["custom"] = sCustom
+ r.update()
+ return nil
+ } else {
+ return fmt.Errorf("cannot add custom field - error converting to JSON, field: %v ", field)
+ }
+ } else {
+ return fmt.Errorf("cannot add custom field - custom[] is not the expected array type, custom: %v ", iCustom)
+ }
+}
+
+func (r *Record) CanClone() bool {
+ if strings.TrimSpace(r.folderUid) != "" && len(r.folderKeyBytes) > 0 {
+ return true
+ } else {
+ return false
+ }
+}
+
+func findTemplateRecord(templateRecordUid string, records []*Record) (*Record, error) {
+ var templateRecord *Record = nil
+
+ for _, r := range records {
+ if r.Uid == templateRecordUid {
+ templateRecord = r
+ if strings.TrimSpace(r.folderUid) != "" && len(r.folderKeyBytes) > 0 {
+ break
+ }
+ }
+ }
+
+ if templateRecord == nil {
+ return nil, fmt.Errorf("cannot find template record '%s' in record", templateRecordUid)
+ }
+
+ // Records shared directly to the application cannot be used as template records
+ // only records in a shared folder (shared to the application) should be used as templates
+ if strings.TrimSpace(templateRecord.folderUid) == "" || len(templateRecord.folderKeyBytes) == 0 {
+ return nil, fmt.Errorf("found matching template record %s which is not in a shared folder", templateRecordUid)
+ }
+
+ return templateRecord, nil
+}
+
+// NewRecordClone returns a deep copy of the template object with new UID and RecordKeyBytes
+// generates and uses new random UID if newRecordUid is empty
+// returns error if template record is not found
+func NewRecordClone(templateRecordUid string, records []*Record, newRecordUid string) (*Record, error) {
+ templateRecord, err := findTemplateRecord(templateRecordUid, records)
+ if err != nil {
+ return nil, err
+ }
+
+ recordKeyBytes, _ := GetRandomBytes(32)
+ folderKeyBytesCopy := make([]byte, len(templateRecord.folderKeyBytes))
+ copy(folderKeyBytesCopy, templateRecord.folderKeyBytes)
+ recordDictCopy := CopyableMap(templateRecord.RecordDict).DeepCopy()
+
+ filesCopy := []*KeeperFile{}
+ for _, f := range templateRecord.Files {
+ filesCopy = append(filesCopy, f.DeepCopy())
+ }
+
+ recordUid := GenerateUid()
+ if ruid := strings.TrimSpace(newRecordUid); ruid != "" {
+ if numBytes := len(Base64ToBytes(ruid)); numBytes == 16 {
+ recordUid = newRecordUid
+ }
+ }
+ if newRecordUid != "" && recordUid != newRecordUid {
+ klog.Warning("invalid new record UID provided:", newRecordUid, " - using autogenerated UID:", recordUid)
+ }
+
+ rec := &Record{
+ RecordKeyBytes: recordKeyBytes,
+ Uid: recordUid,
+ folderKeyBytes: folderKeyBytesCopy,
+ folderUid: templateRecord.folderUid,
+ innerFolderUid: templateRecord.innerFolderUid,
+ Files: filesCopy,
+ Revision: templateRecord.Revision,
+ IsEditable: templateRecord.IsEditable,
+ recordType: templateRecord.recordType,
+ RawJson: templateRecord.RawJson,
+ RecordDict: recordDictCopy,
+ }
+
+ return rec, nil
+}
+
+// NewRecord returns a new empty record of the same type as template object but with new UID and RecordKeyBytes
+// generates and uses new random UID if newRecordUid is empty
+// returns error if template record is not found
+func NewRecord(templateRecordUid string, records []*Record, newRecordUid string) (*Record, error) {
+ templateRecord, err := findTemplateRecord(templateRecordUid, records)
+ if err != nil {
+ return nil, err
+ }
+
+ recordKeyBytes, _ := GetRandomBytes(32)
+ folderKeyBytesCopy := make([]byte, len(templateRecord.folderKeyBytes))
+ copy(folderKeyBytesCopy, templateRecord.folderKeyBytes)
+
+ // copy and preserve known keys but clear all other values except record type
+ // drop custom[] and any other unknown top-level keys
+ recordDictCopy := CopyableMap(templateRecord.RecordDict).DeepCopy()
+ for key, val := range recordDictCopy {
+ switch key {
+ case "type":
+ continue
+ case "title", "notes":
+ recordDictCopy[key] = ""
+ case "custom":
+ delete(recordDictCopy, key)
+ case "fields":
+ if fslice, ok := val.([]interface{}); ok {
+ for _, fs := range fslice {
+ if fmap, ok := fs.(map[string]interface{}); ok {
+ for fkey := range fmap {
+ // preserve field type, clear label and value, drop everything else
+ switch fkey {
+ case "type":
+ continue
+ case "label":
+ fmap[fkey] = ""
+ case "value":
+ fmap[fkey] = []interface{}{}
+ default:
+ klog.Warning("create new record - removing field type property", key)
+ delete(fmap, key)
+ }
+ }
+ } else {
+ klog.Warning("create new record - fields type is not in the expected format and is removed")
+ }
+ }
+ } else {
+ klog.Warning("create new record - fields[] is not in the expected format and is replaced")
+ recordDictCopy[key] = []interface{}{}
+ }
+ default:
+ klog.Warning("create new record - removing unknown record type property", key)
+ delete(recordDictCopy, key)
+ }
+ }
+ rawJson := DictToJson(recordDictCopy)
+
+ recordUid := GenerateUid()
+ if ruid := strings.TrimSpace(newRecordUid); ruid != "" {
+ if numBytes := len(Base64ToBytes(ruid)); numBytes == 16 {
+ recordUid = newRecordUid
+ }
+ }
+ if newRecordUid != "" && recordUid != newRecordUid {
+ klog.Warning("invalid new record UID provided:", newRecordUid, " - using autogenerated UID:", recordUid)
+ }
+
+ rec := &Record{
+ RecordKeyBytes: recordKeyBytes,
+ Uid: recordUid,
+ folderKeyBytes: folderKeyBytesCopy,
+ folderUid: templateRecord.folderUid,
+ innerFolderUid: templateRecord.innerFolderUid,
+ Files: []*KeeperFile{},
+ Revision: templateRecord.Revision,
+ IsEditable: templateRecord.IsEditable,
+ recordType: templateRecord.recordType,
+ RawJson: rawJson,
+ RecordDict: recordDictCopy,
+ }
+
+ return rec, nil
+}
+
+func (r *Record) Print() {
+ fmt.Println("===")
+ fmt.Println("Title: " + r.Title())
+ fmt.Println("UID: " + r.Uid)
+ fmt.Println("Type: " + r.Type())
+
+ fmt.Println()
+ fmt.Println("Fields")
+ fmt.Println("------")
+ skipFileds := map[string]struct{}{"fileRef": {}, "oneTimeCode": {}}
+ if _fields, ok := r.RecordDict["fields"]; ok {
+ if fields, ok := _fields.([]interface{}); ok {
+ for i := range fields {
+ if fmap, ok := fields[i].(map[string]interface{}); ok {
+ ftype, _ := fmap["type"].(string)
+ // flabel, _ := fmap["label"].(string)
+ if _, found := skipFileds[ftype]; !found {
+ fmt.Printf("%s : %v\n", ftype, fmap["value"]) // ", ".join(item["value"]
+ }
+ }
+ }
+ }
+ }
+
+ fmt.Println()
+ fmt.Println("Custom Fields")
+ fmt.Println("------")
+ if _fields, ok := r.RecordDict["custom"]; ok {
+ if fields, ok := _fields.([]interface{}); ok {
+ for i := range fields {
+ if fmap, ok := fields[i].(map[string]interface{}); ok {
+ ftype, _ := fmap["type"].(string)
+ flabel, _ := fmap["label"].(string)
+ fmt.Printf("%s (%s) : %v\n", ftype, flabel, fmap["value"]) // ", ".join(item["value"]
+ }
+ }
+ }
+ }
+}
+
+type KeeperFolder struct {
+ FolderKey []byte
+ FolderUid string
+ ParentUid string
+ Name string
+}
+
+func NewKeeperFolder(folderMap map[string]interface{}, folderKey []byte) *KeeperFolder {
+ folder := KeeperFolder{FolderKey: folderKey}
+ if key, found := folderMap["folderUid"]; found {
+ if val, ok := key.(string); ok {
+ folder.FolderUid = val
+ }
+ }
+ if key, found := folderMap["parent"]; found {
+ if val, ok := key.(string); ok {
+ folder.ParentUid = val
+ }
+ }
+ if key, found := folderMap["data"]; found {
+ if val, ok := key.(string); ok {
+ if folderNameJson, err := DecryptAesCbc(UrlSafeStrToBytes(val), folderKey); err == nil {
+ folderName := struct {
+ Name string `json:"name"`
+ }{}
+ if err := json.Unmarshal(folderNameJson, &folderName); err == nil {
+ folder.Name = folderName.Name
+ } else {
+ klog.Error("error parsing folder name: " + err.Error())
+ }
+ }
+ }
+ }
+
+ return &folder
+}
+
+type Folder struct {
+ key []byte
+ uid string
+ ParentUid string
+ Name string
+ data map[string]interface{}
+ folderRecords []map[string]interface{}
+}
+
+func NewFolderFromJson(folderDict map[string]interface{}, secretKey []byte) *Folder {
+ folder := Folder{
+ data: folderDict,
+ }
+ if uid, ok := folderDict["folderUid"]; ok {
+ folder.uid = strings.TrimSpace(uid.(string))
+ // only /get_folders retrieves parent and name/data
+ if folderKeyEnc, ok := folderDict["folderKey"]; ok {
+ if folderKey, err := Decrypt(Base64ToBytes(folderKeyEnc.(string)), secretKey); err == nil {
+ folder.key = folderKey
+ if folderRecords, ok := folderDict["records"]; ok {
+ if iFolderRecords, ok := folderRecords.([]interface{}); ok {
+ for i := range iFolderRecords {
+ if folderRecord, ok := iFolderRecords[i].(map[string]interface{}); ok {
+ folder.folderRecords = append(folder.folderRecords, folderRecord)
+ }
+ }
+ } else {
+ klog.Error("folder records JSON is in incorrect format")
+ }
+ }
+ } else {
+ klog.Error("error decrypting folder key: " + err.Error())
+ }
+ }
+ } else {
+ klog.Error("Not a folder")
+ return nil
+ }
+
+ return &folder
+}
+
+func (f *Folder) Records() []*Record {
+ records := []*Record{}
+ if f.folderRecords != nil {
+ for _, r := range f.folderRecords {
+ if record := NewRecordFromJson(r, f.key, f.uid); record.Uid != "" {
+ records = append(records, record)
+ } else {
+ klog.Error("error parsing folder record: ", r)
+ }
+ }
+ }
+ return records
+}
+
+type KeeperFile struct {
+ FileKey string
+ metaDict map[string]interface{}
+
+ FileData []byte
+
+ Uid string
+ Type string
+ Title string
+ Name string
+ LastModified int
+ Size int
+
+ F map[string]interface{}
+ RecordKeyBytes []byte
+}
+
+func NewKeeperFileFromJson(fileDict map[string]interface{}, recordKeyBytes []byte) *KeeperFile {
+ f := &KeeperFile{
+ F: fileDict,
+ RecordKeyBytes: recordKeyBytes,
+ }
+
+ // Set file metadata
+ meta := f.GetMeta()
+
+ if fuid, ok := fileDict["fileUid"].(string); ok {
+ f.Uid = fuid
+ }
+ if recordType, ok := meta["type"].(string); ok {
+ f.Type = recordType
+ }
+ if title, ok := meta["title"].(string); ok {
+ f.Title = title
+ }
+ if name, ok := meta["name"].(string); ok {
+ f.Name = name
+ }
+ if lastModified, ok := meta["lastModified"].(float64); ok {
+ f.LastModified = int(lastModified)
+ }
+ if size, ok := meta["size"].(float64); ok {
+ f.Size = int(size)
+ }
+
+ return f
+}
+
+func (f *KeeperFile) DeepCopy() *KeeperFile {
+ return &KeeperFile{
+ FileKey: f.FileKey,
+ metaDict: CopyableMap(f.metaDict).DeepCopy(),
+ FileData: CloneByteSlice(f.FileData),
+ Uid: f.Uid,
+ Type: f.Type,
+ Title: f.Title,
+ Name: f.Name,
+ LastModified: f.LastModified,
+ Size: f.Size,
+ F: CopyableMap(f.F).DeepCopy(),
+ RecordKeyBytes: CloneByteSlice(f.RecordKeyBytes),
+ }
+}
+
+func (f *KeeperFile) DecryptFileKey() []byte {
+ fileKeyEncryptedBase64 := f.F["fileKey"]
+ fileKeyEncryptedBase64Str := fmt.Sprintf("%v", fileKeyEncryptedBase64)
+ fileKeyEncrypted := Base64ToBytes(fileKeyEncryptedBase64Str)
+ if fileKey, err := Decrypt(fileKeyEncrypted, f.RecordKeyBytes); err == nil {
+ return fileKey
+ } else {
+ klog.Error("error decrypting file key " + fileKeyEncryptedBase64Str)
+ return []byte{}
+ }
+}
+
+func (f *KeeperFile) GetMeta() map[string]interface{} {
+ // Returns file metadata dictionary (file name, title, size, type, etc.)
+ if len(f.metaDict) == 0 {
+ if data, ok := f.F["data"]; ok && data != nil {
+ fileKey := f.DecryptFileKey()
+ dataStr := fmt.Sprintf("%v", data)
+ if metaJson, err := Decrypt(Base64ToBytes(dataStr), fileKey); err == nil {
+ f.metaDict = JsonToDict(string(metaJson[:]))
+ } else {
+ klog.Error("error parsing file meta data " + dataStr)
+ }
+ }
+ }
+ return f.metaDict
+}
+
+func (f *KeeperFile) GetUrl() string {
+ if url, ok := f.F["url"].(string); ok {
+ return url
+ }
+ return ""
+}
+
+func (f *KeeperFile) GetFileData() []byte {
+ // Return decrypted raw file data
+ if len(f.FileData) == 0 { // cached if nothing
+ fileKey := f.DecryptFileKey()
+ if fileUrl, ok := f.F["url"]; ok && fileUrl != nil {
+ fileUrlStr := fmt.Sprintf("%v", fileUrl)
+ if rs, err := http.Get(fileUrlStr); err == nil {
+ defer rs.Body.Close()
+ if fileEncryptedData, err := ioutil.ReadAll(rs.Body); err == nil {
+ if fileData, err := Decrypt(fileEncryptedData, fileKey); err == nil {
+ f.FileData = fileData
+ }
+ }
+ }
+ }
+ }
+ return f.FileData
+}
+
+func (f *KeeperFile) SaveFile(path string, createFolders bool) bool {
+ // Save decrypted file data to the provided path
+ if createFolders {
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+ klog.Error("error creating folders " + err.Error())
+ }
+ }
+
+ pathExists := false
+ if absPath, err := filepath.Abs(path); err == nil {
+ dirPath := filepath.Dir(absPath)
+ if found, _ := PathExists(dirPath); found {
+ pathExists = true
+ }
+ }
+
+ if !pathExists {
+ klog.Error("No such file or directory %s\nConsider using `SaveFile()` method with `createFolders=True` ", path)
+ return false
+ }
+
+ fileData := f.GetFileData()
+ if err := ioutil.WriteFile(path, fileData, 0644); err != nil {
+ klog.Error("error savig file " + err.Error())
+ }
+
+ return true
+}
+
+func (f *KeeperFile) ToString() string {
+ return fmt.Sprintf("[KeeperFile - name: %s, title: %s]", f.Name, f.Title)
+}
+
+type KeeperFileUpload struct {
+ Name string
+ Title string
+ Type string
+ Data []byte
+}
+
+func GetFileForUpload(filePath, fileName, fileTitle, mimeType string) (*KeeperFileUpload, error) {
+ // Helper method to get KeeperFileUpload struct from the file path
+ if fileName == "" {
+ fileName = path.Base(filePath)
+ }
+ if fileTitle == "" {
+ fileTitle = fileName
+ }
+ if mimeType == "" {
+ mimeType = "application/octet-stream"
+ }
+ if fileDataBytes, err := ioutil.ReadFile(filePath); err == nil {
+ return &KeeperFileUpload{
+ Name: fileName,
+ Title: fileTitle,
+ Type: mimeType,
+ Data: fileDataBytes,
+ }, nil
+ } else {
+ return nil, err
+ }
+}
+
+type KeeperFileData struct {
+ Title string `json:"title,omitempty"`
+ Name string `json:"name,omitempty"`
+ Type string `json:"type,omitempty"`
+ Size int64 `json:"size,omitempty"`
+ LastModified int64 `json:"lastModified,omitempty"`
+}
+
+type RecordField struct {
+ Type string
+ Label string
+ Value []interface{}
+ Required bool
+}
+
+func NewRecordField(fieldType, label string, required bool, value interface{}) *RecordField {
+ recordField := &RecordField{
+ Type: fieldType,
+ Label: label,
+ Required: required,
+ }
+ if iValue, ok := value.([]interface{}); ok {
+ recordField.Value = iValue
+ } else if value == nil {
+ recordField.Value = []interface{}{}
+ } else {
+ recordField.Value = []interface{}{value}
+ }
+ return recordField
+}
+
+type RecordCreate struct {
+ RecordType string `json:"type,omitempty"`
+ Title string `json:"title,omitempty"`
+ Notes string `json:"notes,omitempty"`
+ Fields []interface{} `json:"fields,omitempty"`
+ Custom []interface{} `json:"custom,omitempty"`
+}
+
+func NewRecordCreate(recordType, title string) *RecordCreate {
+ return &RecordCreate{
+ RecordType: recordType,
+ Title: title,
+ Fields: []interface{}{},
+ Custom: []interface{}{},
+ }
+}
+
+func NewRecordCreateFromJson(recordJson string) *RecordCreate {
+ // NB! this will silently ignore any unknown record and field attributes
+ // NB! Do not serialize back to record or field for update - use only for record create
+ rc := getRecordCreateFromJson(recordJson)
+ if rc != nil {
+ fields := []interface{}{}
+ custom := []interface{}{}
+ for _, fMap := range rc.Fields {
+ if fld, err := convertToKeeperRecordField(fMap, false); err == nil {
+ fields = append(fields, fld)
+ } else {
+ klog.Warning("skipped field definition due to conversion error(s) - " + err.Error())
+ }
+ }
+ for _, fMap := range rc.Custom {
+ if fld, err := convertToKeeperRecordField(fMap, false); err == nil {
+ custom = append(custom, fld)
+ } else {
+ klog.Warning("skipped custom field definition due to conversion error(s) - " + err.Error())
+ }
+ }
+ rc.Fields = fields
+ rc.Custom = custom
+ }
+ return rc
+}
+
+func getRecordCreateFromJson(jsonData string) *RecordCreate {
+ bytes := []byte(jsonData)
+ res := RecordCreate{}
+
+ if err := json.Unmarshal(bytes, &res); err != nil {
+ klog.Error("Error deserializing RecordCreate from JSON: " + err.Error())
+ return nil
+ }
+ return &res
+}
+
+func NewRecordCreateFromJsonDecoder(recordJson string, disallowUnknownFields bool) (*RecordCreate, error) {
+ // NB! JSON mapping is controlled by disallowUnknownFields and may ignore any unknown record and field attributes
+ // when disallowUnknownFields is true it is safe to serialize back to record or field for update but
+ // when disallowUnknownFields is false avoid serializing RecordCreate back to JSON as may remove any extras
+ rc, err := getRecordCreateFromJsonDecoder(recordJson, disallowUnknownFields)
+ if err != nil {
+ return nil, err
+ }
+ if rc != nil {
+ fields := []interface{}{}
+ custom := []interface{}{}
+ for _, fMap := range rc.Fields {
+ if fld, err := convertToKeeperRecordField(fMap, true); err == nil {
+ fields = append(fields, fld)
+ } else {
+ return nil, err
+ }
+ }
+ for _, fMap := range rc.Custom {
+ if fld, err := convertToKeeperRecordField(fMap, true); err == nil {
+ custom = append(custom, fld)
+ } else {
+ return nil, err
+ }
+ }
+ rc.Fields = fields
+ rc.Custom = custom
+ }
+ return rc, nil
+}
+
+func getRecordCreateFromJsonDecoder(jsonData string, disallowUnknownFields bool) (*RecordCreate, error) {
+ // NB! Cannot validate RecordType because of custom types
+ rc := RecordCreate{}
+
+ if disallowUnknownFields {
+ decoder := json.NewDecoder(strings.NewReader(jsonData))
+ decoder.DisallowUnknownFields()
+ if err := decoder.Decode(&rc); err != nil {
+ klog.Error("Error deserializing RecordCreate from strict JSON: " + err.Error())
+ return nil, err
+ }
+ } else {
+ if err := json.Unmarshal([]byte(jsonData), &rc); err != nil {
+ klog.Error("Error deserializing RecordCreate from JSON: " + err.Error())
+ return nil, err
+ }
+ }
+
+ return &rc, nil
+}
+
+func convertToKeeperRecordField(fieldData interface{}, validate bool) (interface{}, error) {
+ if fieldData == nil {
+ return nil, errors.New("cannot convert empty field data")
+ }
+ fieldTypes := "|login|password|url|fileRef|oneTimeCode|name" +
+ "|birthDate|date|expirationDate|text|securityQuestion|multiline|email|cardRef" +
+ "|addressRef|pinCode|phone|secret|note|accountNumber|paymentCard|bankAccount" +
+ "|keyPair|host|address|licenseNumber|recordRef|schedule|directoryType|databaseType" +
+ "|pamHostname|pamResources|checkbox|script|passkey|"
+ if fMap, ok := fieldData.(map[string]interface{}); ok {
+ if fType, found := fMap["type"]; found {
+ if sType, ok := fType.(string); ok && strings.Contains(fieldTypes, "|"+sType+"|") {
+ return getKeeperRecordField(sType, fMap, validate)
+ } else {
+ return nil, fmt.Errorf("unknown field type %v", fMap)
+ }
+ } else {
+ return nil, fmt.Errorf("field type missing in field data %v", fieldData)
+ }
+ } else {
+ return nil, fmt.Errorf("expected format for field data %v", fieldData)
+ }
+}
+
+func (r RecordCreate) ToDict() map[string]interface{} {
+ recDict := map[string]interface{}{
+ "type": r.RecordType,
+ "title": r.Title,
+ "fields": r.Fields,
+ }
+ if r.Notes != "" {
+ recDict["notes"] = r.Notes
+ }
+ if len(r.Custom) > 0 {
+ recDict["custom"] = r.Custom
+ }
+ return recDict
+}
+
+func (r RecordCreate) ToJson() string {
+ return DictToJsonWithDefultIndent(r.ToDict())
+}
+
+func (r RecordCreate) getFieldsByType(field interface{}, single bool) []interface{} {
+ result := []interface{}{}
+ if field == nil {
+ return result
+ }
+
+ fieldPtr := getFieldPtr(field)
+ if fieldPtr == nil {
+ return result
+ }
+
+ iType := reflect.TypeOf(fieldPtr)
+ for i, f := range r.Fields {
+ fptr := getFieldPtr(f)
+ if fType := reflect.TypeOf(fptr); iType == fType {
+ result = append(result, fptr)
+ if reflect.TypeOf(f).Kind() != reflect.Ptr {
+ r.Fields[i] = fptr
+ }
+ if single {
+ return result
+ }
+ }
+ }
+ for i, f := range r.Custom {
+ fptr := getFieldPtr(f)
+ if fType := reflect.TypeOf(fptr); iType == fType {
+ result = append(result, fptr)
+ if reflect.TypeOf(f).Kind() != reflect.Ptr {
+ r.Custom[i] = fptr
+ }
+ if single {
+ return result
+ }
+ }
+ }
+ return result
+}
+
+// GetFieldsByType returns all fields of the same type as field param
+// The search goes first through fields[] then custom[]
+// Note: Method returns pointers so any value modifications are reflected directly in the record
+func (r RecordCreate) GetFieldsByType(field interface{}) []interface{} {
+ result := []interface{}{}
+ if field == nil {
+ return result
+ }
+
+ if records := r.getFieldsByType(field, false); records == nil {
+ return result
+ } else {
+ return records
+ }
+}
+
+// GetFieldByType returns first found field of the same type as field param
+// The search goes first through fields[] then custom[]
+// Note: Method returns a pointer so any value modifications are reflected directly in the record
+func (r RecordCreate) GetFieldByType(field interface{}) interface{} {
+ var result interface{}
+ if field == nil {
+ return result
+ }
+
+ if records := r.getFieldsByType(field, true); len(records) == 0 {
+ return result
+ } else {
+ return records[0]
+ }
+}
+
+// Return a pointer to the supplied struct via interface{}
+func toFieldPtr(obj interface{}) interface{} {
+ vp := reflect.New(reflect.TypeOf(obj))
+ vp.Elem().Set(reflect.ValueOf(obj))
+ return vp.Interface()
+}
+
+func getFieldPtr(field interface{}) interface{} {
+ // already pointer type
+ if fType := reflect.TypeOf(field); fType.Kind() == reflect.Ptr {
+ return field
+ }
+
+ // struct - passed by value, get pointer
+ switch field.(type) {
+ case nil:
+ return nil
+ default:
+ return toFieldPtr(field)
+ }
+}
+
+// Application info
+type AppData struct {
+ Title string `json:"title,omitempty"`
+ AppType string `json:"type,omitempty"`
+}
+
+func NewAppData(title, appType string) *AppData {
+ return &AppData{
+ Title: title,
+ AppType: appType,
+ }
+}
+
+// Server response contained details about the application and the records
+// that were requested to be returned
+type SecretsManagerResponse struct {
+ AppData AppData
+ Folders []*Folder
+ Records []*Record
+ ExpiresOn int64
+ Warnings string
+ JustBound bool
+ // AppOwnerPublicKey string
+ // EncryptedAppKey string
+}
+
+// ExpiresOnStr retrieves string formatted expiration date
+// if dateFormat is empty default format is used: "%Y-%m-%d %H:%M:%S"
+func (r SecretsManagerResponse) ExpiresOnStr(dateFormat string) string {
+ unixtimeSeconds := r.ExpiresOn / 1000
+ return time.Unix(unixtimeSeconds, 0).Format("2006-01-02 15:04:05")
+ // "2006-01-02 15:04:05" = "%Y-%m-%d %H:%M:%S"
+ // RFC3339 = "2006-01-02T15:04:05Z07:00"
+ // RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
+}
+
+type AddFileResponse struct {
+ Url string `json:"url"`
+ Parameters string `json:"parameters"`
+ SuccessStatusCode int `json:"successStatusCode"`
+}
+
+func AddFileResponseFromJson(jsonData string) (*AddFileResponse, error) {
+ bytes := []byte(jsonData)
+ res := AddFileResponse{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ return &res, nil
+ } else {
+ return nil, fmt.Errorf("Error deserializing AddFileResponse from JSON: " + err.Error())
+ }
+}
+
+type DeleteSecretResponse struct {
+ RecordUid string `json:"recordUid"`
+ ResponseCode string `json:"responseCode"`
+ ErrorMessage string `json:"errorMessage"`
+}
+
+type DeleteSecretsResponse struct {
+ Records []DeleteSecretResponse `json:"records"`
+}
+
+func DeleteSecretsResponseFromJson(jsonData string) (*DeleteSecretsResponse, error) {
+ bytes := []byte(jsonData)
+ res := DeleteSecretsResponse{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ return &res, nil
+ } else {
+ return nil, fmt.Errorf("Error deserializing DeleteSecretsResponse from JSON: " + err.Error())
+ }
+}
+
+type DeleteFolderResponse struct {
+ FolderUid string `json:"folderUid"`
+ ResponseCode string `json:"responseCode"`
+ ErrorMessage string `json:"errorMessage"`
+}
+
+type DeleteFoldersResponse struct {
+ Folders []DeleteFolderResponse `json:"folders"`
+}
+
+func DeleteFoldersResponseFromJson(jsonData string) (*DeleteFoldersResponse, error) {
+ bytes := []byte(jsonData)
+ res := DeleteFoldersResponse{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ return &res, nil
+ } else {
+ return nil, fmt.Errorf("Error deserializing DeleteFoldersResponse from JSON: " + err.Error())
+ }
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/helpers.go b/vendor/github.com/keeper-security/secrets-manager-go/core/helpers.go
new file mode 100644
index 00000000..0be26345
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/helpers.go
@@ -0,0 +1,66 @@
+package core
+
+import (
+ "encoding/json"
+ "net"
+ "net/url"
+ "os"
+ "strings"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+func GetServerHostname(hostname string, configStore IKeyValueStorage) string {
+ hostnameToUse := defaultKeeperHostname
+ if envHostname := strings.TrimSpace(os.Getenv("KSM_HOSTNAME")); envHostname != "" {
+ hostnameToUse = envHostname
+ } else if cfgHostname := strings.TrimSpace(configStore.Get(KEY_HOSTNAME)); cfgHostname != "" {
+ hostnameToUse = cfgHostname
+ } else if codedHostname := strings.TrimSpace(hostname); codedHostname != "" {
+ hostnameToUse = codedHostname
+ }
+
+ // Parse URL to get only domain:
+ hostnameToUse = strings.TrimSpace(hostnameToUse)
+ hostnameToReturn := hostnameToUse
+
+ if !strings.HasPrefix(strings.ToLower(hostnameToUse), "http") {
+ hostnameToUse = "https://" + hostnameToUse
+ }
+ if u, err := url.Parse(hostnameToUse); err == nil && u.Host != "" {
+ hostnameToReturn = u.Host
+ if host, _, err := net.SplitHostPort(u.Host); err == nil && host != "" {
+ hostnameToReturn = host
+ }
+ }
+
+ klog.Debug("Keeper server hostname: " + hostnameToReturn)
+
+ return hostnameToReturn
+}
+
+func IsJson(jsonStr string) bool {
+ var js interface{}
+ return json.Unmarshal([]byte(jsonStr), &js) == nil
+}
+
+func ObjToDict(obj interface{}) map[string]interface{} {
+ if o, ok := obj.(map[string]interface{}); ok {
+ return o
+ }
+ content, err := json.Marshal(obj)
+ if err != nil {
+ content = []byte("{}")
+ }
+ return JsonToDict(string(content))
+
+}
+
+func GetFolderByKey(folderUid string, folders []*Folder) *Folder {
+ for _, f := range folders {
+ if f.uid == folderUid {
+ return f
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/keeper_globals.go b/vendor/github.com/keeper-security/secrets-manager-go/core/keeper_globals.go
new file mode 100644
index 00000000..1642334e
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/keeper_globals.go
@@ -0,0 +1,69 @@
+package core
+
+import (
+ "fmt"
+ "strings"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+const (
+ versionMajor string = "16"
+ version string = "16.6.2"
+ keeperSecretsManagerClientId string = "mg16.6.2" // Golang client ID starts with "mg" + version
+ defaultKeeperHostname string = "keepersecurity.com"
+ clientIdHashTag string = "KEEPER_SECRETS_MANAGER_CLIENT_ID" // Tag for hashing the client key to client id
+)
+
+var (
+ keeperServers = map[string]string{
+ "US": "keepersecurity.com",
+ "EU": "keepersecurity.eu",
+ "AU": "keepersecurity.com.au",
+ "GOV": "govcloud.keepersecurity.us",
+ "JP": "keepersecurity.jp",
+ "CA": "keepersecurity.ca",
+ }
+)
+
+// getClientVersion returns the version of the client
+func GetClientVersion(hardcode bool) string {
+ // For the client version number we use the defined major and minor and revision numbers of the module version.
+ // For example, module version of 0.1.23 would create a client version would be 16.1.23.
+
+ // Get the version of the keeper secrets manager core
+ result := versionMajor + ".2.0"
+
+ // Allow the default version to be hard coded. If not build the client version from the module version.
+ if !hardcode {
+ if versionParts := strings.Split(version, "."); len(versionParts) > 2 {
+ versionMinor := strings.TrimSpace(versionParts[1])
+ parts := strings.FieldsFunc(versionParts[2], func(r rune) bool { return '0' > r || r > '9' })
+ versionRevision := strings.TrimSpace(parts[0])
+ if versionMajor != "" && versionMinor != "" && versionRevision != "" {
+ result = fmt.Sprintf("%s.%s.%s", versionMajor, versionMinor, versionRevision)
+ } else {
+ klog.Error("Unable to determine the client version - using default: " + result)
+ }
+ }
+ }
+ return result
+}
+
+var (
+ // Right now the client version is being hardcoded.
+ // keeperSecretsManagerSdkClientId string = "mg" + GetClientVersion(true)
+ keeperServerPublicKeys map[string]string = map[string]string{
+ "7": "BK9w6TZFxE6nFNbMfIpULCup2a8xc6w2tUTABjxny7yFmxW0dAEojwC6j6zb5nTlmb1dAx8nwo3qF7RPYGmloRM",
+ "8": "BKnhy0obglZJK-igwthNLdknoSXRrGB-mvFRzyb_L-DKKefWjYdFD2888qN1ROczz4n3keYSfKz9Koj90Z6w_tQ",
+ "9": "BAsPQdCpLIGXdWNLdAwx-3J5lNqUtKbaOMV56hUj8VzxE2USLHuHHuKDeno0ymJt-acxWV1xPlBfNUShhRTR77g",
+ "10": "BNYIh_Sv03nRZUUJveE8d2mxKLIDXv654UbshaItHrCJhd6cT7pdZ_XwbdyxAOCWMkBb9AZ4t1XRCsM8-wkEBRg",
+ "11": "BA6uNfeYSvqagwu4TOY6wFK4JyU5C200vJna0lH4PJ-SzGVXej8l9dElyQ58_ljfPs5Rq6zVVXpdDe8A7Y3WRhk",
+ "12": "BMjTIlXfohI8TDymsHxo0DqYysCy7yZGJ80WhgOBR4QUd6LBDA6-_318a-jCGW96zxXKMm8clDTKpE8w75KG-FY",
+ "13": "BJBDU1P1H21IwIdT2brKkPqbQR0Zl0TIHf7Bz_OO9jaNgIwydMkxt4GpBmkYoprZ_DHUGOrno2faB7pmTR7HhuI",
+ "14": "BJFF8j-dH7pDEw_U347w2CBM6xYM8Dk5fPPAktjib-opOqzvvbsER-WDHM4ONCSBf9O_obAHzCyygxmtpktDuiE",
+ "15": "BDKyWBvLbyZ-jMueORl3JwJnnEpCiZdN7yUvT0vOyjwpPBCDf6zfL4RWzvSkhAAFnwOni_1tQSl8dfXHbXqXsQ8",
+ "16": "BDXyZZnrl0tc2jdC5I61JjwkjK2kr7uet9tZjt8StTiJTAQQmnVOYBgbtP08PWDbecxnHghx3kJ8QXq1XE68y8c",
+ "17": "BFX68cb97m9_sweGdOVavFM3j5ot6gveg6xT4BtGahfGhKib-zdZyO9pwvv1cBda9ahkSzo1BQ4NVXp9qRyqVGU",
+ }
+)
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/logger/logger.go b/vendor/github.com/keeper-security/secrets-manager-go/core/logger/logger.go
new file mode 100644
index 00000000..5dad9f53
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/logger/logger.go
@@ -0,0 +1,227 @@
+package logger
+
+import (
+ "io"
+ "log"
+ "os"
+ "runtime"
+)
+
+type LogLevel int
+
+const (
+ CriticalLevel LogLevel = iota + 1
+ ErrorLevel
+ WarningLevel
+ NoticeLevel
+ InfoLevel
+ DebugLevel
+)
+
+type Logger struct {
+ logInstance *log.Logger
+ logLevel LogLevel
+}
+
+var (
+ klog Logger
+)
+
+func init() {
+ klog = Logger{
+ logInstance: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lmicroseconds),
+ logLevel: WarningLevel,
+ }
+}
+
+func (l *Logger) logLevelString() string {
+ return logLevelString(l.logLevel)
+}
+
+func logLevelString(level LogLevel) string {
+ if level >= CriticalLevel && level <= DebugLevel {
+ logLevels := [...]string{
+ "CRITICAL",
+ "ERROR",
+ "WARNING",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ }
+ return logLevels[level-1]
+ }
+ return ""
+}
+
+func logLevelTokenString(level LogLevel) string {
+ return logLevelString(level) + ": "
+}
+
+func (l *Logger) SetLogLevel(level LogLevel) {
+ if level >= CriticalLevel && level <= DebugLevel {
+ l.logLevel = level
+ }
+}
+
+func (l *Logger) Flags() int {
+ return l.logInstance.Flags()
+}
+
+func (l *Logger) SetFlags(flag int) {
+ l.logInstance.SetFlags(flag)
+}
+
+func (l *Logger) Prefix() string {
+ return l.logInstance.Prefix()
+}
+
+func (l *Logger) SetPrefix(prefix string) {
+ l.logInstance.SetPrefix(prefix)
+}
+
+func (l *Logger) Writer() io.Writer {
+ return l.logInstance.Writer()
+}
+
+func (l *Logger) SetOutput(w io.Writer) {
+ l.logInstance.SetOutput(w)
+}
+
+func (l *Logger) Log(level LogLevel, v ...interface{}) {
+ l.logInternal(level, v...)
+}
+
+func (l *Logger) logInternal(level LogLevel, v ...interface{}) {
+ if level <= l.logLevel && level >= CriticalLevel {
+ token := logLevelTokenString(level)
+ all := append([]interface{}{token}, v...)
+ l.logInstance.Println(all...)
+ }
+}
+
+// Note! Built-in Fatal != regular log message with status FATAL
+func (l *Logger) Fatal(v ...interface{}) {
+ l.logInstance.Fatal(v...)
+}
+func (l *Logger) Fatalf(format string, v ...interface{}) {
+ l.logInstance.Fatalf(format, v...)
+}
+func (l *Logger) Fatalln(v ...interface{}) {
+ l.logInstance.Fatalln(v...)
+}
+
+func (l *Logger) Panic(v ...interface{}) {
+ l.logInstance.Panic(v...)
+}
+func (l *Logger) Panicf(format string, v ...interface{}) {
+ l.logInstance.Panicf(format, v...)
+}
+func (l *Logger) Panicln(v ...interface{}) {
+ l.logInstance.Panicln(v...)
+}
+
+func (l *Logger) Print(v ...interface{}) {
+ l.logInstance.Print(v...)
+}
+func (l *Logger) Printf(format string, v ...interface{}) {
+ l.logInstance.Printf(format, v...)
+}
+func (l *Logger) Println(v ...interface{}) {
+ l.logInstance.Println(v...)
+}
+
+func (l *Logger) PrintStack(level LogLevel, message string) {
+ if message == "" {
+ message = "Stack info"
+ }
+ message += "\n"
+ l.Log(ErrorLevel, message+Stack())
+}
+
+func Stack() string {
+ buf := make([]byte, 1000000)
+ runtime.Stack(buf, false)
+ return string(buf)
+}
+
+// public interface
+func Fatal(v ...interface{}) {
+ klog.logInstance.Fatal(v...)
+}
+func Fatalf(format string, v ...interface{}) {
+ klog.logInstance.Fatalf(format, v...)
+}
+func Fatalln(v ...interface{}) {
+ klog.logInstance.Fatalln(v...)
+}
+
+func Panic(v ...interface{}) {
+ klog.logInstance.Panic(v...)
+}
+func Panicf(format string, v ...interface{}) {
+ klog.logInstance.Panicf(format, v...)
+}
+func Panicln(v ...interface{}) {
+ klog.logInstance.Panicln(v...)
+}
+
+func Print(v ...interface{}) {
+ klog.logInstance.Print(v...)
+}
+func Printf(format string, v ...interface{}) {
+ klog.logInstance.Printf(format, v...)
+}
+func Println(v ...interface{}) {
+ klog.logInstance.Println(v...)
+}
+
+func Log(level LogLevel, v ...interface{}) {
+ klog.Log(level, v...)
+}
+
+func Critical(v ...interface{}) {
+ klog.Log(CriticalLevel, v...)
+}
+func Error(v ...interface{}) {
+ klog.Log(ErrorLevel, v...)
+}
+func Warning(v ...interface{}) {
+ klog.Log(WarningLevel, v...)
+}
+func Notice(v ...interface{}) {
+ klog.Log(NoticeLevel, v...)
+}
+func Info(v ...interface{}) {
+ klog.Log(InfoLevel, v...)
+}
+func Debug(v ...interface{}) {
+ klog.Log(DebugLevel, v...)
+}
+
+func SetLogLevel(level LogLevel) {
+ klog.SetLogLevel(level)
+}
+
+func Flags() int {
+ return klog.Flags()
+}
+
+func SetFlags(flag int) {
+ klog.SetFlags(flag)
+}
+
+func Prefix() string {
+ return klog.Prefix()
+}
+
+func SetPrefix(prefix string) {
+ klog.SetPrefix(prefix)
+}
+
+func Writer() io.Writer {
+ return klog.Writer()
+}
+
+func SetOutput(w io.Writer) {
+ klog.SetOutput(w)
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/payload.go b/vendor/github.com/keeper-security/secrets-manager-go/core/payload.go
new file mode 100644
index 00000000..7dc9f9f6
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/payload.go
@@ -0,0 +1,337 @@
+package core
+
+import (
+ "encoding/json"
+ "net/http"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+type Context struct {
+ TransmissionKey TransmissionKey
+ ClientId []byte
+ ClientKey []byte
+}
+
+func NewContext(transmissionKey TransmissionKey, clientId []byte, clientKey []byte) *Context {
+ return &Context{
+ TransmissionKey: transmissionKey,
+ ClientId: clientId,
+ ClientKey: clientKey,
+ }
+}
+
+type TransmissionKey struct {
+ PublicKeyId string
+ Key []byte
+ EncryptedKey []byte
+}
+
+func NewTransmissionKey(publicKeyId string, key []byte, encryptedKey []byte) *TransmissionKey {
+ return &TransmissionKey{
+ PublicKeyId: publicKeyId,
+ Key: key,
+ EncryptedKey: encryptedKey,
+ }
+}
+
+type GetPayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ PublicKey string `json:"publicKey,omitempty"`
+ RequestedRecords []string `json:"requestedRecords"`
+ RequestedFolders []string `json:"requestedFolders"`
+}
+
+func (p *GetPayload) GetPayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing GetPayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *GetPayload) GetPayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := GetPayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing GetPayload from JSON: " + err.Error())
+ }
+}
+
+type UpdateTransactionType string
+
+const (
+ TransactionTypeNone UpdateTransactionType = ""
+ TransactionTypeGeneral UpdateTransactionType = "general"
+ TransactionTypeRotation UpdateTransactionType = "rotation"
+)
+
+type UpdatePayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ RecordUid string `json:"recordUid"`
+ Revision int64 `json:"revision"`
+ Data string `json:"data"`
+ TransactionType UpdateTransactionType `json:"transactionType,omitempty"`
+}
+
+func (p *UpdatePayload) UpdatePayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing UpdatePayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *UpdatePayload) UpdatePayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := UpdatePayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing UpdatePayload from JSON: " + err.Error())
+ }
+}
+
+type CompleteTransactionPayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ RecordUid string `json:"recordUid"`
+}
+
+func (p *CompleteTransactionPayload) CompleteTransactionPayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing CompleteTransactionPayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *CompleteTransactionPayload) CompleteTransactionPayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := CompleteTransactionPayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing CompleteTransactionPayload from JSON: " + err.Error())
+ }
+}
+
+type CreatePayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ RecordUid string `json:"recordUid"`
+ RecordKey string `json:"recordKey"`
+ FolderUid string `json:"folderUid"`
+ FolderKey string `json:"folderKey"`
+ Data string `json:"data"`
+ SubFolderUid string `json:"subFolderUid,omitempty"`
+}
+
+func (p *CreatePayload) CreatePayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing CreatePayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *CreatePayload) CreatePayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := CreatePayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing CreatePayload from JSON: " + err.Error())
+ }
+}
+
+type DeletePayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ RecordUids []string `json:"recordUids"`
+}
+
+func (p *DeletePayload) DeletePayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing DeletePayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *DeletePayload) DeletePayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := DeletePayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing DeletePayload from JSON: " + err.Error())
+ }
+}
+
+type CreateFolderPayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ FolderUid string `json:"folderUid"`
+ SharedFolderUid string `json:"sharedFolderUid"`
+ SharedFolderKey string `json:"sharedFolderKey"`
+ Data string `json:"data"`
+ ParentUid string `json:"parentUid"`
+}
+
+func (p *CreateFolderPayload) CreateFolderPayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing CreateFolderPayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *CreateFolderPayload) CreateFolderPayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := CreateFolderPayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing CreateFolderPayload from JSON: " + err.Error())
+ }
+}
+
+type UpdateFolderPayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ FolderUid string `json:"folderUid"`
+ Data string `json:"data"`
+}
+
+func (p *UpdateFolderPayload) UpdateFolderPayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing UpdateFolderPayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *UpdateFolderPayload) UpdateFolderPayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := UpdateFolderPayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing UpdateFolderPayload from JSON: " + err.Error())
+ }
+}
+
+type DeleteFolderPayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ FolderUids []string `json:"folderUids"`
+ ForceDeletion bool `json:"forceDeletion"`
+}
+
+func (p *DeleteFolderPayload) DeleteFolderPayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing DeleteFolderPayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func (p *DeleteFolderPayload) DeleteFolderPayloadFromJson(jsonData string) {
+ bytes := []byte(jsonData)
+ res := DeleteFolderPayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ *p = res
+ } else {
+ klog.Error("Error deserializing DeleteFolderPayload from JSON: " + err.Error())
+ }
+}
+
+type FileUploadPayload struct {
+ ClientVersion string `json:"clientVersion"`
+ ClientId string `json:"clientId"`
+ FileRecordUid string `json:"fileRecordUid"`
+ FileRecordKey string `json:"fileRecordKey"`
+ FileRecordData string `json:"fileRecordData"`
+ OwnerRecordUid string `json:"ownerRecordUid"`
+ OwnerRecordData string `json:"ownerRecordData"`
+ LinkKey string `json:"linkKey"`
+ FileSize int `json:"fileSize"`
+}
+
+func (p *FileUploadPayload) FileUploadPayloadToJson() (string, error) {
+ if pb, err := json.Marshal(p); err == nil {
+ return string(pb), nil
+ } else {
+ klog.Error("Error serializing FileUploadPayload to JSON: " + err.Error())
+ return "", err
+ }
+}
+
+func FileUploadPayloadFromJson(jsonData string) *FileUploadPayload {
+ bytes := []byte(jsonData)
+ res := FileUploadPayload{}
+
+ if err := json.Unmarshal(bytes, &res); err == nil {
+ return &res
+ } else {
+ klog.Error("Error deserializing FileUploadPayload from JSON: " + err.Error())
+ return nil
+ }
+}
+
+type EncryptedPayload struct {
+ EncryptedPayload []byte
+ Signature []byte
+}
+
+func NewEncryptedPayload(encryptedPayload []byte, signature []byte) *EncryptedPayload {
+ return &EncryptedPayload{
+ EncryptedPayload: encryptedPayload,
+ Signature: signature,
+ }
+}
+
+type KsmHttpResponse struct {
+ StatusCode int
+ Data []byte
+ HttpResponse *http.Response
+}
+
+func NewKsmHttpResponse(statusCode int, data []byte, httpResponse *http.Response) *KsmHttpResponse {
+ return &KsmHttpResponse{
+ StatusCode: statusCode,
+ Data: data,
+ HttpResponse: httpResponse,
+ }
+}
+
+type QueryOptions struct {
+ RecordsFilter []string
+ FoldersFilter []string
+}
+
+type CreateOptions struct {
+ FolderUid string
+ SubFolderUid string
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/record_data.go b/vendor/github.com/keeper-security/secrets-manager-go/core/record_data.go
new file mode 100644
index 00000000..c1c4cd98
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/record_data.go
@@ -0,0 +1,783 @@
+package core
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+)
+
+type KeeperRecordData struct {
+ Type string `json:"type,omitempty"`
+ Title string `json:"title,omitempty"`
+ Notes string `json:"notes,omitempty"`
+ Fields []KeeperRecordField `json:"fields,omitempty"`
+ Custom []KeeperRecordField `json:"custom,omitempty"`
+}
+
+type KeeperRecordField struct {
+ Type string `json:"type"`
+ Label string `json:"label,omitempty"`
+}
+
+type Login struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Login field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewLogin(value string) *Login {
+ return &Login{
+ KeeperRecordField: KeeperRecordField{Type: "login"},
+ Value: []string{value},
+ }
+}
+
+type PasswordComplexity struct {
+ Length int `json:"length,omitempty"`
+ Caps int `json:"caps,omitempty"`
+ Lowercase int `json:"lowercase,omitempty"`
+ Digits int `json:"digits,omitempty"`
+ Special int `json:"special,omitempty"`
+}
+
+type Password struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ EnforceGeneration bool `json:"enforceGeneration,omitempty"`
+ Complexity *PasswordComplexity `json:"complexity,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Password field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPassword(value string) *Password {
+ return &Password{
+ KeeperRecordField: KeeperRecordField{Type: "password"},
+ Value: []string{value},
+ }
+}
+
+type Url struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Url field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewUrl(value string) *Url {
+ return &Url{
+ KeeperRecordField: KeeperRecordField{Type: "url"},
+ Value: []string{value},
+ }
+}
+
+type FileRef struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// FileRef field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewFileRef(value string) *FileRef {
+ return &FileRef{
+ KeeperRecordField: KeeperRecordField{Type: "fileRef"},
+ Value: []string{value},
+ }
+}
+
+type OneTimeCode struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// OneTimeCode field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewOneTimeCode(value string) *OneTimeCode {
+ return &OneTimeCode{
+ KeeperRecordField: KeeperRecordField{Type: "oneTimeCode"},
+ Value: []string{value},
+ }
+}
+
+type Name struct {
+ First string `json:"first,omitempty"`
+ Middle string `json:"middle,omitempty"`
+ Last string `json:"last,omitempty"`
+}
+
+type Names struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []Name `json:"value,omitempty"`
+}
+
+// Names field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewNames(value Name) *Names {
+ return &Names{
+ KeeperRecordField: KeeperRecordField{Type: "name"},
+ Value: []Name{value},
+ }
+}
+
+type BirthDate struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []int64 `json:"value,omitempty"`
+}
+
+// BirthDate field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewBirthDate(value int64) *BirthDate {
+ return &BirthDate{
+ KeeperRecordField: KeeperRecordField{Type: "birthDate"},
+ Value: []int64{value},
+ }
+}
+
+type Date struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []int64 `json:"value,omitempty"`
+}
+
+// Date field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewDate(value int64) *Date {
+ return &Date{
+ KeeperRecordField: KeeperRecordField{Type: "date"},
+ Value: []int64{value},
+ }
+}
+
+type ExpirationDate struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []int64 `json:"value,omitempty"`
+}
+
+// ExpirationDate field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewExpirationDate(value int64) *ExpirationDate {
+ return &ExpirationDate{
+ KeeperRecordField: KeeperRecordField{Type: "expirationDate"},
+ Value: []int64{value},
+ }
+}
+
+type Text struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Text field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewText(value string) *Text {
+ return &Text{
+ KeeperRecordField: KeeperRecordField{Type: "text"},
+ Value: []string{value},
+ }
+}
+
+type SecurityQuestion struct {
+ Question string `json:"question,omitempty"`
+ Answer string `json:"answer,omitempty"`
+}
+
+type SecurityQuestions struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []SecurityQuestion `json:"value,omitempty"`
+}
+
+// SecurityQuestions field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewSecurityQuestions(value SecurityQuestion) *SecurityQuestions {
+ return &SecurityQuestions{
+ KeeperRecordField: KeeperRecordField{Type: "securityQuestion"},
+ Value: []SecurityQuestion{value},
+ }
+}
+
+type Multiline struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Multiline field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewMultiline(value string) *Multiline {
+ return &Multiline{
+ KeeperRecordField: KeeperRecordField{Type: "multiline"},
+ Value: []string{value},
+ }
+}
+
+type Email struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Email field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewEmail(value string) *Email {
+ return &Email{
+ KeeperRecordField: KeeperRecordField{Type: "email"},
+ Value: []string{value},
+ }
+}
+
+type CardRef struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// CardRef field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewCardRef(value string) *CardRef {
+ return &CardRef{
+ KeeperRecordField: KeeperRecordField{Type: "cardRef"},
+ Value: []string{value},
+ }
+}
+
+type AddressRef struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// AddressRef field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewAddressRef(value string) *AddressRef {
+ return &AddressRef{
+ KeeperRecordField: KeeperRecordField{Type: "addressRef"},
+ Value: []string{value},
+ }
+}
+
+type PinCode struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// PinCode field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPinCode(value string) *PinCode {
+ return &PinCode{
+ KeeperRecordField: KeeperRecordField{Type: "pinCode"},
+ Value: []string{value},
+ }
+}
+
+type Phone struct {
+ Region string `json:"region,omitempty"` // Region code. Ex. US
+ Number string `json:"number,omitempty"` // Phone number. Ex. 510-222-5555
+ Ext string `json:"ext,omitempty"` // Extension number. Ex. 9987
+ Type string `json:"type,omitempty"` // Phone number type. Ex. Mobile
+}
+
+type Phones struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []Phone `json:"value,omitempty"`
+}
+
+// Phones field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPhones(value Phone) *Phones {
+ return &Phones{
+ KeeperRecordField: KeeperRecordField{Type: "phone"},
+ Value: []Phone{value},
+ }
+}
+
+type Secret struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// Secret field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewSecret(value string) *Secret {
+ return &Secret{
+ KeeperRecordField: KeeperRecordField{Type: "secret"},
+ Value: []string{value},
+ }
+}
+
+type SecureNote struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// SecureNote field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewSecureNote(value string) *SecureNote {
+ return &SecureNote{
+ KeeperRecordField: KeeperRecordField{Type: "note"},
+ Value: []string{value},
+ }
+}
+
+type AccountNumber struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// AccountNumber field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewAccountNumber(value string) *AccountNumber {
+ return &AccountNumber{
+ KeeperRecordField: KeeperRecordField{Type: "accountNumber"},
+ Value: []string{value},
+ }
+}
+
+type PaymentCard struct {
+ CardNumber string `json:"cardNumber,omitempty"`
+ CardExpirationDate string `json:"cardExpirationDate,omitempty"`
+ CardSecurityCode string `json:"cardSecurityCode,omitempty"`
+}
+
+type PaymentCards struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []PaymentCard `json:"value,omitempty"`
+}
+
+// PaymentCards field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPaymentCards(value PaymentCard) *PaymentCards {
+ return &PaymentCards{
+ KeeperRecordField: KeeperRecordField{Type: "paymentCard"},
+ Value: []PaymentCard{value},
+ }
+}
+
+type BankAccount struct {
+ AccountType string `json:"accountType,omitempty"`
+ RoutingNumber string `json:"routingNumber,omitempty"`
+ AccountNumber string `json:"accountNumber,omitempty"`
+ OtherType string `json:"otherType,omitempty"`
+}
+
+type BankAccounts struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []BankAccount `json:"value,omitempty"`
+}
+
+// BankAccounts field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewBankAccounts(value BankAccount) *BankAccounts {
+ return &BankAccounts{
+ KeeperRecordField: KeeperRecordField{Type: "bankAccount"},
+ Value: []BankAccount{value},
+ }
+}
+
+type KeyPair struct {
+ PublicKey string `json:"publicKey,omitempty"`
+ PrivateKey string `json:"privateKey,omitempty"`
+}
+
+type KeyPairs struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []KeyPair `json:"value,omitempty"`
+}
+
+// KeyPairs field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewKeyPairs(value KeyPair) *KeyPairs {
+ return &KeyPairs{
+ KeeperRecordField: KeeperRecordField{Type: "keyPair"},
+ Value: []KeyPair{value},
+ }
+}
+
+type Host struct {
+ Hostname string `json:"hostName,omitempty"`
+ Port string `json:"port,omitempty"`
+}
+
+type Hosts struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []Host `json:"value,omitempty"`
+}
+
+// Hosts field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewHosts(value Host) *Hosts {
+ return &Hosts{
+ KeeperRecordField: KeeperRecordField{Type: "host"},
+ Value: []Host{value},
+ }
+}
+
+type Address struct {
+ Street1 string `json:"street1,omitempty"`
+ Street2 string `json:"street2,omitempty"`
+ City string `json:"city,omitempty"`
+ State string `json:"state,omitempty"`
+ Country string `json:"country,omitempty"`
+ Zip string `json:"zip,omitempty"`
+}
+
+type Addresses struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []Address `json:"value,omitempty"`
+}
+
+// Addresses field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewAddresses(value Address) *Addresses {
+ return &Addresses{
+ KeeperRecordField: KeeperRecordField{Type: "address"},
+ Value: []Address{value},
+ }
+}
+
+type LicenseNumber struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// LicenseNumber field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewLicenseNumber(value string) *LicenseNumber {
+ return &LicenseNumber{
+ KeeperRecordField: KeeperRecordField{Type: "licenseNumber"},
+ Value: []string{value},
+ }
+}
+
+type RecordRef struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// RecordRef field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewRecordRef(value string) *RecordRef {
+ return &RecordRef{
+ KeeperRecordField: KeeperRecordField{Type: "recordRef"},
+ Value: []string{value},
+ }
+}
+
+type Schedule struct {
+ Type string `json:"type,omitempty"`
+ UtcTime string `json:"utcTime,omitempty"`
+ Weekday string `json:"weekday,omitempty"`
+ IntervalCount int `json:"intervalCount,omitempty"`
+}
+
+type Schedules struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []Schedule `json:"value,omitempty"`
+}
+
+// Schedules field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewSchedules(value Schedule) *Schedules {
+ return &Schedules{
+ KeeperRecordField: KeeperRecordField{Type: "schedule"},
+ Value: []Schedule{value},
+ }
+}
+
+type DirectoryType struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// DirectoryType field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewDirectoryType(value string) *DirectoryType {
+ return &DirectoryType{
+ KeeperRecordField: KeeperRecordField{Type: "directoryType"},
+ Value: []string{value},
+ }
+}
+
+type DatabaseType struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []string `json:"value,omitempty"`
+}
+
+// DatabaseType field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewDatabaseType(value string) *DatabaseType {
+ return &DatabaseType{
+ KeeperRecordField: KeeperRecordField{Type: "databaseType"},
+ Value: []string{value},
+ }
+}
+
+type PamHostname struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []Host `json:"value,omitempty"`
+}
+
+// PamHostname field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPamHostname(value Host) *PamHostname {
+ return &PamHostname{
+ KeeperRecordField: KeeperRecordField{Type: "pamHostname"},
+ Value: []Host{value},
+ }
+}
+
+type PamResource struct {
+ ControllerUid string `json:"controllerUid,omitempty"`
+ FolderUid string `json:"folderUid,omitempty"`
+ ResourceRef []string `json:"resourceRef,omitempty"`
+}
+
+type PamResources struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []PamResource `json:"value,omitempty"`
+}
+
+// PamResources field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPamResources(value PamResource) *PamResources {
+ return &PamResources{
+ KeeperRecordField: KeeperRecordField{Type: "pamResources"},
+ Value: []PamResource{value},
+ }
+}
+
+type Checkbox struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []bool `json:"value,omitempty"`
+}
+
+// Checkbox field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewCheckbox(value bool) *Checkbox {
+ return &Checkbox{
+ KeeperRecordField: KeeperRecordField{Type: "checkbox"},
+ Value: []bool{value},
+ }
+}
+
+type Script struct {
+ FileRef string `json:"fileRef,omitempty"`
+ Command string `json:"command,omitempty"`
+ RecordRef []string `json:"recordRef,omitempty"`
+}
+
+type Scripts struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ PrivacyScreen bool `json:"privacyScreen,omitempty"`
+ Value []Script `json:"value,omitempty"`
+}
+
+// Scripts field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewScripts(value Script) *Scripts {
+ return &Scripts{
+ KeeperRecordField: KeeperRecordField{Type: "script"},
+ Value: []Script{value},
+ }
+}
+
+type PasskeyPrivateKey struct {
+ Crv string `json:"crv,omitempty"`
+ D string `json:"d,omitempty"`
+ Ext bool `json:"ext,omitempty"`
+ KeyOps []string `json:"key_ops,omitempty"`
+ Kty string `json:"kty,omitempty"`
+ X string `json:"x,omitempty"`
+ Y int64 `json:"y,omitempty"`
+}
+
+type Passkey struct {
+ PrivateKey PasskeyPrivateKey `json:"privateKey,omitempty"`
+ CredentialId string `json:"credentialId,omitempty"`
+ SignCount int64 `json:"signCount,omitempty"`
+ UserId string `json:"userId,omitempty"`
+ RelyingParty string `json:"relyingParty,omitempty"`
+ Username string `json:"username,omitempty"`
+ CreatedDate int64 `json:"createdDate,omitempty"`
+}
+
+type Passkeys struct {
+ KeeperRecordField
+ Required bool `json:"required,omitempty"`
+ Value []Passkey `json:"value,omitempty"`
+}
+
+// Passkeys field constructor with the single value to eliminate the complexity of the passing List as a value
+func NewPasskeys(value Passkey) *Passkeys {
+ return &Passkeys{
+ KeeperRecordField: KeeperRecordField{Type: "passkey"},
+ Value: []Passkey{value},
+ }
+}
+
+// getKeeperRecordField converts fieldData from generic interface{} to strongly typed interface{}
+func getKeeperRecordField(fieldType string, fieldData map[string]interface{}, validate bool) (field interface{}, err error) {
+ if jsonField := DictToJson(fieldData); strings.TrimSpace(jsonField) != "" {
+ switch fieldType {
+ case "login":
+ field = &Login{}
+ case "password":
+ field = &Password{}
+ case "url":
+ field = &Url{}
+ case "fileRef":
+ field = &FileRef{}
+ case "oneTimeCode":
+ field = &OneTimeCode{}
+ case "name":
+ field = &Names{}
+ case "birthDate":
+ field = &BirthDate{}
+ case "date":
+ field = &Date{}
+ case "expirationDate":
+ field = &ExpirationDate{}
+ case "text":
+ field = &Text{}
+ case "securityQuestion":
+ field = &SecurityQuestions{}
+ case "multiline":
+ field = &Multiline{}
+ case "email":
+ field = &Email{}
+ case "cardRef":
+ field = &CardRef{}
+ case "addressRef":
+ field = &AddressRef{}
+ case "pinCode":
+ field = &PinCode{}
+ case "phone":
+ field = &Phones{}
+ case "secret":
+ field = &Secret{}
+ case "note":
+ field = &SecureNote{}
+ case "accountNumber":
+ field = &AccountNumber{}
+ case "paymentCard":
+ field = &PaymentCards{}
+ case "bankAccount":
+ field = &BankAccounts{}
+ case "keyPair":
+ field = &KeyPairs{}
+ case "host":
+ field = &Hosts{}
+ case "address":
+ field = &Addresses{}
+ case "licenseNumber":
+ field = &LicenseNumber{}
+ case "recordRef":
+ field = &RecordRef{}
+ case "schedule":
+ field = &Schedules{}
+ case "directoryType":
+ field = &DirectoryType{}
+ case "databaseType":
+ field = &DatabaseType{}
+ case "pamHostname":
+ field = &PamHostname{}
+ case "pamResources":
+ field = &PamResources{}
+ case "checkbox":
+ field = &Checkbox{}
+ case "script":
+ field = &Scripts{}
+ case "passkey":
+ field = &Passkeys{}
+ default:
+ return nil, fmt.Errorf("unable to convert unknown field type %v", fieldType)
+ }
+
+ if validate {
+ decoder := json.NewDecoder(strings.NewReader(jsonField))
+ decoder.DisallowUnknownFields()
+ err = decoder.Decode(field)
+ } else {
+ err = json.Unmarshal([]byte(jsonField), field)
+ }
+ return
+ } else {
+ return nil, fmt.Errorf("unable to parse field from JSON '%v'", fieldData)
+ }
+}
+
+func IsFieldClass(field interface{}) bool {
+ switch field.(type) {
+ case
+ AccountNumber, *AccountNumber,
+ AddressRef, *AddressRef,
+ Addresses, *Addresses,
+ BankAccounts, *BankAccounts,
+ BirthDate, *BirthDate,
+ CardRef, *CardRef,
+ Checkbox, *Checkbox,
+ DatabaseType, *DatabaseType,
+ Date, *Date,
+ DirectoryType, *DirectoryType,
+ Email, *Email,
+ ExpirationDate, *ExpirationDate,
+ FileRef, *FileRef,
+ Hosts, *Hosts,
+ KeyPairs, *KeyPairs,
+ LicenseNumber, *LicenseNumber,
+ Login, *Login,
+ Multiline, *Multiline,
+ Names, *Names,
+ OneTimeCode, *OneTimeCode,
+ Password, *Password,
+ PamHostname, *PamHostname,
+ PamResources, *PamResources,
+ PaymentCards, *PaymentCards,
+ Phones, *Phones,
+ PinCode, *PinCode,
+ RecordRef, *RecordRef,
+ Schedules, *Schedules,
+ Secret, *Secret,
+ SecureNote, *SecureNote,
+ SecurityQuestions, *SecurityQuestions,
+ Text, *Text,
+ Url, *Url,
+ Scripts, *Scripts,
+ Passkeys, *Passkeys:
+ return true
+ }
+ return false
+}
+
+func structToMap(data interface{}) (map[string]interface{}, error) {
+ dataBytes, err := json.Marshal(data)
+ if err != nil {
+ return nil, err
+ }
+ mapData := make(map[string]interface{})
+ err = json.Unmarshal(dataBytes, &mapData)
+ if err != nil {
+ return nil, err
+ }
+ return mapData, nil
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/storage.go b/vendor/github.com/keeper-security/secrets-manager-go/core/storage.go
new file mode 100644
index 00000000..77d4ee21
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/storage.go
@@ -0,0 +1,298 @@
+package core
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "unicode/utf8"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+const (
+ DEFAULT_CONFIG_PATH string = "client-config.json"
+)
+
+type IKeyValueStorage interface {
+ ReadStorage() map[string]interface{}
+ SaveStorage(updatedConfig map[string]interface{})
+ Get(key ConfigKey) string
+ Set(key ConfigKey, value interface{}) map[string]interface{}
+ Delete(key ConfigKey) map[string]interface{}
+ DeleteAll() map[string]interface{}
+ Contains(key ConfigKey) bool
+ IsEmpty() bool
+}
+
+// File based implementation of the key value storage
+type fileKeyValueStorage struct {
+ ConfigPath string
+}
+
+func (f *fileKeyValueStorage) ReadStorage() map[string]interface{} {
+ f.createConfigFileIfMissing()
+ content, err := ioutil.ReadFile(f.ConfigPath)
+ if err != nil {
+ klog.Error("Unable to open file: " + f.ConfigPath + " Error: " + err.Error())
+ return map[string]interface{}{}
+ }
+
+ // RFC3629 - having the BOM in JSON string is forbidden
+ // Implementations MUST NOT add a byte order mark (U+FEFF)
+ // Implementations that parse JSON texts MAY ignore BOM rather than treating it as an error.
+ // In JSON BOM is useless and will always appear as the octet sequence EF BB BF.
+ if len(content) >= 3 && content[0] == 0xef && content[1] == 0xbb && content[2] == 0xbf {
+ content = content[3:]
+ }
+
+ // check for valid UTF-8, check for UTF-16 BE/LE separately
+ // all 128 ASCII chars are also valid UTF-8 but 0x00 must be escaped in JSON
+ if !utf8.Valid(content) ||
+ (len(content) > 1 && (content[0] == 0 || content[1] == 0)) {
+ klog.Error("Config file is not utf-8 encoded JSON.")
+ return map[string]interface{}{}
+ }
+
+ // If it was an empty file, overwrite with the JSON config
+ content = bytes.TrimSpace(content)
+ if len(content) == 0 {
+ klog.Warning("Looks like config file is empty.")
+ content = []byte("{}")
+ }
+
+ var payload map[string]interface{}
+ err = json.Unmarshal(content, &payload)
+ if err != nil {
+ klog.Error("Error parsing JSON configuration file: " + err.Error())
+ return map[string]interface{}{}
+ }
+ return payload
+}
+
+func (f *fileKeyValueStorage) SaveStorage(updatedConfig map[string]interface{}) {
+ f.createConfigFileIfMissing()
+ content, err := json.MarshalIndent(updatedConfig, "", " ")
+ if err != nil {
+ klog.Error("Error writing JSON: " + err.Error())
+ return
+ }
+ if err := ioutil.WriteFile(f.ConfigPath, content, 0666); err != nil {
+ klog.Error("Error writing JSON configuration file: " + err.Error())
+ }
+}
+
+func (f *fileKeyValueStorage) Get(key ConfigKey) string {
+ config := f.ReadStorage()
+ if value, found := config[string(key)]; found {
+ if strValue, ok := value.(string); ok {
+ return strValue
+ }
+ }
+ return ""
+}
+
+func (f *fileKeyValueStorage) Set(key ConfigKey, value interface{}) map[string]interface{} {
+ config := f.ReadStorage()
+ config[string(key)] = value
+ f.SaveStorage(config)
+ return config
+}
+
+func (f *fileKeyValueStorage) Delete(key ConfigKey) map[string]interface{} {
+ config := f.ReadStorage()
+ kv := string(key)
+ if _, found := config[kv]; found {
+ delete(config, kv)
+ klog.Debug("Removed key: " + kv)
+ } else {
+ klog.Warning(fmt.Sprintf("No key '%s' was found in config", kv))
+ }
+
+ f.SaveStorage(config)
+ return config
+}
+
+func (f *fileKeyValueStorage) DeleteAll() map[string]interface{} {
+ config := f.ReadStorage()
+
+ for k := range config {
+ delete(config, k)
+ }
+
+ f.SaveStorage(config)
+
+ return config
+}
+
+func (f *fileKeyValueStorage) Contains(key ConfigKey) bool {
+ config := f.ReadStorage()
+ _, found := config[string(key)]
+ return found
+}
+
+func (f *fileKeyValueStorage) IsEmpty() bool {
+ config := f.ReadStorage()
+
+ return len(config) == 0
+}
+
+func (f *fileKeyValueStorage) createConfigFileIfMissing() {
+ if ok, err := PathExists(f.ConfigPath); !ok {
+ if err != nil {
+ klog.Error("Error accessing config file: " + err.Error())
+ }
+
+ if err := os.MkdirAll(filepath.Dir(f.ConfigPath), 0755); err != nil {
+ klog.Error("Error creating folders: " + err.Error())
+ }
+
+ if c, err := os.Create(f.ConfigPath); err == nil {
+ defer c.Close()
+ if _, err := c.WriteString("{}"); err != nil {
+ klog.Error("Failed to write config content: " + err.Error())
+ }
+ } else {
+ klog.Error("Unable to create file: " + err.Error())
+ }
+ }
+}
+
+func NewFileKeyValueStorage(filePath ...interface{}) *fileKeyValueStorage {
+ configPath := DEFAULT_CONFIG_PATH
+
+ if len(filePath) > 0 {
+ switch t := filePath[0].(type) {
+ case string:
+ configPath = t
+ default:
+ klog.Warning("Incorrect config file path - switching to default config path.")
+ }
+ } else if envKeeperConfigFile := strings.TrimSpace(os.Getenv("KSM_CONFIG_FILE")); envKeeperConfigFile != "" {
+ configPath = envKeeperConfigFile
+ }
+
+ return &fileKeyValueStorage{
+ ConfigPath: configPath,
+ }
+}
+
+// Memory based implementation of the key value storage
+type memoryKeyValueStorage struct {
+ Config map[ConfigKey]string
+}
+
+func NewMemoryKeyValueStorage(config ...interface{}) *memoryKeyValueStorage {
+ iConfig := make(map[string]interface{})
+ sConfig := make(map[string]string)
+ if len(config) > 0 {
+ switch t := config[0].(type) {
+ case string:
+ jsonStr := t
+ // Decode if config json was provided as base64 string
+ oldWriter := klog.Writer()
+ klog.SetOutput(io.Discard)
+ if decodedJson := Base64ToString(jsonStr); len(decodedJson) > 2 {
+ jsonStr = decodedJson
+ }
+ klog.SetOutput(oldWriter)
+
+ iConfig = JsonToDict(jsonStr)
+ if len(iConfig) == 0 {
+ strJson := fmt.Sprintf("%.16s", t)
+ if len(t) > len(strJson) {
+ strJson += "..."
+ }
+ klog.Error(fmt.Sprintf("Could not load config data. Text size: %d Text: '%s'", len(t), strJson))
+ }
+ case map[string]interface{}:
+ iConfig = t
+ case map[string]string:
+ sConfig = t
+ default:
+ klog.Error(fmt.Sprintf("skipping unsupported config type '%v'", t))
+ }
+ }
+ if len(iConfig) > 0 {
+ for key, value := range iConfig {
+ switch value := value.(type) {
+ case string:
+ sConfig[key] = value
+ default:
+ klog.Error(fmt.Sprintf("skipping Config['%s'] - unsupported value type '%v'", key, value))
+ }
+ }
+ }
+
+ newConfig := make(map[ConfigKey]string)
+ for key, value := range sConfig {
+ if k := GetConfigKey(key); k != "" {
+ newConfig[k] = value
+ } else {
+ klog.Error("skipping unknown config key value: " + key)
+ }
+ }
+
+ return &memoryKeyValueStorage{
+ Config: newConfig,
+ }
+}
+
+func (m *memoryKeyValueStorage) ReadStorage() map[string]interface{} {
+ // To match what FileKeyValueStorage does, we need to return the enum values as keys
+ // instead of the enum keys
+ dictConfig := map[string]interface{}{}
+ for key, value := range m.Config {
+ dictConfig[string(key)] = value
+ }
+
+ return dictConfig
+}
+
+func (m *memoryKeyValueStorage) SaveStorage(updatedConfig map[string]interface{}) {}
+
+func (m *memoryKeyValueStorage) Get(key ConfigKey) string {
+ if val, ok := m.Config[key]; ok {
+ return val
+ }
+ return ""
+}
+
+func (m *memoryKeyValueStorage) Set(key ConfigKey, value interface{}) map[string]interface{} {
+ switch v := value.(type) {
+ case string:
+ m.Config[key] = v
+ return m.ReadStorage()
+ default:
+ klog.Error(fmt.Sprintf("Unknown value for ConfigKey: %s, Value: %v", string(key), v))
+ }
+ return nil
+}
+
+func (m *memoryKeyValueStorage) Delete(key ConfigKey) map[string]interface{} {
+ if _, found := m.Config[key]; found {
+ delete(m.Config, key)
+ klog.Debug("Removed key: " + key)
+ } else {
+ klog.Warning(fmt.Sprintf("No key '%s' was found in config", string(key)))
+ }
+ return m.ReadStorage()
+}
+
+func (m *memoryKeyValueStorage) DeleteAll() map[string]interface{} {
+ m.Config = map[ConfigKey]string{}
+ return m.ReadStorage()
+}
+
+func (m *memoryKeyValueStorage) Contains(key ConfigKey) bool {
+ _, found := m.Config[key]
+ return found
+}
+
+func (m *memoryKeyValueStorage) IsEmpty() bool {
+ return len(m.Config) == 0
+}
diff --git a/vendor/github.com/keeper-security/secrets-manager-go/core/utils.go b/vendor/github.com/keeper-security/secrets-manager-go/core/utils.go
new file mode 100644
index 00000000..65d83161
--- /dev/null
+++ b/vendor/github.com/keeper-security/secrets-manager-go/core/utils.go
@@ -0,0 +1,715 @@
+package core
+
+import (
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/base32"
+ "encoding/base64"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "hash"
+ "math"
+ "math/big"
+ "net/url"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+
+ klog "github.com/keeper-security/secrets-manager-go/core/logger"
+)
+
+// ECDSASignature needed for compatibility with openssl (python > hazmat > openssl > ec > _ecdsa_sig_sign)
+// which uses ASN.1/DER SEQUENCE format
+// NB! MaxLen for ASN.1, depends on the encoding. P1363 only needs 64 bytes. And an OpePGP encoding only needs 66 bytes.
+// ECDSASignature using ASN.1/DER needs up to 72 bytes. DER requires a minimum number of bytes.
+// If ASN.1/BER is used, then the signature can be hundreds of bytes.
+type ECDSASignature struct {
+ R, S *big.Int
+}
+
+func GetOS() string {
+ os := runtime.GOOS
+ switch os {
+ case "windows":
+ return "Windows"
+ case "darwin":
+ return "MacOS"
+ case "linux":
+ return "Linux"
+ default:
+ return os
+ }
+}
+
+func BytesToString(b []byte) string {
+ return string(b)
+}
+
+func StringToBytes(s string) []byte {
+ return []byte(s)
+}
+
+func ByteToInt(b []byte) string {
+ return string(b)
+}
+
+func BytesToUrlSafeStr(data []byte) string {
+ return base64.RawURLEncoding.EncodeToString(data)
+}
+
+func UrlSafeStrToBytes(text string) []byte {
+ text = strings.TrimRight(text, "=")
+ // fix non URL Safe strings
+ text = strings.ReplaceAll(text, "+", "-")
+ text = strings.ReplaceAll(text, "/", "_")
+
+ if result, err := base64.RawURLEncoding.DecodeString(text); err != nil {
+ klog.Error("error converting base64 URL safe string to bytes - text: '" + text + "' - " + err.Error())
+ return nil
+ } else {
+ return result
+ }
+}
+
+// UrlSafeStrToBytesSafe decodes base64 text to bytes, returns empty byte slice on error
+func UrlSafeStrToBytesSafe(text string) []byte {
+ text = strings.TrimRight(text, "=")
+ result, err := base64.RawURLEncoding.DecodeString(text)
+ if err != nil {
+ result = []byte{}
+ }
+ return result
+}
+
+func BytesToBase64(data []byte) string {
+ return base64.StdEncoding.EncodeToString(data)
+}
+
+func Base64ToBytes(text string) []byte {
+ return UrlSafeStrToBytes(text)
+}
+
+func Base64ToString(base64Text string) string {
+ if bytes := UrlSafeStrToBytes(base64Text); len(bytes) > 0 {
+ return BytesToString(bytes)
+ }
+ return ""
+}
+
+func Base64ToStringSafe(base64Text string) string {
+ if bytes := UrlSafeStrToBytesSafe(base64Text); len(bytes) > 0 {
+ return BytesToString(bytes)
+ }
+ return ""
+}
+
+func GetRandomBytes(size int) ([]byte, error) {
+ data := make([]byte, size)
+ _, err := rand.Read(data)
+ return data, err
+}
+
+func ClearBytes(bytes []byte) {
+ for i := range bytes {
+ bytes[i] = 0
+ }
+}
+
+func GenerateRandomBytes(size int) ([]byte, error) {
+ return GetRandomBytes(size)
+}
+
+func GenerateUid() string {
+ uid, _ := GetRandomBytes(16)
+ return BytesToUrlSafeStr(uid)
+}
+
+func GenerateUidWithLength(bitLength int) string {
+ if bitLength < 1 {
+ return ""
+ }
+
+ bitmask := byte(0xFF)
+ byteLength := bitLength / 8
+ if bitLength%8 > 0 {
+ byteLength++
+ bitmask = byte(0x00)
+ for i := 0; i < bitLength%8; i++ {
+ bitmask |= (byte(0x01) << (7 - i))
+ }
+ }
+
+ uid, _ := GetRandomBytes(byteLength)
+ if bitmask != byte(0xFF) {
+ uid = append(uid[:len(uid)-1], uid[len(uid)-1]&bitmask)
+ }
+
+ return BytesToUrlSafeStr(uid)
+}
+
+// UrlSafeSha256FromString generates URL safe encoded SHA256 sum of data in URL safe base64 encoded string
+func UrlSafeSha256FromString(text string) string {
+ if text == "" {
+ return ""
+ }
+
+ bytes := UrlSafeStrToBytes(text)
+ if len(bytes) == 0 {
+ return ""
+ }
+
+ sha256 := sha256.Sum256(bytes)
+ result := BytesToUrlSafeStr(sha256[:])
+ return result
+}
+
+// Base64HmacFromString generates base64 encoded HMAC of the message string with the given key
+func Base64HmacFromString(key []byte, message string) string {
+ msgBytes := StringToBytes(message)
+ hmac := HmacDigest(key, msgBytes)
+ result := BytesToBase64(hmac)
+ return result
+}
+
+func HmacDigest(key []byte, message []byte) []byte {
+ mac := hmac.New(sha512.New, key)
+ mac.Write(message)
+ result := mac.Sum(nil)
+ return result
+}
+
+func JsonToDict(content string) map[string]interface{} {
+ var payload map[string]interface{}
+ err := json.Unmarshal([]byte(content), &payload)
+ if err != nil {
+ klog.Error("Error parsing JSON: " + err.Error())
+ return map[string]interface{}{}
+ }
+ return payload
+}
+
+func DictToJson(dict map[string]interface{}) string {
+ content, err := json.Marshal(dict)
+ if err != nil {
+ klog.Error("Error converting to JSON: " + err.Error())
+ return ""
+ }
+ return string(content)
+}
+
+func DictToJsonWithIndent(dict map[string]interface{}, indent string) string {
+ content, err := json.MarshalIndent(dict, "", indent)
+ if err != nil {
+ klog.Error("Error converting to JSON: " + err.Error())
+ return ""
+ }
+ return string(content)
+}
+
+func DictToJsonWithDefultIndent(dict map[string]interface{}) string {
+ return DictToJsonWithIndent(dict, " ")
+}
+
+func NowMilliseconds() int64 {
+ // time.Now().UnixMilli() // requires go1.17+
+ return time.Now().UnixNano() / int64(time.Millisecond)
+}
+
+var strToBoolMap = map[string]bool{
+ "y": true,
+ "yes": true,
+ "t": true,
+ "true": true,
+ "on": true,
+ "1": true,
+ "n": false,
+ "no": false,
+ "f": false,
+ "false": false,
+ "off": false,
+ "0": false,
+}
+
+// StrToBool convert a string representation of truth to a boolean true or false.
+func StrToBool(val string) (bool, error) {
+ // true values are 'y', 'yes', 't', 'true', 'on', and '1'
+ // false values are 'n', 'no', 'f', 'false', 'off', and '0'.
+ val = strings.ToLower(val)
+ if res, ok := strToBoolMap[val]; ok {
+ return res, nil
+ }
+ return false, fmt.Errorf("invalid truth value %s", val)
+}
+
+// PathExists returns whether the given file or directory exists
+func PathExists(path string) (bool, error) {
+ if _, err := os.Stat(path); err == nil {
+ return true, nil
+ } else if os.IsNotExist(err) {
+ return false, nil
+ } else {
+ return false, err
+ }
+}
+
+func CloneByteSlice(src []byte) []byte {
+ if src == nil {
+ return nil
+ } else {
+ dst := make([]byte, len(src))
+ copy(dst, src)
+ return dst
+ }
+}
+
+type CopyableMap map[string]interface{}
+type CopyableSlice []interface{}
+
+// DeepCopy will create a deep copy of this map.
+// The depth of this copy is all inclusive.
+// Both maps and slices will be considered when making the copy.
+func (m CopyableMap) DeepCopy() map[string]interface{} {
+ result := map[string]interface{}{}
+
+ for k, v := range m {
+ if mapvalue, isMap := v.(map[string]interface{}); isMap {
+ result[k] = CopyableMap(mapvalue).DeepCopy()
+ continue
+ }
+
+ if slicevalue, isSlice := v.([]interface{}); isSlice {
+ result[k] = CopyableSlice(slicevalue).DeepCopy()
+ continue
+ }
+
+ result[k] = v
+ }
+
+ return result
+}
+
+// DeepCopy will create a deep copy of this slice.
+// The depth of this copy is all inclusive.
+// Both maps and slices will be considered when making the copy.
+func (s CopyableSlice) DeepCopy() []interface{} {
+ result := []interface{}{}
+
+ for _, v := range s {
+ if mapvalue, isMap := v.(map[string]interface{}); isMap {
+ result = append(result, CopyableMap(mapvalue).DeepCopy())
+ continue
+ }
+
+ if slicevalue, isSlice := v.([]interface{}); isSlice {
+ result = append(result, CopyableSlice(slicevalue).DeepCopy())
+ continue
+ }
+
+ result = append(result, v)
+ }
+
+ return result
+}
+
+// Generate TOTP/HOTP codes - RFC 6238/RFC 4226
+
+// TOTP represents Time-based OTP - https://datatracker.ietf.org/doc/html/rfc6238
+type TOTP struct {
+ Secret string // Secret key (required)
+ Digits int // OTP digit count (default: 6)
+ Algorithm string // OTP Algorithm ("SHA1" or "SHA256" or "SHA512") (default: SHA1)
+ Period int64 // Period for which OTP is valid (seconds) (default: 30) == X in RFC6238
+ UnixTime int64 // (Optional) Unix Timestamp (default: Current unix timestamp)
+}
+
+// HOTP represents HMAC-Based OTP - https://datatracker.ietf.org/doc/html/rfc4226
+type HOTP struct {
+ Secret string // Secret key (required)
+ Digits int // OTP digit count (default: 6)
+ Counter int64 // Counter value (default: 0)
+}
+
+// TotpCode provides detailed info about the generated TOTP code
+type TotpCode struct {
+ Code string // TOTP Code
+ TimeLeft int // Time left in seconds (time before expiration)
+ Period int // Period in seconds
+}
+
+// Generates TOTP code from the URL and returns OTP as string, seconds remaining and any error encountered.
+func GetTotpCode(totpUrl string) (*TotpCode, error) {
+ // https://github.com/google/google-authenticator/wiki/Key-Uri-Format
+ // ex. otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30
+ u, err := url.Parse(totpUrl)
+ if err != nil || strings.ToLower(u.Scheme) != "otpauth" {
+ return nil, errors.New("invalid TOTP URL: " + totpUrl)
+ }
+ m, err := url.ParseQuery(u.RawQuery)
+ if err != nil {
+ return nil, errors.New("invalid TOTP URL query values: " + u.RawQuery)
+ }
+
+ secret := ""
+ digits := 6
+ algorithm := "SHA1"
+ period := int64(30)
+
+ // the only required parameter is the secret
+ if value, ok := m["secret"]; ok {
+ secret = strings.TrimSpace(value[0])
+ }
+
+ // fallback to defaults for optional parameters
+ if value, ok := m["digits"]; ok {
+ if d, err := strconv.Atoi(value[0]); err == nil {
+ digits = d
+ }
+ }
+ if value, ok := m["algorithm"]; ok && strings.TrimSpace(value[0]) != "" {
+ algorithm = strings.TrimSpace(value[0])
+ }
+ if value, ok := m["period"]; ok {
+ if d, err := strconv.Atoi(value[0]); err == nil {
+ period = int64(d)
+ }
+ }
+
+ totp := TOTP{
+ Secret: secret,
+ Digits: digits,
+ Algorithm: algorithm,
+ Period: period,
+ }
+
+ if code, ttl, err := totp.Generate(); err == nil {
+ return &TotpCode{
+ Code: code,
+ TimeLeft: ttl,
+ Period: int(period),
+ }, nil
+ } else {
+ return nil, err
+ }
+}
+
+// Generates TOTP code and returns OTP as string, seconds remaining and any error encountered.
+func (totp *TOTP) Generate() (code string, seconds int, err error) {
+ var T0 int64 = 0 // initial counter time / start time
+ var currentUnixTime int64
+
+ if totp.Secret == "" {
+ return "", 0, errors.New("TOTP secret key required")
+ }
+
+ if totp.Digits == 0 {
+ totp.Digits = 6
+ }
+
+ if totp.Algorithm == "" {
+ totp.Algorithm = "SHA1"
+ }
+
+ if totp.Period == 0 {
+ totp.Period = 30
+ }
+
+ if totp.UnixTime != 0 {
+ currentUnixTime = totp.UnixTime // get OTP at the given timestamp
+ } else {
+ currentUnixTime = time.Now().Unix() - T0 // get OTP at current timestamp
+ }
+
+ counter := currentUnixTime / totp.Period
+ code, err = generateOTP(totp.Secret, counter, totp.Digits, totp.Algorithm)
+ seconds = int(totp.Period - currentUnixTime%totp.Period)
+ return
+}
+
+// Generates HOTP code and returns OTP as string and any error encountered.
+func (hotp *HOTP) Generate() (string, error) {
+
+ if hotp.Secret == "" {
+ return "", errors.New("HOTP secret key required")
+ }
+
+ if hotp.Digits == 0 {
+ hotp.Digits = 6
+ }
+
+ return generateOTP(hotp.Secret, hotp.Counter, hotp.Digits, "SHA1")
+}
+
+// Generates TOTP/HOTP code.
+func generateOTP(base32Key string, counter int64, digits int, algo string) (string, error) {
+ counterBytes := make([]byte, 8)
+ binary.BigEndian.PutUint64(counterBytes, uint64(counter)) // convert counter to byte array
+ rawBase32Key := strings.TrimRight(base32Key, "=") // remove padding and use RawEncoding
+ secretKey, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(rawBase32Key)
+ if err != nil {
+ return "", errors.New("bad OTP secret key: " + err.Error())
+ }
+
+ var hasher hash.Hash
+ switch strings.ToUpper(algo) {
+ case "SHA1":
+ hasher = hmac.New(sha1.New, secretKey)
+ case "SHA256":
+ hasher = hmac.New(sha256.New, secretKey)
+ case "SHA512":
+ hasher = hmac.New(sha512.New, secretKey)
+ // although once part of Google Key Uri Format - https://github.com/google/google-authenticator/wiki/Key-Uri-Format/_history
+ // removed MD5 as unreliable - only digests of length >= 20 can be used (MD5 has a digest length of 16)
+ // case AlgorithmMD5:
+ // hasher = md5.New()
+ default:
+ return "", errors.New("invalid OTP algorithm. Please use any one of SHA1/SHA256/SHA512")
+ }
+
+ if _, err = hasher.Write(counterBytes); err != nil {
+ return "", errors.New("unable to compute HMAC: " + err.Error())
+ }
+
+ hash := hasher.Sum(nil)
+
+ // truncate hash
+ offset := hash[len(hash)-1] & 0x0F
+ hash = hash[offset : offset+4]
+ hash[0] = hash[0] & 0x7F
+
+ decimal := binary.BigEndian.Uint32(hash)
+ otp := decimal % uint32(math.Pow10(digits))
+
+ result := strconv.Itoa(int(otp))
+ if len(result) < digits {
+ padded := strings.Repeat("0", digits) + result
+ result = padded[len(padded)-digits:]
+ }
+
+ return result, nil
+}
+
+// Generate password
+const DefaultPasswordLength int = 32
+const AsciiLowercase string = "abcdefghijklmnopqrstuvwxyz"
+const AsciiUppercase string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+const AsciiDigits string = "0123456789"
+const AsciiSpecialCharacters string = "\"!@#$%()+;<>=?[]{}^.,"
+
+func randomSample(sampleLength int, sampleString string) (string, error) {
+ if sampleLength > 0 && sampleString != "" {
+ letters := []rune(sampleString)
+ b := make([]rune, sampleLength)
+ sampleStringLen := new(big.Int).SetInt64(int64(len(sampleString)))
+ for i := range b {
+ // Int returns a uniform random value in [0, max)
+ r, err := rand.Int(rand.Reader, sampleStringLen)
+ if err != nil {
+ return "", fmt.Errorf("can't generate random value: %v, %v", i, err)
+ }
+ b[i] = letters[int(r.Int64())]
+ }
+ return string(b), nil
+ }
+ return "", nil
+}
+
+func shuffleString(text string) (string, error) {
+ result := ""
+ if text != "" {
+ letters := []rune(text)
+ for i := len(letters) - 1; i >= 1; i-- {
+ n := new(big.Int).SetInt64(int64(i + 1))
+ // Int returns a uniform random value in [0, max)
+ bj, err := rand.Int(rand.Reader, n) // 0 <= j <= i
+ if err != nil {
+ return "", fmt.Errorf("can't generate random value: %v, %v", i, err)
+ }
+ if j := int(bj.Int64()); i != j {
+ letters[i], letters[j] = letters[j], letters[i]
+ }
+ }
+ return string(letters), nil
+ }
+ return result, nil
+}
+
+// PasswordOptions provides complexity settings for GeneratePasswordWithOptions
+// Positive values specify minimum length, zero or negative - exact length
+// Generated password must have at least MinLength characters - exact values may be converted to min values
+// Empty strings or missing values will be substituted with a reasonable defaults
+// ex. passing nil will generate password with length = DefaultPasswordLength using all charsets
+type PasswordOptions struct {
+ MinLength string
+ UppercaseLength string
+ LowercaseLength string
+ DigitsLength string
+ SpecialCharactersLength string
+ SpecialCharacterSet string
+}
+
+// GeneratePasswordWithOptions generates new password using provided options
+// If options is nil the new password will be generated using defaults
+// All lengths are optional and substituted with reasonable defaults when missing
+// To exclude a charset - set corresponding option to 0
+// To use default length value - set its option to empty string ""
+// Note: Any strings containing non integer values will be treated as empty string
+func GeneratePasswordWithOptions(options *PasswordOptions) (string, error) {
+ if options == nil {
+ return GeneratePassword(DefaultPasswordLength, "", "", "", "", AsciiSpecialCharacters)
+ }
+
+ minLength := 0
+ if i, err := strconv.Atoi(options.MinLength); err == nil {
+ minLength = i
+ } else {
+ minLength = DefaultPasswordLength
+ klog.Warning("error converting MinLength='" + options.MinLength + "' to int - switching to default length: " + strconv.Itoa(DefaultPasswordLength))
+ }
+ return GeneratePassword(minLength,
+ options.LowercaseLength,
+ options.UppercaseLength,
+ options.DigitsLength,
+ options.SpecialCharactersLength,
+ options.SpecialCharacterSet)
+}
+
+// GeneratePassword returns a new password of specified minimum length
+// using provided number of uppercase, lowercase, digits and special characters.
+//
+// Empty strings or strings with invalid int values are treated as nil
+// and used only if sum of the non nil values don't reach minLength
+//
+// Note: If all character groups are unspecified or all have exact zero length
+// then password characters are chosen from all groups uniformly at random.
+//
+// Note: If all charset lengths are negative or 0 but can't reach min_length
+// then all exact/negative charset lengths will be treated as minimum number of characters instead.
+//
+// minLength is the minimum password length - default: 32
+// lowercase is the minimum number of lowercase characters if positive, exact if 0 or negative
+// uppercase is the minimum number of uppercase characters if positive, exact if 0 or negative
+// digits is the minimum number of digits if positive, exact if 0 or negative
+// specialCharacters is the minimum number of special characters if positive, exact if 0 or negative
+// specialCharacterSet is a string containing custom set of special characters to pick from
+func GeneratePassword(minLength int, lowercase, uppercase, digits, specialCharacters, specialCharacterSet string) (string, error) {
+ abs := func(x int) int {
+ if x < 0 {
+ return -x
+ }
+ return x
+ }
+ boolToInt := func(x bool) int {
+ if x {
+ return 1
+ }
+ return 0
+ }
+ type NullableInt struct {
+ Text string
+ HasValue bool
+ Value int
+ }
+ params := map[string]*NullableInt{
+ "lowercase": {Text: lowercase},
+ "uppercase": {Text: uppercase},
+ "digits": {Text: digits},
+ "specialCharacters": {Text: specialCharacters},
+ }
+ for k, v := range params {
+ if v.Text != "" {
+ if i, err := strconv.Atoi(v.Text); err == nil {
+ v.HasValue = true
+ v.Value = i
+ } else {
+ klog.Warning("error converting '" + k + "' length '" + v.Text + "' to int - switching to default value '': " + err.Error())
+ }
+ }
+ }
+
+ if minLength <= 0 {
+ minLength = DefaultPasswordLength
+ }
+ if specialCharacterSet == "" {
+ specialCharacterSet = AsciiSpecialCharacters
+ }
+
+ sumCategories := 0
+ numExactCounts := 0
+ counts := [...]*NullableInt{params["lowercase"], params["uppercase"], params["digits"], params["specialCharacters"]}
+ for _, i := range counts {
+ if i.HasValue {
+ sumCategories += abs(i.Value)
+ if i.Value <= 0 {
+ numExactCounts++
+ }
+ }
+ }
+
+ // If all lengths are exact/negative but don't reach min_length - convert to minimum/positive lengths
+ if len(counts) == numExactCounts && sumCategories < minLength {
+ if params["lowercase"].HasValue && params["lowercase"].Value < 0 {
+ params["lowercase"].Value = abs(params["lowercase"].Value)
+ }
+ if params["uppercase"].HasValue && params["uppercase"].Value < 0 {
+ params["uppercase"].Value = abs(params["uppercase"].Value)
+ }
+ if params["digits"].HasValue && params["digits"].Value < 0 {
+ params["digits"].Value = abs(params["digits"].Value)
+ }
+ if params["specialCharacters"].HasValue && params["specialCharacters"].Value < 0 {
+ params["specialCharacters"].Value = abs(params["specialCharacters"].Value)
+ }
+ }
+
+ extraChars := ""
+ extraCount := 0
+ if minLength > sumCategories {
+ extraCount = minLength - sumCategories
+ }
+ if !params["lowercase"].HasValue || params["lowercase"].Value > 0 {
+ extraChars += AsciiLowercase
+ }
+ if !params["uppercase"].HasValue || params["uppercase"].Value > 0 {
+ extraChars += AsciiUppercase
+ }
+ if !params["digits"].HasValue || params["digits"].Value > 0 {
+ extraChars += AsciiDigits
+ }
+ if !params["specialCharacters"].HasValue || params["specialCharacters"].Value > 0 {
+ extraChars += specialCharacterSet
+ }
+ if extraCount > 0 && extraChars == "" {
+ extraChars = AsciiLowercase + AsciiUppercase + AsciiDigits + specialCharacterSet
+ }
+
+ type categoryItem struct {
+ count int
+ charset string
+ }
+ categoryMap := []categoryItem{
+ {count: boolToInt(params["lowercase"].HasValue) * abs(params["lowercase"].Value), charset: AsciiLowercase},
+ {count: boolToInt(params["uppercase"].HasValue) * abs(params["uppercase"].Value), charset: AsciiUppercase},
+ {count: boolToInt(params["digits"].HasValue) * abs(params["digits"].Value), charset: AsciiDigits},
+ {count: boolToInt(params["specialCharacters"].HasValue) * abs(params["specialCharacters"].Value), charset: specialCharacterSet},
+ {count: extraCount, charset: extraChars},
+ }
+
+ passwordCharacters := ""
+ for _, kvp := range categoryMap {
+ if kvp.count > 0 {
+ if sample, err := randomSample(kvp.count, kvp.charset); err == nil {
+ passwordCharacters += sample
+ } else {
+ return passwordCharacters, err
+ }
+ }
+ }
+ return shuffleString(passwordCharacters)
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go
index bc62161d..00f963ea 100644
--- a/vendor/golang.org/x/crypto/curve25519/curve25519.go
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go
@@ -5,71 +5,18 @@
// Package curve25519 provides an implementation of the X25519 function, which
// performs scalar multiplication on the elliptic curve known as Curve25519.
// See RFC 7748.
+//
+// Starting in Go 1.20, this package is a wrapper for the X25519 implementation
+// in the crypto/ecdh package.
package curve25519 // import "golang.org/x/crypto/curve25519"
-import (
- "crypto/subtle"
- "errors"
- "strconv"
-
- "golang.org/x/crypto/curve25519/internal/field"
-)
-
// ScalarMult sets dst to the product scalar * point.
//
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
// will return an error.
func ScalarMult(dst, scalar, point *[32]byte) {
- var e [32]byte
-
- copy(e[:], scalar[:])
- e[0] &= 248
- e[31] &= 127
- e[31] |= 64
-
- var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
- x1.SetBytes(point[:])
- x2.One()
- x3.Set(&x1)
- z3.One()
-
- swap := 0
- for pos := 254; pos >= 0; pos-- {
- b := e[pos/8] >> uint(pos&7)
- b &= 1
- swap ^= int(b)
- x2.Swap(&x3, swap)
- z2.Swap(&z3, swap)
- swap = int(b)
-
- tmp0.Subtract(&x3, &z3)
- tmp1.Subtract(&x2, &z2)
- x2.Add(&x2, &z2)
- z2.Add(&x3, &z3)
- z3.Multiply(&tmp0, &x2)
- z2.Multiply(&z2, &tmp1)
- tmp0.Square(&tmp1)
- tmp1.Square(&x2)
- x3.Add(&z3, &z2)
- z2.Subtract(&z3, &z2)
- x2.Multiply(&tmp1, &tmp0)
- tmp1.Subtract(&tmp1, &tmp0)
- z2.Square(&z2)
-
- z3.Mult32(&tmp1, 121666)
- x3.Square(&x3)
- tmp0.Add(&tmp0, &z3)
- z3.Multiply(&x1, &z2)
- z2.Multiply(&tmp1, &tmp0)
- }
-
- x2.Swap(&x3, swap)
- z2.Swap(&z3, swap)
-
- z2.Invert(&z2)
- x2.Multiply(&x2, &z2)
- copy(dst[:], x2.Bytes())
+ scalarMult(dst, scalar, point)
}
// ScalarBaseMult sets dst to the product scalar * base where base is the
@@ -78,7 +25,7 @@ func ScalarMult(dst, scalar, point *[32]byte) {
// It is recommended to use the X25519 function with Basepoint instead, as
// copying into fixed size arrays can lead to unexpected bugs.
func ScalarBaseMult(dst, scalar *[32]byte) {
- ScalarMult(dst, scalar, &basePoint)
+ scalarBaseMult(dst, scalar)
}
const (
@@ -91,21 +38,10 @@ const (
// Basepoint is the canonical Curve25519 generator.
var Basepoint []byte
-var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+var basePoint = [32]byte{9}
func init() { Basepoint = basePoint[:] }
-func checkBasepoint() {
- if subtle.ConstantTimeCompare(Basepoint, []byte{
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- }) != 1 {
- panic("curve25519: global Basepoint value was modified")
- }
-}
-
// X25519 returns the result of the scalar multiplication (scalar * point),
// according to RFC 7748, Section 5. scalar, point and the return value are
// slices of 32 bytes.
@@ -121,26 +57,3 @@ func X25519(scalar, point []byte) ([]byte, error) {
var dst [32]byte
return x25519(&dst, scalar, point)
}
-
-func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
- var in [32]byte
- if l := len(scalar); l != 32 {
- return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32")
- }
- if l := len(point); l != 32 {
- return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32")
- }
- copy(in[:], scalar)
- if &point[0] == &Basepoint[0] {
- checkBasepoint()
- ScalarBaseMult(dst, &in)
- } else {
- var base, zero [32]byte
- copy(base[:], point)
- ScalarMult(dst, &in, &base)
- if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
- return nil, errors.New("bad input point: low order point")
- }
- }
- return dst[:], nil
-}
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_compat.go b/vendor/golang.org/x/crypto/curve25519/curve25519_compat.go
new file mode 100644
index 00000000..ba647e8d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519_compat.go
@@ -0,0 +1,105 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.20
+
+package curve25519
+
+import (
+ "crypto/subtle"
+ "errors"
+ "strconv"
+
+ "golang.org/x/crypto/curve25519/internal/field"
+)
+
+func scalarMult(dst, scalar, point *[32]byte) {
+ var e [32]byte
+
+ copy(e[:], scalar[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
+ x1.SetBytes(point[:])
+ x2.One()
+ x3.Set(&x1)
+ z3.One()
+
+ swap := 0
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int(b)
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+ swap = int(b)
+
+ tmp0.Subtract(&x3, &z3)
+ tmp1.Subtract(&x2, &z2)
+ x2.Add(&x2, &z2)
+ z2.Add(&x3, &z3)
+ z3.Multiply(&tmp0, &x2)
+ z2.Multiply(&z2, &tmp1)
+ tmp0.Square(&tmp1)
+ tmp1.Square(&x2)
+ x3.Add(&z3, &z2)
+ z2.Subtract(&z3, &z2)
+ x2.Multiply(&tmp1, &tmp0)
+ tmp1.Subtract(&tmp1, &tmp0)
+ z2.Square(&z2)
+
+ z3.Mult32(&tmp1, 121666)
+ x3.Square(&x3)
+ tmp0.Add(&tmp0, &z3)
+ z3.Multiply(&x1, &z2)
+ z2.Multiply(&tmp1, &tmp0)
+ }
+
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+
+ z2.Invert(&z2)
+ x2.Multiply(&x2, &z2)
+ copy(dst[:], x2.Bytes())
+}
+
+func scalarBaseMult(dst, scalar *[32]byte) {
+ checkBasepoint()
+ scalarMult(dst, scalar, &basePoint)
+}
+
+func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
+ var in [32]byte
+ if l := len(scalar); l != 32 {
+ return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32")
+ }
+ if l := len(point); l != 32 {
+ return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32")
+ }
+ copy(in[:], scalar)
+ if &point[0] == &Basepoint[0] {
+ scalarBaseMult(dst, &in)
+ } else {
+ var base, zero [32]byte
+ copy(base[:], point)
+ scalarMult(dst, &in, &base)
+ if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
+ return nil, errors.New("bad input point: low order point")
+ }
+ }
+ return dst[:], nil
+}
+
+func checkBasepoint() {
+ if subtle.ConstantTimeCompare(Basepoint, []byte{
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }) != 1 {
+ panic("curve25519: global Basepoint value was modified")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_go120.go b/vendor/golang.org/x/crypto/curve25519/curve25519_go120.go
new file mode 100644
index 00000000..627df497
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519_go120.go
@@ -0,0 +1,46 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.20
+
+package curve25519
+
+import "crypto/ecdh"
+
+func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
+ curve := ecdh.X25519()
+ pub, err := curve.NewPublicKey(point)
+ if err != nil {
+ return nil, err
+ }
+ priv, err := curve.NewPrivateKey(scalar)
+ if err != nil {
+ return nil, err
+ }
+ out, err := priv.ECDH(pub)
+ if err != nil {
+ return nil, err
+ }
+ copy(dst[:], out)
+ return dst[:], nil
+}
+
+func scalarMult(dst, scalar, point *[32]byte) {
+ if _, err := x25519(dst, scalar[:], point[:]); err != nil {
+ // The only error condition for x25519 when the inputs are 32 bytes long
+ // is if the output would have been the all-zero value.
+ for i := range dst {
+ dst[i] = 0
+ }
+ }
+}
+
+func scalarBaseMult(dst, scalar *[32]byte) {
+ curve := ecdh.X25519()
+ priv, err := curve.NewPrivateKey(scalar[:])
+ if err != nil {
+ panic("curve25519: internal error: scalarBaseMult was not 32 bytes")
+ }
+ copy(dst[:], priv.PublicKey().Bytes())
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go b/vendor/golang.org/x/crypto/openpgp/packet/compressed.go
index e8f0b5ca..353f9452 100644
--- a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go
+++ b/vendor/golang.org/x/crypto/openpgp/packet/compressed.go
@@ -60,7 +60,7 @@ func (c *Compressed) parse(r io.Reader) error {
return err
}
-// compressedWriterCloser represents the serialized compression stream
+// compressedWriteCloser represents the serialized compression stream
// header and the compressor. Its Close() method ensures that both the
// compressor and serialized stream header are closed. Its Write()
// method writes to the compressor.
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
index 87f48552..741e984f 100644
--- a/vendor/golang.org/x/crypto/ssh/cipher.go
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -114,7 +114,8 @@ var cipherModes = map[string]*cipherMode{
"arcfour": {16, 0, streamCipherMode(0, newRC4)},
// AEAD ciphers
- gcmCipherID: {16, 12, newGCMCipher},
+ gcm128CipherID: {16, 12, newGCMCipher},
+ gcm256CipherID: {32, 12, newGCMCipher},
chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
// CBC mode is insecure and so is not included in the default config.
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index c7964275..e6a77f26 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -28,7 +28,7 @@ const (
// supportedCiphers lists ciphers we support but might not recommend.
var supportedCiphers = []string{
"aes128-ctr", "aes192-ctr", "aes256-ctr",
- "aes128-gcm@openssh.com",
+ "aes128-gcm@openssh.com", gcm256CipherID,
chacha20Poly1305ID,
"arcfour256", "arcfour128", "arcfour",
aes128cbcID,
@@ -37,7 +37,7 @@ var supportedCiphers = []string{
// preferredCiphers specifies the default preference for ciphers.
var preferredCiphers = []string{
- "aes128-gcm@openssh.com",
+ "aes128-gcm@openssh.com", gcm256CipherID,
chacha20Poly1305ID,
"aes128-ctr", "aes192-ctr", "aes256-ctr",
}
@@ -168,7 +168,7 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
// 128.
switch a.Cipher {
- case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID:
+ case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcm128CipherID, gcm256CipherID, aes128cbcID:
return 16 * (1 << 32)
}
@@ -178,7 +178,8 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
}
var aeadCiphers = map[string]bool{
- gcmCipherID: true,
+ gcm128CipherID: true,
+ gcm256CipherID: true,
chacha20Poly1305ID: true,
}
diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go
index 35661a52..8f345ee9 100644
--- a/vendor/golang.org/x/crypto/ssh/connection.go
+++ b/vendor/golang.org/x/crypto/ssh/connection.go
@@ -97,7 +97,7 @@ func (c *connection) Close() error {
return c.sshConn.conn.Close()
}
-// sshconn provides net.Conn metadata, but disallows direct reads and
+// sshConn provides net.Conn metadata, but disallows direct reads and
// writes.
type sshConn struct {
conn net.Conn
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index 72969804..dac8ee72 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -1087,9 +1087,9 @@ func (*PassphraseMissingError) Error() string {
return "ssh: this private key is passphrase protected"
}
-// ParseRawPrivateKey returns a private key from a PEM encoded private key. It
-// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. If the
-// private key is encrypted, it will return a PassphraseMissingError.
+// ParseRawPrivateKey returns a private key from a PEM encoded private key. It supports
+// RSA, DSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, OpenSSL, and OpenSSH
+// formats. If the private key is encrypted, it will return a PassphraseMissingError.
func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
index acf5a21b..da015801 100644
--- a/vendor/golang.org/x/crypto/ssh/transport.go
+++ b/vendor/golang.org/x/crypto/ssh/transport.go
@@ -17,7 +17,8 @@ import (
const debugTransport = false
const (
- gcmCipherID = "aes128-gcm@openssh.com"
+ gcm128CipherID = "aes128-gcm@openssh.com"
+ gcm256CipherID = "aes256-gcm@openssh.com"
aes128cbcID = "aes128-cbc"
tripledescbcID = "3des-cbc"
)
diff --git a/vendor/golang.org/x/net/http2/frame.go b/vendor/golang.org/x/net/http2/frame.go
index 184ac45f..c1f6b90d 100644
--- a/vendor/golang.org/x/net/http2/frame.go
+++ b/vendor/golang.org/x/net/http2/frame.go
@@ -662,6 +662,15 @@ func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
// It is the caller's responsibility not to violate the maximum frame size
// and to not call other Write methods concurrently.
func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
+ if err := f.startWriteDataPadded(streamID, endStream, data, pad); err != nil {
+ return err
+ }
+ return f.endWrite()
+}
+
+// startWriteDataPadded is WriteDataPadded, but only writes the frame to the Framer's internal buffer.
+// The caller should call endWrite to flush the frame to the underlying writer.
+func (f *Framer) startWriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
if !validStreamID(streamID) && !f.AllowIllegalWrites {
return errStreamID
}
@@ -691,7 +700,7 @@ func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []by
}
f.wbuf = append(f.wbuf, data...)
f.wbuf = append(f.wbuf, pad...)
- return f.endWrite()
+ return nil
}
// A SettingsFrame conveys configuration parameters that affect how
diff --git a/vendor/golang.org/x/net/http2/hpack/hpack.go b/vendor/golang.org/x/net/http2/hpack/hpack.go
index b184a277..7a1d9766 100644
--- a/vendor/golang.org/x/net/http2/hpack/hpack.go
+++ b/vendor/golang.org/x/net/http2/hpack/hpack.go
@@ -359,6 +359,7 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
var hf HeaderField
wantStr := d.emitEnabled || it.indexed()
+ var undecodedName undecodedString
if nameIdx > 0 {
ihf, ok := d.at(nameIdx)
if !ok {
@@ -366,15 +367,27 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
}
hf.Name = ihf.Name
} else {
- hf.Name, buf, err = d.readString(buf, wantStr)
+ undecodedName, buf, err = d.readString(buf)
if err != nil {
return err
}
}
- hf.Value, buf, err = d.readString(buf, wantStr)
+ undecodedValue, buf, err := d.readString(buf)
if err != nil {
return err
}
+ if wantStr {
+ if nameIdx <= 0 {
+ hf.Name, err = d.decodeString(undecodedName)
+ if err != nil {
+ return err
+ }
+ }
+ hf.Value, err = d.decodeString(undecodedValue)
+ if err != nil {
+ return err
+ }
+ }
d.buf = buf
if it.indexed() {
d.dynTab.add(hf)
@@ -459,46 +472,52 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
return 0, origP, errNeedMore
}
-// readString decodes an hpack string from p.
+// readString reads an hpack string from p.
//
-// wantStr is whether s will be used. If false, decompression and
-// []byte->string garbage are skipped if s will be ignored
-// anyway. This does mean that huffman decoding errors for non-indexed
-// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
-// is returning an error anyway, and because they're not indexed, the error
-// won't affect the decoding state.
-func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
+// It returns a reference to the encoded string data to permit deferring decode costs
+// until after the caller verifies all data is present.
+func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) {
if len(p) == 0 {
- return "", p, errNeedMore
+ return u, p, errNeedMore
}
isHuff := p[0]&128 != 0
strLen, p, err := readVarInt(7, p)
if err != nil {
- return "", p, err
+ return u, p, err
}
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
- return "", nil, ErrStringLength
+ // Returning an error here means Huffman decoding errors
+ // for non-indexed strings past the maximum string length
+ // are ignored, but the server is returning an error anyway
+ // and because the string is not indexed the error will not
+ // affect the decoding state.
+ return u, nil, ErrStringLength
}
if uint64(len(p)) < strLen {
- return "", p, errNeedMore
- }
- if !isHuff {
- if wantStr {
- s = string(p[:strLen])
- }
- return s, p[strLen:], nil
+ return u, p, errNeedMore
}
+ u.isHuff = isHuff
+ u.b = p[:strLen]
+ return u, p[strLen:], nil
+}
- if wantStr {
- buf := bufPool.Get().(*bytes.Buffer)
- buf.Reset() // don't trust others
- defer bufPool.Put(buf)
- if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
- buf.Reset()
- return "", nil, err
- }
+type undecodedString struct {
+ isHuff bool
+ b []byte
+}
+
+func (d *Decoder) decodeString(u undecodedString) (string, error) {
+ if !u.isHuff {
+ return string(u.b), nil
+ }
+ buf := bufPool.Get().(*bytes.Buffer)
+ buf.Reset() // don't trust others
+ var s string
+ err := huffmanDecode(buf, d.maxStrLen, u.b)
+ if err == nil {
s = buf.String()
- buf.Reset() // be nice to GC
}
- return s, p[strLen:], nil
+ buf.Reset() // be nice to GC
+ bufPool.Put(buf)
+ return s, err
}
diff --git a/vendor/golang.org/x/net/http2/pipe.go b/vendor/golang.org/x/net/http2/pipe.go
index c15b8a77..684d984f 100644
--- a/vendor/golang.org/x/net/http2/pipe.go
+++ b/vendor/golang.org/x/net/http2/pipe.go
@@ -88,13 +88,9 @@ func (p *pipe) Write(d []byte) (n int, err error) {
p.c.L = &p.mu
}
defer p.c.Signal()
- if p.err != nil {
+ if p.err != nil || p.breakErr != nil {
return 0, errClosedPipeWrite
}
- if p.breakErr != nil {
- p.unread += len(d)
- return len(d), nil // discard when there is no reader
- }
return p.b.Write(d)
}
diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go
index 9bd7035b..cd057f39 100644
--- a/vendor/golang.org/x/net/http2/server.go
+++ b/vendor/golang.org/x/net/http2/server.go
@@ -843,8 +843,13 @@ type frameWriteResult struct {
// and then reports when it's done.
// At most one goroutine can be running writeFrameAsync at a time per
// serverConn.
-func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest) {
- err := wr.write.writeFrame(sc)
+func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest, wd *writeData) {
+ var err error
+ if wd == nil {
+ err = wr.write.writeFrame(sc)
+ } else {
+ err = sc.framer.endWrite()
+ }
sc.wroteFrameCh <- frameWriteResult{wr: wr, err: err}
}
@@ -1251,9 +1256,16 @@ func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
sc.writingFrameAsync = false
err := wr.write.writeFrame(sc)
sc.wroteFrame(frameWriteResult{wr: wr, err: err})
+ } else if wd, ok := wr.write.(*writeData); ok {
+ // Encode the frame in the serve goroutine, to ensure we don't have
+ // any lingering asynchronous references to data passed to Write.
+ // See https://go.dev/issue/58446.
+ sc.framer.startWriteDataPadded(wd.streamID, wd.endStream, wd.p, nil)
+ sc.writingFrameAsync = true
+ go sc.writeFrameAsync(wr, wd)
} else {
sc.writingFrameAsync = true
- go sc.writeFrameAsync(wr)
+ go sc.writeFrameAsync(wr, nil)
}
}
@@ -1810,15 +1822,18 @@ func (sc *serverConn) processData(f *DataFrame) error {
}
if len(data) > 0 {
+ st.bodyBytes += int64(len(data))
wrote, err := st.body.Write(data)
if err != nil {
+ // The handler has closed the request body.
+ // Return the connection-level flow control for the discarded data,
+ // but not the stream-level flow control.
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
- return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
+ return nil
}
if wrote != len(data) {
panic("internal error: bad Writer")
}
- st.bodyBytes += int64(len(data))
}
// Return any padded flow control now, since we won't
diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go
index 05ba23d3..f965579f 100644
--- a/vendor/golang.org/x/net/http2/transport.go
+++ b/vendor/golang.org/x/net/http2/transport.go
@@ -560,10 +560,11 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
traceGotConn(req, cc, reused)
res, err := cc.RoundTrip(req)
if err != nil && retry <= 6 {
+ roundTripErr := err
if req, err = shouldRetryRequest(req, err); err == nil {
// After the first retry, do exponential backoff with 10% jitter.
if retry == 0 {
- t.vlogf("RoundTrip retrying after failure: %v", err)
+ t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
continue
}
backoff := float64(uint(1) << (uint(retry) - 1))
@@ -572,7 +573,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
timer := backoffNewTimer(d)
select {
case <-timer.C:
- t.vlogf("RoundTrip retrying after failure: %v", err)
+ t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
continue
case <-req.Context().Done():
timer.Stop()
@@ -2555,6 +2556,9 @@ func (b transportResponseBody) Close() error {
cs := b.cs
cc := cs.cc
+ cs.bufPipe.BreakWithError(errClosedResponseBody)
+ cs.abortStream(errClosedResponseBody)
+
unread := cs.bufPipe.Len()
if unread > 0 {
cc.mu.Lock()
@@ -2573,9 +2577,6 @@ func (b transportResponseBody) Close() error {
cc.wmu.Unlock()
}
- cs.bufPipe.BreakWithError(errClosedResponseBody)
- cs.abortStream(errClosedResponseBody)
-
select {
case <-cs.donec:
case <-cs.ctx.Done():
diff --git a/vendor/golang.org/x/sys/cpu/hwcap_linux.go b/vendor/golang.org/x/sys/cpu/hwcap_linux.go
index f3baa379..1d9d91f3 100644
--- a/vendor/golang.org/x/sys/cpu/hwcap_linux.go
+++ b/vendor/golang.org/x/sys/cpu/hwcap_linux.go
@@ -24,6 +24,21 @@ var hwCap uint
var hwCap2 uint
func readHWCAP() error {
+ // For Go 1.21+, get auxv from the Go runtime.
+ if a := getAuxv(); len(a) > 0 {
+ for len(a) >= 2 {
+ tag, val := a[0], uint(a[1])
+ a = a[2:]
+ switch tag {
+ case _AT_HWCAP:
+ hwCap = val
+ case _AT_HWCAP2:
+ hwCap2 = val
+ }
+ }
+ return nil
+ }
+
buf, err := ioutil.ReadFile(procAuxv)
if err != nil {
// e.g. on android /proc/self/auxv is not accessible, so silently
diff --git a/vendor/golang.org/x/sys/cpu/runtime_auxv.go b/vendor/golang.org/x/sys/cpu/runtime_auxv.go
new file mode 100644
index 00000000..5f92ac9a
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/runtime_auxv.go
@@ -0,0 +1,16 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+// getAuxvFn is non-nil on Go 1.21+ (via runtime_auxv_go121.go init)
+// on platforms that use auxv.
+var getAuxvFn func() []uintptr
+
+func getAuxv() []uintptr {
+ if getAuxvFn == nil {
+ return nil
+ }
+ return getAuxvFn()
+}
diff --git a/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go b/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go
new file mode 100644
index 00000000..b975ea2a
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go
@@ -0,0 +1,19 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.21
+// +build go1.21
+
+package cpu
+
+import (
+ _ "unsafe" // for linkname
+)
+
+//go:linkname runtime_getAuxv runtime.getAuxv
+func runtime_getAuxv() []uintptr
+
+func init() {
+ getAuxvFn = runtime_getAuxv
+}
diff --git a/vendor/golang.org/x/sys/execabs/execabs.go b/vendor/golang.org/x/sys/execabs/execabs.go
index b981cfbb..3bf40fdf 100644
--- a/vendor/golang.org/x/sys/execabs/execabs.go
+++ b/vendor/golang.org/x/sys/execabs/execabs.go
@@ -63,7 +63,7 @@ func LookPath(file string) (string, error) {
}
func fixCmd(name string, cmd *exec.Cmd) {
- if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
+ if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) && !isGo119ErrFieldSet(cmd) {
// exec.Command was called with a bare binary name and
// exec.LookPath returned a path which is not absolute.
// Set cmd.lookPathErr and clear cmd.Path so that it
diff --git a/vendor/golang.org/x/sys/execabs/execabs_go118.go b/vendor/golang.org/x/sys/execabs/execabs_go118.go
index 6ab5f508..2000064a 100644
--- a/vendor/golang.org/x/sys/execabs/execabs_go118.go
+++ b/vendor/golang.org/x/sys/execabs/execabs_go118.go
@@ -7,6 +7,12 @@
package execabs
+import "os/exec"
+
func isGo119ErrDot(err error) bool {
return false
}
+
+func isGo119ErrFieldSet(cmd *exec.Cmd) bool {
+ return false
+}
diff --git a/vendor/golang.org/x/sys/execabs/execabs_go119.go b/vendor/golang.org/x/sys/execabs/execabs_go119.go
index 46c5b525..f364b341 100644
--- a/vendor/golang.org/x/sys/execabs/execabs_go119.go
+++ b/vendor/golang.org/x/sys/execabs/execabs_go119.go
@@ -15,3 +15,7 @@ import (
func isGo119ErrDot(err error) bool {
return errors.Is(err, exec.ErrDot)
}
+
+func isGo119ErrFieldSet(cmd *exec.Cmd) bool {
+ return cmd.Err != nil
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl_signed.go b/vendor/golang.org/x/sys/unix/ioctl_signed.go
new file mode 100644
index 00000000..7def9580
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl_signed.go
@@ -0,0 +1,70 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || solaris
+// +build aix solaris
+
+package unix
+
+import (
+ "unsafe"
+)
+
+// ioctl itself should not be exposed directly, but additional get/set
+// functions for specific types are permissible.
+
+// IoctlSetInt performs an ioctl operation which sets an integer value
+// on fd, using the specified request number.
+func IoctlSetInt(fd int, req int, value int) error {
+ return ioctl(fd, req, uintptr(value))
+}
+
+// IoctlSetPointerInt performs an ioctl operation which sets an
+// integer value on fd, using the specified request number. The ioctl
+// argument is called with a pointer to the integer value, rather than
+// passing the integer value directly.
+func IoctlSetPointerInt(fd int, req int, value int) error {
+ v := int32(value)
+ return ioctlPtr(fd, req, unsafe.Pointer(&v))
+}
+
+// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
+//
+// To change fd's window size, the req argument should be TIOCSWINSZ.
+func IoctlSetWinsize(fd int, req int, value *Winsize) error {
+ // TODO: if we get the chance, remove the req parameter and
+ // hardcode TIOCSWINSZ.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlSetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value will usually be TCSETA or TIOCSETA.
+func IoctlSetTermios(fd int, req int, value *Termios) error {
+ // TODO: if we get the chance, remove the req parameter.
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
+
+// IoctlGetInt performs an ioctl operation which gets an integer value
+// from fd, using the specified request number.
+//
+// A few ioctl requests use the return value as an output parameter;
+// for those, IoctlRetInt should be used instead of this function.
+func IoctlGetInt(fd int, req int) (int, error) {
+ var value int
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return value, err
+}
+
+func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
+ var value Winsize
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
+
+func IoctlGetTermios(fd int, req int) (*Termios, error) {
+ var value Termios
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
+ return &value, err
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl.go b/vendor/golang.org/x/sys/unix/ioctl_unsigned.go
similarity index 76%
rename from vendor/golang.org/x/sys/unix/ioctl.go
rename to vendor/golang.org/x/sys/unix/ioctl_unsigned.go
index 1c51b0ec..649913d1 100644
--- a/vendor/golang.org/x/sys/unix/ioctl.go
+++ b/vendor/golang.org/x/sys/unix/ioctl_unsigned.go
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
+//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd
+// +build darwin dragonfly freebsd hurd linux netbsd openbsd
package unix
import (
- "runtime"
"unsafe"
)
@@ -27,7 +26,7 @@ func IoctlSetInt(fd int, req uint, value int) error {
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req uint, value int) error {
v := int32(value)
- return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
+ return ioctlPtr(fd, req, unsafe.Pointer(&v))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
@@ -36,9 +35,7 @@ func IoctlSetPointerInt(fd int, req uint, value int) error {
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
- err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
- runtime.KeepAlive(value)
- return err
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
@@ -46,9 +43,7 @@ func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
// The req value will usually be TCSETA or TIOCSETA.
func IoctlSetTermios(fd int, req uint, value *Termios) error {
// TODO: if we get the chance, remove the req parameter.
- err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
- runtime.KeepAlive(value)
- return err
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
@@ -58,18 +53,18 @@ func IoctlSetTermios(fd int, req uint, value *Termios) error {
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req uint) (int, error) {
var value int
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
var value Winsize
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
var value Termios
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
diff --git a/vendor/golang.org/x/sys/unix/ioctl_zos.go b/vendor/golang.org/x/sys/unix/ioctl_zos.go
index 5384e7d9..cdc21bf7 100644
--- a/vendor/golang.org/x/sys/unix/ioctl_zos.go
+++ b/vendor/golang.org/x/sys/unix/ioctl_zos.go
@@ -17,25 +17,23 @@ import (
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
-func IoctlSetInt(fd int, req uint, value int) error {
+func IoctlSetInt(fd int, req int, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
-func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
+func IoctlSetWinsize(fd int, req int, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
- err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
- runtime.KeepAlive(value)
- return err
+ return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value is expected to be TCSETS, TCSETSW, or TCSETSF
-func IoctlSetTermios(fd int, req uint, value *Termios) error {
+func IoctlSetTermios(fd int, req int, value *Termios) error {
if (req != TCSETS) && (req != TCSETSW) && (req != TCSETSF) {
return ENOSYS
}
@@ -49,22 +47,22 @@ func IoctlSetTermios(fd int, req uint, value *Termios) error {
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
-func IoctlGetInt(fd int, req uint) (int, error) {
+func IoctlGetInt(fd int, req int) (int, error) {
var value int
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
+func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
var value Winsize
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
// IoctlGetTermios performs an ioctl on fd with a *Termios.
//
// The req value is expected to be TCGETS
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
+func IoctlGetTermios(fd int, req int) (*Termios, error) {
var value Termios
if req != TCGETS {
return &value, ENOSYS
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index 7456d9dd..2045d3da 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -66,6 +66,7 @@ includes_Darwin='
#include
#include
#include
+#include
#include
#include
#include
@@ -521,6 +522,7 @@ ccflags="$@"
$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
$2 ~ /^RAW_PAYLOAD_/ ||
+ $2 ~ /^[US]F_/ ||
$2 ~ /^TP_STATUS_/ ||
$2 ~ /^FALLOC_/ ||
$2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
diff --git a/vendor/golang.org/x/sys/unix/ptrace_darwin.go b/vendor/golang.org/x/sys/unix/ptrace_darwin.go
index 463c3eff..39dba6ca 100644
--- a/vendor/golang.org/x/sys/unix/ptrace_darwin.go
+++ b/vendor/golang.org/x/sys/unix/ptrace_darwin.go
@@ -7,6 +7,12 @@
package unix
+import "unsafe"
+
func ptrace(request int, pid int, addr uintptr, data uintptr) error {
return ptrace1(request, pid, addr, data)
}
+
+func ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) error {
+ return ptrace1Ptr(request, pid, addr, data)
+}
diff --git a/vendor/golang.org/x/sys/unix/ptrace_ios.go b/vendor/golang.org/x/sys/unix/ptrace_ios.go
index ed0509a0..9ea66330 100644
--- a/vendor/golang.org/x/sys/unix/ptrace_ios.go
+++ b/vendor/golang.org/x/sys/unix/ptrace_ios.go
@@ -7,6 +7,12 @@
package unix
+import "unsafe"
+
func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
return ENOTSUP
}
+
+func ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) {
+ return ENOTSUP
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go
index 2db1b51e..c406ae00 100644
--- a/vendor/golang.org/x/sys/unix/syscall_aix.go
+++ b/vendor/golang.org/x/sys/unix/syscall_aix.go
@@ -292,9 +292,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
break
}
}
-
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
- sa.Name = string(bytes)
+ sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
return sa, nil
case AF_INET:
@@ -410,7 +408,8 @@ func (w WaitStatus) CoreDump() bool { return w&0x80 == 0x80 }
func (w WaitStatus) TrapCause() int { return -1 }
-//sys ioctl(fd int, req uint, arg uintptr) (err error)
+//sys ioctl(fd int, req int, arg uintptr) (err error)
+//sys ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) = ioctl
// fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX
// There is no way to create a custom fcntl and to keep //sys fcntl easily,
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go b/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
index e92a0be1..f2871fa9 100644
--- a/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
@@ -8,7 +8,6 @@
package unix
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = getrlimit64
-//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) = setrlimit64
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek64
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go b/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
index 16eed170..75718ec0 100644
--- a/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
@@ -8,7 +8,6 @@
package unix
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
-//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) = mmap64
diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go
index eda42671..7705c327 100644
--- a/vendor/golang.org/x/sys/unix/syscall_bsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go
@@ -245,8 +245,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
break
}
}
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
- sa.Name = string(bytes)
+ sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
return sa, nil
case AF_INET:
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go
index 192b071b..20692150 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go
@@ -14,7 +14,6 @@ package unix
import (
"fmt"
- "runtime"
"syscall"
"unsafe"
)
@@ -376,11 +375,10 @@ func Flistxattr(fd int, dest []byte) (sz int, err error) {
func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) }
//sys ioctl(fd int, req uint, arg uintptr) (err error)
+//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
func IoctlCtlInfo(fd int, ctlInfo *CtlInfo) error {
- err := ioctl(fd, CTLIOCGINFO, uintptr(unsafe.Pointer(ctlInfo)))
- runtime.KeepAlive(ctlInfo)
- return err
+ return ioctlPtr(fd, CTLIOCGINFO, unsafe.Pointer(ctlInfo))
}
// IfreqMTU is struct ifreq used to get or set a network device's MTU.
@@ -394,16 +392,14 @@ type IfreqMTU struct {
func IoctlGetIfreqMTU(fd int, ifname string) (*IfreqMTU, error) {
var ifreq IfreqMTU
copy(ifreq.Name[:], ifname)
- err := ioctl(fd, SIOCGIFMTU, uintptr(unsafe.Pointer(&ifreq)))
+ err := ioctlPtr(fd, SIOCGIFMTU, unsafe.Pointer(&ifreq))
return &ifreq, err
}
// IoctlSetIfreqMTU performs the SIOCSIFMTU ioctl operation on fd to set the MTU
// of the network device specified by ifreq.Name.
func IoctlSetIfreqMTU(fd int, ifreq *IfreqMTU) error {
- err := ioctl(fd, SIOCSIFMTU, uintptr(unsafe.Pointer(ifreq)))
- runtime.KeepAlive(ifreq)
- return err
+ return ioctlPtr(fd, SIOCSIFMTU, unsafe.Pointer(ifreq))
}
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS_SYSCTL
@@ -617,6 +613,7 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
+//sys Setattrlist(path string, attrlist *Attrlist, attrBuf []byte, options int) (err error)
//sys Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -626,7 +623,6 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
//sys Setprivexec(flag int) (err error)
//sysnb Setregid(rgid int, egid int) (err error)
//sysnb Setreuid(ruid int, euid int) (err error)
-//sysnb Setrlimit(which int, lim *Rlimit) (err error)
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
@@ -680,7 +676,6 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
// Kqueue_from_portset_np
// Kqueue_portset
// Getattrlist
-// Setattrlist
// Getdirentriesattr
// Searchfs
// Delete
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
index b37310ce..9fa87980 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
@@ -47,5 +47,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
+//sys ptrace1Ptr(request int, pid int, addr unsafe.Pointer, data uintptr) (err error) = SYS_ptrace
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
index d51ec996..f17b8c52 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
@@ -47,5 +47,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT
//sys Lstat(path string, stat *Stat_t) (err error)
//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
+//sys ptrace1Ptr(request int, pid int, addr unsafe.Pointer, data uintptr) (err error) = SYS_ptrace
//sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
index a41111a7..d4ce988e 100644
--- a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
+++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
@@ -172,6 +172,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
}
//sys ioctl(fd int, req uint, arg uintptr) (err error)
+//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
@@ -325,7 +326,6 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sysnb Setreuid(ruid int, euid int) (err error)
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
-//sysnb Setrlimit(which int, lim *Rlimit) (err error)
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd.go b/vendor/golang.org/x/sys/unix/syscall_freebsd.go
index d50b9dc2..afb10106 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd.go
@@ -161,7 +161,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
-//sys ioctl(fd int, req uint, arg uintptr) (err error)
+//sys ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL
+//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
@@ -253,6 +254,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
}
//sys ptrace(request int, pid int, addr uintptr, data int) (err error)
+//sys ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) = SYS_PTRACE
func PtraceAttach(pid int) (err error) {
return ptrace(PT_ATTACH, pid, 0, 0)
@@ -267,19 +269,36 @@ func PtraceDetach(pid int) (err error) {
}
func PtraceGetFpRegs(pid int, fpregsout *FpReg) (err error) {
- return ptrace(PT_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0)
+ return ptracePtr(PT_GETFPREGS, pid, unsafe.Pointer(fpregsout), 0)
}
func PtraceGetRegs(pid int, regsout *Reg) (err error) {
- return ptrace(PT_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
+ return ptracePtr(PT_GETREGS, pid, unsafe.Pointer(regsout), 0)
+}
+
+func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
+ ioDesc := PtraceIoDesc{
+ Op: int32(req),
+ Offs: offs,
+ }
+ if countin > 0 {
+ _ = out[:countin] // check bounds
+ ioDesc.Addr = &out[0]
+ } else if out != nil {
+ ioDesc.Addr = (*byte)(unsafe.Pointer(&_zero))
+ }
+ ioDesc.SetLen(countin)
+
+ err = ptracePtr(PT_IO, pid, unsafe.Pointer(&ioDesc), 0)
+ return int(ioDesc.Len), err
}
func PtraceLwpEvents(pid int, enable int) (err error) {
return ptrace(PT_LWP_EVENTS, pid, 0, enable)
}
-func PtraceLwpInfo(pid int, info uintptr) (err error) {
- return ptrace(PT_LWPINFO, pid, info, int(unsafe.Sizeof(PtraceLwpInfoStruct{})))
+func PtraceLwpInfo(pid int, info *PtraceLwpInfoStruct) (err error) {
+ return ptracePtr(PT_LWPINFO, pid, unsafe.Pointer(info), int(unsafe.Sizeof(*info)))
}
func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
@@ -299,13 +318,25 @@ func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
}
func PtraceSetRegs(pid int, regs *Reg) (err error) {
- return ptrace(PT_SETREGS, pid, uintptr(unsafe.Pointer(regs)), 0)
+ return ptracePtr(PT_SETREGS, pid, unsafe.Pointer(regs), 0)
}
func PtraceSingleStep(pid int) (err error) {
return ptrace(PT_STEP, pid, 1, 0)
}
+func Dup3(oldfd, newfd, flags int) error {
+ if oldfd == newfd || flags&^O_CLOEXEC != 0 {
+ return EINVAL
+ }
+ how := F_DUP2FD
+ if flags&O_CLOEXEC != 0 {
+ how = F_DUP2FD_CLOEXEC
+ }
+ _, err := fcntl(oldfd, how, newfd)
+ return err
+}
+
/*
* Exposed directly
*/
@@ -402,7 +433,6 @@ func PtraceSingleStep(pid int) (err error) {
//sysnb Setreuid(ruid int, euid int) (err error)
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
-//sysnb Setrlimit(which int, lim *Rlimit) (err error)
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
index 6a91d471..b8da5100 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+func (d *PtraceIoDesc) SetLen(length int) {
+ d.Len = uint32(length)
+}
+
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
@@ -57,16 +61,5 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
- return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
-}
-
-func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
- ioDesc := PtraceIoDesc{
- Op: int32(req),
- Offs: offs,
- Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
- Len: uint32(countin),
- }
- err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
- return int(ioDesc.Len), err
+ return ptracePtr(PT_GETFSBASE, pid, unsafe.Pointer(fsbase), 0)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
index 48110a0a..47155c48 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+func (d *PtraceIoDesc) SetLen(length int) {
+ d.Len = uint64(length)
+}
+
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
@@ -57,16 +61,5 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
- return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
-}
-
-func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
- ioDesc := PtraceIoDesc{
- Op: int32(req),
- Offs: offs,
- Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
- Len: uint64(countin),
- }
- err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
- return int(ioDesc.Len), err
+ return ptracePtr(PT_GETFSBASE, pid, unsafe.Pointer(fsbase), 0)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
index 52f1d4b7..08932093 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+func (d *PtraceIoDesc) SetLen(length int) {
+ d.Len = uint32(length)
+}
+
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
@@ -55,14 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
-
-func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
- ioDesc := PtraceIoDesc{
- Op: int32(req),
- Offs: offs,
- Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
- Len: uint32(countin),
- }
- err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
- return int(ioDesc.Len), err
-}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
index 5537ee4f..d151a0d0 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+func (d *PtraceIoDesc) SetLen(length int) {
+ d.Len = uint64(length)
+}
+
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
@@ -55,14 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
-
-func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
- ioDesc := PtraceIoDesc{
- Op: int32(req),
- Offs: offs,
- Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
- Len: uint64(countin),
- }
- err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
- return int(ioDesc.Len), err
-}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go
index 164abd5d..d5cd64b3 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+func (d *PtraceIoDesc) SetLen(length int) {
+ d.Len = uint64(length)
+}
+
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
@@ -55,14 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
-
-func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
- ioDesc := PtraceIoDesc{
- Op: int32(req),
- Offs: offs,
- Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
- Len: uint64(countin),
- }
- err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
- return int(ioDesc.Len), err
-}
diff --git a/vendor/golang.org/x/sys/unix/syscall_hurd.go b/vendor/golang.org/x/sys/unix/syscall_hurd.go
index 4ffb6480..381fd467 100644
--- a/vendor/golang.org/x/sys/unix/syscall_hurd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_hurd.go
@@ -20,3 +20,11 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
}
return
}
+
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ r0, er := C.ioctl(C.int(fd), C.ulong(req), C.uintptr_t(uintptr(arg)))
+ if r0 == -1 && er != nil {
+ err = er
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index 5443dddd..fbaeb5ff 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -1015,8 +1015,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
for n < len(pp.Path) && pp.Path[n] != 0 {
n++
}
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
- sa.Name = string(bytes)
+ sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
return sa, nil
case AF_INET:
@@ -1365,6 +1364,10 @@ func SetsockoptTCPRepairOpt(fd, level, opt int, o []TCPRepairOpt) (err error) {
return setsockopt(fd, level, opt, unsafe.Pointer(&o[0]), uintptr(SizeofTCPRepairOpt*len(o)))
}
+func SetsockoptTCPMD5Sig(fd, level, opt int, s *TCPMD5Sig) error {
+ return setsockopt(fd, level, opt, unsafe.Pointer(s), unsafe.Sizeof(*s))
+}
+
// Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
// KeyctlInt calls keyctl commands in which each argument is an int.
@@ -1579,6 +1582,7 @@ func BindToDevice(fd int, device string) (err error) {
}
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
+//sys ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) = SYS_PTRACE
func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) {
// The peek requests are machine-size oriented, so we wrap it
@@ -1596,7 +1600,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
// boundary.
n := 0
if addr%SizeofPtr != 0 {
- err = ptrace(req, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ err = ptracePtr(req, pid, addr-addr%SizeofPtr, unsafe.Pointer(&buf[0]))
if err != nil {
return 0, err
}
@@ -1608,7 +1612,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
for len(out) > 0 {
// We use an internal buffer to guarantee alignment.
// It's not documented if this is necessary, but we're paranoid.
- err = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ err = ptracePtr(req, pid, addr+uintptr(n), unsafe.Pointer(&buf[0]))
if err != nil {
return n, err
}
@@ -1640,7 +1644,7 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
n := 0
if addr%SizeofPtr != 0 {
var buf [SizeofPtr]byte
- err = ptrace(peekReq, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ err = ptracePtr(peekReq, pid, addr-addr%SizeofPtr, unsafe.Pointer(&buf[0]))
if err != nil {
return 0, err
}
@@ -1667,7 +1671,7 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
// Trailing edge.
if len(data) > 0 {
var buf [SizeofPtr]byte
- err = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ err = ptracePtr(peekReq, pid, addr+uintptr(n), unsafe.Pointer(&buf[0]))
if err != nil {
return n, err
}
@@ -1696,11 +1700,11 @@ func PtracePokeUser(pid int, addr uintptr, data []byte) (count int, err error) {
}
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
- return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+ return ptracePtr(PTRACE_GETREGS, pid, 0, unsafe.Pointer(regsout))
}
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
- return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+ return ptracePtr(PTRACE_SETREGS, pid, 0, unsafe.Pointer(regs))
}
func PtraceSetOptions(pid int, options int) (err error) {
@@ -1709,7 +1713,7 @@ func PtraceSetOptions(pid int, options int) (err error) {
func PtraceGetEventMsg(pid int) (msg uint, err error) {
var data _C_long
- err = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
+ err = ptracePtr(PTRACE_GETEVENTMSG, pid, 0, unsafe.Pointer(&data))
msg = uint(data)
return
}
@@ -1869,7 +1873,6 @@ func Getpgrp() (pid int) {
//sys OpenTree(dfd int, fileName string, flags uint) (r int, err error)
//sys PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error)
//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
-//sysnb Prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64
//sys Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error)
//sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6
//sys read(fd int, p []byte) (n int, err error)
@@ -1883,6 +1886,15 @@ func Getpgrp() (pid int) {
//sysnb Settimeofday(tv *Timeval) (err error)
//sys Setns(fd int, nstype int) (err error)
+//go:linkname syscall_prlimit syscall.prlimit
+func syscall_prlimit(pid, resource int, newlimit, old *syscall.Rlimit) error
+
+func Prlimit(pid, resource int, newlimit, old *Rlimit) error {
+ // Just call the syscall version, because as of Go 1.21
+ // it will affect starting a new process.
+ return syscall_prlimit(pid, resource, (*syscall.Rlimit)(newlimit), (*syscall.Rlimit)(old))
+}
+
// PrctlRetInt performs a prctl operation specified by option and further
// optional arguments arg2 through arg5 depending on option. It returns a
// non-negative integer that is returned by the prctl syscall.
@@ -2154,6 +2166,14 @@ func isGroupMember(gid int) bool {
return false
}
+func isCapDacOverrideSet() bool {
+ hdr := CapUserHeader{Version: LINUX_CAPABILITY_VERSION_3}
+ data := [2]CapUserData{}
+ err := Capget(&hdr, &data[0])
+
+ return err == nil && data[0].Effective&(1< 0 {
+ _p1 = unsafe.Pointer(&attrBuf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(attrlist)), uintptr(_p1), uintptr(len(attrBuf)), uintptr(options), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_setattrlist_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (err error) {
_, _, e1 := syscall_syscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0)
if e1 != 0 {
@@ -2115,20 +2148,6 @@ var libc_setreuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := syscall_rawSyscall(libc_setsid_trampoline_addr, 0, 0, 0)
pid = int(r0)
@@ -2502,6 +2521,14 @@ func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) {
return
}
+func ptrace1Ptr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall6(libc_ptrace_trampoline_addr, uintptr(request), uintptr(pid), addr, uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ptrace_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib"
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
index 95fe4c0e..4baaed0b 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
@@ -705,6 +705,11 @@ TEXT libc_select_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_select_trampoline_addr(SB), RODATA, $8
DATA ·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB)
+TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_setattrlist(SB)
+GLOBL ·libc_setattrlist_trampoline_addr(SB), RODATA, $8
+DATA ·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
+
TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setegid(SB)
@@ -759,12 +764,6 @@ TEXT libc_setreuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setreuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setreuid_trampoline_addr(SB)/8, $libc_setreuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setsid_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setsid(SB)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
index 26a0fdc5..51d6f3fb 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
@@ -725,6 +725,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "/usr/lib/libSystem.B.dylib"
@@ -1984,6 +1992,31 @@ var libc_select_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Setattrlist(path string, attrlist *Attrlist, attrBuf []byte, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(attrBuf) > 0 {
+ _p1 = unsafe.Pointer(&attrBuf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := syscall_syscall6(libc_setattrlist_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(attrlist)), uintptr(_p1), uintptr(len(attrBuf)), uintptr(options), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_setattrlist_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (err error) {
_, _, e1 := syscall_syscall(libc_setegid_trampoline_addr, uintptr(egid), 0, 0)
if e1 != 0 {
@@ -2115,20 +2148,6 @@ var libc_setreuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "/usr/lib/libSystem.B.dylib"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := syscall_rawSyscall(libc_setsid_trampoline_addr, 0, 0, 0)
pid = int(r0)
@@ -2502,6 +2521,14 @@ func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) {
return
}
+func ptrace1Ptr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall6(libc_ptrace_trampoline_addr, uintptr(request), uintptr(pid), addr, uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ptrace_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib"
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
index efa5b4c9..c3b82c03 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
@@ -705,6 +705,11 @@ TEXT libc_select_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_select_trampoline_addr(SB), RODATA, $8
DATA ·libc_select_trampoline_addr(SB)/8, $libc_select_trampoline<>(SB)
+TEXT libc_setattrlist_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_setattrlist(SB)
+GLOBL ·libc_setattrlist_trampoline_addr(SB), RODATA, $8
+DATA ·libc_setattrlist_trampoline_addr(SB)/8, $libc_setattrlist_trampoline<>(SB)
+
TEXT libc_setegid_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setegid(SB)
@@ -759,12 +764,6 @@ TEXT libc_setreuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setreuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setreuid_trampoline_addr(SB)/8, $libc_setreuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setsid_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setsid(SB)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
index 54749f9c..0eabac7a 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
@@ -436,6 +436,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -1400,16 +1410,6 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go
index 77479d45..ee313eb0 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go
@@ -388,6 +388,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -414,6 +424,16 @@ func ptrace(request int, pid int, addr uintptr, data int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1625,16 +1645,6 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go
index 2e966d4d..4c986e44 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go
@@ -388,6 +388,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -414,6 +424,16 @@ func ptrace(request int, pid int, addr uintptr, data int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1625,16 +1645,6 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go
index d65a7c0f..55521694 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go
@@ -388,6 +388,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -414,6 +424,16 @@ func ptrace(request int, pid int, addr uintptr, data int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1625,16 +1645,6 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go
index 6f0b97c6..67a226fb 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go
@@ -388,6 +388,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -414,6 +424,16 @@ func ptrace(request int, pid int, addr uintptr, data int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1625,16 +1645,6 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go
index e1c23b52..f0b9ddaa 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go
@@ -388,6 +388,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -414,6 +424,16 @@ func ptrace(request int, pid int, addr uintptr, data int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Access(path string, mode uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -1625,16 +1645,6 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index 36ea3a55..da63d9d7 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -379,6 +379,16 @@ func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(arg)
@@ -1336,16 +1346,6 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) {
_, _, e1 := Syscall6(SYS_PRCTL, uintptr(option), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
index c81b0ad4..07b549cc 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
@@ -411,16 +411,6 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setrlimit(resource int, rlim *rlimit32) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func futimesat(dirfd int, path string, times *[2]Timeval) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
index 2206bce7..5f481bf8 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
@@ -334,16 +334,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
index edf6b39f..824cd52c 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
@@ -578,16 +578,6 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setrlimit(resource int, rlim *rlimit32) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func armSyncFileRange(fd int, flags int, off int64, n int64) (err error) {
_, _, e1 := Syscall6(SYS_ARM_SYNC_FILE_RANGE, uintptr(fd), uintptr(flags), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
index 190609f2..e77aecfe 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
@@ -289,16 +289,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
index 5f984cbb..961a3afb 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
@@ -644,16 +644,6 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setrlimit(resource int, rlim *rlimit32) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Alarm(seconds uint) (remaining uint, err error) {
r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0)
remaining = uint(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
index 46fc380a..ed05005e 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
@@ -278,16 +278,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
index cbd0d4da..d365b718 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
@@ -278,16 +278,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
index 0c13d15f..c3f1b8bb 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
@@ -644,16 +644,6 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setrlimit(resource int, rlim *rlimit32) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Alarm(seconds uint) (remaining uint, err error) {
r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0)
remaining = uint(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
index e01432ae..a6574cf9 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
@@ -624,16 +624,6 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setrlimit(resource int, rlim *rlimit32) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func syncFileRange2(fd int, flags int, off int64, n int64) (err error) {
_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off>>32), uintptr(off), uintptr(n>>32), uintptr(n))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
index 13c7ee7b..f4099026 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
@@ -349,16 +349,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
index 02d0c0fd..9dfcc299 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
@@ -349,16 +349,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
index 9fee3b1d..0b292395 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
@@ -269,16 +269,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
index 647bbfec..6cde3223 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
@@ -319,16 +319,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
n = int64(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
index ada057f8..5253d65b 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
@@ -329,16 +329,6 @@ func setfsuid(uid int) (prev int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go
index 79f73899..cdb2af5a 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go
@@ -405,6 +405,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -1597,16 +1607,6 @@ func Setreuid(ruid int, euid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go
index fb161f3a..9d25f76b 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go
@@ -405,6 +405,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -1597,16 +1607,6 @@ func Setreuid(ruid int, euid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go
index 4c8ac993..d3f80351 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go
@@ -405,6 +405,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -1597,16 +1607,6 @@ func Setreuid(ruid int, euid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go
index 76dd8ec4..887188a5 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go
@@ -405,6 +405,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
@@ -1597,16 +1607,6 @@ func Setreuid(ruid int, euid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
index caeb807b..6699a783 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s
index 08744425..04f0de34 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s
@@ -573,11 +573,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $4
DATA ·libc_setresuid_trampoline_addr(SB)/4, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $4
-DATA ·libc_setrlimit_trampoline_addr(SB)/4, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setrtable(SB)
GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $4
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
index a05e5f4f..1e775fe0 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s
index 5782cd10..27b6f4df 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s
@@ -573,11 +573,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setresuid_trampoline_addr(SB)/8, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setrtable(SB)
GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $8
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
index b2da8e50..7f642789 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s
index cf310420..b797045f 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s
@@ -573,11 +573,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $4
DATA ·libc_setresuid_trampoline_addr(SB)/4, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $4
-DATA ·libc_setrlimit_trampoline_addr(SB)/4, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setrtable(SB)
GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $4
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
index 048b2655..756ef7b1 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s
index 484bb42e..a8712662 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s
@@ -573,11 +573,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setresuid_trampoline_addr(SB)/8, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setrtable(SB)
GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $8
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
index 6f33e37e..7bc2e24e 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s
index 55af2726..05d4bffd 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s
@@ -573,11 +573,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setresuid_trampoline_addr(SB)/8, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setrtable(SB)
GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $8
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
index 330cf7f7..739be621 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s
index 4028255b..74a25f8d 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s
@@ -687,12 +687,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setresuid_trampoline_addr(SB)/8, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- CALL libc_setrlimit(SB)
- RET
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
CALL libc_setrtable(SB)
RET
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
index 5f24de0d..7d95a197 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
@@ -527,6 +527,14 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
return
}
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+ _, _, e1 := syscall_syscall(libc_ioctl_trampoline_addr, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
var libc_ioctl_trampoline_addr uintptr
//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
@@ -1886,20 +1894,6 @@ var libc_setresuid_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := syscall_rawSyscall(libc_setrlimit_trampoline_addr, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-var libc_setrlimit_trampoline_addr uintptr
-
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setrtable(rtable int) (err error) {
_, _, e1 := syscall_rawSyscall(libc_setrtable_trampoline_addr, uintptr(rtable), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s
index e1fbd4df..990be245 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s
@@ -573,11 +573,6 @@ TEXT libc_setresuid_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_setresuid_trampoline_addr(SB), RODATA, $8
DATA ·libc_setresuid_trampoline_addr(SB)/8, $libc_setresuid_trampoline<>(SB)
-TEXT libc_setrlimit_trampoline<>(SB),NOSPLIT,$0-0
- JMP libc_setrlimit(SB)
-GLOBL ·libc_setrlimit_trampoline_addr(SB), RODATA, $8
-DATA ·libc_setrlimit_trampoline_addr(SB)/8, $libc_setrlimit_trampoline<>(SB)
-
TEXT libc_setrtable_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_setrtable(SB)
GLOBL ·libc_setrtable_trampoline_addr(SB), RODATA, $8
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
index 78d4a424..609d1c59 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
@@ -110,7 +110,6 @@ import (
//go:cgo_import_dynamic libc_setpriority setpriority "libc.so"
//go:cgo_import_dynamic libc_setregid setregid "libc.so"
//go:cgo_import_dynamic libc_setreuid setreuid "libc.so"
-//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.so"
//go:cgo_import_dynamic libc_setsid setsid "libc.so"
//go:cgo_import_dynamic libc_setuid setuid "libc.so"
//go:cgo_import_dynamic libc_shutdown shutdown "libsocket.so"
@@ -250,7 +249,6 @@ import (
//go:linkname procSetpriority libc_setpriority
//go:linkname procSetregid libc_setregid
//go:linkname procSetreuid libc_setreuid
-//go:linkname procSetrlimit libc_setrlimit
//go:linkname procSetsid libc_setsid
//go:linkname procSetuid libc_setuid
//go:linkname procshutdown libc_shutdown
@@ -391,7 +389,6 @@ var (
procSetpriority,
procSetregid,
procSetreuid,
- procSetrlimit,
procSetsid,
procSetuid,
procshutdown,
@@ -646,7 +643,18 @@ func __minor(version int, dev uint64) (val uint) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) {
+func ioctlRet(fd int, req int, arg uintptr) (ret int, err error) {
+ r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, uintptr(fd), uintptr(req), uintptr(arg), 0, 0, 0)
+ ret = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ioctlPtrRet(fd int, req int, arg unsafe.Pointer) (ret int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, uintptr(fd), uintptr(req), uintptr(arg), 0, 0, 0)
ret = int(r0)
if e1 != 0 {
@@ -1639,16 +1647,6 @@ func Setreuid(ruid int, euid int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Setsid() (pid int, err error) {
r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&procSetsid)), 0, 0, 0, 0, 0, 0, 0)
pid = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go
index f2079457..c3168174 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go
@@ -257,7 +257,17 @@ func munmap(addr uintptr, length uintptr) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ioctl(fd int, req uint, arg uintptr) (err error) {
+func ioctl(fd int, req int, arg uintptr) (err error) {
+ _, _, e1 := syscall_syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
_, _, e1 := syscall_syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
if e1 != 0 {
err = errnoErr(e1)
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
index e2a64f09..690cefc3 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
@@ -151,6 +151,16 @@ type Dirent struct {
_ [3]byte
}
+type Attrlist struct {
+ Bitmapcount uint16
+ Reserved uint16
+ Commonattr uint32
+ Volattr uint32
+ Dirattr uint32
+ Fileattr uint32
+ Forkattr uint32
+}
+
const (
PathMax = 0x400
)
@@ -610,6 +620,7 @@ const (
AT_REMOVEDIR = 0x80
AT_SYMLINK_FOLLOW = 0x40
AT_SYMLINK_NOFOLLOW = 0x20
+ AT_EACCESS = 0x10
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
index 34aa7752..5bffc10e 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
@@ -151,6 +151,16 @@ type Dirent struct {
_ [3]byte
}
+type Attrlist struct {
+ Bitmapcount uint16
+ Reserved uint16
+ Commonattr uint32
+ Volattr uint32
+ Dirattr uint32
+ Fileattr uint32
+ Forkattr uint32
+}
+
const (
PathMax = 0x400
)
@@ -610,6 +620,7 @@ const (
AT_REMOVEDIR = 0x80
AT_SYMLINK_FOLLOW = 0x40
AT_SYMLINK_NOFOLLOW = 0x20
+ AT_EACCESS = 0x10
)
type PollFd struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
index d9c78cdc..29dc4833 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
@@ -362,7 +362,7 @@ type FpExtendedPrecision struct{}
type PtraceIoDesc struct {
Op int32
Offs uintptr
- Addr uintptr
+ Addr *byte
Len uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
index 26991b16..0a89b289 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
@@ -367,7 +367,7 @@ type FpExtendedPrecision struct{}
type PtraceIoDesc struct {
Op int32
Offs uintptr
- Addr uintptr
+ Addr *byte
Len uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
index f8324e7e..c8666bb1 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
@@ -350,7 +350,7 @@ type FpExtendedPrecision struct {
type PtraceIoDesc struct {
Op int32
Offs uintptr
- Addr uintptr
+ Addr *byte
Len uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
index 4220411f..88fb48a8 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
@@ -347,7 +347,7 @@ type FpExtendedPrecision struct{}
type PtraceIoDesc struct {
Op int32
Offs uintptr
- Addr uintptr
+ Addr *byte
Len uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go
index 0660fd45..698dc975 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go
@@ -348,7 +348,7 @@ type FpExtendedPrecision struct{}
type PtraceIoDesc struct {
Op int32
Offs uintptr
- Addr uintptr
+ Addr *byte
Len uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index 7d9fc8f1..ca84727c 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -456,36 +456,60 @@ type Ucred struct {
}
type TCPInfo struct {
- State uint8
- Ca_state uint8
- Retransmits uint8
- Probes uint8
- Backoff uint8
- Options uint8
- Rto uint32
- Ato uint32
- Snd_mss uint32
- Rcv_mss uint32
- Unacked uint32
- Sacked uint32
- Lost uint32
- Retrans uint32
- Fackets uint32
- Last_data_sent uint32
- Last_ack_sent uint32
- Last_data_recv uint32
- Last_ack_recv uint32
- Pmtu uint32
- Rcv_ssthresh uint32
- Rtt uint32
- Rttvar uint32
- Snd_ssthresh uint32
- Snd_cwnd uint32
- Advmss uint32
- Reordering uint32
- Rcv_rtt uint32
- Rcv_space uint32
- Total_retrans uint32
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+ Pacing_rate uint64
+ Max_pacing_rate uint64
+ Bytes_acked uint64
+ Bytes_received uint64
+ Segs_out uint32
+ Segs_in uint32
+ Notsent_bytes uint32
+ Min_rtt uint32
+ Data_segs_in uint32
+ Data_segs_out uint32
+ Delivery_rate uint64
+ Busy_time uint64
+ Rwnd_limited uint64
+ Sndbuf_limited uint64
+ Delivered uint32
+ Delivered_ce uint32
+ Bytes_sent uint64
+ Bytes_retrans uint64
+ Dsack_dups uint32
+ Reord_seen uint32
+ Rcv_ooopack uint32
+ Snd_wnd uint32
+ Rcv_wnd uint32
+ Rehash uint32
}
type CanFilter struct {
@@ -528,7 +552,7 @@ const (
SizeofIPv6MTUInfo = 0x20
SizeofICMPv6Filter = 0x20
SizeofUcred = 0xc
- SizeofTCPInfo = 0x68
+ SizeofTCPInfo = 0xf0
SizeofCanFilter = 0x8
SizeofTCPRepairOpt = 0x8
)
@@ -1043,6 +1067,7 @@ const (
PerfBitCommExec = CBitFieldMaskBit24
PerfBitUseClockID = CBitFieldMaskBit25
PerfBitContextSwitch = CBitFieldMaskBit26
+ PerfBitWriteBackward = CBitFieldMaskBit27
)
const (
@@ -1239,7 +1264,7 @@ type TCPMD5Sig struct {
Flags uint8
Prefixlen uint8
Keylen uint16
- _ uint32
+ Ifindex int32
Key [80]uint8
}
@@ -1939,7 +1964,11 @@ const (
NFT_MSG_GETOBJ = 0x13
NFT_MSG_DELOBJ = 0x14
NFT_MSG_GETOBJ_RESET = 0x15
- NFT_MSG_MAX = 0x19
+ NFT_MSG_NEWFLOWTABLE = 0x16
+ NFT_MSG_GETFLOWTABLE = 0x17
+ NFT_MSG_DELFLOWTABLE = 0x18
+ NFT_MSG_GETRULE_RESET = 0x19
+ NFT_MSG_MAX = 0x1a
NFTA_LIST_UNSPEC = 0x0
NFTA_LIST_ELEM = 0x1
NFTA_HOOK_UNSPEC = 0x0
@@ -2443,9 +2472,11 @@ const (
SOF_TIMESTAMPING_OPT_STATS = 0x1000
SOF_TIMESTAMPING_OPT_PKTINFO = 0x2000
SOF_TIMESTAMPING_OPT_TX_SWHW = 0x4000
+ SOF_TIMESTAMPING_BIND_PHC = 0x8000
+ SOF_TIMESTAMPING_OPT_ID_TCP = 0x10000
- SOF_TIMESTAMPING_LAST = 0x8000
- SOF_TIMESTAMPING_MASK = 0xffff
+ SOF_TIMESTAMPING_LAST = 0x10000
+ SOF_TIMESTAMPING_MASK = 0x1ffff
SCM_TSTAMP_SND = 0x0
SCM_TSTAMP_SCHED = 0x1
@@ -3265,7 +3296,7 @@ const (
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES = 0xae
DEVLINK_ATTR_NESTED_DEVLINK = 0xaf
DEVLINK_ATTR_SELFTESTS = 0xb0
- DEVLINK_ATTR_MAX = 0xb0
+ DEVLINK_ATTR_MAX = 0xb3
DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0x0
DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 0x1
DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0x0
@@ -3281,7 +3312,8 @@ const (
DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 0x1
DEVLINK_PORT_FN_ATTR_STATE = 0x2
DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3
- DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x3
+ DEVLINK_PORT_FN_ATTR_CAPS = 0x4
+ DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x4
)
type FsverityDigest struct {
@@ -3572,7 +3604,8 @@ const (
ETHTOOL_MSG_MODULE_SET = 0x23
ETHTOOL_MSG_PSE_GET = 0x24
ETHTOOL_MSG_PSE_SET = 0x25
- ETHTOOL_MSG_USER_MAX = 0x25
+ ETHTOOL_MSG_RSS_GET = 0x26
+ ETHTOOL_MSG_USER_MAX = 0x26
ETHTOOL_MSG_KERNEL_NONE = 0x0
ETHTOOL_MSG_STRSET_GET_REPLY = 0x1
ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2
@@ -3611,7 +3644,8 @@ const (
ETHTOOL_MSG_MODULE_GET_REPLY = 0x23
ETHTOOL_MSG_MODULE_NTF = 0x24
ETHTOOL_MSG_PSE_GET_REPLY = 0x25
- ETHTOOL_MSG_KERNEL_MAX = 0x25
+ ETHTOOL_MSG_RSS_GET_REPLY = 0x26
+ ETHTOOL_MSG_KERNEL_MAX = 0x26
ETHTOOL_A_HEADER_UNSPEC = 0x0
ETHTOOL_A_HEADER_DEV_INDEX = 0x1
ETHTOOL_A_HEADER_DEV_NAME = 0x2
@@ -3679,7 +3713,8 @@ const (
ETHTOOL_A_LINKSTATE_SQI_MAX = 0x4
ETHTOOL_A_LINKSTATE_EXT_STATE = 0x5
ETHTOOL_A_LINKSTATE_EXT_SUBSTATE = 0x6
- ETHTOOL_A_LINKSTATE_MAX = 0x6
+ ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT = 0x7
+ ETHTOOL_A_LINKSTATE_MAX = 0x7
ETHTOOL_A_DEBUG_UNSPEC = 0x0
ETHTOOL_A_DEBUG_HEADER = 0x1
ETHTOOL_A_DEBUG_MSGMASK = 0x2
@@ -4409,7 +4444,7 @@ const (
NL80211_ATTR_MAC_HINT = 0xc8
NL80211_ATTR_MAC_MASK = 0xd7
NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca
- NL80211_ATTR_MAX = 0x140
+ NL80211_ATTR_MAX = 0x141
NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4
NL80211_ATTR_MAX_CSA_COUNTERS = 0xce
NL80211_ATTR_MAX_MATCH_SETS = 0x85
@@ -4552,6 +4587,7 @@ const (
NL80211_ATTR_SUPPORT_MESH_AUTH = 0x73
NL80211_ATTR_SURVEY_INFO = 0x54
NL80211_ATTR_SURVEY_RADIO_STATS = 0xda
+ NL80211_ATTR_TD_BITMAP = 0x141
NL80211_ATTR_TDLS_ACTION = 0x88
NL80211_ATTR_TDLS_DIALOG_TOKEN = 0x89
NL80211_ATTR_TDLS_EXTERNAL_SETUP = 0x8c
@@ -5752,3 +5788,25 @@ const (
AUDIT_NLGRP_NONE = 0x0
AUDIT_NLGRP_READLOG = 0x1
)
+
+const (
+ TUN_F_CSUM = 0x1
+ TUN_F_TSO4 = 0x2
+ TUN_F_TSO6 = 0x4
+ TUN_F_TSO_ECN = 0x8
+ TUN_F_UFO = 0x10
+)
+
+const (
+ VIRTIO_NET_HDR_F_NEEDS_CSUM = 0x1
+ VIRTIO_NET_HDR_F_DATA_VALID = 0x2
+ VIRTIO_NET_HDR_F_RSC_INFO = 0x4
+)
+
+const (
+ VIRTIO_NET_HDR_GSO_NONE = 0x0
+ VIRTIO_NET_HDR_GSO_TCPV4 = 0x1
+ VIRTIO_NET_HDR_GSO_UDP = 0x3
+ VIRTIO_NET_HDR_GSO_TCPV6 = 0x4
+ VIRTIO_NET_HDR_GSO_ECN = 0x80
+)
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
index 89c516a2..4ecc1495 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
@@ -414,7 +414,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [122]int8
+ Data [122]byte
_ uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
index 62b4fb26..34fddff9 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
@@ -427,7 +427,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
index e86b3589..3b14a603 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
@@ -405,7 +405,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [122]uint8
+ Data [122]byte
_ uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
index 6c6be4c9..0517651a 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
@@ -406,7 +406,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
index 4982ea35..3b0c5181 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
@@ -407,7 +407,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
index 173141a6..fccdf4dd 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
@@ -410,7 +410,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [122]int8
+ Data [122]byte
_ uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
index 93ae4c51..500de8fc 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
@@ -409,7 +409,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
index 4e4e510c..d0434cd2 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
@@ -409,7 +409,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
index 3f5ba013..84206ba5 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
@@ -410,7 +410,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [122]int8
+ Data [122]byte
_ uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
index 71dfe7cd..ab078cf1 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
@@ -417,7 +417,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [122]uint8
+ Data [122]byte
_ uint32
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
index 3a2b7f0a..42eb2c4c 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
@@ -416,7 +416,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]uint8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
index a52d6275..31304a4e 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
@@ -416,7 +416,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]uint8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
index dfc007d8..c311f961 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
@@ -434,7 +434,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]uint8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
index b53cb910..bba3cefa 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
@@ -429,7 +429,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
index fe0aa354..ad8a0138 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
@@ -411,7 +411,7 @@ const (
type SockaddrStorage struct {
Family uint16
- _ [118]int8
+ Data [118]byte
_ uint64
}
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 41cb3c01..3723b2c2 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -824,6 +824,9 @@ const socket_error = uintptr(^uint32(0))
//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
+//sys WSALookupServiceBegin(querySet *WSAQUERYSET, flags uint32, handle *Handle) (err error) [failretval==socket_error] = ws2_32.WSALookupServiceBeginW
+//sys WSALookupServiceNext(handle Handle, flags uint32, size *int32, querySet *WSAQUERYSET) (err error) [failretval==socket_error] = ws2_32.WSALookupServiceNextW
+//sys WSALookupServiceEnd(handle Handle) (err error) [failretval==socket_error] = ws2_32.WSALookupServiceEnd
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
//sys sendto(s Handle, buf []byte, flags int32, to unsafe.Pointer, tolen int32) (err error) [failretval==socket_error] = ws2_32.sendto
//sys recvfrom(s Handle, buf []byte, flags int32, from *RawSockaddrAny, fromlen *int32) (n int32, err error) [failretval==-1] = ws2_32.recvfrom
@@ -1019,8 +1022,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
for n < len(pp.Path) && pp.Path[n] != 0 {
n++
}
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
- sa.Name = string(bytes)
+ sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
return sa, nil
case AF_INET:
diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go
index 0c4add97..0dbb2084 100644
--- a/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/vendor/golang.org/x/sys/windows/types_windows.go
@@ -1243,6 +1243,51 @@ const (
DnsSectionAdditional = 0x0003
)
+const (
+ // flags of WSALookupService
+ LUP_DEEP = 0x0001
+ LUP_CONTAINERS = 0x0002
+ LUP_NOCONTAINERS = 0x0004
+ LUP_NEAREST = 0x0008
+ LUP_RETURN_NAME = 0x0010
+ LUP_RETURN_TYPE = 0x0020
+ LUP_RETURN_VERSION = 0x0040
+ LUP_RETURN_COMMENT = 0x0080
+ LUP_RETURN_ADDR = 0x0100
+ LUP_RETURN_BLOB = 0x0200
+ LUP_RETURN_ALIASES = 0x0400
+ LUP_RETURN_QUERY_STRING = 0x0800
+ LUP_RETURN_ALL = 0x0FF0
+ LUP_RES_SERVICE = 0x8000
+
+ LUP_FLUSHCACHE = 0x1000
+ LUP_FLUSHPREVIOUS = 0x2000
+
+ LUP_NON_AUTHORITATIVE = 0x4000
+ LUP_SECURE = 0x8000
+ LUP_RETURN_PREFERRED_NAMES = 0x10000
+ LUP_DNS_ONLY = 0x20000
+
+ LUP_ADDRCONFIG = 0x100000
+ LUP_DUAL_ADDR = 0x200000
+ LUP_FILESERVER = 0x400000
+ LUP_DISABLE_IDN_ENCODING = 0x00800000
+ LUP_API_ANSI = 0x01000000
+
+ LUP_RESOLUTION_HANDLE = 0x80000000
+)
+
+const (
+ // values of WSAQUERYSET's namespace
+ NS_ALL = 0
+ NS_DNS = 12
+ NS_NLA = 15
+ NS_BTH = 16
+ NS_EMAIL = 37
+ NS_PNRPNAME = 38
+ NS_PNRPCLOUD = 39
+)
+
type DNSSRVData struct {
Target *uint16
Priority uint16
@@ -2184,10 +2229,10 @@ const (
JobObjectExtendedLimitInformation = 9
JobObjectGroupInformation = 11
JobObjectGroupInformationEx = 14
- JobObjectLimitViolationInformation2 = 35
+ JobObjectLimitViolationInformation2 = 34
JobObjectNetRateControlInformation = 32
JobObjectNotificationLimitInformation = 12
- JobObjectNotificationLimitInformation2 = 34
+ JobObjectNotificationLimitInformation2 = 33
JobObjectSecurityLimitInformation = 5
)
@@ -3258,3 +3303,43 @@ const (
DWMWA_TEXT_COLOR = 36
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37
)
+
+type WSAQUERYSET struct {
+ Size uint32
+ ServiceInstanceName *uint16
+ ServiceClassId *GUID
+ Version *WSAVersion
+ Comment *uint16
+ NameSpace uint32
+ NSProviderId *GUID
+ Context *uint16
+ NumberOfProtocols uint32
+ AfpProtocols *AFProtocols
+ QueryString *uint16
+ NumberOfCsAddrs uint32
+ SaBuffer *CSAddrInfo
+ OutputFlags uint32
+ Blob *BLOB
+}
+
+type WSAVersion struct {
+ Version uint32
+ EnumerationOfComparison int32
+}
+
+type AFProtocols struct {
+ AddressFamily int32
+ Protocol int32
+}
+
+type CSAddrInfo struct {
+ LocalAddr SocketAddress
+ RemoteAddr SocketAddress
+ SocketType int32
+ Protocol int32
+}
+
+type BLOB struct {
+ Size uint32
+ BlobData *byte
+}
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index ac60052e..6d2a2685 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -474,6 +474,9 @@ var (
procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW")
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procWSALookupServiceBeginW = modws2_32.NewProc("WSALookupServiceBeginW")
+ procWSALookupServiceEnd = modws2_32.NewProc("WSALookupServiceEnd")
+ procWSALookupServiceNextW = modws2_32.NewProc("WSALookupServiceNextW")
procWSARecv = modws2_32.NewProc("WSARecv")
procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
procWSASend = modws2_32.NewProc("WSASend")
@@ -4067,6 +4070,30 @@ func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbo
return
}
+func WSALookupServiceBegin(querySet *WSAQUERYSET, flags uint32, handle *Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procWSALookupServiceBeginW.Addr(), 3, uintptr(unsafe.Pointer(querySet)), uintptr(flags), uintptr(unsafe.Pointer(handle)))
+ if r1 == socket_error {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func WSALookupServiceEnd(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procWSALookupServiceEnd.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == socket_error {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func WSALookupServiceNext(handle Handle, flags uint32, size *int32, querySet *WSAQUERYSET) (err error) {
+ r1, _, e1 := syscall.Syscall6(procWSALookupServiceNextW.Addr(), 4, uintptr(handle), uintptr(flags), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(querySet)), 0, 0)
+ if r1 == socket_error {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := syscall.Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if r1 == socket_error {
diff --git a/vendor/golang.org/x/text/unicode/norm/forminfo.go b/vendor/golang.org/x/text/unicode/norm/forminfo.go
index d69ccb4f..487335d1 100644
--- a/vendor/golang.org/x/text/unicode/norm/forminfo.go
+++ b/vendor/golang.org/x/text/unicode/norm/forminfo.go
@@ -13,7 +13,7 @@ import "encoding/binary"
// a rune to a uint16. The values take two forms. For v >= 0x8000:
// bits
// 15: 1 (inverse of NFD_QC bit of qcInfo)
-// 13..7: qcInfo (see below). isYesD is always true (no decompostion).
+// 13..7: qcInfo (see below). isYesD is always true (no decomposition).
// 6..0: ccc (compressed CCC value).
// For v < 0x8000, the respective rune has a decomposition and v is an index
// into a byte array of UTF-8 decomposition sequences and additional info and
diff --git a/vendor/modules.txt b/vendor/modules.txt
index f78ecb5d..2bfe53c8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -501,6 +501,10 @@ github.com/karrick/godirwalk
# github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
## explicit
github.com/kballard/go-shellquote
+# github.com/keeper-security/secrets-manager-go/core v1.6.2
+## explicit; go 1.14
+github.com/keeper-security/secrets-manager-go/core
+github.com/keeper-security/secrets-manager-go/core/logger
# github.com/mattn/go-colorable v0.1.13
## explicit; go 1.15
github.com/mattn/go-colorable
@@ -781,8 +785,6 @@ golang.org/x/text/width
# golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
## explicit
golang.org/x/time/rate
-# golang.org/x/tools v0.6.0
-## explicit; go 1.18
# google.golang.org/api v0.40.0
## explicit; go 1.11
google.golang.org/api/internal