chore: make deps, go mod vendor
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
f664599836
commit
31fa9b1a7a
93
go.mod
93
go.mod
@ -1,6 +1,8 @@
|
|||||||
module coopcloud.tech/abra
|
module coopcloud.tech/abra
|
||||||
|
|
||||||
go 1.21
|
go 1.22.7
|
||||||
|
|
||||||
|
toolchain go1.23.1
|
||||||
|
|
||||||
replace github.com/urfave/cli/v3 => github.com/urfave/cli/v3 v3.0.0-alpha9.1.0.20241019193437-5053ec708a44
|
replace github.com/urfave/cli/v3 => github.com/urfave/cli/v3 v3.0.0-alpha9.1.0.20241019193437-5053ec708a44
|
||||||
|
|
||||||
@ -8,38 +10,38 @@ require (
|
|||||||
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb
|
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb
|
||||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355
|
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||||
github.com/charmbracelet/lipgloss v0.11.1
|
github.com/charmbracelet/lipgloss v1.0.0
|
||||||
github.com/charmbracelet/log v0.4.0
|
github.com/charmbracelet/log v0.4.0
|
||||||
github.com/distribution/reference v0.6.0
|
github.com/distribution/reference v0.6.0
|
||||||
github.com/docker/cli v27.0.3+incompatible
|
github.com/docker/cli v27.3.1+incompatible
|
||||||
github.com/docker/docker v27.0.3+incompatible
|
github.com/docker/docker v27.3.1+incompatible
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/go-git/go-git/v5 v5.12.0
|
github.com/go-git/go-git/v5 v5.12.0
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
github.com/moby/sys/signal v0.7.0
|
github.com/moby/sys/signal v0.7.1
|
||||||
github.com/moby/term v0.5.0
|
github.com/moby/term v0.5.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/schollz/progressbar/v3 v3.14.4
|
github.com/schollz/progressbar/v3 v3.17.1
|
||||||
github.com/urfave/cli/v3 v3.0.0-alpha9
|
github.com/urfave/cli/v3 v3.0.0-alpha9
|
||||||
golang.org/x/term v0.22.0
|
golang.org/x/term v0.26.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gotest.tools/v3 v3.5.1
|
gotest.tools/v3 v3.5.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.1 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.0.0 // indirect
|
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.1.3 // indirect
|
github.com/charmbracelet/x/ansi v0.5.2 // indirect
|
||||||
github.com/cloudflare/circl v1.3.9 // indirect
|
github.com/cloudflare/circl v1.5.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
|
github.com/cyphar/filepath-securejoin v0.3.4 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||||
@ -50,31 +52,32 @@ require (
|
|||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.5.0 // indirect
|
github.com/go-git/go-billy/v5 v5.6.0 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/sys/user v0.1.0 // indirect
|
github.com/moby/sys/user v0.3.0 // indirect
|
||||||
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/muesli/termenv v0.15.2 // indirect
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
@ -83,41 +86,41 @@ require (
|
|||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.55.0 // indirect
|
github.com/prometheus/common v0.60.1 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
golang.org/x/crypto v0.25.0 // indirect
|
golang.org/x/crypto v0.29.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/net v0.31.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.20.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.8.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
|
||||||
google.golang.org/grpc v1.65.0 // indirect
|
google.golang.org/grpc v1.68.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.35.2 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/containerd/containerd v1.7.19 // indirect
|
github.com/containerd/containerd v1.7.24 // indirect
|
||||||
github.com/containers/image v3.0.2+incompatible
|
github.com/containers/image v3.0.2+incompatible
|
||||||
github.com/containers/storage v1.38.2 // indirect
|
github.com/containers/storage v1.38.2 // indirect
|
||||||
github.com/decentral1se/passgen v1.0.1
|
github.com/decentral1se/passgen v1.0.1
|
||||||
@ -127,13 +130,13 @@ require (
|
|||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.7
|
github.com/hashicorp/go-retryablehttp v0.7.7
|
||||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||||
github.com/spf13/cobra v1.8.1 // indirect
|
github.com/spf13/cobra v1.8.1 // indirect
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
golang.org/x/sys v0.22.0
|
golang.org/x/sys v0.27.0
|
||||||
)
|
)
|
||||||
|
95
go.sum
95
go.sum
@ -26,6 +26,8 @@ coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb h1:Ws6WEwKXeaYEkfdkX6Aq
|
|||||||
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb/go.mod h1:ESVm0wQKcbcFi06jItF3rI7enf4Jt2PvbkWpDDHk1DQ=
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355 h1:tCv2B4qoN6RMheKDnCzIafOkWS5BB1h7hwhmo+9bVeE=
|
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355 h1:tCv2B4qoN6RMheKDnCzIafOkWS5BB1h7hwhmo+9bVeE=
|
||||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355/go.mod h1:Q8V1zbtPAlzYSr/Dvky3wS6x58IQAl3rot2me1oSO2Q=
|
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355/go.mod h1:Q8V1zbtPAlzYSr/Dvky3wS6x58IQAl3rot2me1oSO2Q=
|
||||||
@ -81,6 +83,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe
|
|||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
@ -130,16 +134,21 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
|
|||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/charmbracelet/lipgloss v0.11.1 h1:a8KgVPHa7kOoP95vm2tQQrjD2AKhbWmfr4uJ2RW6kNk=
|
github.com/charmbracelet/lipgloss v0.11.1 h1:a8KgVPHa7kOoP95vm2tQQrjD2AKhbWmfr4uJ2RW6kNk=
|
||||||
github.com/charmbracelet/lipgloss v0.11.1/go.mod h1:beLlcmkF7MWA+5UrKKIRo/VJ21xGXr7YJ9miWfdMRIU=
|
github.com/charmbracelet/lipgloss v0.11.1/go.mod h1:beLlcmkF7MWA+5UrKKIRo/VJ21xGXr7YJ9miWfdMRIU=
|
||||||
|
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
|
||||||
|
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
|
||||||
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
||||||
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
||||||
github.com/charmbracelet/x/ansi v0.1.3 h1:RBh/eleNWML5R524mjUF0yVRePTwqN9tPtV+DPgO5Lw=
|
github.com/charmbracelet/x/ansi v0.1.3 h1:RBh/eleNWML5R524mjUF0yVRePTwqN9tPtV+DPgO5Lw=
|
||||||
github.com/charmbracelet/x/ansi v0.1.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
github.com/charmbracelet/x/ansi v0.1.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||||
|
github.com/charmbracelet/x/ansi v0.5.2 h1:dEa1x2qdOZXD/6439s+wF7xjV+kZLu/iN00GuXXrU9E=
|
||||||
|
github.com/charmbracelet/x/ansi v0.5.2/go.mod h1:KBUFw1la39nl0dLl10l5ORDAqGXaeurTQmwyyVKse/Q=
|
||||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||||
@ -158,6 +167,8 @@ github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON
|
|||||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||||
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
|
||||||
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||||
|
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||||
|
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
@ -198,6 +209,8 @@ github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTV
|
|||||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||||
github.com/containerd/containerd v1.7.19 h1:/xQ4XRJ0tamDkdzrrBAUy/LE5nCcxFKdBm4EcPrSMEE=
|
github.com/containerd/containerd v1.7.19 h1:/xQ4XRJ0tamDkdzrrBAUy/LE5nCcxFKdBm4EcPrSMEE=
|
||||||
github.com/containerd/containerd v1.7.19/go.mod h1:h4FtNYUUMB4Phr6v+xG89RYKj9XccvbNSCKjdufCrkc=
|
github.com/containerd/containerd v1.7.19/go.mod h1:h4FtNYUUMB4Phr6v+xG89RYKj9XccvbNSCKjdufCrkc=
|
||||||
|
github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA=
|
||||||
|
github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
|
||||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
@ -283,6 +296,8 @@ github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2
|
|||||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
|
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
|
||||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||||
@ -303,6 +318,8 @@ github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyG
|
|||||||
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ=
|
github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ=
|
||||||
github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ=
|
||||||
|
github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
||||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
@ -311,6 +328,8 @@ github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc
|
|||||||
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
|
github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
|
||||||
github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
|
||||||
|
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
@ -374,6 +393,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
|
|||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||||
|
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
|
||||||
|
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||||
@ -411,6 +432,8 @@ github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
|
|||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||||
@ -436,6 +459,8 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
|
|||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
@ -515,9 +540,12 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
|
|||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@ -582,6 +610,8 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
|
|||||||
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -621,6 +651,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
@ -656,11 +688,19 @@ github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vyg
|
|||||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||||
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
|
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
|
||||||
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
|
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
|
||||||
|
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
|
||||||
|
github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
|
||||||
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
|
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
|
||||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||||
|
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||||
|
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
|
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
@ -702,6 +742,7 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
|
|||||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||||
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
@ -760,6 +801,8 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ
|
|||||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||||
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
@ -775,6 +818,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+
|
|||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
|
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||||
|
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
@ -797,12 +842,15 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
|||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/schollz/progressbar/v3 v3.14.4 h1:W9ZrDSJk7eqmQhd3uxFNNcTr0QL+xuGNI9dEMrw0r74=
|
github.com/schollz/progressbar/v3 v3.14.4 h1:W9ZrDSJk7eqmQhd3uxFNNcTr0QL+xuGNI9dEMrw0r74=
|
||||||
github.com/schollz/progressbar/v3 v3.14.4/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
|
github.com/schollz/progressbar/v3 v3.14.4/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
|
||||||
|
github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U=
|
||||||
|
github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4=
|
||||||
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||||
@ -821,6 +869,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
|||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
|
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
|
||||||
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||||
|
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||||
|
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
@ -864,6 +914,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||||
@ -923,24 +975,42 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
|
||||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||||
|
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||||
|
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||||
|
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
|
||||||
|
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
|
go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
|
go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||||
|
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||||
|
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||||
@ -972,6 +1042,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
|
|||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
|
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||||
|
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -984,6 +1056,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
|||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||||
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
|
||||||
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@ -1053,6 +1127,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
|
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||||
|
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -1073,6 +1149,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||||
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -1157,6 +1235,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
|
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -1166,6 +1246,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
|||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
|
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||||
|
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -1179,6 +1261,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@ -1187,6 +1271,8 @@ golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxb
|
|||||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||||
|
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -1283,8 +1369,12 @@ google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7Fc
|
|||||||
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
||||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
@ -1306,6 +1396,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
|||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||||
|
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||||
|
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@ -1321,6 +1413,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
|||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
|
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||||
|
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||||
@ -1360,6 +1454,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||||
|
3
vendor/dario.cat/mergo/.gitignore
vendored
3
vendor/dario.cat/mergo/.gitignore
vendored
@ -13,6 +13,9 @@
|
|||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
|
# Golang/Intellij
|
||||||
|
.idea
|
||||||
|
|
||||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||||
.glide/
|
.glide/
|
||||||
|
|
||||||
|
102
vendor/dario.cat/mergo/README.md
vendored
102
vendor/dario.cat/mergo/README.md
vendored
@ -44,13 +44,21 @@ Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, Microsoft, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
|
Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||||
|
|
||||||
|
No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases.
|
||||||
|
|
||||||
### Important notes
|
### Important notes
|
||||||
|
|
||||||
#### 1.0.0
|
#### 1.0.0
|
||||||
|
|
||||||
In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`.
|
In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released.
|
||||||
|
|
||||||
|
If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
|
||||||
|
```
|
||||||
|
|
||||||
#### 0.3.9
|
#### 0.3.9
|
||||||
|
|
||||||
@ -64,55 +72,24 @@ If you were using Mergo before April 6th, 2015, please check your project works
|
|||||||
|
|
||||||
If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
|
If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
|
||||||
|
|
||||||
<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
|
||||||
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
|
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
|
||||||
<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
|
<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
|
||||||
|
|
||||||
### Mergo in the wild
|
### Mergo in the wild
|
||||||
|
|
||||||
- [moby/moby](https://github.com/moby/moby)
|
Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including:
|
||||||
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
|
||||||
- [vmware/dispatch](https://github.com/vmware/dispatch)
|
* [containerd/containerd](https://github.com/containerd/containerd)
|
||||||
- [Shopify/themekit](https://github.com/Shopify/themekit)
|
* [datadog/datadog-agent](https://github.com/datadog/datadog-agent)
|
||||||
- [imdario/zas](https://github.com/imdario/zas)
|
* [docker/cli/](https://github.com/docker/cli/)
|
||||||
- [matcornic/hermes](https://github.com/matcornic/hermes)
|
* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
|
||||||
- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
|
* [go-micro/go-micro](https://github.com/go-micro/go-micro)
|
||||||
- [kataras/iris](https://github.com/kataras/iris)
|
* [grafana/loki](https://github.com/grafana/loki)
|
||||||
- [michaelsauter/crane](https://github.com/michaelsauter/crane)
|
* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||||
- [go-task/task](https://github.com/go-task/task)
|
* [masterminds/sprig](github.com/Masterminds/sprig)
|
||||||
- [sensu/uchiwa](https://github.com/sensu/uchiwa)
|
* [moby/moby](https://github.com/moby/moby)
|
||||||
- [ory/hydra](https://github.com/ory/hydra)
|
* [slackhq/nebula](https://github.com/slackhq/nebula)
|
||||||
- [sisatech/vcli](https://github.com/sisatech/vcli)
|
* [volcano-sh/volcano](https://github.com/volcano-sh/volcano)
|
||||||
- [dairycart/dairycart](https://github.com/dairycart/dairycart)
|
|
||||||
- [projectcalico/felix](https://github.com/projectcalico/felix)
|
|
||||||
- [resin-os/balena](https://github.com/resin-os/balena)
|
|
||||||
- [go-kivik/kivik](https://github.com/go-kivik/kivik)
|
|
||||||
- [Telefonica/govice](https://github.com/Telefonica/govice)
|
|
||||||
- [supergiant/supergiant](supergiant/supergiant)
|
|
||||||
- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
|
|
||||||
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
|
|
||||||
- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
|
|
||||||
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
|
|
||||||
- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
|
|
||||||
- [russross/canvasassignments](https://github.com/russross/canvasassignments)
|
|
||||||
- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
|
|
||||||
- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
|
|
||||||
- [divshot/gitling](https://github.com/divshot/gitling)
|
|
||||||
- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
|
|
||||||
- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
|
|
||||||
- [elwinar/rambler](https://github.com/elwinar/rambler)
|
|
||||||
- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
|
|
||||||
- [jfbus/impressionist](https://github.com/jfbus/impressionist)
|
|
||||||
- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
|
|
||||||
- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
|
|
||||||
- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
|
|
||||||
- [thoas/picfit](https://github.com/thoas/picfit)
|
|
||||||
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
|
|
||||||
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
|
|
||||||
- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
|
|
||||||
- [containerssh/containerssh](https://github.com/containerssh/containerssh)
|
|
||||||
- [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
|
|
||||||
- [tjpnz/structbot](https://github.com/tjpnz/structbot)
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@ -141,6 +118,39 @@ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"dario.cat/mergo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
A *string
|
||||||
|
B int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
first := "first"
|
||||||
|
second := "second"
|
||||||
|
src := Foo{
|
||||||
|
A: &first,
|
||||||
|
B: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
dest := Foo{
|
||||||
|
A: &second,
|
||||||
|
B: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
|
Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
2
vendor/dario.cat/mergo/map.go
vendored
2
vendor/dario.cat/mergo/map.go
vendored
@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
|
|||||||
}
|
}
|
||||||
fieldName := field.Name
|
fieldName := field.Name
|
||||||
fieldName = changeInitialCase(fieldName, unicode.ToLower)
|
fieldName = changeInitialCase(fieldName, unicode.ToLower)
|
||||||
if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) || overwrite) {
|
if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue {
|
||||||
dstMap[fieldName] = src.Field(i).Interface()
|
dstMap[fieldName] = src.Field(i).Interface()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
vendor/dario.cat/mergo/merge.go
vendored
2
vendor/dario.cat/mergo/merge.go
vendored
@ -269,7 +269,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
|||||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else if src.Elem().Kind() != reflect.Struct {
|
||||||
if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
|
if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
|
||||||
dst.Set(src)
|
dst.Set(src)
|
||||||
}
|
}
|
||||||
|
5
vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
generated
vendored
5
vendor/github.com/ProtonMail/go-crypto/ocb/ocb.go
generated
vendored
@ -18,8 +18,9 @@ import (
|
|||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/ProtonMail/go-crypto/internal/byteutil"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/internal/byteutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ocb struct {
|
type ocb struct {
|
||||||
@ -153,7 +154,7 @@ func (o *ocb) crypt(instruction int, Y, nonce, adata, X []byte) []byte {
|
|||||||
truncatedNonce := make([]byte, len(nonce))
|
truncatedNonce := make([]byte, len(nonce))
|
||||||
copy(truncatedNonce, nonce)
|
copy(truncatedNonce, nonce)
|
||||||
truncatedNonce[len(truncatedNonce)-1] &= 192
|
truncatedNonce[len(truncatedNonce)-1] &= 192
|
||||||
Ktop := make([]byte, blockSize)
|
var Ktop []byte
|
||||||
if bytes.Equal(truncatedNonce, o.reusableKtop.noncePrefix) {
|
if bytes.Equal(truncatedNonce, o.reusableKtop.noncePrefix) {
|
||||||
Ktop = o.reusableKtop.Ktop
|
Ktop = o.reusableKtop.Ktop
|
||||||
} else {
|
} else {
|
||||||
|
66
vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
generated
vendored
66
vendor/github.com/ProtonMail/go-crypto/openpgp/armor/armor.go
generated
vendored
@ -23,7 +23,7 @@ import (
|
|||||||
// Headers
|
// Headers
|
||||||
//
|
//
|
||||||
// base64-encoded Bytes
|
// base64-encoded Bytes
|
||||||
// '=' base64 encoded checksum
|
// '=' base64 encoded checksum (optional) not checked anymore
|
||||||
// -----END Type-----
|
// -----END Type-----
|
||||||
//
|
//
|
||||||
// where Headers is a possibly empty sequence of Key: Value lines.
|
// where Headers is a possibly empty sequence of Key: Value lines.
|
||||||
@ -40,36 +40,15 @@ type Block struct {
|
|||||||
|
|
||||||
var ArmorCorrupt error = errors.StructuralError("armor invalid")
|
var ArmorCorrupt error = errors.StructuralError("armor invalid")
|
||||||
|
|
||||||
const crc24Init = 0xb704ce
|
|
||||||
const crc24Poly = 0x1864cfb
|
|
||||||
const crc24Mask = 0xffffff
|
|
||||||
|
|
||||||
// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
|
|
||||||
func crc24(crc uint32, d []byte) uint32 {
|
|
||||||
for _, b := range d {
|
|
||||||
crc ^= uint32(b) << 16
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
crc <<= 1
|
|
||||||
if crc&0x1000000 != 0 {
|
|
||||||
crc ^= crc24Poly
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return crc
|
|
||||||
}
|
|
||||||
|
|
||||||
var armorStart = []byte("-----BEGIN ")
|
var armorStart = []byte("-----BEGIN ")
|
||||||
var armorEnd = []byte("-----END ")
|
var armorEnd = []byte("-----END ")
|
||||||
var armorEndOfLine = []byte("-----")
|
var armorEndOfLine = []byte("-----")
|
||||||
|
|
||||||
// lineReader wraps a line based reader. It watches for the end of an armor
|
// lineReader wraps a line based reader. It watches for the end of an armor block
|
||||||
// block and records the expected CRC value.
|
|
||||||
type lineReader struct {
|
type lineReader struct {
|
||||||
in *bufio.Reader
|
in *bufio.Reader
|
||||||
buf []byte
|
buf []byte
|
||||||
eof bool
|
eof bool
|
||||||
crc uint32
|
|
||||||
crcSet bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lineReader) Read(p []byte) (n int, err error) {
|
func (l *lineReader) Read(p []byte) (n int, err error) {
|
||||||
@ -98,26 +77,9 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
|
|||||||
|
|
||||||
if len(line) == 5 && line[0] == '=' {
|
if len(line) == 5 && line[0] == '=' {
|
||||||
// This is the checksum line
|
// This is the checksum line
|
||||||
var expectedBytes [3]byte
|
// Don't check the checksum
|
||||||
var m int
|
|
||||||
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
|
|
||||||
if m != 3 || err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
l.crc = uint32(expectedBytes[0])<<16 |
|
|
||||||
uint32(expectedBytes[1])<<8 |
|
|
||||||
uint32(expectedBytes[2])
|
|
||||||
|
|
||||||
line, _, err = l.in.ReadLine()
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !bytes.HasPrefix(line, armorEnd) {
|
|
||||||
return 0, ArmorCorrupt
|
|
||||||
}
|
|
||||||
|
|
||||||
l.eof = true
|
l.eof = true
|
||||||
l.crcSet = true
|
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,23 +100,14 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
|
// openpgpReader passes Read calls to the underlying base64 decoder.
|
||||||
// a running CRC of the resulting data and checks the CRC against the value
|
|
||||||
// found by the lineReader at EOF.
|
|
||||||
type openpgpReader struct {
|
type openpgpReader struct {
|
||||||
lReader *lineReader
|
lReader *lineReader
|
||||||
b64Reader io.Reader
|
b64Reader io.Reader
|
||||||
currentCRC uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *openpgpReader) Read(p []byte) (n int, err error) {
|
func (r *openpgpReader) Read(p []byte) (n int, err error) {
|
||||||
n, err = r.b64Reader.Read(p)
|
n, err = r.b64Reader.Read(p)
|
||||||
r.currentCRC = crc24(r.currentCRC, p[:n])
|
|
||||||
|
|
||||||
if err == io.EOF && r.lReader.crcSet && r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
|
|
||||||
return 0, ArmorCorrupt
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +175,6 @@ TryNextBlock:
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.lReader.in = r
|
p.lReader.in = r
|
||||||
p.oReader.currentCRC = crc24Init
|
|
||||||
p.oReader.lReader = &p.lReader
|
p.oReader.lReader = &p.lReader
|
||||||
p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
|
p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
|
||||||
p.Body = &p.oReader
|
p.Body = &p.oReader
|
||||||
|
77
vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go
generated
vendored
77
vendor/github.com/ProtonMail/go-crypto/openpgp/armor/encode.go
generated
vendored
@ -14,6 +14,23 @@ var blockEnd = []byte("\n=")
|
|||||||
var newline = []byte("\n")
|
var newline = []byte("\n")
|
||||||
var armorEndOfLineOut = []byte("-----\n")
|
var armorEndOfLineOut = []byte("-----\n")
|
||||||
|
|
||||||
|
const crc24Init = 0xb704ce
|
||||||
|
const crc24Poly = 0x1864cfb
|
||||||
|
|
||||||
|
// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
|
||||||
|
func crc24(crc uint32, d []byte) uint32 {
|
||||||
|
for _, b := range d {
|
||||||
|
crc ^= uint32(b) << 16
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
crc <<= 1
|
||||||
|
if crc&0x1000000 != 0 {
|
||||||
|
crc ^= crc24Poly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc
|
||||||
|
}
|
||||||
|
|
||||||
// writeSlices writes its arguments to the given Writer.
|
// writeSlices writes its arguments to the given Writer.
|
||||||
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
|
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
|
||||||
for _, s := range slices {
|
for _, s := range slices {
|
||||||
@ -99,15 +116,18 @@ func (l *lineBreaker) Close() (err error) {
|
|||||||
//
|
//
|
||||||
// encoding -> base64 encoder -> lineBreaker -> out
|
// encoding -> base64 encoder -> lineBreaker -> out
|
||||||
type encoding struct {
|
type encoding struct {
|
||||||
out io.Writer
|
out io.Writer
|
||||||
breaker *lineBreaker
|
breaker *lineBreaker
|
||||||
b64 io.WriteCloser
|
b64 io.WriteCloser
|
||||||
crc uint32
|
crc uint32
|
||||||
blockType []byte
|
crcEnabled bool
|
||||||
|
blockType []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoding) Write(data []byte) (n int, err error) {
|
func (e *encoding) Write(data []byte) (n int, err error) {
|
||||||
e.crc = crc24(e.crc, data)
|
if e.crcEnabled {
|
||||||
|
e.crc = crc24(e.crc, data)
|
||||||
|
}
|
||||||
return e.b64.Write(data)
|
return e.b64.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,20 +138,21 @@ func (e *encoding) Close() (err error) {
|
|||||||
}
|
}
|
||||||
e.breaker.Close()
|
e.breaker.Close()
|
||||||
|
|
||||||
var checksumBytes [3]byte
|
if e.crcEnabled {
|
||||||
checksumBytes[0] = byte(e.crc >> 16)
|
var checksumBytes [3]byte
|
||||||
checksumBytes[1] = byte(e.crc >> 8)
|
checksumBytes[0] = byte(e.crc >> 16)
|
||||||
checksumBytes[2] = byte(e.crc)
|
checksumBytes[1] = byte(e.crc >> 8)
|
||||||
|
checksumBytes[2] = byte(e.crc)
|
||||||
|
|
||||||
var b64ChecksumBytes [4]byte
|
var b64ChecksumBytes [4]byte
|
||||||
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
|
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
|
||||||
|
|
||||||
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
|
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
|
||||||
|
}
|
||||||
|
return writeSlices(e.out, newline, armorEnd, e.blockType, armorEndOfLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode returns a WriteCloser which will encode the data written to it in
|
func encode(out io.Writer, blockType string, headers map[string]string, checksum bool) (w io.WriteCloser, err error) {
|
||||||
// OpenPGP armor.
|
|
||||||
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
|
|
||||||
bType := []byte(blockType)
|
bType := []byte(blockType)
|
||||||
err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
|
err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -151,11 +172,27 @@ func Encode(out io.Writer, blockType string, headers map[string]string) (w io.Wr
|
|||||||
}
|
}
|
||||||
|
|
||||||
e := &encoding{
|
e := &encoding{
|
||||||
out: out,
|
out: out,
|
||||||
breaker: newLineBreaker(out, 64),
|
breaker: newLineBreaker(out, 64),
|
||||||
crc: crc24Init,
|
blockType: bType,
|
||||||
blockType: bType,
|
crc: crc24Init,
|
||||||
|
crcEnabled: checksum,
|
||||||
}
|
}
|
||||||
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
|
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode returns a WriteCloser which will encode the data written to it in
|
||||||
|
// OpenPGP armor.
|
||||||
|
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
|
||||||
|
return encode(out, blockType, headers, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeWithChecksumOption returns a WriteCloser which will encode the data written to it in
|
||||||
|
// OpenPGP armor and provides the option to include a checksum.
|
||||||
|
// When forming ASCII Armor, the CRC24 footer SHOULD NOT be generated,
|
||||||
|
// unless interoperability with implementations that require the CRC24 footer
|
||||||
|
// to be present is a concern.
|
||||||
|
func EncodeWithChecksumOption(out io.Writer, blockType string, headers map[string]string, doChecksum bool) (w io.WriteCloser, err error) {
|
||||||
|
return encode(out, blockType, headers, doChecksum)
|
||||||
|
}
|
||||||
|
12
vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go
generated
vendored
12
vendor/github.com/ProtonMail/go-crypto/openpgp/canonical_text.go
generated
vendored
@ -30,8 +30,12 @@ func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) {
|
|||||||
if c == '\r' {
|
if c == '\r' {
|
||||||
*s = 1
|
*s = 1
|
||||||
} else if c == '\n' {
|
} else if c == '\n' {
|
||||||
cw.Write(buf[start:i])
|
if _, err := cw.Write(buf[start:i]); err != nil {
|
||||||
cw.Write(newline)
|
return 0, err
|
||||||
|
}
|
||||||
|
if _, err := cw.Write(newline); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
start = i + 1
|
start = i + 1
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
@ -39,7 +43,9 @@ func writeCanonical(cw io.Writer, buf []byte, s *int) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cw.Write(buf[start:])
|
if _, err := cw.Write(buf[start:]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
return len(buf), nil
|
return len(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
generated
vendored
6
vendor/github.com/ProtonMail/go-crypto/openpgp/ecdh/ecdh.go
generated
vendored
@ -163,13 +163,9 @@ func buildKey(pub *PublicKey, zb []byte, curveOID, fingerprint []byte, stripLead
|
|||||||
if _, err := param.Write([]byte("Anonymous Sender ")); err != nil {
|
if _, err := param.Write([]byte("Anonymous Sender ")); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// For v5 keys, the 20 leftmost octets of the fingerprint are used.
|
if _, err := param.Write(fingerprint[:]); err != nil {
|
||||||
if _, err := param.Write(fingerprint[:20]); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if param.Len()-len(curveOID) != 45 {
|
|
||||||
return nil, errors.New("ecdh: malformed KDF Param")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
|
// MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
|
||||||
h := pub.KDF.Hash.New()
|
h := pub.KDF.Hash.New()
|
||||||
|
115
vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go
generated
vendored
Normal file
115
vendor/github.com/ProtonMail/go-crypto/openpgp/ed25519/ed25519.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Package ed25519 implements the ed25519 signature algorithm for OpenPGP
|
||||||
|
// as defined in the Open PGP crypto refresh.
|
||||||
|
package ed25519
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
ed25519lib "github.com/cloudflare/circl/sign/ed25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PublicKeySize is the size, in bytes, of public keys in this package.
|
||||||
|
PublicKeySize = ed25519lib.PublicKeySize
|
||||||
|
// SeedSize is the size, in bytes, of private key seeds.
|
||||||
|
// The private key representation used by RFC 8032.
|
||||||
|
SeedSize = ed25519lib.SeedSize
|
||||||
|
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||||
|
SignatureSize = ed25519lib.SignatureSize
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicKey struct {
|
||||||
|
// Point represents the elliptic curve point of the public key.
|
||||||
|
Point []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivateKey struct {
|
||||||
|
PublicKey
|
||||||
|
// Key the private key representation by RFC 8032,
|
||||||
|
// encoded as seed | pub key point.
|
||||||
|
Key []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPublicKey creates a new empty ed25519 public key.
|
||||||
|
func NewPublicKey() *PublicKey {
|
||||||
|
return &PublicKey{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPrivateKey creates a new empty private key referencing the public key.
|
||||||
|
func NewPrivateKey(key PublicKey) *PrivateKey {
|
||||||
|
return &PrivateKey{
|
||||||
|
PublicKey: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed returns the ed25519 private key secret seed.
|
||||||
|
// The private key representation by RFC 8032.
|
||||||
|
func (pk *PrivateKey) Seed() []byte {
|
||||||
|
return pk.Key[:SeedSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalByteSecret returns the underlying 32 byte seed of the private key.
|
||||||
|
func (pk *PrivateKey) MarshalByteSecret() []byte {
|
||||||
|
return pk.Seed()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalByteSecret computes the private key from the secret seed
|
||||||
|
// and stores it in the private key object.
|
||||||
|
func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
|
||||||
|
sk.Key = ed25519lib.NewKeyFromSeed(seed)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey generates a fresh private key with the provided randomness source.
|
||||||
|
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
|
publicKey, privateKey, err := ed25519lib.GenerateKey(rand)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privateKeyOut := new(PrivateKey)
|
||||||
|
privateKeyOut.PublicKey.Point = publicKey[:]
|
||||||
|
privateKeyOut.Key = privateKey[:]
|
||||||
|
return privateKeyOut, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs a message with the ed25519 algorithm.
|
||||||
|
// priv MUST be a valid key! Check this with Validate() before use.
|
||||||
|
func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
|
||||||
|
return ed25519lib.Sign(priv.Key, message), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies an ed25519 signature.
|
||||||
|
func Verify(pub *PublicKey, message []byte, signature []byte) bool {
|
||||||
|
return ed25519lib.Verify(pub.Point, message, signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks if the ed25519 private key is valid.
|
||||||
|
func Validate(priv *PrivateKey) error {
|
||||||
|
expectedPrivateKey := ed25519lib.NewKeyFromSeed(priv.Seed())
|
||||||
|
if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
|
||||||
|
return errors.KeyInvalidError("ed25519: invalid ed25519 secret")
|
||||||
|
}
|
||||||
|
if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
|
||||||
|
return errors.KeyInvalidError("ed25519: invalid ed25519 public key")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENCODING/DECODING signature:
|
||||||
|
|
||||||
|
// WriteSignature encodes and writes an ed25519 signature to writer.
|
||||||
|
func WriteSignature(writer io.Writer, signature []byte) error {
|
||||||
|
_, err := writer.Write(signature)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignature decodes an ed25519 signature from a reader.
|
||||||
|
func ReadSignature(reader io.Reader) ([]byte, error) {
|
||||||
|
signature := make([]byte, SignatureSize)
|
||||||
|
if _, err := io.ReadFull(reader, signature); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return signature, nil
|
||||||
|
}
|
119
vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go
generated
vendored
Normal file
119
vendor/github.com/ProtonMail/go-crypto/openpgp/ed448/ed448.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// Package ed448 implements the ed448 signature algorithm for OpenPGP
|
||||||
|
// as defined in the Open PGP crypto refresh.
|
||||||
|
package ed448
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
ed448lib "github.com/cloudflare/circl/sign/ed448"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PublicKeySize is the size, in bytes, of public keys in this package.
|
||||||
|
PublicKeySize = ed448lib.PublicKeySize
|
||||||
|
// SeedSize is the size, in bytes, of private key seeds.
|
||||||
|
// The private key representation used by RFC 8032.
|
||||||
|
SeedSize = ed448lib.SeedSize
|
||||||
|
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||||
|
SignatureSize = ed448lib.SignatureSize
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicKey struct {
|
||||||
|
// Point represents the elliptic curve point of the public key.
|
||||||
|
Point []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivateKey struct {
|
||||||
|
PublicKey
|
||||||
|
// Key the private key representation by RFC 8032,
|
||||||
|
// encoded as seed | public key point.
|
||||||
|
Key []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPublicKey creates a new empty ed448 public key.
|
||||||
|
func NewPublicKey() *PublicKey {
|
||||||
|
return &PublicKey{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPrivateKey creates a new empty private key referencing the public key.
|
||||||
|
func NewPrivateKey(key PublicKey) *PrivateKey {
|
||||||
|
return &PrivateKey{
|
||||||
|
PublicKey: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed returns the ed448 private key secret seed.
|
||||||
|
// The private key representation by RFC 8032.
|
||||||
|
func (pk *PrivateKey) Seed() []byte {
|
||||||
|
return pk.Key[:SeedSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalByteSecret returns the underlying seed of the private key.
|
||||||
|
func (pk *PrivateKey) MarshalByteSecret() []byte {
|
||||||
|
return pk.Seed()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalByteSecret computes the private key from the secret seed
|
||||||
|
// and stores it in the private key object.
|
||||||
|
func (sk *PrivateKey) UnmarshalByteSecret(seed []byte) error {
|
||||||
|
sk.Key = ed448lib.NewKeyFromSeed(seed)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey generates a fresh private key with the provided randomness source.
|
||||||
|
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
|
publicKey, privateKey, err := ed448lib.GenerateKey(rand)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privateKeyOut := new(PrivateKey)
|
||||||
|
privateKeyOut.PublicKey.Point = publicKey[:]
|
||||||
|
privateKeyOut.Key = privateKey[:]
|
||||||
|
return privateKeyOut, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs a message with the ed448 algorithm.
|
||||||
|
// priv MUST be a valid key! Check this with Validate() before use.
|
||||||
|
func Sign(priv *PrivateKey, message []byte) ([]byte, error) {
|
||||||
|
// Ed448 is used with the empty string as a context string.
|
||||||
|
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
|
||||||
|
return ed448lib.Sign(priv.Key, message, ""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies a ed448 signature
|
||||||
|
func Verify(pub *PublicKey, message []byte, signature []byte) bool {
|
||||||
|
// Ed448 is used with the empty string as a context string.
|
||||||
|
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-08#section-13.7
|
||||||
|
return ed448lib.Verify(pub.Point, message, signature, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks if the ed448 private key is valid
|
||||||
|
func Validate(priv *PrivateKey) error {
|
||||||
|
expectedPrivateKey := ed448lib.NewKeyFromSeed(priv.Seed())
|
||||||
|
if subtle.ConstantTimeCompare(priv.Key, expectedPrivateKey) == 0 {
|
||||||
|
return errors.KeyInvalidError("ed448: invalid ed448 secret")
|
||||||
|
}
|
||||||
|
if subtle.ConstantTimeCompare(priv.PublicKey.Point, expectedPrivateKey[SeedSize:]) == 0 {
|
||||||
|
return errors.KeyInvalidError("ed448: invalid ed448 public key")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENCODING/DECODING signature:
|
||||||
|
|
||||||
|
// WriteSignature encodes and writes an ed448 signature to writer.
|
||||||
|
func WriteSignature(writer io.Writer, signature []byte) error {
|
||||||
|
_, err := writer.Write(signature)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignature decodes an ed448 signature from a reader.
|
||||||
|
func ReadSignature(reader io.Reader) ([]byte, error) {
|
||||||
|
signature := make([]byte, SignatureSize)
|
||||||
|
if _, err := io.ReadFull(reader, signature); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return signature, nil
|
||||||
|
}
|
70
vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
generated
vendored
70
vendor/github.com/ProtonMail/go-crypto/openpgp/errors/errors.go
generated
vendored
@ -9,6 +9,18 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrDecryptSessionKeyParsing is a generic error message for parsing errors in decrypted data
|
||||||
|
// to reduce the risk of oracle attacks.
|
||||||
|
ErrDecryptSessionKeyParsing = DecryptWithSessionKeyError("parsing error")
|
||||||
|
// ErrAEADTagVerification is returned if one of the tag verifications in SEIPDv2 fails
|
||||||
|
ErrAEADTagVerification error = DecryptWithSessionKeyError("AEAD tag verification failed")
|
||||||
|
// ErrMDCHashMismatch
|
||||||
|
ErrMDCHashMismatch error = SignatureError("MDC hash mismatch")
|
||||||
|
// ErrMDCMissing
|
||||||
|
ErrMDCMissing error = SignatureError("MDC packet not found")
|
||||||
|
)
|
||||||
|
|
||||||
// A StructuralError is returned when OpenPGP data is found to be syntactically
|
// A StructuralError is returned when OpenPGP data is found to be syntactically
|
||||||
// invalid.
|
// invalid.
|
||||||
type StructuralError string
|
type StructuralError string
|
||||||
@ -17,6 +29,34 @@ func (s StructuralError) Error() string {
|
|||||||
return "openpgp: invalid data: " + string(s)
|
return "openpgp: invalid data: " + string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A DecryptWithSessionKeyError is returned when a failure occurs when reading from symmetrically decrypted data or
|
||||||
|
// an authentication tag verification fails.
|
||||||
|
// Such an error indicates that the supplied session key is likely wrong or the data got corrupted.
|
||||||
|
type DecryptWithSessionKeyError string
|
||||||
|
|
||||||
|
func (s DecryptWithSessionKeyError) Error() string {
|
||||||
|
return "openpgp: decryption with session key failed: " + string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleSensitiveParsingError handles parsing errors when reading data from potentially decrypted data.
|
||||||
|
// The function makes parsing errors generic to reduce the risk of oracle attacks in SEIPDv1.
|
||||||
|
func HandleSensitiveParsingError(err error, decrypted bool) error {
|
||||||
|
if !decrypted {
|
||||||
|
// Data was not encrypted so we return the inner error.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// The data is read from a stream that decrypts using a session key;
|
||||||
|
// therefore, we need to handle parsing errors appropriately.
|
||||||
|
// This is essential to mitigate the risk of oracle attacks.
|
||||||
|
if decError, ok := err.(*DecryptWithSessionKeyError); ok {
|
||||||
|
return decError
|
||||||
|
}
|
||||||
|
if decError, ok := err.(DecryptWithSessionKeyError); ok {
|
||||||
|
return decError
|
||||||
|
}
|
||||||
|
return ErrDecryptSessionKeyParsing
|
||||||
|
}
|
||||||
|
|
||||||
// UnsupportedError indicates that, although the OpenPGP data is valid, it
|
// UnsupportedError indicates that, although the OpenPGP data is valid, it
|
||||||
// makes use of currently unimplemented features.
|
// makes use of currently unimplemented features.
|
||||||
type UnsupportedError string
|
type UnsupportedError string
|
||||||
@ -41,9 +81,6 @@ func (b SignatureError) Error() string {
|
|||||||
return "openpgp: invalid signature: " + string(b)
|
return "openpgp: invalid signature: " + string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrMDCHashMismatch error = SignatureError("MDC hash mismatch")
|
|
||||||
var ErrMDCMissing error = SignatureError("MDC packet not found")
|
|
||||||
|
|
||||||
type signatureExpiredError int
|
type signatureExpiredError int
|
||||||
|
|
||||||
func (se signatureExpiredError) Error() string {
|
func (se signatureExpiredError) Error() string {
|
||||||
@ -58,6 +95,14 @@ func (ke keyExpiredError) Error() string {
|
|||||||
return "openpgp: key expired"
|
return "openpgp: key expired"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrSignatureOlderThanKey error = signatureOlderThanKeyError(0)
|
||||||
|
|
||||||
|
type signatureOlderThanKeyError int
|
||||||
|
|
||||||
|
func (ske signatureOlderThanKeyError) Error() string {
|
||||||
|
return "openpgp: signature is older than the key"
|
||||||
|
}
|
||||||
|
|
||||||
var ErrKeyExpired error = keyExpiredError(0)
|
var ErrKeyExpired error = keyExpiredError(0)
|
||||||
|
|
||||||
type keyIncorrectError int
|
type keyIncorrectError int
|
||||||
@ -92,12 +137,24 @@ func (keyRevokedError) Error() string {
|
|||||||
|
|
||||||
var ErrKeyRevoked error = keyRevokedError(0)
|
var ErrKeyRevoked error = keyRevokedError(0)
|
||||||
|
|
||||||
|
type WeakAlgorithmError string
|
||||||
|
|
||||||
|
func (e WeakAlgorithmError) Error() string {
|
||||||
|
return "openpgp: weak algorithms are rejected: " + string(e)
|
||||||
|
}
|
||||||
|
|
||||||
type UnknownPacketTypeError uint8
|
type UnknownPacketTypeError uint8
|
||||||
|
|
||||||
func (upte UnknownPacketTypeError) Error() string {
|
func (upte UnknownPacketTypeError) Error() string {
|
||||||
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
|
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CriticalUnknownPacketTypeError uint8
|
||||||
|
|
||||||
|
func (upte CriticalUnknownPacketTypeError) Error() string {
|
||||||
|
return "openpgp: unknown critical packet type: " + strconv.Itoa(int(upte))
|
||||||
|
}
|
||||||
|
|
||||||
// AEADError indicates that there is a problem when initializing or using a
|
// AEADError indicates that there is a problem when initializing or using a
|
||||||
// AEAD instance, configuration struct, nonces or index values.
|
// AEAD instance, configuration struct, nonces or index values.
|
||||||
type AEADError string
|
type AEADError string
|
||||||
@ -114,3 +171,10 @@ type ErrDummyPrivateKey string
|
|||||||
func (dke ErrDummyPrivateKey) Error() string {
|
func (dke ErrDummyPrivateKey) Error() string {
|
||||||
return "openpgp: s2k GNU dummy key: " + string(dke)
|
return "openpgp: s2k GNU dummy key: " + string(dke)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrMalformedMessage results when the packet sequence is incorrect
|
||||||
|
type ErrMalformedMessage string
|
||||||
|
|
||||||
|
func (dke ErrMalformedMessage) Error() string {
|
||||||
|
return "openpgp: malformed message " + string(dke)
|
||||||
|
}
|
||||||
|
12
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
generated
vendored
12
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/algorithm/cipher.go
generated
vendored
@ -51,24 +51,14 @@ func (sk CipherFunction) Id() uint8 {
|
|||||||
return uint8(sk)
|
return uint8(sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
var keySizeByID = map[uint8]int{
|
|
||||||
TripleDES.Id(): 24,
|
|
||||||
CAST5.Id(): cast5.KeySize,
|
|
||||||
AES128.Id(): 16,
|
|
||||||
AES192.Id(): 24,
|
|
||||||
AES256.Id(): 32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeySize returns the key size, in bytes, of cipher.
|
// KeySize returns the key size, in bytes, of cipher.
|
||||||
func (cipher CipherFunction) KeySize() int {
|
func (cipher CipherFunction) KeySize() int {
|
||||||
switch cipher {
|
switch cipher {
|
||||||
case TripleDES:
|
|
||||||
return 24
|
|
||||||
case CAST5:
|
case CAST5:
|
||||||
return cast5.KeySize
|
return cast5.KeySize
|
||||||
case AES128:
|
case AES128:
|
||||||
return 16
|
return 16
|
||||||
case AES192:
|
case AES192, TripleDES:
|
||||||
return 24
|
return 24
|
||||||
case AES256:
|
case AES256:
|
||||||
return 32
|
return 32
|
||||||
|
9
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
generated
vendored
9
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/curve_info.go
generated
vendored
@ -4,11 +4,14 @@ package ecc
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/bitcurves"
|
"github.com/ProtonMail/go-crypto/bitcurves"
|
||||||
"github.com/ProtonMail/go-crypto/brainpool"
|
"github.com/ProtonMail/go-crypto/brainpool"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const Curve25519GenName = "Curve25519"
|
||||||
|
|
||||||
type CurveInfo struct {
|
type CurveInfo struct {
|
||||||
GenName string
|
GenName string
|
||||||
Oid *encoding.OID
|
Oid *encoding.OID
|
||||||
@ -42,19 +45,19 @@ var Curves = []CurveInfo{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Curve25519
|
// Curve25519
|
||||||
GenName: "Curve25519",
|
GenName: Curve25519GenName,
|
||||||
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}),
|
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}),
|
||||||
Curve: NewCurve25519(),
|
Curve: NewCurve25519(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// X448
|
// x448
|
||||||
GenName: "Curve448",
|
GenName: "Curve448",
|
||||||
Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x6F}),
|
Oid: encoding.NewOID([]byte{0x2B, 0x65, 0x6F}),
|
||||||
Curve: NewX448(),
|
Curve: NewX448(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Ed25519
|
// Ed25519
|
||||||
GenName: "Curve25519",
|
GenName: Curve25519GenName,
|
||||||
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}),
|
Oid: encoding.NewOID([]byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}),
|
||||||
Curve: NewEd25519(),
|
Curve: NewEd25519(),
|
||||||
},
|
},
|
||||||
|
10
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
generated
vendored
10
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed25519.go
generated
vendored
@ -2,6 +2,7 @@
|
|||||||
package ecc
|
package ecc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@ -90,7 +91,14 @@ func (c *ed25519) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey {
|
func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey {
|
||||||
return append(privateKey, publicKey...)
|
privateKeyCap, privateKeyLen, publicKeyLen := cap(privateKey), len(privateKey), len(publicKey)
|
||||||
|
|
||||||
|
if privateKeyCap >= privateKeyLen+publicKeyLen &&
|
||||||
|
bytes.Equal(privateKey[privateKeyLen:privateKeyLen+publicKeyLen], publicKey) {
|
||||||
|
return privateKey[:privateKeyLen+publicKeyLen]
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(privateKey[:privateKeyLen:privateKeyLen], publicKey...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
|
func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
|
||||||
|
10
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
generated
vendored
10
vendor/github.com/ProtonMail/go-crypto/openpgp/internal/ecc/ed448.go
generated
vendored
@ -2,6 +2,7 @@
|
|||||||
package ecc
|
package ecc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@ -84,7 +85,14 @@ func (c *ed448) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey {
|
func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey {
|
||||||
return append(privateKey, publicKey...)
|
privateKeyCap, privateKeyLen, publicKeyLen := cap(privateKey), len(privateKey), len(publicKey)
|
||||||
|
|
||||||
|
if privateKeyCap >= privateKeyLen+publicKeyLen &&
|
||||||
|
bytes.Equal(privateKey[privateKeyLen:privateKeyLen+publicKeyLen], publicKey) {
|
||||||
|
return privateKey[:privateKeyLen+publicKeyLen]
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(privateKey[:privateKeyLen:privateKeyLen], publicKey...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
|
func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
|
||||||
|
135
vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
generated
vendored
135
vendor/github.com/ProtonMail/go-crypto/openpgp/key_generation.go
generated
vendored
@ -15,11 +15,15 @@ import (
|
|||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/ecdh"
|
"github.com/ProtonMail/go-crypto/openpgp/ecdh"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
|
"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/ed25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/ed448"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
|
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x448"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
|
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
|
||||||
@ -36,8 +40,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
primary := packet.NewSignerPrivateKey(creationTime, primaryPrivRaw)
|
primary := packet.NewSignerPrivateKey(creationTime, primaryPrivRaw)
|
||||||
if config != nil && config.V5Keys {
|
if config.V6() {
|
||||||
primary.UpgradeToV5()
|
if err := primary.UpgradeToV6(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e := &Entity{
|
e := &Entity{
|
||||||
@ -45,9 +51,25 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
|||||||
PrivateKey: primary,
|
PrivateKey: primary,
|
||||||
Identities: make(map[string]*Identity),
|
Identities: make(map[string]*Identity),
|
||||||
Subkeys: []Subkey{},
|
Subkeys: []Subkey{},
|
||||||
|
Signatures: []*packet.Signature{},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs)
|
if config.V6() {
|
||||||
|
// In v6 keys algorithm preferences should be stored in direct key signatures
|
||||||
|
selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypeDirectSignature, config)
|
||||||
|
err = writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = selfSignature.SignDirectKeyBinding(&primary.PublicKey, primary, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.Signatures = append(e.Signatures, selfSignature)
|
||||||
|
e.SelfSignature = selfSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -65,32 +87,19 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
|||||||
func (t *Entity) AddUserId(name, comment, email string, config *packet.Config) error {
|
func (t *Entity) AddUserId(name, comment, email string, config *packet.Config) error {
|
||||||
creationTime := config.Now()
|
creationTime := config.Now()
|
||||||
keyLifetimeSecs := config.KeyLifetime()
|
keyLifetimeSecs := config.KeyLifetime()
|
||||||
return t.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs)
|
return t.addUserId(name, comment, email, config, creationTime, keyLifetimeSecs, !config.V6())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32) error {
|
func writeKeyProperties(selfSignature *packet.Signature, creationTime time.Time, keyLifetimeSecs uint32, config *packet.Config) error {
|
||||||
uid := packet.NewUserId(name, comment, email)
|
advertiseAead := config.AEAD() != nil
|
||||||
if uid == nil {
|
|
||||||
return errors.InvalidArgumentError("user id field contained invalid characters")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := t.Identities[uid.Id]; ok {
|
|
||||||
return errors.InvalidArgumentError("user id exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
primary := t.PrivateKey
|
|
||||||
|
|
||||||
isPrimaryId := len(t.Identities) == 0
|
|
||||||
|
|
||||||
selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypePositiveCert, config)
|
|
||||||
selfSignature.CreationTime = creationTime
|
selfSignature.CreationTime = creationTime
|
||||||
selfSignature.KeyLifetimeSecs = &keyLifetimeSecs
|
selfSignature.KeyLifetimeSecs = &keyLifetimeSecs
|
||||||
selfSignature.IsPrimaryId = &isPrimaryId
|
|
||||||
selfSignature.FlagsValid = true
|
selfSignature.FlagsValid = true
|
||||||
selfSignature.FlagSign = true
|
selfSignature.FlagSign = true
|
||||||
selfSignature.FlagCertify = true
|
selfSignature.FlagCertify = true
|
||||||
selfSignature.SEIPDv1 = true // true by default, see 5.8 vs. 5.14
|
selfSignature.SEIPDv1 = true // true by default, see 5.8 vs. 5.14
|
||||||
selfSignature.SEIPDv2 = config.AEAD() != nil
|
selfSignature.SEIPDv2 = advertiseAead
|
||||||
|
|
||||||
// Set the PreferredHash for the SelfSignature from the packet.Config.
|
// Set the PreferredHash for the SelfSignature from the packet.Config.
|
||||||
// If it is not the must-implement algorithm from rfc4880bis, append that.
|
// If it is not the must-implement algorithm from rfc4880bis, append that.
|
||||||
@ -119,18 +128,44 @@ func (t *Entity) addUserId(name, comment, email string, config *packet.Config, c
|
|||||||
selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression()))
|
selfSignature.PreferredCompression = append(selfSignature.PreferredCompression, uint8(config.Compression()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// And for DefaultMode.
|
if advertiseAead {
|
||||||
modes := []uint8{uint8(config.AEAD().Mode())}
|
// Get the preferred AEAD mode from the packet.Config.
|
||||||
if config.AEAD().Mode() != packet.AEADModeOCB {
|
// If it is not the must-implement algorithm from rfc9580, append that.
|
||||||
modes = append(modes, uint8(packet.AEADModeOCB))
|
modes := []uint8{uint8(config.AEAD().Mode())}
|
||||||
}
|
if config.AEAD().Mode() != packet.AEADModeOCB {
|
||||||
|
modes = append(modes, uint8(packet.AEADModeOCB))
|
||||||
|
}
|
||||||
|
|
||||||
// For preferred (AES256, GCM), we'll generate (AES256, GCM), (AES256, OCB), (AES128, GCM), (AES128, OCB)
|
// For preferred (AES256, GCM), we'll generate (AES256, GCM), (AES256, OCB), (AES128, GCM), (AES128, OCB)
|
||||||
for _, cipher := range selfSignature.PreferredSymmetric {
|
for _, cipher := range selfSignature.PreferredSymmetric {
|
||||||
for _, mode := range modes {
|
for _, mode := range modes {
|
||||||
selfSignature.PreferredCipherSuites = append(selfSignature.PreferredCipherSuites, [2]uint8{cipher, mode})
|
selfSignature.PreferredCipherSuites = append(selfSignature.PreferredCipherSuites, [2]uint8{cipher, mode})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Entity) addUserId(name, comment, email string, config *packet.Config, creationTime time.Time, keyLifetimeSecs uint32, writeProperties bool) error {
|
||||||
|
uid := packet.NewUserId(name, comment, email)
|
||||||
|
if uid == nil {
|
||||||
|
return errors.InvalidArgumentError("user id field contained invalid characters")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := t.Identities[uid.Id]; ok {
|
||||||
|
return errors.InvalidArgumentError("user id exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
primary := t.PrivateKey
|
||||||
|
isPrimaryId := len(t.Identities) == 0
|
||||||
|
selfSignature := createSignaturePacket(&primary.PublicKey, packet.SigTypePositiveCert, config)
|
||||||
|
if writeProperties {
|
||||||
|
err := writeKeyProperties(selfSignature, creationTime, keyLifetimeSecs, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selfSignature.IsPrimaryId = &isPrimaryId
|
||||||
|
|
||||||
// User ID binding signature
|
// User ID binding signature
|
||||||
err := selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config)
|
err := selfSignature.SignUserId(uid.Id, &primary.PublicKey, primary, config)
|
||||||
@ -158,8 +193,10 @@ func (e *Entity) AddSigningSubkey(config *packet.Config) error {
|
|||||||
}
|
}
|
||||||
sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw)
|
sub := packet.NewSignerPrivateKey(creationTime, subPrivRaw)
|
||||||
sub.IsSubkey = true
|
sub.IsSubkey = true
|
||||||
if config != nil && config.V5Keys {
|
if config.V6() {
|
||||||
sub.UpgradeToV5()
|
if err := sub.UpgradeToV6(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subkey := Subkey{
|
subkey := Subkey{
|
||||||
@ -203,8 +240,10 @@ func (e *Entity) addEncryptionSubkey(config *packet.Config, creationTime time.Ti
|
|||||||
}
|
}
|
||||||
sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw)
|
sub := packet.NewDecrypterPrivateKey(creationTime, subPrivRaw)
|
||||||
sub.IsSubkey = true
|
sub.IsSubkey = true
|
||||||
if config != nil && config.V5Keys {
|
if config.V6() {
|
||||||
sub.UpgradeToV5()
|
if err := sub.UpgradeToV6(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subkey := Subkey{
|
subkey := Subkey{
|
||||||
@ -242,6 +281,11 @@ func newSigner(config *packet.Config) (signer interface{}, err error) {
|
|||||||
}
|
}
|
||||||
return rsa.GenerateKey(config.Random(), bits)
|
return rsa.GenerateKey(config.Random(), bits)
|
||||||
case packet.PubKeyAlgoEdDSA:
|
case packet.PubKeyAlgoEdDSA:
|
||||||
|
if config.V6() {
|
||||||
|
// Implementations MUST NOT accept or generate v6 key material
|
||||||
|
// using the deprecated OIDs.
|
||||||
|
return nil, errors.InvalidArgumentError("EdDSALegacy cannot be used for v6 keys")
|
||||||
|
}
|
||||||
curve := ecc.FindEdDSAByGenName(string(config.CurveName()))
|
curve := ecc.FindEdDSAByGenName(string(config.CurveName()))
|
||||||
if curve == nil {
|
if curve == nil {
|
||||||
return nil, errors.InvalidArgumentError("unsupported curve")
|
return nil, errors.InvalidArgumentError("unsupported curve")
|
||||||
@ -263,6 +307,18 @@ func newSigner(config *packet.Config) (signer interface{}, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return priv, nil
|
return priv, nil
|
||||||
|
case packet.PubKeyAlgoEd25519:
|
||||||
|
priv, err := ed25519.GenerateKey(config.Random())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return priv, nil
|
||||||
|
case packet.PubKeyAlgoEd448:
|
||||||
|
priv, err := ed448.GenerateKey(config.Random())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return priv, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.InvalidArgumentError("unsupported public key algorithm")
|
return nil, errors.InvalidArgumentError("unsupported public key algorithm")
|
||||||
}
|
}
|
||||||
@ -285,6 +341,13 @@ func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
|
|||||||
case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA:
|
case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA:
|
||||||
fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey
|
fallthrough // When passing EdDSA or ECDSA, we generate an ECDH subkey
|
||||||
case packet.PubKeyAlgoECDH:
|
case packet.PubKeyAlgoECDH:
|
||||||
|
if config.V6() &&
|
||||||
|
(config.CurveName() == packet.Curve25519 ||
|
||||||
|
config.CurveName() == packet.Curve448) {
|
||||||
|
// Implementations MUST NOT accept or generate v6 key material
|
||||||
|
// using the deprecated OIDs.
|
||||||
|
return nil, errors.InvalidArgumentError("ECDH with Curve25519/448 legacy cannot be used for v6 keys")
|
||||||
|
}
|
||||||
var kdf = ecdh.KDF{
|
var kdf = ecdh.KDF{
|
||||||
Hash: algorithm.SHA512,
|
Hash: algorithm.SHA512,
|
||||||
Cipher: algorithm.AES256,
|
Cipher: algorithm.AES256,
|
||||||
@ -294,6 +357,10 @@ func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
|
|||||||
return nil, errors.InvalidArgumentError("unsupported curve")
|
return nil, errors.InvalidArgumentError("unsupported curve")
|
||||||
}
|
}
|
||||||
return ecdh.GenerateKey(config.Random(), curve, kdf)
|
return ecdh.GenerateKey(config.Random(), curve, kdf)
|
||||||
|
case packet.PubKeyAlgoEd25519, packet.PubKeyAlgoX25519: // When passing Ed25519, we generate an x25519 subkey
|
||||||
|
return x25519.GenerateKey(config.Random())
|
||||||
|
case packet.PubKeyAlgoEd448, packet.PubKeyAlgoX448: // When passing Ed448, we generate an x448 subkey
|
||||||
|
return x448.GenerateKey(config.Random())
|
||||||
default:
|
default:
|
||||||
return nil, errors.InvalidArgumentError("unsupported public key algorithm")
|
return nil, errors.InvalidArgumentError("unsupported public key algorithm")
|
||||||
}
|
}
|
||||||
@ -302,7 +369,7 @@ func newDecrypter(config *packet.Config) (decrypter interface{}, err error) {
|
|||||||
var bigOne = big.NewInt(1)
|
var bigOne = big.NewInt(1)
|
||||||
|
|
||||||
// generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the
|
// generateRSAKeyWithPrimes generates a multi-prime RSA keypair of the
|
||||||
// given bit size, using the given random source and prepopulated primes.
|
// given bit size, using the given random source and pre-populated primes.
|
||||||
func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) {
|
func generateRSAKeyWithPrimes(random io.Reader, nprimes int, bits int, prepopulatedPrimes []*big.Int) (*rsa.PrivateKey, error) {
|
||||||
priv := new(rsa.PrivateKey)
|
priv := new(rsa.PrivateKey)
|
||||||
priv.E = 65537
|
priv.E = 65537
|
||||||
|
125
vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
generated
vendored
125
vendor/github.com/ProtonMail/go-crypto/openpgp/keys.go
generated
vendored
@ -6,6 +6,7 @@ package openpgp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
goerrors "errors"
|
goerrors "errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -24,11 +25,13 @@ var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
|
|||||||
// (which must be a signing key), one or more identities claimed by that key,
|
// (which must be a signing key), one or more identities claimed by that key,
|
||||||
// and zero or more subkeys, which may be encryption keys.
|
// and zero or more subkeys, which may be encryption keys.
|
||||||
type Entity struct {
|
type Entity struct {
|
||||||
PrimaryKey *packet.PublicKey
|
PrimaryKey *packet.PublicKey
|
||||||
PrivateKey *packet.PrivateKey
|
PrivateKey *packet.PrivateKey
|
||||||
Identities map[string]*Identity // indexed by Identity.Name
|
Identities map[string]*Identity // indexed by Identity.Name
|
||||||
Revocations []*packet.Signature
|
Revocations []*packet.Signature
|
||||||
Subkeys []Subkey
|
Subkeys []Subkey
|
||||||
|
SelfSignature *packet.Signature // Direct-key self signature of the PrimaryKey (contains primary key properties in v6)
|
||||||
|
Signatures []*packet.Signature // all (potentially unverified) self-signatures, revocations, and third-party signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Identity represents an identity claimed by an Entity and zero or more
|
// An Identity represents an identity claimed by an Entity and zero or more
|
||||||
@ -120,12 +123,12 @@ func shouldPreferIdentity(existingId, potentialNewId *Identity) bool {
|
|||||||
// given Entity.
|
// given Entity.
|
||||||
func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
|
func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
|
||||||
// Fail to find any encryption key if the...
|
// Fail to find any encryption key if the...
|
||||||
i := e.PrimaryIdentity()
|
primarySelfSignature, primaryIdentity := e.PrimarySelfSignature()
|
||||||
if e.PrimaryKey.KeyExpired(i.SelfSignature, now) || // primary key has expired
|
if primarySelfSignature == nil || // no self-signature found
|
||||||
i.SelfSignature == nil || // user ID has no self-signature
|
e.PrimaryKey.KeyExpired(primarySelfSignature, now) || // primary key has expired
|
||||||
i.SelfSignature.SigExpired(now) || // user ID self-signature has expired
|
|
||||||
e.Revoked(now) || // primary key has been revoked
|
e.Revoked(now) || // primary key has been revoked
|
||||||
i.Revoked(now) { // user ID has been revoked
|
primarySelfSignature.SigExpired(now) || // user ID or or direct self-signature has expired
|
||||||
|
(primaryIdentity != nil && primaryIdentity.Revoked(now)) { // user ID has been revoked (for v4 keys)
|
||||||
return Key{}, false
|
return Key{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,9 +155,9 @@ func (e *Entity) EncryptionKey(now time.Time) (Key, bool) {
|
|||||||
|
|
||||||
// If we don't have any subkeys for encryption and the primary key
|
// If we don't have any subkeys for encryption and the primary key
|
||||||
// is marked as OK to encrypt with, then we can use it.
|
// is marked as OK to encrypt with, then we can use it.
|
||||||
if i.SelfSignature.FlagsValid && i.SelfSignature.FlagEncryptCommunications &&
|
if primarySelfSignature.FlagsValid && primarySelfSignature.FlagEncryptCommunications &&
|
||||||
e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
|
e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
|
||||||
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, e.Revocations}, true
|
return Key{e, e.PrimaryKey, e.PrivateKey, primarySelfSignature, e.Revocations}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return Key{}, false
|
return Key{}, false
|
||||||
@ -186,12 +189,12 @@ func (e *Entity) SigningKeyById(now time.Time, id uint64) (Key, bool) {
|
|||||||
|
|
||||||
func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key, bool) {
|
func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key, bool) {
|
||||||
// Fail to find any signing key if the...
|
// Fail to find any signing key if the...
|
||||||
i := e.PrimaryIdentity()
|
primarySelfSignature, primaryIdentity := e.PrimarySelfSignature()
|
||||||
if e.PrimaryKey.KeyExpired(i.SelfSignature, now) || // primary key has expired
|
if primarySelfSignature == nil || // no self-signature found
|
||||||
i.SelfSignature == nil || // user ID has no self-signature
|
e.PrimaryKey.KeyExpired(primarySelfSignature, now) || // primary key has expired
|
||||||
i.SelfSignature.SigExpired(now) || // user ID self-signature has expired
|
|
||||||
e.Revoked(now) || // primary key has been revoked
|
e.Revoked(now) || // primary key has been revoked
|
||||||
i.Revoked(now) { // user ID has been revoked
|
primarySelfSignature.SigExpired(now) || // user ID or direct self-signature has expired
|
||||||
|
(primaryIdentity != nil && primaryIdentity.Revoked(now)) { // user ID has been revoked (for v4 keys)
|
||||||
return Key{}, false
|
return Key{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,12 +223,12 @@ func (e *Entity) signingKeyByIdUsage(now time.Time, id uint64, flags int) (Key,
|
|||||||
|
|
||||||
// If we don't have any subkeys for signing and the primary key
|
// If we don't have any subkeys for signing and the primary key
|
||||||
// is marked as OK to sign with, then we can use it.
|
// is marked as OK to sign with, then we can use it.
|
||||||
if i.SelfSignature.FlagsValid &&
|
if primarySelfSignature.FlagsValid &&
|
||||||
(flags&packet.KeyFlagCertify == 0 || i.SelfSignature.FlagCertify) &&
|
(flags&packet.KeyFlagCertify == 0 || primarySelfSignature.FlagCertify) &&
|
||||||
(flags&packet.KeyFlagSign == 0 || i.SelfSignature.FlagSign) &&
|
(flags&packet.KeyFlagSign == 0 || primarySelfSignature.FlagSign) &&
|
||||||
e.PrimaryKey.PubKeyAlgo.CanSign() &&
|
e.PrimaryKey.PubKeyAlgo.CanSign() &&
|
||||||
(id == 0 || e.PrimaryKey.KeyId == id) {
|
(id == 0 || e.PrimaryKey.KeyId == id) {
|
||||||
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, e.Revocations}, true
|
return Key{e, e.PrimaryKey, e.PrivateKey, primarySelfSignature, e.Revocations}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// No keys with a valid Signing Flag or no keys matched the id passed in
|
// No keys with a valid Signing Flag or no keys matched the id passed in
|
||||||
@ -259,7 +262,7 @@ func (e *Entity) EncryptPrivateKeys(passphrase []byte, config *packet.Config) er
|
|||||||
var keysToEncrypt []*packet.PrivateKey
|
var keysToEncrypt []*packet.PrivateKey
|
||||||
// Add entity private key to encrypt.
|
// Add entity private key to encrypt.
|
||||||
if e.PrivateKey != nil && !e.PrivateKey.Dummy() && !e.PrivateKey.Encrypted {
|
if e.PrivateKey != nil && !e.PrivateKey.Dummy() && !e.PrivateKey.Encrypted {
|
||||||
keysToEncrypt = append(keysToEncrypt, e.PrivateKey)
|
keysToEncrypt = append(keysToEncrypt, e.PrivateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add subkeys to encrypt.
|
// Add subkeys to encrypt.
|
||||||
@ -271,7 +274,7 @@ func (e *Entity) EncryptPrivateKeys(passphrase []byte, config *packet.Config) er
|
|||||||
return packet.EncryptPrivateKeys(keysToEncrypt, passphrase, config)
|
return packet.EncryptPrivateKeys(keysToEncrypt, passphrase, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptPrivateKeys decrypts all encrypted keys in the entitiy with the given passphrase.
|
// DecryptPrivateKeys decrypts all encrypted keys in the entity with the given passphrase.
|
||||||
// Avoids recomputation of similar s2k key derivations. Public keys and dummy keys are ignored,
|
// Avoids recomputation of similar s2k key derivations. Public keys and dummy keys are ignored,
|
||||||
// and don't cause an error to be returned.
|
// and don't cause an error to be returned.
|
||||||
func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
|
func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
|
||||||
@ -284,7 +287,7 @@ func (e *Entity) DecryptPrivateKeys(passphrase []byte) error {
|
|||||||
// Add subkeys to decrypt.
|
// Add subkeys to decrypt.
|
||||||
for _, sub := range e.Subkeys {
|
for _, sub := range e.Subkeys {
|
||||||
if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted {
|
if sub.PrivateKey != nil && !sub.PrivateKey.Dummy() && sub.PrivateKey.Encrypted {
|
||||||
keysToDecrypt = append(keysToDecrypt, sub.PrivateKey)
|
keysToDecrypt = append(keysToDecrypt, sub.PrivateKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return packet.DecryptPrivateKeys(keysToDecrypt, passphrase)
|
return packet.DecryptPrivateKeys(keysToDecrypt, passphrase)
|
||||||
@ -318,8 +321,7 @@ type EntityList []*Entity
|
|||||||
func (el EntityList) KeysById(id uint64) (keys []Key) {
|
func (el EntityList) KeysById(id uint64) (keys []Key) {
|
||||||
for _, e := range el {
|
for _, e := range el {
|
||||||
if e.PrimaryKey.KeyId == id {
|
if e.PrimaryKey.KeyId == id {
|
||||||
ident := e.PrimaryIdentity()
|
selfSig, _ := e.PrimarySelfSignature()
|
||||||
selfSig := ident.SelfSignature
|
|
||||||
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, e.Revocations})
|
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, e.Revocations})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +443,6 @@ func readToNextPublicKey(packets *packet.Reader) (err error) {
|
|||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
if _, ok := err.(errors.UnsupportedError); ok {
|
if _, ok := err.(errors.UnsupportedError); ok {
|
||||||
err = nil
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -479,6 +480,7 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var revocations []*packet.Signature
|
var revocations []*packet.Signature
|
||||||
|
var directSignatures []*packet.Signature
|
||||||
EachPacket:
|
EachPacket:
|
||||||
for {
|
for {
|
||||||
p, err := packets.Next()
|
p, err := packets.Next()
|
||||||
@ -497,9 +499,7 @@ EachPacket:
|
|||||||
if pkt.SigType == packet.SigTypeKeyRevocation {
|
if pkt.SigType == packet.SigTypeKeyRevocation {
|
||||||
revocations = append(revocations, pkt)
|
revocations = append(revocations, pkt)
|
||||||
} else if pkt.SigType == packet.SigTypeDirectSignature {
|
} else if pkt.SigType == packet.SigTypeDirectSignature {
|
||||||
// TODO: RFC4880 5.2.1 permits signatures
|
directSignatures = append(directSignatures, pkt)
|
||||||
// directly on keys (eg. to bind additional
|
|
||||||
// revocation keys).
|
|
||||||
}
|
}
|
||||||
// Else, ignoring the signature as it does not follow anything
|
// Else, ignoring the signature as it does not follow anything
|
||||||
// we would know to attach it to.
|
// we would know to attach it to.
|
||||||
@ -522,12 +522,39 @@ EachPacket:
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// we ignore unknown packets
|
// we ignore unknown packets.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(e.Identities) == 0 {
|
if len(e.Identities) == 0 && e.PrimaryKey.Version < 6 {
|
||||||
return nil, errors.StructuralError("entity without any identities")
|
return nil, errors.StructuralError(fmt.Sprintf("v%d entity without any identities", e.PrimaryKey.Version))
|
||||||
|
}
|
||||||
|
|
||||||
|
// An implementation MUST ensure that a valid direct-key signature is present before using a v6 key.
|
||||||
|
if e.PrimaryKey.Version == 6 {
|
||||||
|
if len(directSignatures) == 0 {
|
||||||
|
return nil, errors.StructuralError("v6 entity without a valid direct-key signature")
|
||||||
|
}
|
||||||
|
// Select main direct key signature.
|
||||||
|
var mainDirectKeySelfSignature *packet.Signature
|
||||||
|
for _, directSignature := range directSignatures {
|
||||||
|
if directSignature.SigType == packet.SigTypeDirectSignature &&
|
||||||
|
directSignature.CheckKeyIdOrFingerprint(e.PrimaryKey) &&
|
||||||
|
(mainDirectKeySelfSignature == nil ||
|
||||||
|
directSignature.CreationTime.After(mainDirectKeySelfSignature.CreationTime)) {
|
||||||
|
mainDirectKeySelfSignature = directSignature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mainDirectKeySelfSignature == nil {
|
||||||
|
return nil, errors.StructuralError("no valid direct-key self-signature for v6 primary key found")
|
||||||
|
}
|
||||||
|
// Check that the main self-signature is valid.
|
||||||
|
err = e.PrimaryKey.VerifyDirectKeySignature(mainDirectKeySelfSignature)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.StructuralError("invalid direct-key self-signature for v6 primary key")
|
||||||
|
}
|
||||||
|
e.SelfSignature = mainDirectKeySelfSignature
|
||||||
|
e.Signatures = directSignatures
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, revocation := range revocations {
|
for _, revocation := range revocations {
|
||||||
@ -672,6 +699,12 @@ func (e *Entity) serializePrivate(w io.Writer, config *packet.Config, reSign boo
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, directSignature := range e.Signatures {
|
||||||
|
err := directSignature.Serialize(w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, ident := range e.Identities {
|
for _, ident := range e.Identities {
|
||||||
err = ident.UserId.Serialize(w)
|
err = ident.UserId.Serialize(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -738,6 +771,12 @@ func (e *Entity) Serialize(w io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, directSignature := range e.Signatures {
|
||||||
|
err := directSignature.Serialize(w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, ident := range e.Identities {
|
for _, ident := range e.Identities {
|
||||||
err = ident.UserId.Serialize(w)
|
err = ident.UserId.Serialize(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -840,3 +879,23 @@ func (e *Entity) RevokeSubkey(sk *Subkey, reason packet.ReasonForRevocation, rea
|
|||||||
sk.Revocations = append(sk.Revocations, revSig)
|
sk.Revocations = append(sk.Revocations, revSig)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Entity) primaryDirectSignature() *packet.Signature {
|
||||||
|
return e.SelfSignature
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrimarySelfSignature searches the entity for the self-signature that stores key preferences.
|
||||||
|
// For V4 keys, returns the self-signature of the primary identity, and the identity.
|
||||||
|
// For V6 keys, returns the latest valid direct-key self-signature, and no identity (nil).
|
||||||
|
// This self-signature is to be used to check the key expiration,
|
||||||
|
// algorithm preferences, and so on.
|
||||||
|
func (e *Entity) PrimarySelfSignature() (*packet.Signature, *Identity) {
|
||||||
|
if e.PrimaryKey.Version == 6 {
|
||||||
|
return e.primaryDirectSignature(), nil
|
||||||
|
}
|
||||||
|
primaryIdentity := e.PrimaryIdentity()
|
||||||
|
if primaryIdentity == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return primaryIdentity.SelfSignature, primaryIdentity
|
||||||
|
}
|
||||||
|
36
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go
generated
vendored
36
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/aead_crypter.go
generated
vendored
@ -88,17 +88,20 @@ func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) {
|
|||||||
if errRead != nil && errRead != io.EOF {
|
if errRead != nil && errRead != io.EOF {
|
||||||
return 0, errRead
|
return 0, errRead
|
||||||
}
|
}
|
||||||
decrypted, errChunk := ar.openChunk(cipherChunk)
|
|
||||||
if errChunk != nil {
|
|
||||||
return 0, errChunk
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return decrypted bytes, buffering if necessary
|
if len(cipherChunk) > 0 {
|
||||||
if len(dst) < len(decrypted) {
|
decrypted, errChunk := ar.openChunk(cipherChunk)
|
||||||
n = copy(dst, decrypted[:len(dst)])
|
if errChunk != nil {
|
||||||
ar.buffer.Write(decrypted[len(dst):])
|
return 0, errChunk
|
||||||
} else {
|
}
|
||||||
n = copy(dst, decrypted)
|
|
||||||
|
// Return decrypted bytes, buffering if necessary
|
||||||
|
if len(dst) < len(decrypted) {
|
||||||
|
n = copy(dst, decrypted[:len(dst)])
|
||||||
|
ar.buffer.Write(decrypted[len(dst):])
|
||||||
|
} else {
|
||||||
|
n = copy(dst, decrypted)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check final authentication tag
|
// Check final authentication tag
|
||||||
@ -116,6 +119,12 @@ func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) {
|
|||||||
// checked in the last Read call. In the future, this function could be used to
|
// checked in the last Read call. In the future, this function could be used to
|
||||||
// wipe the reader and peeked, decrypted bytes, if necessary.
|
// wipe the reader and peeked, decrypted bytes, if necessary.
|
||||||
func (ar *aeadDecrypter) Close() (err error) {
|
func (ar *aeadDecrypter) Close() (err error) {
|
||||||
|
if !ar.eof {
|
||||||
|
errChunk := ar.validateFinalTag(ar.peekedBytes)
|
||||||
|
if errChunk != nil {
|
||||||
|
return errChunk
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +147,7 @@ func (ar *aeadDecrypter) openChunk(data []byte) ([]byte, error) {
|
|||||||
nonce := ar.computeNextNonce()
|
nonce := ar.computeNextNonce()
|
||||||
plainChunk, err := ar.aead.Open(nil, nonce, chunk, adata)
|
plainChunk, err := ar.aead.Open(nil, nonce, chunk, adata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.ErrAEADTagVerification
|
||||||
}
|
}
|
||||||
ar.bytesProcessed += len(plainChunk)
|
ar.bytesProcessed += len(plainChunk)
|
||||||
if err = ar.aeadCrypter.incrementIndex(); err != nil {
|
if err = ar.aeadCrypter.incrementIndex(); err != nil {
|
||||||
@ -163,9 +172,8 @@ func (ar *aeadDecrypter) validateFinalTag(tag []byte) error {
|
|||||||
// ... and total number of encrypted octets
|
// ... and total number of encrypted octets
|
||||||
adata = append(adata, amountBytes...)
|
adata = append(adata, amountBytes...)
|
||||||
nonce := ar.computeNextNonce()
|
nonce := ar.computeNextNonce()
|
||||||
_, err := ar.aead.Open(nil, nonce, tag, adata)
|
if _, err := ar.aead.Open(nil, nonce, tag, adata); err != nil {
|
||||||
if err != nil {
|
return errors.ErrAEADTagVerification
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
44
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
generated
vendored
44
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go
generated
vendored
@ -8,9 +8,10 @@ import (
|
|||||||
"compress/bzip2"
|
"compress/bzip2"
|
||||||
"compress/flate"
|
"compress/flate"
|
||||||
"compress/zlib"
|
"compress/zlib"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compressed represents a compressed OpenPGP packet. The decompressed contents
|
// Compressed represents a compressed OpenPGP packet. The decompressed contents
|
||||||
@ -39,6 +40,37 @@ type CompressionConfig struct {
|
|||||||
Level int
|
Level int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decompressionReader ensures that the whole compression packet is read.
|
||||||
|
type decompressionReader struct {
|
||||||
|
compressed io.Reader
|
||||||
|
decompressed io.ReadCloser
|
||||||
|
readAll bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDecompressionReader(r io.Reader, decompressor io.ReadCloser) *decompressionReader {
|
||||||
|
return &decompressionReader{
|
||||||
|
compressed: r,
|
||||||
|
decompressed: decompressor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dr *decompressionReader) Read(data []byte) (n int, err error) {
|
||||||
|
if dr.readAll {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
n, err = dr.decompressed.Read(data)
|
||||||
|
if err == io.EOF {
|
||||||
|
dr.readAll = true
|
||||||
|
// Close the decompressor.
|
||||||
|
if errDec := dr.decompressed.Close(); errDec != nil {
|
||||||
|
return n, errDec
|
||||||
|
}
|
||||||
|
// Consume all remaining data from the compressed packet.
|
||||||
|
consumeAll(dr.compressed)
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compressed) parse(r io.Reader) error {
|
func (c *Compressed) parse(r io.Reader) error {
|
||||||
var buf [1]byte
|
var buf [1]byte
|
||||||
_, err := readFull(r, buf[:])
|
_, err := readFull(r, buf[:])
|
||||||
@ -50,11 +82,15 @@ func (c *Compressed) parse(r io.Reader) error {
|
|||||||
case 0:
|
case 0:
|
||||||
c.Body = r
|
c.Body = r
|
||||||
case 1:
|
case 1:
|
||||||
c.Body = flate.NewReader(r)
|
c.Body = newDecompressionReader(r, flate.NewReader(r))
|
||||||
case 2:
|
case 2:
|
||||||
c.Body, err = zlib.NewReader(r)
|
decompressor, err := zlib.NewReader(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Body = newDecompressionReader(r, decompressor)
|
||||||
case 3:
|
case 3:
|
||||||
c.Body = bzip2.NewReader(r)
|
c.Body = newDecompressionReader(r, io.NopCloser(bzip2.NewReader(r)))
|
||||||
default:
|
default:
|
||||||
err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
|
err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
|
||||||
}
|
}
|
||||||
|
170
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
generated
vendored
170
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config.go
generated
vendored
@ -14,6 +14,34 @@ import (
|
|||||||
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultRejectPublicKeyAlgorithms = map[PublicKeyAlgorithm]bool{
|
||||||
|
PubKeyAlgoElGamal: true,
|
||||||
|
PubKeyAlgoDSA: true,
|
||||||
|
}
|
||||||
|
defaultRejectHashAlgorithms = map[crypto.Hash]bool{
|
||||||
|
crypto.MD5: true,
|
||||||
|
crypto.RIPEMD160: true,
|
||||||
|
}
|
||||||
|
defaultRejectMessageHashAlgorithms = map[crypto.Hash]bool{
|
||||||
|
crypto.SHA1: true,
|
||||||
|
crypto.MD5: true,
|
||||||
|
crypto.RIPEMD160: true,
|
||||||
|
}
|
||||||
|
defaultRejectCurves = map[Curve]bool{
|
||||||
|
CurveSecP256k1: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// A global feature flag to indicate v5 support.
|
||||||
|
// Can be set via a build tag, e.g.: `go build -tags v5 ./...`
|
||||||
|
// If the build tag is missing config_v5.go will set it to true.
|
||||||
|
//
|
||||||
|
// Disables parsing of v5 keys and v5 signatures.
|
||||||
|
// These are non-standard entities, which in the crypto-refresh have been superseded
|
||||||
|
// by v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively.
|
||||||
|
var V5Disabled = false
|
||||||
|
|
||||||
// Config collects a number of parameters along with sensible defaults.
|
// Config collects a number of parameters along with sensible defaults.
|
||||||
// A nil *Config is valid and results in all default values.
|
// A nil *Config is valid and results in all default values.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -73,9 +101,16 @@ type Config struct {
|
|||||||
// **Note: using this option may break compatibility with other OpenPGP
|
// **Note: using this option may break compatibility with other OpenPGP
|
||||||
// implementations, as well as future versions of this library.**
|
// implementations, as well as future versions of this library.**
|
||||||
AEADConfig *AEADConfig
|
AEADConfig *AEADConfig
|
||||||
// V5Keys configures version 5 key generation. If false, this package still
|
// V6Keys configures version 6 key generation. If false, this package still
|
||||||
// supports version 5 keys, but produces version 4 keys.
|
// supports version 6 keys, but produces version 4 keys.
|
||||||
V5Keys bool
|
V6Keys bool
|
||||||
|
// Minimum RSA key size allowed for key generation and message signing, verification and encryption.
|
||||||
|
MinRSABits uint16
|
||||||
|
// Reject insecure algorithms, only works with v2 api
|
||||||
|
RejectPublicKeyAlgorithms map[PublicKeyAlgorithm]bool
|
||||||
|
RejectHashAlgorithms map[crypto.Hash]bool
|
||||||
|
RejectMessageHashAlgorithms map[crypto.Hash]bool
|
||||||
|
RejectCurves map[Curve]bool
|
||||||
// "The validity period of the key. This is the number of seconds after
|
// "The validity period of the key. This is the number of seconds after
|
||||||
// the key creation time that the key expires. If this is not present
|
// the key creation time that the key expires. If this is not present
|
||||||
// or has a value of zero, the key never expires. This is found only on
|
// or has a value of zero, the key never expires. This is found only on
|
||||||
@ -104,12 +139,40 @@ type Config struct {
|
|||||||
// might be no other way than to tolerate the missing MDC. Setting this flag, allows this
|
// might be no other way than to tolerate the missing MDC. Setting this flag, allows this
|
||||||
// mode of operation. It should be considered a measure of last resort.
|
// mode of operation. It should be considered a measure of last resort.
|
||||||
InsecureAllowUnauthenticatedMessages bool
|
InsecureAllowUnauthenticatedMessages bool
|
||||||
|
// InsecureAllowDecryptionWithSigningKeys allows decryption with keys marked as signing keys in the v2 API.
|
||||||
|
// This setting is potentially insecure, but it is needed as some libraries
|
||||||
|
// ignored key flags when selecting a key for encryption.
|
||||||
|
// Not relevant for the v1 API, as all keys were allowed in decryption.
|
||||||
|
InsecureAllowDecryptionWithSigningKeys bool
|
||||||
// KnownNotations is a map of Notation Data names to bools, which controls
|
// KnownNotations is a map of Notation Data names to bools, which controls
|
||||||
// the notation names that are allowed to be present in critical Notation Data
|
// the notation names that are allowed to be present in critical Notation Data
|
||||||
// signature subpackets.
|
// signature subpackets.
|
||||||
KnownNotations map[string]bool
|
KnownNotations map[string]bool
|
||||||
// SignatureNotations is a list of Notations to be added to any signatures.
|
// SignatureNotations is a list of Notations to be added to any signatures.
|
||||||
SignatureNotations []*Notation
|
SignatureNotations []*Notation
|
||||||
|
// CheckIntendedRecipients controls, whether the OpenPGP Intended Recipient Fingerprint feature
|
||||||
|
// should be enabled for encryption and decryption.
|
||||||
|
// (See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr).
|
||||||
|
// When the flag is set, encryption produces Intended Recipient Fingerprint signature sub-packets and decryption
|
||||||
|
// checks whether the key it was encrypted to is one of the included fingerprints in the signature.
|
||||||
|
// If the flag is disabled, no Intended Recipient Fingerprint sub-packets are created or checked.
|
||||||
|
// The default behavior, when the config or flag is nil, is to enable the feature.
|
||||||
|
CheckIntendedRecipients *bool
|
||||||
|
// CacheSessionKey controls if decryption should return the session key used for decryption.
|
||||||
|
// If the flag is set, the session key is cached in the message details struct.
|
||||||
|
CacheSessionKey bool
|
||||||
|
// CheckPacketSequence is a flag that controls if the pgp message reader should strictly check
|
||||||
|
// that the packet sequence conforms with the grammar mandated by rfc4880.
|
||||||
|
// The default behavior, when the config or flag is nil, is to check the packet sequence.
|
||||||
|
CheckPacketSequence *bool
|
||||||
|
// NonDeterministicSignaturesViaNotation is a flag to enable randomization of signatures.
|
||||||
|
// If true, a salt notation is used to randomize signatures generated by v4 and v5 keys
|
||||||
|
// (v6 signatures are always non-deterministic, by design).
|
||||||
|
// This protects EdDSA signatures from potentially leaking the secret key in case of faults (i.e. bitflips) which, in principle, could occur
|
||||||
|
// during the signing computation. It is added to signatures of any algo for simplicity, and as it may also serve as protection in case of
|
||||||
|
// weaknesses in the hash algo, potentially hindering e.g. some chosen-prefix attacks.
|
||||||
|
// The default behavior, when the config or flag is nil, is to enable the feature.
|
||||||
|
NonDeterministicSignaturesViaNotation *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Random() io.Reader {
|
func (c *Config) Random() io.Reader {
|
||||||
@ -197,7 +260,7 @@ func (c *Config) S2K() *s2k.Config {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// for backwards compatibility
|
// for backwards compatibility
|
||||||
if c != nil && c.S2KCount > 0 && c.S2KConfig == nil {
|
if c.S2KCount > 0 && c.S2KConfig == nil {
|
||||||
return &s2k.Config{
|
return &s2k.Config{
|
||||||
S2KCount: c.S2KCount,
|
S2KCount: c.S2KCount,
|
||||||
}
|
}
|
||||||
@ -233,6 +296,13 @@ func (c *Config) AllowUnauthenticatedMessages() bool {
|
|||||||
return c.InsecureAllowUnauthenticatedMessages
|
return c.InsecureAllowUnauthenticatedMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) AllowDecryptionWithSigningKeys() bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return c.InsecureAllowDecryptionWithSigningKeys
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) KnownNotation(notationName string) bool {
|
func (c *Config) KnownNotation(notationName string) bool {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return false
|
return false
|
||||||
@ -246,3 +316,95 @@ func (c *Config) Notations() []*Notation {
|
|||||||
}
|
}
|
||||||
return c.SignatureNotations
|
return c.SignatureNotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) V6() bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return c.V6Keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) IntendedRecipients() bool {
|
||||||
|
if c == nil || c.CheckIntendedRecipients == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return *c.CheckIntendedRecipients
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) RetrieveSessionKey() bool {
|
||||||
|
if c == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return c.CacheSessionKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) MinimumRSABits() uint16 {
|
||||||
|
if c == nil || c.MinRSABits == 0 {
|
||||||
|
return 2047
|
||||||
|
}
|
||||||
|
return c.MinRSABits
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) RejectPublicKeyAlgorithm(alg PublicKeyAlgorithm) bool {
|
||||||
|
var rejectedAlgorithms map[PublicKeyAlgorithm]bool
|
||||||
|
if c == nil || c.RejectPublicKeyAlgorithms == nil {
|
||||||
|
// Default
|
||||||
|
rejectedAlgorithms = defaultRejectPublicKeyAlgorithms
|
||||||
|
} else {
|
||||||
|
rejectedAlgorithms = c.RejectPublicKeyAlgorithms
|
||||||
|
}
|
||||||
|
return rejectedAlgorithms[alg]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) RejectHashAlgorithm(hash crypto.Hash) bool {
|
||||||
|
var rejectedAlgorithms map[crypto.Hash]bool
|
||||||
|
if c == nil || c.RejectHashAlgorithms == nil {
|
||||||
|
// Default
|
||||||
|
rejectedAlgorithms = defaultRejectHashAlgorithms
|
||||||
|
} else {
|
||||||
|
rejectedAlgorithms = c.RejectHashAlgorithms
|
||||||
|
}
|
||||||
|
return rejectedAlgorithms[hash]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) RejectMessageHashAlgorithm(hash crypto.Hash) bool {
|
||||||
|
var rejectedAlgorithms map[crypto.Hash]bool
|
||||||
|
if c == nil || c.RejectMessageHashAlgorithms == nil {
|
||||||
|
// Default
|
||||||
|
rejectedAlgorithms = defaultRejectMessageHashAlgorithms
|
||||||
|
} else {
|
||||||
|
rejectedAlgorithms = c.RejectMessageHashAlgorithms
|
||||||
|
}
|
||||||
|
return rejectedAlgorithms[hash]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) RejectCurve(curve Curve) bool {
|
||||||
|
var rejectedCurve map[Curve]bool
|
||||||
|
if c == nil || c.RejectCurves == nil {
|
||||||
|
// Default
|
||||||
|
rejectedCurve = defaultRejectCurves
|
||||||
|
} else {
|
||||||
|
rejectedCurve = c.RejectCurves
|
||||||
|
}
|
||||||
|
return rejectedCurve[curve]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) StrictPacketSequence() bool {
|
||||||
|
if c == nil || c.CheckPacketSequence == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return *c.CheckPacketSequence
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) RandomizeSignaturesViaNotation() bool {
|
||||||
|
if c == nil || c.NonDeterministicSignaturesViaNotation == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return *c.NonDeterministicSignaturesViaNotation
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolPointer is a helper function to set a boolean pointer in the Config.
|
||||||
|
// e.g., config.CheckPacketSequence = BoolPointer(true)
|
||||||
|
func BoolPointer(value bool) *bool {
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
7
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go
generated
vendored
Normal file
7
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/config_v5.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//go:build !v5
|
||||||
|
|
||||||
|
package packet
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
V5Disabled = true
|
||||||
|
}
|
422
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
generated
vendored
422
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/encrypted_key.go
generated
vendored
@ -5,9 +5,11 @@
|
|||||||
package packet
|
package packet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -16,32 +18,85 @@ import (
|
|||||||
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x448"
|
||||||
)
|
)
|
||||||
|
|
||||||
const encryptedKeyVersion = 3
|
|
||||||
|
|
||||||
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
|
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
|
||||||
// section 5.1.
|
// section 5.1.
|
||||||
type EncryptedKey struct {
|
type EncryptedKey struct {
|
||||||
KeyId uint64
|
Version int
|
||||||
Algo PublicKeyAlgorithm
|
KeyId uint64
|
||||||
CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet
|
KeyVersion int // v6
|
||||||
Key []byte // only valid after a successful Decrypt
|
KeyFingerprint []byte // v6
|
||||||
|
Algo PublicKeyAlgorithm
|
||||||
|
CipherFunc CipherFunction // only valid after a successful Decrypt for a v3 packet
|
||||||
|
Key []byte // only valid after a successful Decrypt
|
||||||
|
|
||||||
encryptedMPI1, encryptedMPI2 encoding.Field
|
encryptedMPI1, encryptedMPI2 encoding.Field
|
||||||
|
ephemeralPublicX25519 *x25519.PublicKey // used for x25519
|
||||||
|
ephemeralPublicX448 *x448.PublicKey // used for x448
|
||||||
|
encryptedSession []byte // used for x25519 and x448
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EncryptedKey) parse(r io.Reader) (err error) {
|
func (e *EncryptedKey) parse(r io.Reader) (err error) {
|
||||||
var buf [10]byte
|
var buf [8]byte
|
||||||
_, err = readFull(r, buf[:])
|
_, err = readFull(r, buf[:versionSize])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if buf[0] != encryptedKeyVersion {
|
e.Version = int(buf[0])
|
||||||
|
if e.Version != 3 && e.Version != 6 {
|
||||||
return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
|
return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
|
||||||
}
|
}
|
||||||
e.KeyId = binary.BigEndian.Uint64(buf[1:9])
|
if e.Version == 6 {
|
||||||
e.Algo = PublicKeyAlgorithm(buf[9])
|
//Read a one-octet size of the following two fields.
|
||||||
|
if _, err = readFull(r, buf[:1]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// The size may also be zero, and the key version and
|
||||||
|
// fingerprint omitted for an "anonymous recipient"
|
||||||
|
if buf[0] != 0 {
|
||||||
|
// non-anonymous case
|
||||||
|
_, err = readFull(r, buf[:versionSize])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.KeyVersion = int(buf[0])
|
||||||
|
if e.KeyVersion != 4 && e.KeyVersion != 6 {
|
||||||
|
return errors.UnsupportedError("unknown public key version " + strconv.Itoa(e.KeyVersion))
|
||||||
|
}
|
||||||
|
var fingerprint []byte
|
||||||
|
if e.KeyVersion == 6 {
|
||||||
|
fingerprint = make([]byte, fingerprintSizeV6)
|
||||||
|
} else if e.KeyVersion == 4 {
|
||||||
|
fingerprint = make([]byte, fingerprintSize)
|
||||||
|
}
|
||||||
|
_, err = readFull(r, fingerprint)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.KeyFingerprint = fingerprint
|
||||||
|
if e.KeyVersion == 6 {
|
||||||
|
e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[:keyIdSize])
|
||||||
|
} else if e.KeyVersion == 4 {
|
||||||
|
e.KeyId = binary.BigEndian.Uint64(e.KeyFingerprint[fingerprintSize-keyIdSize : fingerprintSize])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err = readFull(r, buf[:8])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.KeyId = binary.BigEndian.Uint64(buf[:keyIdSize])
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = readFull(r, buf[:1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.Algo = PublicKeyAlgorithm(buf[0])
|
||||||
|
var cipherFunction byte
|
||||||
switch e.Algo {
|
switch e.Algo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||||
e.encryptedMPI1 = new(encoding.MPI)
|
e.encryptedMPI1 = new(encoding.MPI)
|
||||||
@ -68,26 +123,39 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) {
|
|||||||
if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
|
if _, err = e.encryptedMPI2.ReadFrom(r); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
e.ephemeralPublicX25519, e.encryptedSession, cipherFunction, err = x25519.DecodeFields(r, e.Version == 6)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
e.ephemeralPublicX448, e.encryptedSession, cipherFunction, err = x448.DecodeFields(r, e.Version == 6)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if e.Version < 6 {
|
||||||
|
switch e.Algo {
|
||||||
|
case PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||||
|
e.CipherFunc = CipherFunction(cipherFunction)
|
||||||
|
// Check for validiy is in the Decrypt method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err = consumeAll(r)
|
_, err = consumeAll(r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func checksumKeyMaterial(key []byte) uint16 {
|
|
||||||
var checksum uint16
|
|
||||||
for _, v := range key {
|
|
||||||
checksum += uint16(v)
|
|
||||||
}
|
|
||||||
return checksum
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt decrypts an encrypted session key with the given private key. The
|
// Decrypt decrypts an encrypted session key with the given private key. The
|
||||||
// private key must have been decrypted first.
|
// private key must have been decrypted first.
|
||||||
// If config is nil, sensible defaults will be used.
|
// If config is nil, sensible defaults will be used.
|
||||||
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
|
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
|
||||||
if e.KeyId != 0 && e.KeyId != priv.KeyId {
|
if e.Version < 6 && e.KeyId != 0 && e.KeyId != priv.KeyId {
|
||||||
return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16))
|
return errors.InvalidArgumentError("cannot decrypt encrypted session key for key id " + strconv.FormatUint(e.KeyId, 16) + " with private key id " + strconv.FormatUint(priv.KeyId, 16))
|
||||||
}
|
}
|
||||||
|
if e.Version == 6 && e.KeyVersion != 0 && !bytes.Equal(e.KeyFingerprint, priv.Fingerprint) {
|
||||||
|
return errors.InvalidArgumentError("cannot decrypt encrypted session key for key fingerprint " + hex.EncodeToString(e.KeyFingerprint) + " with private key fingerprint " + hex.EncodeToString(priv.Fingerprint))
|
||||||
|
}
|
||||||
if e.Algo != priv.PubKeyAlgo {
|
if e.Algo != priv.PubKeyAlgo {
|
||||||
return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
|
return errors.InvalidArgumentError("cannot decrypt encrypted session key of type " + strconv.Itoa(int(e.Algo)) + " with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
|
||||||
}
|
}
|
||||||
@ -113,52 +181,116 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
|
|||||||
vsG := e.encryptedMPI1.Bytes()
|
vsG := e.encryptedMPI1.Bytes()
|
||||||
m := e.encryptedMPI2.Bytes()
|
m := e.encryptedMPI2.Bytes()
|
||||||
oid := priv.PublicKey.oid.EncodedBytes()
|
oid := priv.PublicKey.oid.EncodedBytes()
|
||||||
b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, priv.PublicKey.Fingerprint[:])
|
fp := priv.PublicKey.Fingerprint[:]
|
||||||
|
if priv.PublicKey.Version == 5 {
|
||||||
|
// For v5 the, the fingerprint must be restricted to 20 bytes
|
||||||
|
fp = fp[:20]
|
||||||
|
}
|
||||||
|
b, err = ecdh.Decrypt(priv.PrivateKey.(*ecdh.PrivateKey), vsG, m, oid, fp)
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
b, err = x25519.Decrypt(priv.PrivateKey.(*x25519.PrivateKey), e.ephemeralPublicX25519, e.encryptedSession)
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
b, err = x448.Decrypt(priv.PrivateKey.(*x448.PrivateKey), e.ephemeralPublicX448, e.encryptedSession)
|
||||||
default:
|
default:
|
||||||
err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
|
err = errors.InvalidArgumentError("cannot decrypt encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.CipherFunc = CipherFunction(b[0])
|
var key []byte
|
||||||
if !e.CipherFunc.IsSupported() {
|
switch priv.PubKeyAlgo {
|
||||||
return errors.UnsupportedError("unsupported encryption function")
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
|
||||||
|
keyOffset := 0
|
||||||
|
if e.Version < 6 {
|
||||||
|
e.CipherFunc = CipherFunction(b[0])
|
||||||
|
keyOffset = 1
|
||||||
|
if !e.CipherFunc.IsSupported() {
|
||||||
|
return errors.UnsupportedError("unsupported encryption function")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key, err = decodeChecksumKey(b[keyOffset:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||||
|
if e.Version < 6 {
|
||||||
|
switch e.CipherFunc {
|
||||||
|
case CipherAES128, CipherAES192, CipherAES256:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return errors.StructuralError("v3 PKESK mandates AES as cipher function for x25519 and x448")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key = b[:]
|
||||||
|
default:
|
||||||
|
return errors.UnsupportedError("unsupported algorithm for decryption")
|
||||||
}
|
}
|
||||||
|
e.Key = key
|
||||||
e.Key = b[1 : len(b)-2]
|
|
||||||
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
|
|
||||||
checksum := checksumKeyMaterial(e.Key)
|
|
||||||
if checksum != expectedChecksum {
|
|
||||||
return errors.StructuralError("EncryptedKey checksum incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize writes the encrypted key packet, e, to w.
|
// Serialize writes the encrypted key packet, e, to w.
|
||||||
func (e *EncryptedKey) Serialize(w io.Writer) error {
|
func (e *EncryptedKey) Serialize(w io.Writer) error {
|
||||||
var mpiLen int
|
var encodedLength int
|
||||||
switch e.Algo {
|
switch e.Algo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||||
mpiLen = int(e.encryptedMPI1.EncodedLength())
|
encodedLength = int(e.encryptedMPI1.EncodedLength())
|
||||||
case PubKeyAlgoElGamal:
|
case PubKeyAlgoElGamal:
|
||||||
mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
|
encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
|
||||||
case PubKeyAlgoECDH:
|
case PubKeyAlgoECDH:
|
||||||
mpiLen = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
|
encodedLength = int(e.encryptedMPI1.EncodedLength()) + int(e.encryptedMPI2.EncodedLength())
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
encodedLength = x25519.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
encodedLength = x448.EncodedFieldsLength(e.encryptedSession, e.Version == 6)
|
||||||
default:
|
default:
|
||||||
return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
|
return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
|
packetLen := versionSize /* version */ + keyIdSize /* key id */ + algorithmSize /* algo */ + encodedLength
|
||||||
|
if e.Version == 6 {
|
||||||
|
packetLen = versionSize /* version */ + algorithmSize /* algo */ + encodedLength + keyVersionSize /* key version */
|
||||||
|
if e.KeyVersion == 6 {
|
||||||
|
packetLen += fingerprintSizeV6
|
||||||
|
} else if e.KeyVersion == 4 {
|
||||||
|
packetLen += fingerprintSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte{encryptedKeyVersion})
|
_, err = w.Write([]byte{byte(e.Version)})
|
||||||
binary.Write(w, binary.BigEndian, e.KeyId)
|
if err != nil {
|
||||||
w.Write([]byte{byte(e.Algo)})
|
return err
|
||||||
|
}
|
||||||
|
if e.Version == 6 {
|
||||||
|
_, err = w.Write([]byte{byte(e.KeyVersion)})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// The key version number may also be zero,
|
||||||
|
// and the fingerprint omitted
|
||||||
|
if e.KeyVersion != 0 {
|
||||||
|
_, err = w.Write(e.KeyFingerprint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Write KeyID
|
||||||
|
err = binary.Write(w, binary.BigEndian, e.KeyId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = w.Write([]byte{byte(e.Algo)})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
switch e.Algo {
|
switch e.Algo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||||
@ -176,34 +308,115 @@ func (e *EncryptedKey) Serialize(w io.Writer) error {
|
|||||||
}
|
}
|
||||||
_, err := w.Write(e.encryptedMPI2.EncodedBytes())
|
_, err := w.Write(e.encryptedMPI2.EncodedBytes())
|
||||||
return err
|
return err
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
err := x25519.EncodeFields(w, e.ephemeralPublicX25519, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
|
||||||
|
return err
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
err := x448.EncodeFields(w, e.ephemeralPublicX448, e.encryptedSession, byte(e.CipherFunc), e.Version == 6)
|
||||||
|
return err
|
||||||
default:
|
default:
|
||||||
panic("internal error")
|
panic("internal error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
|
// SerializeEncryptedKeyAEAD serializes an encrypted key packet to w that contains
|
||||||
// key, encrypted to pub.
|
// key, encrypted to pub.
|
||||||
|
// If aeadSupported is set, PKESK v6 is used, otherwise v3.
|
||||||
|
// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
|
||||||
// If config is nil, sensible defaults will be used.
|
// If config is nil, sensible defaults will be used.
|
||||||
func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
|
func SerializeEncryptedKeyAEAD(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, config *Config) error {
|
||||||
var buf [10]byte
|
return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, aeadSupported, key, false, config)
|
||||||
buf[0] = encryptedKeyVersion
|
}
|
||||||
binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
|
|
||||||
buf[9] = byte(pub.PubKeyAlgo)
|
|
||||||
|
|
||||||
keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */)
|
// SerializeEncryptedKeyAEADwithHiddenOption serializes an encrypted key packet to w that contains
|
||||||
keyBlock[0] = byte(cipherFunc)
|
// key, encrypted to pub.
|
||||||
copy(keyBlock[1:], key)
|
// Offers the hidden flag option to indicated if the PKESK packet should include a wildcard KeyID.
|
||||||
checksum := checksumKeyMaterial(key)
|
// If aeadSupported is set, PKESK v6 is used, otherwise v3.
|
||||||
keyBlock[1+len(key)] = byte(checksum >> 8)
|
// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
|
||||||
keyBlock[1+len(key)+1] = byte(checksum)
|
// If config is nil, sensible defaults will be used.
|
||||||
|
func SerializeEncryptedKeyAEADwithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, aeadSupported bool, key []byte, hidden bool, config *Config) error {
|
||||||
|
var buf [36]byte // max possible header size is v6
|
||||||
|
lenHeaderWritten := versionSize
|
||||||
|
version := 3
|
||||||
|
|
||||||
|
if aeadSupported {
|
||||||
|
version = 6
|
||||||
|
}
|
||||||
|
// An implementation MUST NOT generate ElGamal v6 PKESKs.
|
||||||
|
if version == 6 && pub.PubKeyAlgo == PubKeyAlgoElGamal {
|
||||||
|
return errors.InvalidArgumentError("ElGamal v6 PKESK are not allowed")
|
||||||
|
}
|
||||||
|
// In v3 PKESKs, for x25519 and x448, mandate using AES
|
||||||
|
if version == 3 && (pub.PubKeyAlgo == PubKeyAlgoX25519 || pub.PubKeyAlgo == PubKeyAlgoX448) {
|
||||||
|
switch cipherFunc {
|
||||||
|
case CipherAES128, CipherAES192, CipherAES256:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return errors.InvalidArgumentError("v3 PKESK mandates AES for x25519 and x448")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0] = byte(version)
|
||||||
|
|
||||||
|
// If hidden is set, the key should be hidden
|
||||||
|
// An implementation MAY accept or use a Key ID of all zeros,
|
||||||
|
// or a key version of zero and no key fingerprint, to hide the intended decryption key.
|
||||||
|
// See Section 5.1.8. in the open pgp crypto refresh
|
||||||
|
if version == 6 {
|
||||||
|
if !hidden {
|
||||||
|
// A one-octet size of the following two fields.
|
||||||
|
buf[1] = byte(keyVersionSize + len(pub.Fingerprint))
|
||||||
|
// A one octet key version number.
|
||||||
|
buf[2] = byte(pub.Version)
|
||||||
|
lenHeaderWritten += keyVersionSize + 1
|
||||||
|
// The fingerprint of the public key
|
||||||
|
copy(buf[lenHeaderWritten:lenHeaderWritten+len(pub.Fingerprint)], pub.Fingerprint)
|
||||||
|
lenHeaderWritten += len(pub.Fingerprint)
|
||||||
|
} else {
|
||||||
|
// The size may also be zero, and the key version
|
||||||
|
// and fingerprint omitted for an "anonymous recipient"
|
||||||
|
buf[1] = 0
|
||||||
|
lenHeaderWritten += 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !hidden {
|
||||||
|
binary.BigEndian.PutUint64(buf[versionSize:(versionSize+keyIdSize)], pub.KeyId)
|
||||||
|
}
|
||||||
|
lenHeaderWritten += keyIdSize
|
||||||
|
}
|
||||||
|
buf[lenHeaderWritten] = byte(pub.PubKeyAlgo)
|
||||||
|
lenHeaderWritten += algorithmSize
|
||||||
|
|
||||||
|
var keyBlock []byte
|
||||||
|
switch pub.PubKeyAlgo {
|
||||||
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
|
||||||
|
lenKeyBlock := len(key) + 2
|
||||||
|
if version < 6 {
|
||||||
|
lenKeyBlock += 1 // cipher type included
|
||||||
|
}
|
||||||
|
keyBlock = make([]byte, lenKeyBlock)
|
||||||
|
keyOffset := 0
|
||||||
|
if version < 6 {
|
||||||
|
keyBlock[0] = byte(cipherFunc)
|
||||||
|
keyOffset = 1
|
||||||
|
}
|
||||||
|
encodeChecksumKey(keyBlock[keyOffset:], key)
|
||||||
|
case PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||||
|
// algorithm is added in plaintext below
|
||||||
|
keyBlock = key
|
||||||
|
}
|
||||||
|
|
||||||
switch pub.PubKeyAlgo {
|
switch pub.PubKeyAlgo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||||
return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
|
return serializeEncryptedKeyRSA(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*rsa.PublicKey), keyBlock)
|
||||||
case PubKeyAlgoElGamal:
|
case PubKeyAlgoElGamal:
|
||||||
return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
|
return serializeEncryptedKeyElGamal(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*elgamal.PublicKey), keyBlock)
|
||||||
case PubKeyAlgoECDH:
|
case PubKeyAlgoECDH:
|
||||||
return serializeEncryptedKeyECDH(w, config.Random(), buf, pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
|
return serializeEncryptedKeyECDH(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*ecdh.PublicKey), keyBlock, pub.oid, pub.Fingerprint)
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
return serializeEncryptedKeyX25519(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x25519.PublicKey), keyBlock, byte(cipherFunc), version)
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
return serializeEncryptedKeyX448(w, config.Random(), buf[:lenHeaderWritten], pub.PublicKey.(*x448.PublicKey), keyBlock, byte(cipherFunc), version)
|
||||||
case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
|
case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
|
||||||
return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
|
return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
|
||||||
}
|
}
|
||||||
@ -211,14 +424,32 @@ func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunctio
|
|||||||
return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
|
return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
|
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
|
||||||
|
// key, encrypted to pub.
|
||||||
|
// PKESKv6 is used if config.AEAD() is not nil.
|
||||||
|
// If config is nil, sensible defaults will be used.
|
||||||
|
// Deprecated: Use SerializeEncryptedKeyAEAD instead.
|
||||||
|
func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
|
||||||
|
return SerializeEncryptedKeyAEAD(w, pub, cipherFunc, config.AEAD() != nil, key, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeEncryptedKeyWithHiddenOption serializes an encrypted key packet to w that contains
|
||||||
|
// key, encrypted to pub. PKESKv6 is used if config.AEAD() is not nil.
|
||||||
|
// The hidden option controls if the packet should be anonymous, i.e., omit key metadata.
|
||||||
|
// If config is nil, sensible defaults will be used.
|
||||||
|
// Deprecated: Use SerializeEncryptedKeyAEADwithHiddenOption instead.
|
||||||
|
func SerializeEncryptedKeyWithHiddenOption(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, hidden bool, config *Config) error {
|
||||||
|
return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, config.AEAD() != nil, key, hidden, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header []byte, pub *rsa.PublicKey, keyBlock []byte) error {
|
||||||
cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
|
cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
|
return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
cipherMPI := encoding.NewMPI(cipherText)
|
cipherMPI := encoding.NewMPI(cipherText)
|
||||||
packetLen := 10 /* header length */ + int(cipherMPI.EncodedLength())
|
packetLen := len(header) /* header length */ + int(cipherMPI.EncodedLength())
|
||||||
|
|
||||||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -232,13 +463,13 @@ func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
|
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header []byte, pub *elgamal.PublicKey, keyBlock []byte) error {
|
||||||
c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
|
c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
|
return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
packetLen := 10 /* header length */
|
packetLen := len(header) /* header length */
|
||||||
packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
|
packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
|
||||||
packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
|
packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
|
||||||
|
|
||||||
@ -257,7 +488,7 @@ func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
|
func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header []byte, pub *ecdh.PublicKey, keyBlock []byte, oid encoding.Field, fingerprint []byte) error {
|
||||||
vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
|
vsG, c, err := ecdh.Encrypt(rand, pub, keyBlock, oid.EncodedBytes(), fingerprint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
|
return errors.InvalidArgumentError("ECDH encryption failed: " + err.Error())
|
||||||
@ -266,7 +497,7 @@ func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub
|
|||||||
g := encoding.NewMPI(vsG)
|
g := encoding.NewMPI(vsG)
|
||||||
m := encoding.NewOID(c)
|
m := encoding.NewOID(c)
|
||||||
|
|
||||||
packetLen := 10 /* header length */
|
packetLen := len(header) /* header length */
|
||||||
packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
|
packetLen += int(g.EncodedLength()) + int(m.EncodedLength())
|
||||||
|
|
||||||
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||||
@ -284,3 +515,70 @@ func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub
|
|||||||
_, err = w.Write(m.EncodedBytes())
|
_, err = w.Write(m.EncodedBytes())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func serializeEncryptedKeyX25519(w io.Writer, rand io.Reader, header []byte, pub *x25519.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
|
||||||
|
ephemeralPublicX25519, ciphertext, err := x25519.Encrypt(rand, pub, keyBlock)
|
||||||
|
if err != nil {
|
||||||
|
return errors.InvalidArgumentError("x25519 encryption failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
packetLen := len(header) /* header length */
|
||||||
|
packetLen += x25519.EncodedFieldsLength(ciphertext, version == 6)
|
||||||
|
|
||||||
|
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(header[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return x25519.EncodeFields(w, ephemeralPublicX25519, ciphertext, cipherFunc, version == 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeEncryptedKeyX448(w io.Writer, rand io.Reader, header []byte, pub *x448.PublicKey, keyBlock []byte, cipherFunc byte, version int) error {
|
||||||
|
ephemeralPublicX448, ciphertext, err := x448.Encrypt(rand, pub, keyBlock)
|
||||||
|
if err != nil {
|
||||||
|
return errors.InvalidArgumentError("x448 encryption failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
packetLen := len(header) /* header length */
|
||||||
|
packetLen += x448.EncodedFieldsLength(ciphertext, version == 6)
|
||||||
|
|
||||||
|
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(header[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return x448.EncodeFields(w, ephemeralPublicX448, ciphertext, cipherFunc, version == 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checksumKeyMaterial(key []byte) uint16 {
|
||||||
|
var checksum uint16
|
||||||
|
for _, v := range key {
|
||||||
|
checksum += uint16(v)
|
||||||
|
}
|
||||||
|
return checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeChecksumKey(msg []byte) (key []byte, err error) {
|
||||||
|
key = msg[:len(msg)-2]
|
||||||
|
expectedChecksum := uint16(msg[len(msg)-2])<<8 | uint16(msg[len(msg)-1])
|
||||||
|
checksum := checksumKeyMaterial(key)
|
||||||
|
if checksum != expectedChecksum {
|
||||||
|
err = errors.StructuralError("session key checksum is incorrect")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeChecksumKey(buffer []byte, key []byte) {
|
||||||
|
copy(buffer, key)
|
||||||
|
checksum := checksumKeyMaterial(key)
|
||||||
|
buffer[len(key)] = byte(checksum >> 8)
|
||||||
|
buffer[len(key)+1] = byte(checksum)
|
||||||
|
}
|
||||||
|
6
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
generated
vendored
6
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/literal.go
generated
vendored
@ -58,9 +58,9 @@ func (l *LiteralData) parse(r io.Reader) (err error) {
|
|||||||
// on completion. The fileName is truncated to 255 bytes.
|
// on completion. The fileName is truncated to 255 bytes.
|
||||||
func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
|
func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
|
||||||
var buf [4]byte
|
var buf [4]byte
|
||||||
buf[0] = 't'
|
buf[0] = 'b'
|
||||||
if isBinary {
|
if !isBinary {
|
||||||
buf[0] = 'b'
|
buf[0] = 'u'
|
||||||
}
|
}
|
||||||
if len(fileName) > 255 {
|
if len(fileName) > 255 {
|
||||||
fileName = fileName[:255]
|
fileName = fileName[:255]
|
||||||
|
33
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go
generated
vendored
Normal file
33
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/marker.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package packet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Marker struct{}
|
||||||
|
|
||||||
|
const markerString = "PGP"
|
||||||
|
|
||||||
|
// parse just checks if the packet contains "PGP".
|
||||||
|
func (m *Marker) parse(reader io.Reader) error {
|
||||||
|
var buffer [3]byte
|
||||||
|
if _, err := io.ReadFull(reader, buffer[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if string(buffer[:]) != markerString {
|
||||||
|
return errors.StructuralError("invalid marker packet")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeMarker writes a marker packet to writer.
|
||||||
|
func SerializeMarker(writer io.Writer) error {
|
||||||
|
err := serializeHeader(writer, packetTypeMarker, len(markerString))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = writer.Write([]byte(markerString))
|
||||||
|
return err
|
||||||
|
}
|
132
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
generated
vendored
132
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/one_pass_signature.go
generated
vendored
@ -7,34 +7,37 @@ package packet
|
|||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OnePassSignature represents a one-pass signature packet. See RFC 4880,
|
// OnePassSignature represents a one-pass signature packet. See RFC 4880,
|
||||||
// section 5.4.
|
// section 5.4.
|
||||||
type OnePassSignature struct {
|
type OnePassSignature struct {
|
||||||
SigType SignatureType
|
Version int
|
||||||
Hash crypto.Hash
|
SigType SignatureType
|
||||||
PubKeyAlgo PublicKeyAlgorithm
|
Hash crypto.Hash
|
||||||
KeyId uint64
|
PubKeyAlgo PublicKeyAlgorithm
|
||||||
IsLast bool
|
KeyId uint64
|
||||||
|
IsLast bool
|
||||||
|
Salt []byte // v6 only
|
||||||
|
KeyFingerprint []byte // v6 only
|
||||||
}
|
}
|
||||||
|
|
||||||
const onePassSignatureVersion = 3
|
|
||||||
|
|
||||||
func (ops *OnePassSignature) parse(r io.Reader) (err error) {
|
func (ops *OnePassSignature) parse(r io.Reader) (err error) {
|
||||||
var buf [13]byte
|
var buf [8]byte
|
||||||
|
// Read: version | signature type | hash algorithm | public-key algorithm
|
||||||
_, err = readFull(r, buf[:])
|
_, err = readFull(r, buf[:4])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if buf[0] != onePassSignatureVersion {
|
if buf[0] != 3 && buf[0] != 6 {
|
||||||
err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
|
return errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
|
||||||
}
|
}
|
||||||
|
ops.Version = int(buf[0])
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2])
|
ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2])
|
||||||
@ -44,15 +47,69 @@ func (ops *OnePassSignature) parse(r io.Reader) (err error) {
|
|||||||
|
|
||||||
ops.SigType = SignatureType(buf[1])
|
ops.SigType = SignatureType(buf[1])
|
||||||
ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
|
ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
|
||||||
ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
|
|
||||||
ops.IsLast = buf[12] != 0
|
if ops.Version == 6 {
|
||||||
|
// Only for v6, a variable-length field containing the salt
|
||||||
|
_, err = readFull(r, buf[:1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
saltLength := int(buf[0])
|
||||||
|
var expectedSaltLength int
|
||||||
|
expectedSaltLength, err = SaltLengthForHash(ops.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if saltLength != expectedSaltLength {
|
||||||
|
err = errors.StructuralError("unexpected salt size for the given hash algorithm")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
salt := make([]byte, expectedSaltLength)
|
||||||
|
_, err = readFull(r, salt)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ops.Salt = salt
|
||||||
|
|
||||||
|
// Only for v6 packets, 32 octets of the fingerprint of the signing key.
|
||||||
|
fingerprint := make([]byte, 32)
|
||||||
|
_, err = readFull(r, fingerprint)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ops.KeyFingerprint = fingerprint
|
||||||
|
ops.KeyId = binary.BigEndian.Uint64(ops.KeyFingerprint[:8])
|
||||||
|
} else {
|
||||||
|
_, err = readFull(r, buf[:8])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ops.KeyId = binary.BigEndian.Uint64(buf[:8])
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = readFull(r, buf[:1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ops.IsLast = buf[0] != 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize marshals the given OnePassSignature to w.
|
// Serialize marshals the given OnePassSignature to w.
|
||||||
func (ops *OnePassSignature) Serialize(w io.Writer) error {
|
func (ops *OnePassSignature) Serialize(w io.Writer) error {
|
||||||
var buf [13]byte
|
//v3 length 1+1+1+1+8+1 =
|
||||||
buf[0] = onePassSignatureVersion
|
packetLength := 13
|
||||||
|
if ops.Version == 6 {
|
||||||
|
// v6 length 1+1+1+1+1+len(salt)+32+1 =
|
||||||
|
packetLength = 38 + len(ops.Salt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := serializeHeader(w, packetTypeOnePassSignature, packetLength); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf [8]byte
|
||||||
|
buf[0] = byte(ops.Version)
|
||||||
buf[1] = uint8(ops.SigType)
|
buf[1] = uint8(ops.SigType)
|
||||||
var ok bool
|
var ok bool
|
||||||
buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash)
|
buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash)
|
||||||
@ -60,14 +117,41 @@ func (ops *OnePassSignature) Serialize(w io.Writer) error {
|
|||||||
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
|
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
|
||||||
}
|
}
|
||||||
buf[3] = uint8(ops.PubKeyAlgo)
|
buf[3] = uint8(ops.PubKeyAlgo)
|
||||||
binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
|
|
||||||
if ops.IsLast {
|
|
||||||
buf[12] = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
|
_, err := w.Write(buf[:4])
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err := w.Write(buf[:])
|
|
||||||
|
if ops.Version == 6 {
|
||||||
|
// write salt for v6 signatures
|
||||||
|
_, err := w.Write([]byte{uint8(len(ops.Salt))})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = w.Write(ops.Salt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write fingerprint v6 signatures
|
||||||
|
_, err = w.Write(ops.KeyFingerprint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binary.BigEndian.PutUint64(buf[:8], ops.KeyId)
|
||||||
|
_, err := w.Write(buf[:8])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isLast := []byte{byte(0)}
|
||||||
|
if ops.IsLast {
|
||||||
|
isLast[0] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(isLast)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
3
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
generated
vendored
3
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/opaque.go
generated
vendored
@ -7,7 +7,6 @@ package packet
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
)
|
)
|
||||||
@ -26,7 +25,7 @@ type OpaquePacket struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (op *OpaquePacket) parse(r io.Reader) (err error) {
|
func (op *OpaquePacket) parse(r io.Reader) (err error) {
|
||||||
op.Contents, err = ioutil.ReadAll(r)
|
op.Contents, err = io.ReadAll(r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
154
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
generated
vendored
154
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet.go
generated
vendored
@ -311,12 +311,15 @@ const (
|
|||||||
packetTypePrivateSubkey packetType = 7
|
packetTypePrivateSubkey packetType = 7
|
||||||
packetTypeCompressed packetType = 8
|
packetTypeCompressed packetType = 8
|
||||||
packetTypeSymmetricallyEncrypted packetType = 9
|
packetTypeSymmetricallyEncrypted packetType = 9
|
||||||
|
packetTypeMarker packetType = 10
|
||||||
packetTypeLiteralData packetType = 11
|
packetTypeLiteralData packetType = 11
|
||||||
|
packetTypeTrust packetType = 12
|
||||||
packetTypeUserId packetType = 13
|
packetTypeUserId packetType = 13
|
||||||
packetTypePublicSubkey packetType = 14
|
packetTypePublicSubkey packetType = 14
|
||||||
packetTypeUserAttribute packetType = 17
|
packetTypeUserAttribute packetType = 17
|
||||||
packetTypeSymmetricallyEncryptedIntegrityProtected packetType = 18
|
packetTypeSymmetricallyEncryptedIntegrityProtected packetType = 18
|
||||||
packetTypeAEADEncrypted packetType = 20
|
packetTypeAEADEncrypted packetType = 20
|
||||||
|
packetPadding packetType = 21
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncryptedDataPacket holds encrypted data. It is currently implemented by
|
// EncryptedDataPacket holds encrypted data. It is currently implemented by
|
||||||
@ -328,7 +331,7 @@ type EncryptedDataPacket interface {
|
|||||||
// Read reads a single OpenPGP packet from the given io.Reader. If there is an
|
// Read reads a single OpenPGP packet from the given io.Reader. If there is an
|
||||||
// error parsing a packet, the whole packet is consumed from the input.
|
// error parsing a packet, the whole packet is consumed from the input.
|
||||||
func Read(r io.Reader) (p Packet, err error) {
|
func Read(r io.Reader) (p Packet, err error) {
|
||||||
tag, _, contents, err := readHeader(r)
|
tag, len, contents, err := readHeader(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -367,8 +370,93 @@ func Read(r io.Reader) (p Packet, err error) {
|
|||||||
p = se
|
p = se
|
||||||
case packetTypeAEADEncrypted:
|
case packetTypeAEADEncrypted:
|
||||||
p = new(AEADEncrypted)
|
p = new(AEADEncrypted)
|
||||||
default:
|
case packetPadding:
|
||||||
|
p = Padding(len)
|
||||||
|
case packetTypeMarker:
|
||||||
|
p = new(Marker)
|
||||||
|
case packetTypeTrust:
|
||||||
|
// Not implemented, just consume
|
||||||
err = errors.UnknownPacketTypeError(tag)
|
err = errors.UnknownPacketTypeError(tag)
|
||||||
|
default:
|
||||||
|
// Packet Tags from 0 to 39 are critical.
|
||||||
|
// Packet Tags from 40 to 63 are non-critical.
|
||||||
|
if tag < 40 {
|
||||||
|
err = errors.CriticalUnknownPacketTypeError(tag)
|
||||||
|
} else {
|
||||||
|
err = errors.UnknownPacketTypeError(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p != nil {
|
||||||
|
err = p.parse(contents)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
consumeAll(contents)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadWithCheck reads a single OpenPGP message packet from the given io.Reader. If there is an
|
||||||
|
// error parsing a packet, the whole packet is consumed from the input.
|
||||||
|
// ReadWithCheck additionally checks if the OpenPGP message packet sequence adheres
|
||||||
|
// to the packet composition rules in rfc4880, if not throws an error.
|
||||||
|
func ReadWithCheck(r io.Reader, sequence *SequenceVerifier) (p Packet, msgErr error, err error) {
|
||||||
|
tag, len, contents, err := readHeader(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch tag {
|
||||||
|
case packetTypeEncryptedKey:
|
||||||
|
msgErr = sequence.Next(ESKSymbol)
|
||||||
|
p = new(EncryptedKey)
|
||||||
|
case packetTypeSignature:
|
||||||
|
msgErr = sequence.Next(SigSymbol)
|
||||||
|
p = new(Signature)
|
||||||
|
case packetTypeSymmetricKeyEncrypted:
|
||||||
|
msgErr = sequence.Next(ESKSymbol)
|
||||||
|
p = new(SymmetricKeyEncrypted)
|
||||||
|
case packetTypeOnePassSignature:
|
||||||
|
msgErr = sequence.Next(OPSSymbol)
|
||||||
|
p = new(OnePassSignature)
|
||||||
|
case packetTypeCompressed:
|
||||||
|
msgErr = sequence.Next(CompSymbol)
|
||||||
|
p = new(Compressed)
|
||||||
|
case packetTypeSymmetricallyEncrypted:
|
||||||
|
msgErr = sequence.Next(EncSymbol)
|
||||||
|
p = new(SymmetricallyEncrypted)
|
||||||
|
case packetTypeLiteralData:
|
||||||
|
msgErr = sequence.Next(LDSymbol)
|
||||||
|
p = new(LiteralData)
|
||||||
|
case packetTypeSymmetricallyEncryptedIntegrityProtected:
|
||||||
|
msgErr = sequence.Next(EncSymbol)
|
||||||
|
se := new(SymmetricallyEncrypted)
|
||||||
|
se.IntegrityProtected = true
|
||||||
|
p = se
|
||||||
|
case packetTypeAEADEncrypted:
|
||||||
|
msgErr = sequence.Next(EncSymbol)
|
||||||
|
p = new(AEADEncrypted)
|
||||||
|
case packetPadding:
|
||||||
|
p = Padding(len)
|
||||||
|
case packetTypeMarker:
|
||||||
|
p = new(Marker)
|
||||||
|
case packetTypeTrust:
|
||||||
|
// Not implemented, just consume
|
||||||
|
err = errors.UnknownPacketTypeError(tag)
|
||||||
|
case packetTypePrivateKey,
|
||||||
|
packetTypePrivateSubkey,
|
||||||
|
packetTypePublicKey,
|
||||||
|
packetTypePublicSubkey,
|
||||||
|
packetTypeUserId,
|
||||||
|
packetTypeUserAttribute:
|
||||||
|
msgErr = sequence.Next(UnknownSymbol)
|
||||||
|
consumeAll(contents)
|
||||||
|
default:
|
||||||
|
// Packet Tags from 0 to 39 are critical.
|
||||||
|
// Packet Tags from 40 to 63 are non-critical.
|
||||||
|
if tag < 40 {
|
||||||
|
err = errors.CriticalUnknownPacketTypeError(tag)
|
||||||
|
} else {
|
||||||
|
err = errors.UnknownPacketTypeError(tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if p != nil {
|
if p != nil {
|
||||||
err = p.parse(contents)
|
err = p.parse(contents)
|
||||||
@ -385,17 +473,17 @@ type SignatureType uint8
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
SigTypeBinary SignatureType = 0x00
|
SigTypeBinary SignatureType = 0x00
|
||||||
SigTypeText = 0x01
|
SigTypeText SignatureType = 0x01
|
||||||
SigTypeGenericCert = 0x10
|
SigTypeGenericCert SignatureType = 0x10
|
||||||
SigTypePersonaCert = 0x11
|
SigTypePersonaCert SignatureType = 0x11
|
||||||
SigTypeCasualCert = 0x12
|
SigTypeCasualCert SignatureType = 0x12
|
||||||
SigTypePositiveCert = 0x13
|
SigTypePositiveCert SignatureType = 0x13
|
||||||
SigTypeSubkeyBinding = 0x18
|
SigTypeSubkeyBinding SignatureType = 0x18
|
||||||
SigTypePrimaryKeyBinding = 0x19
|
SigTypePrimaryKeyBinding SignatureType = 0x19
|
||||||
SigTypeDirectSignature = 0x1F
|
SigTypeDirectSignature SignatureType = 0x1F
|
||||||
SigTypeKeyRevocation = 0x20
|
SigTypeKeyRevocation SignatureType = 0x20
|
||||||
SigTypeSubkeyRevocation = 0x28
|
SigTypeSubkeyRevocation SignatureType = 0x28
|
||||||
SigTypeCertificationRevocation = 0x30
|
SigTypeCertificationRevocation SignatureType = 0x30
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicKeyAlgorithm represents the different public key system specified for
|
// PublicKeyAlgorithm represents the different public key system specified for
|
||||||
@ -412,6 +500,11 @@ const (
|
|||||||
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
|
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
|
||||||
// https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt
|
// https://www.ietf.org/archive/id/draft-koch-eddsa-for-openpgp-04.txt
|
||||||
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
|
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
|
||||||
|
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh
|
||||||
|
PubKeyAlgoX25519 PublicKeyAlgorithm = 25
|
||||||
|
PubKeyAlgoX448 PublicKeyAlgorithm = 26
|
||||||
|
PubKeyAlgoEd25519 PublicKeyAlgorithm = 27
|
||||||
|
PubKeyAlgoEd448 PublicKeyAlgorithm = 28
|
||||||
|
|
||||||
// Deprecated in RFC 4880, Section 13.5. Use key flags instead.
|
// Deprecated in RFC 4880, Section 13.5. Use key flags instead.
|
||||||
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
|
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
|
||||||
@ -422,7 +515,7 @@ const (
|
|||||||
// key of the given type.
|
// key of the given type.
|
||||||
func (pka PublicKeyAlgorithm) CanEncrypt() bool {
|
func (pka PublicKeyAlgorithm) CanEncrypt() bool {
|
||||||
switch pka {
|
switch pka {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH, PubKeyAlgoX25519, PubKeyAlgoX448:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -432,7 +525,7 @@ func (pka PublicKeyAlgorithm) CanEncrypt() bool {
|
|||||||
// sign a message.
|
// sign a message.
|
||||||
func (pka PublicKeyAlgorithm) CanSign() bool {
|
func (pka PublicKeyAlgorithm) CanSign() bool {
|
||||||
switch pka {
|
switch pka {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA:
|
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA, PubKeyAlgoEd25519, PubKeyAlgoEd448:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -512,6 +605,11 @@ func (mode AEADMode) TagLength() int {
|
|||||||
return algorithm.AEADMode(mode).TagLength()
|
return algorithm.AEADMode(mode).TagLength()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSupported returns true if the aead mode is supported from the library
|
||||||
|
func (mode AEADMode) IsSupported() bool {
|
||||||
|
return algorithm.AEADMode(mode).TagLength() > 0
|
||||||
|
}
|
||||||
|
|
||||||
// new returns a fresh instance of the given mode.
|
// new returns a fresh instance of the given mode.
|
||||||
func (mode AEADMode) new(block cipher.Block) cipher.AEAD {
|
func (mode AEADMode) new(block cipher.Block) cipher.AEAD {
|
||||||
return algorithm.AEADMode(mode).New(block)
|
return algorithm.AEADMode(mode).New(block)
|
||||||
@ -526,8 +624,17 @@ const (
|
|||||||
KeySuperseded ReasonForRevocation = 1
|
KeySuperseded ReasonForRevocation = 1
|
||||||
KeyCompromised ReasonForRevocation = 2
|
KeyCompromised ReasonForRevocation = 2
|
||||||
KeyRetired ReasonForRevocation = 3
|
KeyRetired ReasonForRevocation = 3
|
||||||
|
UserIDNotValid ReasonForRevocation = 32
|
||||||
|
Unknown ReasonForRevocation = 200
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewReasonForRevocation(value byte) ReasonForRevocation {
|
||||||
|
if value < 4 || value == 32 {
|
||||||
|
return ReasonForRevocation(value)
|
||||||
|
}
|
||||||
|
return Unknown
|
||||||
|
}
|
||||||
|
|
||||||
// Curve is a mapping to supported ECC curves for key generation.
|
// Curve is a mapping to supported ECC curves for key generation.
|
||||||
// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-06.html#name-curve-specific-wire-formats
|
// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-06.html#name-curve-specific-wire-formats
|
||||||
type Curve string
|
type Curve string
|
||||||
@ -549,3 +656,20 @@ type TrustLevel uint8
|
|||||||
|
|
||||||
// TrustAmount represents a trust amount per RFC4880 5.2.3.13
|
// TrustAmount represents a trust amount per RFC4880 5.2.3.13
|
||||||
type TrustAmount uint8
|
type TrustAmount uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// versionSize is the length in bytes of the version value.
|
||||||
|
versionSize = 1
|
||||||
|
// algorithmSize is the length in bytes of the key algorithm value.
|
||||||
|
algorithmSize = 1
|
||||||
|
// keyVersionSize is the length in bytes of the key version value
|
||||||
|
keyVersionSize = 1
|
||||||
|
// keyIdSize is the length in bytes of the key identifier value.
|
||||||
|
keyIdSize = 8
|
||||||
|
// timestampSize is the length in bytes of encoded timestamps.
|
||||||
|
timestampSize = 4
|
||||||
|
// fingerprintSizeV6 is the length in bytes of the key fingerprint in v6.
|
||||||
|
fingerprintSizeV6 = 32
|
||||||
|
// fingerprintSize is the length in bytes of the key fingerprint.
|
||||||
|
fingerprintSize = 20
|
||||||
|
)
|
||||||
|
222
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_sequence.go
generated
vendored
Normal file
222
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_sequence.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
package packet
|
||||||
|
|
||||||
|
// This file implements the pushdown automata (PDA) from PGPainless (Paul Schaub)
|
||||||
|
// to verify pgp packet sequences. See Paul's blogpost for more details:
|
||||||
|
// https://blog.jabberhead.tk/2022/10/26/implementing-packet-sequence-validation-using-pushdown-automata/
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewErrMalformedMessage(from State, input InputSymbol, stackSymbol StackSymbol) errors.ErrMalformedMessage {
|
||||||
|
return errors.ErrMalformedMessage(fmt.Sprintf("state %d, input symbol %d, stack symbol %d ", from, input, stackSymbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputSymbol defines the input alphabet of the PDA
|
||||||
|
type InputSymbol uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
LDSymbol InputSymbol = iota
|
||||||
|
SigSymbol
|
||||||
|
OPSSymbol
|
||||||
|
CompSymbol
|
||||||
|
ESKSymbol
|
||||||
|
EncSymbol
|
||||||
|
EOSSymbol
|
||||||
|
UnknownSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
// StackSymbol defines the stack alphabet of the PDA
|
||||||
|
type StackSymbol int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
MsgStackSymbol StackSymbol = iota
|
||||||
|
OpsStackSymbol
|
||||||
|
KeyStackSymbol
|
||||||
|
EndStackSymbol
|
||||||
|
EmptyStackSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
// State defines the states of the PDA
|
||||||
|
type State int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
OpenPGPMessage State = iota
|
||||||
|
ESKMessage
|
||||||
|
LiteralMessage
|
||||||
|
CompressedMessage
|
||||||
|
EncryptedMessage
|
||||||
|
ValidMessage
|
||||||
|
)
|
||||||
|
|
||||||
|
// transition represents a state transition in the PDA
|
||||||
|
type transition func(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error)
|
||||||
|
|
||||||
|
// SequenceVerifier is a pushdown automata to verify
|
||||||
|
// PGP messages packet sequences according to rfc4880.
|
||||||
|
type SequenceVerifier struct {
|
||||||
|
stack []StackSymbol
|
||||||
|
state State
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next performs a state transition with the given input symbol.
|
||||||
|
// If the transition fails a ErrMalformedMessage is returned.
|
||||||
|
func (sv *SequenceVerifier) Next(input InputSymbol) error {
|
||||||
|
for {
|
||||||
|
stackSymbol := sv.popStack()
|
||||||
|
transitionFunc := getTransition(sv.state)
|
||||||
|
nextState, newStackSymbols, redo, err := transitionFunc(input, stackSymbol)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if redo {
|
||||||
|
sv.pushStack(stackSymbol)
|
||||||
|
}
|
||||||
|
for _, newStackSymbol := range newStackSymbols {
|
||||||
|
sv.pushStack(newStackSymbol)
|
||||||
|
}
|
||||||
|
sv.state = nextState
|
||||||
|
if !redo {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid returns true if RDA is in a valid state.
|
||||||
|
func (sv *SequenceVerifier) Valid() bool {
|
||||||
|
return sv.state == ValidMessage && len(sv.stack) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sv *SequenceVerifier) AssertValid() error {
|
||||||
|
if !sv.Valid() {
|
||||||
|
return errors.ErrMalformedMessage("invalid message")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSequenceVerifier() *SequenceVerifier {
|
||||||
|
return &SequenceVerifier{
|
||||||
|
stack: []StackSymbol{EndStackSymbol, MsgStackSymbol},
|
||||||
|
state: OpenPGPMessage,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sv *SequenceVerifier) popStack() StackSymbol {
|
||||||
|
if len(sv.stack) == 0 {
|
||||||
|
return EmptyStackSymbol
|
||||||
|
}
|
||||||
|
elemIndex := len(sv.stack) - 1
|
||||||
|
stackSymbol := sv.stack[elemIndex]
|
||||||
|
sv.stack = sv.stack[:elemIndex]
|
||||||
|
return stackSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sv *SequenceVerifier) pushStack(stackSymbol StackSymbol) {
|
||||||
|
sv.stack = append(sv.stack, stackSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransition(from State) transition {
|
||||||
|
switch from {
|
||||||
|
case OpenPGPMessage:
|
||||||
|
return fromOpenPGPMessage
|
||||||
|
case LiteralMessage:
|
||||||
|
return fromLiteralMessage
|
||||||
|
case CompressedMessage:
|
||||||
|
return fromCompressedMessage
|
||||||
|
case EncryptedMessage:
|
||||||
|
return fromEncryptedMessage
|
||||||
|
case ESKMessage:
|
||||||
|
return fromESKMessage
|
||||||
|
case ValidMessage:
|
||||||
|
return fromValidMessage
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromOpenPGPMessage is the transition for the state OpenPGPMessage.
|
||||||
|
func fromOpenPGPMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
|
||||||
|
if stackSymbol != MsgStackSymbol {
|
||||||
|
return 0, nil, false, NewErrMalformedMessage(OpenPGPMessage, input, stackSymbol)
|
||||||
|
}
|
||||||
|
switch input {
|
||||||
|
case LDSymbol:
|
||||||
|
return LiteralMessage, nil, false, nil
|
||||||
|
case SigSymbol:
|
||||||
|
return OpenPGPMessage, []StackSymbol{MsgStackSymbol}, false, nil
|
||||||
|
case OPSSymbol:
|
||||||
|
return OpenPGPMessage, []StackSymbol{OpsStackSymbol, MsgStackSymbol}, false, nil
|
||||||
|
case CompSymbol:
|
||||||
|
return CompressedMessage, nil, false, nil
|
||||||
|
case ESKSymbol:
|
||||||
|
return ESKMessage, []StackSymbol{KeyStackSymbol}, false, nil
|
||||||
|
case EncSymbol:
|
||||||
|
return EncryptedMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
return 0, nil, false, NewErrMalformedMessage(OpenPGPMessage, input, stackSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromESKMessage is the transition for the state ESKMessage.
|
||||||
|
func fromESKMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
|
||||||
|
if stackSymbol != KeyStackSymbol {
|
||||||
|
return 0, nil, false, NewErrMalformedMessage(ESKMessage, input, stackSymbol)
|
||||||
|
}
|
||||||
|
switch input {
|
||||||
|
case ESKSymbol:
|
||||||
|
return ESKMessage, []StackSymbol{KeyStackSymbol}, false, nil
|
||||||
|
case EncSymbol:
|
||||||
|
return EncryptedMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
return 0, nil, false, NewErrMalformedMessage(ESKMessage, input, stackSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromLiteralMessage is the transition for the state LiteralMessage.
|
||||||
|
func fromLiteralMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
|
||||||
|
switch input {
|
||||||
|
case SigSymbol:
|
||||||
|
if stackSymbol == OpsStackSymbol {
|
||||||
|
return LiteralMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
case EOSSymbol:
|
||||||
|
if stackSymbol == EndStackSymbol {
|
||||||
|
return ValidMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, nil, false, NewErrMalformedMessage(LiteralMessage, input, stackSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromLiteralMessage is the transition for the state CompressedMessage.
|
||||||
|
func fromCompressedMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
|
||||||
|
switch input {
|
||||||
|
case SigSymbol:
|
||||||
|
if stackSymbol == OpsStackSymbol {
|
||||||
|
return CompressedMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
case EOSSymbol:
|
||||||
|
if stackSymbol == EndStackSymbol {
|
||||||
|
return ValidMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OpenPGPMessage, []StackSymbol{MsgStackSymbol}, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromEncryptedMessage is the transition for the state EncryptedMessage.
|
||||||
|
func fromEncryptedMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
|
||||||
|
switch input {
|
||||||
|
case SigSymbol:
|
||||||
|
if stackSymbol == OpsStackSymbol {
|
||||||
|
return EncryptedMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
case EOSSymbol:
|
||||||
|
if stackSymbol == EndStackSymbol {
|
||||||
|
return ValidMessage, nil, false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OpenPGPMessage, []StackSymbol{MsgStackSymbol}, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromValidMessage is the transition for the state ValidMessage.
|
||||||
|
func fromValidMessage(input InputSymbol, stackSymbol StackSymbol) (State, []StackSymbol, bool, error) {
|
||||||
|
return 0, nil, false, NewErrMalformedMessage(ValidMessage, input, stackSymbol)
|
||||||
|
}
|
24
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_unsupported.go
generated
vendored
Normal file
24
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/packet_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package packet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnsupportedPackage represents a OpenPGP packet with a known packet type
|
||||||
|
// but with unsupported content.
|
||||||
|
type UnsupportedPacket struct {
|
||||||
|
IncompletePacket Packet
|
||||||
|
Error errors.UnsupportedError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the Packet interface
|
||||||
|
func (up *UnsupportedPacket) parse(read io.Reader) error {
|
||||||
|
err := up.IncompletePacket.parse(read)
|
||||||
|
if castedErr, ok := err.(errors.UnsupportedError); ok {
|
||||||
|
up.Error = castedErr
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
26
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/padding.go
generated
vendored
Normal file
26
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/padding.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package packet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Padding type represents a Padding Packet (Tag 21).
|
||||||
|
// The padding type is represented by the length of its padding.
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-padding-packet-tag-21
|
||||||
|
type Padding int
|
||||||
|
|
||||||
|
// parse just ignores the padding content.
|
||||||
|
func (pad Padding) parse(reader io.Reader) error {
|
||||||
|
_, err := io.CopyN(io.Discard, reader, int64(pad))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializePadding writes the padding to writer.
|
||||||
|
func (pad Padding) SerializePadding(writer io.Writer, rand io.Reader) error {
|
||||||
|
err := serializeHeader(writer, packetPadding, int(pad))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.CopyN(writer, rand, int64(pad))
|
||||||
|
return err
|
||||||
|
}
|
540
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
generated
vendored
540
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/private_key.go
generated
vendored
@ -9,22 +9,28 @@ import (
|
|||||||
"crypto"
|
"crypto"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/subtle"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/ecdh"
|
"github.com/ProtonMail/go-crypto/openpgp/ecdh"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
|
"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/ed25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/ed448"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
|
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x448"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
|
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
|
||||||
@ -35,14 +41,14 @@ type PrivateKey struct {
|
|||||||
encryptedData []byte
|
encryptedData []byte
|
||||||
cipher CipherFunction
|
cipher CipherFunction
|
||||||
s2k func(out, in []byte)
|
s2k func(out, in []byte)
|
||||||
// An *{rsa|dsa|elgamal|ecdh|ecdsa|ed25519}.PrivateKey or
|
aead AEADMode // only relevant if S2KAEAD is enabled
|
||||||
|
// An *{rsa|dsa|elgamal|ecdh|ecdsa|ed25519|ed448}.PrivateKey or
|
||||||
// crypto.Signer/crypto.Decrypter (Decryptor RSA only).
|
// crypto.Signer/crypto.Decrypter (Decryptor RSA only).
|
||||||
PrivateKey interface{}
|
PrivateKey interface{}
|
||||||
sha1Checksum bool
|
iv []byte
|
||||||
iv []byte
|
|
||||||
|
|
||||||
// Type of encryption of the S2K packet
|
// Type of encryption of the S2K packet
|
||||||
// Allowed values are 0 (Not encrypted), 254 (SHA1), or
|
// Allowed values are 0 (Not encrypted), 253 (AEAD), 254 (SHA1), or
|
||||||
// 255 (2-byte checksum)
|
// 255 (2-byte checksum)
|
||||||
s2kType S2KType
|
s2kType S2KType
|
||||||
// Full parameters of the S2K packet
|
// Full parameters of the S2K packet
|
||||||
@ -55,6 +61,8 @@ type S2KType uint8
|
|||||||
const (
|
const (
|
||||||
// S2KNON unencrypt
|
// S2KNON unencrypt
|
||||||
S2KNON S2KType = 0
|
S2KNON S2KType = 0
|
||||||
|
// S2KAEAD use authenticated encryption
|
||||||
|
S2KAEAD S2KType = 253
|
||||||
// S2KSHA1 sha1 sum check
|
// S2KSHA1 sha1 sum check
|
||||||
S2KSHA1 S2KType = 254
|
S2KSHA1 S2KType = 254
|
||||||
// S2KCHECKSUM sum check
|
// S2KCHECKSUM sum check
|
||||||
@ -103,6 +111,34 @@ func NewECDHPrivateKey(creationTime time.Time, priv *ecdh.PrivateKey) *PrivateKe
|
|||||||
return pk
|
return pk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewX25519PrivateKey(creationTime time.Time, priv *x25519.PrivateKey) *PrivateKey {
|
||||||
|
pk := new(PrivateKey)
|
||||||
|
pk.PublicKey = *NewX25519PublicKey(creationTime, &priv.PublicKey)
|
||||||
|
pk.PrivateKey = priv
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewX448PrivateKey(creationTime time.Time, priv *x448.PrivateKey) *PrivateKey {
|
||||||
|
pk := new(PrivateKey)
|
||||||
|
pk.PublicKey = *NewX448PublicKey(creationTime, &priv.PublicKey)
|
||||||
|
pk.PrivateKey = priv
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEd25519PrivateKey(creationTime time.Time, priv *ed25519.PrivateKey) *PrivateKey {
|
||||||
|
pk := new(PrivateKey)
|
||||||
|
pk.PublicKey = *NewEd25519PublicKey(creationTime, &priv.PublicKey)
|
||||||
|
pk.PrivateKey = priv
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEd448PrivateKey(creationTime time.Time, priv *ed448.PrivateKey) *PrivateKey {
|
||||||
|
pk := new(PrivateKey)
|
||||||
|
pk.PublicKey = *NewEd448PublicKey(creationTime, &priv.PublicKey)
|
||||||
|
pk.PrivateKey = priv
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
|
// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that
|
||||||
// implements RSA, ECDSA or EdDSA.
|
// implements RSA, ECDSA or EdDSA.
|
||||||
func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey {
|
func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey {
|
||||||
@ -122,6 +158,14 @@ func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey
|
|||||||
pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
|
pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
|
||||||
case eddsa.PrivateKey:
|
case eddsa.PrivateKey:
|
||||||
pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
|
pk.PublicKey = *NewEdDSAPublicKey(creationTime, &pubkey.PublicKey)
|
||||||
|
case *ed25519.PrivateKey:
|
||||||
|
pk.PublicKey = *NewEd25519PublicKey(creationTime, &pubkey.PublicKey)
|
||||||
|
case ed25519.PrivateKey:
|
||||||
|
pk.PublicKey = *NewEd25519PublicKey(creationTime, &pubkey.PublicKey)
|
||||||
|
case *ed448.PrivateKey:
|
||||||
|
pk.PublicKey = *NewEd448PublicKey(creationTime, &pubkey.PublicKey)
|
||||||
|
case ed448.PrivateKey:
|
||||||
|
pk.PublicKey = *NewEd448PublicKey(creationTime, &pubkey.PublicKey)
|
||||||
default:
|
default:
|
||||||
panic("openpgp: unknown signer type in NewSignerPrivateKey")
|
panic("openpgp: unknown signer type in NewSignerPrivateKey")
|
||||||
}
|
}
|
||||||
@ -129,7 +173,7 @@ func NewSignerPrivateKey(creationTime time.Time, signer interface{}) *PrivateKey
|
|||||||
return pk
|
return pk
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh}.PrivateKey.
|
// NewDecrypterPrivateKey creates a PrivateKey from a *{rsa|elgamal|ecdh|x25519|x448}.PrivateKey.
|
||||||
func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *PrivateKey {
|
func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *PrivateKey {
|
||||||
pk := new(PrivateKey)
|
pk := new(PrivateKey)
|
||||||
switch priv := decrypter.(type) {
|
switch priv := decrypter.(type) {
|
||||||
@ -139,6 +183,10 @@ func NewDecrypterPrivateKey(creationTime time.Time, decrypter interface{}) *Priv
|
|||||||
pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
|
pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey)
|
||||||
case *ecdh.PrivateKey:
|
case *ecdh.PrivateKey:
|
||||||
pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey)
|
pk.PublicKey = *NewECDHPublicKey(creationTime, &priv.PublicKey)
|
||||||
|
case *x25519.PrivateKey:
|
||||||
|
pk.PublicKey = *NewX25519PublicKey(creationTime, &priv.PublicKey)
|
||||||
|
case *x448.PrivateKey:
|
||||||
|
pk.PublicKey = *NewX448PublicKey(creationTime, &priv.PublicKey)
|
||||||
default:
|
default:
|
||||||
panic("openpgp: unknown decrypter type in NewDecrypterPrivateKey")
|
panic("openpgp: unknown decrypter type in NewDecrypterPrivateKey")
|
||||||
}
|
}
|
||||||
@ -152,6 +200,11 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
v5 := pk.PublicKey.Version == 5
|
v5 := pk.PublicKey.Version == 5
|
||||||
|
v6 := pk.PublicKey.Version == 6
|
||||||
|
|
||||||
|
if V5Disabled && v5 {
|
||||||
|
return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
|
||||||
|
}
|
||||||
|
|
||||||
var buf [1]byte
|
var buf [1]byte
|
||||||
_, err = readFull(r, buf[:])
|
_, err = readFull(r, buf[:])
|
||||||
@ -160,7 +213,7 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
pk.s2kType = S2KType(buf[0])
|
pk.s2kType = S2KType(buf[0])
|
||||||
var optCount [1]byte
|
var optCount [1]byte
|
||||||
if v5 {
|
if v5 || (v6 && pk.s2kType != S2KNON) {
|
||||||
if _, err = readFull(r, optCount[:]); err != nil {
|
if _, err = readFull(r, optCount[:]); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -170,9 +223,9 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
case S2KNON:
|
case S2KNON:
|
||||||
pk.s2k = nil
|
pk.s2k = nil
|
||||||
pk.Encrypted = false
|
pk.Encrypted = false
|
||||||
case S2KSHA1, S2KCHECKSUM:
|
case S2KSHA1, S2KCHECKSUM, S2KAEAD:
|
||||||
if v5 && pk.s2kType == S2KCHECKSUM {
|
if (v5 || v6) && pk.s2kType == S2KCHECKSUM {
|
||||||
return errors.StructuralError("wrong s2k identifier for version 5")
|
return errors.StructuralError(fmt.Sprintf("wrong s2k identifier for version %d", pk.Version))
|
||||||
}
|
}
|
||||||
_, err = readFull(r, buf[:])
|
_, err = readFull(r, buf[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -182,6 +235,29 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
if pk.cipher != 0 && !pk.cipher.IsSupported() {
|
if pk.cipher != 0 && !pk.cipher.IsSupported() {
|
||||||
return errors.UnsupportedError("unsupported cipher function in private key")
|
return errors.UnsupportedError("unsupported cipher function in private key")
|
||||||
}
|
}
|
||||||
|
// [Optional] If string-to-key usage octet was 253,
|
||||||
|
// a one-octet AEAD algorithm.
|
||||||
|
if pk.s2kType == S2KAEAD {
|
||||||
|
_, err = readFull(r, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pk.aead = AEADMode(buf[0])
|
||||||
|
if !pk.aead.IsSupported() {
|
||||||
|
return errors.UnsupportedError("unsupported aead mode in private key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [Optional] Only for a version 6 packet,
|
||||||
|
// and if string-to-key usage octet was 255, 254, or 253,
|
||||||
|
// an one-octet count of the following field.
|
||||||
|
if v6 {
|
||||||
|
_, err = readFull(r, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pk.s2kParams, err = s2k.ParseIntoParams(r)
|
pk.s2kParams, err = s2k.ParseIntoParams(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -189,28 +265,43 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
if pk.s2kParams.Dummy() {
|
if pk.s2kParams.Dummy() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if pk.s2kParams.Mode() == s2k.Argon2S2K && pk.s2kType != S2KAEAD {
|
||||||
|
return errors.StructuralError("using Argon2 S2K without AEAD is not allowed")
|
||||||
|
}
|
||||||
|
if pk.s2kParams.Mode() == s2k.SimpleS2K && pk.Version == 6 {
|
||||||
|
return errors.StructuralError("using Simple S2K with version 6 keys is not allowed")
|
||||||
|
}
|
||||||
pk.s2k, err = pk.s2kParams.Function()
|
pk.s2k, err = pk.s2kParams.Function()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pk.Encrypted = true
|
pk.Encrypted = true
|
||||||
if pk.s2kType == S2KSHA1 {
|
|
||||||
pk.sha1Checksum = true
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return errors.UnsupportedError("deprecated s2k function in private key")
|
return errors.UnsupportedError("deprecated s2k function in private key")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pk.Encrypted {
|
if pk.Encrypted {
|
||||||
blockSize := pk.cipher.blockSize()
|
var ivSize int
|
||||||
if blockSize == 0 {
|
// If the S2K usage octet was 253, the IV is of the size expected by the AEAD mode,
|
||||||
|
// unless it's a version 5 key, in which case it's the size of the symmetric cipher's block size.
|
||||||
|
// For all other S2K modes, it's always the block size.
|
||||||
|
if !v5 && pk.s2kType == S2KAEAD {
|
||||||
|
ivSize = pk.aead.IvLength()
|
||||||
|
} else {
|
||||||
|
ivSize = pk.cipher.blockSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ivSize == 0 {
|
||||||
return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
|
return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
|
||||||
}
|
}
|
||||||
pk.iv = make([]byte, blockSize)
|
pk.iv = make([]byte, ivSize)
|
||||||
_, err = readFull(r, pk.iv)
|
_, err = readFull(r, pk.iv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if v5 && pk.s2kType == S2KAEAD {
|
||||||
|
pk.iv = pk.iv[:pk.aead.IvLength()]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var privateKeyData []byte
|
var privateKeyData []byte
|
||||||
@ -230,7 +321,7 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
privateKeyData, err = ioutil.ReadAll(r)
|
privateKeyData, err = io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -239,16 +330,22 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
|
|||||||
if len(privateKeyData) < 2 {
|
if len(privateKeyData) < 2 {
|
||||||
return errors.StructuralError("truncated private key data")
|
return errors.StructuralError("truncated private key data")
|
||||||
}
|
}
|
||||||
var sum uint16
|
if pk.Version != 6 {
|
||||||
for i := 0; i < len(privateKeyData)-2; i++ {
|
// checksum
|
||||||
sum += uint16(privateKeyData[i])
|
var sum uint16
|
||||||
|
for i := 0; i < len(privateKeyData)-2; i++ {
|
||||||
|
sum += uint16(privateKeyData[i])
|
||||||
|
}
|
||||||
|
if privateKeyData[len(privateKeyData)-2] != uint8(sum>>8) ||
|
||||||
|
privateKeyData[len(privateKeyData)-1] != uint8(sum) {
|
||||||
|
return errors.StructuralError("private key checksum failure")
|
||||||
|
}
|
||||||
|
privateKeyData = privateKeyData[:len(privateKeyData)-2]
|
||||||
|
return pk.parsePrivateKey(privateKeyData)
|
||||||
|
} else {
|
||||||
|
// No checksum
|
||||||
|
return pk.parsePrivateKey(privateKeyData)
|
||||||
}
|
}
|
||||||
if privateKeyData[len(privateKeyData)-2] != uint8(sum>>8) ||
|
|
||||||
privateKeyData[len(privateKeyData)-1] != uint8(sum) {
|
|
||||||
return errors.StructuralError("private key checksum failure")
|
|
||||||
}
|
|
||||||
privateKeyData = privateKeyData[:len(privateKeyData)-2]
|
|
||||||
return pk.parsePrivateKey(privateKeyData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pk.encryptedData = privateKeyData
|
pk.encryptedData = privateKeyData
|
||||||
@ -280,18 +377,59 @@ func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
|
|||||||
|
|
||||||
optional := bytes.NewBuffer(nil)
|
optional := bytes.NewBuffer(nil)
|
||||||
if pk.Encrypted || pk.Dummy() {
|
if pk.Encrypted || pk.Dummy() {
|
||||||
optional.Write([]byte{uint8(pk.cipher)})
|
// [Optional] If string-to-key usage octet was 255, 254, or 253,
|
||||||
if err := pk.s2kParams.Serialize(optional); err != nil {
|
// a one-octet symmetric encryption algorithm.
|
||||||
|
if _, err = optional.Write([]byte{uint8(pk.cipher)}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// [Optional] If string-to-key usage octet was 253,
|
||||||
|
// a one-octet AEAD algorithm.
|
||||||
|
if pk.s2kType == S2KAEAD {
|
||||||
|
if _, err = optional.Write([]byte{uint8(pk.aead)}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s2kBuffer := bytes.NewBuffer(nil)
|
||||||
|
if err := pk.s2kParams.Serialize(s2kBuffer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// [Optional] Only for a version 6 packet, and if string-to-key
|
||||||
|
// usage octet was 255, 254, or 253, an one-octet
|
||||||
|
// count of the following field.
|
||||||
|
if pk.Version == 6 {
|
||||||
|
if _, err = optional.Write([]byte{uint8(s2kBuffer.Len())}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// [Optional] If string-to-key usage octet was 255, 254, or 253,
|
||||||
|
// a string-to-key (S2K) specifier. The length of the string-to-key specifier
|
||||||
|
// depends on its type
|
||||||
|
if _, err = io.Copy(optional, s2kBuffer); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IV
|
||||||
if pk.Encrypted {
|
if pk.Encrypted {
|
||||||
optional.Write(pk.iv)
|
if _, err = optional.Write(pk.iv); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pk.Version == 5 && pk.s2kType == S2KAEAD {
|
||||||
|
// Add padding for version 5
|
||||||
|
padding := make([]byte, pk.cipher.blockSize()-len(pk.iv))
|
||||||
|
if _, err = optional.Write(padding); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pk.Version == 5 {
|
if pk.Version == 5 || (pk.Version == 6 && pk.s2kType != S2KNON) {
|
||||||
contents.Write([]byte{uint8(optional.Len())})
|
contents.Write([]byte{uint8(optional.Len())})
|
||||||
}
|
}
|
||||||
io.Copy(contents, optional)
|
|
||||||
|
if _, err := io.Copy(contents, optional); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !pk.Dummy() {
|
if !pk.Dummy() {
|
||||||
l := 0
|
l := 0
|
||||||
@ -303,8 +441,10 @@ func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l = buf.Len()
|
l = buf.Len()
|
||||||
checksum := mod64kHash(buf.Bytes())
|
if pk.Version != 6 {
|
||||||
buf.Write([]byte{byte(checksum >> 8), byte(checksum)})
|
checksum := mod64kHash(buf.Bytes())
|
||||||
|
buf.Write([]byte{byte(checksum >> 8), byte(checksum)})
|
||||||
|
}
|
||||||
priv = buf.Bytes()
|
priv = buf.Bytes()
|
||||||
} else {
|
} else {
|
||||||
priv, l = pk.encryptedData, len(pk.encryptedData)
|
priv, l = pk.encryptedData, len(pk.encryptedData)
|
||||||
@ -370,6 +510,26 @@ func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func serializeX25519PrivateKey(w io.Writer, priv *x25519.PrivateKey) error {
|
||||||
|
_, err := w.Write(priv.Secret)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeX448PrivateKey(w io.Writer, priv *x448.PrivateKey) error {
|
||||||
|
_, err := w.Write(priv.Secret)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeEd25519PrivateKey(w io.Writer, priv *ed25519.PrivateKey) error {
|
||||||
|
_, err := w.Write(priv.MarshalByteSecret())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeEd448PrivateKey(w io.Writer, priv *ed448.PrivateKey) error {
|
||||||
|
_, err := w.Write(priv.MarshalByteSecret())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// decrypt decrypts an encrypted private key using a decryption key.
|
// decrypt decrypts an encrypted private key using a decryption key.
|
||||||
func (pk *PrivateKey) decrypt(decryptionKey []byte) error {
|
func (pk *PrivateKey) decrypt(decryptionKey []byte) error {
|
||||||
if pk.Dummy() {
|
if pk.Dummy() {
|
||||||
@ -378,37 +538,51 @@ func (pk *PrivateKey) decrypt(decryptionKey []byte) error {
|
|||||||
if !pk.Encrypted {
|
if !pk.Encrypted {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
block := pk.cipher.new(decryptionKey)
|
block := pk.cipher.new(decryptionKey)
|
||||||
cfb := cipher.NewCFBDecrypter(block, pk.iv)
|
var data []byte
|
||||||
|
switch pk.s2kType {
|
||||||
data := make([]byte, len(pk.encryptedData))
|
case S2KAEAD:
|
||||||
cfb.XORKeyStream(data, pk.encryptedData)
|
aead := pk.aead.new(block)
|
||||||
|
additionalData, err := pk.additionalData()
|
||||||
if pk.sha1Checksum {
|
if err != nil {
|
||||||
if len(data) < sha1.Size {
|
return err
|
||||||
return errors.StructuralError("truncated private key data")
|
|
||||||
}
|
}
|
||||||
h := sha1.New()
|
// Decrypt the encrypted key material with aead
|
||||||
h.Write(data[:len(data)-sha1.Size])
|
data, err = aead.Open(nil, pk.iv, pk.encryptedData, additionalData)
|
||||||
sum := h.Sum(nil)
|
if err != nil {
|
||||||
if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
|
return err
|
||||||
return errors.StructuralError("private key checksum failure")
|
|
||||||
}
|
}
|
||||||
data = data[:len(data)-sha1.Size]
|
case S2KSHA1, S2KCHECKSUM:
|
||||||
} else {
|
cfb := cipher.NewCFBDecrypter(block, pk.iv)
|
||||||
if len(data) < 2 {
|
data = make([]byte, len(pk.encryptedData))
|
||||||
return errors.StructuralError("truncated private key data")
|
cfb.XORKeyStream(data, pk.encryptedData)
|
||||||
|
if pk.s2kType == S2KSHA1 {
|
||||||
|
if len(data) < sha1.Size {
|
||||||
|
return errors.StructuralError("truncated private key data")
|
||||||
|
}
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write(data[:len(data)-sha1.Size])
|
||||||
|
sum := h.Sum(nil)
|
||||||
|
if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
|
||||||
|
return errors.StructuralError("private key checksum failure")
|
||||||
|
}
|
||||||
|
data = data[:len(data)-sha1.Size]
|
||||||
|
} else {
|
||||||
|
if len(data) < 2 {
|
||||||
|
return errors.StructuralError("truncated private key data")
|
||||||
|
}
|
||||||
|
var sum uint16
|
||||||
|
for i := 0; i < len(data)-2; i++ {
|
||||||
|
sum += uint16(data[i])
|
||||||
|
}
|
||||||
|
if data[len(data)-2] != uint8(sum>>8) ||
|
||||||
|
data[len(data)-1] != uint8(sum) {
|
||||||
|
return errors.StructuralError("private key checksum failure")
|
||||||
|
}
|
||||||
|
data = data[:len(data)-2]
|
||||||
}
|
}
|
||||||
var sum uint16
|
default:
|
||||||
for i := 0; i < len(data)-2; i++ {
|
return errors.InvalidArgumentError("invalid s2k type")
|
||||||
sum += uint16(data[i])
|
|
||||||
}
|
|
||||||
if data[len(data)-2] != uint8(sum>>8) ||
|
|
||||||
data[len(data)-1] != uint8(sum) {
|
|
||||||
return errors.StructuralError("private key checksum failure")
|
|
||||||
}
|
|
||||||
data = data[:len(data)-2]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pk.parsePrivateKey(data)
|
err := pk.parsePrivateKey(data)
|
||||||
@ -424,7 +598,6 @@ func (pk *PrivateKey) decrypt(decryptionKey []byte) error {
|
|||||||
pk.s2k = nil
|
pk.s2k = nil
|
||||||
pk.Encrypted = false
|
pk.Encrypted = false
|
||||||
pk.encryptedData = nil
|
pk.encryptedData = nil
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,6 +613,9 @@ func (pk *PrivateKey) decryptWithCache(passphrase []byte, keyCache *s2k.Cache) e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if pk.s2kType == S2KAEAD {
|
||||||
|
key = pk.applyHKDF(key)
|
||||||
|
}
|
||||||
return pk.decrypt(key)
|
return pk.decrypt(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,11 +630,14 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) error {
|
|||||||
|
|
||||||
key := make([]byte, pk.cipher.KeySize())
|
key := make([]byte, pk.cipher.KeySize())
|
||||||
pk.s2k(key, passphrase)
|
pk.s2k(key, passphrase)
|
||||||
|
if pk.s2kType == S2KAEAD {
|
||||||
|
key = pk.applyHKDF(key)
|
||||||
|
}
|
||||||
return pk.decrypt(key)
|
return pk.decrypt(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptPrivateKeys decrypts all encrypted keys with the given config and passphrase.
|
// DecryptPrivateKeys decrypts all encrypted keys with the given config and passphrase.
|
||||||
// Avoids recomputation of similar s2k key derivations.
|
// Avoids recomputation of similar s2k key derivations.
|
||||||
func DecryptPrivateKeys(keys []*PrivateKey, passphrase []byte) error {
|
func DecryptPrivateKeys(keys []*PrivateKey, passphrase []byte) error {
|
||||||
// Create a cache to avoid recomputation of key derviations for the same passphrase.
|
// Create a cache to avoid recomputation of key derviations for the same passphrase.
|
||||||
s2kCache := &s2k.Cache{}
|
s2kCache := &s2k.Cache{}
|
||||||
@ -474,7 +653,7 @@ func DecryptPrivateKeys(keys []*PrivateKey, passphrase []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encrypt encrypts an unencrypted private key.
|
// encrypt encrypts an unencrypted private key.
|
||||||
func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, cipherFunction CipherFunction) error {
|
func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, s2kType S2KType, cipherFunction CipherFunction, rand io.Reader) error {
|
||||||
if pk.Dummy() {
|
if pk.Dummy() {
|
||||||
return errors.ErrDummyPrivateKey("dummy key found")
|
return errors.ErrDummyPrivateKey("dummy key found")
|
||||||
}
|
}
|
||||||
@ -485,7 +664,15 @@ func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, cipherFunction Cip
|
|||||||
if len(key) != cipherFunction.KeySize() {
|
if len(key) != cipherFunction.KeySize() {
|
||||||
return errors.InvalidArgumentError("supplied encryption key has the wrong size")
|
return errors.InvalidArgumentError("supplied encryption key has the wrong size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.Mode() == s2k.Argon2S2K && s2kType != S2KAEAD {
|
||||||
|
return errors.InvalidArgumentError("using Argon2 S2K without AEAD is not allowed")
|
||||||
|
}
|
||||||
|
if params.Mode() != s2k.Argon2S2K && params.Mode() != s2k.IteratedSaltedS2K &&
|
||||||
|
params.Mode() != s2k.SaltedS2K { // only allowed for high-entropy passphrases
|
||||||
|
return errors.InvalidArgumentError("insecure S2K mode")
|
||||||
|
}
|
||||||
|
|
||||||
priv := bytes.NewBuffer(nil)
|
priv := bytes.NewBuffer(nil)
|
||||||
err := pk.serializePrivateKey(priv)
|
err := pk.serializePrivateKey(priv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -497,35 +684,53 @@ func (pk *PrivateKey) encrypt(key []byte, params *s2k.Params, cipherFunction Cip
|
|||||||
pk.s2k, err = pk.s2kParams.Function()
|
pk.s2k, err = pk.s2kParams.Function()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKeyBytes := priv.Bytes()
|
privateKeyBytes := priv.Bytes()
|
||||||
pk.sha1Checksum = true
|
pk.s2kType = s2kType
|
||||||
block := pk.cipher.new(key)
|
block := pk.cipher.new(key)
|
||||||
pk.iv = make([]byte, pk.cipher.blockSize())
|
switch s2kType {
|
||||||
_, err = rand.Read(pk.iv)
|
case S2KAEAD:
|
||||||
if err != nil {
|
if pk.aead == 0 {
|
||||||
return err
|
return errors.StructuralError("aead mode is not set on key")
|
||||||
}
|
|
||||||
cfb := cipher.NewCFBEncrypter(block, pk.iv)
|
|
||||||
|
|
||||||
if pk.sha1Checksum {
|
|
||||||
pk.s2kType = S2KSHA1
|
|
||||||
h := sha1.New()
|
|
||||||
h.Write(privateKeyBytes)
|
|
||||||
sum := h.Sum(nil)
|
|
||||||
privateKeyBytes = append(privateKeyBytes, sum...)
|
|
||||||
} else {
|
|
||||||
pk.s2kType = S2KCHECKSUM
|
|
||||||
var sum uint16
|
|
||||||
for _, b := range privateKeyBytes {
|
|
||||||
sum += uint16(b)
|
|
||||||
}
|
}
|
||||||
priv.Write([]byte{uint8(sum >> 8), uint8(sum)})
|
aead := pk.aead.new(block)
|
||||||
|
additionalData, err := pk.additionalData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.iv = make([]byte, aead.NonceSize())
|
||||||
|
_, err = io.ReadFull(rand, pk.iv)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Decrypt the encrypted key material with aead
|
||||||
|
pk.encryptedData = aead.Seal(nil, pk.iv, privateKeyBytes, additionalData)
|
||||||
|
case S2KSHA1, S2KCHECKSUM:
|
||||||
|
pk.iv = make([]byte, pk.cipher.blockSize())
|
||||||
|
_, err = io.ReadFull(rand, pk.iv)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfb := cipher.NewCFBEncrypter(block, pk.iv)
|
||||||
|
if s2kType == S2KSHA1 {
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write(privateKeyBytes)
|
||||||
|
sum := h.Sum(nil)
|
||||||
|
privateKeyBytes = append(privateKeyBytes, sum...)
|
||||||
|
} else {
|
||||||
|
var sum uint16
|
||||||
|
for _, b := range privateKeyBytes {
|
||||||
|
sum += uint16(b)
|
||||||
|
}
|
||||||
|
privateKeyBytes = append(privateKeyBytes, []byte{uint8(sum >> 8), uint8(sum)}...)
|
||||||
|
}
|
||||||
|
pk.encryptedData = make([]byte, len(privateKeyBytes))
|
||||||
|
cfb.XORKeyStream(pk.encryptedData, privateKeyBytes)
|
||||||
|
default:
|
||||||
|
return errors.InvalidArgumentError("invalid s2k type for encryption")
|
||||||
}
|
}
|
||||||
|
|
||||||
pk.encryptedData = make([]byte, len(privateKeyBytes))
|
|
||||||
cfb.XORKeyStream(pk.encryptedData, privateKeyBytes)
|
|
||||||
pk.Encrypted = true
|
pk.Encrypted = true
|
||||||
pk.PrivateKey = nil
|
pk.PrivateKey = nil
|
||||||
return err
|
return err
|
||||||
@ -544,8 +749,15 @@ func (pk *PrivateKey) EncryptWithConfig(passphrase []byte, config *Config) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s2k(key, passphrase)
|
s2k(key, passphrase)
|
||||||
|
s2kType := S2KSHA1
|
||||||
|
if config.AEAD() != nil {
|
||||||
|
s2kType = S2KAEAD
|
||||||
|
pk.aead = config.AEAD().Mode()
|
||||||
|
pk.cipher = config.Cipher()
|
||||||
|
key = pk.applyHKDF(key)
|
||||||
|
}
|
||||||
// Encrypt the private key with the derived encryption key.
|
// Encrypt the private key with the derived encryption key.
|
||||||
return pk.encrypt(key, params, config.Cipher())
|
return pk.encrypt(key, params, s2kType, config.Cipher(), config.Random())
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptPrivateKeys encrypts all unencrypted keys with the given config and passphrase.
|
// EncryptPrivateKeys encrypts all unencrypted keys with the given config and passphrase.
|
||||||
@ -564,7 +776,16 @@ func EncryptPrivateKeys(keys []*PrivateKey, passphrase []byte, config *Config) e
|
|||||||
s2k(encryptionKey, passphrase)
|
s2k(encryptionKey, passphrase)
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if key != nil && !key.Dummy() && !key.Encrypted {
|
if key != nil && !key.Dummy() && !key.Encrypted {
|
||||||
err = key.encrypt(encryptionKey, params, config.Cipher())
|
s2kType := S2KSHA1
|
||||||
|
if config.AEAD() != nil {
|
||||||
|
s2kType = S2KAEAD
|
||||||
|
key.aead = config.AEAD().Mode()
|
||||||
|
key.cipher = config.Cipher()
|
||||||
|
derivedKey := key.applyHKDF(encryptionKey)
|
||||||
|
err = key.encrypt(derivedKey, params, s2kType, config.Cipher(), config.Random())
|
||||||
|
} else {
|
||||||
|
err = key.encrypt(encryptionKey, params, s2kType, config.Cipher(), config.Random())
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -581,7 +802,7 @@ func (pk *PrivateKey) Encrypt(passphrase []byte) error {
|
|||||||
S2KMode: s2k.IteratedSaltedS2K,
|
S2KMode: s2k.IteratedSaltedS2K,
|
||||||
S2KCount: 65536,
|
S2KCount: 65536,
|
||||||
Hash: crypto.SHA256,
|
Hash: crypto.SHA256,
|
||||||
} ,
|
},
|
||||||
DefaultCipher: CipherAES256,
|
DefaultCipher: CipherAES256,
|
||||||
}
|
}
|
||||||
return pk.EncryptWithConfig(passphrase, config)
|
return pk.EncryptWithConfig(passphrase, config)
|
||||||
@ -601,6 +822,14 @@ func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) {
|
|||||||
err = serializeEdDSAPrivateKey(w, priv)
|
err = serializeEdDSAPrivateKey(w, priv)
|
||||||
case *ecdh.PrivateKey:
|
case *ecdh.PrivateKey:
|
||||||
err = serializeECDHPrivateKey(w, priv)
|
err = serializeECDHPrivateKey(w, priv)
|
||||||
|
case *x25519.PrivateKey:
|
||||||
|
err = serializeX25519PrivateKey(w, priv)
|
||||||
|
case *x448.PrivateKey:
|
||||||
|
err = serializeX448PrivateKey(w, priv)
|
||||||
|
case *ed25519.PrivateKey:
|
||||||
|
err = serializeEd25519PrivateKey(w, priv)
|
||||||
|
case *ed448.PrivateKey:
|
||||||
|
err = serializeEd448PrivateKey(w, priv)
|
||||||
default:
|
default:
|
||||||
err = errors.InvalidArgumentError("unknown private key type")
|
err = errors.InvalidArgumentError("unknown private key type")
|
||||||
}
|
}
|
||||||
@ -621,8 +850,18 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
|
|||||||
return pk.parseECDHPrivateKey(data)
|
return pk.parseECDHPrivateKey(data)
|
||||||
case PubKeyAlgoEdDSA:
|
case PubKeyAlgoEdDSA:
|
||||||
return pk.parseEdDSAPrivateKey(data)
|
return pk.parseEdDSAPrivateKey(data)
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
return pk.parseX25519PrivateKey(data)
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
return pk.parseX448PrivateKey(data)
|
||||||
|
case PubKeyAlgoEd25519:
|
||||||
|
return pk.parseEd25519PrivateKey(data)
|
||||||
|
case PubKeyAlgoEd448:
|
||||||
|
return pk.parseEd448PrivateKey(data)
|
||||||
|
default:
|
||||||
|
err = errors.StructuralError("unknown private key type")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
panic("impossible")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {
|
func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {
|
||||||
@ -743,6 +982,86 @@ func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pk *PrivateKey) parseX25519PrivateKey(data []byte) (err error) {
|
||||||
|
publicKey := pk.PublicKey.PublicKey.(*x25519.PublicKey)
|
||||||
|
privateKey := x25519.NewPrivateKey(*publicKey)
|
||||||
|
privateKey.PublicKey = *publicKey
|
||||||
|
|
||||||
|
privateKey.Secret = make([]byte, x25519.KeySize)
|
||||||
|
|
||||||
|
if len(data) != x25519.KeySize {
|
||||||
|
err = errors.StructuralError("wrong x25519 key size")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
subtle.ConstantTimeCopy(1, privateKey.Secret, data)
|
||||||
|
if err = x25519.Validate(privateKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.PrivateKey = privateKey
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PrivateKey) parseX448PrivateKey(data []byte) (err error) {
|
||||||
|
publicKey := pk.PublicKey.PublicKey.(*x448.PublicKey)
|
||||||
|
privateKey := x448.NewPrivateKey(*publicKey)
|
||||||
|
privateKey.PublicKey = *publicKey
|
||||||
|
|
||||||
|
privateKey.Secret = make([]byte, x448.KeySize)
|
||||||
|
|
||||||
|
if len(data) != x448.KeySize {
|
||||||
|
err = errors.StructuralError("wrong x448 key size")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
subtle.ConstantTimeCopy(1, privateKey.Secret, data)
|
||||||
|
if err = x448.Validate(privateKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.PrivateKey = privateKey
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PrivateKey) parseEd25519PrivateKey(data []byte) (err error) {
|
||||||
|
publicKey := pk.PublicKey.PublicKey.(*ed25519.PublicKey)
|
||||||
|
privateKey := ed25519.NewPrivateKey(*publicKey)
|
||||||
|
privateKey.PublicKey = *publicKey
|
||||||
|
|
||||||
|
if len(data) != ed25519.SeedSize {
|
||||||
|
err = errors.StructuralError("wrong ed25519 key size")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = privateKey.UnmarshalByteSecret(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ed25519.Validate(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.PrivateKey = privateKey
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PrivateKey) parseEd448PrivateKey(data []byte) (err error) {
|
||||||
|
publicKey := pk.PublicKey.PublicKey.(*ed448.PublicKey)
|
||||||
|
privateKey := ed448.NewPrivateKey(*publicKey)
|
||||||
|
privateKey.PublicKey = *publicKey
|
||||||
|
|
||||||
|
if len(data) != ed448.SeedSize {
|
||||||
|
err = errors.StructuralError("wrong ed448 key size")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = privateKey.UnmarshalByteSecret(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ed448.Validate(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pk.PrivateKey = privateKey
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) {
|
func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) {
|
||||||
eddsaPub := pk.PublicKey.PublicKey.(*eddsa.PublicKey)
|
eddsaPub := pk.PublicKey.PublicKey.(*eddsa.PublicKey)
|
||||||
eddsaPriv := eddsa.NewPrivateKey(*eddsaPub)
|
eddsaPriv := eddsa.NewPrivateKey(*eddsaPub)
|
||||||
@ -767,6 +1086,41 @@ func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pk *PrivateKey) additionalData() ([]byte, error) {
|
||||||
|
additionalData := bytes.NewBuffer(nil)
|
||||||
|
// Write additional data prefix based on packet type
|
||||||
|
var packetByte byte
|
||||||
|
if pk.PublicKey.IsSubkey {
|
||||||
|
packetByte = 0xc7
|
||||||
|
} else {
|
||||||
|
packetByte = 0xc5
|
||||||
|
}
|
||||||
|
// Write public key to additional data
|
||||||
|
_, err := additionalData.Write([]byte{packetByte})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = pk.PublicKey.serializeWithoutHeaders(additionalData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return additionalData.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PrivateKey) applyHKDF(inputKey []byte) []byte {
|
||||||
|
var packetByte byte
|
||||||
|
if pk.PublicKey.IsSubkey {
|
||||||
|
packetByte = 0xc7
|
||||||
|
} else {
|
||||||
|
packetByte = 0xc5
|
||||||
|
}
|
||||||
|
associatedData := []byte{packetByte, byte(pk.Version), byte(pk.cipher), byte(pk.aead)}
|
||||||
|
hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, associatedData)
|
||||||
|
encryptionKey := make([]byte, pk.cipher.KeySize())
|
||||||
|
_, _ = readFull(hkdfReader, encryptionKey)
|
||||||
|
return encryptionKey
|
||||||
|
}
|
||||||
|
|
||||||
func validateDSAParameters(priv *dsa.PrivateKey) error {
|
func validateDSAParameters(priv *dsa.PrivateKey) error {
|
||||||
p := priv.P // group prime
|
p := priv.P // group prime
|
||||||
q := priv.Q // subgroup order
|
q := priv.Q // subgroup order
|
||||||
|
482
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
generated
vendored
482
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/public_key.go
generated
vendored
@ -5,7 +5,6 @@
|
|||||||
package packet
|
package packet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
@ -21,23 +20,24 @@ import (
|
|||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/ecdh"
|
"github.com/ProtonMail/go-crypto/openpgp/ecdh"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
|
"github.com/ProtonMail/go-crypto/openpgp/ecdsa"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/ed25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/ed448"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
|
"github.com/ProtonMail/go-crypto/openpgp/eddsa"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/ecc"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
"github.com/ProtonMail/go-crypto/openpgp/internal/encoding"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x25519"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/x448"
|
||||||
)
|
)
|
||||||
|
|
||||||
type kdfHashFunction byte
|
|
||||||
type kdfAlgorithm byte
|
|
||||||
|
|
||||||
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
|
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
|
||||||
type PublicKey struct {
|
type PublicKey struct {
|
||||||
Version int
|
Version int
|
||||||
CreationTime time.Time
|
CreationTime time.Time
|
||||||
PubKeyAlgo PublicKeyAlgorithm
|
PubKeyAlgo PublicKeyAlgorithm
|
||||||
PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey
|
PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey or *eddsa.PublicKey, *x25519.PublicKey, *x448.PublicKey, *ed25519.PublicKey, *ed448.PublicKey
|
||||||
Fingerprint []byte
|
Fingerprint []byte
|
||||||
KeyId uint64
|
KeyId uint64
|
||||||
IsSubkey bool
|
IsSubkey bool
|
||||||
@ -61,11 +61,19 @@ func (pk *PublicKey) UpgradeToV5() {
|
|||||||
pk.setFingerprintAndKeyId()
|
pk.setFingerprintAndKeyId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpgradeToV6 updates the version of the key to v6, and updates all necessary
|
||||||
|
// fields.
|
||||||
|
func (pk *PublicKey) UpgradeToV6() error {
|
||||||
|
pk.Version = 6
|
||||||
|
pk.setFingerprintAndKeyId()
|
||||||
|
return pk.checkV6Compatibility()
|
||||||
|
}
|
||||||
|
|
||||||
// signingKey provides a convenient abstraction over signature verification
|
// signingKey provides a convenient abstraction over signature verification
|
||||||
// for v3 and v4 public keys.
|
// for v3 and v4 public keys.
|
||||||
type signingKey interface {
|
type signingKey interface {
|
||||||
SerializeForHash(io.Writer) error
|
SerializeForHash(io.Writer) error
|
||||||
SerializeSignaturePrefix(io.Writer)
|
SerializeSignaturePrefix(io.Writer) error
|
||||||
serializeWithoutHeaders(io.Writer) error
|
serializeWithoutHeaders(io.Writer) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +182,54 @@ func NewEdDSAPublicKey(creationTime time.Time, pub *eddsa.PublicKey) *PublicKey
|
|||||||
return pk
|
return pk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewX25519PublicKey(creationTime time.Time, pub *x25519.PublicKey) *PublicKey {
|
||||||
|
pk := &PublicKey{
|
||||||
|
Version: 4,
|
||||||
|
CreationTime: creationTime,
|
||||||
|
PubKeyAlgo: PubKeyAlgoX25519,
|
||||||
|
PublicKey: pub,
|
||||||
|
}
|
||||||
|
|
||||||
|
pk.setFingerprintAndKeyId()
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewX448PublicKey(creationTime time.Time, pub *x448.PublicKey) *PublicKey {
|
||||||
|
pk := &PublicKey{
|
||||||
|
Version: 4,
|
||||||
|
CreationTime: creationTime,
|
||||||
|
PubKeyAlgo: PubKeyAlgoX448,
|
||||||
|
PublicKey: pub,
|
||||||
|
}
|
||||||
|
|
||||||
|
pk.setFingerprintAndKeyId()
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEd25519PublicKey(creationTime time.Time, pub *ed25519.PublicKey) *PublicKey {
|
||||||
|
pk := &PublicKey{
|
||||||
|
Version: 4,
|
||||||
|
CreationTime: creationTime,
|
||||||
|
PubKeyAlgo: PubKeyAlgoEd25519,
|
||||||
|
PublicKey: pub,
|
||||||
|
}
|
||||||
|
|
||||||
|
pk.setFingerprintAndKeyId()
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEd448PublicKey(creationTime time.Time, pub *ed448.PublicKey) *PublicKey {
|
||||||
|
pk := &PublicKey{
|
||||||
|
Version: 4,
|
||||||
|
CreationTime: creationTime,
|
||||||
|
PubKeyAlgo: PubKeyAlgoEd448,
|
||||||
|
PublicKey: pub,
|
||||||
|
}
|
||||||
|
|
||||||
|
pk.setFingerprintAndKeyId()
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
func (pk *PublicKey) parse(r io.Reader) (err error) {
|
func (pk *PublicKey) parse(r io.Reader) (err error) {
|
||||||
// RFC 4880, section 5.5.2
|
// RFC 4880, section 5.5.2
|
||||||
var buf [6]byte
|
var buf [6]byte
|
||||||
@ -181,12 +237,19 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if buf[0] != 4 && buf[0] != 5 {
|
|
||||||
|
pk.Version = int(buf[0])
|
||||||
|
if pk.Version != 4 && pk.Version != 5 && pk.Version != 6 {
|
||||||
return errors.UnsupportedError("public key version " + strconv.Itoa(int(buf[0])))
|
return errors.UnsupportedError("public key version " + strconv.Itoa(int(buf[0])))
|
||||||
}
|
}
|
||||||
|
|
||||||
pk.Version = int(buf[0])
|
if V5Disabled && pk.Version == 5 {
|
||||||
if pk.Version == 5 {
|
return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pk.Version >= 5 {
|
||||||
|
// Read the four-octet scalar octet count
|
||||||
|
// The count is not used in this implementation
|
||||||
var n [4]byte
|
var n [4]byte
|
||||||
_, err = readFull(r, n[:])
|
_, err = readFull(r, n[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -195,6 +258,7 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
|
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
|
||||||
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
|
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
|
||||||
|
// Ignore four-ocet length
|
||||||
switch pk.PubKeyAlgo {
|
switch pk.PubKeyAlgo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
||||||
err = pk.parseRSA(r)
|
err = pk.parseRSA(r)
|
||||||
@ -208,6 +272,14 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
|||||||
err = pk.parseECDH(r)
|
err = pk.parseECDH(r)
|
||||||
case PubKeyAlgoEdDSA:
|
case PubKeyAlgoEdDSA:
|
||||||
err = pk.parseEdDSA(r)
|
err = pk.parseEdDSA(r)
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
err = pk.parseX25519(r)
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
err = pk.parseX448(r)
|
||||||
|
case PubKeyAlgoEd25519:
|
||||||
|
err = pk.parseEd25519(r)
|
||||||
|
case PubKeyAlgoEd448:
|
||||||
|
err = pk.parseEd448(r)
|
||||||
default:
|
default:
|
||||||
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
|
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
|
||||||
}
|
}
|
||||||
@ -221,21 +293,44 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
|
|||||||
|
|
||||||
func (pk *PublicKey) setFingerprintAndKeyId() {
|
func (pk *PublicKey) setFingerprintAndKeyId() {
|
||||||
// RFC 4880, section 12.2
|
// RFC 4880, section 12.2
|
||||||
if pk.Version == 5 {
|
if pk.Version >= 5 {
|
||||||
fingerprint := sha256.New()
|
fingerprint := sha256.New()
|
||||||
pk.SerializeForHash(fingerprint)
|
if err := pk.SerializeForHash(fingerprint); err != nil {
|
||||||
|
// Should not happen for a hash.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
pk.Fingerprint = make([]byte, 32)
|
pk.Fingerprint = make([]byte, 32)
|
||||||
copy(pk.Fingerprint, fingerprint.Sum(nil))
|
copy(pk.Fingerprint, fingerprint.Sum(nil))
|
||||||
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[:8])
|
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[:8])
|
||||||
} else {
|
} else {
|
||||||
fingerprint := sha1.New()
|
fingerprint := sha1.New()
|
||||||
pk.SerializeForHash(fingerprint)
|
if err := pk.SerializeForHash(fingerprint); err != nil {
|
||||||
|
// Should not happen for a hash.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
pk.Fingerprint = make([]byte, 20)
|
pk.Fingerprint = make([]byte, 20)
|
||||||
copy(pk.Fingerprint, fingerprint.Sum(nil))
|
copy(pk.Fingerprint, fingerprint.Sum(nil))
|
||||||
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
|
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pk *PublicKey) checkV6Compatibility() error {
|
||||||
|
// Implementations MUST NOT accept or generate version 6 key material using the deprecated OIDs.
|
||||||
|
switch pk.PubKeyAlgo {
|
||||||
|
case PubKeyAlgoECDH:
|
||||||
|
curveInfo := ecc.FindByOid(pk.oid)
|
||||||
|
if curveInfo == nil {
|
||||||
|
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
||||||
|
}
|
||||||
|
if curveInfo.GenName == ecc.Curve25519GenName {
|
||||||
|
return errors.StructuralError("cannot generate v6 key with deprecated OID: Curve25519Legacy")
|
||||||
|
}
|
||||||
|
case PubKeyAlgoEdDSA:
|
||||||
|
return errors.StructuralError("cannot generate v6 key with deprecated algorithm: EdDSALegacy")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
|
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
|
||||||
// section 5.5.2.
|
// section 5.5.2.
|
||||||
func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
|
func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
|
||||||
@ -324,16 +419,17 @@ func (pk *PublicKey) parseECDSA(r io.Reader) (err error) {
|
|||||||
if _, err = pk.oid.ReadFrom(r); err != nil {
|
if _, err = pk.oid.ReadFrom(r); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pk.p = new(encoding.MPI)
|
|
||||||
if _, err = pk.p.ReadFrom(r); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
curveInfo := ecc.FindByOid(pk.oid)
|
curveInfo := ecc.FindByOid(pk.oid)
|
||||||
if curveInfo == nil {
|
if curveInfo == nil {
|
||||||
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pk.p = new(encoding.MPI)
|
||||||
|
if _, err = pk.p.ReadFrom(r); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c, ok := curveInfo.Curve.(ecc.ECDSACurve)
|
c, ok := curveInfo.Curve.(ecc.ECDSACurve)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
|
return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
|
||||||
@ -353,6 +449,17 @@ func (pk *PublicKey) parseECDH(r io.Reader) (err error) {
|
|||||||
if _, err = pk.oid.ReadFrom(r); err != nil {
|
if _, err = pk.oid.ReadFrom(r); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
curveInfo := ecc.FindByOid(pk.oid)
|
||||||
|
if curveInfo == nil {
|
||||||
|
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
||||||
|
}
|
||||||
|
|
||||||
|
if pk.Version == 6 && curveInfo.GenName == ecc.Curve25519GenName {
|
||||||
|
// Implementations MUST NOT accept or generate version 6 key material using the deprecated OIDs.
|
||||||
|
return errors.StructuralError("cannot read v6 key with deprecated OID: Curve25519Legacy")
|
||||||
|
}
|
||||||
|
|
||||||
pk.p = new(encoding.MPI)
|
pk.p = new(encoding.MPI)
|
||||||
if _, err = pk.p.ReadFrom(r); err != nil {
|
if _, err = pk.p.ReadFrom(r); err != nil {
|
||||||
return
|
return
|
||||||
@ -362,12 +469,6 @@ func (pk *PublicKey) parseECDH(r io.Reader) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
curveInfo := ecc.FindByOid(pk.oid)
|
|
||||||
|
|
||||||
if curveInfo == nil {
|
|
||||||
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
|
||||||
}
|
|
||||||
|
|
||||||
c, ok := curveInfo.Curve.(ecc.ECDHCurve)
|
c, ok := curveInfo.Curve.(ecc.ECDHCurve)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
|
return errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", pk.oid))
|
||||||
@ -396,10 +497,16 @@ func (pk *PublicKey) parseECDH(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pk *PublicKey) parseEdDSA(r io.Reader) (err error) {
|
func (pk *PublicKey) parseEdDSA(r io.Reader) (err error) {
|
||||||
|
if pk.Version == 6 {
|
||||||
|
// Implementations MUST NOT accept or generate version 6 key material using the deprecated OIDs.
|
||||||
|
return errors.StructuralError("cannot generate v6 key with deprecated algorithm: EdDSALegacy")
|
||||||
|
}
|
||||||
|
|
||||||
pk.oid = new(encoding.OID)
|
pk.oid = new(encoding.OID)
|
||||||
if _, err = pk.oid.ReadFrom(r); err != nil {
|
if _, err = pk.oid.ReadFrom(r); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
curveInfo := ecc.FindByOid(pk.oid)
|
curveInfo := ecc.FindByOid(pk.oid)
|
||||||
if curveInfo == nil {
|
if curveInfo == nil {
|
||||||
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
return errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
||||||
@ -435,75 +542,145 @@ func (pk *PublicKey) parseEdDSA(r io.Reader) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pk *PublicKey) parseX25519(r io.Reader) (err error) {
|
||||||
|
point := make([]byte, x25519.KeySize)
|
||||||
|
_, err = io.ReadFull(r, point)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pub := &x25519.PublicKey{
|
||||||
|
Point: point,
|
||||||
|
}
|
||||||
|
pk.PublicKey = pub
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PublicKey) parseX448(r io.Reader) (err error) {
|
||||||
|
point := make([]byte, x448.KeySize)
|
||||||
|
_, err = io.ReadFull(r, point)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pub := &x448.PublicKey{
|
||||||
|
Point: point,
|
||||||
|
}
|
||||||
|
pk.PublicKey = pub
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PublicKey) parseEd25519(r io.Reader) (err error) {
|
||||||
|
point := make([]byte, ed25519.PublicKeySize)
|
||||||
|
_, err = io.ReadFull(r, point)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pub := &ed25519.PublicKey{
|
||||||
|
Point: point,
|
||||||
|
}
|
||||||
|
pk.PublicKey = pub
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pk *PublicKey) parseEd448(r io.Reader) (err error) {
|
||||||
|
point := make([]byte, ed448.PublicKeySize)
|
||||||
|
_, err = io.ReadFull(r, point)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pub := &ed448.PublicKey{
|
||||||
|
Point: point,
|
||||||
|
}
|
||||||
|
pk.PublicKey = pub
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SerializeForHash serializes the PublicKey to w with the special packet
|
// SerializeForHash serializes the PublicKey to w with the special packet
|
||||||
// header format needed for hashing.
|
// header format needed for hashing.
|
||||||
func (pk *PublicKey) SerializeForHash(w io.Writer) error {
|
func (pk *PublicKey) SerializeForHash(w io.Writer) error {
|
||||||
pk.SerializeSignaturePrefix(w)
|
if err := pk.SerializeSignaturePrefix(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return pk.serializeWithoutHeaders(w)
|
return pk.serializeWithoutHeaders(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
|
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
|
||||||
// The prefix is used when calculating a signature over this public key. See
|
// The prefix is used when calculating a signature over this public key. See
|
||||||
// RFC 4880, section 5.2.4.
|
// RFC 4880, section 5.2.4.
|
||||||
func (pk *PublicKey) SerializeSignaturePrefix(w io.Writer) {
|
func (pk *PublicKey) SerializeSignaturePrefix(w io.Writer) error {
|
||||||
var pLength = pk.algorithmSpecificByteCount()
|
var pLength = pk.algorithmSpecificByteCount()
|
||||||
if pk.Version == 5 {
|
// version, timestamp, algorithm
|
||||||
pLength += 10 // version, timestamp (4), algorithm, key octet count (4).
|
pLength += versionSize + timestampSize + algorithmSize
|
||||||
w.Write([]byte{
|
if pk.Version >= 5 {
|
||||||
0x9A,
|
// key octet count (4).
|
||||||
|
pLength += 4
|
||||||
|
_, err := w.Write([]byte{
|
||||||
|
// When a v4 signature is made over a key, the hash data starts with the octet 0x99, followed by a two-octet length
|
||||||
|
// of the key, and then the body of the key packet. When a v6 signature is made over a key, the hash data starts
|
||||||
|
// with the salt, then octet 0x9B, followed by a four-octet length of the key, and then the body of the key packet.
|
||||||
|
0x95 + byte(pk.Version),
|
||||||
byte(pLength >> 24),
|
byte(pLength >> 24),
|
||||||
byte(pLength >> 16),
|
byte(pLength >> 16),
|
||||||
byte(pLength >> 8),
|
byte(pLength >> 8),
|
||||||
byte(pLength),
|
byte(pLength),
|
||||||
})
|
})
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
pLength += 6
|
if _, err := w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}); err != nil {
|
||||||
w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pk *PublicKey) Serialize(w io.Writer) (err error) {
|
func (pk *PublicKey) Serialize(w io.Writer) (err error) {
|
||||||
length := 6 // 6 byte header
|
length := uint32(versionSize + timestampSize + algorithmSize) // 6 byte header
|
||||||
length += pk.algorithmSpecificByteCount()
|
length += pk.algorithmSpecificByteCount()
|
||||||
if pk.Version == 5 {
|
if pk.Version >= 5 {
|
||||||
length += 4 // octet key count
|
length += 4 // octet key count
|
||||||
}
|
}
|
||||||
packetType := packetTypePublicKey
|
packetType := packetTypePublicKey
|
||||||
if pk.IsSubkey {
|
if pk.IsSubkey {
|
||||||
packetType = packetTypePublicSubkey
|
packetType = packetTypePublicSubkey
|
||||||
}
|
}
|
||||||
err = serializeHeader(w, packetType, length)
|
err = serializeHeader(w, packetType, int(length))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return pk.serializeWithoutHeaders(w)
|
return pk.serializeWithoutHeaders(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pk *PublicKey) algorithmSpecificByteCount() int {
|
func (pk *PublicKey) algorithmSpecificByteCount() uint32 {
|
||||||
length := 0
|
length := uint32(0)
|
||||||
switch pk.PubKeyAlgo {
|
switch pk.PubKeyAlgo {
|
||||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
||||||
length += int(pk.n.EncodedLength())
|
length += uint32(pk.n.EncodedLength())
|
||||||
length += int(pk.e.EncodedLength())
|
length += uint32(pk.e.EncodedLength())
|
||||||
case PubKeyAlgoDSA:
|
case PubKeyAlgoDSA:
|
||||||
length += int(pk.p.EncodedLength())
|
length += uint32(pk.p.EncodedLength())
|
||||||
length += int(pk.q.EncodedLength())
|
length += uint32(pk.q.EncodedLength())
|
||||||
length += int(pk.g.EncodedLength())
|
length += uint32(pk.g.EncodedLength())
|
||||||
length += int(pk.y.EncodedLength())
|
length += uint32(pk.y.EncodedLength())
|
||||||
case PubKeyAlgoElGamal:
|
case PubKeyAlgoElGamal:
|
||||||
length += int(pk.p.EncodedLength())
|
length += uint32(pk.p.EncodedLength())
|
||||||
length += int(pk.g.EncodedLength())
|
length += uint32(pk.g.EncodedLength())
|
||||||
length += int(pk.y.EncodedLength())
|
length += uint32(pk.y.EncodedLength())
|
||||||
case PubKeyAlgoECDSA:
|
case PubKeyAlgoECDSA:
|
||||||
length += int(pk.oid.EncodedLength())
|
length += uint32(pk.oid.EncodedLength())
|
||||||
length += int(pk.p.EncodedLength())
|
length += uint32(pk.p.EncodedLength())
|
||||||
case PubKeyAlgoECDH:
|
case PubKeyAlgoECDH:
|
||||||
length += int(pk.oid.EncodedLength())
|
length += uint32(pk.oid.EncodedLength())
|
||||||
length += int(pk.p.EncodedLength())
|
length += uint32(pk.p.EncodedLength())
|
||||||
length += int(pk.kdf.EncodedLength())
|
length += uint32(pk.kdf.EncodedLength())
|
||||||
case PubKeyAlgoEdDSA:
|
case PubKeyAlgoEdDSA:
|
||||||
length += int(pk.oid.EncodedLength())
|
length += uint32(pk.oid.EncodedLength())
|
||||||
length += int(pk.p.EncodedLength())
|
length += uint32(pk.p.EncodedLength())
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
length += x25519.KeySize
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
length += x448.KeySize
|
||||||
|
case PubKeyAlgoEd25519:
|
||||||
|
length += ed25519.PublicKeySize
|
||||||
|
case PubKeyAlgoEd448:
|
||||||
|
length += ed448.PublicKeySize
|
||||||
default:
|
default:
|
||||||
panic("unknown public key algorithm")
|
panic("unknown public key algorithm")
|
||||||
}
|
}
|
||||||
@ -522,7 +699,7 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pk.Version == 5 {
|
if pk.Version >= 5 {
|
||||||
n := pk.algorithmSpecificByteCount()
|
n := pk.algorithmSpecificByteCount()
|
||||||
if _, err = w.Write([]byte{
|
if _, err = w.Write([]byte{
|
||||||
byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n),
|
byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n),
|
||||||
@ -580,6 +757,22 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
|
|||||||
}
|
}
|
||||||
_, err = w.Write(pk.p.EncodedBytes())
|
_, err = w.Write(pk.p.EncodedBytes())
|
||||||
return
|
return
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
publicKey := pk.PublicKey.(*x25519.PublicKey)
|
||||||
|
_, err = w.Write(publicKey.Point)
|
||||||
|
return
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
publicKey := pk.PublicKey.(*x448.PublicKey)
|
||||||
|
_, err = w.Write(publicKey.Point)
|
||||||
|
return
|
||||||
|
case PubKeyAlgoEd25519:
|
||||||
|
publicKey := pk.PublicKey.(*ed25519.PublicKey)
|
||||||
|
_, err = w.Write(publicKey.Point)
|
||||||
|
return
|
||||||
|
case PubKeyAlgoEd448:
|
||||||
|
publicKey := pk.PublicKey.(*ed448.PublicKey)
|
||||||
|
_, err = w.Write(publicKey.Point)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return errors.InvalidArgumentError("bad public-key algorithm")
|
return errors.InvalidArgumentError("bad public-key algorithm")
|
||||||
}
|
}
|
||||||
@ -589,6 +782,20 @@ func (pk *PublicKey) CanSign() bool {
|
|||||||
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal && pk.PubKeyAlgo != PubKeyAlgoECDH
|
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal && pk.PubKeyAlgo != PubKeyAlgoECDH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyHashTag returns nil iff sig appears to be a plausible signature of the data
|
||||||
|
// hashed into signed, based solely on its HashTag. signed is mutated by this call.
|
||||||
|
func VerifyHashTag(signed hash.Hash, sig *Signature) (err error) {
|
||||||
|
if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
|
||||||
|
sig.AddMetadataToHashSuffix()
|
||||||
|
}
|
||||||
|
signed.Write(sig.HashSuffix)
|
||||||
|
hashBytes := signed.Sum(nil)
|
||||||
|
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
|
||||||
|
return errors.SignatureError("hash tag doesn't match")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// VerifySignature returns nil iff sig is a valid signature, made by this
|
// VerifySignature returns nil iff sig is a valid signature, made by this
|
||||||
// public key, of the data hashed into signed. signed is mutated by this call.
|
// public key, of the data hashed into signed. signed is mutated by this call.
|
||||||
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
|
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
|
||||||
@ -600,7 +807,8 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
|
|||||||
}
|
}
|
||||||
signed.Write(sig.HashSuffix)
|
signed.Write(sig.HashSuffix)
|
||||||
hashBytes := signed.Sum(nil)
|
hashBytes := signed.Sum(nil)
|
||||||
if sig.Version == 5 && (hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1]) {
|
// see discussion https://github.com/ProtonMail/go-crypto/issues/107
|
||||||
|
if sig.Version >= 5 && (hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1]) {
|
||||||
return errors.SignatureError("hash tag doesn't match")
|
return errors.SignatureError("hash tag doesn't match")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,6 +847,18 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
|
|||||||
return errors.SignatureError("EdDSA verification failure")
|
return errors.SignatureError("EdDSA verification failure")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
case PubKeyAlgoEd25519:
|
||||||
|
ed25519PublicKey := pk.PublicKey.(*ed25519.PublicKey)
|
||||||
|
if !ed25519.Verify(ed25519PublicKey, hashBytes, sig.EdSig) {
|
||||||
|
return errors.SignatureError("Ed25519 verification failure")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case PubKeyAlgoEd448:
|
||||||
|
ed448PublicKey := pk.PublicKey.(*ed448.PublicKey)
|
||||||
|
if !ed448.Verify(ed448PublicKey, hashBytes, sig.EdSig) {
|
||||||
|
return errors.SignatureError("ed448 verification failure")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
return errors.SignatureError("Unsupported public key algorithm used in signature")
|
return errors.SignatureError("Unsupported public key algorithm used in signature")
|
||||||
}
|
}
|
||||||
@ -646,11 +866,8 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
|
|||||||
|
|
||||||
// keySignatureHash returns a Hash of the message that needs to be signed for
|
// keySignatureHash returns a Hash of the message that needs to be signed for
|
||||||
// pk to assert a subkey relationship to signed.
|
// pk to assert a subkey relationship to signed.
|
||||||
func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
|
func keySignatureHash(pk, signed signingKey, hashFunc hash.Hash) (h hash.Hash, err error) {
|
||||||
if !hashFunc.Available() {
|
h = hashFunc
|
||||||
return nil, errors.UnsupportedError("hash function")
|
|
||||||
}
|
|
||||||
h = hashFunc.New()
|
|
||||||
|
|
||||||
// RFC 4880, section 5.2.4
|
// RFC 4880, section 5.2.4
|
||||||
err = pk.SerializeForHash(h)
|
err = pk.SerializeForHash(h)
|
||||||
@ -662,10 +879,28 @@ func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyKeyHashTag returns nil iff sig appears to be a plausible signature over this
|
||||||
|
// primary key and subkey, based solely on its HashTag.
|
||||||
|
func (pk *PublicKey) VerifyKeyHashTag(signed *PublicKey, sig *Signature) error {
|
||||||
|
preparedHash, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h, err := keySignatureHash(pk, signed, preparedHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return VerifyHashTag(h, sig)
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyKeySignature returns nil iff sig is a valid signature, made by this
|
// VerifyKeySignature returns nil iff sig is a valid signature, made by this
|
||||||
// public key, of signed.
|
// public key, of signed.
|
||||||
func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
|
func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
|
||||||
h, err := keySignatureHash(pk, signed, sig.Hash)
|
preparedHash, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h, err := keySignatureHash(pk, signed, preparedHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -679,10 +914,14 @@ func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error
|
|||||||
if sig.EmbeddedSignature == nil {
|
if sig.EmbeddedSignature == nil {
|
||||||
return errors.StructuralError("signing subkey is missing cross-signature")
|
return errors.StructuralError("signing subkey is missing cross-signature")
|
||||||
}
|
}
|
||||||
|
preparedHashEmbedded, err := sig.EmbeddedSignature.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Verify the cross-signature. This is calculated over the same
|
// Verify the cross-signature. This is calculated over the same
|
||||||
// data as the main signature, so we cannot just recursively
|
// data as the main signature, so we cannot just recursively
|
||||||
// call signed.VerifyKeySignature(...)
|
// call signed.VerifyKeySignature(...)
|
||||||
if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil {
|
if h, err = keySignatureHash(pk, signed, preparedHashEmbedded); err != nil {
|
||||||
return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
|
return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
|
||||||
}
|
}
|
||||||
if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
|
if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
|
||||||
@ -693,32 +932,44 @@ func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
|
func keyRevocationHash(pk signingKey, hashFunc hash.Hash) (err error) {
|
||||||
if !hashFunc.Available() {
|
return pk.SerializeForHash(hashFunc)
|
||||||
return nil, errors.UnsupportedError("hash function")
|
}
|
||||||
|
|
||||||
|
// VerifyRevocationHashTag returns nil iff sig appears to be a plausible signature
|
||||||
|
// over this public key, based solely on its HashTag.
|
||||||
|
func (pk *PublicKey) VerifyRevocationHashTag(sig *Signature) (err error) {
|
||||||
|
preparedHash, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
h = hashFunc.New()
|
if err = keyRevocationHash(pk, preparedHash); err != nil {
|
||||||
|
return err
|
||||||
// RFC 4880, section 5.2.4
|
}
|
||||||
err = pk.SerializeForHash(h)
|
return VerifyHashTag(preparedHash, sig)
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
|
// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
|
||||||
// public key.
|
// public key.
|
||||||
func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) {
|
func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) {
|
||||||
h, err := keyRevocationHash(pk, sig.Hash)
|
preparedHash, err := sig.PrepareVerify()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pk.VerifySignature(h, sig)
|
if err = keyRevocationHash(pk, preparedHash); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return pk.VerifySignature(preparedHash, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySubkeyRevocationSignature returns nil iff sig is a valid subkey revocation signature,
|
// VerifySubkeyRevocationSignature returns nil iff sig is a valid subkey revocation signature,
|
||||||
// made by this public key, of signed.
|
// made by this public key, of signed.
|
||||||
func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signed *PublicKey) (err error) {
|
func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signed *PublicKey) (err error) {
|
||||||
h, err := keySignatureHash(pk, signed, sig.Hash)
|
preparedHash, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h, err := keySignatureHash(pk, signed, preparedHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -727,15 +978,15 @@ func (pk *PublicKey) VerifySubkeyRevocationSignature(sig *Signature, signed *Pub
|
|||||||
|
|
||||||
// userIdSignatureHash returns a Hash of the message that needs to be signed
|
// userIdSignatureHash returns a Hash of the message that needs to be signed
|
||||||
// to assert that pk is a valid key for id.
|
// to assert that pk is a valid key for id.
|
||||||
func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
|
func userIdSignatureHash(id string, pk *PublicKey, h hash.Hash) (err error) {
|
||||||
if !hashFunc.Available() {
|
|
||||||
return nil, errors.UnsupportedError("hash function")
|
|
||||||
}
|
|
||||||
h = hashFunc.New()
|
|
||||||
|
|
||||||
// RFC 4880, section 5.2.4
|
// RFC 4880, section 5.2.4
|
||||||
pk.SerializeSignaturePrefix(h)
|
if err := pk.SerializeSignaturePrefix(h); err != nil {
|
||||||
pk.serializeWithoutHeaders(h)
|
return err
|
||||||
|
}
|
||||||
|
if err := pk.serializeWithoutHeaders(h); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var buf [5]byte
|
var buf [5]byte
|
||||||
buf[0] = 0xb4
|
buf[0] = 0xb4
|
||||||
@ -746,16 +997,51 @@ func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash
|
|||||||
h.Write(buf[:])
|
h.Write(buf[:])
|
||||||
h.Write([]byte(id))
|
h.Write([]byte(id))
|
||||||
|
|
||||||
return
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// directKeySignatureHash returns a Hash of the message that needs to be signed.
|
||||||
|
func directKeySignatureHash(pk *PublicKey, h hash.Hash) (err error) {
|
||||||
|
return pk.SerializeForHash(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserIdHashTag returns nil iff sig appears to be a plausible signature over this
|
||||||
|
// public key and UserId, based solely on its HashTag
|
||||||
|
func (pk *PublicKey) VerifyUserIdHashTag(id string, sig *Signature) (err error) {
|
||||||
|
preparedHash, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = userIdSignatureHash(id, pk, preparedHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return VerifyHashTag(preparedHash, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
|
// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
|
||||||
// public key, that id is the identity of pub.
|
// public key, that id is the identity of pub.
|
||||||
func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) {
|
func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) {
|
||||||
h, err := userIdSignatureHash(id, pub, sig.Hash)
|
h, err := sig.PrepareVerify()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := userIdSignatureHash(id, pub, h); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return pk.VerifySignature(h, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyDirectKeySignature returns nil iff sig is a valid signature, made by this
|
||||||
|
// public key.
|
||||||
|
func (pk *PublicKey) VerifyDirectKeySignature(sig *Signature) (err error) {
|
||||||
|
h, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := directKeySignatureHash(pk, h); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return pk.VerifySignature(h, sig)
|
return pk.VerifySignature(h, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,21 +1072,49 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
|
|||||||
bitLength = pk.p.BitLength()
|
bitLength = pk.p.BitLength()
|
||||||
case PubKeyAlgoEdDSA:
|
case PubKeyAlgoEdDSA:
|
||||||
bitLength = pk.p.BitLength()
|
bitLength = pk.p.BitLength()
|
||||||
|
case PubKeyAlgoX25519:
|
||||||
|
bitLength = x25519.KeySize * 8
|
||||||
|
case PubKeyAlgoX448:
|
||||||
|
bitLength = x448.KeySize * 8
|
||||||
|
case PubKeyAlgoEd25519:
|
||||||
|
bitLength = ed25519.PublicKeySize * 8
|
||||||
|
case PubKeyAlgoEd448:
|
||||||
|
bitLength = ed448.PublicKeySize * 8
|
||||||
default:
|
default:
|
||||||
err = errors.InvalidArgumentError("bad public-key algorithm")
|
err = errors.InvalidArgumentError("bad public-key algorithm")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Curve returns the used elliptic curve of this public key.
|
||||||
|
// Returns an error if no elliptic curve is used.
|
||||||
|
func (pk *PublicKey) Curve() (curve Curve, err error) {
|
||||||
|
switch pk.PubKeyAlgo {
|
||||||
|
case PubKeyAlgoECDSA, PubKeyAlgoECDH, PubKeyAlgoEdDSA:
|
||||||
|
curveInfo := ecc.FindByOid(pk.oid)
|
||||||
|
if curveInfo == nil {
|
||||||
|
return "", errors.UnsupportedError(fmt.Sprintf("unknown oid: %x", pk.oid))
|
||||||
|
}
|
||||||
|
curve = Curve(curveInfo.GenName)
|
||||||
|
case PubKeyAlgoEd25519, PubKeyAlgoX25519:
|
||||||
|
curve = Curve25519
|
||||||
|
case PubKeyAlgoEd448, PubKeyAlgoX448:
|
||||||
|
curve = Curve448
|
||||||
|
default:
|
||||||
|
err = errors.InvalidArgumentError("public key does not operate with an elliptic curve")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// KeyExpired returns whether sig is a self-signature of a key that has
|
// KeyExpired returns whether sig is a self-signature of a key that has
|
||||||
// expired or is created in the future.
|
// expired or is created in the future.
|
||||||
func (pk *PublicKey) KeyExpired(sig *Signature, currentTime time.Time) bool {
|
func (pk *PublicKey) KeyExpired(sig *Signature, currentTime time.Time) bool {
|
||||||
if pk.CreationTime.After(currentTime) {
|
if pk.CreationTime.Unix() > currentTime.Unix() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if sig.KeyLifetimeSecs == nil || *sig.KeyLifetimeSecs == 0 {
|
if sig.KeyLifetimeSecs == nil || *sig.KeyLifetimeSecs == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
expiry := pk.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second)
|
expiry := pk.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second)
|
||||||
return currentTime.After(expiry)
|
return currentTime.Unix() > expiry.Unix()
|
||||||
}
|
}
|
||||||
|
159
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
generated
vendored
159
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/reader.go
generated
vendored
@ -10,6 +10,12 @@ import (
|
|||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PacketReader interface {
|
||||||
|
Next() (p Packet, err error)
|
||||||
|
Push(reader io.Reader) (err error)
|
||||||
|
Unread(p Packet)
|
||||||
|
}
|
||||||
|
|
||||||
// Reader reads packets from an io.Reader and allows packets to be 'unread' so
|
// Reader reads packets from an io.Reader and allows packets to be 'unread' so
|
||||||
// that they result from the next call to Next.
|
// that they result from the next call to Next.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
@ -26,37 +32,81 @@ type Reader struct {
|
|||||||
const maxReaders = 32
|
const maxReaders = 32
|
||||||
|
|
||||||
// Next returns the most recently unread Packet, or reads another packet from
|
// Next returns the most recently unread Packet, or reads another packet from
|
||||||
// the top-most io.Reader. Unknown packet types are skipped.
|
// the top-most io.Reader. Unknown/unsupported/Marker packet types are skipped.
|
||||||
func (r *Reader) Next() (p Packet, err error) {
|
func (r *Reader) Next() (p Packet, err error) {
|
||||||
|
for {
|
||||||
|
p, err := r.read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
if _, ok := err.(errors.UnknownPacketTypeError); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := err.(errors.UnsupportedError); ok {
|
||||||
|
switch p.(type) {
|
||||||
|
case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
//A marker packet MUST be ignored when received
|
||||||
|
switch p.(type) {
|
||||||
|
case *Marker:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the most recently unread Packet, or reads another packet from
|
||||||
|
// the top-most io.Reader. Unknown/Marker packet types are skipped while unsupported
|
||||||
|
// packets are returned as UnsupportedPacket type.
|
||||||
|
func (r *Reader) NextWithUnsupported() (p Packet, err error) {
|
||||||
|
for {
|
||||||
|
p, err = r.read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
if _, ok := err.(errors.UnknownPacketTypeError); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if casteErr, ok := err.(errors.UnsupportedError); ok {
|
||||||
|
return &UnsupportedPacket{
|
||||||
|
IncompletePacket: p,
|
||||||
|
Error: casteErr,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
//A marker packet MUST be ignored when received
|
||||||
|
switch p.(type) {
|
||||||
|
case *Marker:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) read() (p Packet, err error) {
|
||||||
if len(r.q) > 0 {
|
if len(r.q) > 0 {
|
||||||
p = r.q[len(r.q)-1]
|
p = r.q[len(r.q)-1]
|
||||||
r.q = r.q[:len(r.q)-1]
|
r.q = r.q[:len(r.q)-1]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for len(r.readers) > 0 {
|
for len(r.readers) > 0 {
|
||||||
p, err = Read(r.readers[len(r.readers)-1])
|
p, err = Read(r.readers[len(r.readers)-1])
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
r.readers = r.readers[:len(r.readers)-1]
|
r.readers = r.readers[:len(r.readers)-1]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO: Add strict mode that rejects unknown packets, instead of ignoring them.
|
return p, err
|
||||||
if _, ok := err.(errors.UnknownPacketTypeError); ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, ok := err.(errors.UnsupportedError); ok {
|
|
||||||
switch p.(type) {
|
|
||||||
case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, io.EOF
|
return nil, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,3 +134,76 @@ func NewReader(r io.Reader) *Reader {
|
|||||||
readers: []io.Reader{r},
|
readers: []io.Reader{r},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckReader is similar to Reader but additionally
|
||||||
|
// uses the pushdown automata to verify the read packet sequence.
|
||||||
|
type CheckReader struct {
|
||||||
|
Reader
|
||||||
|
verifier *SequenceVerifier
|
||||||
|
fullyRead bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the most recently unread Packet, or reads another packet from
|
||||||
|
// the top-most io.Reader. Unknown packet types are skipped.
|
||||||
|
// If the read packet sequence does not conform to the packet composition
|
||||||
|
// rules in rfc4880, it returns an error.
|
||||||
|
func (r *CheckReader) Next() (p Packet, err error) {
|
||||||
|
if r.fullyRead {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
if len(r.q) > 0 {
|
||||||
|
p = r.q[len(r.q)-1]
|
||||||
|
r.q = r.q[:len(r.q)-1]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var errMsg error
|
||||||
|
for len(r.readers) > 0 {
|
||||||
|
p, errMsg, err = ReadWithCheck(r.readers[len(r.readers)-1], r.verifier)
|
||||||
|
if errMsg != nil {
|
||||||
|
err = errMsg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
r.readers = r.readers[:len(r.readers)-1]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//A marker packet MUST be ignored when received
|
||||||
|
switch p.(type) {
|
||||||
|
case *Marker:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := err.(errors.UnknownPacketTypeError); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := err.(errors.UnsupportedError); ok {
|
||||||
|
switch p.(type) {
|
||||||
|
case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if errMsg = r.verifier.Next(EOSSymbol); errMsg != nil {
|
||||||
|
return nil, errMsg
|
||||||
|
}
|
||||||
|
if errMsg = r.verifier.AssertValid(); errMsg != nil {
|
||||||
|
return nil, errMsg
|
||||||
|
}
|
||||||
|
r.fullyRead = true
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCheckReader(r io.Reader) *CheckReader {
|
||||||
|
return &CheckReader{
|
||||||
|
Reader: Reader{
|
||||||
|
q: nil,
|
||||||
|
readers: []io.Reader{r},
|
||||||
|
},
|
||||||
|
verifier: NewSequenceVerifier(),
|
||||||
|
fullyRead: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
15
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/recipient.go
generated
vendored
Normal file
15
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/recipient.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package packet
|
||||||
|
|
||||||
|
// Recipient type represents a Intended Recipient Fingerprint subpacket
|
||||||
|
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-intended-recipient-fingerpr
|
||||||
|
type Recipient struct {
|
||||||
|
KeyVersion int
|
||||||
|
Fingerprint []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Recipient) Serialize() []byte {
|
||||||
|
packet := make([]byte, len(r.Fingerprint)+1)
|
||||||
|
packet[0] = byte(r.KeyVersion)
|
||||||
|
copy(packet[1:], r.Fingerprint)
|
||||||
|
return packet
|
||||||
|
}
|
747
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
generated
vendored
747
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/signature.go
generated
vendored
File diff suppressed because it is too large
Load Diff
89
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
generated
vendored
89
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetric_key_encrypted.go
generated
vendored
@ -7,11 +7,13 @@ package packet
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/sha256"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
"github.com/ProtonMail/go-crypto/openpgp/s2k"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is the largest session key that we'll support. Since at most 256-bit cipher
|
// This is the largest session key that we'll support. Since at most 256-bit cipher
|
||||||
@ -39,10 +41,21 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ske.Version = int(buf[0])
|
ske.Version = int(buf[0])
|
||||||
if ske.Version != 4 && ske.Version != 5 {
|
if ske.Version != 4 && ske.Version != 5 && ske.Version != 6 {
|
||||||
return errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
|
return errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if V5Disabled && ske.Version == 5 {
|
||||||
|
return errors.UnsupportedError("support for parsing v5 entities is disabled; build with `-tags v5` if needed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ske.Version > 5 {
|
||||||
|
// Scalar octet count
|
||||||
|
if _, err := readFull(r, buf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cipher function
|
// Cipher function
|
||||||
if _, err := readFull(r, buf[:]); err != nil {
|
if _, err := readFull(r, buf[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -52,7 +65,7 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
|
|||||||
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[0])))
|
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[0])))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ske.Version == 5 {
|
if ske.Version >= 5 {
|
||||||
// AEAD mode
|
// AEAD mode
|
||||||
if _, err := readFull(r, buf[:]); err != nil {
|
if _, err := readFull(r, buf[:]); err != nil {
|
||||||
return errors.StructuralError("cannot read AEAD octet from packet")
|
return errors.StructuralError("cannot read AEAD octet from packet")
|
||||||
@ -60,6 +73,13 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
|
|||||||
ske.Mode = AEADMode(buf[0])
|
ske.Mode = AEADMode(buf[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ske.Version > 5 {
|
||||||
|
// Scalar octet count
|
||||||
|
if _, err := readFull(r, buf[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if ske.s2k, err = s2k.Parse(r); err != nil {
|
if ske.s2k, err = s2k.Parse(r); err != nil {
|
||||||
if _, ok := err.(errors.ErrDummyPrivateKey); ok {
|
if _, ok := err.(errors.ErrDummyPrivateKey); ok {
|
||||||
@ -68,7 +88,7 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ske.Version == 5 {
|
if ske.Version >= 5 {
|
||||||
// AEAD IV
|
// AEAD IV
|
||||||
iv := make([]byte, ske.Mode.IvLength())
|
iv := make([]byte, ske.Mode.IvLength())
|
||||||
_, err := readFull(r, iv)
|
_, err := readFull(r, iv)
|
||||||
@ -109,8 +129,8 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunc
|
|||||||
case 4:
|
case 4:
|
||||||
plaintextKey, cipherFunc, err := ske.decryptV4(key)
|
plaintextKey, cipherFunc, err := ske.decryptV4(key)
|
||||||
return plaintextKey, cipherFunc, err
|
return plaintextKey, cipherFunc, err
|
||||||
case 5:
|
case 5, 6:
|
||||||
plaintextKey, err := ske.decryptV5(key)
|
plaintextKey, err := ske.aeadDecrypt(ske.Version, key)
|
||||||
return plaintextKey, CipherFunction(0), err
|
return plaintextKey, CipherFunction(0), err
|
||||||
}
|
}
|
||||||
err := errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
|
err := errors.UnsupportedError("unknown SymmetricKeyEncrypted version")
|
||||||
@ -136,9 +156,9 @@ func (ske *SymmetricKeyEncrypted) decryptV4(key []byte) ([]byte, CipherFunction,
|
|||||||
return plaintextKey, cipherFunc, nil
|
return plaintextKey, cipherFunc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ske *SymmetricKeyEncrypted) decryptV5(key []byte) ([]byte, error) {
|
func (ske *SymmetricKeyEncrypted) aeadDecrypt(version int, key []byte) ([]byte, error) {
|
||||||
adata := []byte{0xc3, byte(5), byte(ske.CipherFunc), byte(ske.Mode)}
|
adata := []byte{0xc3, byte(version), byte(ske.CipherFunc), byte(ske.Mode)}
|
||||||
aead := getEncryptedKeyAeadInstance(ske.CipherFunc, ske.Mode, key, adata)
|
aead := getEncryptedKeyAeadInstance(ske.CipherFunc, ske.Mode, key, adata, version)
|
||||||
|
|
||||||
plaintextKey, err := aead.Open(nil, ske.iv, ske.encryptedKey, adata)
|
plaintextKey, err := aead.Open(nil, ske.iv, ske.encryptedKey, adata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -175,10 +195,22 @@ func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Conf
|
|||||||
// the given passphrase. The returned session key must be passed to
|
// the given passphrase. The returned session key must be passed to
|
||||||
// SerializeSymmetricallyEncrypted.
|
// SerializeSymmetricallyEncrypted.
|
||||||
// If config is nil, sensible defaults will be used.
|
// If config is nil, sensible defaults will be used.
|
||||||
|
// Deprecated: Use SerializeSymmetricKeyEncryptedAEADReuseKey instead.
|
||||||
func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, config *Config) (err error) {
|
func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, config *Config) (err error) {
|
||||||
|
return SerializeSymmetricKeyEncryptedAEADReuseKey(w, sessionKey, passphrase, config.AEAD() != nil, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeSymmetricKeyEncryptedAEADReuseKey serializes a symmetric key packet to w.
|
||||||
|
// The packet contains the given session key, encrypted by a key derived from
|
||||||
|
// the given passphrase. The returned session key must be passed to
|
||||||
|
// SerializeSymmetricallyEncrypted.
|
||||||
|
// If aeadSupported is set, SKESK v6 is used, otherwise v4.
|
||||||
|
// Note: aeadSupported MUST match the value passed to SerializeSymmetricallyEncrypted.
|
||||||
|
// If config is nil, sensible defaults will be used.
|
||||||
|
func SerializeSymmetricKeyEncryptedAEADReuseKey(w io.Writer, sessionKey []byte, passphrase []byte, aeadSupported bool, config *Config) (err error) {
|
||||||
var version int
|
var version int
|
||||||
if config.AEAD() != nil {
|
if aeadSupported {
|
||||||
version = 5
|
version = 6
|
||||||
} else {
|
} else {
|
||||||
version = 4
|
version = 4
|
||||||
}
|
}
|
||||||
@ -203,11 +235,15 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
|
|||||||
switch version {
|
switch version {
|
||||||
case 4:
|
case 4:
|
||||||
packetLength = 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
|
packetLength = 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
|
||||||
case 5:
|
case 5, 6:
|
||||||
ivLen := config.AEAD().Mode().IvLength()
|
ivLen := config.AEAD().Mode().IvLength()
|
||||||
tagLen := config.AEAD().Mode().TagLength()
|
tagLen := config.AEAD().Mode().TagLength()
|
||||||
packetLength = 3 + len(s2kBytes) + ivLen + keySize + tagLen
|
packetLength = 3 + len(s2kBytes) + ivLen + keySize + tagLen
|
||||||
}
|
}
|
||||||
|
if version > 5 {
|
||||||
|
packetLength += 2 // additional octet count fields
|
||||||
|
}
|
||||||
|
|
||||||
err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
|
err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -216,13 +252,22 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
|
|||||||
// Symmetric Key Encrypted Version
|
// Symmetric Key Encrypted Version
|
||||||
buf := []byte{byte(version)}
|
buf := []byte{byte(version)}
|
||||||
|
|
||||||
|
if version > 5 {
|
||||||
|
// Scalar octet count
|
||||||
|
buf = append(buf, byte(3+len(s2kBytes)+config.AEAD().Mode().IvLength()))
|
||||||
|
}
|
||||||
|
|
||||||
// Cipher function
|
// Cipher function
|
||||||
buf = append(buf, byte(cipherFunc))
|
buf = append(buf, byte(cipherFunc))
|
||||||
|
|
||||||
if version == 5 {
|
if version >= 5 {
|
||||||
// AEAD mode
|
// AEAD mode
|
||||||
buf = append(buf, byte(config.AEAD().Mode()))
|
buf = append(buf, byte(config.AEAD().Mode()))
|
||||||
}
|
}
|
||||||
|
if version > 5 {
|
||||||
|
// Scalar octet count
|
||||||
|
buf = append(buf, byte(len(s2kBytes)))
|
||||||
|
}
|
||||||
_, err = w.Write(buf)
|
_, err = w.Write(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -243,10 +288,10 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 5:
|
case 5, 6:
|
||||||
mode := config.AEAD().Mode()
|
mode := config.AEAD().Mode()
|
||||||
adata := []byte{0xc3, byte(5), byte(cipherFunc), byte(mode)}
|
adata := []byte{0xc3, byte(version), byte(cipherFunc), byte(mode)}
|
||||||
aead := getEncryptedKeyAeadInstance(cipherFunc, mode, keyEncryptingKey, adata)
|
aead := getEncryptedKeyAeadInstance(cipherFunc, mode, keyEncryptingKey, adata, version)
|
||||||
|
|
||||||
// Sample iv using random reader
|
// Sample iv using random reader
|
||||||
iv := make([]byte, config.AEAD().Mode().IvLength())
|
iv := make([]byte, config.AEAD().Mode().IvLength())
|
||||||
@ -270,7 +315,17 @@ func SerializeSymmetricKeyEncryptedReuseKey(w io.Writer, sessionKey []byte, pass
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEncryptedKeyAeadInstance(c CipherFunction, mode AEADMode, inputKey, associatedData []byte) (aead cipher.AEAD) {
|
func getEncryptedKeyAeadInstance(c CipherFunction, mode AEADMode, inputKey, associatedData []byte, version int) (aead cipher.AEAD) {
|
||||||
blockCipher := c.new(inputKey)
|
var blockCipher cipher.Block
|
||||||
|
if version > 5 {
|
||||||
|
hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, associatedData)
|
||||||
|
|
||||||
|
encryptionKey := make([]byte, c.KeySize())
|
||||||
|
_, _ = readFull(hkdfReader, encryptionKey)
|
||||||
|
|
||||||
|
blockCipher = c.new(encryptionKey)
|
||||||
|
} else {
|
||||||
|
blockCipher = c.new(inputKey)
|
||||||
|
}
|
||||||
return mode.new(blockCipher)
|
return mode.new(blockCipher)
|
||||||
}
|
}
|
||||||
|
4
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
generated
vendored
4
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted.go
generated
vendored
@ -74,6 +74,10 @@ func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.Read
|
|||||||
// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
|
// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
|
||||||
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
|
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
|
||||||
// written.
|
// written.
|
||||||
|
// If aeadSupported is set to true, SEIPDv2 is used with the indicated CipherSuite.
|
||||||
|
// Otherwise, SEIPDv1 is used with the indicated CipherFunction.
|
||||||
|
// Note: aeadSupported MUST match the value passed to SerializeEncryptedKeyAEAD
|
||||||
|
// and/or SerializeSymmetricKeyEncryptedAEADReuseKey.
|
||||||
// If config is nil, sensible defaults will be used.
|
// If config is nil, sensible defaults will be used.
|
||||||
func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, aeadSupported bool, cipherSuite CipherSuite, key []byte, config *Config) (Contents io.WriteCloser, err error) {
|
func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, aeadSupported bool, cipherSuite CipherSuite, key []byte, config *Config) (Contents io.WriteCloser, err error) {
|
||||||
writeCloser := noOpCloser{w}
|
writeCloser := noOpCloser{w}
|
||||||
|
15
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go
generated
vendored
15
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_aead.go
generated
vendored
@ -7,7 +7,9 @@ package packet
|
|||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
"golang.org/x/crypto/hkdf"
|
"golang.org/x/crypto/hkdf"
|
||||||
@ -25,19 +27,19 @@ func (se *SymmetricallyEncrypted) parseAead(r io.Reader) error {
|
|||||||
se.Cipher = CipherFunction(headerData[0])
|
se.Cipher = CipherFunction(headerData[0])
|
||||||
// cipherFunc must have block size 16 to use AEAD
|
// cipherFunc must have block size 16 to use AEAD
|
||||||
if se.Cipher.blockSize() != 16 {
|
if se.Cipher.blockSize() != 16 {
|
||||||
return errors.UnsupportedError("invalid aead cipher: " + string(se.Cipher))
|
return errors.UnsupportedError("invalid aead cipher: " + strconv.Itoa(int(se.Cipher)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode
|
// Mode
|
||||||
se.Mode = AEADMode(headerData[1])
|
se.Mode = AEADMode(headerData[1])
|
||||||
if se.Mode.TagLength() == 0 {
|
if se.Mode.TagLength() == 0 {
|
||||||
return errors.UnsupportedError("unknown aead mode: " + string(se.Mode))
|
return errors.UnsupportedError("unknown aead mode: " + strconv.Itoa(int(se.Mode)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chunk size
|
// Chunk size
|
||||||
se.ChunkSizeByte = headerData[2]
|
se.ChunkSizeByte = headerData[2]
|
||||||
if se.ChunkSizeByte > 16 {
|
if se.ChunkSizeByte > 16 {
|
||||||
return errors.UnsupportedError("invalid aead chunk size byte: " + string(se.ChunkSizeByte))
|
return errors.UnsupportedError("invalid aead chunk size byte: " + strconv.Itoa(int(se.ChunkSizeByte)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Salt
|
// Salt
|
||||||
@ -62,8 +64,11 @@ func (se *SymmetricallyEncrypted) associatedData() []byte {
|
|||||||
// decryptAead decrypts a V2 SEIPD packet (AEAD) as specified in
|
// decryptAead decrypts a V2 SEIPD packet (AEAD) as specified in
|
||||||
// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
|
// https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#section-5.13.2
|
||||||
func (se *SymmetricallyEncrypted) decryptAead(inputKey []byte) (io.ReadCloser, error) {
|
func (se *SymmetricallyEncrypted) decryptAead(inputKey []byte) (io.ReadCloser, error) {
|
||||||
aead, nonce := getSymmetricallyEncryptedAeadInstance(se.Cipher, se.Mode, inputKey, se.Salt[:], se.associatedData())
|
if se.Cipher.KeySize() != len(inputKey) {
|
||||||
|
return nil, errors.StructuralError(fmt.Sprintf("invalid session key length for cipher: got %d bytes, but expected %d bytes", len(inputKey), se.Cipher.KeySize()))
|
||||||
|
}
|
||||||
|
|
||||||
|
aead, nonce := getSymmetricallyEncryptedAeadInstance(se.Cipher, se.Mode, inputKey, se.Salt[:], se.associatedData())
|
||||||
// Carry the first tagLen bytes
|
// Carry the first tagLen bytes
|
||||||
tagLen := se.Mode.TagLength()
|
tagLen := se.Mode.TagLength()
|
||||||
peekedBytes := make([]byte, tagLen)
|
peekedBytes := make([]byte, tagLen)
|
||||||
@ -115,7 +120,7 @@ func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite
|
|||||||
|
|
||||||
// Random salt
|
// Random salt
|
||||||
salt := make([]byte, aeadSaltSize)
|
salt := make([]byte, aeadSaltSize)
|
||||||
if _, err := rand.Read(salt); err != nil {
|
if _, err := io.ReadFull(rand, salt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_mdc.go
generated
vendored
10
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/symmetrically_encrypted_mdc.go
generated
vendored
@ -148,7 +148,7 @@ const mdcPacketTagByte = byte(0x80) | 0x40 | 19
|
|||||||
|
|
||||||
func (ser *seMDCReader) Close() error {
|
func (ser *seMDCReader) Close() error {
|
||||||
if ser.error {
|
if ser.error {
|
||||||
return errors.ErrMDCMissing
|
return errors.ErrMDCHashMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
for !ser.eof {
|
for !ser.eof {
|
||||||
@ -159,7 +159,7 @@ func (ser *seMDCReader) Close() error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.ErrMDCMissing
|
return errors.ErrMDCHashMismatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ func (ser *seMDCReader) Close() error {
|
|||||||
// The hash already includes the MDC header, but we still check its value
|
// The hash already includes the MDC header, but we still check its value
|
||||||
// to confirm encryption correctness
|
// to confirm encryption correctness
|
||||||
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
|
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
|
||||||
return errors.ErrMDCMissing
|
return errors.ErrMDCHashMismatch
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -237,9 +237,9 @@ func serializeSymmetricallyEncryptedMdc(ciphertext io.WriteCloser, c CipherFunct
|
|||||||
block := c.new(key)
|
block := c.new(key)
|
||||||
blockSize := block.BlockSize()
|
blockSize := block.BlockSize()
|
||||||
iv := make([]byte, blockSize)
|
iv := make([]byte, blockSize)
|
||||||
_, err = config.Random().Read(iv)
|
_, err = io.ReadFull(config.Random(), iv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
|
s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
|
||||||
_, err = ciphertext.Write(prefix)
|
_, err = ciphertext.Write(prefix)
|
||||||
|
3
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
generated
vendored
3
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userattribute.go
generated
vendored
@ -9,7 +9,6 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const UserAttrImageSubpacket = 1
|
const UserAttrImageSubpacket = 1
|
||||||
@ -63,7 +62,7 @@ func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute {
|
|||||||
|
|
||||||
func (uat *UserAttribute) parse(r io.Reader) (err error) {
|
func (uat *UserAttribute) parse(r io.Reader) (err error) {
|
||||||
// RFC 4880, section 5.13
|
// RFC 4880, section 5.13
|
||||||
b, err := ioutil.ReadAll(r)
|
b, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
3
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
generated
vendored
3
vendor/github.com/ProtonMail/go-crypto/openpgp/packet/userid.go
generated
vendored
@ -6,7 +6,6 @@ package packet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -66,7 +65,7 @@ func NewUserId(name, comment, email string) *UserId {
|
|||||||
|
|
||||||
func (uid *UserId) parse(r io.Reader) (err error) {
|
func (uid *UserId) parse(r io.Reader) (err error) {
|
||||||
// RFC 4880, section 5.11
|
// RFC 4880, section 5.11
|
||||||
b, err := ioutil.ReadAll(r)
|
b, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
115
vendor/github.com/ProtonMail/go-crypto/openpgp/read.go
generated
vendored
115
vendor/github.com/ProtonMail/go-crypto/openpgp/read.go
generated
vendored
@ -46,6 +46,7 @@ type MessageDetails struct {
|
|||||||
DecryptedWith Key // the private key used to decrypt the message, if any.
|
DecryptedWith Key // the private key used to decrypt the message, if any.
|
||||||
IsSigned bool // true if the message is signed.
|
IsSigned bool // true if the message is signed.
|
||||||
SignedByKeyId uint64 // the key id of the signer, if any.
|
SignedByKeyId uint64 // the key id of the signer, if any.
|
||||||
|
SignedByFingerprint []byte // the key fingerprint of the signer, if any.
|
||||||
SignedBy *Key // the key of the signer, if available.
|
SignedBy *Key // the key of the signer, if available.
|
||||||
LiteralData *packet.LiteralData // the metadata of the contents
|
LiteralData *packet.LiteralData // the metadata of the contents
|
||||||
UnverifiedBody io.Reader // the contents of the message.
|
UnverifiedBody io.Reader // the contents of the message.
|
||||||
@ -117,7 +118,7 @@ ParsePackets:
|
|||||||
// This packet contains the decryption key encrypted to a public key.
|
// This packet contains the decryption key encrypted to a public key.
|
||||||
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
|
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
|
||||||
switch p.Algo {
|
switch p.Algo {
|
||||||
case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH:
|
case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH, packet.PubKeyAlgoX25519, packet.PubKeyAlgoX448:
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
@ -232,7 +233,7 @@ FindKey:
|
|||||||
}
|
}
|
||||||
mdFinal, sensitiveParsingErr := readSignedMessage(packets, md, keyring, config)
|
mdFinal, sensitiveParsingErr := readSignedMessage(packets, md, keyring, config)
|
||||||
if sensitiveParsingErr != nil {
|
if sensitiveParsingErr != nil {
|
||||||
return nil, errors.StructuralError("parsing error")
|
return nil, errors.HandleSensitiveParsingError(sensitiveParsingErr, md.decrypted != nil)
|
||||||
}
|
}
|
||||||
return mdFinal, nil
|
return mdFinal, nil
|
||||||
}
|
}
|
||||||
@ -270,13 +271,17 @@ FindLiteralData:
|
|||||||
prevLast = true
|
prevLast = true
|
||||||
}
|
}
|
||||||
|
|
||||||
h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
|
h, wrappedHash, err = hashForSignature(p.Hash, p.SigType, p.Salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.SignatureError = err
|
md.SignatureError = err
|
||||||
}
|
}
|
||||||
|
|
||||||
md.IsSigned = true
|
md.IsSigned = true
|
||||||
|
if p.Version == 6 {
|
||||||
|
md.SignedByFingerprint = p.KeyFingerprint
|
||||||
|
}
|
||||||
md.SignedByKeyId = p.KeyId
|
md.SignedByKeyId = p.KeyId
|
||||||
|
|
||||||
if keyring != nil {
|
if keyring != nil {
|
||||||
keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
|
keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
@ -292,7 +297,7 @@ FindLiteralData:
|
|||||||
if md.IsSigned && md.SignatureError == nil {
|
if md.IsSigned && md.SignatureError == nil {
|
||||||
md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config}
|
md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config}
|
||||||
} else if md.decrypted != nil {
|
} else if md.decrypted != nil {
|
||||||
md.UnverifiedBody = checkReader{md}
|
md.UnverifiedBody = &checkReader{md, false}
|
||||||
} else {
|
} else {
|
||||||
md.UnverifiedBody = md.LiteralData.Body
|
md.UnverifiedBody = md.LiteralData.Body
|
||||||
}
|
}
|
||||||
@ -300,12 +305,22 @@ FindLiteralData:
|
|||||||
return md, nil
|
return md, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapHashForSignature(hashFunc hash.Hash, sigType packet.SignatureType) (hash.Hash, error) {
|
||||||
|
switch sigType {
|
||||||
|
case packet.SigTypeBinary:
|
||||||
|
return hashFunc, nil
|
||||||
|
case packet.SigTypeText:
|
||||||
|
return NewCanonicalTextHash(hashFunc), nil
|
||||||
|
}
|
||||||
|
return nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
|
||||||
|
}
|
||||||
|
|
||||||
// hashForSignature returns a pair of hashes that can be used to verify a
|
// hashForSignature returns a pair of hashes that can be used to verify a
|
||||||
// signature. The signature may specify that the contents of the signed message
|
// signature. The signature may specify that the contents of the signed message
|
||||||
// should be preprocessed (i.e. to normalize line endings). Thus this function
|
// should be preprocessed (i.e. to normalize line endings). Thus this function
|
||||||
// returns two hashes. The second should be used to hash the message itself and
|
// returns two hashes. The second should be used to hash the message itself and
|
||||||
// performs any needed preprocessing.
|
// performs any needed preprocessing.
|
||||||
func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
|
func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType, sigSalt []byte) (hash.Hash, hash.Hash, error) {
|
||||||
if _, ok := algorithm.HashToHashIdWithSha1(hashFunc); !ok {
|
if _, ok := algorithm.HashToHashIdWithSha1(hashFunc); !ok {
|
||||||
return nil, nil, errors.UnsupportedError("unsupported hash function")
|
return nil, nil, errors.UnsupportedError("unsupported hash function")
|
||||||
}
|
}
|
||||||
@ -313,14 +328,19 @@ func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType) (hash.
|
|||||||
return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashFunc)))
|
return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashFunc)))
|
||||||
}
|
}
|
||||||
h := hashFunc.New()
|
h := hashFunc.New()
|
||||||
|
if sigSalt != nil {
|
||||||
|
h.Write(sigSalt)
|
||||||
|
}
|
||||||
|
wrappedHash, err := wrapHashForSignature(h, sigType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
switch sigType {
|
switch sigType {
|
||||||
case packet.SigTypeBinary:
|
case packet.SigTypeBinary:
|
||||||
return h, h, nil
|
return h, wrappedHash, nil
|
||||||
case packet.SigTypeText:
|
case packet.SigTypeText:
|
||||||
return h, NewCanonicalTextHash(h), nil
|
return h, wrappedHash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
|
return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,21 +348,27 @@ func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType) (hash.
|
|||||||
// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
|
// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
|
||||||
// MDC checks.
|
// MDC checks.
|
||||||
type checkReader struct {
|
type checkReader struct {
|
||||||
md *MessageDetails
|
md *MessageDetails
|
||||||
|
checked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cr checkReader) Read(buf []byte) (int, error) {
|
func (cr *checkReader) Read(buf []byte) (int, error) {
|
||||||
n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf)
|
n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf)
|
||||||
if sensitiveParsingError == io.EOF {
|
if sensitiveParsingError == io.EOF {
|
||||||
|
if cr.checked {
|
||||||
|
// Only check once
|
||||||
|
return n, io.EOF
|
||||||
|
}
|
||||||
mdcErr := cr.md.decrypted.Close()
|
mdcErr := cr.md.decrypted.Close()
|
||||||
if mdcErr != nil {
|
if mdcErr != nil {
|
||||||
return n, mdcErr
|
return n, mdcErr
|
||||||
}
|
}
|
||||||
|
cr.checked = true
|
||||||
return n, io.EOF
|
return n, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
if sensitiveParsingError != nil {
|
if sensitiveParsingError != nil {
|
||||||
return n, errors.StructuralError("parsing error")
|
return n, errors.HandleSensitiveParsingError(sensitiveParsingError, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, nil
|
return n, nil
|
||||||
@ -366,6 +392,7 @@ func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
|
|||||||
scr.wrappedHash.Write(buf[:n])
|
scr.wrappedHash.Write(buf[:n])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readsDecryptedData := scr.md.decrypted != nil
|
||||||
if sensitiveParsingError == io.EOF {
|
if sensitiveParsingError == io.EOF {
|
||||||
var p packet.Packet
|
var p packet.Packet
|
||||||
var readError error
|
var readError error
|
||||||
@ -384,7 +411,7 @@ func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
|
|||||||
key := scr.md.SignedBy
|
key := scr.md.SignedBy
|
||||||
signatureError := key.PublicKey.VerifySignature(scr.h, sig)
|
signatureError := key.PublicKey.VerifySignature(scr.h, sig)
|
||||||
if signatureError == nil {
|
if signatureError == nil {
|
||||||
signatureError = checkSignatureDetails(key, sig, scr.config)
|
signatureError = checkMessageSignatureDetails(key, sig, scr.config)
|
||||||
}
|
}
|
||||||
scr.md.Signature = sig
|
scr.md.Signature = sig
|
||||||
scr.md.SignatureError = signatureError
|
scr.md.SignatureError = signatureError
|
||||||
@ -408,16 +435,15 @@ func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
|
|||||||
// unsigned hash of its own. In order to check this we need to
|
// unsigned hash of its own. In order to check this we need to
|
||||||
// close that Reader.
|
// close that Reader.
|
||||||
if scr.md.decrypted != nil {
|
if scr.md.decrypted != nil {
|
||||||
mdcErr := scr.md.decrypted.Close()
|
if sensitiveParsingError := scr.md.decrypted.Close(); sensitiveParsingError != nil {
|
||||||
if mdcErr != nil {
|
return n, errors.HandleSensitiveParsingError(sensitiveParsingError, true)
|
||||||
return n, mdcErr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n, io.EOF
|
return n, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
if sensitiveParsingError != nil {
|
if sensitiveParsingError != nil {
|
||||||
return n, errors.StructuralError("parsing error")
|
return n, errors.HandleSensitiveParsingError(sensitiveParsingError, readsDecryptedData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, nil
|
return n, nil
|
||||||
@ -428,14 +454,13 @@ func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
|
|||||||
// if any, and a possible signature verification error.
|
// if any, and a possible signature verification error.
|
||||||
// If the signer isn't known, ErrUnknownIssuer is returned.
|
// If the signer isn't known, ErrUnknownIssuer is returned.
|
||||||
func VerifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
|
func VerifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
|
||||||
var expectedHashes []crypto.Hash
|
return verifyDetachedSignature(keyring, signed, signature, nil, false, config)
|
||||||
return verifyDetachedSignature(keyring, signed, signature, expectedHashes, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyDetachedSignatureAndHash performs the same actions as
|
// VerifyDetachedSignatureAndHash performs the same actions as
|
||||||
// VerifyDetachedSignature and checks that the expected hash functions were used.
|
// VerifyDetachedSignature and checks that the expected hash functions were used.
|
||||||
func VerifyDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
|
func VerifyDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
|
||||||
return verifyDetachedSignature(keyring, signed, signature, expectedHashes, config)
|
return verifyDetachedSignature(keyring, signed, signature, expectedHashes, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckDetachedSignature takes a signed file and a detached signature and
|
// CheckDetachedSignature takes a signed file and a detached signature and
|
||||||
@ -443,25 +468,24 @@ func VerifyDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader
|
|||||||
// signature verification error. If the signer isn't known,
|
// signature verification error. If the signer isn't known,
|
||||||
// ErrUnknownIssuer is returned.
|
// ErrUnknownIssuer is returned.
|
||||||
func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
|
func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
|
||||||
var expectedHashes []crypto.Hash
|
_, signer, err = verifyDetachedSignature(keyring, signed, signature, nil, false, config)
|
||||||
return CheckDetachedSignatureAndHash(keyring, signed, signature, expectedHashes, config)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckDetachedSignatureAndHash performs the same actions as
|
// CheckDetachedSignatureAndHash performs the same actions as
|
||||||
// CheckDetachedSignature and checks that the expected hash functions were used.
|
// CheckDetachedSignature and checks that the expected hash functions were used.
|
||||||
func CheckDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (signer *Entity, err error) {
|
func CheckDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (signer *Entity, err error) {
|
||||||
_, signer, err = verifyDetachedSignature(keyring, signed, signature, expectedHashes, config)
|
_, signer, err = verifyDetachedSignature(keyring, signed, signature, expectedHashes, true, config)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
|
func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, checkHashes bool, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
|
||||||
var issuerKeyId uint64
|
var issuerKeyId uint64
|
||||||
var hashFunc crypto.Hash
|
var hashFunc crypto.Hash
|
||||||
var sigType packet.SignatureType
|
var sigType packet.SignatureType
|
||||||
var keys []Key
|
var keys []Key
|
||||||
var p packet.Packet
|
var p packet.Packet
|
||||||
|
|
||||||
expectedHashesLen := len(expectedHashes)
|
|
||||||
packets := packet.NewReader(signature)
|
packets := packet.NewReader(signature)
|
||||||
for {
|
for {
|
||||||
p, err = packets.Next()
|
p, err = packets.Next()
|
||||||
@ -483,16 +507,19 @@ func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expec
|
|||||||
issuerKeyId = *sig.IssuerKeyId
|
issuerKeyId = *sig.IssuerKeyId
|
||||||
hashFunc = sig.Hash
|
hashFunc = sig.Hash
|
||||||
sigType = sig.SigType
|
sigType = sig.SigType
|
||||||
|
if checkHashes {
|
||||||
for i, expectedHash := range expectedHashes {
|
matchFound := false
|
||||||
if hashFunc == expectedHash {
|
// check for hashes
|
||||||
break
|
for _, expectedHash := range expectedHashes {
|
||||||
|
if hashFunc == expectedHash {
|
||||||
|
matchFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if i+1 == expectedHashesLen {
|
if !matchFound {
|
||||||
return nil, nil, errors.StructuralError("hash algorithm mismatch with cleartext message headers")
|
return nil, nil, errors.StructuralError("hash algorithm or salt mismatch with cleartext message headers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
|
keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
break
|
break
|
||||||
@ -503,7 +530,11 @@ func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expec
|
|||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
h, wrappedHash, err := hashForSignature(hashFunc, sigType)
|
h, err := sig.PrepareVerify()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
wrappedHash, err := wrapHashForSignature(h, sigType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -515,7 +546,7 @@ func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expec
|
|||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
err = key.PublicKey.VerifySignature(h, sig)
|
err = key.PublicKey.VerifySignature(h, sig)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return sig, key.Entity, checkSignatureDetails(&key, sig, config)
|
return sig, key.Entity, checkMessageSignatureDetails(&key, sig, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,7 +564,7 @@ func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader,
|
|||||||
return CheckDetachedSignature(keyring, signed, body, config)
|
return CheckDetachedSignature(keyring, signed, body, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkSignatureDetails returns an error if:
|
// checkMessageSignatureDetails returns an error if:
|
||||||
// - The signature (or one of the binding signatures mentioned below)
|
// - The signature (or one of the binding signatures mentioned below)
|
||||||
// has a unknown critical notation data subpacket
|
// has a unknown critical notation data subpacket
|
||||||
// - The primary key of the signing entity is revoked
|
// - The primary key of the signing entity is revoked
|
||||||
@ -551,15 +582,11 @@ func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader,
|
|||||||
// NOTE: The order of these checks is important, as the caller may choose to
|
// NOTE: The order of these checks is important, as the caller may choose to
|
||||||
// ignore ErrSignatureExpired or ErrKeyExpired errors, but should never
|
// ignore ErrSignatureExpired or ErrKeyExpired errors, but should never
|
||||||
// ignore any other errors.
|
// ignore any other errors.
|
||||||
//
|
func checkMessageSignatureDetails(key *Key, signature *packet.Signature, config *packet.Config) error {
|
||||||
// TODO: Also return an error if:
|
|
||||||
// - The primary key is expired according to a direct-key signature
|
|
||||||
// - (For V5 keys only:) The direct-key signature (exists and) is expired
|
|
||||||
func checkSignatureDetails(key *Key, signature *packet.Signature, config *packet.Config) error {
|
|
||||||
now := config.Now()
|
now := config.Now()
|
||||||
primaryIdentity := key.Entity.PrimaryIdentity()
|
primarySelfSignature, primaryIdentity := key.Entity.PrimarySelfSignature()
|
||||||
signedBySubKey := key.PublicKey != key.Entity.PrimaryKey
|
signedBySubKey := key.PublicKey != key.Entity.PrimaryKey
|
||||||
sigsToCheck := []*packet.Signature{signature, primaryIdentity.SelfSignature}
|
sigsToCheck := []*packet.Signature{signature, primarySelfSignature}
|
||||||
if signedBySubKey {
|
if signedBySubKey {
|
||||||
sigsToCheck = append(sigsToCheck, key.SelfSignature, key.SelfSignature.EmbeddedSignature)
|
sigsToCheck = append(sigsToCheck, key.SelfSignature, key.SelfSignature.EmbeddedSignature)
|
||||||
}
|
}
|
||||||
@ -572,10 +599,10 @@ func checkSignatureDetails(key *Key, signature *packet.Signature, config *packet
|
|||||||
}
|
}
|
||||||
if key.Entity.Revoked(now) || // primary key is revoked
|
if key.Entity.Revoked(now) || // primary key is revoked
|
||||||
(signedBySubKey && key.Revoked(now)) || // subkey is revoked
|
(signedBySubKey && key.Revoked(now)) || // subkey is revoked
|
||||||
primaryIdentity.Revoked(now) { // primary identity is revoked
|
(primaryIdentity != nil && primaryIdentity.Revoked(now)) { // primary identity is revoked for v4
|
||||||
return errors.ErrKeyRevoked
|
return errors.ErrKeyRevoked
|
||||||
}
|
}
|
||||||
if key.Entity.PrimaryKey.KeyExpired(primaryIdentity.SelfSignature, now) { // primary key is expired
|
if key.Entity.PrimaryKey.KeyExpired(primarySelfSignature, now) { // primary key is expired
|
||||||
return errors.ErrKeyExpired
|
return errors.ErrKeyExpired
|
||||||
}
|
}
|
||||||
if signedBySubKey {
|
if signedBySubKey {
|
||||||
|
201
vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
generated
vendored
201
vendor/github.com/ProtonMail/go-crypto/openpgp/read_write_test_data.go
generated
vendored
@ -26,6 +26,8 @@ const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a43129
|
|||||||
|
|
||||||
const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
|
const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
|
||||||
|
|
||||||
|
const ed25519wX25519Key = "c54b0663877fe31b00000020f94da7bb48d60a61e567706a6587d0331999bb9d891a08242ead84543df895a3001972817b12be707e8d5f586ce61361201d344eb266a2c82fde6835762b65b0b7c2b1061f1b0a00000042058263877fe3030b090705150a0e080c021600029b03021e09222106cb186c4f0609a697e4d52dfa6c722b0c1f1e27c18a56708f6525ec27bad9acc905270902070200000000ad2820103e2d7d227ec0e6d7ce4471db36bfc97083253690271498a7ef0576c07faae14585b3b903b0127ec4fda2f023045a2ec76bcb4f9571a9651e14aee1137a1d668442c88f951e33c4ffd33fb9a17d511eed758fc6d9cc50cb5fd793b2039d5804c74b0663877fe319000000208693248367f9e5015db922f8f48095dda784987f2d5985b12fbad16caf5e4435004d600a4f794d44775c57a26e0feefed558e9afffd6ad0d582d57fb2ba2dcedb8c29b06181b0a0000002c050263877fe322a106cb186c4f0609a697e4d52dfa6c722b0c1f1e27c18a56708f6525ec27bad9acc9021b0c00000000defa20a6e9186d9d5935fc8fe56314cdb527486a5a5120f9b762a235a729f039010a56b89c658568341fbef3b894e9834ad9bc72afae2f4c9c47a43855e65f1cb0a3f77bbc5f61085c1f8249fe4e7ca59af5f0bcee9398e0fa8d76e522e1d8ab42bb0d"
|
||||||
|
|
||||||
const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
|
const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
|
||||||
|
|
||||||
const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
|
const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
|
||||||
@ -160,18 +162,78 @@ TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw==
|
|||||||
=IiS2
|
=IiS2
|
||||||
-----END PGP PRIVATE KEY BLOCK-----`
|
-----END PGP PRIVATE KEY BLOCK-----`
|
||||||
|
|
||||||
// Generated with the above private key
|
// See OpenPGP crypto refresh Section A.3.
|
||||||
const v5PrivKeyMsg = `-----BEGIN PGP MESSAGE-----
|
const v6PrivKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
Version: OpenPGP.js v4.10.7
|
|
||||||
Comment: https://openpgpjs.org
|
|
||||||
|
|
||||||
xA0DAQoWGTR7yYckZAIByxF1B21zZy50eHRfbIGSdGVzdMJ3BQEWCgAGBQJf
|
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||||||
bIGSACMiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVDQvAP9G
|
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||||||
y29VPonFXqi2zKkpZrvyvZxg+n5e8Nt9wNbuxeCd3QD/TtO2s+JvjrE4Siwv
|
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||||||
UQdl5MlBka1QSNbMq2Bz7XwNPg4=
|
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||||||
=6lbM
|
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||||||
|
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||||||
|
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||||||
|
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||||||
|
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||||||
|
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||||||
|
k0mXubZvyl4GBg==
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----`
|
||||||
|
|
||||||
|
// See OpenPGP crypto refresh merge request:
|
||||||
|
// https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/304
|
||||||
|
const v6PrivKeyMsg = `-----BEGIN PGP MESSAGE-----
|
||||||
|
|
||||||
|
wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
|
||||||
|
WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
|
||||||
|
aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
|
||||||
|
yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
|
||||||
|
bhF30A+IitsxxA==
|
||||||
-----END PGP MESSAGE-----`
|
-----END PGP MESSAGE-----`
|
||||||
|
|
||||||
|
// See OpenPGP crypto refresh merge request:
|
||||||
|
// https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/305
|
||||||
|
const v6PrivKeyInlineSignMsg = `-----BEGIN PGP MESSAGE-----
|
||||||
|
|
||||||
|
wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO
|
||||||
|
WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS
|
||||||
|
aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l
|
||||||
|
yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo
|
||||||
|
bhF30A+IitsxxA==
|
||||||
|
-----END PGP MESSAGE-----`
|
||||||
|
|
||||||
|
// See https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/274
|
||||||
|
// decryption password: "correct horse battery staple"
|
||||||
|
const v6ArgonSealedPrivKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
xYIGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laP9JgkC
|
||||||
|
FARdb9ccngltHraRe25uHuyuAQQVtKipJ0+r5jL4dacGWSAheCWPpITYiyfyIOPS
|
||||||
|
3gIDyg8f7strd1OB4+LZsUhcIjOMpVHgmiY/IutJkulneoBYwrEGHxsKAAAAQgWC
|
||||||
|
Y4d/4wMLCQcFFQoOCAwCFgACmwMCHgkiIQbLGGxPBgmml+TVLfpscisMHx4nwYpW
|
||||||
|
cI9lJewnutmsyQUnCQIHAgAAAACtKCAQPi19In7A5tfORHHbNr/JcIMlNpAnFJin
|
||||||
|
7wV2wH+q4UWFs7kDsBJ+xP2i8CMEWi7Ha8tPlXGpZR4UruETeh1mhELIj5UeM8T/
|
||||||
|
0z+5oX1RHu11j8bZzFDLX9eTsgOdWATHggZjh3/jGQAAACCGkySDZ/nlAV25Ivj0
|
||||||
|
gJXdp4SYfy1ZhbEvutFsr15ENf0mCQIUBA5hhGgp2oaavg6mFUXcFMwBBBUuE8qf
|
||||||
|
9Ock+xwusd+GAglBr5LVyr/lup3xxQvHXFSjjA2haXfoN6xUGRdDEHI6+uevKjVR
|
||||||
|
v5oAxgu7eJpaXNjCmwYYGwoAAAAsBYJjh3/jApsMIiEGyxhsTwYJppfk1S36bHIr
|
||||||
|
DB8eJ8GKVnCPZSXsJ7rZrMkAAAAABAEgpukYbZ1ZNfyP5WMUzbUnSGpaUSD5t2Ki
|
||||||
|
Nacp8DkBClZRa2c3AMQzSDXa9jGhYzxjzVb5scHDzTkjyRZWRdTq8U6L4da+/+Kt
|
||||||
|
ruh8m7Xo2ehSSFyWRSuTSZe5tm/KXgYG
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----`
|
||||||
|
|
||||||
|
const v4Key25519 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
xUkEZB3qzRto01j2k2pwN5ux9w70stPinAdXULLr20CRW7U7h2GSeACch0M+
|
||||||
|
qzQg8yjFQ8VBvu3uwgKH9senoHmj72lLSCLTmhFKzQR0ZXN0wogEEBsIAD4F
|
||||||
|
gmQd6s0ECwkHCAmQIf45+TuC+xMDFQgKBBYAAgECGQECmwMCHgEWIQSWEzMi
|
||||||
|
jJUHvyIbVKIh/jn5O4L7EwAAUhaHNlgudvxARdPPETUzVgjuWi+YIz8w1xIb
|
||||||
|
lHQMvIrbe2sGCQIethpWofd0x7DHuv/ciHg+EoxJ/Td6h4pWtIoKx0kEZB3q
|
||||||
|
zRm4CyA7quliq7yx08AoOqHTuuCgvpkSdEhpp3pEyejQOgBo0p6ywIiLPllY
|
||||||
|
0t+jpNspHpAGfXID6oqjpYuJw3AfVRBlwnQEGBsIACoFgmQd6s0JkCH+Ofk7
|
||||||
|
gvsTApsMFiEElhMzIoyVB78iG1SiIf45+TuC+xMAAGgQuN9G73446ykvJ/mL
|
||||||
|
sCZ7zGFId2gBd1EnG0FTC4npfOKpck0X8dngByrCxU8LDSfvjsEp/xDAiKsQ
|
||||||
|
aU71tdtNBQ==
|
||||||
|
=e7jT
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----`
|
||||||
|
|
||||||
const keyWithExpiredCrossSig = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
const keyWithExpiredCrossSig = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
xsDNBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
|
xsDNBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
|
||||||
@ -272,3 +334,124 @@ AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY
|
|||||||
hz3tYjKhoFTKEIq3y3Pp
|
hz3tYjKhoFTKEIq3y3Pp
|
||||||
=h/aX
|
=h/aX
|
||||||
-----END PGP PUBLIC KEY BLOCK-----`
|
-----END PGP PUBLIC KEY BLOCK-----`
|
||||||
|
|
||||||
|
const keyv5Test = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Comment: Bob's OpenPGP Transferable Secret Key
|
||||||
|
|
||||||
|
lQVYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
|
||||||
|
/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz
|
||||||
|
/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/
|
||||||
|
5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3
|
||||||
|
X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv
|
||||||
|
9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0
|
||||||
|
qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb
|
||||||
|
SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb
|
||||||
|
vLIwa3T4CyshfT0AEQEAAQAL/RZqbJW2IqQDCnJi4Ozm++gPqBPiX1RhTWSjwxfM
|
||||||
|
cJKUZfzLj414rMKm6Jh1cwwGY9jekROhB9WmwaaKT8HtcIgrZNAlYzANGRCM4TLK
|
||||||
|
3VskxfSwKKna8l+s+mZglqbAjUg3wmFuf9Tj2xcUZYmyRm1DEmcN2ZzpvRtHgX7z
|
||||||
|
Wn1mAKUlSDJZSQks0zjuMNbupcpyJokdlkUg2+wBznBOTKzgMxVNC9b2g5/tMPUs
|
||||||
|
hGGWmF1UH+7AHMTaS6dlmr2ZBIyogdnfUqdNg5sZwsxSNrbglKP4sqe7X61uEAIQ
|
||||||
|
bD7rT3LonLbhkrj3I8wilUD8usIwt5IecoHhd9HziqZjRCc1BUBkboUEoyedbDV4
|
||||||
|
i4qfsFZ6CEWoLuD5pW7dEp0M+WeuHXO164Rc+LnH6i1VQrpb1Okl4qO6ejIpIjBI
|
||||||
|
1t3GshtUu/mwGBBxs60KBX5g77mFQ9lLCRj8lSYqOsHRKBhUp4qM869VA+fD0BRP
|
||||||
|
fqPT0I9IH4Oa/A3jYJcg622GwQYA1LhnP208Waf6PkQSJ6kyr8ymY1yVh9VBE/g6
|
||||||
|
fRDYA+pkqKnw9wfH2Qho3ysAA+OmVOX8Hldg+Pc0Zs0e5pCavb0En8iFLvTA0Q2E
|
||||||
|
LR5rLue9uD7aFuKFU/VdcddY9Ww/vo4k5p/tVGp7F8RYCFn9rSjIWbfvvZi1q5Tx
|
||||||
|
+akoZbga+4qQ4WYzB/obdX6SCmi6BndcQ1QdjCCQU6gpYx0MddVERbIp9+2SXDyL
|
||||||
|
hpxjSyz+RGsZi/9UAshT4txP4+MZBgDfK3ZqtW+h2/eMRxkANqOJpxSjMyLO/FXN
|
||||||
|
WxzTDYeWtHNYiAlOwlQZEPOydZFty9IVzzNFQCIUCGjQ/nNyhw7adSgUk3+BXEx/
|
||||||
|
MyJPYY0BYuhLxLYcrfQ9nrhaVKxRJj25SVHj2ASsiwGJRZW4CC3uw40OYxfKEvNC
|
||||||
|
mer/VxM3kg8qqGf9KUzJ1dVdAvjyx2Hz6jY2qWCyRQ6IMjWHyd43C4r3jxooYKUC
|
||||||
|
YnstRQyb/gCSKahveSEjo07CiXMr88UGALwzEr3npFAsPW3osGaFLj49y1oRe11E
|
||||||
|
he9gCHFm+fuzbXrWmdPjYU5/ZdqdojzDqfu4ThfnipknpVUM1o6MQqkjM896FHm8
|
||||||
|
zbKVFSMhEP6DPHSCexMFrrSgN03PdwHTO6iBaIBBFqmGY01tmJ03SxvSpiBPON9P
|
||||||
|
NVvy/6UZFedTq8A07OUAxO62YUSNtT5pmK2vzs3SAZJmbFbMh+NN204TRI72GlqT
|
||||||
|
t5hcfkuv8hrmwPS/ZR6q312mKQ6w/1pqO9qitCFCb2IgQmFiYmFnZSA8Ym9iQG9w
|
||||||
|
ZW5wZ3AuZXhhbXBsZT6JAc4EEwEKADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC
|
||||||
|
F4AWIQTRpm4aI7GCyZgPeIz7/MgqAV5zMAUCXaWe+gAKCRD7/MgqAV5zMG9sC/9U
|
||||||
|
2T3RrqEbw533FPNfEflhEVRIZ8gDXKM8hU6cqqEzCmzZT6xYTe6sv4y+PJBGXJFX
|
||||||
|
yhj0g6FDkSyboM5litOcTupURObVqMgA/Y4UKERznm4fzzH9qek85c4ljtLyNufe
|
||||||
|
doL2pp3vkGtn7eD0QFRaLLmnxPKQ/TlZKdLE1G3u8Uot8QHicaR6GnAdc5UXQJE3
|
||||||
|
BiV7jZuDyWmZ1cUNwJkKL6oRtp+ZNDOQCrLNLecKHcgCqrpjSQG5oouba1I1Q6Vl
|
||||||
|
sP44dhA1nkmLHtxlTOzpeHj4jnk1FaXmyasurrrI5CgU/L2Oi39DGKTH/A/cywDN
|
||||||
|
4ZplIQ9zR8enkbXquUZvFDe+Xz+6xRXtb5MwQyWODB3nHw85HocLwRoIN9WdQEI+
|
||||||
|
L8a/56AuOwhs8llkSuiITjR7r9SgKJC2WlAHl7E8lhJ3VDW3ELC56KH308d6mwOG
|
||||||
|
ZRAqIAKzM1T5FGjMBhq7ZV0eqdEntBh3EcOIfj2M8rg1MzJv+0mHZOIjByawikad
|
||||||
|
BVgEXaWc8gEMANYwv1xsYyunXYK0X1vY/rP1NNPvhLyLIE7NpK90YNBj+xS1ldGD
|
||||||
|
bUdZqZeef2xJe8gMQg05DoD1DF3GipZ0Ies65beh+d5hegb7N4pzh0LzrBrVNHar
|
||||||
|
29b5ExdI7i4iYD5TO6Vr/qTUOiAN/byqELEzAb+L+b2DVz/RoCm4PIp1DU9ewcc2
|
||||||
|
WB38Ofqut3nLYA5tqJ9XvAiEQme+qAVcM3ZFcaMt4I4dXhDZZNg+D9LiTWcxdUPB
|
||||||
|
leu8iwDRjAgyAhPzpFp+nWoqWA81uIiULWD1Fj+IVoY3ZvgivoYOiEFBJ9lbb4te
|
||||||
|
g9m5UT/AaVDTWuHzbspVlbiVe+qyB77C2daWzNyx6UYBPLOo4r0t0c91kbNE5lgj
|
||||||
|
Z7xz6los0N1U8vq91EFSeQJoSQ62XWavYmlCLmdNT6BNfgh4icLsT7Vr1QMX9jzn
|
||||||
|
JtTPxdXytSdHvpSpULsqJ016l0dtmONcK3z9mj5N5z0k1tg1AH970TGYOe2aUcSx
|
||||||
|
IRDMXDOPyzEfjwARAQABAAv9F2CwsjS+Sjh1M1vegJbZjei4gF1HHpEM0K0PSXsp
|
||||||
|
SfVvpR4AoSJ4He6CXSMWg0ot8XKtDuZoV9jnJaES5UL9pMAD7JwIOqZm/DYVJM5h
|
||||||
|
OASCh1c356/wSbFbzRHPtUdZO9Q30WFNJM5pHbCJPjtNoRmRGkf71RxtvHBzy7np
|
||||||
|
Ga+W6U/NVKHw0i0CYwMI0YlKDakYW3Pm+QL+gHZFvngGweTod0f9l2VLLAmeQR/c
|
||||||
|
+EZs7lNumhuZ8mXcwhUc9JQIhOkpO+wreDysEFkAcsKbkQP3UDUsA1gFx9pbMzT0
|
||||||
|
tr1oZq2a4QBtxShHzP/ph7KLpN+6qtjks3xB/yjTgaGmtrwM8tSe0wD1RwXS+/1o
|
||||||
|
BHpXTnQ7TfeOGUAu4KCoOQLv6ELpKWbRBLWuiPwMdbGpvVFALO8+kvKAg9/r+/ny
|
||||||
|
zM2GQHY+J3Jh5JxPiJnHfXNZjIKLbFbIPdSKNyJBuazXW8xIa//mEHMI5OcvsZBK
|
||||||
|
clAIp7LXzjEjKXIwHwDcTn9pBgDpdOKTHOtJ3JUKx0rWVsDH6wq6iKV/FTVSY5jl
|
||||||
|
zN+puOEsskF1Lfxn9JsJihAVO3yNsp6RvkKtyNlFazaCVKtDAmkjoh60XNxcNRqr
|
||||||
|
gCnwdpbgdHP6v/hvZY54ZaJjz6L2e8unNEkYLxDt8cmAyGPgH2XgL7giHIp9jrsQ
|
||||||
|
aS381gnYwNX6wE1aEikgtY91nqJjwPlibF9avSyYQoMtEqM/1UjTjB2KdD/MitK5
|
||||||
|
fP0VpvuXpNYZedmyq4UOMwdkiNMGAOrfmOeT0olgLrTMT5H97Cn3Yxbk13uXHNu/
|
||||||
|
ZUZZNe8s+QtuLfUlKAJtLEUutN33TlWQY522FV0m17S+b80xJib3yZVJteVurrh5
|
||||||
|
HSWHAM+zghQAvCesg5CLXa2dNMkTCmZKgCBvfDLZuZbjFwnwCI6u/NhOY9egKuUf
|
||||||
|
SA/je/RXaT8m5VxLYMxwqQXKApzD87fv0tLPlVIEvjEsaf992tFEFSNPcG1l/jpd
|
||||||
|
5AVXw6kKuf85UkJtYR1x2MkQDrqY1QX/XMw00kt8y9kMZUre19aCArcmor+hDhRJ
|
||||||
|
E3Gt4QJrD9z/bICESw4b4z2DbgD/Xz9IXsA/r9cKiM1h5QMtXvuhyfVeM01enhxM
|
||||||
|
GbOH3gjqqGNKysx0UODGEwr6AV9hAd8RWXMchJLaExK9J5SRawSg671ObAU24SdY
|
||||||
|
vMQ9Z4kAQ2+1ReUZzf3ogSMRZtMT+d18gT6L90/y+APZIaoArLPhebIAGq39HLmJ
|
||||||
|
26x3z0WAgrpA1kNsjXEXkoiZGPLKIGoe3hqJAbYEGAEKACAWIQTRpm4aI7GCyZgP
|
||||||
|
eIz7/MgqAV5zMAUCXaWc8gIbDAAKCRD7/MgqAV5zMOn/C/9ugt+HZIwX308zI+QX
|
||||||
|
c5vDLReuzmJ3ieE0DMO/uNSC+K1XEioSIZP91HeZJ2kbT9nn9fuReuoff0T0Dief
|
||||||
|
rbwcIQQHFFkrqSp1K3VWmUGp2JrUsXFVdjy/fkBIjTd7c5boWljv/6wAsSfiv2V0
|
||||||
|
JSM8EFU6TYXxswGjFVfc6X97tJNeIrXL+mpSmPPqy2bztcCCHkWS5lNLWQw+R7Vg
|
||||||
|
71Fe6yBSNVrqC2/imYG2J9zlowjx1XU63Wdgqp2Wxt0l8OmsB/W80S1fRF5G4SDH
|
||||||
|
s9HXglXXqPsBRZJYfP+VStm9L5P/sKjCcX6WtZR7yS6G8zj/X767MLK/djANvpPd
|
||||||
|
NVniEke6hM3CNBXYPAMhQBMWhCulcoz+0lxi8L34rMN+Dsbma96psdUrn7uLaB91
|
||||||
|
6we0CTfF8qqm7BsVAgalon/UUiuMY80U3ueoj3okiSTiHIjD/YtpXSPioC8nMng7
|
||||||
|
xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE=
|
||||||
|
=miES
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
|
`
|
||||||
|
|
||||||
|
const certv5Test = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
lGEFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd
|
||||||
|
fj75iux+my8QAAAAAAAiAQCHZ1SnSUmWqxEsoI6facIVZQu6mph3cBFzzTvcm5lA
|
||||||
|
Ng5ctBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0e8mHJGQC
|
||||||
|
X5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyICAQYVCgkI
|
||||||
|
CwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3wwJAXRJy9
|
||||||
|
M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2BZxmBVyR9OQSAAAA
|
||||||
|
MgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0YvYWWAoD
|
||||||
|
AQgHAAAAAAAiAP9OdAPppjU1WwpqjIItkxr+VPQRT8Zm/Riw7U3F6v3OiBFHiHoF
|
||||||
|
GBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVAUCXJH05AIb
|
||||||
|
DAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijhob2U5AQC+RtOHCHx7
|
||||||
|
TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw==
|
||||||
|
=IiS2
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
|
`
|
||||||
|
|
||||||
|
const msgv5Test = `-----BEGIN PGP MESSAGE-----
|
||||||
|
|
||||||
|
wcDMA3wvqk35PDeyAQv+PcQiLsoYTH30nJYQh3j3cJaO2+jErtVCrIQRIU0+
|
||||||
|
rmgMddERYST4A9mA0DQIiTI4FQ0Lp440D3BWCgpq3LlNWewGzduaWwym5rN6
|
||||||
|
cwHz5ccDqOcqbd9X0GXXGy/ZH/ljSgzuVMIytMAXKdF/vrRrVgH/+I7cxvm9
|
||||||
|
HwnhjMN5dF0j4aEt996H2T7cbtzSr2GN9SWGW8Gyu7I8Zx73hgrGUI7gDiJB
|
||||||
|
Afaff+P6hfkkHSGOItr94dde8J/7AUF4VEwwxdVVPvsNEFyvv6gRIbYtOCa2
|
||||||
|
6RE6h1V/QTxW2O7zZgzWALrE2ui0oaYr9QuqQSssd9CdgExLfdPbI+3/ZAnE
|
||||||
|
v31Idzpk3/6ILiakYHtXkElPXvf46mCNpobty8ysT34irF+fy3C1p3oGwAsx
|
||||||
|
5VDV9OSFU6z5U+UPbSPYAy9rkc5ZssuIKxCER2oTvZ2L8Q5cfUvEUiJtRGGn
|
||||||
|
CJlHrVDdp3FssKv2tlKgLkvxJLyoOjuEkj44H1qRk+D02FzmmUT/0sAHAYYx
|
||||||
|
lTir6mjHeLpcGjn4waUuWIAJyph8SxUexP60bic0L0NBa6Qp5SxxijKsPIDb
|
||||||
|
FPHxWwfJSDZRrgUyYT7089YFB/ZM4FHyH9TZcnxn0f0xIB7NS6YNDsxzN2zT
|
||||||
|
EVEYf+De4qT/dQTsdww78Chtcv9JY9r2kDm77dk2MUGHL2j7n8jasbLtgA7h
|
||||||
|
pn2DMIWLrGamMLWRmlwslolKr1sMV5x8w+5Ias6C33iBMl9phkg42an0gYmc
|
||||||
|
byVJHvLO/XErtC+GNIJeMg==
|
||||||
|
=liRq
|
||||||
|
-----END PGP MESSAGE-----
|
||||||
|
`
|
||||||
|
45
vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
generated
vendored
45
vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k.go
generated
vendored
@ -87,10 +87,10 @@ func decodeCount(c uint8) int {
|
|||||||
// encodeMemory converts the Argon2 "memory" in the range parallelism*8 to
|
// encodeMemory converts the Argon2 "memory" in the range parallelism*8 to
|
||||||
// 2**31, inclusive, to an encoded memory. The return value is the
|
// 2**31, inclusive, to an encoded memory. The return value is the
|
||||||
// octet that is actually stored in the GPG file. encodeMemory panics
|
// octet that is actually stored in the GPG file. encodeMemory panics
|
||||||
// if is not in the above range
|
// if is not in the above range
|
||||||
// See OpenPGP crypto refresh Section 3.7.1.4.
|
// See OpenPGP crypto refresh Section 3.7.1.4.
|
||||||
func encodeMemory(memory uint32, parallelism uint8) uint8 {
|
func encodeMemory(memory uint32, parallelism uint8) uint8 {
|
||||||
if memory < (8 * uint32(parallelism)) || memory > uint32(2147483648) {
|
if memory < (8*uint32(parallelism)) || memory > uint32(2147483648) {
|
||||||
panic("Memory argument memory is outside the required range")
|
panic("Memory argument memory is outside the required range")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +199,8 @@ func Generate(rand io.Reader, c *Config) (*Params, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params = &Params{
|
params = &Params{
|
||||||
mode: SaltedS2K,
|
mode: SaltedS2K,
|
||||||
hashId: hashId,
|
hashId: hashId,
|
||||||
}
|
}
|
||||||
} else { // Enforce IteratedSaltedS2K method otherwise
|
} else { // Enforce IteratedSaltedS2K method otherwise
|
||||||
hashId, ok := algorithm.HashToHashId(c.hash())
|
hashId, ok := algorithm.HashToHashId(c.hash())
|
||||||
@ -211,7 +211,7 @@ func Generate(rand io.Reader, c *Config) (*Params, error) {
|
|||||||
c.S2KMode = IteratedSaltedS2K
|
c.S2KMode = IteratedSaltedS2K
|
||||||
}
|
}
|
||||||
params = &Params{
|
params = &Params{
|
||||||
mode: IteratedSaltedS2K,
|
mode: IteratedSaltedS2K,
|
||||||
hashId: hashId,
|
hashId: hashId,
|
||||||
countByte: c.EncodedCount(),
|
countByte: c.EncodedCount(),
|
||||||
}
|
}
|
||||||
@ -283,6 +283,9 @@ func ParseIntoParams(r io.Reader) (params *Params, err error) {
|
|||||||
params.passes = buf[Argon2SaltSize]
|
params.passes = buf[Argon2SaltSize]
|
||||||
params.parallelism = buf[Argon2SaltSize+1]
|
params.parallelism = buf[Argon2SaltSize+1]
|
||||||
params.memoryExp = buf[Argon2SaltSize+2]
|
params.memoryExp = buf[Argon2SaltSize+2]
|
||||||
|
if err := validateArgon2Params(params); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return params, nil
|
return params, nil
|
||||||
case GnuS2K:
|
case GnuS2K:
|
||||||
// This is a GNU extension. See
|
// This is a GNU extension. See
|
||||||
@ -300,15 +303,22 @@ func ParseIntoParams(r io.Reader) (params *Params, err error) {
|
|||||||
return nil, errors.UnsupportedError("S2K function")
|
return nil, errors.UnsupportedError("S2K function")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (params *Params) Mode() Mode {
|
||||||
|
return params.mode
|
||||||
|
}
|
||||||
|
|
||||||
func (params *Params) Dummy() bool {
|
func (params *Params) Dummy() bool {
|
||||||
return params != nil && params.mode == GnuS2K
|
return params != nil && params.mode == GnuS2K
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *Params) salt() []byte {
|
func (params *Params) salt() []byte {
|
||||||
switch params.mode {
|
switch params.mode {
|
||||||
case SaltedS2K, IteratedSaltedS2K: return params.saltBytes[:8]
|
case SaltedS2K, IteratedSaltedS2K:
|
||||||
case Argon2S2K: return params.saltBytes[:Argon2SaltSize]
|
return params.saltBytes[:8]
|
||||||
default: return nil
|
case Argon2S2K:
|
||||||
|
return params.saltBytes[:Argon2SaltSize]
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,3 +415,22 @@ func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Co
|
|||||||
f(key, passphrase)
|
f(key, passphrase)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateArgon2Params checks that the argon2 parameters are valid according to RFC9580.
|
||||||
|
func validateArgon2Params(params *Params) error {
|
||||||
|
// The number of passes t and the degree of parallelism p MUST be non-zero.
|
||||||
|
if params.parallelism == 0 {
|
||||||
|
return errors.StructuralError("invalid argon2 params: parallelism is 0")
|
||||||
|
}
|
||||||
|
if params.passes == 0 {
|
||||||
|
return errors.StructuralError("invalid argon2 params: iterations is 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The encoded memory size MUST be a value from 3+ceil(log2(p)) to 31,
|
||||||
|
// such that the decoded memory size m is a value from 8*p to 2^31.
|
||||||
|
if params.memoryExp > 31 || decodeMemory(params.memoryExp) < 8*uint32(params.parallelism) {
|
||||||
|
return errors.StructuralError("invalid argon2 params: memory is out of bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
2
vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go
generated
vendored
2
vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_cache.go
generated
vendored
@ -5,7 +5,7 @@ package s2k
|
|||||||
// the same parameters.
|
// the same parameters.
|
||||||
type Cache map[Params][]byte
|
type Cache map[Params][]byte
|
||||||
|
|
||||||
// GetOrComputeDerivedKey tries to retrieve the key
|
// GetOrComputeDerivedKey tries to retrieve the key
|
||||||
// for the given s2k parameters from the cache.
|
// for the given s2k parameters from the cache.
|
||||||
// If there is no hit, it derives the key with the s2k function from the passphrase,
|
// If there is no hit, it derives the key with the s2k function from the passphrase,
|
||||||
// updates the cache, and returns the key.
|
// updates the cache, and returns the key.
|
||||||
|
6
vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go
generated
vendored
6
vendor/github.com/ProtonMail/go-crypto/openpgp/s2k/s2k_config.go
generated
vendored
@ -50,9 +50,9 @@ type Config struct {
|
|||||||
type Argon2Config struct {
|
type Argon2Config struct {
|
||||||
NumberOfPasses uint8
|
NumberOfPasses uint8
|
||||||
DegreeOfParallelism uint8
|
DegreeOfParallelism uint8
|
||||||
// The memory parameter for Argon2 specifies desired memory usage in kibibytes.
|
// Memory specifies the desired Argon2 memory usage in kibibytes.
|
||||||
// For example memory=64*1024 sets the memory cost to ~64 MB.
|
// For example memory=64*1024 sets the memory cost to ~64 MB.
|
||||||
Memory uint32
|
Memory uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Mode() Mode {
|
func (c *Config) Mode() Mode {
|
||||||
@ -115,7 +115,7 @@ func (c *Argon2Config) EncodedMemory() uint8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memory := c.Memory
|
memory := c.Memory
|
||||||
lowerBound := uint32(c.Parallelism())*8
|
lowerBound := uint32(c.Parallelism()) * 8
|
||||||
upperBound := uint32(2147483648)
|
upperBound := uint32(2147483648)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
65
vendor/github.com/ProtonMail/go-crypto/openpgp/write.go
generated
vendored
65
vendor/github.com/ProtonMail/go-crypto/openpgp/write.go
generated
vendored
@ -76,7 +76,11 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S
|
|||||||
|
|
||||||
sig := createSignaturePacket(signingKey.PublicKey, sigType, config)
|
sig := createSignaturePacket(signingKey.PublicKey, sigType, config)
|
||||||
|
|
||||||
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
|
h, err := sig.PrepareSign(config)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wrappedHash, err := wrapHashForSignature(h, sig.SigType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -275,14 +279,28 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit
|
|||||||
return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
|
return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var salt []byte
|
||||||
if signer != nil {
|
if signer != nil {
|
||||||
|
var opsVersion = 3
|
||||||
|
if signer.Version == 6 {
|
||||||
|
opsVersion = signer.Version
|
||||||
|
}
|
||||||
ops := &packet.OnePassSignature{
|
ops := &packet.OnePassSignature{
|
||||||
|
Version: opsVersion,
|
||||||
SigType: sigType,
|
SigType: sigType,
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
PubKeyAlgo: signer.PubKeyAlgo,
|
PubKeyAlgo: signer.PubKeyAlgo,
|
||||||
KeyId: signer.KeyId,
|
KeyId: signer.KeyId,
|
||||||
IsLast: true,
|
IsLast: true,
|
||||||
}
|
}
|
||||||
|
if opsVersion == 6 {
|
||||||
|
ops.KeyFingerprint = signer.Fingerprint
|
||||||
|
salt, err = packet.SignatureSaltForHash(hash, config.Random())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ops.Salt = salt
|
||||||
|
}
|
||||||
if err := ops.Serialize(payload); err != nil {
|
if err := ops.Serialize(payload); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -310,19 +328,19 @@ func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if signer != nil {
|
if signer != nil {
|
||||||
h, wrappedHash, err := hashForSignature(hash, sigType)
|
h, wrappedHash, err := hashForSignature(hash, sigType, salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
metadata := &packet.LiteralData{
|
metadata := &packet.LiteralData{
|
||||||
Format: 't',
|
Format: 'u',
|
||||||
FileName: hints.FileName,
|
FileName: hints.FileName,
|
||||||
Time: epochSeconds,
|
Time: epochSeconds,
|
||||||
}
|
}
|
||||||
if hints.IsBinary {
|
if hints.IsBinary {
|
||||||
metadata.Format = 'b'
|
metadata.Format = 'b'
|
||||||
}
|
}
|
||||||
return signatureWriter{payload, literalData, hash, wrappedHash, h, signer, sigType, config, metadata}, nil
|
return signatureWriter{payload, literalData, hash, wrappedHash, h, salt, signer, sigType, config, metadata}, nil
|
||||||
}
|
}
|
||||||
return literalData, nil
|
return literalData, nil
|
||||||
}
|
}
|
||||||
@ -380,15 +398,19 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En
|
|||||||
return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no valid encryption keys")
|
return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no valid encryption keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
sig := to[i].PrimaryIdentity().SelfSignature
|
primarySelfSignature, _ := to[i].PrimarySelfSignature()
|
||||||
if !sig.SEIPDv2 {
|
if primarySelfSignature == nil {
|
||||||
|
return nil, errors.InvalidArgumentError("entity without a self-signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !primarySelfSignature.SEIPDv2 {
|
||||||
aeadSupported = false
|
aeadSupported = false
|
||||||
}
|
}
|
||||||
|
|
||||||
candidateCiphers = intersectPreferences(candidateCiphers, sig.PreferredSymmetric)
|
candidateCiphers = intersectPreferences(candidateCiphers, primarySelfSignature.PreferredSymmetric)
|
||||||
candidateHashes = intersectPreferences(candidateHashes, sig.PreferredHash)
|
candidateHashes = intersectPreferences(candidateHashes, primarySelfSignature.PreferredHash)
|
||||||
candidateCipherSuites = intersectCipherSuites(candidateCipherSuites, sig.PreferredCipherSuites)
|
candidateCipherSuites = intersectCipherSuites(candidateCipherSuites, primarySelfSignature.PreferredCipherSuites)
|
||||||
candidateCompression = intersectPreferences(candidateCompression, sig.PreferredCompression)
|
candidateCompression = intersectPreferences(candidateCompression, primarySelfSignature.PreferredCompression)
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the event that the intersection of supported algorithms is empty we use the ones
|
// In the event that the intersection of supported algorithms is empty we use the ones
|
||||||
@ -422,13 +444,19 @@ func encrypt(keyWriter io.Writer, dataWriter io.Writer, to []*Entity, signed *En
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
symKey := make([]byte, cipher.KeySize())
|
var symKey []byte
|
||||||
|
if aeadSupported {
|
||||||
|
symKey = make([]byte, aeadCipherSuite.Cipher.KeySize())
|
||||||
|
} else {
|
||||||
|
symKey = make([]byte, cipher.KeySize())
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
|
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, key := range encryptKeys {
|
for _, key := range encryptKeys {
|
||||||
if err := packet.SerializeEncryptedKey(keyWriter, key.PublicKey, cipher, symKey, config); err != nil {
|
if err := packet.SerializeEncryptedKeyAEAD(keyWriter, key.PublicKey, cipher, aeadSupported, symKey, config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,13 +493,17 @@ func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Con
|
|||||||
hashToHashId(crypto.SHA3_512),
|
hashToHashId(crypto.SHA3_512),
|
||||||
}
|
}
|
||||||
defaultHashes := candidateHashes[0:1]
|
defaultHashes := candidateHashes[0:1]
|
||||||
preferredHashes := signed.PrimaryIdentity().SelfSignature.PreferredHash
|
primarySelfSignature, _ := signed.PrimarySelfSignature()
|
||||||
|
if primarySelfSignature == nil {
|
||||||
|
return nil, errors.StructuralError("signed entity has no self-signature")
|
||||||
|
}
|
||||||
|
preferredHashes := primarySelfSignature.PreferredHash
|
||||||
if len(preferredHashes) == 0 {
|
if len(preferredHashes) == 0 {
|
||||||
preferredHashes = defaultHashes
|
preferredHashes = defaultHashes
|
||||||
}
|
}
|
||||||
candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
|
candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
|
||||||
if len(candidateHashes) == 0 {
|
if len(candidateHashes) == 0 {
|
||||||
return nil, errors.InvalidArgumentError("cannot sign because signing key shares no common algorithms with candidate hashes")
|
return nil, errors.StructuralError("cannot sign because signing key shares no common algorithms with candidate hashes")
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, packet.SigTypeBinary, config)
|
return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, packet.SigTypeBinary, config)
|
||||||
@ -486,6 +518,7 @@ type signatureWriter struct {
|
|||||||
hashType crypto.Hash
|
hashType crypto.Hash
|
||||||
wrappedHash hash.Hash
|
wrappedHash hash.Hash
|
||||||
h hash.Hash
|
h hash.Hash
|
||||||
|
salt []byte // v6 only
|
||||||
signer *packet.PrivateKey
|
signer *packet.PrivateKey
|
||||||
sigType packet.SignatureType
|
sigType packet.SignatureType
|
||||||
config *packet.Config
|
config *packet.Config
|
||||||
@ -509,6 +542,10 @@ func (s signatureWriter) Close() error {
|
|||||||
sig.Hash = s.hashType
|
sig.Hash = s.hashType
|
||||||
sig.Metadata = s.metadata
|
sig.Metadata = s.metadata
|
||||||
|
|
||||||
|
if err := sig.SetSalt(s.salt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := sig.Sign(s.h, s.signer, s.config); err != nil {
|
if err := sig.Sign(s.h, s.signer, s.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
221
vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go
generated
vendored
Normal file
221
vendor/github.com/ProtonMail/go-crypto/openpgp/x25519/x25519.go
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package x25519
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/subtle"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/aes/keywrap"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
x25519lib "github.com/cloudflare/circl/dh/x25519"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hkdfInfo = "OpenPGP X25519"
|
||||||
|
aes128KeySize = 16
|
||||||
|
// The size of a public or private key in bytes.
|
||||||
|
KeySize = x25519lib.Size
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicKey struct {
|
||||||
|
// Point represents the encoded elliptic curve point of the public key.
|
||||||
|
Point []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivateKey struct {
|
||||||
|
PublicKey
|
||||||
|
// Secret represents the secret of the private key.
|
||||||
|
Secret []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPrivateKey creates a new empty private key including the public key.
|
||||||
|
func NewPrivateKey(key PublicKey) *PrivateKey {
|
||||||
|
return &PrivateKey{
|
||||||
|
PublicKey: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates that the provided public key matches the private key.
|
||||||
|
func Validate(pk *PrivateKey) (err error) {
|
||||||
|
var expectedPublicKey, privateKey x25519lib.Key
|
||||||
|
subtle.ConstantTimeCopy(1, privateKey[:], pk.Secret)
|
||||||
|
x25519lib.KeyGen(&expectedPublicKey, &privateKey)
|
||||||
|
if subtle.ConstantTimeCompare(expectedPublicKey[:], pk.PublicKey.Point) == 0 {
|
||||||
|
return errors.KeyInvalidError("x25519: invalid key")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey generates a new x25519 key pair.
|
||||||
|
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
|
var privateKey, publicKey x25519lib.Key
|
||||||
|
privateKeyOut := new(PrivateKey)
|
||||||
|
err := generateKey(rand, &privateKey, &publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privateKeyOut.PublicKey.Point = publicKey[:]
|
||||||
|
privateKeyOut.Secret = privateKey[:]
|
||||||
|
return privateKeyOut, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateKey(rand io.Reader, privateKey *x25519lib.Key, publicKey *x25519lib.Key) error {
|
||||||
|
maxRounds := 10
|
||||||
|
isZero := true
|
||||||
|
for round := 0; isZero; round++ {
|
||||||
|
if round == maxRounds {
|
||||||
|
return errors.InvalidArgumentError("x25519: zero keys only, randomness source might be corrupt")
|
||||||
|
}
|
||||||
|
_, err := io.ReadFull(rand, privateKey[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
isZero = constantTimeIsZero(privateKey[:])
|
||||||
|
}
|
||||||
|
x25519lib.KeyGen(publicKey, privateKey)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt encrypts a sessionKey with x25519 according to
|
||||||
|
// the OpenPGP crypto refresh specification section 5.1.6. The function assumes that the
|
||||||
|
// sessionKey has the correct format and padding according to the specification.
|
||||||
|
func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, err error) {
|
||||||
|
var ephemeralPrivate, ephemeralPublic, staticPublic, shared x25519lib.Key
|
||||||
|
// Check that the input static public key has 32 bytes
|
||||||
|
if len(publicKey.Point) != KeySize {
|
||||||
|
err = errors.KeyInvalidError("x25519: the public key has the wrong size")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(staticPublic[:], publicKey.Point)
|
||||||
|
// Generate ephemeral keyPair
|
||||||
|
err = generateKey(rand, &ephemeralPrivate, &ephemeralPublic)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Compute shared key
|
||||||
|
ok := x25519lib.Shared(&shared, &ephemeralPrivate, &staticPublic)
|
||||||
|
if !ok {
|
||||||
|
err = errors.KeyInvalidError("x25519: the public key is a low order point")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Derive the encryption key from the shared secret
|
||||||
|
encryptionKey := applyHKDF(ephemeralPublic[:], publicKey.Point[:], shared[:])
|
||||||
|
ephemeralPublicKey = &PublicKey{
|
||||||
|
Point: ephemeralPublic[:],
|
||||||
|
}
|
||||||
|
// Encrypt the sessionKey with aes key wrapping
|
||||||
|
encryptedSessionKey, err = keywrap.Wrap(encryptionKey, sessionKey)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypts a session key stored in ciphertext with the provided x25519
|
||||||
|
// private key and ephemeral public key.
|
||||||
|
func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) {
|
||||||
|
var ephemeralPublic, staticPrivate, shared x25519lib.Key
|
||||||
|
// Check that the input ephemeral public key has 32 bytes
|
||||||
|
if len(ephemeralPublicKey.Point) != KeySize {
|
||||||
|
err = errors.KeyInvalidError("x25519: the public key has the wrong size")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(ephemeralPublic[:], ephemeralPublicKey.Point)
|
||||||
|
subtle.ConstantTimeCopy(1, staticPrivate[:], privateKey.Secret)
|
||||||
|
// Compute shared key
|
||||||
|
ok := x25519lib.Shared(&shared, &staticPrivate, &ephemeralPublic)
|
||||||
|
if !ok {
|
||||||
|
err = errors.KeyInvalidError("x25519: the ephemeral public key is a low order point")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Derive the encryption key from the shared secret
|
||||||
|
encryptionKey := applyHKDF(ephemeralPublicKey.Point[:], privateKey.PublicKey.Point[:], shared[:])
|
||||||
|
// Decrypt the session key with aes key wrapping
|
||||||
|
encodedSessionKey, err = keywrap.Unwrap(encryptionKey, ciphertext)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyHKDF(ephemeralPublicKey []byte, publicKey []byte, sharedSecret []byte) []byte {
|
||||||
|
inputKey := make([]byte, 3*KeySize)
|
||||||
|
// ephemeral public key | recipient public key | shared secret
|
||||||
|
subtle.ConstantTimeCopy(1, inputKey[:KeySize], ephemeralPublicKey)
|
||||||
|
subtle.ConstantTimeCopy(1, inputKey[KeySize:2*KeySize], publicKey)
|
||||||
|
subtle.ConstantTimeCopy(1, inputKey[2*KeySize:], sharedSecret)
|
||||||
|
hkdfReader := hkdf.New(sha256.New, inputKey, []byte{}, []byte(hkdfInfo))
|
||||||
|
encryptionKey := make([]byte, aes128KeySize)
|
||||||
|
_, _ = io.ReadFull(hkdfReader, encryptionKey)
|
||||||
|
return encryptionKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func constantTimeIsZero(bytes []byte) bool {
|
||||||
|
isZero := byte(0)
|
||||||
|
for _, b := range bytes {
|
||||||
|
isZero |= b
|
||||||
|
}
|
||||||
|
return isZero == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENCODING/DECODING ciphertexts:
|
||||||
|
|
||||||
|
// EncodeFieldsLength returns the length of the ciphertext encoding
|
||||||
|
// given the encrypted session key.
|
||||||
|
func EncodedFieldsLength(encryptedSessionKey []byte, v6 bool) int {
|
||||||
|
lenCipherFunction := 0
|
||||||
|
if !v6 {
|
||||||
|
lenCipherFunction = 1
|
||||||
|
}
|
||||||
|
return KeySize + 1 + len(encryptedSessionKey) + lenCipherFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeField encodes x25519 session key encryption fields as
|
||||||
|
// ephemeral x25519 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey
|
||||||
|
// and writes it to writer.
|
||||||
|
func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) {
|
||||||
|
lenAlgorithm := 0
|
||||||
|
if !v6 {
|
||||||
|
lenAlgorithm = 1
|
||||||
|
}
|
||||||
|
if _, err = writer.Write(ephemeralPublicKey.Point); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = writer.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !v6 {
|
||||||
|
if _, err = writer.Write([]byte{cipherFunction}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = writer.Write(encryptedSessionKey)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeField decodes a x25519 session key encryption as
|
||||||
|
// ephemeral x25519 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey.
|
||||||
|
func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) {
|
||||||
|
var buf [1]byte
|
||||||
|
ephemeralPublicKey = &PublicKey{
|
||||||
|
Point: make([]byte, KeySize),
|
||||||
|
}
|
||||||
|
// 32 octets representing an ephemeral x25519 public key.
|
||||||
|
if _, err = io.ReadFull(reader, ephemeralPublicKey.Point); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
// A one-octet size of the following fields.
|
||||||
|
if _, err = io.ReadFull(reader, buf[:]); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
followingLen := buf[0]
|
||||||
|
// The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet).
|
||||||
|
if !v6 {
|
||||||
|
if _, err = io.ReadFull(reader, buf[:]); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
cipherFunction = buf[0]
|
||||||
|
followingLen -= 1
|
||||||
|
}
|
||||||
|
// The encrypted session key.
|
||||||
|
encryptedSessionKey = make([]byte, followingLen)
|
||||||
|
if _, err = io.ReadFull(reader, encryptedSessionKey); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
return ephemeralPublicKey, encryptedSessionKey, cipherFunction, nil
|
||||||
|
}
|
229
vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go
generated
vendored
Normal file
229
vendor/github.com/ProtonMail/go-crypto/openpgp/x448/x448.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
package x448
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha512"
|
||||||
|
"crypto/subtle"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/aes/keywrap"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/errors"
|
||||||
|
x448lib "github.com/cloudflare/circl/dh/x448"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hkdfInfo = "OpenPGP X448"
|
||||||
|
aes256KeySize = 32
|
||||||
|
// The size of a public or private key in bytes.
|
||||||
|
KeySize = x448lib.Size
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicKey struct {
|
||||||
|
// Point represents the encoded elliptic curve point of the public key.
|
||||||
|
Point []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrivateKey struct {
|
||||||
|
PublicKey
|
||||||
|
// Secret represents the secret of the private key.
|
||||||
|
Secret []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPrivateKey creates a new empty private key including the public key.
|
||||||
|
func NewPrivateKey(key PublicKey) *PrivateKey {
|
||||||
|
return &PrivateKey{
|
||||||
|
PublicKey: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates that the provided public key matches
|
||||||
|
// the private key.
|
||||||
|
func Validate(pk *PrivateKey) (err error) {
|
||||||
|
var expectedPublicKey, privateKey x448lib.Key
|
||||||
|
subtle.ConstantTimeCopy(1, privateKey[:], pk.Secret)
|
||||||
|
x448lib.KeyGen(&expectedPublicKey, &privateKey)
|
||||||
|
if subtle.ConstantTimeCompare(expectedPublicKey[:], pk.PublicKey.Point) == 0 {
|
||||||
|
return errors.KeyInvalidError("x448: invalid key")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey generates a new x448 key pair.
|
||||||
|
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
|
||||||
|
var privateKey, publicKey x448lib.Key
|
||||||
|
privateKeyOut := new(PrivateKey)
|
||||||
|
err := generateKey(rand, &privateKey, &publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privateKeyOut.PublicKey.Point = publicKey[:]
|
||||||
|
privateKeyOut.Secret = privateKey[:]
|
||||||
|
return privateKeyOut, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateKey(rand io.Reader, privateKey *x448lib.Key, publicKey *x448lib.Key) error {
|
||||||
|
maxRounds := 10
|
||||||
|
isZero := true
|
||||||
|
for round := 0; isZero; round++ {
|
||||||
|
if round == maxRounds {
|
||||||
|
return errors.InvalidArgumentError("x448: zero keys only, randomness source might be corrupt")
|
||||||
|
}
|
||||||
|
_, err := io.ReadFull(rand, privateKey[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
isZero = constantTimeIsZero(privateKey[:])
|
||||||
|
}
|
||||||
|
x448lib.KeyGen(publicKey, privateKey)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt encrypts a sessionKey with x448 according to
|
||||||
|
// the OpenPGP crypto refresh specification section 5.1.7. The function assumes that the
|
||||||
|
// sessionKey has the correct format and padding according to the specification.
|
||||||
|
func Encrypt(rand io.Reader, publicKey *PublicKey, sessionKey []byte) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, err error) {
|
||||||
|
var ephemeralPrivate, ephemeralPublic, staticPublic, shared x448lib.Key
|
||||||
|
// Check that the input static public key has 56 bytes.
|
||||||
|
if len(publicKey.Point) != KeySize {
|
||||||
|
err = errors.KeyInvalidError("x448: the public key has the wrong size")
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
copy(staticPublic[:], publicKey.Point)
|
||||||
|
// Generate ephemeral keyPair.
|
||||||
|
if err = generateKey(rand, &ephemeralPrivate, &ephemeralPublic); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// Compute shared key.
|
||||||
|
ok := x448lib.Shared(&shared, &ephemeralPrivate, &staticPublic)
|
||||||
|
if !ok {
|
||||||
|
err = errors.KeyInvalidError("x448: the public key is a low order point")
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// Derive the encryption key from the shared secret.
|
||||||
|
encryptionKey := applyHKDF(ephemeralPublic[:], publicKey.Point[:], shared[:])
|
||||||
|
ephemeralPublicKey = &PublicKey{
|
||||||
|
Point: ephemeralPublic[:],
|
||||||
|
}
|
||||||
|
// Encrypt the sessionKey with aes key wrapping.
|
||||||
|
encryptedSessionKey, err = keywrap.Wrap(encryptionKey, sessionKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return ephemeralPublicKey, encryptedSessionKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypts a session key stored in ciphertext with the provided x448
|
||||||
|
// private key and ephemeral public key.
|
||||||
|
func Decrypt(privateKey *PrivateKey, ephemeralPublicKey *PublicKey, ciphertext []byte) (encodedSessionKey []byte, err error) {
|
||||||
|
var ephemeralPublic, staticPrivate, shared x448lib.Key
|
||||||
|
// Check that the input ephemeral public key has 56 bytes.
|
||||||
|
if len(ephemeralPublicKey.Point) != KeySize {
|
||||||
|
err = errors.KeyInvalidError("x448: the public key has the wrong size")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
copy(ephemeralPublic[:], ephemeralPublicKey.Point)
|
||||||
|
subtle.ConstantTimeCopy(1, staticPrivate[:], privateKey.Secret)
|
||||||
|
// Compute shared key.
|
||||||
|
ok := x448lib.Shared(&shared, &staticPrivate, &ephemeralPublic)
|
||||||
|
if !ok {
|
||||||
|
err = errors.KeyInvalidError("x448: the ephemeral public key is a low order point")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Derive the encryption key from the shared secret.
|
||||||
|
encryptionKey := applyHKDF(ephemeralPublicKey.Point[:], privateKey.PublicKey.Point[:], shared[:])
|
||||||
|
// Decrypt the session key with aes key wrapping.
|
||||||
|
encodedSessionKey, err = keywrap.Unwrap(encryptionKey, ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return encodedSessionKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyHKDF(ephemeralPublicKey []byte, publicKey []byte, sharedSecret []byte) []byte {
|
||||||
|
inputKey := make([]byte, 3*KeySize)
|
||||||
|
// ephemeral public key | recipient public key | shared secret.
|
||||||
|
subtle.ConstantTimeCopy(1, inputKey[:KeySize], ephemeralPublicKey)
|
||||||
|
subtle.ConstantTimeCopy(1, inputKey[KeySize:2*KeySize], publicKey)
|
||||||
|
subtle.ConstantTimeCopy(1, inputKey[2*KeySize:], sharedSecret)
|
||||||
|
hkdfReader := hkdf.New(sha512.New, inputKey, []byte{}, []byte(hkdfInfo))
|
||||||
|
encryptionKey := make([]byte, aes256KeySize)
|
||||||
|
_, _ = io.ReadFull(hkdfReader, encryptionKey)
|
||||||
|
return encryptionKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func constantTimeIsZero(bytes []byte) bool {
|
||||||
|
isZero := byte(0)
|
||||||
|
for _, b := range bytes {
|
||||||
|
isZero |= b
|
||||||
|
}
|
||||||
|
return isZero == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENCODING/DECODING ciphertexts:
|
||||||
|
|
||||||
|
// EncodeFieldsLength returns the length of the ciphertext encoding
|
||||||
|
// given the encrypted session key.
|
||||||
|
func EncodedFieldsLength(encryptedSessionKey []byte, v6 bool) int {
|
||||||
|
lenCipherFunction := 0
|
||||||
|
if !v6 {
|
||||||
|
lenCipherFunction = 1
|
||||||
|
}
|
||||||
|
return KeySize + 1 + len(encryptedSessionKey) + lenCipherFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeField encodes x448 session key encryption fields as
|
||||||
|
// ephemeral x448 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey
|
||||||
|
// and writes it to writer.
|
||||||
|
func EncodeFields(writer io.Writer, ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, v6 bool) (err error) {
|
||||||
|
lenAlgorithm := 0
|
||||||
|
if !v6 {
|
||||||
|
lenAlgorithm = 1
|
||||||
|
}
|
||||||
|
if _, err = writer.Write(ephemeralPublicKey.Point); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = writer.Write([]byte{byte(len(encryptedSessionKey) + lenAlgorithm)}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !v6 {
|
||||||
|
if _, err = writer.Write([]byte{cipherFunction}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err = writer.Write(encryptedSessionKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeField decodes a x448 session key encryption as
|
||||||
|
// ephemeral x448 public key | follow byte length | cipherFunction (v3 only) | encryptedSessionKey.
|
||||||
|
func DecodeFields(reader io.Reader, v6 bool) (ephemeralPublicKey *PublicKey, encryptedSessionKey []byte, cipherFunction byte, err error) {
|
||||||
|
var buf [1]byte
|
||||||
|
ephemeralPublicKey = &PublicKey{
|
||||||
|
Point: make([]byte, KeySize),
|
||||||
|
}
|
||||||
|
// 56 octets representing an ephemeral x448 public key.
|
||||||
|
if _, err = io.ReadFull(reader, ephemeralPublicKey.Point); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
// A one-octet size of the following fields.
|
||||||
|
if _, err = io.ReadFull(reader, buf[:]); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
followingLen := buf[0]
|
||||||
|
// The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet).
|
||||||
|
if !v6 {
|
||||||
|
if _, err = io.ReadFull(reader, buf[:]); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
cipherFunction = buf[0]
|
||||||
|
followingLen -= 1
|
||||||
|
}
|
||||||
|
// The encrypted session key.
|
||||||
|
encryptedSessionKey = make([]byte, followingLen)
|
||||||
|
if _, err = io.ReadFull(reader, encryptedSessionKey); err != nil {
|
||||||
|
return nil, nil, 0, err
|
||||||
|
}
|
||||||
|
return ephemeralPublicKey, encryptedSessionKey, cipherFunction, nil
|
||||||
|
}
|
8
vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml
generated
vendored
8
vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml
generated
vendored
@ -14,16 +14,13 @@ issues:
|
|||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
# - dupl
|
|
||||||
- exhaustive
|
- exhaustive
|
||||||
# - exhaustivestruct
|
|
||||||
- goconst
|
- goconst
|
||||||
- godot
|
- godot
|
||||||
- godox
|
- godox
|
||||||
- gomnd
|
- mnd
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
# - lll
|
|
||||||
- misspell
|
- misspell
|
||||||
- nakedret
|
- nakedret
|
||||||
- nestif
|
- nestif
|
||||||
@ -34,13 +31,10 @@ linters:
|
|||||||
|
|
||||||
# disable default linters, they are already enabled in .golangci.yml
|
# disable default linters, they are already enabled in .golangci.yml
|
||||||
disable:
|
disable:
|
||||||
- deadcode
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
|
||||||
- typecheck
|
- typecheck
|
||||||
- unused
|
- unused
|
||||||
- varcheck
|
|
||||||
|
2
vendor/github.com/charmbracelet/lipgloss/.golangci.yml
generated
vendored
2
vendor/github.com/charmbracelet/lipgloss/.golangci.yml
generated
vendored
@ -15,12 +15,10 @@ issues:
|
|||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- exportloopref
|
|
||||||
- gofumpt
|
- gofumpt
|
||||||
- goimports
|
- goimports
|
||||||
- gosec
|
- gosec
|
||||||
- nilerr
|
- nilerr
|
||||||
- predeclared
|
|
||||||
- revive
|
- revive
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- sqlclosecheck
|
- sqlclosecheck
|
||||||
|
5
vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml
generated
vendored
Normal file
5
vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
includes:
|
||||||
|
- from_url:
|
||||||
|
url: charmbracelet/meta/main/goreleaser-lib.yaml
|
||||||
|
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
|
||||||
|
|
308
vendor/github.com/charmbracelet/lipgloss/README.md
generated
vendored
308
vendor/github.com/charmbracelet/lipgloss/README.md
generated
vendored
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
Style definitions for nice terminal layouts. Built with TUIs in mind.
|
Style definitions for nice terminal layouts. Built with TUIs in mind.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Lip Gloss takes an expressive, declarative approach to terminal rendering.
|
Lip Gloss takes an expressive, declarative approach to terminal rendering.
|
||||||
Users familiar with CSS will feel at home with Lip Gloss.
|
Users familiar with CSS will feel at home with Lip Gloss.
|
||||||
@ -77,11 +77,11 @@ appropriate color will be chosen at runtime.
|
|||||||
|
|
||||||
### Complete Colors
|
### Complete Colors
|
||||||
|
|
||||||
CompleteColor specifies exact values for truecolor, ANSI256, and ANSI color
|
CompleteColor specifies exact values for True Color, ANSI256, and ANSI color
|
||||||
profiles.
|
profiles.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
lipgloss.CompleteColor{True: "#0000FF", ANSI256: "86", ANSI: "5"}
|
lipgloss.CompleteColor{TrueColor: "#0000FF", ANSI256: "86", ANSI: "5"}
|
||||||
```
|
```
|
||||||
|
|
||||||
Automatic color degradation will not be performed in this case and it will be
|
Automatic color degradation will not be performed in this case and it will be
|
||||||
@ -89,7 +89,7 @@ based on the color specified.
|
|||||||
|
|
||||||
### Complete Adaptive Colors
|
### Complete Adaptive Colors
|
||||||
|
|
||||||
You can use CompleteColor with AdaptiveColor to specify the exact values for
|
You can use `CompleteColor` with `AdaptiveColor` to specify the exact values for
|
||||||
light and dark backgrounds without automatic color degradation.
|
light and dark backgrounds without automatic color degradation.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@ -402,7 +402,7 @@ block := lipgloss.Place(30, 80, lipgloss.Right, lipgloss.Bottom, fancyStyledPara
|
|||||||
|
|
||||||
You can also style the whitespace. For details, see [the docs][docs].
|
You can also style the whitespace. For details, see [the docs][docs].
|
||||||
|
|
||||||
### Rendering Tables
|
## Rendering Tables
|
||||||
|
|
||||||
Lip Gloss ships with a table rendering sub-package.
|
Lip Gloss ships with a table rendering sub-package.
|
||||||
|
|
||||||
@ -455,114 +455,9 @@ fmt.Println(t)
|
|||||||
|
|
||||||
For more on tables see [the docs](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc) and [examples](https://github.com/charmbracelet/lipgloss/tree/master/examples/table).
|
For more on tables see [the docs](https://pkg.go.dev/github.com/charmbracelet/lipgloss?tab=doc) and [examples](https://github.com/charmbracelet/lipgloss/tree/master/examples/table).
|
||||||
|
|
||||||
## Rendering Trees
|
|
||||||
|
|
||||||
Lip Gloss ships with a tree rendering sub-package.
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/charmbracelet/lipgloss/tree"
|
|
||||||
```
|
|
||||||
|
|
||||||
Define a new tree.
|
|
||||||
|
|
||||||
```go
|
|
||||||
t := tree.New("root", "child 1", "child 2", tree.New("child 3", "child 3.1"))
|
|
||||||
```
|
|
||||||
|
|
||||||
Print the tree.
|
|
||||||
|
|
||||||
```go
|
|
||||||
fmt.Println(t)
|
|
||||||
|
|
||||||
// root
|
|
||||||
// ├── child 1
|
|
||||||
// ├── child 2
|
|
||||||
// └── child 3
|
|
||||||
// └── child 3.1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Customization
|
|
||||||
|
|
||||||
Trees can be customized via their enumeration function as well as using
|
|
||||||
`lipgloss.Style`s.
|
|
||||||
|
|
||||||
```go
|
|
||||||
style1 := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1)
|
|
||||||
style2 := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).MarginRight(1)
|
|
||||||
|
|
||||||
t := tree.New().
|
|
||||||
Items(
|
|
||||||
"Glossier",
|
|
||||||
"Claire’s Boutique",
|
|
||||||
tree.New().
|
|
||||||
Root("Nyx").
|
|
||||||
Items("Qux", "Quux").
|
|
||||||
EnumeratorStyle(style2),
|
|
||||||
"Mac",
|
|
||||||
"Milk",
|
|
||||||
).
|
|
||||||
EnumeratorStyle(style1)
|
|
||||||
```
|
|
||||||
|
|
||||||
Print the tree:
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img
|
|
||||||
width="600"
|
|
||||||
alt="Tree example"
|
|
||||||
src="https://github.com/charmbracelet/lipgloss/assets/245435/5a875269-f6d6-43fa-9916-5d8360e66964"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
You may also define custom enumerator implementations:
|
|
||||||
|
|
||||||
```go
|
|
||||||
t := tree.New().
|
|
||||||
Items(
|
|
||||||
"Glossier",
|
|
||||||
"Claire’s Boutique",
|
|
||||||
tree.New().
|
|
||||||
Root("Nyx").
|
|
||||||
Items(
|
|
||||||
"Qux",
|
|
||||||
"Quux",
|
|
||||||
),
|
|
||||||
"Mac",
|
|
||||||
"Milk",
|
|
||||||
).
|
|
||||||
Enumerator(func(tree.Data, int) (string, string) {
|
|
||||||
return "->", "->"
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Print the tree.
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img
|
|
||||||
width="600"
|
|
||||||
alt="Tree example"
|
|
||||||
src="https://github.com/charmbracelet/lipgloss/assets/245435/811e8b39-124f-48bb-b3dd-e015a65b1065"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### Building
|
|
||||||
|
|
||||||
If you need, you can also build trees incrementally:
|
|
||||||
|
|
||||||
```go
|
|
||||||
t := tree.New("")
|
|
||||||
|
|
||||||
for i := 0; i < repeat; i++ {
|
|
||||||
t.Item("Lip Gloss")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Rendering Lists
|
## Rendering Lists
|
||||||
|
|
||||||
Lip Gloss ships with a list rendering sub-package.
|
Lip Gloss ships with a list rendering sub-package.
|
||||||
Implementation-wise, lists are still trees.
|
|
||||||
The `list` package provides many common `Enumerator` implementations, as well as
|
|
||||||
some syntactic sugar.
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/charmbracelet/lipgloss/list"
|
import "github.com/charmbracelet/lipgloss/list"
|
||||||
@ -584,77 +479,190 @@ fmt.Println(l)
|
|||||||
// • C
|
// • C
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Lists have the ability to nest.
|
||||||
|
|
||||||
### Customization
|
```go
|
||||||
|
l := list.New(
|
||||||
|
"A", list.New("Artichoke"),
|
||||||
|
"B", list.New("Baking Flour", "Bananas", "Barley", "Bean Sprouts"),
|
||||||
|
"C", list.New("Cashew Apple", "Cashews", "Coconut Milk", "Curry Paste", "Currywurst"),
|
||||||
|
"D", list.New("Dill", "Dragonfruit", "Dried Shrimp"),
|
||||||
|
"E", list.New("Eggs"),
|
||||||
|
"F", list.New("Fish Cake", "Furikake"),
|
||||||
|
"J", list.New("Jicama"),
|
||||||
|
"K", list.New("Kohlrabi"),
|
||||||
|
"L", list.New("Leeks", "Lentils", "Licorice Root"),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Print the list.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fmt.Println(l)
|
||||||
|
```
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="600" alt="image" src="https://github.com/charmbracelet/lipgloss/assets/42545625/0dc9f440-0748-4151-a3b0-7dcf29dfcdb0">
|
||||||
|
</p>
|
||||||
|
|
||||||
Lists can be customized via their enumeration function as well as using
|
Lists can be customized via their enumeration function as well as using
|
||||||
`lipgloss.Style`s.
|
`lipgloss.Style`s.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1)
|
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1)
|
||||||
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).MarginRight(1)
|
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212")).MarginRight(1)
|
||||||
|
|
||||||
l := list.New(
|
l := list.New(
|
||||||
"Glossier",
|
"Glossier",
|
||||||
"Claire’s Boutique",
|
"Claire’s Boutique",
|
||||||
"Nyx",
|
"Nyx",
|
||||||
"Mac",
|
"Mac",
|
||||||
"Milk",
|
"Milk",
|
||||||
).
|
).
|
||||||
Enumerator(list.Roman).
|
Enumerator(list.Roman).
|
||||||
EnumeratorStyle(enumeratorStyle).
|
EnumeratorStyle(enumeratorStyle).
|
||||||
ItemStyle(itemStyle)
|
ItemStyle(itemStyle)
|
||||||
```
|
```
|
||||||
|
|
||||||
Print the list.
|
Print the list.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img
|
<img width="600" alt="List example" src="https://github.com/charmbracelet/lipgloss/assets/42545625/360494f1-57fb-4e13-bc19-0006efe01561">
|
||||||
width="600"
|
|
||||||
alt="List example"
|
|
||||||
src="https://github.com/charmbracelet/lipgloss/assets/245435/8f5e5e0b-7bf9-4e3b-a8ba-3af10825320e"
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
In addition to the predefined enumerators (`Arabic`, `Alphabet`, `Roman`, `Bullet`, `Tree`),
|
In addition to the predefined enumerators (`Arabic`, `Alphabet`, `Roman`, `Bullet`, `Tree`),
|
||||||
you may also define your own custom enumerator:
|
you may also define your own custom enumerator:
|
||||||
|
|
||||||
```go
|
|
||||||
var DuckDuckGooseEnumerator Enumerator = func(l *List, i int) string {
|
|
||||||
if l.At(i) == "Goose" {
|
|
||||||
return "Honk →"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Use it in a list:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck")
|
l := list.New("Duck", "Duck", "Duck", "Duck", "Goose", "Duck", "Duck")
|
||||||
l.Enumerator(DuckDuckGooseEnumerator)
|
|
||||||
|
func DuckDuckGooseEnumerator(l list.Items, i int) string {
|
||||||
|
if l.At(i).Value() == "Goose" {
|
||||||
|
return "Honk →"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
l = l.Enumerator(DuckDuckGooseEnumerator)
|
||||||
```
|
```
|
||||||
|
|
||||||
Print the list:
|
Print the list:
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img
|
<img width="600" alt="image" src="https://github.com/charmbracelet/lipgloss/assets/42545625/157aaf30-140d-4948-9bb4-dfba46e5b87e">
|
||||||
width="600"
|
|
||||||
alt="image"
|
|
||||||
src="https://github.com/charmbracelet/lipgloss/assets/245435/44e37a5b-5124-4f49-a332-1756a355002e"
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Building
|
If you need, you can also build lists incrementally:
|
||||||
|
|
||||||
If you need, you can also build trees incrementally:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
l := list.New()
|
l := list.New()
|
||||||
|
|
||||||
for i := 0; i < repeat; i++ {
|
for i := 0; i < repeat; i++ {
|
||||||
l.Item("Lip Gloss")
|
l.Item("Lip Gloss")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Rendering Trees
|
||||||
|
|
||||||
|
Lip Gloss ships with a tree rendering sub-package.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/charmbracelet/lipgloss/tree"
|
||||||
|
```
|
||||||
|
|
||||||
|
Define a new tree.
|
||||||
|
|
||||||
|
```go
|
||||||
|
t := tree.Root(".").
|
||||||
|
Child("A", "B", "C")
|
||||||
|
```
|
||||||
|
|
||||||
|
Print the tree.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fmt.Println(t)
|
||||||
|
|
||||||
|
// .
|
||||||
|
// ├── A
|
||||||
|
// ├── B
|
||||||
|
// └── C
|
||||||
|
```
|
||||||
|
|
||||||
|
Trees have the ability to nest.
|
||||||
|
|
||||||
|
```go
|
||||||
|
t := tree.Root(".").
|
||||||
|
Child("macOS").
|
||||||
|
Child(
|
||||||
|
tree.New().
|
||||||
|
Root("Linux").
|
||||||
|
Child("NixOS").
|
||||||
|
Child("Arch Linux (btw)").
|
||||||
|
Child("Void Linux"),
|
||||||
|
).
|
||||||
|
Child(
|
||||||
|
tree.New().
|
||||||
|
Root("BSD").
|
||||||
|
Child("FreeBSD").
|
||||||
|
Child("OpenBSD"),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Print the tree.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fmt.Println(t)
|
||||||
|
```
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="663" alt="Tree Example (simple)" src="https://github.com/user-attachments/assets/5ef14eb8-a5d4-4f94-8834-e15d1e714f89">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Trees can be customized via their enumeration function as well as using
|
||||||
|
`lipgloss.Style`s.
|
||||||
|
|
||||||
|
```go
|
||||||
|
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("63")).MarginRight(1)
|
||||||
|
rootStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("35"))
|
||||||
|
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212"))
|
||||||
|
|
||||||
|
t := tree.
|
||||||
|
Root("⁜ Makeup").
|
||||||
|
Child(
|
||||||
|
"Glossier",
|
||||||
|
"Fenty Beauty",
|
||||||
|
tree.New().Child(
|
||||||
|
"Gloss Bomb Universal Lip Luminizer",
|
||||||
|
"Hot Cheeks Velour Blushlighter",
|
||||||
|
),
|
||||||
|
"Nyx",
|
||||||
|
"Mac",
|
||||||
|
"Milk",
|
||||||
|
).
|
||||||
|
Enumerator(tree.RoundedEnumerator).
|
||||||
|
EnumeratorStyle(enumeratorStyle).
|
||||||
|
RootStyle(rootStyle).
|
||||||
|
ItemStyle(itemStyle)
|
||||||
|
```
|
||||||
|
|
||||||
|
Print the tree.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="663" alt="Tree Example (makeup)" src="https://github.com/user-attachments/assets/06d12d87-744a-4c89-bd98-45de9094a97e">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
The predefined enumerators for trees are `DefaultEnumerator` and `RoundedEnumerator`.
|
||||||
|
|
||||||
|
If you need, you can also build trees incrementally:
|
||||||
|
|
||||||
|
```go
|
||||||
|
t := tree.New()
|
||||||
|
|
||||||
|
for i := 0; i < repeat; i++ {
|
||||||
|
t.Child("Lip Gloss")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
@ -726,6 +734,12 @@ the stylesheet-based Markdown renderer.
|
|||||||
|
|
||||||
[glamour]: https://github.com/charmbracelet/glamour
|
[glamour]: https://github.com/charmbracelet/glamour
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [contributing][contribute].
|
||||||
|
|
||||||
|
[contribute]: https://github.com/charmbracelet/lipgloss/contribute
|
||||||
|
|
||||||
## Feedback
|
## Feedback
|
||||||
|
|
||||||
We’d love to hear your thoughts on this project. Feel free to drop us a note!
|
We’d love to hear your thoughts on this project. Feel free to drop us a note!
|
||||||
|
10
vendor/github.com/charmbracelet/lipgloss/style.go
generated
vendored
10
vendor/github.com/charmbracelet/lipgloss/style.go
generated
vendored
@ -307,9 +307,7 @@ func (s Style) Render(strs ...string) string {
|
|||||||
te = te.Underline()
|
te = te.Underline()
|
||||||
}
|
}
|
||||||
if reverse {
|
if reverse {
|
||||||
if reverse {
|
teWhitespace = teWhitespace.Reverse()
|
||||||
teWhitespace = teWhitespace.Reverse()
|
|
||||||
}
|
|
||||||
te = te.Reverse()
|
te = te.Reverse()
|
||||||
}
|
}
|
||||||
if blink {
|
if blink {
|
||||||
@ -355,6 +353,8 @@ func (s Style) Render(strs ...string) string {
|
|||||||
|
|
||||||
// Potentially convert tabs to spaces
|
// Potentially convert tabs to spaces
|
||||||
str = s.maybeConvertTabs(str)
|
str = s.maybeConvertTabs(str)
|
||||||
|
// carriage returns can cause strange behaviour when rendering.
|
||||||
|
str = strings.ReplaceAll(str, "\r\n", "\n")
|
||||||
|
|
||||||
// Strip newlines in single line mode
|
// Strip newlines in single line mode
|
||||||
if inline {
|
if inline {
|
||||||
@ -564,14 +564,14 @@ func pad(str string, n int, style *termenv.Style) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func max(a, b int) int { //nolint:unparam
|
func max(a, b int) int { //nolint:unparam,predeclared
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(a, b int) int {
|
func min(a, b int) int { //nolint:predeclared
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
131
vendor/github.com/charmbracelet/lipgloss/table/table.go
generated
vendored
131
vendor/github.com/charmbracelet/lipgloss/table/table.go
generated
vendored
@ -7,6 +7,10 @@ import (
|
|||||||
"github.com/charmbracelet/x/ansi"
|
"github.com/charmbracelet/x/ansi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HeaderRow denotes the header's row index used when rendering headers. Use
|
||||||
|
// this value when looking to customize header styles in StyleFunc.
|
||||||
|
const HeaderRow int = -1
|
||||||
|
|
||||||
// StyleFunc is the style function that determines the style of a Cell.
|
// StyleFunc is the style function that determines the style of a Cell.
|
||||||
//
|
//
|
||||||
// It takes the row and column of the cell as an input and determines the
|
// It takes the row and column of the cell as an input and determines the
|
||||||
@ -53,9 +57,10 @@ type Table struct {
|
|||||||
headers []string
|
headers []string
|
||||||
data Data
|
data Data
|
||||||
|
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
offset int
|
useManualHeight bool
|
||||||
|
offset int
|
||||||
|
|
||||||
// widths tracks the width of each column.
|
// widths tracks the width of each column.
|
||||||
widths []int
|
widths []int
|
||||||
@ -84,7 +89,7 @@ func New() *Table {
|
|||||||
|
|
||||||
// ClearRows clears the table rows.
|
// ClearRows clears the table rows.
|
||||||
func (t *Table) ClearRows() *Table {
|
func (t *Table) ClearRows() *Table {
|
||||||
t.data = nil
|
t.data = NewStringData()
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +204,7 @@ func (t *Table) Width(w int) *Table {
|
|||||||
// Height sets the table height.
|
// Height sets the table height.
|
||||||
func (t *Table) Height(h int) *Table {
|
func (t *Table) Height(h int) *Table {
|
||||||
t.height = h
|
t.height = h
|
||||||
|
t.useManualHeight = true
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,15 +216,13 @@ func (t *Table) Offset(o int) *Table {
|
|||||||
|
|
||||||
// String returns the table as a string.
|
// String returns the table as a string.
|
||||||
func (t *Table) String() string {
|
func (t *Table) String() string {
|
||||||
hasHeaders := t.headers != nil && len(t.headers) > 0
|
hasHeaders := len(t.headers) > 0
|
||||||
hasRows := t.data != nil && t.data.Rows() > 0
|
hasRows := t.data != nil && t.data.Rows() > 0
|
||||||
|
|
||||||
if !hasHeaders && !hasRows {
|
if !hasHeaders && !hasRows {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var s strings.Builder
|
|
||||||
|
|
||||||
// Add empty cells to the headers, until it's the same length as the longest
|
// Add empty cells to the headers, until it's the same length as the longest
|
||||||
// row (only if there are at headers in the first place).
|
// row (only if there are at headers in the first place).
|
||||||
if hasHeaders {
|
if hasHeaders {
|
||||||
@ -235,15 +239,15 @@ func (t *Table) String() string {
|
|||||||
// the StyleFunc after the headers and rows. Update the widths for a final
|
// the StyleFunc after the headers and rows. Update the widths for a final
|
||||||
// time.
|
// time.
|
||||||
for i, cell := range t.headers {
|
for i, cell := range t.headers {
|
||||||
t.widths[i] = max(t.widths[i], lipgloss.Width(t.style(0, i).Render(cell)))
|
t.widths[i] = max(t.widths[i], lipgloss.Width(t.style(HeaderRow, i).Render(cell)))
|
||||||
t.heights[0] = max(t.heights[0], lipgloss.Height(t.style(0, i).Render(cell)))
|
t.heights[0] = max(t.heights[0], lipgloss.Height(t.style(HeaderRow, i).Render(cell)))
|
||||||
}
|
}
|
||||||
|
|
||||||
for r := 0; r < t.data.Rows(); r++ {
|
for r := 0; r < t.data.Rows(); r++ {
|
||||||
for i := 0; i < t.data.Columns(); i++ {
|
for i := 0; i < t.data.Columns(); i++ {
|
||||||
cell := t.data.At(r, i)
|
cell := t.data.At(r, i)
|
||||||
|
|
||||||
rendered := t.style(r+1, i).Render(cell)
|
rendered := t.style(r, i).Render(cell)
|
||||||
t.heights[r+btoi(hasHeaders)] = max(t.heights[r+btoi(hasHeaders)], lipgloss.Height(rendered))
|
t.heights[r+btoi(hasHeaders)] = max(t.heights[r+btoi(hasHeaders)], lipgloss.Height(rendered))
|
||||||
t.widths[i] = max(t.widths[i], lipgloss.Width(rendered))
|
t.widths[i] = max(t.widths[i], lipgloss.Width(rendered))
|
||||||
}
|
}
|
||||||
@ -342,27 +346,51 @@ func (t *Table) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
if t.borderTop {
|
if t.borderTop {
|
||||||
s.WriteString(t.constructTopBorder())
|
sb.WriteString(t.constructTopBorder())
|
||||||
s.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasHeaders {
|
if hasHeaders {
|
||||||
s.WriteString(t.constructHeaders())
|
sb.WriteString(t.constructHeaders())
|
||||||
s.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
}
|
|
||||||
|
|
||||||
for r := t.offset; r < t.data.Rows(); r++ {
|
|
||||||
s.WriteString(t.constructRow(r))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bottom string
|
||||||
if t.borderBottom {
|
if t.borderBottom {
|
||||||
s.WriteString(t.constructBottomBorder())
|
bottom = t.constructBottomBorder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there are no data rows render nothing.
|
||||||
|
if t.data.Rows() > 0 {
|
||||||
|
switch {
|
||||||
|
case t.useManualHeight:
|
||||||
|
// The height of the top border. Subtract 1 for the newline.
|
||||||
|
topHeight := lipgloss.Height(sb.String()) - 1
|
||||||
|
availableLines := t.height - (topHeight + lipgloss.Height(bottom))
|
||||||
|
|
||||||
|
// if the height is larger than the number of rows, use the number
|
||||||
|
// of rows.
|
||||||
|
if availableLines > t.data.Rows() {
|
||||||
|
availableLines = t.data.Rows()
|
||||||
|
}
|
||||||
|
sb.WriteString(t.constructRows(availableLines))
|
||||||
|
|
||||||
|
default:
|
||||||
|
for r := t.offset; r < t.data.Rows(); r++ {
|
||||||
|
sb.WriteString(t.constructRow(r, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString(bottom)
|
||||||
|
|
||||||
return lipgloss.NewStyle().
|
return lipgloss.NewStyle().
|
||||||
MaxHeight(t.computeHeight()).
|
MaxHeight(t.computeHeight()).
|
||||||
MaxWidth(t.width).Render(s.String())
|
MaxWidth(t.width).
|
||||||
|
Render(sb.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeWidth computes the width of the table in it's current configuration.
|
// computeWidth computes the width of the table in it's current configuration.
|
||||||
@ -376,7 +404,7 @@ func (t *Table) computeWidth() int {
|
|||||||
|
|
||||||
// computeHeight computes the height of the table in it's current configuration.
|
// computeHeight computes the height of the table in it's current configuration.
|
||||||
func (t *Table) computeHeight() int {
|
func (t *Table) computeHeight() int {
|
||||||
hasHeaders := t.headers != nil && len(t.headers) > 0
|
hasHeaders := len(t.headers) > 0
|
||||||
return sum(t.heights) - 1 + btoi(hasHeaders) +
|
return sum(t.heights) - 1 + btoi(hasHeaders) +
|
||||||
btoi(t.borderTop) + btoi(t.borderBottom) +
|
btoi(t.borderTop) + btoi(t.borderBottom) +
|
||||||
btoi(t.borderHeader) + t.data.Rows()*btoi(t.borderRow)
|
btoi(t.borderHeader) + t.data.Rows()*btoi(t.borderRow)
|
||||||
@ -433,7 +461,7 @@ func (t *Table) constructHeaders() string {
|
|||||||
s.WriteString(t.borderStyle.Render(t.border.Left))
|
s.WriteString(t.borderStyle.Render(t.border.Left))
|
||||||
}
|
}
|
||||||
for i, header := range t.headers {
|
for i, header := range t.headers {
|
||||||
s.WriteString(t.style(0, i).
|
s.WriteString(t.style(HeaderRow, i).
|
||||||
MaxHeight(1).
|
MaxHeight(1).
|
||||||
Width(t.widths[i]).
|
Width(t.widths[i]).
|
||||||
MaxWidth(t.widths[i]).
|
MaxWidth(t.widths[i]).
|
||||||
@ -466,13 +494,49 @@ func (t *Table) constructHeaders() string {
|
|||||||
return s.String()
|
return s.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Table) constructRows(availableLines int) string {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
// The number of rows to render after removing the offset.
|
||||||
|
offsetRowCount := t.data.Rows() - t.offset
|
||||||
|
|
||||||
|
// The number of rows to render. We always render at least one row.
|
||||||
|
rowsToRender := availableLines
|
||||||
|
rowsToRender = max(rowsToRender, 1)
|
||||||
|
|
||||||
|
// Check if we need to render an overflow row.
|
||||||
|
needsOverflow := rowsToRender < offsetRowCount
|
||||||
|
|
||||||
|
// only use the offset as the starting value if there is overflow.
|
||||||
|
rowIdx := t.offset
|
||||||
|
if !needsOverflow {
|
||||||
|
// if there is no overflow, just render to the height of the table
|
||||||
|
// check there's enough content to fill the table
|
||||||
|
rowIdx = t.data.Rows() - rowsToRender
|
||||||
|
}
|
||||||
|
for rowsToRender > 0 && rowIdx < t.data.Rows() {
|
||||||
|
// Whenever the height is too small to render all rows, the bottom row will be an overflow row (ellipsis).
|
||||||
|
isOverflow := needsOverflow && rowsToRender == 1
|
||||||
|
|
||||||
|
sb.WriteString(t.constructRow(rowIdx, isOverflow))
|
||||||
|
|
||||||
|
rowIdx++
|
||||||
|
rowsToRender--
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
// constructRow constructs the row for the table given an index and row data
|
// constructRow constructs the row for the table given an index and row data
|
||||||
// based on the current configuration.
|
// based on the current configuration. If isOverflow is true, the row is
|
||||||
func (t *Table) constructRow(index int) string {
|
// rendered as an overflow row (using ellipsis).
|
||||||
|
func (t *Table) constructRow(index int, isOverflow bool) string {
|
||||||
var s strings.Builder
|
var s strings.Builder
|
||||||
|
|
||||||
hasHeaders := t.headers != nil && len(t.headers) > 0
|
hasHeaders := len(t.headers) > 0
|
||||||
height := t.heights[index+btoi(hasHeaders)]
|
height := t.heights[index+btoi(hasHeaders)]
|
||||||
|
if isOverflow {
|
||||||
|
height = 1
|
||||||
|
}
|
||||||
|
|
||||||
var cells []string
|
var cells []string
|
||||||
left := strings.Repeat(t.borderStyle.Render(t.border.Left)+"\n", height)
|
left := strings.Repeat(t.borderStyle.Render(t.border.Left)+"\n", height)
|
||||||
@ -481,14 +545,21 @@ func (t *Table) constructRow(index int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for c := 0; c < t.data.Columns(); c++ {
|
for c := 0; c < t.data.Columns(); c++ {
|
||||||
cell := t.data.At(index, c)
|
cellWidth := t.widths[c]
|
||||||
|
|
||||||
cells = append(cells, t.style(index+1, c).
|
cell := "…"
|
||||||
Height(height).
|
if !isOverflow {
|
||||||
|
cell = t.data.At(index, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
cellStyle := t.style(index, c)
|
||||||
|
cells = append(cells, cellStyle.
|
||||||
|
// Account for the margins in the cell sizing.
|
||||||
|
Height(height-cellStyle.GetVerticalMargins()).
|
||||||
MaxHeight(height).
|
MaxHeight(height).
|
||||||
Width(t.widths[c]).
|
Width(t.widths[c]-cellStyle.GetHorizontalMargins()).
|
||||||
MaxWidth(t.widths[c]).
|
MaxWidth(t.widths[c]).
|
||||||
Render(ansi.Truncate(cell, t.widths[c]*height, "…")))
|
Render(ansi.Truncate(cell, cellWidth*height, "…")))
|
||||||
|
|
||||||
if c < t.data.Columns()-1 && t.borderColumn {
|
if c < t.data.Columns()-1 && t.borderColumn {
|
||||||
cells = append(cells, left)
|
cells = append(cells, left)
|
||||||
|
4
vendor/github.com/charmbracelet/lipgloss/table/util.go
generated
vendored
4
vendor/github.com/charmbracelet/lipgloss/table/util.go
generated
vendored
@ -13,7 +13,7 @@ func btoi(b bool) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// max returns the greater of two integers.
|
// max returns the greater of two integers.
|
||||||
func max(a, b int) int {
|
func max(a, b int) int { //nolint:predeclared
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ func max(a, b int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// min returns the greater of two integers.
|
// min returns the greater of two integers.
|
||||||
func min(a, b int) int {
|
func min(a, b int) int { //nolint:predeclared
|
||||||
if a < b {
|
if a < b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
114
vendor/github.com/charmbracelet/x/ansi/background.go
generated
vendored
114
vendor/github.com/charmbracelet/x/ansi/background.go
generated
vendored
@ -1,9 +1,73 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Colorizer is a [color.Color] interface that can be formatted as a string.
|
||||||
|
type Colorizer interface {
|
||||||
|
color.Color
|
||||||
|
fmt.Stringer
|
||||||
|
}
|
||||||
|
|
||||||
|
// HexColorizer is a [color.Color] that can be formatted as a hex string.
|
||||||
|
type HexColorizer struct{ color.Color }
|
||||||
|
|
||||||
|
var _ Colorizer = HexColorizer{}
|
||||||
|
|
||||||
|
// String returns the color as a hex string. If the color is nil, an empty
|
||||||
|
// string is returned.
|
||||||
|
func (h HexColorizer) String() string {
|
||||||
|
if h.Color == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
r, g, b, _ := h.RGBA()
|
||||||
|
// Get the lower 8 bits
|
||||||
|
r &= 0xff
|
||||||
|
g &= 0xff
|
||||||
|
b &= 0xff
|
||||||
|
return fmt.Sprintf("#%02x%02x%02x", uint8(r), uint8(g), uint8(b)) //nolint:gosec
|
||||||
|
}
|
||||||
|
|
||||||
|
// XRGBColorizer is a [color.Color] that can be formatted as an XParseColor
|
||||||
|
// rgb: string.
|
||||||
|
//
|
||||||
|
// See: https://linux.die.net/man/3/xparsecolor
|
||||||
|
type XRGBColorizer struct{ color.Color }
|
||||||
|
|
||||||
|
var _ Colorizer = XRGBColorizer{}
|
||||||
|
|
||||||
|
// String returns the color as an XParseColor rgb: string. If the color is nil,
|
||||||
|
// an empty string is returned.
|
||||||
|
func (x XRGBColorizer) String() string {
|
||||||
|
if x.Color == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
r, g, b, _ := x.RGBA()
|
||||||
|
// Get the lower 8 bits
|
||||||
|
return fmt.Sprintf("rgb:%04x/%04x/%04x", r, g, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// XRGBAColorizer is a [color.Color] that can be formatted as an XParseColor
|
||||||
|
// rgba: string.
|
||||||
|
//
|
||||||
|
// See: https://linux.die.net/man/3/xparsecolor
|
||||||
|
type XRGBAColorizer struct{ color.Color }
|
||||||
|
|
||||||
|
var _ Colorizer = XRGBAColorizer{}
|
||||||
|
|
||||||
|
// String returns the color as an XParseColor rgba: string. If the color is nil,
|
||||||
|
// an empty string is returned.
|
||||||
|
func (x XRGBAColorizer) String() string {
|
||||||
|
if x.Color == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
r, g, b, a := x.RGBA()
|
||||||
|
// Get the lower 8 bits
|
||||||
|
return fmt.Sprintf("rgba:%04x/%04x/%04x/%04x", r, g, b, a)
|
||||||
|
}
|
||||||
|
|
||||||
// SetForegroundColor returns a sequence that sets the default terminal
|
// SetForegroundColor returns a sequence that sets the default terminal
|
||||||
// foreground color.
|
// foreground color.
|
||||||
//
|
//
|
||||||
@ -14,7 +78,16 @@ import (
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
func SetForegroundColor(c color.Color) string {
|
func SetForegroundColor(c color.Color) string {
|
||||||
return "\x1b]10;" + colorToHexString(c) + "\x07"
|
var s string
|
||||||
|
switch c := c.(type) {
|
||||||
|
case Colorizer:
|
||||||
|
s = c.String()
|
||||||
|
case fmt.Stringer:
|
||||||
|
s = c.String()
|
||||||
|
default:
|
||||||
|
s = HexColorizer{c}.String()
|
||||||
|
}
|
||||||
|
return "\x1b]10;" + s + "\x07"
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestForegroundColor is a sequence that requests the current default
|
// RequestForegroundColor is a sequence that requests the current default
|
||||||
@ -23,6 +96,12 @@ func SetForegroundColor(c color.Color) string {
|
|||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
const RequestForegroundColor = "\x1b]10;?\x07"
|
const RequestForegroundColor = "\x1b]10;?\x07"
|
||||||
|
|
||||||
|
// ResetForegroundColor is a sequence that resets the default terminal
|
||||||
|
// foreground color.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
|
const ResetForegroundColor = "\x1b]110\x07"
|
||||||
|
|
||||||
// SetBackgroundColor returns a sequence that sets the default terminal
|
// SetBackgroundColor returns a sequence that sets the default terminal
|
||||||
// background color.
|
// background color.
|
||||||
//
|
//
|
||||||
@ -33,7 +112,16 @@ const RequestForegroundColor = "\x1b]10;?\x07"
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
func SetBackgroundColor(c color.Color) string {
|
func SetBackgroundColor(c color.Color) string {
|
||||||
return "\x1b]11;" + colorToHexString(c) + "\x07"
|
var s string
|
||||||
|
switch c := c.(type) {
|
||||||
|
case Colorizer:
|
||||||
|
s = c.String()
|
||||||
|
case fmt.Stringer:
|
||||||
|
s = c.String()
|
||||||
|
default:
|
||||||
|
s = HexColorizer{c}.String()
|
||||||
|
}
|
||||||
|
return "\x1b]11;" + s + "\x07"
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestBackgroundColor is a sequence that requests the current default
|
// RequestBackgroundColor is a sequence that requests the current default
|
||||||
@ -42,6 +130,12 @@ func SetBackgroundColor(c color.Color) string {
|
|||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
const RequestBackgroundColor = "\x1b]11;?\x07"
|
const RequestBackgroundColor = "\x1b]11;?\x07"
|
||||||
|
|
||||||
|
// ResetBackgroundColor is a sequence that resets the default terminal
|
||||||
|
// background color.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
|
const ResetBackgroundColor = "\x1b]111\x07"
|
||||||
|
|
||||||
// SetCursorColor returns a sequence that sets the terminal cursor color.
|
// SetCursorColor returns a sequence that sets the terminal cursor color.
|
||||||
//
|
//
|
||||||
// OSC 12 ; color ST
|
// OSC 12 ; color ST
|
||||||
@ -51,7 +145,16 @@ const RequestBackgroundColor = "\x1b]11;?\x07"
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
func SetCursorColor(c color.Color) string {
|
func SetCursorColor(c color.Color) string {
|
||||||
return "\x1b]12;" + colorToHexString(c) + "\x07"
|
var s string
|
||||||
|
switch c := c.(type) {
|
||||||
|
case Colorizer:
|
||||||
|
s = c.String()
|
||||||
|
case fmt.Stringer:
|
||||||
|
s = c.String()
|
||||||
|
default:
|
||||||
|
s = HexColorizer{c}.String()
|
||||||
|
}
|
||||||
|
return "\x1b]12;" + s + "\x07"
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestCursorColor is a sequence that requests the current terminal cursor
|
// RequestCursorColor is a sequence that requests the current terminal cursor
|
||||||
@ -59,3 +162,8 @@ func SetCursorColor(c color.Color) string {
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
const RequestCursorColor = "\x1b]12;?\x07"
|
const RequestCursorColor = "\x1b]12;?\x07"
|
||||||
|
|
||||||
|
// ResetCursorColor is a sequence that resets the terminal cursor color.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
|
const ResetCursorColor = "\x1b]112\x07"
|
||||||
|
7
vendor/github.com/charmbracelet/x/ansi/c0.go
generated
vendored
7
vendor/github.com/charmbracelet/x/ansi/c0.go
generated
vendored
@ -69,4 +69,11 @@ const (
|
|||||||
RS = 0x1E
|
RS = 0x1E
|
||||||
// US is the unit separator character (Caret: ^_).
|
// US is the unit separator character (Caret: ^_).
|
||||||
US = 0x1F
|
US = 0x1F
|
||||||
|
|
||||||
|
// LS0 is the locking shift 0 character.
|
||||||
|
// This is an alias for [SI].
|
||||||
|
LS0 = SI
|
||||||
|
// LS1 is the locking shift 1 character.
|
||||||
|
// This is an alias for [SO].
|
||||||
|
LS1 = SO
|
||||||
)
|
)
|
||||||
|
55
vendor/github.com/charmbracelet/x/ansi/charset.go
generated
vendored
Normal file
55
vendor/github.com/charmbracelet/x/ansi/charset.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// SelectCharacterSet sets the G-set character designator to the specified
|
||||||
|
// character set.
|
||||||
|
//
|
||||||
|
// ESC Ps Pd
|
||||||
|
//
|
||||||
|
// Where Ps is the G-set character designator, and Pd is the identifier.
|
||||||
|
// For 94-character sets, the designator can be one of:
|
||||||
|
// - ( G0
|
||||||
|
// - ) G1
|
||||||
|
// - * G2
|
||||||
|
// - + G3
|
||||||
|
//
|
||||||
|
// For 96-character sets, the designator can be one of:
|
||||||
|
// - - G1
|
||||||
|
// - . G2
|
||||||
|
// - / G3
|
||||||
|
//
|
||||||
|
// Some common 94-character sets are:
|
||||||
|
// - 0 DEC Special Drawing Set
|
||||||
|
// - A United Kingdom (UK)
|
||||||
|
// - B United States (USASCII)
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// ESC ( B Select character set G0 = United States (USASCII)
|
||||||
|
// ESC ( 0 Select character set G0 = Special Character and Line Drawing Set
|
||||||
|
// ESC ) 0 Select character set G1 = Special Character and Line Drawing Set
|
||||||
|
// ESC * A Select character set G2 = United Kingdom (UK)
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/SCS.html
|
||||||
|
func SelectCharacterSet(gset byte, charset byte) string {
|
||||||
|
return "\x1b" + string(gset) + string(charset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCS is an alias for SelectCharacterSet.
|
||||||
|
func SCS(gset byte, charset byte) string {
|
||||||
|
return SelectCharacterSet(gset, charset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking Shift 1 Right (LS1R) shifts G1 into GR character set.
|
||||||
|
const LS1R = "\x1b~"
|
||||||
|
|
||||||
|
// Locking Shift 2 (LS2) shifts G2 into GL character set.
|
||||||
|
const LS2 = "\x1bn"
|
||||||
|
|
||||||
|
// Locking Shift 2 Right (LS2R) shifts G2 into GR character set.
|
||||||
|
const LS2R = "\x1b}"
|
||||||
|
|
||||||
|
// Locking Shift 3 (LS3) shifts G3 into GL character set.
|
||||||
|
const LS3 = "\x1bo"
|
||||||
|
|
||||||
|
// Locking Shift 3 Right (LS3R) shifts G3 into GR character set.
|
||||||
|
const LS3R = "\x1b|"
|
75
vendor/github.com/charmbracelet/x/ansi/csi.go
generated
vendored
75
vendor/github.com/charmbracelet/x/ansi/csi.go
generated
vendored
@ -3,8 +3,6 @@ package ansi
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CsiSequence represents a control sequence introducer (CSI) sequence.
|
// CsiSequence represents a control sequence introducer (CSI) sequence.
|
||||||
@ -23,7 +21,7 @@ type CsiSequence struct {
|
|||||||
// This is a slice of integers, where each integer is a 32-bit integer
|
// This is a slice of integers, where each integer is a 32-bit integer
|
||||||
// containing the parameter value in the lower 31 bits and a flag in the
|
// containing the parameter value in the lower 31 bits and a flag in the
|
||||||
// most significant bit indicating whether there are more sub-parameters.
|
// most significant bit indicating whether there are more sub-parameters.
|
||||||
Params []int
|
Params []Parameter
|
||||||
|
|
||||||
// Cmd contains the raw command of the sequence.
|
// Cmd contains the raw command of the sequence.
|
||||||
// The command is a 32-bit integer containing the CSI command byte in the
|
// The command is a 32-bit integer containing the CSI command byte in the
|
||||||
@ -35,17 +33,25 @@ type CsiSequence struct {
|
|||||||
// Is represented as:
|
// Is represented as:
|
||||||
//
|
//
|
||||||
// 'u' | '?' << 8
|
// 'u' | '?' << 8
|
||||||
Cmd int
|
Cmd Command
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Sequence = CsiSequence{}
|
var _ Sequence = CsiSequence{}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the CSI sequence.
|
||||||
|
func (s CsiSequence) Clone() Sequence {
|
||||||
|
return CsiSequence{
|
||||||
|
Params: append([]Parameter(nil), s.Params...),
|
||||||
|
Cmd: s.Cmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Marker returns the marker byte of the CSI sequence.
|
// Marker returns the marker byte of the CSI sequence.
|
||||||
// This is always gonna be one of the following '<' '=' '>' '?' and in the
|
// This is always gonna be one of the following '<' '=' '>' '?' and in the
|
||||||
// range of 0x3C-0x3F.
|
// range of 0x3C-0x3F.
|
||||||
// Zero is returned if the sequence does not have a marker.
|
// Zero is returned if the sequence does not have a marker.
|
||||||
func (s CsiSequence) Marker() int {
|
func (s CsiSequence) Marker() int {
|
||||||
return parser.Marker(s.Cmd)
|
return s.Cmd.Marker()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intermediate returns the intermediate byte of the CSI sequence.
|
// Intermediate returns the intermediate byte of the CSI sequence.
|
||||||
@ -54,51 +60,22 @@ func (s CsiSequence) Marker() int {
|
|||||||
// ',', '-', '.', '/'.
|
// ',', '-', '.', '/'.
|
||||||
// Zero is returned if the sequence does not have an intermediate byte.
|
// Zero is returned if the sequence does not have an intermediate byte.
|
||||||
func (s CsiSequence) Intermediate() int {
|
func (s CsiSequence) Intermediate() int {
|
||||||
return parser.Intermediate(s.Cmd)
|
return s.Cmd.Intermediate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the command byte of the CSI sequence.
|
// Command returns the command byte of the CSI sequence.
|
||||||
func (s CsiSequence) Command() int {
|
func (s CsiSequence) Command() int {
|
||||||
return parser.Command(s.Cmd)
|
return s.Cmd.Command()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param returns the parameter at the given index.
|
// Param is a helper that returns the parameter at the given index and falls
|
||||||
// It returns -1 if the parameter does not exist.
|
// back to the default value if the parameter is missing. If the index is out
|
||||||
func (s CsiSequence) Param(i int) int {
|
// of bounds, it returns the default value and false.
|
||||||
return parser.Param(s.Params, i)
|
func (s CsiSequence) Param(i, def int) (int, bool) {
|
||||||
}
|
if i < 0 || i >= len(s.Params) {
|
||||||
|
return def, false
|
||||||
// HasMore returns true if the parameter has more sub-parameters.
|
|
||||||
func (s CsiSequence) HasMore(i int) bool {
|
|
||||||
return parser.HasMore(s.Params, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subparams returns the sub-parameters of the given parameter.
|
|
||||||
// It returns nil if the parameter does not exist.
|
|
||||||
func (s CsiSequence) Subparams(i int) []int {
|
|
||||||
return parser.Subparams(s.Params, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of parameters in the sequence.
|
|
||||||
// This will return the number of parameters in the sequence, excluding any
|
|
||||||
// sub-parameters.
|
|
||||||
func (s CsiSequence) Len() int {
|
|
||||||
return parser.Len(s.Params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Range iterates over the parameters of the sequence and calls the given
|
|
||||||
// function for each parameter.
|
|
||||||
// The function should return false to stop the iteration.
|
|
||||||
func (s CsiSequence) Range(fn func(i int, param int, hasMore bool) bool) {
|
|
||||||
parser.Range(s.Params, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a copy of the CSI sequence.
|
|
||||||
func (s CsiSequence) Clone() Sequence {
|
|
||||||
return CsiSequence{
|
|
||||||
Params: append([]int(nil), s.Params...),
|
|
||||||
Cmd: s.Cmd,
|
|
||||||
}
|
}
|
||||||
|
return s.Params[i].Param(def), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the sequence.
|
// String returns a string representation of the sequence.
|
||||||
@ -114,23 +91,25 @@ func (s CsiSequence) buffer() *bytes.Buffer {
|
|||||||
if m := s.Marker(); m != 0 {
|
if m := s.Marker(); m != 0 {
|
||||||
b.WriteByte(byte(m))
|
b.WriteByte(byte(m))
|
||||||
}
|
}
|
||||||
s.Range(func(i, param int, hasMore bool) bool {
|
for i, p := range s.Params {
|
||||||
|
param := p.Param(-1)
|
||||||
if param >= 0 {
|
if param >= 0 {
|
||||||
b.WriteString(strconv.Itoa(param))
|
b.WriteString(strconv.Itoa(param))
|
||||||
}
|
}
|
||||||
if i < len(s.Params)-1 {
|
if i < len(s.Params)-1 {
|
||||||
if hasMore {
|
if p.HasMore() {
|
||||||
b.WriteByte(':')
|
b.WriteByte(':')
|
||||||
} else {
|
} else {
|
||||||
b.WriteByte(';')
|
b.WriteByte(';')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
}
|
||||||
})
|
|
||||||
if i := s.Intermediate(); i != 0 {
|
if i := s.Intermediate(); i != 0 {
|
||||||
b.WriteByte(byte(i))
|
b.WriteByte(byte(i))
|
||||||
}
|
}
|
||||||
b.WriteByte(byte(s.Command()))
|
if cmd := s.Command(); cmd != 0 {
|
||||||
|
b.WriteByte(byte(cmd))
|
||||||
|
}
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
105
vendor/github.com/charmbracelet/x/ansi/ctrl.go
generated
vendored
105
vendor/github.com/charmbracelet/x/ansi/ctrl.go
generated
vendored
@ -1,12 +1,61 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequestNameVersion (XTVERSION) is a control sequence that requests the
|
||||||
|
// terminal's name and version. It responds with a DSR sequence identifying the
|
||||||
|
// terminal.
|
||||||
|
//
|
||||||
|
// CSI > 0 q
|
||||||
|
// DCS > | text ST
|
||||||
|
//
|
||||||
|
// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys
|
||||||
|
const (
|
||||||
|
RequestNameVersion = "\x1b[>0q"
|
||||||
|
XTVERSION = RequestNameVersion
|
||||||
|
)
|
||||||
|
|
||||||
// RequestXTVersion is a control sequence that requests the terminal's XTVERSION. It responds with a DSR sequence identifying the version.
|
// RequestXTVersion is a control sequence that requests the terminal's XTVERSION. It responds with a DSR sequence identifying the version.
|
||||||
//
|
//
|
||||||
// CSI > Ps q
|
// CSI > Ps q
|
||||||
// DCS > | text ST
|
// DCS > | text ST
|
||||||
//
|
//
|
||||||
// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys
|
// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys
|
||||||
const RequestXTVersion = "\x1b[>0q"
|
// Deprecated: use [RequestNameVersion] instead.
|
||||||
|
const RequestXTVersion = RequestNameVersion
|
||||||
|
|
||||||
|
// PrimaryDeviceAttributes (DA1) is a control sequence that reports the
|
||||||
|
// terminal's primary device attributes.
|
||||||
|
//
|
||||||
|
// CSI c
|
||||||
|
// CSI 0 c
|
||||||
|
// CSI ? Ps ; ... c
|
||||||
|
//
|
||||||
|
// If no attributes are given, or if the attribute is 0, this function returns
|
||||||
|
// the request sequence. Otherwise, it returns the response sequence.
|
||||||
|
//
|
||||||
|
// See https://vt100.net/docs/vt510-rm/DA1.html
|
||||||
|
func PrimaryDeviceAttributes(attrs ...int) string {
|
||||||
|
if len(attrs) == 0 {
|
||||||
|
return "\x1b[c"
|
||||||
|
} else if len(attrs) == 1 && attrs[0] == 0 {
|
||||||
|
return "\x1b[0c"
|
||||||
|
}
|
||||||
|
|
||||||
|
as := make([]string, len(attrs))
|
||||||
|
for i, a := range attrs {
|
||||||
|
as[i] = strconv.Itoa(a)
|
||||||
|
}
|
||||||
|
return "\x1b[?" + strings.Join(as, ";") + "c"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DA1 is an alias for [PrimaryDeviceAttributes].
|
||||||
|
func DA1(attrs ...int) string {
|
||||||
|
return PrimaryDeviceAttributes(attrs...)
|
||||||
|
}
|
||||||
|
|
||||||
// RequestPrimaryDeviceAttributes is a control sequence that requests the
|
// RequestPrimaryDeviceAttributes is a control sequence that requests the
|
||||||
// terminal's primary device attributes (DA1).
|
// terminal's primary device attributes (DA1).
|
||||||
@ -15,3 +64,57 @@ const RequestXTVersion = "\x1b[>0q"
|
|||||||
//
|
//
|
||||||
// See https://vt100.net/docs/vt510-rm/DA1.html
|
// See https://vt100.net/docs/vt510-rm/DA1.html
|
||||||
const RequestPrimaryDeviceAttributes = "\x1b[c"
|
const RequestPrimaryDeviceAttributes = "\x1b[c"
|
||||||
|
|
||||||
|
// SecondaryDeviceAttributes (DA2) is a control sequence that reports the
|
||||||
|
// terminal's secondary device attributes.
|
||||||
|
//
|
||||||
|
// CSI > c
|
||||||
|
// CSI > 0 c
|
||||||
|
// CSI > Ps ; ... c
|
||||||
|
//
|
||||||
|
// See https://vt100.net/docs/vt510-rm/DA2.html
|
||||||
|
func SecondaryDeviceAttributes(attrs ...int) string {
|
||||||
|
if len(attrs) == 0 {
|
||||||
|
return "\x1b[>c"
|
||||||
|
}
|
||||||
|
|
||||||
|
as := make([]string, len(attrs))
|
||||||
|
for i, a := range attrs {
|
||||||
|
as[i] = strconv.Itoa(a)
|
||||||
|
}
|
||||||
|
return "\x1b[>" + strings.Join(as, ";") + "c"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DA2 is an alias for [SecondaryDeviceAttributes].
|
||||||
|
func DA2(attrs ...int) string {
|
||||||
|
return SecondaryDeviceAttributes(attrs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TertiaryDeviceAttributes (DA3) is a control sequence that reports the
|
||||||
|
// terminal's tertiary device attributes.
|
||||||
|
//
|
||||||
|
// CSI = c
|
||||||
|
// CSI = 0 c
|
||||||
|
// DCS ! | Text ST
|
||||||
|
//
|
||||||
|
// Where Text is the unit ID for the terminal.
|
||||||
|
//
|
||||||
|
// If no unit ID is given, or if the unit ID is 0, this function returns the
|
||||||
|
// request sequence. Otherwise, it returns the response sequence.
|
||||||
|
//
|
||||||
|
// See https://vt100.net/docs/vt510-rm/DA3.html
|
||||||
|
func TertiaryDeviceAttributes(unitID string) string {
|
||||||
|
switch unitID {
|
||||||
|
case "":
|
||||||
|
return "\x1b[=c"
|
||||||
|
case "0":
|
||||||
|
return "\x1b[=0c"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "\x1bP!|" + unitID + "\x1b\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DA3 is an alias for [TertiaryDeviceAttributes].
|
||||||
|
func DA3(unitID string) string {
|
||||||
|
return TertiaryDeviceAttributes(unitID)
|
||||||
|
}
|
||||||
|
473
vendor/github.com/charmbracelet/x/ansi/cursor.go
generated
vendored
473
vendor/github.com/charmbracelet/x/ansi/cursor.go
generated
vendored
@ -8,7 +8,10 @@ import "strconv"
|
|||||||
// ESC 7
|
// ESC 7
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECSC.html
|
// See: https://vt100.net/docs/vt510-rm/DECSC.html
|
||||||
const SaveCursor = "\x1b7"
|
const (
|
||||||
|
SaveCursor = "\x1b7"
|
||||||
|
DECSC = SaveCursor
|
||||||
|
)
|
||||||
|
|
||||||
// RestoreCursor (DECRC) is an escape sequence that restores the cursor
|
// RestoreCursor (DECRC) is an escape sequence that restores the cursor
|
||||||
// position.
|
// position.
|
||||||
@ -16,10 +19,13 @@ const SaveCursor = "\x1b7"
|
|||||||
// ESC 8
|
// ESC 8
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECRC.html
|
// See: https://vt100.net/docs/vt510-rm/DECRC.html
|
||||||
const RestoreCursor = "\x1b8"
|
const (
|
||||||
|
RestoreCursor = "\x1b8"
|
||||||
|
DECRC = RestoreCursor
|
||||||
|
)
|
||||||
|
|
||||||
// RequestCursorPosition (CPR) is an escape sequence that requests the current
|
// RequestCursorPosition is an escape sequence that requests the current cursor
|
||||||
// cursor position.
|
// position.
|
||||||
//
|
//
|
||||||
// CSI 6 n
|
// CSI 6 n
|
||||||
//
|
//
|
||||||
@ -60,9 +66,18 @@ func CursorUp(n int) string {
|
|||||||
return "\x1b[" + s + "A"
|
return "\x1b[" + s + "A"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CUU is an alias for [CursorUp].
|
||||||
|
func CUU(n int) string {
|
||||||
|
return CursorUp(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CUU1 is a sequence for moving the cursor up one cell.
|
||||||
|
const CUU1 = "\x1b[A"
|
||||||
|
|
||||||
// CursorUp1 is a sequence for moving the cursor up one cell.
|
// CursorUp1 is a sequence for moving the cursor up one cell.
|
||||||
//
|
//
|
||||||
// This is equivalent to CursorUp(1).
|
// This is equivalent to CursorUp(1).
|
||||||
|
// Deprecated: use [CUU1] instead.
|
||||||
const CursorUp1 = "\x1b[A"
|
const CursorUp1 = "\x1b[A"
|
||||||
|
|
||||||
// CursorDown (CUD) returns a sequence for moving the cursor down n cells.
|
// CursorDown (CUD) returns a sequence for moving the cursor down n cells.
|
||||||
@ -78,17 +93,26 @@ func CursorDown(n int) string {
|
|||||||
return "\x1b[" + s + "B"
|
return "\x1b[" + s + "B"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CUD is an alias for [CursorDown].
|
||||||
|
func CUD(n int) string {
|
||||||
|
return CursorDown(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CUD1 is a sequence for moving the cursor down one cell.
|
||||||
|
const CUD1 = "\x1b[B"
|
||||||
|
|
||||||
// CursorDown1 is a sequence for moving the cursor down one cell.
|
// CursorDown1 is a sequence for moving the cursor down one cell.
|
||||||
//
|
//
|
||||||
// This is equivalent to CursorDown(1).
|
// This is equivalent to CursorDown(1).
|
||||||
|
// Deprecated: use [CUD1] instead.
|
||||||
const CursorDown1 = "\x1b[B"
|
const CursorDown1 = "\x1b[B"
|
||||||
|
|
||||||
// CursorRight (CUF) returns a sequence for moving the cursor right n cells.
|
// CursorForward (CUF) returns a sequence for moving the cursor right n cells.
|
||||||
//
|
//
|
||||||
// CSI n C
|
// # CSI n C
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/CUF.html
|
// See: https://vt100.net/docs/vt510-rm/CUF.html
|
||||||
func CursorRight(n int) string {
|
func CursorForward(n int) string {
|
||||||
var s string
|
var s string
|
||||||
if n > 1 {
|
if n > 1 {
|
||||||
s = strconv.Itoa(n)
|
s = strconv.Itoa(n)
|
||||||
@ -96,17 +120,36 @@ func CursorRight(n int) string {
|
|||||||
return "\x1b[" + s + "C"
|
return "\x1b[" + s + "C"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CUF is an alias for [CursorForward].
|
||||||
|
func CUF(n int) string {
|
||||||
|
return CursorForward(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CUF1 is a sequence for moving the cursor right one cell.
|
||||||
|
const CUF1 = "\x1b[C"
|
||||||
|
|
||||||
|
// CursorRight (CUF) returns a sequence for moving the cursor right n cells.
|
||||||
|
//
|
||||||
|
// CSI n C
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CUF.html
|
||||||
|
// Deprecated: use [CursorForward] instead.
|
||||||
|
func CursorRight(n int) string {
|
||||||
|
return CursorForward(n)
|
||||||
|
}
|
||||||
|
|
||||||
// CursorRight1 is a sequence for moving the cursor right one cell.
|
// CursorRight1 is a sequence for moving the cursor right one cell.
|
||||||
//
|
//
|
||||||
// This is equivalent to CursorRight(1).
|
// This is equivalent to CursorRight(1).
|
||||||
const CursorRight1 = "\x1b[C"
|
// Deprecated: use [CUF1] instead.
|
||||||
|
const CursorRight1 = CUF1
|
||||||
|
|
||||||
// CursorLeft (CUB) returns a sequence for moving the cursor left n cells.
|
// CursorBackward (CUB) returns a sequence for moving the cursor left n cells.
|
||||||
//
|
//
|
||||||
// CSI n D
|
// # CSI n D
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/CUB.html
|
// See: https://vt100.net/docs/vt510-rm/CUB.html
|
||||||
func CursorLeft(n int) string {
|
func CursorBackward(n int) string {
|
||||||
var s string
|
var s string
|
||||||
if n > 1 {
|
if n > 1 {
|
||||||
s = strconv.Itoa(n)
|
s = strconv.Itoa(n)
|
||||||
@ -114,10 +157,29 @@ func CursorLeft(n int) string {
|
|||||||
return "\x1b[" + s + "D"
|
return "\x1b[" + s + "D"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CUB is an alias for [CursorBackward].
|
||||||
|
func CUB(n int) string {
|
||||||
|
return CursorBackward(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CUB1 is a sequence for moving the cursor left one cell.
|
||||||
|
const CUB1 = "\x1b[D"
|
||||||
|
|
||||||
|
// CursorLeft (CUB) returns a sequence for moving the cursor left n cells.
|
||||||
|
//
|
||||||
|
// CSI n D
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CUB.html
|
||||||
|
// Deprecated: use [CursorBackward] instead.
|
||||||
|
func CursorLeft(n int) string {
|
||||||
|
return CursorBackward(n)
|
||||||
|
}
|
||||||
|
|
||||||
// CursorLeft1 is a sequence for moving the cursor left one cell.
|
// CursorLeft1 is a sequence for moving the cursor left one cell.
|
||||||
//
|
//
|
||||||
// This is equivalent to CursorLeft(1).
|
// This is equivalent to CursorLeft(1).
|
||||||
const CursorLeft1 = "\x1b[D"
|
// Deprecated: use [CUB1] instead.
|
||||||
|
const CursorLeft1 = CUB1
|
||||||
|
|
||||||
// CursorNextLine (CNL) returns a sequence for moving the cursor to the
|
// CursorNextLine (CNL) returns a sequence for moving the cursor to the
|
||||||
// beginning of the next line n times.
|
// beginning of the next line n times.
|
||||||
@ -133,6 +195,11 @@ func CursorNextLine(n int) string {
|
|||||||
return "\x1b[" + s + "E"
|
return "\x1b[" + s + "E"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CNL is an alias for [CursorNextLine].
|
||||||
|
func CNL(n int) string {
|
||||||
|
return CursorNextLine(n)
|
||||||
|
}
|
||||||
|
|
||||||
// CursorPreviousLine (CPL) returns a sequence for moving the cursor to the
|
// CursorPreviousLine (CPL) returns a sequence for moving the cursor to the
|
||||||
// beginning of the previous line n times.
|
// beginning of the previous line n times.
|
||||||
//
|
//
|
||||||
@ -147,25 +214,264 @@ func CursorPreviousLine(n int) string {
|
|||||||
return "\x1b[" + s + "F"
|
return "\x1b[" + s + "F"
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveCursor (CUP) returns a sequence for moving the cursor to the given row
|
// CPL is an alias for [CursorPreviousLine].
|
||||||
// and column.
|
func CPL(n int) string {
|
||||||
|
return CursorPreviousLine(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorHorizontalAbsolute (CHA) returns a sequence for moving the cursor to
|
||||||
|
// the given column.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n G
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CHA.html
|
||||||
|
func CursorHorizontalAbsolute(col int) string {
|
||||||
|
var s string
|
||||||
|
if col > 0 {
|
||||||
|
s = strconv.Itoa(col)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "G"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHA is an alias for [CursorHorizontalAbsolute].
|
||||||
|
func CHA(col int) string {
|
||||||
|
return CursorHorizontalAbsolute(col)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorPosition (CUP) returns a sequence for setting the cursor to the
|
||||||
|
// given row and column.
|
||||||
|
//
|
||||||
|
// Default is 1,1.
|
||||||
//
|
//
|
||||||
// CSI n ; m H
|
// CSI n ; m H
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/CUP.html
|
// See: https://vt100.net/docs/vt510-rm/CUP.html
|
||||||
func MoveCursor(row, col int) string {
|
func CursorPosition(col, row int) string {
|
||||||
if row < 0 {
|
if row <= 0 && col <= 0 {
|
||||||
row = 0
|
return HomeCursorPosition
|
||||||
}
|
}
|
||||||
if col < 0 {
|
|
||||||
col = 0
|
var r, c string
|
||||||
|
if row > 0 {
|
||||||
|
r = strconv.Itoa(row)
|
||||||
}
|
}
|
||||||
return "\x1b[" + strconv.Itoa(row) + ";" + strconv.Itoa(col) + "H"
|
if col > 0 {
|
||||||
|
c = strconv.Itoa(col)
|
||||||
|
}
|
||||||
|
return "\x1b[" + r + ";" + c + "H"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CUP is an alias for [CursorPosition].
|
||||||
|
func CUP(col, row int) string {
|
||||||
|
return CursorPosition(col, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorHomePosition is a sequence for moving the cursor to the upper left
|
||||||
|
// corner of the scrolling region. This is equivalent to `CursorPosition(1, 1)`.
|
||||||
|
const CursorHomePosition = "\x1b[H"
|
||||||
|
|
||||||
|
// SetCursorPosition (CUP) returns a sequence for setting the cursor to the
|
||||||
|
// given row and column.
|
||||||
|
//
|
||||||
|
// CSI n ; m H
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CUP.html
|
||||||
|
// Deprecated: use [CursorPosition] instead.
|
||||||
|
func SetCursorPosition(col, row int) string {
|
||||||
|
if row <= 0 && col <= 0 {
|
||||||
|
return HomeCursorPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
var r, c string
|
||||||
|
if row > 0 {
|
||||||
|
r = strconv.Itoa(row)
|
||||||
|
}
|
||||||
|
if col > 0 {
|
||||||
|
c = strconv.Itoa(col)
|
||||||
|
}
|
||||||
|
return "\x1b[" + r + ";" + c + "H"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HomeCursorPosition is a sequence for moving the cursor to the upper left
|
||||||
|
// corner of the scrolling region. This is equivalent to `SetCursorPosition(1, 1)`.
|
||||||
|
// Deprecated: use [CursorHomePosition] instead.
|
||||||
|
const HomeCursorPosition = CursorHomePosition
|
||||||
|
|
||||||
|
// MoveCursor (CUP) returns a sequence for setting the cursor to the
|
||||||
|
// given row and column.
|
||||||
|
//
|
||||||
|
// CSI n ; m H
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CUP.html
|
||||||
|
//
|
||||||
|
// Deprecated: use [CursorPosition] instead.
|
||||||
|
func MoveCursor(col, row int) string {
|
||||||
|
return SetCursorPosition(col, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorOrigin is a sequence for moving the cursor to the upper left corner of
|
||||||
|
// the display. This is equivalent to `SetCursorPosition(1, 1)`.
|
||||||
|
//
|
||||||
|
// Deprecated: use [CursorHomePosition] instead.
|
||||||
|
const CursorOrigin = "\x1b[1;1H"
|
||||||
|
|
||||||
// MoveCursorOrigin is a sequence for moving the cursor to the upper left
|
// MoveCursorOrigin is a sequence for moving the cursor to the upper left
|
||||||
// corner of the screen. This is equivalent to MoveCursor(1, 1).
|
// corner of the display. This is equivalent to `SetCursorPosition(1, 1)`.
|
||||||
const MoveCursorOrigin = "\x1b[1;1H"
|
//
|
||||||
|
// Deprecated: use [CursorHomePosition] instead.
|
||||||
|
const MoveCursorOrigin = CursorOrigin
|
||||||
|
|
||||||
|
// CursorHorizontalForwardTab (CHT) returns a sequence for moving the cursor to
|
||||||
|
// the next tab stop n times.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n I
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CHT.html
|
||||||
|
func CursorHorizontalForwardTab(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "I"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHT is an alias for [CursorHorizontalForwardTab].
|
||||||
|
func CHT(n int) string {
|
||||||
|
return CursorHorizontalForwardTab(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EraseCharacter (ECH) returns a sequence for erasing n characters and moving
|
||||||
|
// the cursor to the right. This doesn't affect other cell attributes.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n X
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/ECH.html
|
||||||
|
func EraseCharacter(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "X"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECH is an alias for [EraseCharacter].
|
||||||
|
func ECH(n int) string {
|
||||||
|
return EraseCharacter(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorBackwardTab (CBT) returns a sequence for moving the cursor to the
|
||||||
|
// previous tab stop n times.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n Z
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/CBT.html
|
||||||
|
func CursorBackwardTab(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "Z"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CBT is an alias for [CursorBackwardTab].
|
||||||
|
func CBT(n int) string {
|
||||||
|
return CursorBackwardTab(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerticalPositionAbsolute (VPA) returns a sequence for moving the cursor to
|
||||||
|
// the given row.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n d
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/VPA.html
|
||||||
|
func VerticalPositionAbsolute(row int) string {
|
||||||
|
var s string
|
||||||
|
if row > 0 {
|
||||||
|
s = strconv.Itoa(row)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "d"
|
||||||
|
}
|
||||||
|
|
||||||
|
// VPA is an alias for [VerticalPositionAbsolute].
|
||||||
|
func VPA(row int) string {
|
||||||
|
return VerticalPositionAbsolute(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerticalPositionRelative (VPR) returns a sequence for moving the cursor down
|
||||||
|
// n rows relative to the current position.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n e
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/VPR.html
|
||||||
|
func VerticalPositionRelative(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "e"
|
||||||
|
}
|
||||||
|
|
||||||
|
// VPR is an alias for [VerticalPositionRelative].
|
||||||
|
func VPR(n int) string {
|
||||||
|
return VerticalPositionRelative(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HorizontalVerticalPosition (HVP) returns a sequence for moving the cursor to
|
||||||
|
// the given row and column.
|
||||||
|
//
|
||||||
|
// Default is 1,1.
|
||||||
|
//
|
||||||
|
// CSI n ; m f
|
||||||
|
//
|
||||||
|
// This has the same effect as [CursorPosition].
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/HVP.html
|
||||||
|
func HorizontalVerticalPosition(col, row int) string {
|
||||||
|
var r, c string
|
||||||
|
if row > 0 {
|
||||||
|
r = strconv.Itoa(row)
|
||||||
|
}
|
||||||
|
if col > 0 {
|
||||||
|
c = strconv.Itoa(col)
|
||||||
|
}
|
||||||
|
return "\x1b[" + r + ";" + c + "f"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HVP is an alias for [HorizontalVerticalPosition].
|
||||||
|
func HVP(col, row int) string {
|
||||||
|
return HorizontalVerticalPosition(col, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HorizontalVerticalHomePosition is a sequence for moving the cursor to the
|
||||||
|
// upper left corner of the scrolling region. This is equivalent to
|
||||||
|
// `HorizontalVerticalPosition(1, 1)`.
|
||||||
|
const HorizontalVerticalHomePosition = "\x1b[f"
|
||||||
|
|
||||||
|
// SaveCurrentCursorPosition (SCOSC) is a sequence for saving the current cursor
|
||||||
|
// position for SCO console mode.
|
||||||
|
//
|
||||||
|
// CSI s
|
||||||
|
//
|
||||||
|
// This acts like [DECSC], except the page number where the cursor is located
|
||||||
|
// is not saved.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/SCOSC.html
|
||||||
|
const (
|
||||||
|
SaveCurrentCursorPosition = "\x1b[s"
|
||||||
|
SCOSC = SaveCurrentCursorPosition
|
||||||
|
)
|
||||||
|
|
||||||
// SaveCursorPosition (SCP or SCOSC) is a sequence for saving the cursor
|
// SaveCursorPosition (SCP or SCOSC) is a sequence for saving the cursor
|
||||||
// position.
|
// position.
|
||||||
@ -176,8 +482,23 @@ const MoveCursorOrigin = "\x1b[1;1H"
|
|||||||
// not saved.
|
// not saved.
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/SCOSC.html
|
// See: https://vt100.net/docs/vt510-rm/SCOSC.html
|
||||||
|
// Deprecated: use [SaveCurrentCursorPosition] instead.
|
||||||
const SaveCursorPosition = "\x1b[s"
|
const SaveCursorPosition = "\x1b[s"
|
||||||
|
|
||||||
|
// RestoreCurrentCursorPosition (SCORC) is a sequence for restoring the current
|
||||||
|
// cursor position for SCO console mode.
|
||||||
|
//
|
||||||
|
// CSI u
|
||||||
|
//
|
||||||
|
// This acts like [DECRC], except the page number where the cursor was saved is
|
||||||
|
// not restored.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/SCORC.html
|
||||||
|
const (
|
||||||
|
RestoreCurrentCursorPosition = "\x1b[u"
|
||||||
|
SCORC = RestoreCurrentCursorPosition
|
||||||
|
)
|
||||||
|
|
||||||
// RestoreCursorPosition (RCP or SCORC) is a sequence for restoring the cursor
|
// RestoreCursorPosition (RCP or SCORC) is a sequence for restoring the cursor
|
||||||
// position.
|
// position.
|
||||||
//
|
//
|
||||||
@ -187,4 +508,112 @@ const SaveCursorPosition = "\x1b[s"
|
|||||||
// cursor was saved.
|
// cursor was saved.
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/SCORC.html
|
// See: https://vt100.net/docs/vt510-rm/SCORC.html
|
||||||
|
// Deprecated: use [RestoreCurrentCursorPosition] instead.
|
||||||
const RestoreCursorPosition = "\x1b[u"
|
const RestoreCursorPosition = "\x1b[u"
|
||||||
|
|
||||||
|
// SetCursorStyle (DECSCUSR) returns a sequence for changing the cursor style.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI Ps SP q
|
||||||
|
//
|
||||||
|
// Where Ps is the cursor style:
|
||||||
|
//
|
||||||
|
// 0: Blinking block
|
||||||
|
// 1: Blinking block (default)
|
||||||
|
// 2: Steady block
|
||||||
|
// 3: Blinking underline
|
||||||
|
// 4: Steady underline
|
||||||
|
// 5: Blinking bar (xterm)
|
||||||
|
// 6: Steady bar (xterm)
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECSCUSR.html
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
|
||||||
|
func SetCursorStyle(style int) string {
|
||||||
|
if style < 0 {
|
||||||
|
style = 0
|
||||||
|
}
|
||||||
|
return "\x1b[" + strconv.Itoa(style) + " q"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECSCUSR is an alias for [SetCursorStyle].
|
||||||
|
func DECSCUSR(style int) string {
|
||||||
|
return SetCursorStyle(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPointerShape returns a sequence for changing the mouse pointer cursor
|
||||||
|
// shape. Use "default" for the default pointer shape.
|
||||||
|
//
|
||||||
|
// OSC 22 ; Pt ST
|
||||||
|
// OSC 22 ; Pt BEL
|
||||||
|
//
|
||||||
|
// Where Pt is the pointer shape name. The name can be anything that the
|
||||||
|
// operating system can understand. Some common names are:
|
||||||
|
//
|
||||||
|
// - copy
|
||||||
|
// - crosshair
|
||||||
|
// - default
|
||||||
|
// - ew-resize
|
||||||
|
// - n-resize
|
||||||
|
// - text
|
||||||
|
// - wait
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands
|
||||||
|
func SetPointerShape(shape string) string {
|
||||||
|
return "\x1b]22;" + shape + "\x07"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReverseIndex (RI) is an escape sequence for moving the cursor up one line in
|
||||||
|
// the same column. If the cursor is at the top margin, the screen scrolls
|
||||||
|
// down.
|
||||||
|
//
|
||||||
|
// This has the same effect as [RI].
|
||||||
|
const ReverseIndex = "\x1bM"
|
||||||
|
|
||||||
|
// HorizontalPositionAbsolute (HPA) returns a sequence for moving the cursor to
|
||||||
|
// the given column. This has the same effect as [CUP].
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n `
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/HPA.html
|
||||||
|
func HorizontalPositionAbsolute(col int) string {
|
||||||
|
var s string
|
||||||
|
if col > 0 {
|
||||||
|
s = strconv.Itoa(col)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "`"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HPA is an alias for [HorizontalPositionAbsolute].
|
||||||
|
func HPA(col int) string {
|
||||||
|
return HorizontalPositionAbsolute(col)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HorizontalPositionRelative (HPR) returns a sequence for moving the cursor
|
||||||
|
// right n columns relative to the current position. This has the same effect
|
||||||
|
// as [CUP].
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI n a
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/HPR.html
|
||||||
|
func HorizontalPositionRelative(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 0 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "a"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HPR is an alias for [HorizontalPositionRelative].
|
||||||
|
func HPR(n int) string {
|
||||||
|
return HorizontalPositionRelative(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index (IND) is an escape sequence for moving the cursor down one line in the
|
||||||
|
// same column. If the cursor is at the bottom margin, the screen scrolls up.
|
||||||
|
// This has the same effect as [IND].
|
||||||
|
const Index = "\x1bD"
|
||||||
|
26
vendor/github.com/charmbracelet/x/ansi/cwd.go
generated
vendored
Normal file
26
vendor/github.com/charmbracelet/x/ansi/cwd.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NotifyWorkingDirectory returns a sequence that notifies the terminal
|
||||||
|
// of the current working directory.
|
||||||
|
//
|
||||||
|
// OSC 7 ; Pt BEL
|
||||||
|
//
|
||||||
|
// Where Pt is a URL in the format "file://[host]/[path]".
|
||||||
|
// Set host to "localhost" if this is a path on the local computer.
|
||||||
|
//
|
||||||
|
// See: https://wezfurlong.org/wezterm/shell-integration.html#osc-7-escape-sequence-to-set-the-working-directory
|
||||||
|
// See: https://iterm2.com/documentation-escape-codes.html#:~:text=RemoteHost%20and%20CurrentDir%3A-,OSC%207,-%3B%20%5BPs%5D%20ST
|
||||||
|
func NotifyWorkingDirectory(host string, paths ...string) string {
|
||||||
|
path := path.Join(paths...)
|
||||||
|
u := &url.URL{
|
||||||
|
Scheme: "file",
|
||||||
|
Host: host,
|
||||||
|
Path: path,
|
||||||
|
}
|
||||||
|
return "\x1b]7;" + u.String() + "\x07"
|
||||||
|
}
|
85
vendor/github.com/charmbracelet/x/ansi/dcs.go
generated
vendored
85
vendor/github.com/charmbracelet/x/ansi/dcs.go
generated
vendored
@ -3,8 +3,7 @@ package ansi
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DcsSequence represents a Device Control String (DCS) escape sequence.
|
// DcsSequence represents a Device Control String (DCS) escape sequence.
|
||||||
@ -22,7 +21,7 @@ type DcsSequence struct {
|
|||||||
// This is a slice of integers, where each integer is a 32-bit integer
|
// This is a slice of integers, where each integer is a 32-bit integer
|
||||||
// containing the parameter value in the lower 31 bits and a flag in the
|
// containing the parameter value in the lower 31 bits and a flag in the
|
||||||
// most significant bit indicating whether there are more sub-parameters.
|
// most significant bit indicating whether there are more sub-parameters.
|
||||||
Params []int
|
Params []Parameter
|
||||||
|
|
||||||
// Data contains the string raw data of the sequence.
|
// Data contains the string raw data of the sequence.
|
||||||
// This is the data between the final byte and the escape sequence terminator.
|
// This is the data between the final byte and the escape sequence terminator.
|
||||||
@ -38,17 +37,31 @@ type DcsSequence struct {
|
|||||||
// Is represented as:
|
// Is represented as:
|
||||||
//
|
//
|
||||||
// 'r' | '>' << 8 | '$' << 16
|
// 'r' | '>' << 8 | '$' << 16
|
||||||
Cmd int
|
Cmd Command
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Sequence = DcsSequence{}
|
var _ Sequence = DcsSequence{}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the DCS sequence.
|
||||||
|
func (s DcsSequence) Clone() Sequence {
|
||||||
|
return DcsSequence{
|
||||||
|
Params: append([]Parameter(nil), s.Params...),
|
||||||
|
Data: append([]byte(nil), s.Data...),
|
||||||
|
Cmd: s.Cmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split returns a slice of data split by the semicolon.
|
||||||
|
func (s DcsSequence) Split() []string {
|
||||||
|
return strings.Split(string(s.Data), ";")
|
||||||
|
}
|
||||||
|
|
||||||
// Marker returns the marker byte of the DCS sequence.
|
// Marker returns the marker byte of the DCS sequence.
|
||||||
// This is always gonna be one of the following '<' '=' '>' '?' and in the
|
// This is always gonna be one of the following '<' '=' '>' '?' and in the
|
||||||
// range of 0x3C-0x3F.
|
// range of 0x3C-0x3F.
|
||||||
// Zero is returned if the sequence does not have a marker.
|
// Zero is returned if the sequence does not have a marker.
|
||||||
func (s DcsSequence) Marker() int {
|
func (s DcsSequence) Marker() int {
|
||||||
return parser.Marker(s.Cmd)
|
return s.Cmd.Marker()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intermediate returns the intermediate byte of the DCS sequence.
|
// Intermediate returns the intermediate byte of the DCS sequence.
|
||||||
@ -57,52 +70,22 @@ func (s DcsSequence) Marker() int {
|
|||||||
// ',', '-', '.', '/'.
|
// ',', '-', '.', '/'.
|
||||||
// Zero is returned if the sequence does not have an intermediate byte.
|
// Zero is returned if the sequence does not have an intermediate byte.
|
||||||
func (s DcsSequence) Intermediate() int {
|
func (s DcsSequence) Intermediate() int {
|
||||||
return parser.Intermediate(s.Cmd)
|
return s.Cmd.Intermediate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the command byte of the CSI sequence.
|
// Command returns the command byte of the CSI sequence.
|
||||||
func (s DcsSequence) Command() int {
|
func (s DcsSequence) Command() int {
|
||||||
return parser.Command(s.Cmd)
|
return s.Cmd.Command()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param returns the parameter at the given index.
|
// Param is a helper that returns the parameter at the given index and falls
|
||||||
// It returns -1 if the parameter does not exist.
|
// back to the default value if the parameter is missing. If the index is out
|
||||||
func (s DcsSequence) Param(i int) int {
|
// of bounds, it returns the default value and false.
|
||||||
return parser.Param(s.Params, i)
|
func (s DcsSequence) Param(i, def int) (int, bool) {
|
||||||
}
|
if i < 0 || i >= len(s.Params) {
|
||||||
|
return def, false
|
||||||
// HasMore returns true if the parameter has more sub-parameters.
|
|
||||||
func (s DcsSequence) HasMore(i int) bool {
|
|
||||||
return parser.HasMore(s.Params, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subparams returns the sub-parameters of the given parameter.
|
|
||||||
// It returns nil if the parameter does not exist.
|
|
||||||
func (s DcsSequence) Subparams(i int) []int {
|
|
||||||
return parser.Subparams(s.Params, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of parameters in the sequence.
|
|
||||||
// This will return the number of parameters in the sequence, excluding any
|
|
||||||
// sub-parameters.
|
|
||||||
func (s DcsSequence) Len() int {
|
|
||||||
return parser.Len(s.Params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Range iterates over the parameters of the sequence and calls the given
|
|
||||||
// function for each parameter.
|
|
||||||
// The function should return false to stop the iteration.
|
|
||||||
func (s DcsSequence) Range(fn func(i int, param int, hasMore bool) bool) {
|
|
||||||
parser.Range(s.Params, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a copy of the DCS sequence.
|
|
||||||
func (s DcsSequence) Clone() Sequence {
|
|
||||||
return DcsSequence{
|
|
||||||
Params: append([]int(nil), s.Params...),
|
|
||||||
Data: append([]byte(nil), s.Data...),
|
|
||||||
Cmd: s.Cmd,
|
|
||||||
}
|
}
|
||||||
|
return s.Params[i].Param(def), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the sequence.
|
// String returns a string representation of the sequence.
|
||||||
@ -118,23 +101,25 @@ func (s DcsSequence) buffer() *bytes.Buffer {
|
|||||||
if m := s.Marker(); m != 0 {
|
if m := s.Marker(); m != 0 {
|
||||||
b.WriteByte(byte(m))
|
b.WriteByte(byte(m))
|
||||||
}
|
}
|
||||||
s.Range(func(i, param int, hasMore bool) bool {
|
for i, p := range s.Params {
|
||||||
if param >= -1 {
|
param := p.Param(-1)
|
||||||
|
if param >= 0 {
|
||||||
b.WriteString(strconv.Itoa(param))
|
b.WriteString(strconv.Itoa(param))
|
||||||
}
|
}
|
||||||
if i < len(s.Params)-1 {
|
if i < len(s.Params)-1 {
|
||||||
if hasMore {
|
if p.HasMore() {
|
||||||
b.WriteByte(':')
|
b.WriteByte(':')
|
||||||
} else {
|
} else {
|
||||||
b.WriteByte(';')
|
b.WriteByte(';')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
}
|
||||||
})
|
|
||||||
if i := s.Intermediate(); i != 0 {
|
if i := s.Intermediate(); i != 0 {
|
||||||
b.WriteByte(byte(i))
|
b.WriteByte(byte(i))
|
||||||
}
|
}
|
||||||
b.WriteByte(byte(s.Command()))
|
if cmd := s.Command(); cmd != 0 {
|
||||||
|
b.WriteByte(byte(cmd))
|
||||||
|
}
|
||||||
b.Write(s.Data)
|
b.Write(s.Data)
|
||||||
b.WriteByte(ESC)
|
b.WriteByte(ESC)
|
||||||
b.WriteByte('\\')
|
b.WriteByte('\\')
|
||||||
|
9
vendor/github.com/charmbracelet/x/ansi/focus.go
generated
vendored
Normal file
9
vendor/github.com/charmbracelet/x/ansi/focus.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// Focus is an escape sequence to notify the terminal that it has focus.
|
||||||
|
// This is used with [FocusEventMode].
|
||||||
|
const Focus = "\x1b[I"
|
||||||
|
|
||||||
|
// Blur is an escape sequence to notify the terminal that it has lost focus.
|
||||||
|
// This is used with [FocusEventMode].
|
||||||
|
const Blur = "\x1b[O"
|
28
vendor/github.com/charmbracelet/x/ansi/keypad.go
generated
vendored
Normal file
28
vendor/github.com/charmbracelet/x/ansi/keypad.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// Keypad Application Mode (DECKPAM) is a mode that determines whether the
|
||||||
|
// keypad sends application sequences or ANSI sequences.
|
||||||
|
//
|
||||||
|
// This works like enabling [DECNKM].
|
||||||
|
// Use [NumericKeypadMode] to set the numeric keypad mode.
|
||||||
|
//
|
||||||
|
// ESC =
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECKPAM.html
|
||||||
|
const (
|
||||||
|
KeypadApplicationMode = "\x1b="
|
||||||
|
DECKPAM = KeypadApplicationMode
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keypad Numeric Mode (DECKPNM) is a mode that determines whether the keypad
|
||||||
|
// sends application sequences or ANSI sequences.
|
||||||
|
//
|
||||||
|
// This works the same as disabling [DECNKM].
|
||||||
|
//
|
||||||
|
// ESC >
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECKPNM.html
|
||||||
|
const (
|
||||||
|
KeypadNumericMode = "\x1b>"
|
||||||
|
DECKPNM = KeypadNumericMode
|
||||||
|
)
|
36
vendor/github.com/charmbracelet/x/ansi/kitty.go
generated
vendored
36
vendor/github.com/charmbracelet/x/ansi/kitty.go
generated
vendored
@ -8,11 +8,11 @@ const (
|
|||||||
KittyDisambiguateEscapeCodes = 1 << iota
|
KittyDisambiguateEscapeCodes = 1 << iota
|
||||||
KittyReportEventTypes
|
KittyReportEventTypes
|
||||||
KittyReportAlternateKeys
|
KittyReportAlternateKeys
|
||||||
KittyReportAllKeys
|
KittyReportAllKeysAsEscapeCodes
|
||||||
KittyReportAssociatedKeys
|
KittyReportAssociatedKeys
|
||||||
|
|
||||||
KittyAllFlags = KittyDisambiguateEscapeCodes | KittyReportEventTypes |
|
KittyAllFlags = KittyDisambiguateEscapeCodes | KittyReportEventTypes |
|
||||||
KittyReportAlternateKeys | KittyReportAllKeys | KittyReportAssociatedKeys
|
KittyReportAlternateKeys | KittyReportAllKeysAsEscapeCodes | KittyReportAssociatedKeys
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequestKittyKeyboard is a sequence to request the terminal Kitty keyboard
|
// RequestKittyKeyboard is a sequence to request the terminal Kitty keyboard
|
||||||
@ -21,9 +21,41 @@ const (
|
|||||||
// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
||||||
const RequestKittyKeyboard = "\x1b[?u"
|
const RequestKittyKeyboard = "\x1b[?u"
|
||||||
|
|
||||||
|
// KittyKeyboard returns a sequence to request keyboard enhancements from the terminal.
|
||||||
|
// The flags argument is a bitmask of the Kitty keyboard protocol flags. While
|
||||||
|
// mode specifies how the flags should be interpreted.
|
||||||
|
//
|
||||||
|
// Possible values for flags mask:
|
||||||
|
//
|
||||||
|
// 1: Disambiguate escape codes
|
||||||
|
// 2: Report event types
|
||||||
|
// 4: Report alternate keys
|
||||||
|
// 8: Report all keys as escape codes
|
||||||
|
// 16: Report associated text
|
||||||
|
//
|
||||||
|
// Possible values for mode:
|
||||||
|
//
|
||||||
|
// 1: Set given flags and unset all others
|
||||||
|
// 2: Set given flags and keep existing flags unchanged
|
||||||
|
// 3: Unset given flags and keep existing flags unchanged
|
||||||
|
//
|
||||||
|
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
|
||||||
|
func KittyKeyboard(flags, mode int) string {
|
||||||
|
return "\x1b[=" + strconv.Itoa(flags) + ";" + strconv.Itoa(mode) + "u"
|
||||||
|
}
|
||||||
|
|
||||||
// PushKittyKeyboard returns a sequence to push the given flags to the terminal
|
// PushKittyKeyboard returns a sequence to push the given flags to the terminal
|
||||||
// Kitty Keyboard stack.
|
// Kitty Keyboard stack.
|
||||||
//
|
//
|
||||||
|
// Possible values for flags mask:
|
||||||
|
//
|
||||||
|
// 0: Disable all features
|
||||||
|
// 1: Disambiguate escape codes
|
||||||
|
// 2: Report event types
|
||||||
|
// 4: Report alternate keys
|
||||||
|
// 8: Report all keys as escape codes
|
||||||
|
// 16: Report associated text
|
||||||
|
//
|
||||||
// CSI > flags u
|
// CSI > flags u
|
||||||
//
|
//
|
||||||
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
|
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
|
||||||
|
660
vendor/github.com/charmbracelet/x/ansi/mode.go
generated
vendored
660
vendor/github.com/charmbracelet/x/ansi/mode.go
generated
vendored
@ -1,100 +1,672 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
// This file define uses multiple sequences to set (SM), reset (RM), and request
|
import (
|
||||||
// (DECRQM) different ANSI and DEC modes.
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModeSetting represents a mode setting.
|
||||||
|
type ModeSetting byte
|
||||||
|
|
||||||
|
// ModeSetting constants.
|
||||||
|
const (
|
||||||
|
ModeNotRecognized ModeSetting = iota
|
||||||
|
ModeSet
|
||||||
|
ModeReset
|
||||||
|
ModePermanentlySet
|
||||||
|
ModePermanentlyReset
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsNotRecognized returns true if the mode is not recognized.
|
||||||
|
func (m ModeSetting) IsNotRecognized() bool {
|
||||||
|
return m == ModeNotRecognized
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet returns true if the mode is set or permanently set.
|
||||||
|
func (m ModeSetting) IsSet() bool {
|
||||||
|
return m == ModeSet || m == ModePermanentlySet
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsReset returns true if the mode is reset or permanently reset.
|
||||||
|
func (m ModeSetting) IsReset() bool {
|
||||||
|
return m == ModeReset || m == ModePermanentlyReset
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPermanentlySet returns true if the mode is permanently set.
|
||||||
|
func (m ModeSetting) IsPermanentlySet() bool {
|
||||||
|
return m == ModePermanentlySet
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPermanentlyReset returns true if the mode is permanently reset.
|
||||||
|
func (m ModeSetting) IsPermanentlyReset() bool {
|
||||||
|
return m == ModePermanentlyReset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode represents an interface for terminal modes.
|
||||||
|
// Modes can be set, reset, and requested.
|
||||||
|
type Mode interface {
|
||||||
|
Mode() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMode (SM) returns a sequence to set a mode.
|
||||||
|
// The mode arguments are a list of modes to set.
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/SM.html
|
// If one of the modes is a [DECMode], the sequence will use the DEC format.
|
||||||
// See: https://vt100.net/docs/vt510-rm/RM.html
|
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECRQM.html
|
|
||||||
//
|
|
||||||
// The terminal then responds to the request with a Report Mode function
|
|
||||||
// (DECRPM) in the format:
|
|
||||||
//
|
//
|
||||||
// ANSI format:
|
// ANSI format:
|
||||||
//
|
//
|
||||||
// CSI Pa ; Ps ; $ y
|
// CSI Pd ; ... ; Pd h
|
||||||
//
|
//
|
||||||
// DEC format:
|
// DEC format:
|
||||||
//
|
//
|
||||||
// CSI ? Pa ; Ps $ y
|
// CSI ? Pd ; ... ; Pd h
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/SM.html
|
||||||
|
func SetMode(modes ...Mode) string {
|
||||||
|
return setMode(false, modes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SM is an alias for [SetMode].
|
||||||
|
func SM(modes ...Mode) string {
|
||||||
|
return SetMode(modes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMode (RM) returns a sequence to reset a mode.
|
||||||
|
// The mode arguments are a list of modes to reset.
|
||||||
|
//
|
||||||
|
// If one of the modes is a [DECMode], the sequence will use the DEC format.
|
||||||
|
//
|
||||||
|
// ANSI format:
|
||||||
|
//
|
||||||
|
// CSI Pd ; ... ; Pd l
|
||||||
|
//
|
||||||
|
// DEC format:
|
||||||
|
//
|
||||||
|
// CSI ? Pd ; ... ; Pd l
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/RM.html
|
||||||
|
func ResetMode(modes ...Mode) string {
|
||||||
|
return setMode(true, modes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RM is an alias for [ResetMode].
|
||||||
|
func RM(modes ...Mode) string {
|
||||||
|
return ResetMode(modes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMode(reset bool, modes ...Mode) string {
|
||||||
|
if len(modes) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := "h"
|
||||||
|
if reset {
|
||||||
|
cmd = "l"
|
||||||
|
}
|
||||||
|
|
||||||
|
seq := "\x1b["
|
||||||
|
if len(modes) == 1 {
|
||||||
|
switch modes[0].(type) {
|
||||||
|
case DECMode:
|
||||||
|
seq += "?"
|
||||||
|
}
|
||||||
|
return seq + strconv.Itoa(modes[0].Mode()) + cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
var dec bool
|
||||||
|
list := make([]string, len(modes))
|
||||||
|
for i, m := range modes {
|
||||||
|
list[i] = strconv.Itoa(m.Mode())
|
||||||
|
switch m.(type) {
|
||||||
|
case DECMode:
|
||||||
|
dec = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if dec {
|
||||||
|
seq += "?"
|
||||||
|
}
|
||||||
|
|
||||||
|
return seq + strings.Join(list, ";") + cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestMode (DECRQM) returns a sequence to request a mode from the terminal.
|
||||||
|
// The terminal responds with a report mode function [DECRPM].
|
||||||
|
//
|
||||||
|
// ANSI format:
|
||||||
|
//
|
||||||
|
// CSI Pa $ p
|
||||||
|
//
|
||||||
|
// DEC format:
|
||||||
|
//
|
||||||
|
// CSI ? Pa $ p
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECRQM.html
|
||||||
|
func RequestMode(m Mode) string {
|
||||||
|
seq := "\x1b["
|
||||||
|
switch m.(type) {
|
||||||
|
case DECMode:
|
||||||
|
seq += "?"
|
||||||
|
}
|
||||||
|
return seq + strconv.Itoa(m.Mode()) + "$p"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECRQM is an alias for [RequestMode].
|
||||||
|
func DECRQM(m Mode) string {
|
||||||
|
return RequestMode(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportMode (DECRPM) returns a sequence that the terminal sends to the host
|
||||||
|
// in response to a mode request [DECRQM].
|
||||||
|
//
|
||||||
|
// ANSI format:
|
||||||
|
//
|
||||||
|
// CSI Pa ; Ps ; $ y
|
||||||
|
//
|
||||||
|
// DEC format:
|
||||||
|
//
|
||||||
|
// CSI ? Pa ; Ps $ y
|
||||||
//
|
//
|
||||||
// Where Pa is the mode number, and Ps is the mode value.
|
// Where Pa is the mode number, and Ps is the mode value.
|
||||||
|
//
|
||||||
|
// 0: Not recognized
|
||||||
|
// 1: Set
|
||||||
|
// 2: Reset
|
||||||
|
// 3: Permanent set
|
||||||
|
// 4: Permanent reset
|
||||||
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECRPM.html
|
// See: https://vt100.net/docs/vt510-rm/DECRPM.html
|
||||||
|
func ReportMode(mode Mode, value ModeSetting) string {
|
||||||
|
if value > 4 {
|
||||||
|
value = 0
|
||||||
|
}
|
||||||
|
switch mode.(type) {
|
||||||
|
case DECMode:
|
||||||
|
return "\x1b[?" + strconv.Itoa(mode.Mode()) + ";" + strconv.Itoa(int(value)) + "$y"
|
||||||
|
}
|
||||||
|
return "\x1b[" + strconv.Itoa(mode.Mode()) + ";" + strconv.Itoa(int(value)) + "$y"
|
||||||
|
}
|
||||||
|
|
||||||
// Application Cursor Keys (DECCKM) is a mode that determines whether the
|
// DECRPM is an alias for [ReportMode].
|
||||||
// cursor keys send ANSI cursor sequences or application sequences.
|
func DECRPM(mode Mode, value ModeSetting) string {
|
||||||
|
return ReportMode(mode, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANSIMode represents an ANSI terminal mode.
|
||||||
|
type ANSIMode int //nolint:revive
|
||||||
|
|
||||||
|
// Mode returns the ANSI mode as an integer.
|
||||||
|
func (m ANSIMode) Mode() int {
|
||||||
|
return int(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECMode represents a private DEC terminal mode.
|
||||||
|
type DECMode int
|
||||||
|
|
||||||
|
// Mode returns the DEC mode as an integer.
|
||||||
|
func (m DECMode) Mode() int {
|
||||||
|
return int(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyboard Action Mode (KAM) is a mode that controls locking of the keyboard.
|
||||||
|
// When the keyboard is locked, it cannot send data to the terminal.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/KAM.html
|
||||||
|
const (
|
||||||
|
KeyboardActionMode = ANSIMode(2)
|
||||||
|
KAM = KeyboardActionMode
|
||||||
|
|
||||||
|
SetKeyboardActionMode = "\x1b[2h"
|
||||||
|
ResetKeyboardActionMode = "\x1b[2l"
|
||||||
|
RequestKeyboardActionMode = "\x1b[2$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Insert/Replace Mode (IRM) is a mode that determines whether characters are
|
||||||
|
// inserted or replaced when typed.
|
||||||
|
//
|
||||||
|
// When enabled, characters are inserted at the cursor position pushing the
|
||||||
|
// characters to the right. When disabled, characters replace the character at
|
||||||
|
// the cursor position.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/IRM.html
|
||||||
|
const (
|
||||||
|
InsertReplaceMode = ANSIMode(4)
|
||||||
|
IRM = InsertReplaceMode
|
||||||
|
|
||||||
|
SetInsertReplaceMode = "\x1b[4h"
|
||||||
|
ResetInsertReplaceMode = "\x1b[4l"
|
||||||
|
RequestInsertReplaceMode = "\x1b[4$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Send Receive Mode (SRM) or Local Echo Mode is a mode that determines whether
|
||||||
|
// the terminal echoes characters back to the host. When enabled, the terminal
|
||||||
|
// sends characters to the host as they are typed.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/SRM.html
|
||||||
|
const (
|
||||||
|
SendReceiveMode = ANSIMode(12)
|
||||||
|
LocalEchoMode = SendReceiveMode
|
||||||
|
SRM = SendReceiveMode
|
||||||
|
|
||||||
|
SetSendReceiveMode = "\x1b[12h"
|
||||||
|
ResetSendReceiveMode = "\x1b[12l"
|
||||||
|
RequestSendReceiveMode = "\x1b[12$p"
|
||||||
|
|
||||||
|
SetLocalEchoMode = "\x1b[12h"
|
||||||
|
ResetLocalEchoMode = "\x1b[12l"
|
||||||
|
RequestLocalEchoMode = "\x1b[12$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Line Feed/New Line Mode (LNM) is a mode that determines whether the terminal
|
||||||
|
// interprets the line feed character as a new line.
|
||||||
|
//
|
||||||
|
// When enabled, the terminal interprets the line feed character as a new line.
|
||||||
|
// When disabled, the terminal interprets the line feed character as a line feed.
|
||||||
|
//
|
||||||
|
// A new line moves the cursor to the first position of the next line.
|
||||||
|
// A line feed moves the cursor down one line without changing the column
|
||||||
|
// scrolling the screen if necessary.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/LNM.html
|
||||||
|
const (
|
||||||
|
LineFeedNewLineMode = ANSIMode(20)
|
||||||
|
LNM = LineFeedNewLineMode
|
||||||
|
|
||||||
|
SetLineFeedNewLineMode = "\x1b[20h"
|
||||||
|
ResetLineFeedNewLineMode = "\x1b[20l"
|
||||||
|
RequestLineFeedNewLineMode = "\x1b[20$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cursor Keys Mode (DECCKM) is a mode that determines whether the cursor keys
|
||||||
|
// send ANSI cursor sequences or application sequences.
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECCKM.html
|
// See: https://vt100.net/docs/vt510-rm/DECCKM.html
|
||||||
|
const (
|
||||||
|
CursorKeysMode = DECMode(1)
|
||||||
|
DECCKM = CursorKeysMode
|
||||||
|
|
||||||
|
SetCursorKeysMode = "\x1b[?1h"
|
||||||
|
ResetCursorKeysMode = "\x1b[?1l"
|
||||||
|
RequestCursorKeysMode = "\x1b[?1$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetCursorKeysMode] and [ResetCursorKeysMode] instead.
|
||||||
const (
|
const (
|
||||||
EnableCursorKeys = "\x1b[?1h"
|
EnableCursorKeys = "\x1b[?1h"
|
||||||
DisableCursorKeys = "\x1b[?1l"
|
DisableCursorKeys = "\x1b[?1l"
|
||||||
RequestCursorKeys = "\x1b[?1$p"
|
)
|
||||||
|
|
||||||
|
// Origin Mode (DECOM) is a mode that determines whether the cursor moves to the
|
||||||
|
// home position or the margin position.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECOM.html
|
||||||
|
const (
|
||||||
|
OriginMode = DECMode(6)
|
||||||
|
DECOM = OriginMode
|
||||||
|
|
||||||
|
SetOriginMode = "\x1b[?6h"
|
||||||
|
ResetOriginMode = "\x1b[?6l"
|
||||||
|
RequestOriginMode = "\x1b[?6$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Auto Wrap Mode (DECAWM) is a mode that determines whether the cursor wraps
|
||||||
|
// to the next line when it reaches the right margin.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECAWM.html
|
||||||
|
const (
|
||||||
|
AutoWrapMode = DECMode(7)
|
||||||
|
DECAWM = AutoWrapMode
|
||||||
|
|
||||||
|
SetAutoWrapMode = "\x1b[?7h"
|
||||||
|
ResetAutoWrapMode = "\x1b[?7l"
|
||||||
|
RequestAutoWrapMode = "\x1b[?7$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// X10 Mouse Mode is a mode that determines whether the mouse reports on button
|
||||||
|
// presses.
|
||||||
|
//
|
||||||
|
// The terminal responds with the following encoding:
|
||||||
|
//
|
||||||
|
// CSI M CbCxCy
|
||||||
|
//
|
||||||
|
// Where Cb is the button-1, where it can be 1, 2, or 3.
|
||||||
|
// Cx and Cy are the x and y coordinates of the mouse event.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
X10MouseMode = DECMode(9)
|
||||||
|
|
||||||
|
SetX10MouseMode = "\x1b[?9h"
|
||||||
|
ResetX10MouseMode = "\x1b[?9l"
|
||||||
|
RequestX10MouseMode = "\x1b[?9$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
|
// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
|
// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
|
||||||
const (
|
const (
|
||||||
ShowCursor = "\x1b[?25h"
|
TextCursorEnableMode = DECMode(25)
|
||||||
HideCursor = "\x1b[?25l"
|
DECTCEM = TextCursorEnableMode
|
||||||
|
|
||||||
|
SetTextCursorEnableMode = "\x1b[?25h"
|
||||||
|
ResetTextCursorEnableMode = "\x1b[?25l"
|
||||||
|
RequestTextCursorEnableMode = "\x1b[?25$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are aliases for [SetTextCursorEnableMode] and [ResetTextCursorEnableMode].
|
||||||
|
const (
|
||||||
|
ShowCursor = SetTextCursorEnableMode
|
||||||
|
HideCursor = ResetTextCursorEnableMode
|
||||||
|
)
|
||||||
|
|
||||||
|
// Text Cursor Enable Mode (DECTCEM) is a mode that shows/hides the cursor.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECTCEM.html
|
||||||
|
//
|
||||||
|
// Deprecated: use [SetTextCursorEnableMode] and [ResetTextCursorEnableMode] instead.
|
||||||
|
const (
|
||||||
|
CursorEnableMode = DECMode(25)
|
||||||
RequestCursorVisibility = "\x1b[?25$p"
|
RequestCursorVisibility = "\x1b[?25$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Numeric Keypad Mode (DECNKM) is a mode that determines whether the keypad
|
||||||
|
// sends application sequences or numeric sequences.
|
||||||
|
//
|
||||||
|
// This works like [DECKPAM] and [DECKPNM], but uses different sequences.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECNKM.html
|
||||||
|
const (
|
||||||
|
NumericKeypadMode = DECMode(66)
|
||||||
|
DECNKM = NumericKeypadMode
|
||||||
|
|
||||||
|
SetNumericKeypadMode = "\x1b[?66h"
|
||||||
|
ResetNumericKeypadMode = "\x1b[?66l"
|
||||||
|
RequestNumericKeypadMode = "\x1b[?66$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Backarrow Key Mode (DECBKM) is a mode that determines whether the backspace
|
||||||
|
// key sends a backspace or delete character. Disabled by default.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECBKM.html
|
||||||
|
const (
|
||||||
|
BackarrowKeyMode = DECMode(67)
|
||||||
|
DECBKM = BackarrowKeyMode
|
||||||
|
|
||||||
|
SetBackarrowKeyMode = "\x1b[?67h"
|
||||||
|
ResetBackarrowKeyMode = "\x1b[?67l"
|
||||||
|
RequestBackarrowKeyMode = "\x1b[?67$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Left Right Margin Mode (DECLRMM) is a mode that determines whether the left
|
||||||
|
// and right margins can be set with [DECSLRM].
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECLRMM.html
|
||||||
|
const (
|
||||||
|
LeftRightMarginMode = DECMode(69)
|
||||||
|
DECLRMM = LeftRightMarginMode
|
||||||
|
|
||||||
|
SetLeftRightMarginMode = "\x1b[?69h"
|
||||||
|
ResetLeftRightMarginMode = "\x1b[?69l"
|
||||||
|
RequestLeftRightMarginMode = "\x1b[?69$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Normal Mouse Mode is a mode that determines whether the mouse reports on
|
||||||
|
// button presses and releases. It will also report modifier keys, wheel
|
||||||
|
// events, and extra buttons.
|
||||||
|
//
|
||||||
|
// It uses the same encoding as [X10MouseMode] with a few differences:
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
NormalMouseMode = DECMode(1000)
|
||||||
|
|
||||||
|
SetNormalMouseMode = "\x1b[?1000h"
|
||||||
|
ResetNormalMouseMode = "\x1b[?1000l"
|
||||||
|
RequestNormalMouseMode = "\x1b[?1000$p"
|
||||||
|
)
|
||||||
|
|
||||||
// VT Mouse Tracking is a mode that determines whether the mouse reports on
|
// VT Mouse Tracking is a mode that determines whether the mouse reports on
|
||||||
// button press and release.
|
// button press and release.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
//
|
||||||
|
// Deprecated: use [NormalMouseMode] instead.
|
||||||
const (
|
const (
|
||||||
|
MouseMode = DECMode(1000)
|
||||||
|
|
||||||
EnableMouse = "\x1b[?1000h"
|
EnableMouse = "\x1b[?1000h"
|
||||||
DisableMouse = "\x1b[?1000l"
|
DisableMouse = "\x1b[?1000l"
|
||||||
RequestMouse = "\x1b[?1000$p"
|
RequestMouse = "\x1b[?1000$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Highlight Mouse Tracking is a mode that determines whether the mouse reports
|
||||||
|
// on button presses, releases, and highlighted cells.
|
||||||
|
//
|
||||||
|
// It uses the same encoding as [NormalMouseMode] with a few differences:
|
||||||
|
//
|
||||||
|
// On highlight events, the terminal responds with the following encoding:
|
||||||
|
//
|
||||||
|
// CSI t CxCy
|
||||||
|
// CSI T CxCyCxCyCxCy
|
||||||
|
//
|
||||||
|
// Where the parameters are startx, starty, endx, endy, mousex, and mousey.
|
||||||
|
const (
|
||||||
|
HighlightMouseMode = DECMode(1001)
|
||||||
|
|
||||||
|
SetHighlightMouseMode = "\x1b[?1001h"
|
||||||
|
ResetHighlightMouseMode = "\x1b[?1001l"
|
||||||
|
RequestHighlightMouseMode = "\x1b[?1001$p"
|
||||||
|
)
|
||||||
|
|
||||||
// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on
|
// VT Hilite Mouse Tracking is a mode that determines whether the mouse reports on
|
||||||
// button presses, releases, and highlighted cells.
|
// button presses, releases, and highlighted cells.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
//
|
||||||
|
// Deprecated: use [HighlightMouseMode] instead.
|
||||||
const (
|
const (
|
||||||
|
MouseHiliteMode = DECMode(1001)
|
||||||
|
|
||||||
EnableMouseHilite = "\x1b[?1001h"
|
EnableMouseHilite = "\x1b[?1001h"
|
||||||
DisableMouseHilite = "\x1b[?1001l"
|
DisableMouseHilite = "\x1b[?1001l"
|
||||||
RequestMouseHilite = "\x1b[?1001$p"
|
RequestMouseHilite = "\x1b[?1001$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Button Event Mouse Tracking is essentially the same as [NormalMouseMode],
|
||||||
|
// but it also reports button-motion events when a button is pressed.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
ButtonEventMouseMode = DECMode(1002)
|
||||||
|
|
||||||
|
SetButtonEventMouseMode = "\x1b[?1002h"
|
||||||
|
ResetButtonEventMouseMode = "\x1b[?1002l"
|
||||||
|
RequestButtonEventMouseMode = "\x1b[?1002$p"
|
||||||
|
)
|
||||||
|
|
||||||
// Cell Motion Mouse Tracking is a mode that determines whether the mouse
|
// Cell Motion Mouse Tracking is a mode that determines whether the mouse
|
||||||
// reports on button press, release, and motion events.
|
// reports on button press, release, and motion events.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
//
|
||||||
|
// Deprecated: use [ButtonEventMouseMode] instead.
|
||||||
const (
|
const (
|
||||||
|
MouseCellMotionMode = DECMode(1002)
|
||||||
|
|
||||||
EnableMouseCellMotion = "\x1b[?1002h"
|
EnableMouseCellMotion = "\x1b[?1002h"
|
||||||
DisableMouseCellMotion = "\x1b[?1002l"
|
DisableMouseCellMotion = "\x1b[?1002l"
|
||||||
RequestMouseCellMotion = "\x1b[?1002$p"
|
RequestMouseCellMotion = "\x1b[?1002$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Any Event Mouse Tracking is the same as [ButtonEventMouseMode], except that
|
||||||
|
// all motion events are reported even if no mouse buttons are pressed.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
AnyEventMouseMode = DECMode(1003)
|
||||||
|
|
||||||
|
SetAnyEventMouseMode = "\x1b[?1003h"
|
||||||
|
ResetAnyEventMouseMode = "\x1b[?1003l"
|
||||||
|
RequestAnyEventMouseMode = "\x1b[?1003$p"
|
||||||
|
)
|
||||||
|
|
||||||
// All Mouse Tracking is a mode that determines whether the mouse reports on
|
// All Mouse Tracking is a mode that determines whether the mouse reports on
|
||||||
// button press, release, motion, and highlight events.
|
// button press, release, motion, and highlight events.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
//
|
||||||
|
// Deprecated: use [AnyEventMouseMode] instead.
|
||||||
const (
|
const (
|
||||||
|
MouseAllMotionMode = DECMode(1003)
|
||||||
|
|
||||||
EnableMouseAllMotion = "\x1b[?1003h"
|
EnableMouseAllMotion = "\x1b[?1003h"
|
||||||
DisableMouseAllMotion = "\x1b[?1003l"
|
DisableMouseAllMotion = "\x1b[?1003l"
|
||||||
RequestMouseAllMotion = "\x1b[?1003$p"
|
RequestMouseAllMotion = "\x1b[?1003$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SGR Mouse Extension is a mode that determines whether the mouse reports events
|
// Focus Event Mode is a mode that determines whether the terminal reports focus
|
||||||
// formatted with SGR parameters.
|
// and blur events.
|
||||||
|
//
|
||||||
|
// The terminal sends the following encoding:
|
||||||
|
//
|
||||||
|
// CSI I // Focus In
|
||||||
|
// CSI O // Focus Out
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Focus-Tracking
|
||||||
|
const (
|
||||||
|
FocusEventMode = DECMode(1004)
|
||||||
|
|
||||||
|
SetFocusEventMode = "\x1b[?1004h"
|
||||||
|
ResetFocusEventMode = "\x1b[?1004l"
|
||||||
|
RequestFocusEventMode = "\x1b[?1004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetFocusEventMode], [ResetFocusEventMode], and
|
||||||
|
// [RequestFocusEventMode] instead.
|
||||||
|
const (
|
||||||
|
ReportFocusMode = DECMode(1004)
|
||||||
|
|
||||||
|
EnableReportFocus = "\x1b[?1004h"
|
||||||
|
DisableReportFocus = "\x1b[?1004l"
|
||||||
|
RequestReportFocus = "\x1b[?1004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SGR Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
||||||
|
// to use SGR parameters.
|
||||||
|
//
|
||||||
|
// The terminal responds with the following encoding:
|
||||||
|
//
|
||||||
|
// CSI < Cb ; Cx ; Cy M
|
||||||
|
//
|
||||||
|
// Where Cb is the same as [NormalMouseMode], and Cx and Cy are the x and y.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
const (
|
const (
|
||||||
|
SgrExtMouseMode = DECMode(1006)
|
||||||
|
|
||||||
|
SetSgrExtMouseMode = "\x1b[?1006h"
|
||||||
|
ResetSgrExtMouseMode = "\x1b[?1006l"
|
||||||
|
RequestSgrExtMouseMode = "\x1b[?1006$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SgrExtMouseMode] [SetSgrExtMouseMode],
|
||||||
|
// [ResetSgrExtMouseMode], and [RequestSgrExtMouseMode] instead.
|
||||||
|
const (
|
||||||
|
MouseSgrExtMode = DECMode(1006)
|
||||||
EnableMouseSgrExt = "\x1b[?1006h"
|
EnableMouseSgrExt = "\x1b[?1006h"
|
||||||
DisableMouseSgrExt = "\x1b[?1006l"
|
DisableMouseSgrExt = "\x1b[?1006l"
|
||||||
RequestMouseSgrExt = "\x1b[?1006$p"
|
RequestMouseSgrExt = "\x1b[?1006$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UTF-8 Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
||||||
|
// to use UTF-8 parameters.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
Utf8ExtMouseMode = DECMode(1005)
|
||||||
|
|
||||||
|
SetUtf8ExtMouseMode = "\x1b[?1005h"
|
||||||
|
ResetUtf8ExtMouseMode = "\x1b[?1005l"
|
||||||
|
RequestUtf8ExtMouseMode = "\x1b[?1005$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URXVT Extended Mouse Mode is a mode that changes the mouse tracking encoding
|
||||||
|
// to use an alternate encoding.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
UrxvtExtMouseMode = DECMode(1015)
|
||||||
|
|
||||||
|
SetUrxvtExtMouseMode = "\x1b[?1015h"
|
||||||
|
ResetUrxvtExtMouseMode = "\x1b[?1015l"
|
||||||
|
RequestUrxvtExtMouseMode = "\x1b[?1015$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SGR Pixel Extended Mouse Mode is a mode that changes the mouse tracking
|
||||||
|
// encoding to use SGR parameters with pixel coordinates.
|
||||||
|
//
|
||||||
|
// This is similar to [SgrExtMouseMode], but also reports pixel coordinates.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
const (
|
||||||
|
SgrPixelExtMouseMode = DECMode(1016)
|
||||||
|
|
||||||
|
SetSgrPixelExtMouseMode = "\x1b[?1016h"
|
||||||
|
ResetSgrPixelExtMouseMode = "\x1b[?1016l"
|
||||||
|
RequestSgrPixelExtMouseMode = "\x1b[?1016$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alternate Screen Mode is a mode that determines whether the alternate screen
|
||||||
|
// buffer is active. When this mode is enabled, the alternate screen buffer is
|
||||||
|
// cleared.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
|
const (
|
||||||
|
AltScreenMode = DECMode(1047)
|
||||||
|
|
||||||
|
SetAltScreenMode = "\x1b[?1047h"
|
||||||
|
ResetAltScreenMode = "\x1b[?1047l"
|
||||||
|
RequestAltScreenMode = "\x1b[?1047$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save Cursor Mode is a mode that saves the cursor position.
|
||||||
|
// This is equivalent to [SaveCursor] and [RestoreCursor].
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
|
const (
|
||||||
|
SaveCursorMode = DECMode(1048)
|
||||||
|
|
||||||
|
SetSaveCursorMode = "\x1b[?1048h"
|
||||||
|
ResetSaveCursorMode = "\x1b[?1048l"
|
||||||
|
RequestSaveCursorMode = "\x1b[?1048$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Alternate Screen Save Cursor Mode is a mode that saves the cursor position as in
|
||||||
|
// [SaveCursorMode], switches to the alternate screen buffer as in [AltScreenMode],
|
||||||
|
// and clears the screen on switch.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
|
const (
|
||||||
|
AltScreenSaveCursorMode = DECMode(1049)
|
||||||
|
|
||||||
|
SetAltScreenSaveCursorMode = "\x1b[?1049h"
|
||||||
|
ResetAltScreenSaveCursorMode = "\x1b[?1049l"
|
||||||
|
RequestAltScreenSaveCursorMode = "\x1b[?1049$p"
|
||||||
|
)
|
||||||
|
|
||||||
// Alternate Screen Buffer is a mode that determines whether the alternate screen
|
// Alternate Screen Buffer is a mode that determines whether the alternate screen
|
||||||
// buffer is active.
|
// buffer is active.
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
|
||||||
|
//
|
||||||
|
// Deprecated: use [AltScreenSaveCursorMode] instead.
|
||||||
const (
|
const (
|
||||||
|
AltScreenBufferMode = DECMode(1049)
|
||||||
|
|
||||||
|
SetAltScreenBufferMode = "\x1b[?1049h"
|
||||||
|
ResetAltScreenBufferMode = "\x1b[?1049l"
|
||||||
|
RequestAltScreenBufferMode = "\x1b[?1049$p"
|
||||||
|
|
||||||
EnableAltScreenBuffer = "\x1b[?1049h"
|
EnableAltScreenBuffer = "\x1b[?1049h"
|
||||||
DisableAltScreenBuffer = "\x1b[?1049l"
|
DisableAltScreenBuffer = "\x1b[?1049l"
|
||||||
RequestAltScreenBuffer = "\x1b[?1049$p"
|
RequestAltScreenBuffer = "\x1b[?1049$p"
|
||||||
@ -105,6 +677,16 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://cirw.in/blog/bracketed-paste
|
// See: https://cirw.in/blog/bracketed-paste
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
|
||||||
|
const (
|
||||||
|
BracketedPasteMode = DECMode(2004)
|
||||||
|
|
||||||
|
SetBracketedPasteMode = "\x1b[?2004h"
|
||||||
|
ResetBracketedPasteMode = "\x1b[?2004l"
|
||||||
|
RequestBracketedPasteMode = "\x1b[?2004$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetBracketedPasteMode], [ResetBracketedPasteMode], and
|
||||||
|
// [RequestBracketedPasteMode] instead.
|
||||||
const (
|
const (
|
||||||
EnableBracketedPaste = "\x1b[?2004h"
|
EnableBracketedPaste = "\x1b[?2004h"
|
||||||
DisableBracketedPaste = "\x1b[?2004l"
|
DisableBracketedPaste = "\x1b[?2004l"
|
||||||
@ -116,15 +698,59 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036
|
// See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036
|
||||||
const (
|
const (
|
||||||
|
SynchronizedOutputMode = DECMode(2026)
|
||||||
|
|
||||||
|
SetSynchronizedOutputMode = "\x1b[?2026h"
|
||||||
|
ResetSynchronizedOutputMode = "\x1b[?2026l"
|
||||||
|
RequestSynchronizedOutputMode = "\x1b[?2026$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SynchronizedOutputMode], [SetSynchronizedOutputMode], and
|
||||||
|
// [ResetSynchronizedOutputMode], and [RequestSynchronizedOutputMode] instead.
|
||||||
|
const (
|
||||||
|
SyncdOutputMode = DECMode(2026)
|
||||||
|
|
||||||
EnableSyncdOutput = "\x1b[?2026h"
|
EnableSyncdOutput = "\x1b[?2026h"
|
||||||
DisableSyncdOutput = "\x1b[?2026l"
|
DisableSyncdOutput = "\x1b[?2026l"
|
||||||
RequestSyncdOutput = "\x1b[?2026$p"
|
RequestSyncdOutput = "\x1b[?2026$p"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Grapheme Clustering Mode is a mode that determines whether the terminal
|
||||||
|
// should look for grapheme clusters instead of single runes in the rendered
|
||||||
|
// text. This makes the terminal properly render combining characters such as
|
||||||
|
// emojis.
|
||||||
|
//
|
||||||
|
// See: https://github.com/contour-terminal/terminal-unicode-core
|
||||||
|
const (
|
||||||
|
GraphemeClusteringMode = DECMode(2027)
|
||||||
|
|
||||||
|
SetGraphemeClusteringMode = "\x1b[?2027h"
|
||||||
|
ResetGraphemeClusteringMode = "\x1b[?2027l"
|
||||||
|
RequestGraphemeClusteringMode = "\x1b[?2027$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetGraphemeClusteringMode], [ResetGraphemeClusteringMode], and
|
||||||
|
// [RequestGraphemeClusteringMode] instead.
|
||||||
|
const (
|
||||||
|
EnableGraphemeClustering = "\x1b[?2027h"
|
||||||
|
DisableGraphemeClustering = "\x1b[?2027l"
|
||||||
|
RequestGraphemeClustering = "\x1b[?2027$p"
|
||||||
|
)
|
||||||
|
|
||||||
// Win32Input is a mode that determines whether input is processed by the
|
// Win32Input is a mode that determines whether input is processed by the
|
||||||
// Win32 console and Conpty.
|
// Win32 console and Conpty.
|
||||||
//
|
//
|
||||||
// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
|
// See: https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
|
||||||
|
const (
|
||||||
|
Win32InputMode = DECMode(9001)
|
||||||
|
|
||||||
|
SetWin32InputMode = "\x1b[?9001h"
|
||||||
|
ResetWin32InputMode = "\x1b[?9001l"
|
||||||
|
RequestWin32InputMode = "\x1b[?9001$p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: use [SetWin32InputMode], [ResetWin32InputMode], and
|
||||||
|
// [RequestWin32InputMode] instead.
|
||||||
const (
|
const (
|
||||||
EnableWin32Input = "\x1b[?9001h"
|
EnableWin32Input = "\x1b[?9001h"
|
||||||
DisableWin32Input = "\x1b[?9001l"
|
DisableWin32Input = "\x1b[?9001l"
|
||||||
|
36
vendor/github.com/charmbracelet/x/ansi/mouse.go
generated
vendored
Normal file
36
vendor/github.com/charmbracelet/x/ansi/mouse.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MouseX10 returns an escape sequence representing a mouse event in X10 mode.
|
||||||
|
// Note that this requires the terminal support X10 mouse modes.
|
||||||
|
//
|
||||||
|
// CSI M Cb Cx Cy
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
|
||||||
|
func MouseX10(b byte, x, y int) string {
|
||||||
|
const x10Offset = 32
|
||||||
|
return "\x1b[M" + string(b+x10Offset) + string(byte(x)+x10Offset+1) + string(byte(y)+x10Offset+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseSgr returns an escape sequence representing a mouse event in SGR mode.
|
||||||
|
//
|
||||||
|
// CSI < Cb ; Cx ; Cy M
|
||||||
|
// CSI < Cb ; Cx ; Cy m (release)
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
|
||||||
|
func MouseSgr(b byte, x, y int, release bool) string {
|
||||||
|
s := "M"
|
||||||
|
if release {
|
||||||
|
s = "m"
|
||||||
|
}
|
||||||
|
if x < 0 {
|
||||||
|
x = -x
|
||||||
|
}
|
||||||
|
if y < 0 {
|
||||||
|
y = -y
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("\x1b[<%d;%d;%d%s", b, x+1, y+1, s)
|
||||||
|
}
|
13
vendor/github.com/charmbracelet/x/ansi/notification.go
generated
vendored
Normal file
13
vendor/github.com/charmbracelet/x/ansi/notification.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// Notify sends a desktop notification using iTerm's OSC 9.
|
||||||
|
//
|
||||||
|
// OSC 9 ; Mc ST
|
||||||
|
// OSC 9 ; Mc BEL
|
||||||
|
//
|
||||||
|
// Where Mc is the notification body.
|
||||||
|
//
|
||||||
|
// See: https://iterm2.com/documentation-escape-codes.html
|
||||||
|
func Notify(s string) string {
|
||||||
|
return "\x1b]9;" + s + "\x07"
|
||||||
|
}
|
31
vendor/github.com/charmbracelet/x/ansi/osc.go
generated
vendored
31
vendor/github.com/charmbracelet/x/ansi/osc.go
generated
vendored
@ -27,25 +27,26 @@ type OscSequence struct {
|
|||||||
|
|
||||||
var _ Sequence = OscSequence{}
|
var _ Sequence = OscSequence{}
|
||||||
|
|
||||||
// Command returns the command of the OSC sequence.
|
// Clone returns a deep copy of the OSC sequence.
|
||||||
func (s OscSequence) Command() int {
|
func (o OscSequence) Clone() Sequence {
|
||||||
return s.Cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params returns the parameters of the OSC sequence split by ';'.
|
|
||||||
// The first element is the identifier command.
|
|
||||||
func (s OscSequence) Params() []string {
|
|
||||||
return strings.Split(string(s.Data), ";")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a copy of the OSC sequence.
|
|
||||||
func (s OscSequence) Clone() Sequence {
|
|
||||||
return OscSequence{
|
return OscSequence{
|
||||||
Data: append([]byte(nil), s.Data...),
|
Data: append([]byte(nil), o.Data...),
|
||||||
Cmd: s.Cmd,
|
Cmd: o.Cmd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split returns a slice of data split by the semicolon with the first element
|
||||||
|
// being the identifier command.
|
||||||
|
func (o OscSequence) Split() []string {
|
||||||
|
return strings.Split(string(o.Data), ";")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the OSC command. This is always gonna be a positive integer
|
||||||
|
// that identifies the OSC sequence.
|
||||||
|
func (o OscSequence) Command() int {
|
||||||
|
return o.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the string representation of the OSC sequence.
|
// String returns the string representation of the OSC sequence.
|
||||||
// To be more compatible with different terminal, this will always return a
|
// To be more compatible with different terminal, this will always return a
|
||||||
// 7-bit formatted sequence, terminated by BEL.
|
// 7-bit formatted sequence, terminated by BEL.
|
||||||
|
386
vendor/github.com/charmbracelet/x/ansi/parser.go
generated
vendored
386
vendor/github.com/charmbracelet/x/ansi/parser.go
generated
vendored
@ -2,6 +2,7 @@ package ansi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/charmbracelet/x/ansi/parser"
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
)
|
)
|
||||||
@ -19,128 +20,200 @@ type ParserDispatcher func(Sequence)
|
|||||||
//
|
//
|
||||||
//go:generate go run ./gen.go
|
//go:generate go run ./gen.go
|
||||||
type Parser struct {
|
type Parser struct {
|
||||||
// Params contains the raw parameters of the sequence.
|
// the dispatch function to call when a sequence is complete
|
||||||
|
dispatcher ParserDispatcher
|
||||||
|
|
||||||
|
// params contains the raw parameters of the sequence.
|
||||||
// These parameters used when constructing CSI and DCS sequences.
|
// These parameters used when constructing CSI and DCS sequences.
|
||||||
Params []int
|
params []int
|
||||||
|
|
||||||
// Data contains the raw data of the sequence.
|
// data contains the raw data of the sequence.
|
||||||
// These data used when constructing OSC, DCS, SOS, PM, and APC sequences.
|
// These data used when constructing OSC, DCS, SOS, PM, and APC sequences.
|
||||||
Data []byte
|
data []byte
|
||||||
|
|
||||||
// DataLen keeps track of the length of the data buffer.
|
// dataLen keeps track of the length of the data buffer.
|
||||||
// If DataLen is -1, the data buffer is unlimited and will grow as needed.
|
// If dataLen is -1, the data buffer is unlimited and will grow as needed.
|
||||||
// Otherwise, DataLen is limited by the size of the Data buffer.
|
// Otherwise, dataLen is limited by the size of the data buffer.
|
||||||
DataLen int
|
dataLen int
|
||||||
|
|
||||||
// ParamsLen keeps track of the number of parameters.
|
// paramsLen keeps track of the number of parameters.
|
||||||
// This is limited by the size of the Params buffer.
|
// This is limited by the size of the params buffer.
|
||||||
ParamsLen int
|
//
|
||||||
|
// This is also used when collecting UTF-8 runes to keep track of the
|
||||||
|
// number of rune bytes collected.
|
||||||
|
paramsLen int
|
||||||
|
|
||||||
// Cmd contains the raw command along with the private marker and
|
// cmd contains the raw command along with the private marker and
|
||||||
// intermediate bytes of the sequence.
|
// intermediate bytes of the sequence.
|
||||||
// The first lower byte contains the command byte, the next byte contains
|
// The first lower byte contains the command byte, the next byte contains
|
||||||
// the private marker, and the next byte contains the intermediate byte.
|
// the private marker, and the next byte contains the intermediate byte.
|
||||||
Cmd int
|
//
|
||||||
|
// This is also used when collecting UTF-8 runes treating it as a slice of
|
||||||
|
// 4 bytes.
|
||||||
|
cmd int
|
||||||
|
|
||||||
// RuneLen keeps track of the number of bytes collected for a UTF-8 rune.
|
// state is the current state of the parser.
|
||||||
RuneLen int
|
state byte
|
||||||
|
|
||||||
// RuneBuf contains the bytes collected for a UTF-8 rune.
|
|
||||||
RuneBuf [utf8.MaxRune]byte
|
|
||||||
|
|
||||||
// State is the current state of the parser.
|
|
||||||
State byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser returns a new parser with the given sizes allocated.
|
// NewParser returns a new parser with an optional [ParserDispatcher].
|
||||||
// If dataSize is zero, the underlying data buffer will be unlimited and will
|
// The [Parser] uses a default size of 32 for the parameters and 64KB for the
|
||||||
|
// data buffer. Use [Parser.SetParamsSize] and [Parser.SetDataSize] to set the
|
||||||
|
// size of the parameters and data buffer respectively.
|
||||||
|
func NewParser(d ParserDispatcher) *Parser {
|
||||||
|
p := new(Parser)
|
||||||
|
p.SetDispatcher(d)
|
||||||
|
p.SetParamsSize(parser.MaxParamsSize)
|
||||||
|
p.SetDataSize(1024 * 64) // 64KB data buffer
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDispatcher sets the dispatcher function to call when a sequence is
|
||||||
|
// complete.
|
||||||
|
func (p *Parser) SetDispatcher(d ParserDispatcher) {
|
||||||
|
p.dispatcher = d
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetParamsSize sets the size of the parameters buffer.
|
||||||
|
// This is used when constructing CSI and DCS sequences.
|
||||||
|
func (p *Parser) SetParamsSize(size int) {
|
||||||
|
p.params = make([]int, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDataSize sets the size of the data buffer.
|
||||||
|
// This is used when constructing OSC, DCS, SOS, PM, and APC sequences.
|
||||||
|
// If size is less than or equal to 0, the data buffer is unlimited and will
|
||||||
// grow as needed.
|
// grow as needed.
|
||||||
func NewParser(paramsSize, dataSize int) *Parser {
|
func (p *Parser) SetDataSize(size int) {
|
||||||
s := &Parser{
|
if size <= 0 {
|
||||||
Params: make([]int, paramsSize),
|
size = 0
|
||||||
Data: make([]byte, dataSize),
|
p.dataLen = -1
|
||||||
}
|
}
|
||||||
if dataSize <= 0 {
|
p.data = make([]byte, size)
|
||||||
s.DataLen = -1
|
}
|
||||||
|
|
||||||
|
// Params returns the list of parsed packed parameters.
|
||||||
|
func (p *Parser) Params() []Parameter {
|
||||||
|
return unsafe.Slice((*Parameter)(unsafe.Pointer(&p.params[0])), p.paramsLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param returns the parameter at the given index and falls back to the default
|
||||||
|
// value if the parameter is missing. If the index is out of bounds, it returns
|
||||||
|
// the default value and false.
|
||||||
|
func (p *Parser) Param(i, def int) (int, bool) {
|
||||||
|
if i < 0 || i >= p.paramsLen {
|
||||||
|
return def, false
|
||||||
}
|
}
|
||||||
return s
|
return Parameter(p.params[i]).Param(def), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmd returns the packed command of the last dispatched sequence.
|
||||||
|
func (p *Parser) Cmd() Command {
|
||||||
|
return Command(p.cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rune returns the last dispatched sequence as a rune.
|
||||||
|
func (p *Parser) Rune() rune {
|
||||||
|
rw := utf8ByteLen(byte(p.cmd & 0xff))
|
||||||
|
if rw == -1 {
|
||||||
|
return utf8.RuneError
|
||||||
|
}
|
||||||
|
r, _ := utf8.DecodeRune((*[utf8.UTFMax]byte)(unsafe.Pointer(&p.cmd))[:rw])
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data returns the raw data of the last dispatched sequence.
|
||||||
|
func (p *Parser) Data() []byte {
|
||||||
|
return p.data[:p.dataLen]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset resets the parser to its initial state.
|
// Reset resets the parser to its initial state.
|
||||||
func (p *Parser) Reset() {
|
func (p *Parser) Reset() {
|
||||||
p.clear()
|
p.clear()
|
||||||
p.State = parser.GroundState
|
p.state = parser.GroundState
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear clears the parser parameters and command.
|
// clear clears the parser parameters and command.
|
||||||
func (p *Parser) clear() {
|
func (p *Parser) clear() {
|
||||||
if len(p.Params) > 0 {
|
if len(p.params) > 0 {
|
||||||
p.Params[0] = parser.MissingParam
|
p.params[0] = parser.MissingParam
|
||||||
}
|
}
|
||||||
p.ParamsLen = 0
|
p.paramsLen = 0
|
||||||
p.Cmd = 0
|
p.cmd = 0
|
||||||
p.RuneLen = 0
|
}
|
||||||
|
|
||||||
|
// State returns the current state of the parser.
|
||||||
|
func (p *Parser) State() parser.State {
|
||||||
|
return p.state
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateName returns the name of the current state.
|
// StateName returns the name of the current state.
|
||||||
func (p *Parser) StateName() string {
|
func (p *Parser) StateName() string {
|
||||||
return parser.StateNames[p.State]
|
return parser.StateNames[p.state]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the given dispatcher and byte buffer.
|
// Parse parses the given dispatcher and byte buffer.
|
||||||
func (p *Parser) Parse(dispatcher ParserDispatcher, b []byte) {
|
// Deprecated: Loop over the buffer and call [Parser.Advance] instead.
|
||||||
|
func (p *Parser) Parse(b []byte) {
|
||||||
for i := 0; i < len(b); i++ {
|
for i := 0; i < len(b); i++ {
|
||||||
p.Advance(dispatcher, b[i], i < len(b)-1)
|
p.Advance(b[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance advances the parser with the given dispatcher and byte.
|
// Advance advances the parser using the given byte. It returns the action
|
||||||
func (p *Parser) Advance(dispatcher ParserDispatcher, b byte, more bool) parser.Action {
|
// performed by the parser.
|
||||||
switch p.State {
|
func (p *Parser) Advance(b byte) parser.Action {
|
||||||
|
switch p.state {
|
||||||
case parser.Utf8State:
|
case parser.Utf8State:
|
||||||
// We handle UTF-8 here.
|
// We handle UTF-8 here.
|
||||||
return p.advanceUtf8(dispatcher, b)
|
return p.advanceUtf8(b)
|
||||||
default:
|
default:
|
||||||
return p.advance(dispatcher, b, more)
|
return p.advance(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) collectRune(b byte) {
|
func (p *Parser) collectRune(b byte) {
|
||||||
if p.RuneLen < utf8.UTFMax {
|
if p.paramsLen >= utf8.UTFMax {
|
||||||
p.RuneBuf[p.RuneLen] = b
|
return
|
||||||
p.RuneLen++
|
}
|
||||||
|
|
||||||
|
shift := p.paramsLen * 8
|
||||||
|
p.cmd &^= 0xff << shift
|
||||||
|
p.cmd |= int(b) << shift
|
||||||
|
p.paramsLen++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) dispatch(s Sequence) {
|
||||||
|
if p.dispatcher != nil {
|
||||||
|
p.dispatcher(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) advanceUtf8(dispatcher ParserDispatcher, b byte) parser.Action {
|
func (p *Parser) advanceUtf8(b byte) parser.Action {
|
||||||
// Collect UTF-8 rune bytes.
|
// Collect UTF-8 rune bytes.
|
||||||
p.collectRune(b)
|
p.collectRune(b)
|
||||||
rw := utf8ByteLen(p.RuneBuf[0])
|
rw := utf8ByteLen(byte(p.cmd & 0xff))
|
||||||
if rw == -1 {
|
if rw == -1 {
|
||||||
// We panic here because the first byte comes from the state machine,
|
// We panic here because the first byte comes from the state machine,
|
||||||
// if this panics, it means there is a bug in the state machine!
|
// if this panics, it means there is a bug in the state machine!
|
||||||
panic("invalid rune") // unreachable
|
panic("invalid rune") // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.RuneLen < rw {
|
if p.paramsLen < rw {
|
||||||
return parser.NoneAction
|
return parser.CollectAction
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have enough bytes to decode the rune
|
// We have enough bytes to decode the rune using unsafe
|
||||||
bts := p.RuneBuf[:rw]
|
p.dispatch(Rune(p.Rune()))
|
||||||
r, _ := utf8.DecodeRune(bts)
|
|
||||||
if dispatcher != nil {
|
|
||||||
dispatcher(Rune(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
p.State = parser.GroundState
|
p.state = parser.GroundState
|
||||||
p.RuneLen = 0
|
p.paramsLen = 0
|
||||||
|
|
||||||
return parser.NoneAction
|
return parser.PrintAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) advance(d ParserDispatcher, b byte, more bool) parser.Action {
|
func (p *Parser) advance(b byte) parser.Action {
|
||||||
state, action := parser.Table.Transition(p.State, b)
|
state, action := parser.Table.Transition(p.state, b)
|
||||||
|
|
||||||
// We need to clear the parser state if the state changes from EscapeState.
|
// We need to clear the parser state if the state changes from EscapeState.
|
||||||
// This is because when we enter the EscapeState, we don't get a chance to
|
// This is because when we enter the EscapeState, we don't get a chance to
|
||||||
@ -148,60 +221,53 @@ func (p *Parser) advance(d ParserDispatcher, b byte, more bool) parser.Action {
|
|||||||
// ST (\x1b\\ or \x9c), we dispatch the current sequence and transition to
|
// ST (\x1b\\ or \x9c), we dispatch the current sequence and transition to
|
||||||
// EscapeState. However, the parser state is not cleared in this case and
|
// EscapeState. However, the parser state is not cleared in this case and
|
||||||
// we need to clear it here before dispatching the esc sequence.
|
// we need to clear it here before dispatching the esc sequence.
|
||||||
if p.State != state {
|
if p.state != state {
|
||||||
switch p.State {
|
if p.state == parser.EscapeState {
|
||||||
case parser.EscapeState:
|
p.performAction(parser.ClearAction, state, b)
|
||||||
p.performAction(d, parser.ClearAction, b)
|
|
||||||
}
|
}
|
||||||
if action == parser.PutAction &&
|
if action == parser.PutAction &&
|
||||||
p.State == parser.DcsEntryState && state == parser.DcsStringState {
|
p.state == parser.DcsEntryState && state == parser.DcsStringState {
|
||||||
// XXX: This is a special case where we need to start collecting
|
// XXX: This is a special case where we need to start collecting
|
||||||
// non-string parameterized data i.e. doesn't follow the ECMA-48 §
|
// non-string parameterized data i.e. doesn't follow the ECMA-48 §
|
||||||
// 5.4.1 string parameters format.
|
// 5.4.1 string parameters format.
|
||||||
p.performAction(d, parser.StartAction, 0)
|
p.performAction(parser.StartAction, state, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle special cases
|
// Handle special cases
|
||||||
switch {
|
switch {
|
||||||
case b == ESC && p.State == parser.EscapeState:
|
case b == ESC && p.state == parser.EscapeState:
|
||||||
// Two ESCs in a row
|
// Two ESCs in a row
|
||||||
p.performAction(d, parser.ExecuteAction, b)
|
p.performAction(parser.ExecuteAction, state, b)
|
||||||
if !more {
|
|
||||||
// Two ESCs at the end of the buffer
|
|
||||||
p.performAction(d, parser.ExecuteAction, b)
|
|
||||||
}
|
|
||||||
case b == ESC && !more:
|
|
||||||
// Last byte is an ESC
|
|
||||||
p.performAction(d, parser.ExecuteAction, b)
|
|
||||||
case p.State == parser.EscapeState && b == 'P' && !more:
|
|
||||||
// ESC P (DCS) at the end of the buffer
|
|
||||||
p.performAction(d, parser.DispatchAction, b)
|
|
||||||
case p.State == parser.EscapeState && b == 'X' && !more:
|
|
||||||
// ESC X (SOS) at the end of the buffer
|
|
||||||
p.performAction(d, parser.DispatchAction, b)
|
|
||||||
case p.State == parser.EscapeState && b == '[' && !more:
|
|
||||||
// ESC [ (CSI) at the end of the buffer
|
|
||||||
p.performAction(d, parser.DispatchAction, b)
|
|
||||||
case p.State == parser.EscapeState && b == ']' && !more:
|
|
||||||
// ESC ] (OSC) at the end of the buffer
|
|
||||||
p.performAction(d, parser.DispatchAction, b)
|
|
||||||
case p.State == parser.EscapeState && b == '^' && !more:
|
|
||||||
// ESC ^ (PM) at the end of the buffer
|
|
||||||
p.performAction(d, parser.DispatchAction, b)
|
|
||||||
case p.State == parser.EscapeState && b == '_' && !more:
|
|
||||||
// ESC _ (APC) at the end of the buffer
|
|
||||||
p.performAction(d, parser.DispatchAction, b)
|
|
||||||
default:
|
default:
|
||||||
p.performAction(d, action, b)
|
p.performAction(action, state, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.State = state
|
p.state = state
|
||||||
|
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) performAction(dispatcher ParserDispatcher, action parser.Action, b byte) {
|
func (p *Parser) parseStringCmd() {
|
||||||
|
// Try to parse the command
|
||||||
|
datalen := len(p.data)
|
||||||
|
if p.dataLen >= 0 {
|
||||||
|
datalen = p.dataLen
|
||||||
|
}
|
||||||
|
for i := 0; i < datalen; i++ {
|
||||||
|
d := p.data[i]
|
||||||
|
if d < '0' || d > '9' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if p.cmd == parser.MissingCommand {
|
||||||
|
p.cmd = 0
|
||||||
|
}
|
||||||
|
p.cmd *= 10
|
||||||
|
p.cmd += int(d - '0')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) performAction(action parser.Action, state parser.State, b byte) {
|
||||||
switch action {
|
switch action {
|
||||||
case parser.IgnoreAction:
|
case parser.IgnoreAction:
|
||||||
break
|
break
|
||||||
@ -210,127 +276,117 @@ func (p *Parser) performAction(dispatcher ParserDispatcher, action parser.Action
|
|||||||
p.clear()
|
p.clear()
|
||||||
|
|
||||||
case parser.PrintAction:
|
case parser.PrintAction:
|
||||||
if utf8ByteLen(b) > 1 {
|
p.dispatch(Rune(b))
|
||||||
p.collectRune(b)
|
|
||||||
} else if dispatcher != nil {
|
|
||||||
dispatcher(Rune(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
case parser.ExecuteAction:
|
case parser.ExecuteAction:
|
||||||
if dispatcher != nil {
|
p.dispatch(ControlCode(b))
|
||||||
dispatcher(ControlCode(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
case parser.MarkerAction:
|
case parser.MarkerAction:
|
||||||
// Collect private marker
|
// Collect private marker
|
||||||
// we only store the last marker
|
// we only store the last marker
|
||||||
p.Cmd &^= 0xff << parser.MarkerShift
|
p.cmd &^= 0xff << parser.MarkerShift
|
||||||
p.Cmd |= int(b) << parser.MarkerShift
|
p.cmd |= int(b) << parser.MarkerShift
|
||||||
|
|
||||||
case parser.CollectAction:
|
case parser.CollectAction:
|
||||||
// Collect intermediate bytes
|
if state == parser.Utf8State {
|
||||||
// we only store the last intermediate byte
|
// Reset the UTF-8 counter
|
||||||
p.Cmd &^= 0xff << parser.IntermedShift
|
p.paramsLen = 0
|
||||||
p.Cmd |= int(b) << parser.IntermedShift
|
p.collectRune(b)
|
||||||
|
} else {
|
||||||
|
// Collect intermediate bytes
|
||||||
|
// we only store the last intermediate byte
|
||||||
|
p.cmd &^= 0xff << parser.IntermedShift
|
||||||
|
p.cmd |= int(b) << parser.IntermedShift
|
||||||
|
}
|
||||||
|
|
||||||
case parser.ParamAction:
|
case parser.ParamAction:
|
||||||
// Collect parameters
|
// Collect parameters
|
||||||
if p.ParamsLen >= len(p.Params) {
|
if p.paramsLen >= len(p.params) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if b >= '0' && b <= '9' {
|
if b >= '0' && b <= '9' {
|
||||||
if p.Params[p.ParamsLen] == parser.MissingParam {
|
if p.params[p.paramsLen] == parser.MissingParam {
|
||||||
p.Params[p.ParamsLen] = 0
|
p.params[p.paramsLen] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Params[p.ParamsLen] *= 10
|
p.params[p.paramsLen] *= 10
|
||||||
p.Params[p.ParamsLen] += int(b - '0')
|
p.params[p.paramsLen] += int(b - '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
if b == ':' {
|
if b == ':' {
|
||||||
p.Params[p.ParamsLen] |= parser.HasMoreFlag
|
p.params[p.paramsLen] |= parser.HasMoreFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
if b == ';' || b == ':' {
|
if b == ';' || b == ':' {
|
||||||
p.ParamsLen++
|
p.paramsLen++
|
||||||
if p.ParamsLen < len(p.Params) {
|
if p.paramsLen < len(p.params) {
|
||||||
p.Params[p.ParamsLen] = parser.MissingParam
|
p.params[p.paramsLen] = parser.MissingParam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case parser.StartAction:
|
case parser.StartAction:
|
||||||
if p.DataLen < 0 {
|
if p.dataLen < 0 && p.data != nil {
|
||||||
p.Data = make([]byte, 0)
|
p.data = p.data[:0]
|
||||||
} else {
|
} else {
|
||||||
p.DataLen = 0
|
p.dataLen = 0
|
||||||
}
|
}
|
||||||
if p.State >= parser.DcsEntryState && p.State <= parser.DcsStringState {
|
if p.state >= parser.DcsEntryState && p.state <= parser.DcsStringState {
|
||||||
// Collect the command byte for DCS
|
// Collect the command byte for DCS
|
||||||
p.Cmd |= int(b)
|
p.cmd |= int(b)
|
||||||
} else {
|
} else {
|
||||||
p.Cmd = parser.MissingCommand
|
p.cmd = parser.MissingCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
case parser.PutAction:
|
case parser.PutAction:
|
||||||
switch p.State {
|
switch p.state {
|
||||||
case parser.OscStringState:
|
case parser.OscStringState:
|
||||||
if b == ';' && p.Cmd == parser.MissingCommand {
|
if b == ';' && p.cmd == parser.MissingCommand {
|
||||||
// Try to parse the command
|
p.parseStringCmd()
|
||||||
datalen := len(p.Data)
|
|
||||||
if p.DataLen >= 0 {
|
|
||||||
datalen = p.DataLen
|
|
||||||
}
|
|
||||||
for i := 0; i < datalen; i++ {
|
|
||||||
d := p.Data[i]
|
|
||||||
if d < '0' || d > '9' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if p.Cmd == parser.MissingCommand {
|
|
||||||
p.Cmd = 0
|
|
||||||
}
|
|
||||||
p.Cmd *= 10
|
|
||||||
p.Cmd += int(d - '0')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.DataLen < 0 {
|
if p.dataLen < 0 {
|
||||||
p.Data = append(p.Data, b)
|
p.data = append(p.data, b)
|
||||||
} else {
|
} else {
|
||||||
if p.DataLen < len(p.Data) {
|
if p.dataLen < len(p.data) {
|
||||||
p.Data[p.DataLen] = b
|
p.data[p.dataLen] = b
|
||||||
p.DataLen++
|
p.dataLen++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case parser.DispatchAction:
|
case parser.DispatchAction:
|
||||||
// Increment the last parameter
|
// Increment the last parameter
|
||||||
if p.ParamsLen > 0 && p.ParamsLen < len(p.Params)-1 ||
|
if p.paramsLen > 0 && p.paramsLen < len(p.params)-1 ||
|
||||||
p.ParamsLen == 0 && len(p.Params) > 0 && p.Params[0] != parser.MissingParam {
|
p.paramsLen == 0 && len(p.params) > 0 && p.params[0] != parser.MissingParam {
|
||||||
p.ParamsLen++
|
p.paramsLen++
|
||||||
}
|
}
|
||||||
|
|
||||||
if dispatcher == nil {
|
if p.state == parser.OscStringState && p.cmd == parser.MissingCommand {
|
||||||
|
// Ensure we have a command for OSC
|
||||||
|
p.parseStringCmd()
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.dispatcher == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
var seq Sequence
|
var seq Sequence
|
||||||
data := p.Data
|
data := p.data
|
||||||
if p.DataLen >= 0 {
|
if p.dataLen >= 0 {
|
||||||
data = data[:p.DataLen]
|
data = data[:p.dataLen]
|
||||||
}
|
}
|
||||||
switch p.State {
|
switch p.state {
|
||||||
case parser.CsiEntryState, parser.CsiParamState, parser.CsiIntermediateState:
|
case parser.CsiEntryState, parser.CsiParamState, parser.CsiIntermediateState:
|
||||||
p.Cmd |= int(b)
|
p.cmd |= int(b)
|
||||||
seq = CsiSequence{Cmd: p.Cmd, Params: p.Params[:p.ParamsLen]}
|
seq = CsiSequence{Cmd: Command(p.cmd), Params: p.Params()}
|
||||||
case parser.EscapeState, parser.EscapeIntermediateState:
|
case parser.EscapeState, parser.EscapeIntermediateState:
|
||||||
p.Cmd |= int(b)
|
p.cmd |= int(b)
|
||||||
seq = EscSequence(p.Cmd)
|
seq = EscSequence(p.cmd)
|
||||||
case parser.DcsEntryState, parser.DcsParamState, parser.DcsIntermediateState, parser.DcsStringState:
|
case parser.DcsEntryState, parser.DcsParamState, parser.DcsIntermediateState, parser.DcsStringState:
|
||||||
seq = DcsSequence{Cmd: p.Cmd, Params: p.Params[:p.ParamsLen], Data: data}
|
seq = DcsSequence{Cmd: Command(p.cmd), Params: p.Params(), Data: data}
|
||||||
case parser.OscStringState:
|
case parser.OscStringState:
|
||||||
seq = OscSequence{Cmd: p.Cmd, Data: data}
|
seq = OscSequence{Cmd: p.cmd, Data: data}
|
||||||
case parser.SosStringState:
|
case parser.SosStringState:
|
||||||
seq = SosSequence{Data: data}
|
seq = SosSequence{Data: data}
|
||||||
case parser.PmStringState:
|
case parser.PmStringState:
|
||||||
@ -339,7 +395,7 @@ func (p *Parser) performAction(dispatcher ParserDispatcher, action parser.Action
|
|||||||
seq = ApcSequence{Data: data}
|
seq = ApcSequence{Data: data}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatcher(seq)
|
p.dispatch(seq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go
generated
vendored
16
vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go
generated
vendored
@ -81,6 +81,9 @@ func r(start, end byte) []byte {
|
|||||||
// - We don't ignore 0x3A (':') when building Csi and Dcs parameters and
|
// - We don't ignore 0x3A (':') when building Csi and Dcs parameters and
|
||||||
// instead use it to denote sub-parameters.
|
// instead use it to denote sub-parameters.
|
||||||
// - Support dispatching SosPmApc sequences.
|
// - Support dispatching SosPmApc sequences.
|
||||||
|
// - The DEL (0x7F) character is executed in the Ground state.
|
||||||
|
// - The DEL (0x7F) character is collected in the DcsPassthrough string state.
|
||||||
|
// - The ST C1 control character (0x9C) is executed and not ignored.
|
||||||
func GenerateTransitionTable() TransitionTable {
|
func GenerateTransitionTable() TransitionTable {
|
||||||
table := NewTransitionTable(DefaultTableSize)
|
table := NewTransitionTable(DefaultTableSize)
|
||||||
table.SetDefault(NoneAction, GroundState)
|
table.SetDefault(NoneAction, GroundState)
|
||||||
@ -91,7 +94,7 @@ func GenerateTransitionTable() TransitionTable {
|
|||||||
table.AddMany([]byte{0x18, 0x1a, 0x99, 0x9a}, state, ExecuteAction, GroundState)
|
table.AddMany([]byte{0x18, 0x1a, 0x99, 0x9a}, state, ExecuteAction, GroundState)
|
||||||
table.AddRange(0x80, 0x8F, state, ExecuteAction, GroundState)
|
table.AddRange(0x80, 0x8F, state, ExecuteAction, GroundState)
|
||||||
table.AddRange(0x90, 0x97, state, ExecuteAction, GroundState)
|
table.AddRange(0x90, 0x97, state, ExecuteAction, GroundState)
|
||||||
table.AddOne(0x9C, state, IgnoreAction, GroundState)
|
table.AddOne(0x9C, state, ExecuteAction, GroundState)
|
||||||
// Anywhere -> Escape
|
// Anywhere -> Escape
|
||||||
table.AddOne(0x1B, state, ClearAction, EscapeState)
|
table.AddOne(0x1B, state, ClearAction, EscapeState)
|
||||||
// Anywhere -> SosStringState
|
// Anywhere -> SosStringState
|
||||||
@ -107,16 +110,17 @@ func GenerateTransitionTable() TransitionTable {
|
|||||||
// Anywhere -> OscString
|
// Anywhere -> OscString
|
||||||
table.AddOne(0x9D, state, StartAction, OscStringState)
|
table.AddOne(0x9D, state, StartAction, OscStringState)
|
||||||
// Anywhere -> Utf8
|
// Anywhere -> Utf8
|
||||||
table.AddRange(0xC2, 0xDF, state, PrintAction, Utf8State) // UTF8 2 byte sequence
|
table.AddRange(0xC2, 0xDF, state, CollectAction, Utf8State) // UTF8 2 byte sequence
|
||||||
table.AddRange(0xE0, 0xEF, state, PrintAction, Utf8State) // UTF8 3 byte sequence
|
table.AddRange(0xE0, 0xEF, state, CollectAction, Utf8State) // UTF8 3 byte sequence
|
||||||
table.AddRange(0xF0, 0xF4, state, PrintAction, Utf8State) // UTF8 4 byte sequence
|
table.AddRange(0xF0, 0xF4, state, CollectAction, Utf8State) // UTF8 4 byte sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ground
|
// Ground
|
||||||
table.AddRange(0x00, 0x17, GroundState, ExecuteAction, GroundState)
|
table.AddRange(0x00, 0x17, GroundState, ExecuteAction, GroundState)
|
||||||
table.AddOne(0x19, GroundState, ExecuteAction, GroundState)
|
table.AddOne(0x19, GroundState, ExecuteAction, GroundState)
|
||||||
table.AddRange(0x1C, 0x1F, GroundState, ExecuteAction, GroundState)
|
table.AddRange(0x1C, 0x1F, GroundState, ExecuteAction, GroundState)
|
||||||
table.AddRange(0x20, 0x7F, GroundState, PrintAction, GroundState)
|
table.AddRange(0x20, 0x7E, GroundState, PrintAction, GroundState)
|
||||||
|
table.AddOne(0x7F, GroundState, ExecuteAction, GroundState)
|
||||||
|
|
||||||
// EscapeIntermediate
|
// EscapeIntermediate
|
||||||
table.AddRange(0x00, 0x17, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
|
table.AddRange(0x00, 0x17, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
|
||||||
@ -209,7 +213,7 @@ func GenerateTransitionTable() TransitionTable {
|
|||||||
table.AddOne(0x19, DcsStringState, PutAction, DcsStringState)
|
table.AddOne(0x19, DcsStringState, PutAction, DcsStringState)
|
||||||
table.AddRange(0x1C, 0x1F, DcsStringState, PutAction, DcsStringState)
|
table.AddRange(0x1C, 0x1F, DcsStringState, PutAction, DcsStringState)
|
||||||
table.AddRange(0x20, 0x7E, DcsStringState, PutAction, DcsStringState)
|
table.AddRange(0x20, 0x7E, DcsStringState, PutAction, DcsStringState)
|
||||||
table.AddOne(0x7F, DcsStringState, IgnoreAction, DcsStringState)
|
table.AddOne(0x7F, DcsStringState, PutAction, DcsStringState)
|
||||||
table.AddRange(0x80, 0xFF, DcsStringState, PutAction, DcsStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF
|
table.AddRange(0x80, 0xFF, DcsStringState, PutAction, DcsStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF
|
||||||
// ST, CAN, SUB, and ESC terminate the sequence
|
// ST, CAN, SUB, and ESC terminate the sequence
|
||||||
table.AddOne(0x1B, DcsStringState, DispatchAction, EscapeState)
|
table.AddOne(0x1B, DcsStringState, DispatchAction, EscapeState)
|
||||||
|
461
vendor/github.com/charmbracelet/x/ansi/parser_decode.go
generated
vendored
Normal file
461
vendor/github.com/charmbracelet/x/ansi/parser_decode.go
generated
vendored
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
|
"github.com/rivo/uniseg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// State represents the state of the ANSI escape sequence parser used by
|
||||||
|
// [DecodeSequence].
|
||||||
|
type State = byte
|
||||||
|
|
||||||
|
// ANSI escape sequence states used by [DecodeSequence].
|
||||||
|
const (
|
||||||
|
NormalState State = iota
|
||||||
|
MarkerState
|
||||||
|
ParamsState
|
||||||
|
IntermedState
|
||||||
|
EscapeState
|
||||||
|
StringState
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecodeSequence decodes the first ANSI escape sequence or a printable
|
||||||
|
// grapheme from the given data. It returns the sequence slice, the number of
|
||||||
|
// bytes read, the cell width for each sequence, and the new state.
|
||||||
|
//
|
||||||
|
// The cell width will always be 0 for control and escape sequences, 1 for
|
||||||
|
// ASCII printable characters, and the number of cells other Unicode characters
|
||||||
|
// occupy. It uses the uniseg package to calculate the width of Unicode
|
||||||
|
// graphemes and characters. This means it will always do grapheme clustering
|
||||||
|
// (mode 2027).
|
||||||
|
//
|
||||||
|
// Passing a non-nil [*Parser] as the last argument will allow the decoder to
|
||||||
|
// collect sequence parameters, data, and commands. The parser cmd will have
|
||||||
|
// the packed command value that contains intermediate and marker characters.
|
||||||
|
// In the case of a OSC sequence, the cmd will be the OSC command number. Use
|
||||||
|
// [Command] and [Parameter] types to unpack command intermediates and markers as well
|
||||||
|
// as parameters.
|
||||||
|
//
|
||||||
|
// Zero [Command] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
|
||||||
|
// validity of other data sequences, OSC, DCS, etc, will require checking for
|
||||||
|
// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
|
||||||
|
//
|
||||||
|
// We store the command byte in [Command] in the most significant byte, the
|
||||||
|
// marker byte in the next byte, and the intermediate byte in the least
|
||||||
|
// significant byte. This is done to avoid using a struct to store the command
|
||||||
|
// and its intermediates and markers. The command byte is always the least
|
||||||
|
// significant byte i.e. [Cmd & 0xff]. Use the [Command] type to unpack the
|
||||||
|
// command, intermediate, and marker bytes. Note that we only collect the last
|
||||||
|
// marker character and intermediate byte.
|
||||||
|
//
|
||||||
|
// The [p.Params] slice will contain the parameters of the sequence. Any
|
||||||
|
// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Parameter] type
|
||||||
|
// to unpack the parameters.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// var state byte // the initial state is always zero [NormalState]
|
||||||
|
// p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
|
||||||
|
// input := []byte("\x1b[31mHello, World!\x1b[0m")
|
||||||
|
// for len(input) > 0 {
|
||||||
|
// seq, width, n, newState := DecodeSequence(input, state, p)
|
||||||
|
// log.Printf("seq: %q, width: %d", seq, width)
|
||||||
|
// state = newState
|
||||||
|
// input = input[n:]
|
||||||
|
// }
|
||||||
|
func DecodeSequence[T string | []byte](b T, state byte, p *Parser) (seq T, width int, n int, newState byte) {
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
c := b[i]
|
||||||
|
|
||||||
|
switch state {
|
||||||
|
case NormalState:
|
||||||
|
switch c {
|
||||||
|
case ESC:
|
||||||
|
if p != nil {
|
||||||
|
if len(p.params) > 0 {
|
||||||
|
p.params[0] = parser.MissingParam
|
||||||
|
}
|
||||||
|
p.cmd = 0
|
||||||
|
p.paramsLen = 0
|
||||||
|
p.dataLen = 0
|
||||||
|
}
|
||||||
|
state = EscapeState
|
||||||
|
continue
|
||||||
|
case CSI, DCS:
|
||||||
|
if p != nil {
|
||||||
|
if len(p.params) > 0 {
|
||||||
|
p.params[0] = parser.MissingParam
|
||||||
|
}
|
||||||
|
p.cmd = 0
|
||||||
|
p.paramsLen = 0
|
||||||
|
p.dataLen = 0
|
||||||
|
}
|
||||||
|
state = MarkerState
|
||||||
|
continue
|
||||||
|
case OSC, APC, SOS, PM:
|
||||||
|
if p != nil {
|
||||||
|
p.cmd = parser.MissingCommand
|
||||||
|
p.dataLen = 0
|
||||||
|
}
|
||||||
|
state = StringState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != nil {
|
||||||
|
p.dataLen = 0
|
||||||
|
p.paramsLen = 0
|
||||||
|
p.cmd = 0
|
||||||
|
}
|
||||||
|
if c > US && c < DEL {
|
||||||
|
// ASCII printable characters
|
||||||
|
return b[i : i+1], 1, 1, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
if c <= US || c == DEL || c < 0xC0 {
|
||||||
|
// C0 & C1 control characters & DEL
|
||||||
|
return b[i : i+1], 0, 1, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
if utf8.RuneStart(c) {
|
||||||
|
seq, _, width, _ = FirstGraphemeCluster(b, -1)
|
||||||
|
i += len(seq)
|
||||||
|
return b[:i], width, i, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid UTF-8 sequence
|
||||||
|
return b[:i], 0, i, NormalState
|
||||||
|
case MarkerState:
|
||||||
|
if c >= '<' && c <= '?' {
|
||||||
|
if p != nil {
|
||||||
|
// We only collect the last marker character.
|
||||||
|
p.cmd &^= 0xff << parser.MarkerShift
|
||||||
|
p.cmd |= int(c) << parser.MarkerShift
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
state = ParamsState
|
||||||
|
fallthrough
|
||||||
|
case ParamsState:
|
||||||
|
if c >= '0' && c <= '9' {
|
||||||
|
if p != nil {
|
||||||
|
if p.params[p.paramsLen] == parser.MissingParam {
|
||||||
|
p.params[p.paramsLen] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p.params[p.paramsLen] *= 10
|
||||||
|
p.params[p.paramsLen] += int(c - '0')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == ':' {
|
||||||
|
if p != nil {
|
||||||
|
p.params[p.paramsLen] |= parser.HasMoreFlag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == ';' || c == ':' {
|
||||||
|
if p != nil {
|
||||||
|
p.paramsLen++
|
||||||
|
if p.paramsLen < len(p.params) {
|
||||||
|
p.params[p.paramsLen] = parser.MissingParam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
state = IntermedState
|
||||||
|
fallthrough
|
||||||
|
case IntermedState:
|
||||||
|
if c >= ' ' && c <= '/' {
|
||||||
|
if p != nil {
|
||||||
|
p.cmd &^= 0xff << parser.IntermedShift
|
||||||
|
p.cmd |= int(c) << parser.IntermedShift
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != nil {
|
||||||
|
// Increment the last parameter
|
||||||
|
if p.paramsLen > 0 && p.paramsLen < len(p.params)-1 ||
|
||||||
|
p.paramsLen == 0 && len(p.params) > 0 && p.params[0] != parser.MissingParam {
|
||||||
|
p.paramsLen++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c >= '@' && c <= '~' {
|
||||||
|
if p != nil {
|
||||||
|
p.cmd &^= 0xff
|
||||||
|
p.cmd |= int(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if HasDcsPrefix(b) {
|
||||||
|
// Continue to collect DCS data
|
||||||
|
if p != nil {
|
||||||
|
p.dataLen = 0
|
||||||
|
}
|
||||||
|
state = StringState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return b[:i+1], 0, i + 1, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid CSI/DCS sequence
|
||||||
|
return b[:i], 0, i, NormalState
|
||||||
|
case EscapeState:
|
||||||
|
switch c {
|
||||||
|
case '[', 'P':
|
||||||
|
if p != nil {
|
||||||
|
if len(p.params) > 0 {
|
||||||
|
p.params[0] = parser.MissingParam
|
||||||
|
}
|
||||||
|
p.paramsLen = 0
|
||||||
|
p.cmd = 0
|
||||||
|
}
|
||||||
|
state = MarkerState
|
||||||
|
continue
|
||||||
|
case ']', 'X', '^', '_':
|
||||||
|
if p != nil {
|
||||||
|
p.cmd = parser.MissingCommand
|
||||||
|
p.dataLen = 0
|
||||||
|
}
|
||||||
|
state = StringState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if c >= ' ' && c <= '/' {
|
||||||
|
if p != nil {
|
||||||
|
p.cmd &^= 0xff << parser.IntermedShift
|
||||||
|
p.cmd |= int(c) << parser.IntermedShift
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else if c >= '0' && c <= '~' {
|
||||||
|
if p != nil {
|
||||||
|
p.cmd &^= 0xff
|
||||||
|
p.cmd |= int(c)
|
||||||
|
}
|
||||||
|
return b[:i+1], 0, i + 1, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid escape sequence
|
||||||
|
return b[:i], 0, i, NormalState
|
||||||
|
case StringState:
|
||||||
|
switch c {
|
||||||
|
case BEL:
|
||||||
|
if HasOscPrefix(b) {
|
||||||
|
parseOscCmd(p)
|
||||||
|
return b[:i+1], 0, i + 1, NormalState
|
||||||
|
}
|
||||||
|
case CAN, SUB:
|
||||||
|
if HasOscPrefix(b) {
|
||||||
|
// Ensure we parse the OSC command number
|
||||||
|
parseOscCmd(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel the sequence
|
||||||
|
return b[:i], 0, i, NormalState
|
||||||
|
case ST:
|
||||||
|
if HasOscPrefix(b) {
|
||||||
|
// Ensure we parse the OSC command number
|
||||||
|
parseOscCmd(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b[:i+1], 0, i + 1, NormalState
|
||||||
|
case ESC:
|
||||||
|
if HasStPrefix(b[i:]) {
|
||||||
|
if HasOscPrefix(b) {
|
||||||
|
// Ensure we parse the OSC command number
|
||||||
|
parseOscCmd(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of string 7-bit (ST)
|
||||||
|
return b[:i+2], 0, i + 2, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, cancel the sequence
|
||||||
|
return b[:i], 0, i, NormalState
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != nil && p.dataLen < len(p.data) {
|
||||||
|
p.data[p.dataLen] = c
|
||||||
|
p.dataLen++
|
||||||
|
|
||||||
|
// Parse the OSC command number
|
||||||
|
if c == ';' && HasOscPrefix(b) {
|
||||||
|
parseOscCmd(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, 0, len(b), state
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOscCmd(p *Parser) {
|
||||||
|
if p == nil || p.cmd != parser.MissingCommand {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < p.dataLen; j++ {
|
||||||
|
d := p.data[j]
|
||||||
|
if d < '0' || d > '9' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if p.cmd == parser.MissingCommand {
|
||||||
|
p.cmd = 0
|
||||||
|
}
|
||||||
|
p.cmd *= 10
|
||||||
|
p.cmd += int(d - '0')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns true if the given byte slices are equal.
|
||||||
|
func Equal[T string | []byte](a, b T) bool {
|
||||||
|
return string(a) == string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPrefix returns true if the given byte slice has prefix.
|
||||||
|
func HasPrefix[T string | []byte](b, prefix T) bool {
|
||||||
|
return len(b) >= len(prefix) && Equal(b[0:len(prefix)], prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSuffix returns true if the given byte slice has suffix.
|
||||||
|
func HasSuffix[T string | []byte](b, suffix T) bool {
|
||||||
|
return len(b) >= len(suffix) && Equal(b[len(b)-len(suffix):], suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasCsiPrefix returns true if the given byte slice has a CSI prefix.
|
||||||
|
func HasCsiPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == CSI) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasOscPrefix returns true if the given byte slice has an OSC prefix.
|
||||||
|
func HasOscPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == OSC) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == ']')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasApcPrefix returns true if the given byte slice has an APC prefix.
|
||||||
|
func HasApcPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == APC) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == '_')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasDcsPrefix returns true if the given byte slice has a DCS prefix.
|
||||||
|
func HasDcsPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == DCS) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == 'P')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSosPrefix returns true if the given byte slice has a SOS prefix.
|
||||||
|
func HasSosPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == SOS) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == 'X')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPmPrefix returns true if the given byte slice has a PM prefix.
|
||||||
|
func HasPmPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == PM) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == '^')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasStPrefix returns true if the given byte slice has a ST prefix.
|
||||||
|
func HasStPrefix[T string | []byte](b T) bool {
|
||||||
|
return (len(b) > 0 && b[0] == ST) ||
|
||||||
|
(len(b) > 1 && b[0] == ESC && b[1] == '\\')
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasEscPrefix returns true if the given byte slice has an ESC prefix.
|
||||||
|
func HasEscPrefix[T string | []byte](b T) bool {
|
||||||
|
return len(b) > 0 && b[0] == ESC
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirstGraphemeCluster returns the first grapheme cluster in the given string or byte slice.
|
||||||
|
// This is a syntactic sugar function that wraps
|
||||||
|
// uniseg.FirstGraphemeClusterInString and uniseg.FirstGraphemeCluster.
|
||||||
|
func FirstGraphemeCluster[T string | []byte](b T, state int) (T, T, int, int) {
|
||||||
|
switch b := any(b).(type) {
|
||||||
|
case string:
|
||||||
|
cluster, rest, width, newState := uniseg.FirstGraphemeClusterInString(b, state)
|
||||||
|
return T(cluster), T(rest), width, newState
|
||||||
|
case []byte:
|
||||||
|
cluster, rest, width, newState := uniseg.FirstGraphemeCluster(b, state)
|
||||||
|
return T(cluster), T(rest), width, newState
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command represents a sequence command. This is used to pack/unpack a sequence
|
||||||
|
// command with its intermediate and marker characters. Those are commonly
|
||||||
|
// found in CSI and DCS sequences.
|
||||||
|
type Command int
|
||||||
|
|
||||||
|
// Marker returns the unpacked marker byte of the CSI sequence.
|
||||||
|
// This is always gonna be one of the following '<' '=' '>' '?' and in the
|
||||||
|
// range of 0x3C-0x3F.
|
||||||
|
// Zero is returned if the sequence does not have a marker.
|
||||||
|
func (c Command) Marker() int {
|
||||||
|
return parser.Marker(int(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intermediate returns the unpacked intermediate byte of the CSI sequence.
|
||||||
|
// An intermediate byte is in the range of 0x20-0x2F. This includes these
|
||||||
|
// characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+',
|
||||||
|
// ',', '-', '.', '/'.
|
||||||
|
// Zero is returned if the sequence does not have an intermediate byte.
|
||||||
|
func (c Command) Intermediate() int {
|
||||||
|
return parser.Intermediate(int(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the unpacked command byte of the CSI sequence.
|
||||||
|
func (c Command) Command() int {
|
||||||
|
return parser.Command(int(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmd returns a packed [Command] with the given command, marker, and
|
||||||
|
// intermediate.
|
||||||
|
// The first byte is the command, the next shift is the marker, and the next
|
||||||
|
// shift is the intermediate.
|
||||||
|
//
|
||||||
|
// Even though this function takes integers, it only uses the lower 8 bits of
|
||||||
|
// each integer.
|
||||||
|
func Cmd(marker, inter, cmd int) (c Command) {
|
||||||
|
c = Command(cmd & parser.CommandMask)
|
||||||
|
c |= Command(marker&parser.CommandMask) << parser.MarkerShift
|
||||||
|
c |= Command(inter&parser.CommandMask) << parser.IntermedShift
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameter represents a sequence parameter. Sequence parameters with
|
||||||
|
// sub-parameters are packed with the HasMoreFlag set. This is used to unpack
|
||||||
|
// the parameters from a CSI and DCS sequences.
|
||||||
|
type Parameter int
|
||||||
|
|
||||||
|
// Param returns the unpacked parameter at the given index.
|
||||||
|
// It returns the default value if the parameter is missing.
|
||||||
|
func (s Parameter) Param(def int) int {
|
||||||
|
p := int(s) & parser.ParamMask
|
||||||
|
if p == parser.MissingParam {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasMore unpacks the HasMoreFlag from the parameter.
|
||||||
|
func (s Parameter) HasMore() bool {
|
||||||
|
return s&parser.HasMoreFlag != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param returns a packed [Parameter] with the given parameter and whether this
|
||||||
|
// parameter has following sub-parameters.
|
||||||
|
func Param(p int, hasMore bool) (s Parameter) {
|
||||||
|
s = Parameter(p & parser.ParamMask)
|
||||||
|
if hasMore {
|
||||||
|
s |= Parameter(parser.HasMoreFlag)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
29
vendor/github.com/charmbracelet/x/ansi/parser_sync.go
generated
vendored
Normal file
29
vendor/github.com/charmbracelet/x/ansi/parser_sync.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/x/ansi/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
var parserPool = sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
p := NewParser(nil)
|
||||||
|
p.SetParamsSize(parser.MaxParamsSize)
|
||||||
|
p.SetDataSize(1024 * 1024 * 4) // 4MB of data buffer
|
||||||
|
return p
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetParser returns a parser from a sync pool.
|
||||||
|
func GetParser() *Parser {
|
||||||
|
return parserPool.Get().(*Parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutParser returns a parser to a sync pool. The parser is reset
|
||||||
|
// automatically.
|
||||||
|
func PutParser(p *Parser) {
|
||||||
|
p.Reset()
|
||||||
|
p.dataLen = 0
|
||||||
|
parserPool.Put(p)
|
||||||
|
}
|
7
vendor/github.com/charmbracelet/x/ansi/paste.go
generated
vendored
Normal file
7
vendor/github.com/charmbracelet/x/ansi/paste.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// BracketedPasteStart is the control sequence to enable bracketed paste mode.
|
||||||
|
const BracketedPasteStart = "\x1b[200~"
|
||||||
|
|
||||||
|
// BracketedPasteEnd is the control sequence to disable bracketed paste mode.
|
||||||
|
const BracketedPasteEnd = "\x1b[201~"
|
11
vendor/github.com/charmbracelet/x/ansi/reset.go
generated
vendored
Normal file
11
vendor/github.com/charmbracelet/x/ansi/reset.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
// ResetInitialState (RIS) resets the terminal to its initial state.
|
||||||
|
//
|
||||||
|
// ESC c
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/RIS.html
|
||||||
|
const (
|
||||||
|
ResetInitialState = "\x1bc"
|
||||||
|
RIS = ResetInitialState
|
||||||
|
)
|
317
vendor/github.com/charmbracelet/x/ansi/screen.go
generated
vendored
317
vendor/github.com/charmbracelet/x/ansi/screen.go
generated
vendored
@ -1,30 +1,44 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
import "strconv"
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// EraseDisplay (ED) clears the screen or parts of the screen. Possible values:
|
// EraseDisplay (ED) clears the display or parts of the display. A screen is
|
||||||
|
// the shown part of the terminal display excluding the scrollback buffer.
|
||||||
|
// Possible values:
|
||||||
|
//
|
||||||
|
// Default is 0.
|
||||||
//
|
//
|
||||||
// 0: Clear from cursor to end of screen.
|
// 0: Clear from cursor to end of screen.
|
||||||
// 1: Clear from cursor to beginning of the screen.
|
// 1: Clear from cursor to beginning of the screen.
|
||||||
// 2: Clear entire screen (and moves cursor to upper left on DOS).
|
// 2: Clear entire screen (and moves cursor to upper left on DOS).
|
||||||
// 3: Clear entire screen and delete all lines saved in the scrollback buffer.
|
// 3: Clear entire display which delete all lines saved in the scrollback buffer (xterm).
|
||||||
//
|
//
|
||||||
// CSI <n> J
|
// CSI <n> J
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/ED.html
|
// See: https://vt100.net/docs/vt510-rm/ED.html
|
||||||
func EraseDisplay(n int) string {
|
func EraseDisplay(n int) string {
|
||||||
if n < 0 {
|
var s string
|
||||||
n = 0
|
if n > 0 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
}
|
}
|
||||||
return "\x1b[" + strconv.Itoa(n) + "J"
|
return "\x1b[" + s + "J"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ED is an alias for [EraseDisplay].
|
||||||
|
func ED(n int) string {
|
||||||
|
return EraseDisplay(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EraseDisplay constants.
|
// EraseDisplay constants.
|
||||||
// These are the possible values for the EraseDisplay function.
|
// These are the possible values for the EraseDisplay function.
|
||||||
const (
|
const (
|
||||||
EraseDisplayRight = "\x1b[0J"
|
EraseScreenBelow = "\x1b[J"
|
||||||
EraseDisplayLeft = "\x1b[1J"
|
EraseScreenAbove = "\x1b[1J"
|
||||||
EraseEntireDisplay = "\x1b[2J"
|
EraseEntireScreen = "\x1b[2J"
|
||||||
|
EraseEntireDisplay = "\x1b[3J"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EraseLine (EL) clears the current line or parts of the line. Possible values:
|
// EraseLine (EL) clears the current line or parts of the line. Possible values:
|
||||||
@ -39,16 +53,22 @@ const (
|
|||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/EL.html
|
// See: https://vt100.net/docs/vt510-rm/EL.html
|
||||||
func EraseLine(n int) string {
|
func EraseLine(n int) string {
|
||||||
if n < 0 {
|
var s string
|
||||||
n = 0
|
if n > 0 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
}
|
}
|
||||||
return "\x1b[" + strconv.Itoa(n) + "K"
|
return "\x1b[" + s + "K"
|
||||||
|
}
|
||||||
|
|
||||||
|
// EL is an alias for [EraseLine].
|
||||||
|
func EL(n int) string {
|
||||||
|
return EraseLine(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EraseLine constants.
|
// EraseLine constants.
|
||||||
// These are the possible values for the EraseLine function.
|
// These are the possible values for the EraseLine function.
|
||||||
const (
|
const (
|
||||||
EraseLineRight = "\x1b[0K"
|
EraseLineRight = "\x1b[K"
|
||||||
EraseLineLeft = "\x1b[1K"
|
EraseLineLeft = "\x1b[1K"
|
||||||
EraseEntireLine = "\x1b[2K"
|
EraseEntireLine = "\x1b[2K"
|
||||||
)
|
)
|
||||||
@ -56,7 +76,7 @@ const (
|
|||||||
// ScrollUp (SU) scrolls the screen up n lines. New lines are added at the
|
// ScrollUp (SU) scrolls the screen up n lines. New lines are added at the
|
||||||
// bottom of the screen.
|
// bottom of the screen.
|
||||||
//
|
//
|
||||||
// CSI <n> S
|
// CSI Pn S
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/SU.html
|
// See: https://vt100.net/docs/vt510-rm/SU.html
|
||||||
func ScrollUp(n int) string {
|
func ScrollUp(n int) string {
|
||||||
@ -67,10 +87,20 @@ func ScrollUp(n int) string {
|
|||||||
return "\x1b[" + s + "S"
|
return "\x1b[" + s + "S"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PanDown is an alias for [ScrollUp].
|
||||||
|
func PanDown(n int) string {
|
||||||
|
return ScrollUp(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SU is an alias for [ScrollUp].
|
||||||
|
func SU(n int) string {
|
||||||
|
return ScrollUp(n)
|
||||||
|
}
|
||||||
|
|
||||||
// ScrollDown (SD) scrolls the screen down n lines. New lines are added at the
|
// ScrollDown (SD) scrolls the screen down n lines. New lines are added at the
|
||||||
// top of the screen.
|
// top of the screen.
|
||||||
//
|
//
|
||||||
// CSI <n> T
|
// CSI Pn T
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/SD.html
|
// See: https://vt100.net/docs/vt510-rm/SD.html
|
||||||
func ScrollDown(n int) string {
|
func ScrollDown(n int) string {
|
||||||
@ -81,10 +111,20 @@ func ScrollDown(n int) string {
|
|||||||
return "\x1b[" + s + "T"
|
return "\x1b[" + s + "T"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PanUp is an alias for [ScrollDown].
|
||||||
|
func PanUp(n int) string {
|
||||||
|
return ScrollDown(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SD is an alias for [ScrollDown].
|
||||||
|
func SD(n int) string {
|
||||||
|
return ScrollDown(n)
|
||||||
|
}
|
||||||
|
|
||||||
// InsertLine (IL) inserts n blank lines at the current cursor position.
|
// InsertLine (IL) inserts n blank lines at the current cursor position.
|
||||||
// Existing lines are moved down.
|
// Existing lines are moved down.
|
||||||
//
|
//
|
||||||
// CSI <n> L
|
// CSI Pn L
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/IL.html
|
// See: https://vt100.net/docs/vt510-rm/IL.html
|
||||||
func InsertLine(n int) string {
|
func InsertLine(n int) string {
|
||||||
@ -95,10 +135,15 @@ func InsertLine(n int) string {
|
|||||||
return "\x1b[" + s + "L"
|
return "\x1b[" + s + "L"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IL is an alias for [InsertLine].
|
||||||
|
func IL(n int) string {
|
||||||
|
return InsertLine(n)
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteLine (DL) deletes n lines at the current cursor position. Existing
|
// DeleteLine (DL) deletes n lines at the current cursor position. Existing
|
||||||
// lines are moved up.
|
// lines are moved up.
|
||||||
//
|
//
|
||||||
// CSI <n> M
|
// CSI Pn M
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DL.html
|
// See: https://vt100.net/docs/vt510-rm/DL.html
|
||||||
func DeleteLine(n int) string {
|
func DeleteLine(n int) string {
|
||||||
@ -109,12 +154,66 @@ func DeleteLine(n int) string {
|
|||||||
return "\x1b[" + s + "M"
|
return "\x1b[" + s + "M"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DL is an alias for [DeleteLine].
|
||||||
|
func DL(n int) string {
|
||||||
|
return DeleteLine(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTopBottomMargins (DECSTBM) sets the top and bottom margins for the scrolling
|
||||||
|
// region. The default is the entire screen.
|
||||||
|
//
|
||||||
|
// Default is 1 and the bottom of the screen.
|
||||||
|
//
|
||||||
|
// CSI Pt ; Pb r
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECSTBM.html
|
||||||
|
func SetTopBottomMargins(top, bot int) string {
|
||||||
|
var t, b string
|
||||||
|
if top > 0 {
|
||||||
|
t = strconv.Itoa(top)
|
||||||
|
}
|
||||||
|
if bot > 0 {
|
||||||
|
b = strconv.Itoa(bot)
|
||||||
|
}
|
||||||
|
return "\x1b[" + t + ";" + b + "r"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECSTBM is an alias for [SetTopBottomMargins].
|
||||||
|
func DECSTBM(top, bot int) string {
|
||||||
|
return SetTopBottomMargins(top, bot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLeftRightMargins (DECSLRM) sets the left and right margins for the scrolling
|
||||||
|
// region.
|
||||||
|
//
|
||||||
|
// Default is 1 and the right of the screen.
|
||||||
|
//
|
||||||
|
// CSI Pl ; Pr s
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECSLRM.html
|
||||||
|
func SetLeftRightMargins(left, right int) string {
|
||||||
|
var l, r string
|
||||||
|
if left > 0 {
|
||||||
|
l = strconv.Itoa(left)
|
||||||
|
}
|
||||||
|
if right > 0 {
|
||||||
|
r = strconv.Itoa(right)
|
||||||
|
}
|
||||||
|
return "\x1b[" + l + ";" + r + "s"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECSLRM is an alias for [SetLeftRightMargins].
|
||||||
|
func DECSLRM(left, right int) string {
|
||||||
|
return SetLeftRightMargins(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
// SetScrollingRegion (DECSTBM) sets the top and bottom margins for the scrolling
|
// SetScrollingRegion (DECSTBM) sets the top and bottom margins for the scrolling
|
||||||
// region. The default is the entire screen.
|
// region. The default is the entire screen.
|
||||||
//
|
//
|
||||||
// CSI <top> ; <bottom> r
|
// CSI <top> ; <bottom> r
|
||||||
//
|
//
|
||||||
// See: https://vt100.net/docs/vt510-rm/DECSTBM.html
|
// See: https://vt100.net/docs/vt510-rm/DECSTBM.html
|
||||||
|
// Deprecated: use [SetTopBottomMargins] instead.
|
||||||
func SetScrollingRegion(t, b int) string {
|
func SetScrollingRegion(t, b int) string {
|
||||||
if t < 0 {
|
if t < 0 {
|
||||||
t = 0
|
t = 0
|
||||||
@ -124,3 +223,187 @@ func SetScrollingRegion(t, b int) string {
|
|||||||
}
|
}
|
||||||
return "\x1b[" + strconv.Itoa(t) + ";" + strconv.Itoa(b) + "r"
|
return "\x1b[" + strconv.Itoa(t) + ";" + strconv.Itoa(b) + "r"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertCharacter (ICH) inserts n blank characters at the current cursor
|
||||||
|
// position. Existing characters move to the right. Characters moved past the
|
||||||
|
// right margin are lost. ICH has no effect outside the scrolling margins.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI Pn @
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/ICH.html
|
||||||
|
func InsertCharacter(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "@"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICH is an alias for [InsertCharacter].
|
||||||
|
func ICH(n int) string {
|
||||||
|
return InsertCharacter(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCharacter (DCH) deletes n characters at the current cursor position.
|
||||||
|
// As the characters are deleted, the remaining characters move to the left and
|
||||||
|
// the cursor remains at the same position.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI Pn P
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DCH.html
|
||||||
|
func DeleteCharacter(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "P"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DCH is an alias for [DeleteCharacter].
|
||||||
|
func DCH(n int) string {
|
||||||
|
return DeleteCharacter(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTabEvery8Columns (DECST8C) sets the tab stops at every 8 columns.
|
||||||
|
//
|
||||||
|
// CSI ? 5 W
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECST8C.html
|
||||||
|
const (
|
||||||
|
SetTabEvery8Columns = "\x1b[?5W"
|
||||||
|
DECST8C = SetTabEvery8Columns
|
||||||
|
)
|
||||||
|
|
||||||
|
// HorizontalTabSet (HTS) sets a horizontal tab stop at the current cursor
|
||||||
|
// column.
|
||||||
|
//
|
||||||
|
// This is equivalent to [HTS].
|
||||||
|
//
|
||||||
|
// ESC H
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/HTS.html
|
||||||
|
const HorizontalTabSet = "\x1bH"
|
||||||
|
|
||||||
|
// TabClear (TBC) clears tab stops.
|
||||||
|
//
|
||||||
|
// Default is 0.
|
||||||
|
//
|
||||||
|
// Possible values:
|
||||||
|
// 0: Clear tab stop at the current column. (default)
|
||||||
|
// 3: Clear all tab stops.
|
||||||
|
//
|
||||||
|
// CSI Pn g
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/TBC.html
|
||||||
|
func TabClear(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 0 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "g"
|
||||||
|
}
|
||||||
|
|
||||||
|
// TBC is an alias for [TabClear].
|
||||||
|
func TBC(n int) string {
|
||||||
|
return TabClear(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestPresentationStateReport (DECRQPSR) requests the terminal to send a
|
||||||
|
// report of the presentation state. This includes the cursor information [DECCIR],
|
||||||
|
// and tab stop [DECTABSR] reports.
|
||||||
|
//
|
||||||
|
// Default is 0.
|
||||||
|
//
|
||||||
|
// Possible values:
|
||||||
|
// 0: Error, request ignored.
|
||||||
|
// 1: Cursor information report [DECCIR].
|
||||||
|
// 2: Tab stop report [DECTABSR].
|
||||||
|
//
|
||||||
|
// CSI Ps $ w
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECRQPSR.html
|
||||||
|
func RequestPresentationStateReport(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 0 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "$w"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECRQPSR is an alias for [RequestPresentationStateReport].
|
||||||
|
func DECRQPSR(n int) string {
|
||||||
|
return RequestPresentationStateReport(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TabStopReport (DECTABSR) is the response to a tab stop report request.
|
||||||
|
// It reports the tab stops set in the terminal.
|
||||||
|
//
|
||||||
|
// The response is a list of tab stops separated by a slash (/) character.
|
||||||
|
//
|
||||||
|
// DCS 2 $ u D ... D ST
|
||||||
|
//
|
||||||
|
// Where D is a decimal number representing a tab stop.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECTABSR.html
|
||||||
|
func TabStopReport(stops ...int) string {
|
||||||
|
var s []string
|
||||||
|
for _, v := range stops {
|
||||||
|
s = append(s, strconv.Itoa(v))
|
||||||
|
}
|
||||||
|
return "\x1bP2$u" + strings.Join(s, "/") + "\x1b\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECTABSR is an alias for [TabStopReport].
|
||||||
|
func DECTABSR(stops ...int) string {
|
||||||
|
return TabStopReport(stops...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorInformationReport (DECCIR) is the response to a cursor information
|
||||||
|
// report request. It reports the cursor position, visual attributes, and
|
||||||
|
// character protection attributes. It also reports the status of origin mode
|
||||||
|
// [DECOM] and the current active character set.
|
||||||
|
//
|
||||||
|
// The response is a list of values separated by a semicolon (;) character.
|
||||||
|
//
|
||||||
|
// DCS 1 $ u D ... D ST
|
||||||
|
//
|
||||||
|
// Where D is a decimal number representing a value.
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/DECCIR.html
|
||||||
|
func CursorInformationReport(values ...int) string {
|
||||||
|
var s []string
|
||||||
|
for _, v := range values {
|
||||||
|
s = append(s, strconv.Itoa(v))
|
||||||
|
}
|
||||||
|
return "\x1bP1$u" + strings.Join(s, ";") + "\x1b\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECCIR is an alias for [CursorInformationReport].
|
||||||
|
func DECCIR(values ...int) string {
|
||||||
|
return CursorInformationReport(values...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepeatPreviousCharacter (REP) repeats the previous character n times.
|
||||||
|
// This is identical to typing the same character n times.
|
||||||
|
//
|
||||||
|
// Default is 1.
|
||||||
|
//
|
||||||
|
// CSI Pn b
|
||||||
|
//
|
||||||
|
// See: ECMA-48 § 8.3.103
|
||||||
|
func RepeatPreviousCharacter(n int) string {
|
||||||
|
var s string
|
||||||
|
if n > 1 {
|
||||||
|
s = strconv.Itoa(n)
|
||||||
|
}
|
||||||
|
return "\x1b[" + s + "b"
|
||||||
|
}
|
||||||
|
|
||||||
|
// REP is an alias for [RepeatPreviousCharacter].
|
||||||
|
func REP(n int) string {
|
||||||
|
return RepeatPreviousCharacter(n)
|
||||||
|
}
|
||||||
|
94
vendor/github.com/charmbracelet/x/ansi/sequence.go
generated
vendored
94
vendor/github.com/charmbracelet/x/ansi/sequence.go
generated
vendored
@ -8,12 +8,19 @@ import (
|
|||||||
|
|
||||||
// Sequence represents an ANSI sequence. This can be a control sequence, escape
|
// Sequence represents an ANSI sequence. This can be a control sequence, escape
|
||||||
// sequence, a printable character, etc.
|
// sequence, a printable character, etc.
|
||||||
|
// A Sequence can be one of the following types:
|
||||||
|
// - [Rune]
|
||||||
|
// - [ControlCode]
|
||||||
|
// - [Grapheme]
|
||||||
|
// - [EscSequence]
|
||||||
|
// - [CsiSequence]
|
||||||
|
// - [OscSequence]
|
||||||
|
// - [DcsSequence]
|
||||||
|
// - [SosSequence]
|
||||||
|
// - [PmSequence]
|
||||||
|
// - [ApcSequence]
|
||||||
type Sequence interface {
|
type Sequence interface {
|
||||||
// String returns the string representation of the sequence.
|
// Clone returns a deep copy of the sequence.
|
||||||
String() string
|
|
||||||
// Bytes returns the byte representation of the sequence.
|
|
||||||
Bytes() []byte
|
|
||||||
// Clone returns a copy of the sequence.
|
|
||||||
Clone() Sequence
|
Clone() Sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,21 +29,24 @@ type Rune rune
|
|||||||
|
|
||||||
var _ Sequence = Rune(0)
|
var _ Sequence = Rune(0)
|
||||||
|
|
||||||
// Bytes implements Sequence.
|
// Clone returns a deep copy of the rune.
|
||||||
func (r Rune) Bytes() []byte {
|
|
||||||
return []byte(string(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String implements Sequence.
|
|
||||||
func (r Rune) String() string {
|
|
||||||
return string(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone implements Sequence.
|
|
||||||
func (r Rune) Clone() Sequence {
|
func (r Rune) Clone() Sequence {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grapheme represents a grapheme cluster.
|
||||||
|
type Grapheme struct {
|
||||||
|
Cluster string
|
||||||
|
Width int
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Sequence = Grapheme{}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the grapheme.
|
||||||
|
func (g Grapheme) Clone() Sequence {
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
// ControlCode represents a control code character. This is a character that
|
// ControlCode represents a control code character. This is a character that
|
||||||
// is not printable and is used to control the terminal. This would be a
|
// is not printable and is used to control the terminal. This would be a
|
||||||
// character in the C0 or C1 set in the range of 0x00-0x1F and 0x80-0x9F.
|
// character in the C0 or C1 set in the range of 0x00-0x1F and 0x80-0x9F.
|
||||||
@ -54,13 +64,13 @@ func (c ControlCode) String() string {
|
|||||||
return string(c)
|
return string(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone implements Sequence.
|
// Clone returns a deep copy of the control code.
|
||||||
func (c ControlCode) Clone() Sequence {
|
func (c ControlCode) Clone() Sequence {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// EscSequence represents an escape sequence.
|
// EscSequence represents an escape sequence.
|
||||||
type EscSequence int
|
type EscSequence Command
|
||||||
|
|
||||||
var _ Sequence = EscSequence(0)
|
var _ Sequence = EscSequence(0)
|
||||||
|
|
||||||
@ -71,7 +81,9 @@ func (e EscSequence) buffer() *bytes.Buffer {
|
|||||||
if i := parser.Intermediate(int(e)); i != 0 {
|
if i := parser.Intermediate(int(e)); i != 0 {
|
||||||
b.WriteByte(byte(i))
|
b.WriteByte(byte(i))
|
||||||
}
|
}
|
||||||
b.WriteByte(byte(e.Command()))
|
if cmd := e.Command(); cmd != 0 {
|
||||||
|
b.WriteByte(byte(cmd))
|
||||||
|
}
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,19 +97,19 @@ func (e EscSequence) String() string {
|
|||||||
return e.buffer().String()
|
return e.buffer().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone implements Sequence.
|
// Clone returns a deep copy of the escape sequence.
|
||||||
func (e EscSequence) Clone() Sequence {
|
func (e EscSequence) Clone() Sequence {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command returns the command byte of the escape sequence.
|
// Command returns the command byte of the escape sequence.
|
||||||
func (e EscSequence) Command() int {
|
func (e EscSequence) Command() int {
|
||||||
return parser.Command(int(e))
|
return Command(e).Command()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intermediate returns the intermediate byte of the escape sequence.
|
// Intermediate returns the intermediate byte of the escape sequence.
|
||||||
func (e EscSequence) Intermediate() int {
|
func (e EscSequence) Intermediate() int {
|
||||||
return parser.Intermediate(int(e))
|
return Command(e).Intermediate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SosSequence represents a SOS sequence.
|
// SosSequence represents a SOS sequence.
|
||||||
@ -106,12 +118,7 @@ type SosSequence struct {
|
|||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Sequence = &SosSequence{}
|
var _ Sequence = SosSequence{}
|
||||||
|
|
||||||
// Clone implements Sequence.
|
|
||||||
func (s SosSequence) Clone() Sequence {
|
|
||||||
return SosSequence{Data: append([]byte(nil), s.Data...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes implements Sequence.
|
// Bytes implements Sequence.
|
||||||
func (s SosSequence) Bytes() []byte {
|
func (s SosSequence) Bytes() []byte {
|
||||||
@ -132,18 +139,20 @@ func (s SosSequence) buffer() *bytes.Buffer {
|
|||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the SOS sequence.
|
||||||
|
func (s SosSequence) Clone() Sequence {
|
||||||
|
return SosSequence{
|
||||||
|
Data: append([]byte(nil), s.Data...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PmSequence represents a PM sequence.
|
// PmSequence represents a PM sequence.
|
||||||
type PmSequence struct {
|
type PmSequence struct {
|
||||||
// Data contains the raw data of the sequence.
|
// Data contains the raw data of the sequence.
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Sequence = &PmSequence{}
|
var _ Sequence = PmSequence{}
|
||||||
|
|
||||||
// Clone implements Sequence.
|
|
||||||
func (s PmSequence) Clone() Sequence {
|
|
||||||
return PmSequence{Data: append([]byte(nil), s.Data...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes implements Sequence.
|
// Bytes implements Sequence.
|
||||||
func (s PmSequence) Bytes() []byte {
|
func (s PmSequence) Bytes() []byte {
|
||||||
@ -165,17 +174,26 @@ func (s PmSequence) buffer() *bytes.Buffer {
|
|||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the PM sequence.
|
||||||
|
func (p PmSequence) Clone() Sequence {
|
||||||
|
return PmSequence{
|
||||||
|
Data: append([]byte(nil), p.Data...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ApcSequence represents an APC sequence.
|
// ApcSequence represents an APC sequence.
|
||||||
type ApcSequence struct {
|
type ApcSequence struct {
|
||||||
// Data contains the raw data of the sequence.
|
// Data contains the raw data of the sequence.
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Sequence = &ApcSequence{}
|
var _ Sequence = ApcSequence{}
|
||||||
|
|
||||||
// Clone implements Sequence.
|
// Clone returns a deep copy of the APC sequence.
|
||||||
func (s ApcSequence) Clone() Sequence {
|
func (a ApcSequence) Clone() Sequence {
|
||||||
return ApcSequence{Data: append([]byte(nil), s.Data...)}
|
return ApcSequence{
|
||||||
|
Data: append([]byte(nil), a.Data...),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes implements Sequence.
|
// Bytes implements Sequence.
|
||||||
|
95
vendor/github.com/charmbracelet/x/ansi/sgr.go
generated
vendored
Normal file
95
vendor/github.com/charmbracelet/x/ansi/sgr.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// Select Graphic Rendition (SGR) is a command that sets display attributes.
|
||||||
|
//
|
||||||
|
// Default is 0.
|
||||||
|
//
|
||||||
|
// CSI Ps ; Ps ... m
|
||||||
|
//
|
||||||
|
// See: https://vt100.net/docs/vt510-rm/SGR.html
|
||||||
|
func SelectGraphicRendition(ps ...Attr) string {
|
||||||
|
if len(ps) == 0 {
|
||||||
|
return ResetStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
var s Style
|
||||||
|
for _, p := range ps {
|
||||||
|
attr, ok := attrStrings[p]
|
||||||
|
if ok {
|
||||||
|
s = append(s, attr)
|
||||||
|
} else {
|
||||||
|
if p < 0 {
|
||||||
|
p = 0
|
||||||
|
}
|
||||||
|
s = append(s, strconv.Itoa(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SGR is an alias for [SelectGraphicRendition].
|
||||||
|
func SGR(ps ...Attr) string {
|
||||||
|
return SelectGraphicRendition(ps...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var attrStrings = map[int]string{
|
||||||
|
ResetAttr: "0",
|
||||||
|
BoldAttr: "1",
|
||||||
|
FaintAttr: "2",
|
||||||
|
ItalicAttr: "3",
|
||||||
|
UnderlineAttr: "4",
|
||||||
|
SlowBlinkAttr: "5",
|
||||||
|
RapidBlinkAttr: "6",
|
||||||
|
ReverseAttr: "7",
|
||||||
|
ConcealAttr: "8",
|
||||||
|
StrikethroughAttr: "9",
|
||||||
|
NoBoldAttr: "21",
|
||||||
|
NormalIntensityAttr: "22",
|
||||||
|
NoItalicAttr: "23",
|
||||||
|
NoUnderlineAttr: "24",
|
||||||
|
NoBlinkAttr: "25",
|
||||||
|
NoReverseAttr: "27",
|
||||||
|
NoConcealAttr: "28",
|
||||||
|
NoStrikethroughAttr: "29",
|
||||||
|
BlackForegroundColorAttr: "30",
|
||||||
|
RedForegroundColorAttr: "31",
|
||||||
|
GreenForegroundColorAttr: "32",
|
||||||
|
YellowForegroundColorAttr: "33",
|
||||||
|
BlueForegroundColorAttr: "34",
|
||||||
|
MagentaForegroundColorAttr: "35",
|
||||||
|
CyanForegroundColorAttr: "36",
|
||||||
|
WhiteForegroundColorAttr: "37",
|
||||||
|
ExtendedForegroundColorAttr: "38",
|
||||||
|
DefaultForegroundColorAttr: "39",
|
||||||
|
BlackBackgroundColorAttr: "40",
|
||||||
|
RedBackgroundColorAttr: "41",
|
||||||
|
GreenBackgroundColorAttr: "42",
|
||||||
|
YellowBackgroundColorAttr: "43",
|
||||||
|
BlueBackgroundColorAttr: "44",
|
||||||
|
MagentaBackgroundColorAttr: "45",
|
||||||
|
CyanBackgroundColorAttr: "46",
|
||||||
|
WhiteBackgroundColorAttr: "47",
|
||||||
|
ExtendedBackgroundColorAttr: "48",
|
||||||
|
DefaultBackgroundColorAttr: "49",
|
||||||
|
ExtendedUnderlineColorAttr: "58",
|
||||||
|
DefaultUnderlineColorAttr: "59",
|
||||||
|
BrightBlackForegroundColorAttr: "90",
|
||||||
|
BrightRedForegroundColorAttr: "91",
|
||||||
|
BrightGreenForegroundColorAttr: "92",
|
||||||
|
BrightYellowForegroundColorAttr: "93",
|
||||||
|
BrightBlueForegroundColorAttr: "94",
|
||||||
|
BrightMagentaForegroundColorAttr: "95",
|
||||||
|
BrightCyanForegroundColorAttr: "96",
|
||||||
|
BrightWhiteForegroundColorAttr: "97",
|
||||||
|
BrightBlackBackgroundColorAttr: "100",
|
||||||
|
BrightRedBackgroundColorAttr: "101",
|
||||||
|
BrightGreenBackgroundColorAttr: "102",
|
||||||
|
BrightYellowBackgroundColorAttr: "103",
|
||||||
|
BrightBlueBackgroundColorAttr: "104",
|
||||||
|
BrightMagentaBackgroundColorAttr: "105",
|
||||||
|
BrightCyanBackgroundColorAttr: "106",
|
||||||
|
BrightWhiteBackgroundColorAttr: "107",
|
||||||
|
}
|
115
vendor/github.com/charmbracelet/x/ansi/status.go
generated
vendored
Normal file
115
vendor/github.com/charmbracelet/x/ansi/status.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package ansi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status represents a terminal status report.
|
||||||
|
type Status interface {
|
||||||
|
// Status returns the status report identifier.
|
||||||
|
Status() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANSIStatus represents an ANSI terminal status report.
|
||||||
|
type ANSIStatus int //nolint:revive
|
||||||
|
|
||||||
|
// Status returns the status report identifier.
|
||||||
|
func (s ANSIStatus) Status() int {
|
||||||
|
return int(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECStatus represents a DEC terminal status report.
|
||||||
|
type DECStatus int
|
||||||
|
|
||||||
|
// Status returns the status report identifier.
|
||||||
|
func (s DECStatus) Status() int {
|
||||||
|
return int(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceStatusReport (DSR) is a control sequence that reports the terminal's
|
||||||
|
// status.
|
||||||
|
// The terminal responds with a DSR sequence.
|
||||||
|
//
|
||||||
|
// CSI Ps n
|
||||||
|
// CSI ? Ps n
|
||||||
|
//
|
||||||
|
// If one of the statuses is a [DECStatus], the sequence will use the DEC
|
||||||
|
// format.
|
||||||
|
//
|
||||||
|
// See also https://vt100.net/docs/vt510-rm/DSR.html
|
||||||
|
func DeviceStatusReport(statues ...Status) string {
|
||||||
|
var dec bool
|
||||||
|
list := make([]string, len(statues))
|
||||||
|
seq := "\x1b["
|
||||||
|
for i, status := range statues {
|
||||||
|
list[i] = strconv.Itoa(status.Status())
|
||||||
|
switch status.(type) {
|
||||||
|
case DECStatus:
|
||||||
|
dec = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dec {
|
||||||
|
seq += "?"
|
||||||
|
}
|
||||||
|
return seq + strings.Join(list, ";") + "n"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DSR is an alias for [DeviceStatusReport].
|
||||||
|
func DSR(status Status) string {
|
||||||
|
return DeviceStatusReport(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CursorPositionReport (CPR) is a control sequence that reports the cursor's
|
||||||
|
// position.
|
||||||
|
//
|
||||||
|
// CSI Pl ; Pc R
|
||||||
|
//
|
||||||
|
// Where Pl is the line number and Pc is the column number.
|
||||||
|
//
|
||||||
|
// See also https://vt100.net/docs/vt510-rm/CPR.html
|
||||||
|
func CursorPositionReport(line, column int) string {
|
||||||
|
if line < 1 {
|
||||||
|
line = 1
|
||||||
|
}
|
||||||
|
if column < 1 {
|
||||||
|
column = 1
|
||||||
|
}
|
||||||
|
return "\x1b[" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPR is an alias for [CursorPositionReport].
|
||||||
|
func CPR(line, column int) string {
|
||||||
|
return CursorPositionReport(line, column)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtendedCursorPositionReport (DECXCPR) is a control sequence that reports the
|
||||||
|
// cursor's position along with the page number (optional).
|
||||||
|
//
|
||||||
|
// CSI ? Pl ; Pc R
|
||||||
|
// CSI ? Pl ; Pc ; Pv R
|
||||||
|
//
|
||||||
|
// Where Pl is the line number, Pc is the column number, and Pv is the page
|
||||||
|
// number.
|
||||||
|
//
|
||||||
|
// If the page number is zero or negative, the returned sequence won't include
|
||||||
|
// the page number.
|
||||||
|
//
|
||||||
|
// See also https://vt100.net/docs/vt510-rm/DECXCPR.html
|
||||||
|
func ExtendedCursorPositionReport(line, column, page int) string {
|
||||||
|
if line < 1 {
|
||||||
|
line = 1
|
||||||
|
}
|
||||||
|
if column < 1 {
|
||||||
|
column = 1
|
||||||
|
}
|
||||||
|
if page < 1 {
|
||||||
|
return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R"
|
||||||
|
}
|
||||||
|
return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + ";" + strconv.Itoa(page) + "R"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECXCPR is an alias for [ExtendedCursorPositionReport].
|
||||||
|
func DECXCPR(line, column, page int) string {
|
||||||
|
return ExtendedCursorPositionReport(line, column, page)
|
||||||
|
}
|
355
vendor/github.com/charmbracelet/x/ansi/style.go
generated
vendored
355
vendor/github.com/charmbracelet/x/ansi/style.go
generated
vendored
@ -12,10 +12,10 @@ import (
|
|||||||
const ResetStyle = "\x1b[m"
|
const ResetStyle = "\x1b[m"
|
||||||
|
|
||||||
// Attr is a SGR (Select Graphic Rendition) style attribute.
|
// Attr is a SGR (Select Graphic Rendition) style attribute.
|
||||||
type Attr = string
|
type Attr = int
|
||||||
|
|
||||||
// Style represents an ANSI SGR (Select Graphic Rendition) style.
|
// Style represents an ANSI SGR (Select Graphic Rendition) style.
|
||||||
type Style []Attr
|
type Style []string
|
||||||
|
|
||||||
// String returns the ANSI SGR (Select Graphic Rendition) style sequence for
|
// String returns the ANSI SGR (Select Graphic Rendition) style sequence for
|
||||||
// the given style.
|
// the given style.
|
||||||
@ -36,186 +36,357 @@ func (s Style) Styled(str string) string {
|
|||||||
|
|
||||||
// Reset appends the reset style attribute to the style.
|
// Reset appends the reset style attribute to the style.
|
||||||
func (s Style) Reset() Style {
|
func (s Style) Reset() Style {
|
||||||
return append(s, ResetAttr)
|
return append(s, resetAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bold appends the bold style attribute to the style.
|
// Bold appends the bold style attribute to the style.
|
||||||
func (s Style) Bold() Style {
|
func (s Style) Bold() Style {
|
||||||
return append(s, BoldAttr)
|
return append(s, boldAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Faint appends the faint style attribute to the style.
|
// Faint appends the faint style attribute to the style.
|
||||||
func (s Style) Faint() Style {
|
func (s Style) Faint() Style {
|
||||||
return append(s, FaintAttr)
|
return append(s, faintAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Italic appends the italic style attribute to the style.
|
// Italic appends the italic style attribute to the style.
|
||||||
func (s Style) Italic() Style {
|
func (s Style) Italic() Style {
|
||||||
return append(s, ItalicAttr)
|
return append(s, italicAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Underline appends the underline style attribute to the style.
|
// Underline appends the underline style attribute to the style.
|
||||||
func (s Style) Underline() Style {
|
func (s Style) Underline() Style {
|
||||||
return append(s, UnderlineAttr)
|
return append(s, underlineAttr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnderlineStyle appends the underline style attribute to the style.
|
||||||
|
func (s Style) UnderlineStyle(u UnderlineStyle) Style {
|
||||||
|
switch u {
|
||||||
|
case NoUnderlineStyle:
|
||||||
|
return s.NoUnderline()
|
||||||
|
case SingleUnderlineStyle:
|
||||||
|
return s.Underline()
|
||||||
|
case DoubleUnderlineStyle:
|
||||||
|
return append(s, doubleUnderlineStyle)
|
||||||
|
case CurlyUnderlineStyle:
|
||||||
|
return append(s, curlyUnderlineStyle)
|
||||||
|
case DottedUnderlineStyle:
|
||||||
|
return append(s, dottedUnderlineStyle)
|
||||||
|
case DashedUnderlineStyle:
|
||||||
|
return append(s, dashedUnderlineStyle)
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoubleUnderline appends the double underline style attribute to the style.
|
// DoubleUnderline appends the double underline style attribute to the style.
|
||||||
|
// This is a convenience method for UnderlineStyle(DoubleUnderlineStyle).
|
||||||
func (s Style) DoubleUnderline() Style {
|
func (s Style) DoubleUnderline() Style {
|
||||||
return append(s, DoubleUnderlineAttr)
|
return s.UnderlineStyle(DoubleUnderlineStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurlyUnderline appends the curly underline style attribute to the style.
|
// CurlyUnderline appends the curly underline style attribute to the style.
|
||||||
|
// This is a convenience method for UnderlineStyle(CurlyUnderlineStyle).
|
||||||
func (s Style) CurlyUnderline() Style {
|
func (s Style) CurlyUnderline() Style {
|
||||||
return append(s, CurlyUnderlineAttr)
|
return s.UnderlineStyle(CurlyUnderlineStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DottedUnderline appends the dotted underline style attribute to the style.
|
// DottedUnderline appends the dotted underline style attribute to the style.
|
||||||
|
// This is a convenience method for UnderlineStyle(DottedUnderlineStyle).
|
||||||
func (s Style) DottedUnderline() Style {
|
func (s Style) DottedUnderline() Style {
|
||||||
return append(s, DottedUnderlineAttr)
|
return s.UnderlineStyle(DottedUnderlineStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DashedUnderline appends the dashed underline style attribute to the style.
|
// DashedUnderline appends the dashed underline style attribute to the style.
|
||||||
|
// This is a convenience method for UnderlineStyle(DashedUnderlineStyle).
|
||||||
func (s Style) DashedUnderline() Style {
|
func (s Style) DashedUnderline() Style {
|
||||||
return append(s, DashedUnderlineAttr)
|
return s.UnderlineStyle(DashedUnderlineStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SlowBlink appends the slow blink style attribute to the style.
|
// SlowBlink appends the slow blink style attribute to the style.
|
||||||
func (s Style) SlowBlink() Style {
|
func (s Style) SlowBlink() Style {
|
||||||
return append(s, SlowBlinkAttr)
|
return append(s, slowBlinkAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RapidBlink appends the rapid blink style attribute to the style.
|
// RapidBlink appends the rapid blink style attribute to the style.
|
||||||
func (s Style) RapidBlink() Style {
|
func (s Style) RapidBlink() Style {
|
||||||
return append(s, RapidBlinkAttr)
|
return append(s, rapidBlinkAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse appends the reverse style attribute to the style.
|
// Reverse appends the reverse style attribute to the style.
|
||||||
func (s Style) Reverse() Style {
|
func (s Style) Reverse() Style {
|
||||||
return append(s, ReverseAttr)
|
return append(s, reverseAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conceal appends the conceal style attribute to the style.
|
// Conceal appends the conceal style attribute to the style.
|
||||||
func (s Style) Conceal() Style {
|
func (s Style) Conceal() Style {
|
||||||
return append(s, ConcealAttr)
|
return append(s, concealAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strikethrough appends the strikethrough style attribute to the style.
|
// Strikethrough appends the strikethrough style attribute to the style.
|
||||||
func (s Style) Strikethrough() Style {
|
func (s Style) Strikethrough() Style {
|
||||||
return append(s, StrikethroughAttr)
|
return append(s, strikethroughAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoBold appends the no bold style attribute to the style.
|
// NoBold appends the no bold style attribute to the style.
|
||||||
func (s Style) NoBold() Style {
|
func (s Style) NoBold() Style {
|
||||||
return append(s, NoBoldAttr)
|
return append(s, noBoldAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalIntensity appends the normal intensity style attribute to the style.
|
// NormalIntensity appends the normal intensity style attribute to the style.
|
||||||
func (s Style) NormalIntensity() Style {
|
func (s Style) NormalIntensity() Style {
|
||||||
return append(s, NormalIntensityAttr)
|
return append(s, normalIntensityAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoItalic appends the no italic style attribute to the style.
|
// NoItalic appends the no italic style attribute to the style.
|
||||||
func (s Style) NoItalic() Style {
|
func (s Style) NoItalic() Style {
|
||||||
return append(s, NoItalicAttr)
|
return append(s, noItalicAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoUnderline appends the no underline style attribute to the style.
|
// NoUnderline appends the no underline style attribute to the style.
|
||||||
func (s Style) NoUnderline() Style {
|
func (s Style) NoUnderline() Style {
|
||||||
return append(s, NoUnderlineAttr)
|
return append(s, noUnderlineAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoBlink appends the no blink style attribute to the style.
|
// NoBlink appends the no blink style attribute to the style.
|
||||||
func (s Style) NoBlink() Style {
|
func (s Style) NoBlink() Style {
|
||||||
return append(s, NoBlinkAttr)
|
return append(s, noBlinkAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoReverse appends the no reverse style attribute to the style.
|
// NoReverse appends the no reverse style attribute to the style.
|
||||||
func (s Style) NoReverse() Style {
|
func (s Style) NoReverse() Style {
|
||||||
return append(s, NoReverseAttr)
|
return append(s, noReverseAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoConceal appends the no conceal style attribute to the style.
|
// NoConceal appends the no conceal style attribute to the style.
|
||||||
func (s Style) NoConceal() Style {
|
func (s Style) NoConceal() Style {
|
||||||
return append(s, NoConcealAttr)
|
return append(s, noConcealAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoStrikethrough appends the no strikethrough style attribute to the style.
|
// NoStrikethrough appends the no strikethrough style attribute to the style.
|
||||||
func (s Style) NoStrikethrough() Style {
|
func (s Style) NoStrikethrough() Style {
|
||||||
return append(s, NoStrikethroughAttr)
|
return append(s, noStrikethroughAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultForegroundColor appends the default foreground color style attribute to the style.
|
// DefaultForegroundColor appends the default foreground color style attribute to the style.
|
||||||
func (s Style) DefaultForegroundColor() Style {
|
func (s Style) DefaultForegroundColor() Style {
|
||||||
return append(s, DefaultForegroundColorAttr)
|
return append(s, defaultForegroundColorAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultBackgroundColor appends the default background color style attribute to the style.
|
// DefaultBackgroundColor appends the default background color style attribute to the style.
|
||||||
func (s Style) DefaultBackgroundColor() Style {
|
func (s Style) DefaultBackgroundColor() Style {
|
||||||
return append(s, DefaultBackgroundColorAttr)
|
return append(s, defaultBackgroundColorAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultUnderlineColor appends the default underline color style attribute to the style.
|
// DefaultUnderlineColor appends the default underline color style attribute to the style.
|
||||||
func (s Style) DefaultUnderlineColor() Style {
|
func (s Style) DefaultUnderlineColor() Style {
|
||||||
return append(s, DefaultUnderlineColorAttr)
|
return append(s, defaultUnderlineColorAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForegroundColor appends the foreground color style attribute to the style.
|
// ForegroundColor appends the foreground color style attribute to the style.
|
||||||
func (s Style) ForegroundColor(c Color) Style {
|
func (s Style) ForegroundColor(c Color) Style {
|
||||||
return append(s, ForegroundColorAttr(c))
|
return append(s, foregroundColorString(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackgroundColor appends the background color style attribute to the style.
|
// BackgroundColor appends the background color style attribute to the style.
|
||||||
func (s Style) BackgroundColor(c Color) Style {
|
func (s Style) BackgroundColor(c Color) Style {
|
||||||
return append(s, BackgroundColorAttr(c))
|
return append(s, backgroundColorString(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnderlineColor appends the underline color style attribute to the style.
|
// UnderlineColor appends the underline color style attribute to the style.
|
||||||
func (s Style) UnderlineColor(c Color) Style {
|
func (s Style) UnderlineColor(c Color) Style {
|
||||||
return append(s, UnderlineColorAttr(c))
|
return append(s, underlineColorString(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnderlineStyle represents an ANSI SGR (Select Graphic Rendition) underline
|
||||||
|
// style.
|
||||||
|
type UnderlineStyle = int
|
||||||
|
|
||||||
|
const (
|
||||||
|
doubleUnderlineStyle = "4:2"
|
||||||
|
curlyUnderlineStyle = "4:3"
|
||||||
|
dottedUnderlineStyle = "4:4"
|
||||||
|
dashedUnderlineStyle = "4:5"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NoUnderlineStyle is the default underline style.
|
||||||
|
NoUnderlineStyle UnderlineStyle = iota
|
||||||
|
// SingleUnderlineStyle is a single underline style.
|
||||||
|
SingleUnderlineStyle
|
||||||
|
// DoubleUnderlineStyle is a double underline style.
|
||||||
|
DoubleUnderlineStyle
|
||||||
|
// CurlyUnderlineStyle is a curly underline style.
|
||||||
|
CurlyUnderlineStyle
|
||||||
|
// DottedUnderlineStyle is a dotted underline style.
|
||||||
|
DottedUnderlineStyle
|
||||||
|
// DashedUnderlineStyle is a dashed underline style.
|
||||||
|
DashedUnderlineStyle
|
||||||
|
)
|
||||||
|
|
||||||
// SGR (Select Graphic Rendition) style attributes.
|
// SGR (Select Graphic Rendition) style attributes.
|
||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
const (
|
const (
|
||||||
ResetAttr Attr = "0"
|
ResetAttr Attr = 0
|
||||||
BoldAttr Attr = "1"
|
BoldAttr Attr = 1
|
||||||
FaintAttr Attr = "2"
|
FaintAttr Attr = 2
|
||||||
ItalicAttr Attr = "3"
|
ItalicAttr Attr = 3
|
||||||
UnderlineAttr Attr = "4"
|
UnderlineAttr Attr = 4
|
||||||
DoubleUnderlineAttr Attr = "4:2"
|
SlowBlinkAttr Attr = 5
|
||||||
CurlyUnderlineAttr Attr = "4:3"
|
RapidBlinkAttr Attr = 6
|
||||||
DottedUnderlineAttr Attr = "4:4"
|
ReverseAttr Attr = 7
|
||||||
DashedUnderlineAttr Attr = "4:5"
|
ConcealAttr Attr = 8
|
||||||
SlowBlinkAttr Attr = "5"
|
StrikethroughAttr Attr = 9
|
||||||
RapidBlinkAttr Attr = "6"
|
NoBoldAttr Attr = 21 // Some terminals treat this as double underline.
|
||||||
ReverseAttr Attr = "7"
|
NormalIntensityAttr Attr = 22
|
||||||
ConcealAttr Attr = "8"
|
NoItalicAttr Attr = 23
|
||||||
StrikethroughAttr Attr = "9"
|
NoUnderlineAttr Attr = 24
|
||||||
NoBoldAttr Attr = "21" // Some terminals treat this as double underline.
|
NoBlinkAttr Attr = 25
|
||||||
NormalIntensityAttr Attr = "22"
|
NoReverseAttr Attr = 27
|
||||||
NoItalicAttr Attr = "23"
|
NoConcealAttr Attr = 28
|
||||||
NoUnderlineAttr Attr = "24"
|
NoStrikethroughAttr Attr = 29
|
||||||
NoBlinkAttr Attr = "25"
|
BlackForegroundColorAttr Attr = 30
|
||||||
NoReverseAttr Attr = "27"
|
RedForegroundColorAttr Attr = 31
|
||||||
NoConcealAttr Attr = "28"
|
GreenForegroundColorAttr Attr = 32
|
||||||
NoStrikethroughAttr Attr = "29"
|
YellowForegroundColorAttr Attr = 33
|
||||||
DefaultForegroundColorAttr Attr = "39"
|
BlueForegroundColorAttr Attr = 34
|
||||||
DefaultBackgroundColorAttr Attr = "49"
|
MagentaForegroundColorAttr Attr = 35
|
||||||
DefaultUnderlineColorAttr Attr = "59"
|
CyanForegroundColorAttr Attr = 36
|
||||||
|
WhiteForegroundColorAttr Attr = 37
|
||||||
|
ExtendedForegroundColorAttr Attr = 38
|
||||||
|
DefaultForegroundColorAttr Attr = 39
|
||||||
|
BlackBackgroundColorAttr Attr = 40
|
||||||
|
RedBackgroundColorAttr Attr = 41
|
||||||
|
GreenBackgroundColorAttr Attr = 42
|
||||||
|
YellowBackgroundColorAttr Attr = 43
|
||||||
|
BlueBackgroundColorAttr Attr = 44
|
||||||
|
MagentaBackgroundColorAttr Attr = 45
|
||||||
|
CyanBackgroundColorAttr Attr = 46
|
||||||
|
WhiteBackgroundColorAttr Attr = 47
|
||||||
|
ExtendedBackgroundColorAttr Attr = 48
|
||||||
|
DefaultBackgroundColorAttr Attr = 49
|
||||||
|
ExtendedUnderlineColorAttr Attr = 58
|
||||||
|
DefaultUnderlineColorAttr Attr = 59
|
||||||
|
BrightBlackForegroundColorAttr Attr = 90
|
||||||
|
BrightRedForegroundColorAttr Attr = 91
|
||||||
|
BrightGreenForegroundColorAttr Attr = 92
|
||||||
|
BrightYellowForegroundColorAttr Attr = 93
|
||||||
|
BrightBlueForegroundColorAttr Attr = 94
|
||||||
|
BrightMagentaForegroundColorAttr Attr = 95
|
||||||
|
BrightCyanForegroundColorAttr Attr = 96
|
||||||
|
BrightWhiteForegroundColorAttr Attr = 97
|
||||||
|
BrightBlackBackgroundColorAttr Attr = 100
|
||||||
|
BrightRedBackgroundColorAttr Attr = 101
|
||||||
|
BrightGreenBackgroundColorAttr Attr = 102
|
||||||
|
BrightYellowBackgroundColorAttr Attr = 103
|
||||||
|
BrightBlueBackgroundColorAttr Attr = 104
|
||||||
|
BrightMagentaBackgroundColorAttr Attr = 105
|
||||||
|
BrightCyanBackgroundColorAttr Attr = 106
|
||||||
|
BrightWhiteBackgroundColorAttr Attr = 107
|
||||||
|
|
||||||
|
RGBColorIntroducerAttr Attr = 2
|
||||||
|
ExtendedColorIntroducerAttr Attr = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// ForegroundColorAttr returns the style SGR attribute for the given foreground
|
const (
|
||||||
// color.
|
resetAttr = "0"
|
||||||
|
boldAttr = "1"
|
||||||
|
faintAttr = "2"
|
||||||
|
italicAttr = "3"
|
||||||
|
underlineAttr = "4"
|
||||||
|
slowBlinkAttr = "5"
|
||||||
|
rapidBlinkAttr = "6"
|
||||||
|
reverseAttr = "7"
|
||||||
|
concealAttr = "8"
|
||||||
|
strikethroughAttr = "9"
|
||||||
|
noBoldAttr = "21"
|
||||||
|
normalIntensityAttr = "22"
|
||||||
|
noItalicAttr = "23"
|
||||||
|
noUnderlineAttr = "24"
|
||||||
|
noBlinkAttr = "25"
|
||||||
|
noReverseAttr = "27"
|
||||||
|
noConcealAttr = "28"
|
||||||
|
noStrikethroughAttr = "29"
|
||||||
|
blackForegroundColorAttr = "30"
|
||||||
|
redForegroundColorAttr = "31"
|
||||||
|
greenForegroundColorAttr = "32"
|
||||||
|
yellowForegroundColorAttr = "33"
|
||||||
|
blueForegroundColorAttr = "34"
|
||||||
|
magentaForegroundColorAttr = "35"
|
||||||
|
cyanForegroundColorAttr = "36"
|
||||||
|
whiteForegroundColorAttr = "37"
|
||||||
|
extendedForegroundColorAttr = "38"
|
||||||
|
defaultForegroundColorAttr = "39"
|
||||||
|
blackBackgroundColorAttr = "40"
|
||||||
|
redBackgroundColorAttr = "41"
|
||||||
|
greenBackgroundColorAttr = "42"
|
||||||
|
yellowBackgroundColorAttr = "43"
|
||||||
|
blueBackgroundColorAttr = "44"
|
||||||
|
magentaBackgroundColorAttr = "45"
|
||||||
|
cyanBackgroundColorAttr = "46"
|
||||||
|
whiteBackgroundColorAttr = "47"
|
||||||
|
extendedBackgroundColorAttr = "48"
|
||||||
|
defaultBackgroundColorAttr = "49"
|
||||||
|
extendedUnderlineColorAttr = "58"
|
||||||
|
defaultUnderlineColorAttr = "59"
|
||||||
|
brightBlackForegroundColorAttr = "90"
|
||||||
|
brightRedForegroundColorAttr = "91"
|
||||||
|
brightGreenForegroundColorAttr = "92"
|
||||||
|
brightYellowForegroundColorAttr = "93"
|
||||||
|
brightBlueForegroundColorAttr = "94"
|
||||||
|
brightMagentaForegroundColorAttr = "95"
|
||||||
|
brightCyanForegroundColorAttr = "96"
|
||||||
|
brightWhiteForegroundColorAttr = "97"
|
||||||
|
brightBlackBackgroundColorAttr = "100"
|
||||||
|
brightRedBackgroundColorAttr = "101"
|
||||||
|
brightGreenBackgroundColorAttr = "102"
|
||||||
|
brightYellowBackgroundColorAttr = "103"
|
||||||
|
brightBlueBackgroundColorAttr = "104"
|
||||||
|
brightMagentaBackgroundColorAttr = "105"
|
||||||
|
brightCyanBackgroundColorAttr = "106"
|
||||||
|
brightWhiteBackgroundColorAttr = "107"
|
||||||
|
)
|
||||||
|
|
||||||
|
// foregroundColorString returns the style SGR attribute for the given
|
||||||
|
// foreground color.
|
||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
func ForegroundColorAttr(c Color) Attr {
|
func foregroundColorString(c Color) string {
|
||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
case BasicColor:
|
case BasicColor:
|
||||||
// 3-bit or 4-bit ANSI foreground
|
// 3-bit or 4-bit ANSI foreground
|
||||||
// "3<n>" or "9<n>" where n is the color number from 0 to 7
|
// "3<n>" or "9<n>" where n is the color number from 0 to 7
|
||||||
if c < 8 {
|
switch c {
|
||||||
return "3" + string('0'+c)
|
case Black:
|
||||||
} else if c < 16 {
|
return blackForegroundColorAttr
|
||||||
return "9" + string('0'+c-8)
|
case Red:
|
||||||
|
return redForegroundColorAttr
|
||||||
|
case Green:
|
||||||
|
return greenForegroundColorAttr
|
||||||
|
case Yellow:
|
||||||
|
return yellowForegroundColorAttr
|
||||||
|
case Blue:
|
||||||
|
return blueForegroundColorAttr
|
||||||
|
case Magenta:
|
||||||
|
return magentaForegroundColorAttr
|
||||||
|
case Cyan:
|
||||||
|
return cyanForegroundColorAttr
|
||||||
|
case White:
|
||||||
|
return whiteForegroundColorAttr
|
||||||
|
case BrightBlack:
|
||||||
|
return brightBlackForegroundColorAttr
|
||||||
|
case BrightRed:
|
||||||
|
return brightRedForegroundColorAttr
|
||||||
|
case BrightGreen:
|
||||||
|
return brightGreenForegroundColorAttr
|
||||||
|
case BrightYellow:
|
||||||
|
return brightYellowForegroundColorAttr
|
||||||
|
case BrightBlue:
|
||||||
|
return brightBlueForegroundColorAttr
|
||||||
|
case BrightMagenta:
|
||||||
|
return brightMagentaForegroundColorAttr
|
||||||
|
case BrightCyan:
|
||||||
|
return brightCyanForegroundColorAttr
|
||||||
|
case BrightWhite:
|
||||||
|
return brightWhiteForegroundColorAttr
|
||||||
}
|
}
|
||||||
case ExtendedColor:
|
case ExtendedColor:
|
||||||
// 256-color ANSI foreground
|
// 256-color ANSI foreground
|
||||||
@ -230,21 +401,50 @@ func ForegroundColorAttr(c Color) Attr {
|
|||||||
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
||||||
strconv.FormatUint(uint64(shift(b)), 10)
|
strconv.FormatUint(uint64(shift(b)), 10)
|
||||||
}
|
}
|
||||||
return DefaultForegroundColorAttr
|
return defaultForegroundColorAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackgroundColorAttr returns the style SGR attribute for the given background
|
// backgroundColorString returns the style SGR attribute for the given
|
||||||
// color.
|
// background color.
|
||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
func BackgroundColorAttr(c Color) Attr {
|
func backgroundColorString(c Color) string {
|
||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
case BasicColor:
|
case BasicColor:
|
||||||
// 3-bit or 4-bit ANSI foreground
|
// 3-bit or 4-bit ANSI foreground
|
||||||
// "4<n>" or "10<n>" where n is the color number from 0 to 7
|
// "4<n>" or "10<n>" where n is the color number from 0 to 7
|
||||||
if c < 8 {
|
switch c {
|
||||||
return "4" + string('0'+c)
|
case Black:
|
||||||
} else {
|
return blackBackgroundColorAttr
|
||||||
return "10" + string('0'+c-8)
|
case Red:
|
||||||
|
return redBackgroundColorAttr
|
||||||
|
case Green:
|
||||||
|
return greenBackgroundColorAttr
|
||||||
|
case Yellow:
|
||||||
|
return yellowBackgroundColorAttr
|
||||||
|
case Blue:
|
||||||
|
return blueBackgroundColorAttr
|
||||||
|
case Magenta:
|
||||||
|
return magentaBackgroundColorAttr
|
||||||
|
case Cyan:
|
||||||
|
return cyanBackgroundColorAttr
|
||||||
|
case White:
|
||||||
|
return whiteBackgroundColorAttr
|
||||||
|
case BrightBlack:
|
||||||
|
return brightBlackBackgroundColorAttr
|
||||||
|
case BrightRed:
|
||||||
|
return brightRedBackgroundColorAttr
|
||||||
|
case BrightGreen:
|
||||||
|
return brightGreenBackgroundColorAttr
|
||||||
|
case BrightYellow:
|
||||||
|
return brightYellowBackgroundColorAttr
|
||||||
|
case BrightBlue:
|
||||||
|
return brightBlueBackgroundColorAttr
|
||||||
|
case BrightMagenta:
|
||||||
|
return brightMagentaBackgroundColorAttr
|
||||||
|
case BrightCyan:
|
||||||
|
return brightCyanBackgroundColorAttr
|
||||||
|
case BrightWhite:
|
||||||
|
return brightWhiteBackgroundColorAttr
|
||||||
}
|
}
|
||||||
case ExtendedColor:
|
case ExtendedColor:
|
||||||
// 256-color ANSI foreground
|
// 256-color ANSI foreground
|
||||||
@ -259,13 +459,13 @@ func BackgroundColorAttr(c Color) Attr {
|
|||||||
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
||||||
strconv.FormatUint(uint64(shift(b)), 10)
|
strconv.FormatUint(uint64(shift(b)), 10)
|
||||||
}
|
}
|
||||||
return DefaultBackgroundColorAttr
|
return defaultBackgroundColorAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnderlineColorAttr returns the style SGR attribute for the given underline
|
// underlineColorString returns the style SGR attribute for the given underline
|
||||||
// color.
|
// color.
|
||||||
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
// See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
|
||||||
func UnderlineColorAttr(c Color) Attr {
|
func underlineColorString(c Color) string {
|
||||||
switch c := c.(type) {
|
switch c := c.(type) {
|
||||||
// NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline
|
// NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline
|
||||||
// color, use 256-color instead.
|
// color, use 256-color instead.
|
||||||
@ -285,12 +485,5 @@ func UnderlineColorAttr(c Color) Attr {
|
|||||||
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
strconv.FormatUint(uint64(shift(g)), 10) + ";" +
|
||||||
strconv.FormatUint(uint64(shift(b)), 10)
|
strconv.FormatUint(uint64(shift(b)), 10)
|
||||||
}
|
}
|
||||||
return DefaultUnderlineColorAttr
|
return defaultUnderlineColorAttr
|
||||||
}
|
|
||||||
|
|
||||||
func shift(v uint32) uint32 {
|
|
||||||
if v > 0xff {
|
|
||||||
return v >> 8
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
12
vendor/github.com/charmbracelet/x/ansi/termcap.go
generated
vendored
12
vendor/github.com/charmbracelet/x/ansi/termcap.go
generated
vendored
@ -14,7 +14,7 @@ import (
|
|||||||
//
|
//
|
||||||
// See: https://man7.org/linux/man-pages/man5/terminfo.5.html
|
// See: https://man7.org/linux/man-pages/man5/terminfo.5.html
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
|
||||||
func RequestTermcap(caps ...string) string {
|
func XTGETTCAP(caps ...string) string {
|
||||||
if len(caps) == 0 {
|
if len(caps) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -29,3 +29,13 @@ func RequestTermcap(caps ...string) string {
|
|||||||
|
|
||||||
return s + "\x1b\\"
|
return s + "\x1b\\"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestTermcap is an alias for [XTGETTCAP].
|
||||||
|
func RequestTermcap(caps ...string) string {
|
||||||
|
return XTGETTCAP(caps...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestTerminfo is an alias for [XTGETTCAP].
|
||||||
|
func RequestTerminfo(caps ...string) string {
|
||||||
|
return XTGETTCAP(caps...)
|
||||||
|
}
|
||||||
|
63
vendor/github.com/charmbracelet/x/ansi/truncate.go
generated
vendored
63
vendor/github.com/charmbracelet/x/ansi/truncate.go
generated
vendored
@ -26,7 +26,6 @@ func Truncate(s string, length int, tail string) string {
|
|||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
curWidth := 0
|
curWidth := 0
|
||||||
ignoring := false
|
ignoring := false
|
||||||
gstate := -1
|
|
||||||
pstate := parser.GroundState // initial state
|
pstate := parser.GroundState // initial state
|
||||||
b := []byte(s)
|
b := []byte(s)
|
||||||
i := 0
|
i := 0
|
||||||
@ -38,44 +37,40 @@ func Truncate(s string, length int, tail string) string {
|
|||||||
// collect ANSI escape codes until we reach the end of string.
|
// collect ANSI escape codes until we reach the end of string.
|
||||||
for i < len(b) {
|
for i < len(b) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, b[i])
|
||||||
|
if state == parser.Utf8State {
|
||||||
|
// This action happens when we transition to the Utf8State.
|
||||||
|
var width int
|
||||||
|
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
||||||
|
|
||||||
switch action {
|
// increment the index by the length of the cluster
|
||||||
case parser.PrintAction:
|
i += len(cluster)
|
||||||
if utf8ByteLen(b[i]) > 1 {
|
|
||||||
// This action happens when we transition to the Utf8State.
|
|
||||||
var width int
|
|
||||||
cluster, _, width, gstate = uniseg.FirstGraphemeCluster(b[i:], gstate)
|
|
||||||
|
|
||||||
// increment the index by the length of the cluster
|
// Are we ignoring? Skip to the next byte
|
||||||
i += len(cluster)
|
if ignoring {
|
||||||
|
|
||||||
// Are we ignoring? Skip to the next byte
|
|
||||||
if ignoring {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this gonna be too wide?
|
|
||||||
// If so write the tail and stop collecting.
|
|
||||||
if curWidth+width > length && !ignoring {
|
|
||||||
ignoring = true
|
|
||||||
buf.WriteString(tail)
|
|
||||||
}
|
|
||||||
|
|
||||||
if curWidth+width > length {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
curWidth += width
|
|
||||||
for _, r := range cluster {
|
|
||||||
buf.WriteByte(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
gstate = -1 // reset grapheme state otherwise, width calculation might be off
|
|
||||||
// Done collecting, now we're back in the ground state.
|
|
||||||
pstate = parser.GroundState
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is this gonna be too wide?
|
||||||
|
// If so write the tail and stop collecting.
|
||||||
|
if curWidth+width > length && !ignoring {
|
||||||
|
ignoring = true
|
||||||
|
buf.WriteString(tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
if curWidth+width > length {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
curWidth += width
|
||||||
|
buf.Write(cluster)
|
||||||
|
|
||||||
|
// Done collecting, now we're back in the ground state.
|
||||||
|
pstate = parser.GroundState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case parser.PrintAction:
|
||||||
// Is this gonna be too wide?
|
// Is this gonna be too wide?
|
||||||
// If so write the tail and stop collecting.
|
// If so write the tail and stop collecting.
|
||||||
if curWidth >= length && !ignoring {
|
if curWidth >= length && !ignoring {
|
||||||
|
63
vendor/github.com/charmbracelet/x/ansi/util.go
generated
vendored
63
vendor/github.com/charmbracelet/x/ansi/util.go
generated
vendored
@ -3,6 +3,10 @@ package ansi
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/lucasb-eyer/go-colorful"
|
||||||
)
|
)
|
||||||
|
|
||||||
// colorToHexString returns a hex string representation of a color.
|
// colorToHexString returns a hex string representation of a color.
|
||||||
@ -27,3 +31,62 @@ func colorToHexString(c color.Color) string {
|
|||||||
func rgbToHex(r, g, b uint32) uint32 {
|
func rgbToHex(r, g, b uint32) uint32 {
|
||||||
return r<<16 + g<<8 + b
|
return r<<16 + g<<8 + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type shiftable interface {
|
||||||
|
~uint | ~uint16 | ~uint32 | ~uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func shift[T shiftable](x T) T {
|
||||||
|
if x > 0xff {
|
||||||
|
x >>= 8
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// XParseColor is a helper function that parses a string into a color.Color. It
|
||||||
|
// provides a similar interface to the XParseColor function in Xlib. It
|
||||||
|
// supports the following formats:
|
||||||
|
//
|
||||||
|
// - #RGB
|
||||||
|
// - #RRGGBB
|
||||||
|
// - rgb:RRRR/GGGG/BBBB
|
||||||
|
// - rgba:RRRR/GGGG/BBBB/AAAA
|
||||||
|
//
|
||||||
|
// If the string is not a valid color, nil is returned.
|
||||||
|
//
|
||||||
|
// See: https://linux.die.net/man/3/xparsecolor
|
||||||
|
func XParseColor(s string) color.Color {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(s, "#"):
|
||||||
|
c, err := colorful.Hex(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
case strings.HasPrefix(s, "rgb:"):
|
||||||
|
parts := strings.Split(s[4:], "/")
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _ := strconv.ParseUint(parts[0], 16, 32)
|
||||||
|
g, _ := strconv.ParseUint(parts[1], 16, 32)
|
||||||
|
b, _ := strconv.ParseUint(parts[2], 16, 32)
|
||||||
|
|
||||||
|
return color.RGBA{uint8(shift(r)), uint8(shift(g)), uint8(shift(b)), 255} //nolint:gosec
|
||||||
|
case strings.HasPrefix(s, "rgba:"):
|
||||||
|
parts := strings.Split(s[5:], "/")
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _ := strconv.ParseUint(parts[0], 16, 32)
|
||||||
|
g, _ := strconv.ParseUint(parts[1], 16, 32)
|
||||||
|
b, _ := strconv.ParseUint(parts[2], 16, 32)
|
||||||
|
a, _ := strconv.ParseUint(parts[3], 16, 32)
|
||||||
|
|
||||||
|
return color.RGBA{uint8(shift(r)), uint8(shift(g)), uint8(shift(b)), uint8(shift(a))} //nolint:gosec
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
46
vendor/github.com/charmbracelet/x/ansi/width.go
generated
vendored
46
vendor/github.com/charmbracelet/x/ansi/width.go
generated
vendored
@ -19,13 +19,7 @@ func Strip(s string) string {
|
|||||||
// This implements a subset of the Parser to only collect runes and
|
// This implements a subset of the Parser to only collect runes and
|
||||||
// printable characters.
|
// printable characters.
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
var state, action byte
|
if pstate == parser.Utf8State {
|
||||||
if pstate != parser.Utf8State {
|
|
||||||
state, action = parser.Table.Transition(pstate, s[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case pstate == parser.Utf8State:
|
|
||||||
// During this state, collect rw bytes to form a valid rune in the
|
// During this state, collect rw bytes to form a valid rune in the
|
||||||
// buffer. After getting all the rune bytes into the buffer,
|
// buffer. After getting all the rune bytes into the buffer,
|
||||||
// transition to GroundState and reset the counters.
|
// transition to GroundState and reset the counters.
|
||||||
@ -37,16 +31,19 @@ func Strip(s string) string {
|
|||||||
pstate = parser.GroundState
|
pstate = parser.GroundState
|
||||||
ri = 0
|
ri = 0
|
||||||
rw = 0
|
rw = 0
|
||||||
case action == parser.PrintAction:
|
continue
|
||||||
// This action happens when we transition to the Utf8State.
|
}
|
||||||
if w := utf8ByteLen(s[i]); w > 1 {
|
|
||||||
rw = w
|
state, action := parser.Table.Transition(pstate, s[i])
|
||||||
|
switch action {
|
||||||
|
case parser.CollectAction:
|
||||||
|
if state == parser.Utf8State {
|
||||||
|
// This action happens when we transition to the Utf8State.
|
||||||
|
rw = utf8ByteLen(s[i])
|
||||||
buf.WriteByte(s[i])
|
buf.WriteByte(s[i])
|
||||||
ri++
|
ri++
|
||||||
break
|
|
||||||
}
|
}
|
||||||
fallthrough
|
case parser.PrintAction, parser.ExecuteAction:
|
||||||
case action == parser.ExecuteAction:
|
|
||||||
// collects printable ASCII and non-printable characters
|
// collects printable ASCII and non-printable characters
|
||||||
buf.WriteByte(s[i])
|
buf.WriteByte(s[i])
|
||||||
}
|
}
|
||||||
@ -71,7 +68,6 @@ func StringWidth(s string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gstate = -1
|
|
||||||
pstate = parser.GroundState // initial state
|
pstate = parser.GroundState // initial state
|
||||||
cluster string
|
cluster string
|
||||||
width int
|
width int
|
||||||
@ -79,16 +75,16 @@ func StringWidth(s string) int {
|
|||||||
|
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
state, action := parser.Table.Transition(pstate, s[i])
|
state, action := parser.Table.Transition(pstate, s[i])
|
||||||
switch action {
|
if state == parser.Utf8State {
|
||||||
case parser.PrintAction:
|
var w int
|
||||||
if utf8ByteLen(s[i]) > 1 {
|
cluster, _, w, _ = uniseg.FirstGraphemeClusterInString(s[i:], -1)
|
||||||
var w int
|
width += w
|
||||||
cluster, _, w, gstate = uniseg.FirstGraphemeClusterInString(s[i:], gstate)
|
i += len(cluster) - 1
|
||||||
width += w
|
pstate = parser.GroundState
|
||||||
i += len(cluster) - 1
|
continue
|
||||||
pstate = parser.GroundState
|
}
|
||||||
continue
|
|
||||||
}
|
if action == parser.PrintAction {
|
||||||
width++
|
width++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
186
vendor/github.com/charmbracelet/x/ansi/wrap.go
generated
vendored
186
vendor/github.com/charmbracelet/x/ansi/wrap.go
generated
vendored
@ -27,7 +27,6 @@ func Hardwrap(s string, limit int, preserveSpace bool) string {
|
|||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
curWidth int
|
curWidth int
|
||||||
forceNewline bool
|
forceNewline bool
|
||||||
gstate = -1
|
|
||||||
pstate = parser.GroundState // initial state
|
pstate = parser.GroundState // initial state
|
||||||
b = []byte(s)
|
b = []byte(s)
|
||||||
)
|
)
|
||||||
@ -40,33 +39,30 @@ func Hardwrap(s string, limit int, preserveSpace bool) string {
|
|||||||
i := 0
|
i := 0
|
||||||
for i < len(b) {
|
for i < len(b) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, b[i])
|
||||||
|
if state == parser.Utf8State {
|
||||||
|
var width int
|
||||||
|
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
||||||
|
i += len(cluster)
|
||||||
|
|
||||||
|
if curWidth+width > limit {
|
||||||
|
addNewline()
|
||||||
|
}
|
||||||
|
if !preserveSpace && curWidth == 0 && len(cluster) <= 4 {
|
||||||
|
// Skip spaces at the beginning of a line
|
||||||
|
if r, _ := utf8.DecodeRune(cluster); r != utf8.RuneError && unicode.IsSpace(r) {
|
||||||
|
pstate = parser.GroundState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Write(cluster)
|
||||||
|
curWidth += width
|
||||||
|
pstate = parser.GroundState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case parser.PrintAction:
|
case parser.PrintAction, parser.ExecuteAction:
|
||||||
if utf8ByteLen(b[i]) > 1 {
|
|
||||||
var width int
|
|
||||||
cluster, _, width, gstate = uniseg.FirstGraphemeCluster(b[i:], gstate)
|
|
||||||
i += len(cluster)
|
|
||||||
|
|
||||||
if curWidth+width > limit {
|
|
||||||
addNewline()
|
|
||||||
}
|
|
||||||
if !preserveSpace && curWidth == 0 && len(cluster) <= 4 {
|
|
||||||
// Skip spaces at the beginning of a line
|
|
||||||
if r, _ := utf8.DecodeRune(cluster); r != utf8.RuneError && unicode.IsSpace(r) {
|
|
||||||
pstate = parser.GroundState
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.Write(cluster)
|
|
||||||
curWidth += width
|
|
||||||
gstate = -1 // reset grapheme state otherwise, width calculation might be off
|
|
||||||
pstate = parser.GroundState
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case parser.ExecuteAction:
|
|
||||||
if b[i] == '\n' {
|
if b[i] == '\n' {
|
||||||
addNewline()
|
addNewline()
|
||||||
forceNewline = false
|
forceNewline = false
|
||||||
@ -87,7 +83,9 @@ func Hardwrap(s string, limit int, preserveSpace bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteByte(b[i])
|
buf.WriteByte(b[i])
|
||||||
curWidth++
|
if action == parser.PrintAction {
|
||||||
|
curWidth++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
buf.WriteByte(b[i])
|
buf.WriteByte(b[i])
|
||||||
}
|
}
|
||||||
@ -122,7 +120,6 @@ func Wordwrap(s string, limit int, breakpoints string) string {
|
|||||||
space bytes.Buffer
|
space bytes.Buffer
|
||||||
curWidth int
|
curWidth int
|
||||||
wordLen int
|
wordLen int
|
||||||
gstate = -1
|
|
||||||
pstate = parser.GroundState // initial state
|
pstate = parser.GroundState // initial state
|
||||||
b = []byte(s)
|
b = []byte(s)
|
||||||
)
|
)
|
||||||
@ -154,37 +151,35 @@ func Wordwrap(s string, limit int, breakpoints string) string {
|
|||||||
i := 0
|
i := 0
|
||||||
for i < len(b) {
|
for i < len(b) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, b[i])
|
||||||
|
if state == parser.Utf8State {
|
||||||
|
var width int
|
||||||
|
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
||||||
|
i += len(cluster)
|
||||||
|
|
||||||
|
r, _ := utf8.DecodeRune(cluster)
|
||||||
|
if r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp {
|
||||||
|
addWord()
|
||||||
|
space.WriteRune(r)
|
||||||
|
} else if bytes.ContainsAny(cluster, breakpoints) {
|
||||||
|
addSpace()
|
||||||
|
addWord()
|
||||||
|
buf.Write(cluster)
|
||||||
|
curWidth++
|
||||||
|
} else {
|
||||||
|
word.Write(cluster)
|
||||||
|
wordLen += width
|
||||||
|
if curWidth+space.Len()+wordLen > limit &&
|
||||||
|
wordLen < limit {
|
||||||
|
addNewline()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pstate = parser.GroundState
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case parser.PrintAction:
|
case parser.PrintAction, parser.ExecuteAction:
|
||||||
if utf8ByteLen(b[i]) > 1 {
|
|
||||||
var width int
|
|
||||||
cluster, _, width, gstate = uniseg.FirstGraphemeCluster(b[i:], gstate)
|
|
||||||
i += len(cluster)
|
|
||||||
|
|
||||||
r, _ := utf8.DecodeRune(cluster)
|
|
||||||
if r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp {
|
|
||||||
addWord()
|
|
||||||
space.WriteRune(r)
|
|
||||||
} else if bytes.ContainsAny(cluster, breakpoints) {
|
|
||||||
addSpace()
|
|
||||||
addWord()
|
|
||||||
buf.Write(cluster)
|
|
||||||
curWidth++
|
|
||||||
} else {
|
|
||||||
word.Write(cluster)
|
|
||||||
wordLen += width
|
|
||||||
if curWidth+space.Len()+wordLen > limit &&
|
|
||||||
wordLen < limit {
|
|
||||||
addNewline()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pstate = parser.GroundState
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case parser.ExecuteAction:
|
|
||||||
r := rune(b[i])
|
r := rune(b[i])
|
||||||
switch {
|
switch {
|
||||||
case r == '\n':
|
case r == '\n':
|
||||||
@ -251,9 +246,8 @@ func Wrap(s string, limit int, breakpoints string) string {
|
|||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
word bytes.Buffer
|
word bytes.Buffer
|
||||||
space bytes.Buffer
|
space bytes.Buffer
|
||||||
curWidth int // written width of the line
|
curWidth int // written width of the line
|
||||||
wordLen int // word buffer len without ANSI escape codes
|
wordLen int // word buffer len without ANSI escape codes
|
||||||
gstate = -1
|
|
||||||
pstate = parser.GroundState // initial state
|
pstate = parser.GroundState // initial state
|
||||||
b = []byte(s)
|
b = []byte(s)
|
||||||
)
|
)
|
||||||
@ -285,49 +279,46 @@ func Wrap(s string, limit int, breakpoints string) string {
|
|||||||
i := 0
|
i := 0
|
||||||
for i < len(b) {
|
for i < len(b) {
|
||||||
state, action := parser.Table.Transition(pstate, b[i])
|
state, action := parser.Table.Transition(pstate, b[i])
|
||||||
|
if state == parser.Utf8State {
|
||||||
|
var width int
|
||||||
|
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)
|
||||||
|
i += len(cluster)
|
||||||
|
|
||||||
switch action {
|
r, _ := utf8.DecodeRune(cluster)
|
||||||
case parser.PrintAction:
|
switch {
|
||||||
if utf8ByteLen(b[i]) > 1 {
|
case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space
|
||||||
var width int
|
addWord()
|
||||||
cluster, _, width, gstate = uniseg.FirstGraphemeCluster(b[i:], gstate)
|
space.WriteRune(r)
|
||||||
i += len(cluster)
|
case bytes.ContainsAny(cluster, breakpoints):
|
||||||
|
addSpace()
|
||||||
r, _ := utf8.DecodeRune(cluster)
|
if curWidth+wordLen+width > limit {
|
||||||
switch {
|
|
||||||
case r != utf8.RuneError && unicode.IsSpace(r) && r != nbsp: // nbsp is a non-breaking space
|
|
||||||
addWord()
|
|
||||||
space.WriteRune(r)
|
|
||||||
case bytes.ContainsAny(cluster, breakpoints):
|
|
||||||
addSpace()
|
|
||||||
if curWidth+wordLen+width > limit {
|
|
||||||
word.Write(cluster)
|
|
||||||
wordLen += width
|
|
||||||
} else {
|
|
||||||
addWord()
|
|
||||||
buf.Write(cluster)
|
|
||||||
curWidth += width
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if wordLen+width > limit {
|
|
||||||
// Hardwrap the word if it's too long
|
|
||||||
addWord()
|
|
||||||
}
|
|
||||||
|
|
||||||
word.Write(cluster)
|
word.Write(cluster)
|
||||||
wordLen += width
|
wordLen += width
|
||||||
|
} else {
|
||||||
if curWidth+wordLen+space.Len() > limit {
|
addWord()
|
||||||
addNewline()
|
buf.Write(cluster)
|
||||||
}
|
curWidth += width
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if wordLen+width > limit {
|
||||||
|
// Hardwrap the word if it's too long
|
||||||
|
addWord()
|
||||||
}
|
}
|
||||||
|
|
||||||
pstate = parser.GroundState
|
word.Write(cluster)
|
||||||
continue
|
wordLen += width
|
||||||
|
|
||||||
|
if curWidth+wordLen+space.Len() > limit {
|
||||||
|
addNewline()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fallthrough
|
pstate = parser.GroundState
|
||||||
case parser.ExecuteAction:
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case parser.PrintAction, parser.ExecuteAction:
|
||||||
switch r := rune(b[i]); {
|
switch r := rune(b[i]); {
|
||||||
case r == '\n':
|
case r == '\n':
|
||||||
if wordLen == 0 {
|
if wordLen == 0 {
|
||||||
@ -360,6 +351,9 @@ func Wrap(s string, limit int, breakpoints string) string {
|
|||||||
curWidth++
|
curWidth++
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
if curWidth == limit {
|
||||||
|
addNewline()
|
||||||
|
}
|
||||||
word.WriteRune(r)
|
word.WriteRune(r)
|
||||||
wordLen++
|
wordLen++
|
||||||
|
|
||||||
|
100
vendor/github.com/charmbracelet/x/ansi/xterm.go
generated
vendored
100
vendor/github.com/charmbracelet/x/ansi/xterm.go
generated
vendored
@ -1,11 +1,108 @@
|
|||||||
package ansi
|
package ansi
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// KeyModifierOptions (XTMODKEYS) sets/resets xterm key modifier options.
|
||||||
|
//
|
||||||
|
// Default is 0.
|
||||||
|
//
|
||||||
|
// CSI > Pp m
|
||||||
|
// CSI > Pp ; Pv m
|
||||||
|
//
|
||||||
|
// If Pv is omitted, the resource is reset to its initial value.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
|
func KeyModifierOptions(p int, vs ...int) string {
|
||||||
|
var pp, pv string
|
||||||
|
if p > 0 {
|
||||||
|
pp = strconv.Itoa(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vs) == 0 {
|
||||||
|
return "\x1b[>" + strconv.Itoa(p) + "m"
|
||||||
|
}
|
||||||
|
|
||||||
|
v := vs[0]
|
||||||
|
if v > 0 {
|
||||||
|
pv = strconv.Itoa(v)
|
||||||
|
return "\x1b[>" + pp + ";" + pv + "m"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "\x1b[>" + pp + "m"
|
||||||
|
}
|
||||||
|
|
||||||
|
// XTMODKEYS is an alias for [KeyModifierOptions].
|
||||||
|
func XTMODKEYS(p int, vs ...int) string {
|
||||||
|
return KeyModifierOptions(p, vs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKeyModifierOptions sets xterm key modifier options.
|
||||||
|
// This is an alias for [KeyModifierOptions].
|
||||||
|
func SetKeyModifierOptions(pp int, pv int) string {
|
||||||
|
return KeyModifierOptions(pp, pv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetKeyModifierOptions resets xterm key modifier options.
|
||||||
|
// This is an alias for [KeyModifierOptions].
|
||||||
|
func ResetKeyModifierOptions(pp int) string {
|
||||||
|
return KeyModifierOptions(pp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryKeyModifierOptions (XTQMODKEYS) requests xterm key modifier options.
|
||||||
|
//
|
||||||
|
// Default is 0.
|
||||||
|
//
|
||||||
|
// CSI ? Pp m
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
|
func QueryKeyModifierOptions(pp int) string {
|
||||||
|
var p string
|
||||||
|
if pp > 0 {
|
||||||
|
p = strconv.Itoa(pp)
|
||||||
|
}
|
||||||
|
return "\x1b[?" + p + "m"
|
||||||
|
}
|
||||||
|
|
||||||
|
// XTQMODKEYS is an alias for [QueryKeyModifierOptions].
|
||||||
|
func XTQMODKEYS(pp int) string {
|
||||||
|
return QueryKeyModifierOptions(pp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify Other Keys (modifyOtherKeys) is an xterm feature that allows the
|
||||||
|
// terminal to modify the behavior of certain keys to send different escape
|
||||||
|
// sequences when pressed.
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
||||||
|
const (
|
||||||
|
SetModifyOtherKeys1 = "\x1b[>4;1m"
|
||||||
|
SetModifyOtherKeys2 = "\x1b[>4;2m"
|
||||||
|
ResetModifyOtherKeys = "\x1b[>4m"
|
||||||
|
QueryModifyOtherKeys = "\x1b[?4m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModifyOtherKeys returns a sequence that sets XTerm modifyOtherKeys mode.
|
||||||
|
// The mode argument specifies the mode to set.
|
||||||
|
//
|
||||||
|
// 0: Disable modifyOtherKeys mode.
|
||||||
|
// 1: Enable modifyOtherKeys mode 1.
|
||||||
|
// 2: Enable modifyOtherKeys mode 2.
|
||||||
|
//
|
||||||
|
// CSI > 4 ; mode m
|
||||||
|
//
|
||||||
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
||||||
|
// Deprecated: use [SetModifyOtherKeys1] or [SetModifyOtherKeys2] instead.
|
||||||
|
func ModifyOtherKeys(mode int) string {
|
||||||
|
return "\x1b[>4;" + strconv.Itoa(mode) + "m"
|
||||||
|
}
|
||||||
|
|
||||||
// DisableModifyOtherKeys disables the modifyOtherKeys mode.
|
// DisableModifyOtherKeys disables the modifyOtherKeys mode.
|
||||||
//
|
//
|
||||||
// CSI > 4 ; 0 m
|
// CSI > 4 ; 0 m
|
||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
||||||
|
// Deprecated: use [ResetModifyOtherKeys] instead.
|
||||||
const DisableModifyOtherKeys = "\x1b[>4;0m"
|
const DisableModifyOtherKeys = "\x1b[>4;0m"
|
||||||
|
|
||||||
// EnableModifyOtherKeys1 enables the modifyOtherKeys mode 1.
|
// EnableModifyOtherKeys1 enables the modifyOtherKeys mode 1.
|
||||||
@ -14,6 +111,7 @@ const DisableModifyOtherKeys = "\x1b[>4;0m"
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
||||||
|
// Deprecated: use [SetModifyOtherKeys1] instead.
|
||||||
const EnableModifyOtherKeys1 = "\x1b[>4;1m"
|
const EnableModifyOtherKeys1 = "\x1b[>4;1m"
|
||||||
|
|
||||||
// EnableModifyOtherKeys2 enables the modifyOtherKeys mode 2.
|
// EnableModifyOtherKeys2 enables the modifyOtherKeys mode 2.
|
||||||
@ -22,6 +120,7 @@ const EnableModifyOtherKeys1 = "\x1b[>4;1m"
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
||||||
|
// Deprecated: use [SetModifyOtherKeys2] instead.
|
||||||
const EnableModifyOtherKeys2 = "\x1b[>4;2m"
|
const EnableModifyOtherKeys2 = "\x1b[>4;2m"
|
||||||
|
|
||||||
// RequestModifyOtherKeys requests the modifyOtherKeys mode.
|
// RequestModifyOtherKeys requests the modifyOtherKeys mode.
|
||||||
@ -30,4 +129,5 @@ const EnableModifyOtherKeys2 = "\x1b[>4;2m"
|
|||||||
//
|
//
|
||||||
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Functions-using-CSI-_-ordered-by-the-final-character_s_
|
||||||
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
// See: https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyOtherKeys
|
||||||
|
// Deprecated: use [QueryModifyOtherKeys] instead.
|
||||||
const RequestModifyOtherKeys = "\x1b[?4m"
|
const RequestModifyOtherKeys = "\x1b[?4m"
|
||||||
|
2
vendor/github.com/cloudflare/circl/sign/ed448/ed448.go
generated
vendored
2
vendor/github.com/cloudflare/circl/sign/ed448/ed448.go
generated
vendored
@ -206,7 +206,7 @@ func newKeyFromSeed(privateKey, seed []byte) {
|
|||||||
|
|
||||||
func signAll(signature []byte, privateKey PrivateKey, message, ctx []byte, preHash bool) {
|
func signAll(signature []byte, privateKey PrivateKey, message, ctx []byte, preHash bool) {
|
||||||
if len(ctx) > ContextMaxSize {
|
if len(ctx) > ContextMaxSize {
|
||||||
panic(fmt.Errorf("ed448: bad context length: " + strconv.Itoa(len(ctx))))
|
panic(fmt.Errorf("ed448: bad context length: %v", len(ctx)))
|
||||||
}
|
}
|
||||||
|
|
||||||
H := sha3.NewShake256()
|
H := sha3.NewShake256()
|
||||||
|
3
vendor/github.com/cloudflare/circl/sign/sign.go
generated
vendored
3
vendor/github.com/cloudflare/circl/sign/sign.go
generated
vendored
@ -107,4 +107,7 @@ var (
|
|||||||
// ErrContextNotSupported is the error used if a context is not
|
// ErrContextNotSupported is the error used if a context is not
|
||||||
// supported.
|
// supported.
|
||||||
ErrContextNotSupported = errors.New("context not supported")
|
ErrContextNotSupported = errors.New("context not supported")
|
||||||
|
|
||||||
|
// ErrContextTooLong is the error used if the context string is too long.
|
||||||
|
ErrContextTooLong = errors.New("context string too long")
|
||||||
)
|
)
|
||||||
|
16
vendor/github.com/containerd/containerd/NOTICE
generated
vendored
16
vendor/github.com/containerd/containerd/NOTICE
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
Docker
|
|
||||||
Copyright 2012-2015 Docker, Inc.
|
|
||||||
|
|
||||||
This product includes software developed at Docker, Inc. (https://www.docker.com).
|
|
||||||
|
|
||||||
The following is courtesy of our legal counsel:
|
|
||||||
|
|
||||||
|
|
||||||
Use and transfer of Docker may be subject to certain restrictions by the
|
|
||||||
United States and other governments.
|
|
||||||
It is your responsibility to ensure that your use and/or transfer does not
|
|
||||||
violate applicable laws.
|
|
||||||
|
|
||||||
For more information, please see https://www.bis.doc.gov
|
|
||||||
|
|
||||||
See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.
|
|
62
vendor/github.com/containerd/containerd/pkg/userns/userns_linux.go
generated
vendored
62
vendor/github.com/containerd/containerd/pkg/userns/userns_linux.go
generated
vendored
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package userns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
inUserNS bool
|
|
||||||
nsOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
// RunningInUserNS detects whether we are currently running in a user namespace.
|
|
||||||
// Originally copied from github.com/lxc/lxd/shared/util.go
|
|
||||||
func RunningInUserNS() bool {
|
|
||||||
nsOnce.Do(func() {
|
|
||||||
file, err := os.Open("/proc/self/uid_map")
|
|
||||||
if err != nil {
|
|
||||||
// This kernel-provided file only exists if user namespaces are supported
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
buf := bufio.NewReader(file)
|
|
||||||
l, _, err := buf.ReadLine()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
line := string(l)
|
|
||||||
var a, b, c int64
|
|
||||||
fmt.Sscanf(line, "%d %d %d", &a, &b, &c)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We assume we are in the initial user namespace if we have a full
|
|
||||||
* range - 4294967295 uids starting at uid 0.
|
|
||||||
*/
|
|
||||||
if a == 0 && b == 0 && c == 4294967295 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inUserNS = true
|
|
||||||
})
|
|
||||||
return inUserNS
|
|
||||||
}
|
|
25
vendor/github.com/containerd/containerd/pkg/userns/userns_unsupported.go
generated
vendored
25
vendor/github.com/containerd/containerd/pkg/userns/userns_unsupported.go
generated
vendored
@ -1,25 +0,0 @@
|
|||||||
//go:build !linux
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package userns
|
|
||||||
|
|
||||||
// RunningInUserNS is a stub for non-Linux systems
|
|
||||||
// Always returns false
|
|
||||||
func RunningInUserNS() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
178
vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
generated
vendored
Normal file
178
vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# Changelog #
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [Unreleased] ##
|
||||||
|
|
||||||
|
## [0.3.4] - 2024-10-09 ##
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Previously, some testing mocks we had resulted in us doing `import "testing"`
|
||||||
|
in non-`_test.go` code, which made some downstreams like Kubernetes unhappy.
|
||||||
|
This has been fixed. (#32)
|
||||||
|
|
||||||
|
## [0.3.3] - 2024-09-30 ##
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- The mode and owner verification logic in `MkdirAll` has been removed. This
|
||||||
|
was originally intended to protect against some theoretical attacks but upon
|
||||||
|
further consideration these protections don't actually buy us anything and
|
||||||
|
they were causing spurious errors with more complicated filesystem setups.
|
||||||
|
- The "is the created directory empty" logic in `MkdirAll` has also been
|
||||||
|
removed. This was not causing us issues yet, but some pseudofilesystems (such
|
||||||
|
as `cgroup`) create non-empty directories and so this logic would've been
|
||||||
|
wrong for such cases.
|
||||||
|
|
||||||
|
## [0.3.2] - 2024-09-13 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Passing the `S_ISUID` or `S_ISGID` modes to `MkdirAllInRoot` will now return
|
||||||
|
an explicit error saying that those bits are ignored by `mkdirat(2)`. In the
|
||||||
|
past a different error was returned, but since the silent ignoring behaviour
|
||||||
|
is codified in the man pages a more explicit error seems apt. While silently
|
||||||
|
ignoring these bits would be the most compatible option, it could lead to
|
||||||
|
users thinking their code sets these bits when it doesn't. Programs that need
|
||||||
|
to deal with compatibility can mask the bits themselves. (#23, #25)
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- If a directory has `S_ISGID` set, then all child directories will have
|
||||||
|
`S_ISGID` set when created and a different gid will be used for any inode
|
||||||
|
created under the directory. Previously, the "expected owner and mode"
|
||||||
|
validation in `securejoin.MkdirAll` did not correctly handle this. We now
|
||||||
|
correctly handle this case. (#24, #25)
|
||||||
|
|
||||||
|
## [0.3.1] - 2024-07-23 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- By allowing `Open(at)InRoot` to opt-out of the extra work done by `MkdirAll`
|
||||||
|
to do the necessary "partial lookups", `Open(at)InRoot` now does less work
|
||||||
|
for both implementations (resulting in a many-fold decrease in the number of
|
||||||
|
operations for `openat2`, and a modest improvement for non-`openat2`) and is
|
||||||
|
far more guaranteed to match the correct `openat2(RESOLVE_IN_ROOT)`
|
||||||
|
behaviour.
|
||||||
|
- We now use `readlinkat(fd, "")` where possible. For `Open(at)InRoot` this
|
||||||
|
effectively just means that we no longer risk getting spurious errors during
|
||||||
|
rename races. However, for our hardened procfs handler, this in theory should
|
||||||
|
prevent mount attacks from tricking us when doing magic-link readlinks (even
|
||||||
|
when using the unsafe host `/proc` handle). Unfortunately `Reopen` is still
|
||||||
|
potentially vulnerable to those kinds of somewhat-esoteric attacks.
|
||||||
|
|
||||||
|
Technically this [will only work on post-2.6.39 kernels][linux-readlinkat-emptypath]
|
||||||
|
but it seems incredibly unlikely anyone is using `filepath-securejoin` on a
|
||||||
|
pre-2011 kernel.
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Several improvements were made to the errors returned by `Open(at)InRoot` and
|
||||||
|
`MkdirAll` when dealing with invalid paths under the emulated (ie.
|
||||||
|
non-`openat2`) implementation. Previously, some paths would return the wrong
|
||||||
|
error (`ENOENT` when the last component was a non-directory), and other paths
|
||||||
|
would be returned as though they were acceptable (trailing-slash components
|
||||||
|
after a non-directory would be ignored by `Open(at)InRoot`).
|
||||||
|
|
||||||
|
These changes were done to match `openat2`'s behaviour and purely is a
|
||||||
|
consistency fix (most users are going to be using `openat2` anyway).
|
||||||
|
|
||||||
|
[linux-readlinkat-emptypath]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65cfc6722361570bfe255698d9cd4dccaf47570d
|
||||||
|
|
||||||
|
## [0.3.0] - 2024-07-11 ##
|
||||||
|
|
||||||
|
### Added ###
|
||||||
|
- A new set of `*os.File`-based APIs have been added. These are adapted from
|
||||||
|
[libpathrs][] and we strongly suggest using them if possible (as they provide
|
||||||
|
far more protection against attacks than `SecureJoin`):
|
||||||
|
|
||||||
|
- `Open(at)InRoot` resolves a path inside a rootfs and returns an `*os.File`
|
||||||
|
handle to the path. Note that the handle returned is an `O_PATH` handle,
|
||||||
|
which cannot be used for reading or writing (as well as some other
|
||||||
|
operations -- [see open(2) for more details][open.2])
|
||||||
|
|
||||||
|
- `Reopen` takes an `O_PATH` file handle and safely re-opens it to upgrade
|
||||||
|
it to a regular handle. This can also be used with non-`O_PATH` handles,
|
||||||
|
but `O_PATH` is the most obvious application.
|
||||||
|
|
||||||
|
- `MkdirAll` is an implementation of `os.MkdirAll` that is safe to use to
|
||||||
|
create a directory tree within a rootfs.
|
||||||
|
|
||||||
|
As these are new APIs, they may change in the future. However, they should be
|
||||||
|
safe to start migrating to as we have extensive tests ensuring they behave
|
||||||
|
correctly and are safe against various races and other attacks.
|
||||||
|
|
||||||
|
[libpathrs]: https://github.com/openSUSE/libpathrs
|
||||||
|
[open.2]: https://www.man7.org/linux/man-pages/man2/open.2.html
|
||||||
|
|
||||||
|
## [0.2.5] - 2024-05-03 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Some minor changes were made to how lexical components (like `..` and `.`)
|
||||||
|
are handled during path generation in `SecureJoin`. There is no behaviour
|
||||||
|
change as a result of this fix (the resulting paths are the same).
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- The error returned when we hit a symlink loop now references the correct
|
||||||
|
path. (#10)
|
||||||
|
|
||||||
|
## [0.2.4] - 2023-09-06 ##
|
||||||
|
|
||||||
|
### Security ###
|
||||||
|
- This release fixes a potential security issue in filepath-securejoin when
|
||||||
|
used on Windows ([GHSA-6xv5-86q9-7xr8][], which could be used to generate
|
||||||
|
paths outside of the provided rootfs in certain cases), as well as improving
|
||||||
|
the overall behaviour of filepath-securejoin when dealing with Windows paths
|
||||||
|
that contain volume names. Thanks to Paulo Gomes for discovering and fixing
|
||||||
|
these issues.
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Switch to GitHub Actions for CI so we can test on Windows as well as Linux
|
||||||
|
and MacOS.
|
||||||
|
|
||||||
|
[GHSA-6xv5-86q9-7xr8]: https://github.com/advisories/GHSA-6xv5-86q9-7xr8
|
||||||
|
|
||||||
|
## [0.2.3] - 2021-06-04 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Switch to Go 1.13-style `%w` error wrapping, letting us drop the dependency
|
||||||
|
on `github.com/pkg/errors`.
|
||||||
|
|
||||||
|
## [0.2.2] - 2018-09-05 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Use `syscall.ELOOP` as the base error for symlink loops, rather than our own
|
||||||
|
(internal) error. This allows callers to more easily use `errors.Is` to check
|
||||||
|
for this case.
|
||||||
|
|
||||||
|
## [0.2.1] - 2018-09-05 ##
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Use our own `IsNotExist` implementation, which lets us handle `ENOTDIR`
|
||||||
|
properly within `SecureJoin`.
|
||||||
|
|
||||||
|
## [0.2.0] - 2017-07-19 ##
|
||||||
|
|
||||||
|
We now have 100% test coverage!
|
||||||
|
|
||||||
|
### Added ###
|
||||||
|
- Add a `SecureJoinVFS` API that can be used for mocking (as we do in our new
|
||||||
|
tests) or for implementing custom handling of lookup operations (such as for
|
||||||
|
rootless containers, where work is necessary to access directories with weird
|
||||||
|
modes because we don't have `CAP_DAC_READ_SEARCH` or `CAP_DAC_OVERRIDE`).
|
||||||
|
|
||||||
|
## 0.1.0 - 2017-07-19
|
||||||
|
|
||||||
|
This is our first release of `github.com/cyphar/filepath-securejoin`,
|
||||||
|
containing a full implementation with a coverage of 93.5% (the only missing
|
||||||
|
cases are the error cases, which are hard to mocktest at the moment).
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.4...HEAD
|
||||||
|
[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...v0.3.4
|
||||||
|
[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.2...v0.3.3
|
||||||
|
[0.3.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...v0.3.2
|
||||||
|
[0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1
|
||||||
|
[0.3.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.5...v0.3.0
|
||||||
|
[0.2.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.4...v0.2.5
|
||||||
|
[0.2.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.3...v0.2.4
|
||||||
|
[0.2.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.2...v0.2.3
|
||||||
|
[0.2.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.1...v0.2.2
|
||||||
|
[0.2.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.0...v0.2.1
|
||||||
|
[0.2.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.1.0...v0.2.0
|
2
vendor/github.com/cyphar/filepath-securejoin/LICENSE
generated
vendored
2
vendor/github.com/cyphar/filepath-securejoin/LICENSE
generated
vendored
@ -1,5 +1,5 @@
|
|||||||
Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
|
Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
|
||||||
Copyright (C) 2017 SUSE LLC. All rights reserved.
|
Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
136
vendor/github.com/cyphar/filepath-securejoin/README.md
generated
vendored
136
vendor/github.com/cyphar/filepath-securejoin/README.md
generated
vendored
@ -1,32 +1,26 @@
|
|||||||
## `filepath-securejoin` ##
|
## `filepath-securejoin` ##
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/github.com/cyphar/filepath-securejoin)
|
||||||
[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
|
[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
|
||||||
|
|
||||||
An implementation of `SecureJoin`, a [candidate for inclusion in the Go
|
### Old API ###
|
||||||
standard library][go#20126]. The purpose of this function is to be a "secure"
|
|
||||||
alternative to `filepath.Join`, and in particular it provides certain
|
|
||||||
guarantees that are not provided by `filepath.Join`.
|
|
||||||
|
|
||||||
> **NOTE**: This code is *only* safe if you are not at risk of other processes
|
This library was originally just an implementation of `SecureJoin` which was
|
||||||
> modifying path components after you've used `SecureJoin`. If it is possible
|
[intended to be included in the Go standard library][go#20126] as a safer
|
||||||
> for a malicious process to modify path components of the resolved path, then
|
`filepath.Join` that would restrict the path lookup to be inside a root
|
||||||
> you will be vulnerable to some fairly trivial TOCTOU race conditions. [There
|
directory.
|
||||||
> are some Linux kernel patches I'm working on which might allow for a better
|
|
||||||
> solution.][lwn-obeneath]
|
|
||||||
>
|
|
||||||
> In addition, with a slightly modified API it might be possible to use
|
|
||||||
> `O_PATH` and verify that the opened path is actually the resolved one -- but
|
|
||||||
> I have not done that yet. I might add it in the future as a helper function
|
|
||||||
> to help users verify the path (we can't just return `/proc/self/fd/<foo>`
|
|
||||||
> because that doesn't always work transparently for all users).
|
|
||||||
|
|
||||||
This is the function prototype:
|
The implementation was based on code that existed in several container
|
||||||
|
runtimes. Unfortunately, this API is **fundamentally unsafe** against attackers
|
||||||
|
that can modify path components after `SecureJoin` returns and before the
|
||||||
|
caller uses the path, allowing for some fairly trivial TOCTOU attacks.
|
||||||
|
|
||||||
```go
|
`SecureJoin` (and `SecureJoinVFS`) are still provided by this library to
|
||||||
func SecureJoin(root, unsafePath string) (string, error)
|
support legacy users, but new users are strongly suggested to avoid using
|
||||||
```
|
`SecureJoin` and instead use the [new api](#new-api) or switch to
|
||||||
|
[libpathrs][libpathrs].
|
||||||
|
|
||||||
This library **guarantees** the following:
|
With the above limitations in mind, this library guarantees the following:
|
||||||
|
|
||||||
* If no error is set, the resulting string **must** be a child path of
|
* If no error is set, the resulting string **must** be a child path of
|
||||||
`root` and will not contain any symlink path components (they will all be
|
`root` and will not contain any symlink path components (they will all be
|
||||||
@ -47,7 +41,7 @@ This library **guarantees** the following:
|
|||||||
A (trivial) implementation of this function on GNU/Linux systems could be done
|
A (trivial) implementation of this function on GNU/Linux systems could be done
|
||||||
with the following (note that this requires root privileges and is far more
|
with the following (note that this requires root privileges and is far more
|
||||||
opaque than the implementation in this library, and also requires that
|
opaque than the implementation in this library, and also requires that
|
||||||
`readlink` is inside the `root` path):
|
`readlink` is inside the `root` path and is trustworthy):
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package securejoin
|
package securejoin
|
||||||
@ -70,9 +64,105 @@ func SecureJoin(root, unsafePath string) (string, error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[lwn-obeneath]: https://lwn.net/Articles/767547/
|
[libpathrs]: https://github.com/openSUSE/libpathrs
|
||||||
[go#20126]: https://github.com/golang/go/issues/20126
|
[go#20126]: https://github.com/golang/go/issues/20126
|
||||||
|
|
||||||
|
### New API ###
|
||||||
|
|
||||||
|
While we recommend users switch to [libpathrs][libpathrs] as soon as it has a
|
||||||
|
stable release, some methods implemented by libpathrs have been ported to this
|
||||||
|
library to ease the transition. These APIs are only supported on Linux.
|
||||||
|
|
||||||
|
These APIs are implemented such that `filepath-securejoin` will
|
||||||
|
opportunistically use certain newer kernel APIs that make these operations far
|
||||||
|
more secure. In particular:
|
||||||
|
|
||||||
|
* All of the lookup operations will use [`openat2`][openat2.2] on new enough
|
||||||
|
kernels (Linux 5.6 or later) to restrict lookups through magic-links and
|
||||||
|
bind-mounts (for certain operations) and to make use of `RESOLVE_IN_ROOT` to
|
||||||
|
efficiently resolve symlinks within a rootfs.
|
||||||
|
|
||||||
|
* The APIs provide hardening against a malicious `/proc` mount to either detect
|
||||||
|
or avoid being tricked by a `/proc` that is not legitimate. This is done
|
||||||
|
using [`openat2`][openat2.2] for all users, and privileged users will also be
|
||||||
|
further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2]
|
||||||
|
(Linux 5.2 or later).
|
||||||
|
|
||||||
|
[openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html
|
||||||
|
[fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md
|
||||||
|
[open_tree.2]: https://github.com/brauner/man-pages-md/blob/main/open_tree.md
|
||||||
|
|
||||||
|
#### `OpenInRoot` ####
|
||||||
|
|
||||||
|
```go
|
||||||
|
func OpenInRoot(root, unsafePath string) (*os.File, error)
|
||||||
|
func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error)
|
||||||
|
func Reopen(handle *os.File, flags int) (*os.File, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
`OpenInRoot` is a much safer version of
|
||||||
|
|
||||||
|
```go
|
||||||
|
path, err := securejoin.SecureJoin(root, unsafePath)
|
||||||
|
file, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC)
|
||||||
|
```
|
||||||
|
|
||||||
|
that protects against various race attacks that could lead to serious security
|
||||||
|
issues, depending on the application. Note that the returned `*os.File` is an
|
||||||
|
`O_PATH` file descriptor, which is quite restricted. Callers will probably need
|
||||||
|
to use `Reopen` to get a more usable handle (this split is done to provide
|
||||||
|
useful features like PTY spawning and to avoid users accidentally opening bad
|
||||||
|
inodes that could cause a DoS).
|
||||||
|
|
||||||
|
Callers need to be careful in how they use the returned `*os.File`. Usually it
|
||||||
|
is only safe to operate on the handle directly, and it is very easy to create a
|
||||||
|
security issue. [libpathrs][libpathrs] provides far more helpers to make using
|
||||||
|
these handles safer -- there is currently no plan to port them to
|
||||||
|
`filepath-securejoin`.
|
||||||
|
|
||||||
|
`OpenatInRoot` is like `OpenInRoot` except that the root is provided using an
|
||||||
|
`*os.File`. This allows you to ensure that multiple `OpenatInRoot` (or
|
||||||
|
`MkdirAllHandle`) calls are operating on the same rootfs.
|
||||||
|
|
||||||
|
> **NOTE**: Unlike `SecureJoin`, `OpenInRoot` will error out as soon as it hits
|
||||||
|
> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
|
||||||
|
> which treated non-existent components as though they were real directories,
|
||||||
|
> and would allow for partial resolution of dangling symlinks. These behaviours
|
||||||
|
> are at odds with how Linux treats non-existent paths and dangling symlinks,
|
||||||
|
> and so these are no longer allowed.
|
||||||
|
|
||||||
|
#### `MkdirAll` ####
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MkdirAll(root, unsafePath string, mode int) error
|
||||||
|
func MkdirAllHandle(root *os.File, unsafePath string, mode int) (*os.File, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
`MkdirAll` is a much safer version of
|
||||||
|
|
||||||
|
```go
|
||||||
|
path, err := securejoin.SecureJoin(root, unsafePath)
|
||||||
|
err = os.MkdirAll(path, mode)
|
||||||
|
```
|
||||||
|
|
||||||
|
that protects against the same kinds of races that `OpenInRoot` protects
|
||||||
|
against.
|
||||||
|
|
||||||
|
`MkdirAllHandle` is like `MkdirAll` except that the root is provided using an
|
||||||
|
`*os.File` (the reason for this is the same as with `OpenatInRoot`) and an
|
||||||
|
`*os.File` of the final created directory is returned (this directory is
|
||||||
|
guaranteed to be effectively identical to the directory created by
|
||||||
|
`MkdirAllHandle`, which is not possible to ensure by just using `OpenatInRoot`
|
||||||
|
after `MkdirAll`).
|
||||||
|
|
||||||
|
> **NOTE**: Unlike `SecureJoin`, `MkdirAll` will error out as soon as it hits
|
||||||
|
> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
|
||||||
|
> which treated non-existent components as though they were real directories,
|
||||||
|
> and would allow for partial resolution of dangling symlinks. These behaviours
|
||||||
|
> are at odds with how Linux treats non-existent paths and dangling symlinks,
|
||||||
|
> and so these are no longer allowed. This means that `MkdirAll` will not
|
||||||
|
> create non-existent directories referenced by a dangling symlink.
|
||||||
|
|
||||||
### License ###
|
### License ###
|
||||||
|
|
||||||
The license of this project is the same as Go, which is a BSD 3-clause license
|
The license of this project is the same as Go, which is a BSD 3-clause license
|
||||||
|
2
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
2
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
@ -1 +1 @@
|
|||||||
0.2.5
|
0.3.4
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user