Go: Bump github.com/securego/gosec/v2 from 2.15.0 to 2.17.0 (#7033)

* Go: Bump github.com/securego/gosec/v2 from 2.15.0 to 2.17.0

Bumps [github.com/securego/gosec/v2](https://github.com/securego/gosec) from 2.15.0 to 2.17.0.
- [Release notes](https://github.com/securego/gosec/releases)
- [Changelog](https://github.com/securego/gosec/blob/master/.goreleaser.yml)
- [Commits](https://github.com/securego/gosec/compare/v2.15.0...v2.17.0)

---
updated-dependencies:
- dependency-name: github.com/securego/gosec/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Go: Bump github.com/securego/gosec/v2 from 2.15.0 to 2.17.0

Bumps [github.com/securego/gosec/v2](https://github.com/securego/gosec) from 2.15.0 to 2.17.0.
- [Release notes](https://github.com/securego/gosec/releases)
- [Changelog](https://github.com/securego/gosec/blob/master/.goreleaser.yml)
- [Commits](https://github.com/securego/gosec/compare/v2.15.0...v2.17.0)

---
updated-dependencies:
- dependency-name: github.com/securego/gosec/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Ignore gosec error

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Philippe Martin <phmartin@redhat.com>
This commit is contained in:
dependabot[bot]
2023-08-28 15:18:08 +02:00
committed by GitHub
parent 5a3c33d8ce
commit 319adfa724
228 changed files with 41448 additions and 5330 deletions

22
go.mod
View File

@@ -31,7 +31,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.11.0
github.com/onsi/gomega v1.27.8
github.com/onsi/gomega v1.27.10
github.com/openshift/api v0.0.0-20220525145417-ee5b62754c68
github.com/openshift/client-go v0.0.0-20220603133046-984ee5ebedcf
github.com/openshift/oc v0.0.0-alpha.0.0.20220402064836-f1f09a392fd1
@@ -41,7 +41,7 @@ require (
github.com/posener/complete v1.2.3
github.com/redhat-developer/service-binding-operator v1.0.1-0.20211222115357-5b7bbba3bfb3
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/securego/gosec/v2 v2.15.0
github.com/securego/gosec/v2 v2.17.0
github.com/segmentio/backo-go v1.0.1
github.com/sethvargo/go-envconfig v0.9.0
github.com/spf13/afero v1.6.0
@@ -50,9 +50,9 @@ require (
github.com/tidwall/gjson v1.14.4
github.com/zalando/go-keyring v0.2.3
golang.org/x/sync v0.3.0
golang.org/x/sys v0.10.0
golang.org/x/term v0.9.0
golang.org/x/text v0.10.0
golang.org/x/sys v0.11.0
golang.org/x/term v0.11.0
golang.org/x/text v0.12.0
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gopkg.in/segmentio/analytics-go.v3 v3.0.0-00010101000000-000000000000
gopkg.in/yaml.v2 v2.4.0
@@ -87,6 +87,7 @@ require (
github.com/apcera/gssapi v0.0.0-00010101000000-000000000000 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/ccojocar/zxcvbn-go v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
@@ -128,7 +129,7 @@ require (
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gookit/color v1.5.2 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -161,7 +162,6 @@ require (
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
github.com/openshift/library-go v0.0.0-20220210170159-18f172cff934 // indirect
@@ -191,12 +191,12 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.10.0 // indirect
golang.org/x/tools v0.12.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220706185917-7780775163c4 // indirect

45
go.sum generated
View File

@@ -184,6 +184,8 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4=
github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -684,8 +686,8 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
@@ -925,8 +927,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
@@ -980,8 +980,8 @@ github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
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 v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -1124,8 +1124,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/securego/gosec/v2 v2.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgIAtw=
github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8=
github.com/securego/gosec/v2 v2.17.0 h1:ZpAStTDKY39insEG9OH6kV3IkhQZPTq9a9eGOLOjcdI=
github.com/securego/gosec/v2 v2.17.0/go.mod h1:lt+mgC91VSmriVoJLentrMkRCYs+HLTBnUFUBuhV2hc=
github.com/segmentio/analytics-go/v3 v3.2.1 h1:G+f90zxtc1p9G+WigVyTR0xNfOghOGs/PYAlljLOyeg=
github.com/segmentio/analytics-go/v3 v3.2.1/go.mod h1:p8owAF8X+5o27jmvUognuXxdtqvSGtD0ZrfY2kcS9bE=
github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4=
@@ -1199,7 +1199,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -1382,8 +1381,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1423,8 +1422,8 @@ golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1494,8 +1493,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
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.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1657,8 +1656,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1667,8 +1666,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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=
@@ -1683,8 +1682,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1768,8 +1767,8 @@ golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -145,6 +145,8 @@ func getDefaultCommand(devfileObj parser.DevfileObj, groupType v1alpha2.CommandG
if len(defaultCmds) > 1 {
return v1alpha2.Command{}, false, NewMoreThanOneDefaultCommandFoundError(groupType)
}
// #nosec
// gosec:G602 -> This is safe since we checked the length before
return defaultCmds[0], true, nil
}

5
vendor/github.com/ccojocar/zxcvbn-go/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
zxcvbn
debug.test
# SBOMs generated during CI
/bom.json

39
vendor/github.com/ccojocar/zxcvbn-go/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,39 @@
linters:
enable:
- asciicheck
- bodyclose
- dogsled
- durationcheck
- errcheck
- errorlint
- exportloopref
- gci
- ginkgolinter
- gofmt
- gofumpt
- goimports
- gosimple
- govet
- importas
- ineffassign
- megacheck
- misspell
- nakedret
- nolintlint
- revive
- staticcheck
- typecheck
- unconvert
- unparam
- unused
- wastedassign
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/ccojocar)
run:
timeout: 5m

27
vendor/github.com/ccojocar/zxcvbn-go/.goreleaser.yml generated vendored Normal file
View File

@@ -0,0 +1,27 @@
---
project_name: zxcvbn-go
release:
extra_files:
- glob: ./bom.json
github:
owner: ccojocar
name: zxcvbn-go
builds:
- main: ./testapp/
binary: zxcvbn-go
goos:
- darwin
- linux
- windows
goarch:
- amd64
- arm64
- s390x
ldflags: -X main.Version={{.Version}} -X main.GitTag={{.Tag}} -X main.BuildDate={{.Date}}
env:
- CGO_ENABLED=0
gomod:
proxy: true

61
vendor/github.com/ccojocar/zxcvbn-go/Makefile generated vendored Normal file
View File

@@ -0,0 +1,61 @@
GIT_TAG?= $(shell git describe --always --tags)
BIN = zxcvbn-go
FMT_CMD = $(gofmt -s -l -w $(find . -type f -name '*.go' -not -path './vendor/*') | tee /dev/stderr)
IMAGE_REPO = ccojocar
DATE_FMT=+%Y-%m-%d
ifdef SOURCE_DATE_EPOCH
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)")
else
BUILD_DATE ?= $(shell date "$(DATE_FMT)")
endif
BUILDFLAGS := "-w -s -X 'main.Version=$(GIT_TAG)' -X 'main.GitTag=$(GIT_TAG)' -X 'main.BuildDate=$(BUILD_DATE)'"
CGO_ENABLED = 0
GO := GO111MODULE=on go
GO_NOMOD :=GO111MODULE=off go
GOPATH ?= $(shell $(GO) env GOPATH)
GOBIN ?= $(GOPATH)/bin
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
GOVULN_MIN_VERSION = 17
GO_VERSION = 1.20
default:
$(MAKE) test
install-govulncheck:
@if [ $(GO_MINOR_VERSION) -gt $(GOVULN_MIN_VERSION) ]; then \
go install golang.org/x/vuln/cmd/govulncheck@latest; \
fi
test-all: fmt vet lint sec govulncheck test
test:
go test -v ./...
fmt:
@echo "FORMATTING"
@FORMATTED=`$(GO) fmt ./...`
@([ ! -z "$(FORMATTED)" ] && printf "Fixed unformatted files:\n$(FORMATTED)") || true
vet:
@echo "VETTING"
$(GO) vet ./...
lint:
@echo "LINTING: golangci-lint"
golangci-lint run
sec:
@echo "SECURITY SCANNING"
gosec ./...
govulncheck: install-govulncheck
@echo "CHECKING VULNERABILITIES"
@if [ $(GO_MINOR_VERSION) -gt $(GOVULN_MIN_VERSION) ]; then \
govulncheck ./...; \
fi
clean:
rm -rf build vendor dist coverage.txt
rm -f release image $(BIN)
.PHONY: test test-all fmt vet govulncheck clean

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"log"
"github.com/nbutton23/zxcvbn-go/data"
"github.com/ccojocar/zxcvbn-go/data"
)
// Graph holds information about different graphs
@@ -25,7 +25,7 @@ func init() {
GraphMap["l33t"] = BuildLeet()
}
//BuildQwerty builds the Qwerty Graph
// BuildQwerty builds the Qwerty Graph
func BuildQwerty() Graph {
data, err := data.Asset("data/Qwerty.json")
if err != nil {
@@ -34,7 +34,7 @@ func BuildQwerty() Graph {
return getAdjancencyGraphFromFile(data, "qwerty")
}
//BuildDvorak builds the Dvorak Graph
// BuildDvorak builds the Dvorak Graph
func BuildDvorak() Graph {
data, err := data.Asset("data/Dvorak.json")
if err != nil {
@@ -43,7 +43,7 @@ func BuildDvorak() Graph {
return getAdjancencyGraphFromFile(data, "dvorak")
}
//BuildKeypad builds the Keypad Graph
// BuildKeypad builds the Keypad Graph
func BuildKeypad() Graph {
data, err := data.Asset("data/Keypad.json")
if err != nil {
@@ -52,7 +52,7 @@ func BuildKeypad() Graph {
return getAdjancencyGraphFromFile(data, "keypad")
}
//BuildMacKeypad builds the Mac Keypad Graph
// BuildMacKeypad builds the Mac Keypad Graph
func BuildMacKeypad() Graph {
data, err := data.Asset("data/MacKeypad.json")
if err != nil {
@@ -61,7 +61,7 @@ func BuildMacKeypad() Graph {
return getAdjancencyGraphFromFile(data, "mac_keypad")
}
//BuildLeet builds the L33T Graph
// BuildLeet builds the L33T Graph
func BuildLeet() Graph {
data, err := data.Asset("data/L33t.json")
if err != nil {
@@ -71,7 +71,6 @@ func BuildLeet() Graph {
}
func getAdjancencyGraphFromFile(data []byte, name string) Graph {
var graph Graph
err := json.Unmarshal(data, &graph)
if err != nil {
@@ -82,9 +81,9 @@ func getAdjancencyGraphFromFile(data []byte, name string) Graph {
}
// CalculateAvgDegree calclates the average degree between nodes in the graph
//on qwerty, 'g' has degree 6, being adjacent to 'ftyhbv'. '\' has degree 1.
//this calculates the average over all keys.
//TODO double check that i ported this correctly scoring.coffee ln 5
// on qwerty, 'g' has degree 6, being adjacent to 'ftyhbv'. '\' has degree 1.
// this calculates the average over all keys.
// TODO double check that i ported this correctly scoring.coffee ln 5
func (adjGrp Graph) CalculateAvgDegree() float64 {
if adjGrp.averageDegree != float64(0) {
return adjGrp.averageDegree
@@ -92,14 +91,12 @@ func (adjGrp Graph) CalculateAvgDegree() float64 {
var avg float64
var count float64
for _, value := range adjGrp.Graph {
for _, char := range value {
if len(char) != 0 || char != " " {
avg += float64(len(char))
count++
}
}
}
adjGrp.averageDegree = avg / count

View File

@@ -33,7 +33,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
_, err = io.Copy(&buf, gz) // #nosec
clErr := gz.Close()
if err != nil {
@@ -345,11 +345,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error

View File

@@ -1,12 +1,13 @@
package entropy
import (
"github.com/nbutton23/zxcvbn-go/adjacency"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/nbutton23/zxcvbn-go/utils/math"
"math"
"regexp"
"unicode"
"github.com/ccojocar/zxcvbn-go/adjacency"
"github.com/ccojocar/zxcvbn-go/match"
zxcvbnmath "github.com/ccojocar/zxcvbn-go/utils/math"
)
const (
@@ -27,7 +28,7 @@ var (
func DictionaryEntropy(match match.Match, rank float64) float64 {
baseEntropy := math.Log2(rank)
upperCaseEntropy := extraUpperCaseEntropy(match)
//TODO: L33t
// TODO: L33t
return baseEntropy + upperCaseEntropy
}
@@ -46,18 +47,18 @@ func extraUpperCaseEntropy(match match.Match) float64 {
return float64(0)
}
//a capitalized word is the most common capitalization scheme,
//so it only doubles the search space (uncapitalized + capitalized): 1 extra bit of entropy.
//allcaps and end-capitalized are common enough too, underestimate as 1 extra bit to be safe.
// a capitalized word is the most common capitalization scheme,
// so it only doubles the search space (uncapitalized + capitalized): 1 extra bit of entropy.
// allcaps and end-capitalized are common enough too, underestimate as 1 extra bit to be safe.
for _, matcher := range []*regexp.Regexp{startUpperRx, endUpperRx, allUpperRx} {
if matcher.MatchString(word) {
return float64(1)
}
}
//Otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters with U uppercase letters or
//less. Or, if there's more uppercase than lower (for e.g. PASSwORD), the number of ways to lowercase U+L letters
//with L lowercase letters or less.
// Otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters with U uppercase letters or
// less. Or, if there's more uppercase than lower (for e.g. PASSwORD), the number of ways to lowercase U+L letters
// with L lowercase letters or less.
countUpper, countLower := float64(0), float64(0)
for _, char := range word {
@@ -71,21 +72,21 @@ func extraUpperCaseEntropy(match match.Match) float64 {
var possibililities float64
for i := float64(0); i <= math.Min(countUpper, countLower); i++ {
possibililities += float64(zxcvbnmath.NChoseK(totalLenght, i))
possibililities += zxcvbnmath.NChoseK(totalLenght, i)
}
if possibililities < 1 {
return float64(1)
}
return float64(math.Log2(possibililities))
return (math.Log2(possibililities))
}
// SpatialEntropy calculates the entropy for spatial matches
func SpatialEntropy(match match.Match, turns int, shiftCount int) float64 {
var s, d float64
if match.DictionaryName == "qwerty" || match.DictionaryName == "dvorak" {
//todo: verify qwerty and dvorak have the same length and degree
// todo: verify qwerty and dvorak have the same length and degree
s = float64(len(adjacency.BuildQwerty().Graph))
d = adjacency.BuildQwerty().CalculateAvgDegree()
} else {
@@ -97,8 +98,8 @@ func SpatialEntropy(match match.Match, turns int, shiftCount int) float64 {
length := float64(len(match.Token))
//TODO: Should this be <= or just < ?
//Estimate the number of possible patterns w/ length L or less with t turns or less
// TODO: Should this be <= or just < ?
// Estimate the number of possible patterns w/ length L or less with t turns or less
for i := float64(2); i <= length+1; i++ {
possibleTurns := math.Min(float64(turns), i-1)
for j := float64(1); j <= possibleTurns+1; j++ {
@@ -108,8 +109,8 @@ func SpatialEntropy(match match.Match, turns int, shiftCount int) float64 {
}
entropy := math.Log2(possibilities)
//add extra entropu for shifted keys. ( % instead of 5 A instead of a)
//Math is similar to extra entropy for uppercase letters in dictionary matches.
// add extra entropu for shifted keys. ( % instead of 5 A instead of a)
// Math is similar to extra entropy for uppercase letters in dictionary matches.
if S := float64(shiftCount); S > float64(0) {
possibilities = float64(0)
@@ -134,7 +135,7 @@ func RepeatEntropy(match match.Match) float64 {
}
// CalcBruteForceCardinality calculates the brute force cardinality
//TODO: Validate against python
// TODO: Validate against python
func CalcBruteForceCardinality(password string) float64 {
lower, upper, digits, symbols := float64(0), float64(0), float64(0), float64(0)
@@ -157,12 +158,12 @@ func CalcBruteForceCardinality(password string) float64 {
// SequenceEntropy calculates the entropy for sequences such as 4567 or cdef
func SequenceEntropy(match match.Match, dictionaryLength int, ascending bool) float64 {
firstChar := match.Token[0]
baseEntropy := float64(0)
var baseEntropy float64
if string(firstChar) == "a" || string(firstChar) == "1" {
baseEntropy = float64(0)
} else {
baseEntropy = math.Log2(float64(dictionaryLength))
//TODO: should this be just the first or any char?
// TODO: should this be just the first or any char?
if unicode.IsUpper(rune(firstChar)) {
baseEntropy++
}
@@ -183,7 +184,7 @@ func ExtraLeetEntropy(match match.Match, password string) float64 {
if string(char) != string(match.Token[index]) {
subsitutions++
} else {
//TODO: Make this only true for 1337 chars that are not subs?
// TODO: Make this only true for 1337 chars that are not subs?
unsub++
}
}
@@ -210,7 +211,7 @@ func DateEntropy(dateMatch match.DateMatch) float64 {
}
if dateMatch.Separator != "" {
entropy += 2 //add two bits for separator selection [/,-,.,etc]
entropy += 2 // add two bits for separator selection [/,-,.,etc]
}
return entropy
}

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"log"
"github.com/nbutton23/zxcvbn-go/data"
"github.com/ccojocar/zxcvbn-go/data"
)
// List holds a frequency list
@@ -28,8 +28,8 @@ func init() {
Lists["Surname"] = getStringListFromAsset(surnameFilePath, "Surname")
Lists["English"] = getStringListFromAsset(englishFilePath, "English")
Lists["Passwords"] = getStringListFromAsset(passwordsFilePath, "Passwords")
}
func getAsset(name string) []byte {
data, err := data.Asset(name)
if err != nil {
@@ -38,8 +38,8 @@ func getAsset(name string) []byte {
return data
}
func getStringListFromAsset(data []byte, name string) List {
func getStringListFromAsset(data []byte, name string) List {
var tempList List
err := json.Unmarshal(data, &tempList)
if err != nil {

View File

@@ -1,14 +1,16 @@
package match
//Matches is an alies for []Match used for sorting
// Matches is an alies for []Match used for sorting
type Matches []Match
func (s Matches) Len() int {
return len(s)
}
func (s Matches) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s Matches) Less(i, j int) bool {
if s[i].I < s[j].I {
return true
@@ -28,7 +30,7 @@ type Match struct {
Entropy float64
}
//DateMatch is specifilly a match for type date
// DateMatch is specifilly a match for type date
type DateMatch struct {
Pattern string
I, J int
@@ -37,7 +39,7 @@ type DateMatch struct {
Day, Month, Year int64
}
//Matcher are a func and ID that can be used to match different passwords
// Matcher are a func and ID that can be used to match different passwords
type Matcher struct {
MatchingFunc func(password string) []Match
ID string

View File

@@ -5,8 +5,8 @@ import (
"strconv"
"strings"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
)
const (
@@ -20,12 +20,12 @@ var (
dateWithOutSepMatch = regexp.MustCompile(`\d{4,8}`)
)
//FilterDateSepMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
// FilterDateSepMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
func FilterDateSepMatcher(m match.Matcher) bool {
return m.ID == dateSepMatcherName
}
//FilterDateWithoutSepMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
// FilterDateWithoutSepMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
func FilterDateWithoutSepMatcher(m match.Matcher) bool {
return m.ID == dateWithOutSepMatcherName
}
@@ -64,8 +64,8 @@ func dateSepMatcher(password string) []match.Match {
return matches
}
func dateSepMatchHelper(password string) []match.DateMatch {
func dateSepMatchHelper(password string) []match.DateMatch {
var matches []match.DateMatch
for _, v := range dateRxYearSuffix.FindAllString(password, len(password)) {
@@ -101,7 +101,6 @@ func dateSepMatchHelper(password string) []match.DateMatch {
}
}
return out
}
type dateMatchCandidate struct {
@@ -136,7 +135,7 @@ func dateWithoutSepMatch(password string) []match.Match {
return matches
}
//TODO Has issues with 6 digit dates
// TODO Has issues with 6 digit dates
func dateWithoutSepMatchHelper(password string) (matches []match.DateMatch) {
for _, v := range dateWithOutSepMatch.FindAllString(password, len(password)) {
i := strings.Index(password, v)
@@ -146,17 +145,17 @@ func dateWithoutSepMatchHelper(password string) (matches []match.DateMatch) {
var candidatesRoundOne []dateMatchCandidate
if length <= 6 {
//2-digit year prefix
// 2-digit year prefix
candidatesRoundOne = append(candidatesRoundOne, buildDateMatchCandidate(v[2:], v[0:2], i, j))
//2-digityear suffix
// 2-digityear suffix
candidatesRoundOne = append(candidatesRoundOne, buildDateMatchCandidate(v[0:lastIndex-2], v[lastIndex-2:], i, j))
}
if length >= 6 {
//4-digit year prefix
// 4-digit year prefix
candidatesRoundOne = append(candidatesRoundOne, buildDateMatchCandidate(v[4:], v[0:4], i, j))
//4-digit year sufix
// 4-digit year sufix
candidatesRoundOne = append(candidatesRoundOne, buildDateMatchCandidate(v[0:lastIndex-3], v[lastIndex-3:], i, j))
}
@@ -179,7 +178,6 @@ func dateWithoutSepMatchHelper(password string) (matches []match.DateMatch) {
}
intMonth, err := strconv.ParseInt(candidate.Month, 10, 16)
if err != nil {
continue
}
@@ -204,6 +202,5 @@ func buildDateMatchCandidate(dayMonth, year string, i, j int) dateMatchCandidate
}
func buildDateMatchCandidateTwo(day, month string, year string, i, j int) dateMatchCandidateTwo {
return dateMatchCandidateTwo{Day: day, Month: month, Year: year, I: i, J: j}
}

View File

@@ -3,8 +3,8 @@ package matching
import (
"strings"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
)
func buildDictMatcher(dictName string, rankedDict map[string]int) func(password string) []match.Match {
@@ -15,7 +15,6 @@ func buildDictMatcher(dictName string, rankedDict map[string]int) func(password
}
return matches
}
}
func dictionaryMatch(password string, dictionaryName string, rankedDict map[string]int) []match.Match {
@@ -29,7 +28,8 @@ func dictionaryMatch(password string, dictionaryName string, rankedDict map[stri
for j := i; j < length; j++ {
word := pwLowerRunes[i : j+1]
if val, ok := rankedDict[string(word)]; ok {
matchDic := match.Match{Pattern: "dictionary",
matchDic := match.Match{
Pattern: "dictionary",
DictionaryName: dictionaryName,
I: i,
J: j,
@@ -46,7 +46,6 @@ func dictionaryMatch(password string, dictionaryName string, rankedDict map[stri
}
func buildRankedDict(unrankedList []string) map[string]int {
result := make(map[string]int)
for i, v := range unrankedList {

View File

@@ -3,14 +3,14 @@ package matching
import (
"strings"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
)
// L33TMatcherName id
const L33TMatcherName = "l33t"
//FilterL33tMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
// FilterL33tMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
func FilterL33tMatcher(m match.Matcher) bool {
return m.ID == L33TMatcherName
}
@@ -105,7 +105,7 @@ func createListOfMapsWithoutConflicts(table map[string][]string) []map[string][]
return result
}
// This function retrieves the list of values that appear for one or more keys. This is usefull to
// This function retrieves the list of values that appear for one or more keys. This is useful to
// know which l33t chars can represent more than one letter.
func retrieveConflictsListFromTable(table map[string][]string) []string {
result := []string{}
@@ -128,7 +128,7 @@ func retrieveConflictsListFromTable(table map[string][]string) []string {
}
// This function aims to create different maps for a given char if this char represents a conflict.
// If the specified char is not a conflit one, the same map will be returned. In scenarios which
// If the specified char is not a conflict one, the same map will be returned. In scenarios which
// the provided char can not be found on map, an empty list will be returned. This function was
// designed to be used on conflicts situations.
func createDifferentMapsForLeetChar(table map[string][]string, leetChar string) []map[string][]string {
@@ -158,7 +158,7 @@ func retrieveListOfKeysWithSpecificValueFromTable(table map[string][]string, val
return result
}
// This function returns a lsit of substitution map from a given table. Each map in the result will
// This function returns a list of substitution map from a given table. Each map in the result will
// provide only one representation for each value. As an example, if the provided map contains the
// values "@" and "4" in the possibilities to represent "a", two maps will be created where one
// will contain "a" mapping to "@" and the other one will provide "a" mapping to "4".

View File

@@ -3,9 +3,9 @@ package matching
import (
"sort"
"github.com/nbutton23/zxcvbn-go/adjacency"
"github.com/nbutton23/zxcvbn-go/frequency"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/adjacency"
"github.com/ccojocar/zxcvbn-go/frequency"
"github.com/ccojocar/zxcvbn-go/match"
)
var (
@@ -23,8 +23,7 @@ func init() {
// Omnimatch runs all matchers against the password
func Omnimatch(password string, userInputs []string, filters ...func(match.Matcher) bool) (matches []match.Match) {
//Can I run into the issue where nil is not equal to nil?
// Can I run into the issue where nil is not equal to nil?
if dictionaryMatchers == nil || adjacencyGraphs == nil {
loadFrequencyList()
}
@@ -51,7 +50,6 @@ func Omnimatch(password string, userInputs []string, filters ...func(match.Match
}
func loadFrequencyList() {
for n, list := range frequency.Lists {
dictionaryMatchers = append(dictionaryMatchers, match.Matcher{MatchingFunc: buildDictMatcher(n, buildRankedDict(list.List)), ID: n})
}
@@ -63,8 +61,8 @@ func loadFrequencyList() {
adjacencyGraphs = append(adjacencyGraphs, adjacency.GraphMap["keypad"])
adjacencyGraphs = append(adjacencyGraphs, adjacency.GraphMap["macKeypad"])
//l33tFilePath, _ := filepath.Abs("adjacency/L33t.json")
//L33T_TABLE = adjacency.GetAdjancencyGraphFromFile(l33tFilePath, "l33t")
// l33tFilePath, _ := filepath.Abs("adjacency/L33t.json")
// L33T_TABLE = adjacency.GetAdjancencyGraphFromFile(l33tFilePath, "l33t")
sequences = make(map[string]string)
sequences["lower"] = "abcdefghijklmnopqrstuvwxyz"
@@ -78,5 +76,4 @@ func loadFrequencyList() {
matchers = append(matchers, match.Matcher{MatchingFunc: l33tMatch, ID: L33TMatcherName})
matchers = append(matchers, match.Matcher{MatchingFunc: dateSepMatcher, ID: dateSepMatcherName})
matchers = append(matchers, match.Matcher{MatchingFunc: dateWithoutSepMatch, ID: dateWithOutSepMatcherName})
}

View File

@@ -3,13 +3,13 @@ package matching
import (
"strings"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
)
const repeatMatcherName = "REPEAT"
//FilterRepeatMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
// FilterRepeatMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
func FilterRepeatMatcher(m match.Matcher) bool {
return m.ID == repeatMatcherName
}
@@ -17,7 +17,7 @@ func FilterRepeatMatcher(m match.Matcher) bool {
func repeatMatch(password string) []match.Match {
var matches []match.Match
//Loop through password. if current == prev currentStreak++ else if currentStreak > 2 {buildMatch; currentStreak = 1} prev = current
// Loop through password. if current == prev currentStreak++ else if currentStreak > 2 {buildMatch; currentStreak = 1} prev = current
var current, prev string
currentStreak := 1
var i int
@@ -29,9 +29,8 @@ func repeatMatch(password string) []match.Match {
continue
}
if strings.ToLower(current) == strings.ToLower(prev) {
if strings.EqualFold(current, prev) {
currentStreak++
} else if currentStreak > 2 {
iPos := i - currentStreak
jPos := i - 1
@@ -40,7 +39,8 @@ func repeatMatch(password string) []match.Match {
I: iPos,
J: jPos,
Token: password[iPos : jPos+1],
DictionaryName: prev}
DictionaryName: prev,
}
matchRepeat.Entropy = entropy.RepeatEntropy(matchRepeat)
matches = append(matches, matchRepeat)
currentStreak = 1
@@ -59,7 +59,8 @@ func repeatMatch(password string) []match.Match {
I: iPos,
J: jPos,
Token: password[iPos : jPos+1],
DictionaryName: prev}
DictionaryName: prev,
}
matchRepeat.Entropy = entropy.RepeatEntropy(matchRepeat)
matches = append(matches, matchRepeat)
}

View File

@@ -3,13 +3,13 @@ package matching
import (
"strings"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
)
const sequenceMatcherName = "SEQ"
//FilterSequenceMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
// FilterSequenceMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
func FilterSequenceMatcher(m match.Matcher) bool {
return m.ID == sequenceMatcherName
}
@@ -64,10 +64,8 @@ func sequenceMatch(password string) []match.Match {
matches = append(matches, matchSequence)
}
break
} else {
j++
}
j++
}
}
i = j

View File

@@ -3,14 +3,14 @@ package matching
import (
"strings"
"github.com/nbutton23/zxcvbn-go/adjacency"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/adjacency"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
)
const spatialMatcherName = "SPATIAL"
//FilterSpatialMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
// FilterSpatialMatcher can be pass to zxcvbn-go.PasswordStrength to skip that matcher
func FilterSpatialMatcher(m match.Matcher) bool {
return m.ID == spatialMatcherName
}
@@ -25,39 +25,38 @@ func spatialMatch(password string) (matches []match.Match) {
}
func spatialMatchHelper(password string, graph adjacency.Graph) (matches []match.Match) {
for i := 0; i < len(password)-1; {
j := i + 1
lastDirection := -99 //an int that it should never be!
lastDirection := -99 // an int that it should never be!
turns := 0
shiftedCount := 0
for {
prevChar := password[j-1]
found := false
foundDirection := -1
var foundDirection int
curDirection := -1
//My graphs seem to be wrong. . . and where the hell is qwerty
// My graphs seem to be wrong. . . and where the hell is qwerty
adjacents := graph.Graph[string(prevChar)]
//Consider growing pattern by one character if j hasn't gone over the edge
// Consider growing pattern by one character if j hasn't gone over the edge
if j < len(password) {
curChar := password[j]
for _, adj := range adjacents {
curDirection++
if strings.Index(adj, string(curChar)) != -1 {
if strings.Contains(adj, string(curChar)) {
found = true
foundDirection = curDirection
if strings.Index(adj, string(curChar)) == 1 {
//index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
//for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
// index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
// for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
shiftedCount++
}
if lastDirection != foundDirection {
//adding a turn is correct even in the initial case when last_direction is null:
//every spatial pattern starts with a turn.
// adding a turn is correct even in the initial case when last_direction is null:
// every spatial pattern starts with a turn.
turns++
lastDirection = foundDirection
}
@@ -66,12 +65,12 @@ func spatialMatchHelper(password string, graph adjacency.Graph) (matches []match
}
}
//if the current pattern continued, extend j and try to grow again
// if the current pattern continued, extend j and try to grow again
if found {
j++
} else {
//otherwise push the pattern discovered so far, if any...
//don't consider length 1 or 2 chains.
// otherwise push the pattern discovered so far, if any...
// don't consider length 1 or 2 chains.
if j-i > 2 {
matchSpc := match.Match{Pattern: "spatial", I: i, J: j - 1, Token: password[i:j], DictionaryName: graph.Name}
matchSpc.Entropy = entropy.SpatialEntropy(matchSpc, turns, shiftedCount)

View File

@@ -2,11 +2,12 @@ package scoring
import (
"fmt"
"github.com/nbutton23/zxcvbn-go/entropy"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/nbutton23/zxcvbn-go/utils/math"
"math"
"sort"
"github.com/ccojocar/zxcvbn-go/entropy"
"github.com/ccojocar/zxcvbn-go/match"
zxcvbnmath "github.com/ccojocar/zxcvbn-go/utils/math"
)
const (
@@ -15,7 +16,7 @@ const (
//adjust for your site accordingly if you use another hash function, possibly by
//several orders of magnitude!
singleGuess float64 = 0.010
numAttackers float64 = 100 //Cores used to make guesses
numAttackers float64 = 100 // Cores used to make guesses
secondsPerGuess float64 = singleGuess / numAttackers
)
@@ -37,7 +38,7 @@ MinimumEntropyMatchSequence returns the minimum entropy
minimum entropy. O(nm) dp alg for length-n password with m candidate matches.
*/
func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntropyMatch {
bruteforceCardinality := float64(entropy.CalcBruteForceCardinality(password))
bruteforceCardinality := entropy.CalcBruteForceCardinality(password)
upToK := make([]float64, len(password))
backPointers := make([]match.Match, len(password))
@@ -50,7 +51,7 @@ func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntr
}
i, j := match.I, match.J
//see if best entropy up to i-1 + entropy of match is less that current min at j
// see if best entropy up to i-1 + entropy of match is less that current min at j
upTo := get(upToK, i-1)
candidateEntropy := upTo + match.Entropy
@@ -62,7 +63,7 @@ func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntr
}
}
//walk backwards and decode the best sequence
// walk backwards and decode the best sequence
var matchSequence []match.Match
passwordLen := len(password)
passwordLen--
@@ -80,12 +81,13 @@ func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntr
sort.Sort(match.Matches(matchSequence))
makeBruteForceMatch := func(i, j int) match.Match {
return match.Match{Pattern: "bruteforce",
return match.Match{
Pattern: "bruteforce",
I: i,
J: j,
Token: password[i : j+1],
Entropy: math.Log2(math.Pow(bruteforceCardinality, float64(j-i)))}
Entropy: math.Log2(math.Pow(bruteforceCardinality, float64(j-i))),
}
}
k := 0
@@ -110,14 +112,16 @@ func MinimumEntropyMatchSequence(password string, matches []match.Match) MinEntr
}
crackTime := roundToXDigits(entropyToCrackTime(minEntropy), 3)
return MinEntropyMatch{Password: password,
return MinEntropyMatch{
Password: password,
Entropy: roundToXDigits(minEntropy, 3),
MatchSequence: matchSequenceCopy,
CrackTime: crackTime,
CrackTimeDisplay: displayTime(crackTime),
Score: crackTimeToScore(crackTime)}
Score: crackTimeToScore(crackTime),
}
}
func get(a []float64, i int) float64 {
if i < 0 || i >= len(a) {
return float64(0)

View File

@@ -3,10 +3,10 @@ package zxcvbn
import (
"time"
"github.com/nbutton23/zxcvbn-go/match"
"github.com/nbutton23/zxcvbn-go/matching"
"github.com/nbutton23/zxcvbn-go/scoring"
"github.com/nbutton23/zxcvbn-go/utils/math"
"github.com/ccojocar/zxcvbn-go/match"
"github.com/ccojocar/zxcvbn-go/matching"
"github.com/ccojocar/zxcvbn-go/scoring"
zxcvbnmath "github.com/ccojocar/zxcvbn-go/utils/math"
)
// PasswordStrength takes a password, userInputs and optional filters and returns a MinEntropyMatch

View File

@@ -570,6 +570,7 @@ Check out these projects, which use https://github.com/gookit/color :
- [xo/terminfo](https://github.com/xo/terminfo)
- [beego/bee](https://github.com/beego/bee)
- [issue9/term](https://github.com/issue9/term)
- [muesli/termenv](https://github.com/muesli/termenv)
- [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code)
- [Standard ANSI color map](https://conemu.github.io/en/AnsiEscapeCodes.html#Standard_ANSI_color_map)
- [Terminal Colors](https://gist.github.com/XVilka/8346728)

View File

@@ -578,6 +578,7 @@ const (
## 参考项目
- [inhere/console](https://github.com/inhere/php-console)
- [muesli/termenv](https://github.com/muesli/termenv)
- [xo/terminfo](https://github.com/xo/terminfo)
- [beego/bee](https://github.com/beego/bee)
- [issue9/term](https://github.com/issue9/term)

6
vendor/github.com/gookit/color/any.go generated vendored Normal file
View File

@@ -0,0 +1,6 @@
//go:build !go1.18
// +build !go1.18
package color
type any = interface{}

View File

@@ -183,7 +183,7 @@ func InnerErrs() []error {
// Usage:
//
// msg := RenderCode("3;32;45", "some", "message")
func RenderCode(code string, args ...interface{}) string {
func RenderCode(code string, args ...any) string {
var message string
if ln := len(args); ln == 0 {
return ""
@@ -205,7 +205,7 @@ func RenderCode(code string, args ...interface{}) string {
// RenderWithSpaces Render code with spaces.
// If the number of args is > 1, a space will be added between the args
func RenderWithSpaces(code string, args ...interface{}) string {
func RenderWithSpaces(code string, args ...any) string {
msg := formatArgsForPrintln(args)
if len(code) == 0 {
return msg

View File

@@ -41,15 +41,27 @@ func (o Opts) String() string {
* Basic 16 color definition
*************************************************************/
// Base value for foreground/background color
// base: fg 30~37, bg 40~47
// light: fg 90~97, bg 100~107
const (
// OptMax max option value. range: 0 - 9
OptMax = 10
// DiffFgBg diff foreground and background color
DiffFgBg = 10
)
// Boundary value for foreground/background color 16
//
// - base: fg 30~37, bg 40~47
// - light: fg 90~97, bg 100~107
const (
FgBase uint8 = 30
FgMax uint8 = 37
BgBase uint8 = 40
BgMax uint8 = 47
HiFgBase uint8 = 90
HiFgMax uint8 = 97
HiBgBase uint8 = 100
HiBgMax uint8 = 107
)
// Foreground colors. basic foreground colors 30 - 37
@@ -94,7 +106,7 @@ const (
BgDefault Color = 49
)
// Extra background color 100 - 107(非标准)
// Extra background color 100 - 107 (non-standard)
const (
BgDarkGray Color = iota + 100
BgLightRed
@@ -108,7 +120,7 @@ const (
BgGray Color = 100
)
// Option settings
// Option settings. range: 0 - 9
const (
OpReset Color = iota // 0 重置所有设置
OpBold // 1 加粗
@@ -188,61 +200,69 @@ func (c Color) Text(message string) string { return RenderString(c.String(), mes
// Render messages by color setting
//
// Usage:
//
// green := color.FgGreen.Render
// fmt.Println(green("message"))
func (c Color) Render(a ...interface{}) string { return RenderCode(c.String(), a...) }
func (c Color) Render(a ...any) string { return RenderCode(c.String(), a...) }
// Renderln messages by color setting.
// like Println, will add spaces for each argument
//
// Usage:
//
// green := color.FgGreen.Renderln
// fmt.Println(green("message"))
func (c Color) Renderln(a ...interface{}) string { return RenderWithSpaces(c.String(), a...) }
func (c Color) Renderln(a ...any) string { return RenderWithSpaces(c.String(), a...) }
// Sprint render messages by color setting. is alias of the Render()
func (c Color) Sprint(a ...interface{}) string { return RenderCode(c.String(), a...) }
func (c Color) Sprint(a ...any) string { return RenderCode(c.String(), a...) }
// Sprintf format and render message.
//
// Usage:
//
// green := color.Green.Sprintf
// colored := green("message")
func (c Color) Sprintf(format string, args ...interface{}) string {
func (c Color) Sprintf(format string, args ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, args...))
}
// Print messages.
//
// Usage:
//
// color.Green.Print("message")
//
// OR:
//
// green := color.FgGreen.Print
// green("message")
func (c Color) Print(args ...interface{}) {
func (c Color) Print(args ...any) {
doPrintV2(c.Code(), fmt.Sprint(args...))
}
// Printf format and print messages.
//
// Usage:
//
// color.Cyan.Printf("string %s", "arg0")
func (c Color) Printf(format string, a ...interface{}) {
func (c Color) Printf(format string, a ...any) {
doPrintV2(c.Code(), fmt.Sprintf(format, a...))
}
// Println messages with new line
func (c Color) Println(a ...interface{}) { doPrintlnV2(c.String(), a) }
func (c Color) Println(a ...any) { doPrintlnV2(c.String(), a) }
// Light current color. eg: 36(FgCyan) -> 96(FgLightCyan).
//
// Usage:
//
// lightCyan := Cyan.Light()
// lightCyan.Print("message")
func (c Color) Light() Color {
val := int(c)
val := uint8(c)
if val >= 30 && val <= 47 {
return Color(uint8(c) + 60)
return Color(val + 60)
}
// don't change
@@ -252,12 +272,13 @@ func (c Color) Light() Color {
// Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan)
//
// Usage:
//
// cyan := LightCyan.Darken()
// cyan.Print("message")
func (c Color) Darken() Color {
val := int(c)
val := uint8(c)
if val >= 90 && val <= 107 {
return Color(uint8(c) - 60)
return Color(val - 60)
}
// don't change
@@ -315,7 +336,7 @@ func (c Color) RGB() RGBColor {
return emptyRGBColor
}
return HEX(Basic2hex(val))
return HEX(Basic2hex(val), c.IsBg())
}
// Code convert to code string. eg "35"
@@ -328,8 +349,23 @@ func (c Color) String() string {
return strconv.FormatInt(int64(c), 10)
}
// IsBg check is background color
func (c Color) IsBg() bool {
val := uint8(c)
return val >= BgBase && val <= BgMax || val >= HiBgBase && val <= HiBgMax
}
// IsFg check is foreground color
func (c Color) IsFg() bool {
val := uint8(c)
return val >= FgBase && val <= FgMax || val >= HiFgBase && val <= HiFgMax
}
// IsOption check is option code: 0-9
func (c Color) IsOption() bool { return uint8(c) < OptMax }
// IsValid color value
func (c Color) IsValid() bool { return c < 107 }
func (c Color) IsValid() bool { return uint8(c) < HiBgMax }
/*************************************************************
* basic color maps
@@ -461,9 +497,7 @@ func Fg2Bg(val uint8) uint8 {
}
// Basic2nameMap data
func Basic2nameMap() map[uint8]string {
return basic2nameMap
}
func Basic2nameMap() map[uint8]string { return basic2nameMap }
// func initName2basicMap() map[string]uint8 {
// n2b := make(map[string]uint8, len(basic2nameMap))

View File

@@ -19,15 +19,18 @@ from wikipedia, 256 color:
// tpl for 8 bit 256 color(`2^8`)
//
// format:
//
// ESC[ … 38;5;<n> … m // 选择前景色
// ESC[ … 48;5;<n> … m // 选择背景色
//
// example:
//
// fg "\x1b[38;5;242m"
// bg "\x1b[48;5;208m"
// both "\x1b[38;5;242;48;5;208m"
//
// links:
//
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位
const (
TplFg256 = "38;5;%d"
@@ -40,19 +43,21 @@ const (
* 8bit(256) Color: Bit8Color Color256
*************************************************************/
// Color256 256 color (8 bit), uint8 range at 0 - 255
// Color256 256 color (8 bit), uint8 range at 0 - 255.
// Support 256 color on windows CMD, PowerShell
//
// 颜色值使用10进制和16进制都可 0x98 = 152
//
// The color consists of two uint8:
//
// 0: color value
// 1: color type; Fg=0, Bg=1, >1: unset value
//
// example:
//
// fg color: [152, 0]
// bg color: [152, 1]
//
// NOTICE: now support 256 color on windows CMD, PowerShell
// lint warn - Name starts with package name
type Color256 [2]uint8
type Bit8Color = Color256 // alias
@@ -87,27 +92,27 @@ func (c Color256) Reset() error {
}
// Print print message
func (c Color256) Print(a ...interface{}) {
func (c Color256) Print(a ...any) {
doPrintV2(c.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (c Color256) Printf(format string, a ...interface{}) {
func (c Color256) Printf(format string, a ...any) {
doPrintV2(c.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (c Color256) Println(a ...interface{}) {
func (c Color256) Println(a ...any) {
doPrintlnV2(c.String(), a)
}
// Sprint returns rendered message
func (c Color256) Sprint(a ...interface{}) string {
func (c Color256) Sprint(a ...any) string {
return RenderCode(c.String(), a...)
}
// Sprintf returns format and rendered message
func (c Color256) Sprintf(format string, a ...interface{}) string {
func (c Color256) Sprintf(format string, a ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, a...))
}
@@ -159,9 +164,7 @@ func (c Color256) String() string {
}
// IsFg color
func (c Color256) IsFg() bool {
return c[1] == AsFg
}
func (c Color256) IsFg() bool { return c[1] == AsFg }
// ToFg 256 color
func (c Color256) ToFg() Color256 {
@@ -170,9 +173,7 @@ func (c Color256) ToFg() Color256 {
}
// IsBg color
func (c Color256) IsBg() bool {
return c[1] == AsBg
}
func (c Color256) IsBg() bool { return c[1] == AsBg }
// ToBg 256 color
func (c Color256) ToBg() Color256 {
@@ -181,9 +182,7 @@ func (c Color256) ToBg() Color256 {
}
// IsEmpty value
func (c Color256) IsEmpty() bool {
return c[1] > 1
}
func (c Color256) IsEmpty() bool { return c[1] > 1 }
/*************************************************************
* 8bit(256) Style
@@ -206,6 +205,7 @@ type Style256 struct {
// S256 create a color256 style
//
// Usage:
//
// s := color.S256()
// s := color.S256(132) // fg
// s := color.S256(132, 203) // fg and bg
@@ -256,27 +256,27 @@ func (s *Style256) AddOpts(opts ...Color) *Style256 {
}
// Print message
func (s *Style256) Print(a ...interface{}) {
func (s *Style256) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (s *Style256) Printf(format string, a ...interface{}) {
func (s *Style256) Printf(format string, a ...any) {
doPrintV2(s.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (s *Style256) Println(a ...interface{}) {
func (s *Style256) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Sprint returns rendered message
func (s *Style256) Sprint(a ...interface{}) string {
func (s *Style256) Sprint(a ...any) string {
return RenderCode(s.Code(), a...)
}
// Sprintf returns format and rendered message
func (s *Style256) Sprintf(format string, a ...interface{}) string {
func (s *Style256) Sprintf(format string, a ...any) string {
return RenderString(s.Code(), fmt.Sprintf(format, a...))
}

View File

@@ -8,17 +8,21 @@ import (
// 24 bit RGB color
// RGB:
//
// R 0-255 G 0-255 B 0-255
// R 00-FF G 00-FF B 00-FF (16进制)
//
// Format:
//
// ESC[ … 38;2;<r>;<g>;<b> … m // Select RGB foreground color
// ESC[ … 48;2;<r>;<g>;<b> … m // Choose RGB background color
//
// links:
//
// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位
//
// example:
//
// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m
// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m
// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m
@@ -40,17 +44,17 @@ const (
*************************************************************/
// RGBColor definition.
// Support RGB color on Windows CMD, PowerShell
//
// The first to third digits represent the color value.
// The last digit represents the foreground(0), background(1), >1 is unset value
//
// Usage:
//
// // 0, 1, 2 is R,G,B.
// // 3rd: Fg=0, Bg=1, >1: unset value
// RGBColor{30,144,255, 0}
// RGBColor{30,144,255, 1}
//
// NOTICE: now support RGB color on Windows CMD, PowerShell
type RGBColor [4]uint8
// create an empty RGBColor
@@ -59,6 +63,7 @@ var emptyRGBColor = RGBColor{3: 99}
// RGB color create.
//
// Usage:
//
// c := RGB(30,144,255)
// c := RGB(30,144,255, true)
// c.Print("message")
@@ -90,6 +95,7 @@ func RgbFromInts(rgb []int, isBg ...bool) RGBColor {
// HEX create RGB color from a HEX color string.
//
// Usage:
//
// c := HEX("ccc") // rgb: [204 204 204]
// c := HEX("aabbcc") // rgb: [170 187 204]
// c := HEX("#aabbcc")
@@ -139,6 +145,7 @@ func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor {
// Support use color name in the {namedRgbMap}
//
// Usage:
//
// c := RGBFromString("170,187,204")
// c.Print("message")
//
@@ -180,27 +187,27 @@ func (c RGBColor) Reset() error {
}
// Print print message
func (c RGBColor) Print(a ...interface{}) {
func (c RGBColor) Print(a ...any) {
doPrintV2(c.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (c RGBColor) Printf(format string, a ...interface{}) {
func (c RGBColor) Printf(format string, a ...any) {
doPrintV2(c.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (c RGBColor) Println(a ...interface{}) {
func (c RGBColor) Println(a ...any) {
doPrintlnV2(c.String(), a)
}
// Sprint returns rendered message
func (c RGBColor) Sprint(a ...interface{}) string {
func (c RGBColor) Sprint(a ...any) string {
return RenderCode(c.String(), a...)
}
// Sprintf returns format and rendered message
func (c RGBColor) Sprintf(format string, a ...interface{}) string {
func (c RGBColor) Sprintf(format string, a ...any) string {
return RenderString(c.String(), fmt.Sprintf(format, a...))
}
@@ -243,6 +250,18 @@ func (c RGBColor) String() string {
return ""
}
// ToBg convert to background color
func (c RGBColor) ToBg() RGBColor {
c[3] = AsBg
return c
}
// ToFg convert to foreground color
func (c RGBColor) ToFg() RGBColor {
c[3] = AsFg
return c
}
// IsEmpty value
func (c RGBColor) IsEmpty() bool {
return c[3] > AsBg
@@ -303,6 +322,7 @@ func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle {
// HEXStyle create a RGBStyle from HEX color string.
//
// Usage:
//
// s := HEXStyle("aabbcc", "eee")
// s.Print("message")
func HEXStyle(fg string, bg ...string) *RGBStyle {
@@ -320,6 +340,7 @@ func HEXStyle(fg string, bg ...string) *RGBStyle {
// RGBStyleFromString create a RGBStyle from color value string.
//
// Usage:
//
// s := RGBStyleFromString("170,187,204", "70,87,4")
// s.Print("message")
func RGBStyleFromString(fg string, bg ...string) *RGBStyle {
@@ -363,27 +384,27 @@ func (s *RGBStyle) AddOpts(opts ...Color) *RGBStyle {
}
// Print print message
func (s *RGBStyle) Print(a ...interface{}) {
func (s *RGBStyle) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf format and print message
func (s *RGBStyle) Printf(format string, a ...interface{}) {
func (s *RGBStyle) Printf(format string, a ...any) {
doPrintV2(s.String(), fmt.Sprintf(format, a...))
}
// Println print message with newline
func (s *RGBStyle) Println(a ...interface{}) {
func (s *RGBStyle) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
// Sprint returns rendered message
func (s *RGBStyle) Sprint(a ...interface{}) string {
func (s *RGBStyle) Sprint(a ...any) string {
return RenderCode(s.String(), a...)
}
// Sprintf returns format and rendered message
func (s *RGBStyle) Sprintf(format string, a ...interface{}) string {
func (s *RGBStyle) Sprintf(format string, a ...any) string {
return RenderString(s.String(), fmt.Sprintf(format, a...))
}

View File

@@ -41,6 +41,7 @@ var (
// There are internal defined fg color tags
//
// Usage:
//
// <tag>content text</>
//
// @notice 加 0 在前面是为了防止之前的影响到现在的设置
@@ -324,13 +325,15 @@ func (tp *TagParser) ParseByEnv(str string) string {
return tp.Parse(str)
}
// Parse parse given string, replace color tag and return rendered string
// Parse given string, replace color tag and return rendered string
//
// Use built in tags:
//
// <TAG_NAME>CONTENT</>
// // e.g: `<info>message</>`
//
// Custom tag attributes:
//
// `<fg=VALUE;bg=VALUE;op=VALUES>CONTENT</>`
// // e.g: `<fg=167;bg=232>wel</>`
func (tp *TagParser) Parse(str string) string {
@@ -376,10 +379,12 @@ func ReplaceTag(str string) string {
// ParseCodeFromAttr parse color attributes.
//
// attr format:
//
// // VALUE please see var: FgColors, BgColors, AllOptions
// "fg=VALUE;bg=VALUE;op=VALUE"
//
// 16 color:
//
// "fg=yellow"
// "bg=red"
// "op=bold,underscore" // option is allow multi value
@@ -387,11 +392,13 @@ func ReplaceTag(str string) string {
// "fg=white;op=bold,underscore"
//
// 256 color:
//
// "fg=167"
// "fg=167;bg=23"
// "fg=167;bg=23;op=bold"
//
// True color:
//
// // hex
// "fg=fc1cac"
// "fg=fc1cac;bg=c2c3c4"
@@ -476,12 +483,10 @@ func ClearTag(s string) string {
*************************************************************/
// GetTagCode get color code by tag name
func GetTagCode(name string) string {
return colorTags[name]
}
func GetTagCode(name string) string { return colorTags[name] }
// ApplyTag for messages
func ApplyTag(tag string, a ...interface{}) string {
func ApplyTag(tag string, a ...any) string {
return RenderCode(GetTagCode(tag), a...)
}
@@ -510,11 +515,12 @@ func IsDefinedTag(name string) bool {
// Tag value is a defined style name
// Usage:
//
// Tag("info").Println("message")
type Tag string
// Print messages
func (tg Tag) Print(a ...interface{}) {
func (tg Tag) Print(a ...any) {
name := string(tg)
str := fmt.Sprint(a...)
@@ -526,7 +532,7 @@ func (tg Tag) Print(a ...interface{}) {
}
// Printf format and print messages
func (tg Tag) Printf(format string, a ...interface{}) {
func (tg Tag) Printf(format string, a ...any) {
name := string(tg)
str := fmt.Sprintf(format, a...)
@@ -538,7 +544,7 @@ func (tg Tag) Printf(format string, a ...interface{}) {
}
// Println messages line
func (tg Tag) Println(a ...interface{}) {
func (tg Tag) Println(a ...any) {
name := string(tg)
if stl := GetStyle(name); !stl.IsEmpty() {
stl.Println(a...)
@@ -548,12 +554,12 @@ func (tg Tag) Println(a ...interface{}) {
}
// Sprint render messages
func (tg Tag) Sprint(a ...interface{}) string {
func (tg Tag) Sprint(a ...any) string {
return RenderCode(GetTagCode(string(tg)), a...)
}
// Sprintf format and render messages
func (tg Tag) Sprintf(format string, a ...interface{}) string {
func (tg Tag) Sprintf(format string, a ...any) string {
tag := string(tg)
str := fmt.Sprintf(format, a...)

View File

@@ -52,6 +52,7 @@ var (
// ---------- basic(16) <=> RGB color convert ----------
// refer from Hyper app
// Tip: only keep foreground color, background color need convert to foreground color for convert to RGB
basic2hexMap = map[uint8]string{
30: "000000", // black
31: "c51e14", // red
@@ -61,7 +62,7 @@ var (
35: "c839c5", // magenta
36: "20c5c6", // cyan
37: "c7c7c7", // white
// - don't add bg color
// - don't add bg color, convert to fg color for convert to RGB
// 40: "000000", // black
// 41: "c51e14", // red
// 42: "1dc121", // green
@@ -428,6 +429,7 @@ func HexToRGB(hex string) []int { return HexToRgb(hex) }
// HexToRgb convert hex color string to RGB numbers
//
// Usage:
//
// rgb := HexToRgb("ccc") // rgb: [204 204 204]
// rgb := HexToRgb("aabbcc") // rgb: [170 187 204]
// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204]
@@ -474,6 +476,7 @@ func Rgb2hex(rgb []int) string { return RgbToHex(rgb) }
// RgbToHex convert RGB-code to hex-code
//
// Usage:
//
// hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc"
func RgbToHex(rgb []int) string {
hexNodes := make([]string, len(rgb))
@@ -488,10 +491,15 @@ func RgbToHex(rgb []int) string {
* 4bit(16) color <=> RGB/True color
*************************************************************/
// BasicToHex convert basic color to hex string.
func BasicToHex(val uint8) string {
val = Bg2Fg(val)
return basic2hexMap[val]
}
// Basic2hex convert basic color to hex string.
func Basic2hex(val uint8) string {
val = Fg2Bg(val)
return basic2hexMap[val]
return BasicToHex(val)
}
// Hex2basic convert hex string to basic color code.
@@ -663,6 +671,7 @@ func C256ToRgbV1(val uint8) (rgb []uint8) {
// returns r, g, and b in the set [0, 255].
//
// Usage:
//
// HslIntToRgb(0, 100, 50) // red
// HslIntToRgb(120, 100, 50) // lime
// HslIntToRgb(120, 100, 25) // dark green
@@ -677,6 +686,7 @@ func HslIntToRgb(h, s, l int) (rgb []uint8) {
// returns r, g, and b in the set [0, 255].
//
// Usage:
//
// rgbVals := HslToRgb(0, 1, 0.5) // red
func HslToRgb(h, s, l float64) (rgb []uint8) {
var r, g, b float64

View File

@@ -9,16 +9,17 @@ import "fmt"
// PrinterFace interface
type PrinterFace interface {
fmt.Stringer
Sprint(a ...interface{}) string
Sprintf(format string, a ...interface{}) string
Print(a ...interface{})
Printf(format string, a ...interface{})
Println(a ...interface{})
Sprint(a ...any) string
Sprintf(format string, a ...any) string
Print(a ...any)
Printf(format string, a ...any)
Println(a ...any)
}
// Printer a generic color message printer.
//
// Usage:
//
// p := &Printer{Code: "32;45;3"}
// p.Print("message")
type Printer struct {
@@ -40,27 +41,27 @@ func (p *Printer) String() string {
}
// Sprint returns rendering colored messages
func (p *Printer) Sprint(a ...interface{}) string {
func (p *Printer) Sprint(a ...any) string {
return RenderCode(p.String(), a...)
}
// Sprintf returns format and rendering colored messages
func (p *Printer) Sprintf(format string, a ...interface{}) string {
func (p *Printer) Sprintf(format string, a ...any) string {
return RenderString(p.String(), fmt.Sprintf(format, a...))
}
// Print rendering colored messages
func (p *Printer) Print(a ...interface{}) {
func (p *Printer) Print(a ...any) {
doPrintV2(p.String(), fmt.Sprint(a...))
}
// Printf format and rendering colored messages
func (p *Printer) Printf(format string, a ...interface{}) {
func (p *Printer) Printf(format string, a ...any) {
doPrintV2(p.String(), fmt.Sprintf(format, a...))
}
// Println rendering colored messages with newline
func (p *Printer) Println(a ...interface{}) {
func (p *Printer) Println(a ...any) {
doPrintlnV2(p.Code, a)
}
@@ -77,46 +78,56 @@ func (p *Printer) IsEmpty() bool {
type SimplePrinter struct{}
// Print message
func (s *SimplePrinter) Print(v ...interface{}) {
func (s *SimplePrinter) Print(v ...any) {
Print(v...)
}
// Printf message
func (s *SimplePrinter) Printf(format string, v ...interface{}) {
func (s *SimplePrinter) Printf(format string, v ...any) {
Printf(format, v...)
}
// Println message
func (s *SimplePrinter) Println(v ...interface{}) {
func (s *SimplePrinter) Println(v ...any) {
Println(v...)
}
// Successf message
func (s *SimplePrinter) Successf(format string, a ...any) {
Success.Printf(format, a...)
}
// Successln message
func (s *SimplePrinter) Successln(a ...any) {
Success.Println(a...)
}
// Infof message
func (s *SimplePrinter) Infof(format string, a ...interface{}) {
func (s *SimplePrinter) Infof(format string, a ...any) {
Info.Printf(format, a...)
}
// Infoln message
func (s *SimplePrinter) Infoln(a ...interface{}) {
func (s *SimplePrinter) Infoln(a ...any) {
Info.Println(a...)
}
// Warnf message
func (s *SimplePrinter) Warnf(format string, a ...interface{}) {
func (s *SimplePrinter) Warnf(format string, a ...any) {
Warn.Printf(format, a...)
}
// Warnln message
func (s *SimplePrinter) Warnln(a ...interface{}) {
func (s *SimplePrinter) Warnln(a ...any) {
Warn.Println(a...)
}
// Errorf message
func (s *SimplePrinter) Errorf(format string, a ...interface{}) {
func (s *SimplePrinter) Errorf(format string, a ...any) {
Error.Printf(format, a...)
}
// Errorln message
func (s *SimplePrinter) Errorln(a ...interface{}) {
func (s *SimplePrinter) Errorln(a ...any) {
Error.Println(a...)
}

View File

@@ -5,104 +5,104 @@ package color
*************************************************************/
// Redp print message with Red color
func Redp(a ...interface{}) { Red.Print(a...) }
func Redp(a ...any) { Red.Print(a...) }
// Redf print message with Red color
func Redf(format string, a ...interface{}) { Red.Printf(format, a...) }
func Redf(format string, a ...any) { Red.Printf(format, a...) }
// Redln print message line with Red color
func Redln(a ...interface{}) { Red.Println(a...) }
func Redln(a ...any) { Red.Println(a...) }
// Bluep print message with Blue color
func Bluep(a ...interface{}) { Blue.Print(a...) }
func Bluep(a ...any) { Blue.Print(a...) }
// Bluef print message with Blue color
func Bluef(format string, a ...interface{}) { Blue.Printf(format, a...) }
func Bluef(format string, a ...any) { Blue.Printf(format, a...) }
// Blueln print message line with Blue color
func Blueln(a ...interface{}) { Blue.Println(a...) }
func Blueln(a ...any) { Blue.Println(a...) }
// Cyanp print message with Cyan color
func Cyanp(a ...interface{}) { Cyan.Print(a...) }
func Cyanp(a ...any) { Cyan.Print(a...) }
// Cyanf print message with Cyan color
func Cyanf(format string, a ...interface{}) { Cyan.Printf(format, a...) }
func Cyanf(format string, a ...any) { Cyan.Printf(format, a...) }
// Cyanln print message line with Cyan color
func Cyanln(a ...interface{}) { Cyan.Println(a...) }
func Cyanln(a ...any) { Cyan.Println(a...) }
// Grayp print message with Gray color
func Grayp(a ...interface{}) { Gray.Print(a...) }
func Grayp(a ...any) { Gray.Print(a...) }
// Grayf print message with Gray color
func Grayf(format string, a ...interface{}) { Gray.Printf(format, a...) }
func Grayf(format string, a ...any) { Gray.Printf(format, a...) }
// Grayln print message line with Gray color
func Grayln(a ...interface{}) { Gray.Println(a...) }
func Grayln(a ...any) { Gray.Println(a...) }
// Greenp print message with Green color
func Greenp(a ...interface{}) { Green.Print(a...) }
func Greenp(a ...any) { Green.Print(a...) }
// Greenf print message with Green color
func Greenf(format string, a ...interface{}) { Green.Printf(format, a...) }
func Greenf(format string, a ...any) { Green.Printf(format, a...) }
// Greenln print message line with Green color
func Greenln(a ...interface{}) { Green.Println(a...) }
func Greenln(a ...any) { Green.Println(a...) }
// Yellowp print message with Yellow color
func Yellowp(a ...interface{}) { Yellow.Print(a...) }
func Yellowp(a ...any) { Yellow.Print(a...) }
// Yellowf print message with Yellow color
func Yellowf(format string, a ...interface{}) { Yellow.Printf(format, a...) }
func Yellowf(format string, a ...any) { Yellow.Printf(format, a...) }
// Yellowln print message line with Yellow color
func Yellowln(a ...interface{}) { Yellow.Println(a...) }
func Yellowln(a ...any) { Yellow.Println(a...) }
// Magentap print message with Magenta color
func Magentap(a ...interface{}) { Magenta.Print(a...) }
func Magentap(a ...any) { Magenta.Print(a...) }
// Magentaf print message with Magenta color
func Magentaf(format string, a ...interface{}) { Magenta.Printf(format, a...) }
func Magentaf(format string, a ...any) { Magenta.Printf(format, a...) }
// Magentaln print message line with Magenta color
func Magentaln(a ...interface{}) { Magenta.Println(a...) }
func Magentaln(a ...any) { Magenta.Println(a...) }
/*************************************************************
* quick use style print message
*************************************************************/
// Infop print message with Info color
func Infop(a ...interface{}) { Info.Print(a...) }
func Infop(a ...any) { Info.Print(a...) }
// Infof print message with Info style
func Infof(format string, a ...interface{}) { Info.Printf(format, a...) }
func Infof(format string, a ...any) { Info.Printf(format, a...) }
// Infoln print message with Info style
func Infoln(a ...interface{}) { Info.Println(a...) }
func Infoln(a ...any) { Info.Println(a...) }
// Successp print message with success color
func Successp(a ...interface{}) { Success.Print(a...) }
func Successp(a ...any) { Success.Print(a...) }
// Successf print message with success style
func Successf(format string, a ...interface{}) { Success.Printf(format, a...) }
func Successf(format string, a ...any) { Success.Printf(format, a...) }
// Successln print message with success style
func Successln(a ...interface{}) { Success.Println(a...) }
func Successln(a ...any) { Success.Println(a...) }
// Errorp print message with Error color
func Errorp(a ...interface{}) { Error.Print(a...) }
func Errorp(a ...any) { Error.Print(a...) }
// Errorf print message with Error style
func Errorf(format string, a ...interface{}) { Error.Printf(format, a...) }
func Errorf(format string, a ...any) { Error.Printf(format, a...) }
// Errorln print message with Error style
func Errorln(a ...interface{}) { Error.Println(a...) }
func Errorln(a ...any) { Error.Println(a...) }
// Warnp print message with Warn color
func Warnp(a ...interface{}) { Warn.Print(a...) }
func Warnp(a ...any) { Warn.Print(a...) }
// Warnf print message with Warn style
func Warnf(format string, a ...interface{}) { Warn.Printf(format, a...) }
func Warnf(format string, a ...any) { Warn.Printf(format, a...) }
// Warnln print message with Warn style
func Warnln(a ...interface{}) { Warn.Println(a...) }
func Warnln(a ...any) { Warn.Println(a...) }

View File

@@ -12,12 +12,14 @@ import (
// Style a 16 color style. can add: fg color, bg color, color options
//
// Example:
//
// color.Style{color.FgGreen}.Print("message")
type Style []Color
// New create a custom style
//
// Usage:
//
// color.New(color.FgGreen).Print("message")
// equals to:
// color.Style{color.FgGreen}.Print("message")
@@ -35,45 +37,49 @@ func (s *Style) Add(cs ...Color) {
*s = append(*s, cs...)
}
// Render render text
// Render colored text
//
// Usage:
//
// color.New(color.FgGreen).Render("text")
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text")
func (s Style) Render(a ...interface{}) string {
func (s Style) Render(a ...any) string {
return RenderCode(s.String(), a...)
}
// Renderln render text line.
// Renderln render text with newline.
// like Println, will add spaces for each argument
//
// Usage:
//
// color.New(color.FgGreen).Renderln("text", "more")
// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more")
func (s Style) Renderln(a ...interface{}) string {
func (s Style) Renderln(a ...any) string {
return RenderWithSpaces(s.String(), a...)
}
// Sprint is alias of the 'Render'
func (s Style) Sprint(a ...interface{}) string {
func (s Style) Sprint(a ...any) string {
return RenderCode(s.String(), a...)
}
// Sprintf format and render message.
func (s Style) Sprintf(format string, a ...interface{}) string {
func (s Style) Sprintf(format string, a ...any) string {
return RenderString(s.String(), fmt.Sprintf(format, a...))
}
// Print render and Print text
func (s Style) Print(a ...interface{}) {
func (s Style) Print(a ...any) {
doPrintV2(s.String(), fmt.Sprint(a...))
}
// Printf render and print text
func (s Style) Printf(format string, a ...interface{}) {
func (s Style) Printf(format string, a ...any) {
doPrintV2(s.Code(), fmt.Sprintf(format, a...))
}
// Println render and print text line
func (s Style) Println(a ...interface{}) {
func (s Style) Println(a ...any) {
doPrintlnV2(s.String(), a)
}
@@ -115,20 +121,20 @@ func (t *Theme) Save() {
}
// Tips use name as title, only apply style for name
func (t *Theme) Tips(format string, a ...interface{}) {
func (t *Theme) Tips(format string, a ...any) {
// only apply style for name
t.Print(strings.ToUpper(t.Name) + ": ")
Printf(format+"\n", a...)
}
// Prompt use name as title, and apply style for message
func (t *Theme) Prompt(format string, a ...interface{}) {
func (t *Theme) Prompt(format string, a ...any) {
title := strings.ToUpper(t.Name) + ":"
t.Println(title, fmt.Sprintf(format, a...))
}
// Block like Prompt, but will wrap a empty line
func (t *Theme) Block(format string, a ...interface{}) {
func (t *Theme) Block(format string, a ...any) {
title := strings.ToUpper(t.Name) + ":\n"
t.Println(title, fmt.Sprintf(format, a...))
@@ -140,6 +146,7 @@ func (t *Theme) Block(format string, a ...interface{}) {
// internal themes(like bootstrap style)
// Usage:
//
// color.Info.Print("message")
// color.Info.Printf("a %s message", "test")
// color.Warn.Println("message")
@@ -175,6 +182,7 @@ var (
// Themes internal defined themes.
// Usage:
//
// color.Themes["info"].Println("message")
var Themes = map[string]*Theme{
"info": Info,
@@ -211,6 +219,7 @@ func GetTheme(name string) *Theme {
// Styles internal defined styles, like bootstrap styles.
// Usage:
//
// color.Styles["info"].Println("message")
var Styles = map[string]Style{
"info": {OpReset, FgGreen},
@@ -285,31 +294,31 @@ func (s *Scheme) Style(name string) Style {
}
// Infof message print
func (s *Scheme) Infof(format string, a ...interface{}) {
func (s *Scheme) Infof(format string, a ...any) {
s.Styles["info"].Printf(format, a...)
}
// Infoln message print
func (s *Scheme) Infoln(v ...interface{}) {
func (s *Scheme) Infoln(v ...any) {
s.Styles["info"].Println(v...)
}
// Warnf message print
func (s *Scheme) Warnf(format string, a ...interface{}) {
func (s *Scheme) Warnf(format string, a ...any) {
s.Styles["warn"].Printf(format, a...)
}
// Warnln message print
func (s *Scheme) Warnln(v ...interface{}) {
func (s *Scheme) Warnln(v ...any) {
s.Styles["warn"].Println(v...)
}
// Errorf message print
func (s *Scheme) Errorf(format string, a ...interface{}) {
func (s *Scheme) Errorf(format string, a ...any) {
s.Styles["error"].Printf(format, a...)
}
// Errorln message print
func (s *Scheme) Errorln(v ...interface{}) {
func (s *Scheme) Errorln(v ...any) {
s.Styles["error"].Println(v...)
}

View File

@@ -32,39 +32,31 @@ func ResetTerminal() error {
*************************************************************/
// Print render color tag and print messages
func Print(a ...interface{}) {
func Print(a ...any) {
Fprint(output, a...)
}
// Printf format and print messages
func Printf(format string, a ...interface{}) {
func Printf(format string, a ...any) {
Fprintf(output, format, a...)
}
// Println messages with new line
func Println(a ...interface{}) {
func Println(a ...any) {
Fprintln(output, a...)
}
// Fprint print rendered messages to writer
//
// Notice: will ignore print error
func Fprint(w io.Writer, a ...interface{}) {
func Fprint(w io.Writer, a ...any) {
_, err := fmt.Fprint(w, Render(a...))
saveInternalError(err)
// if isLikeInCmd {
// renderColorCodeOnCmd(func() {
// _, _ = fmt.Fprint(w, Render(a...))
// })
// } else {
// _, _ = fmt.Fprint(w, Render(a...))
// }
}
// Fprintf print format and rendered messages to writer.
// Notice: will ignore print error
func Fprintf(w io.Writer, format string, a ...interface{}) {
func Fprintf(w io.Writer, format string, a ...any) {
str := fmt.Sprintf(format, a...)
_, err := fmt.Fprint(w, ReplaceTag(str))
saveInternalError(err)
@@ -72,7 +64,7 @@ func Fprintf(w io.Writer, format string, a ...interface{}) {
// Fprintln print rendered messages line to writer
// Notice: will ignore print error
func Fprintln(w io.Writer, a ...interface{}) {
func Fprintln(w io.Writer, a ...any) {
str := formatArgsForPrintln(a)
_, err := fmt.Fprintln(w, ReplaceTag(str))
saveInternalError(err)
@@ -80,7 +72,7 @@ func Fprintln(w io.Writer, a ...interface{}) {
// Lprint passes colored messages to a log.Logger for printing.
// Notice: should be goroutine safe
func Lprint(l *log.Logger, a ...interface{}) {
func Lprint(l *log.Logger, a ...any) {
l.Print(Render(a...))
}
@@ -90,7 +82,7 @@ func Lprint(l *log.Logger, a ...interface{}) {
//
// text := Render("<info>hello</> <cyan>world</>!")
// fmt.Println(text)
func Render(a ...interface{}) string {
func Render(a ...any) string {
if len(a) == 0 {
return ""
}
@@ -98,28 +90,23 @@ func Render(a ...interface{}) string {
}
// Sprint parse color tags, return rendered string
func Sprint(a ...interface{}) string {
func Sprint(a ...any) string {
if len(a) == 0 {
return ""
}
return ReplaceTag(fmt.Sprint(a...))
}
// Sprintf format and return rendered string
func Sprintf(format string, a ...interface{}) string {
func Sprintf(format string, a ...any) string {
return ReplaceTag(fmt.Sprintf(format, a...))
}
// String alias of the ReplaceTag
func String(s string) string {
return ReplaceTag(s)
}
func String(s string) string { return ReplaceTag(s) }
// Text alias of the ReplaceTag
func Text(s string) string {
return ReplaceTag(s)
}
func Text(s string) string { return ReplaceTag(s) }
// Uint8sToInts convert []uint8 to []int
// func Uint8sToInts(u8s []uint8 ) []int {
@@ -138,25 +125,17 @@ func Text(s string) string {
func doPrintV2(code, str string) {
_, err := fmt.Fprint(output, RenderString(code, str))
saveInternalError(err)
// if isLikeInCmd {
// renderColorCodeOnCmd(func() {
// _, _ = fmt.Fprint(output, RenderString(code, str))
// })
// } else {
// _, _ = fmt.Fprint(output, RenderString(code, str))
// }
}
// new implementation, support render full color code on pwsh.exe, cmd.exe
func doPrintlnV2(code string, args []interface{}) {
func doPrintlnV2(code string, args []any) {
str := formatArgsForPrintln(args)
_, err := fmt.Fprintln(output, RenderString(code, str))
saveInternalError(err)
}
// use Println, will add spaces for each arg
func formatArgsForPrintln(args []interface{}) (message string) {
func formatArgsForPrintln(args []any) (message string) {
if ln := len(args); ln == 0 {
message = ""
} else if ln == 1 {
@@ -178,7 +157,7 @@ func formatArgsForPrintln(args []interface{}) (message string) {
// return debugMode == "on"
// }
func debugf(f string, v ...interface{}) {
func debugf(f string, v ...any) {
if debugMode {
fmt.Print("COLOR_DEBUG: ")
fmt.Printf(f, v...)

View File

@@ -1,2 +0,0 @@
zxcvbn
debug.test

View File

@@ -1,15 +0,0 @@
PKG_LIST = $$( go list ./... | grep -v /vendor/ | grep -v "zxcvbn-go/data" )
.DEFAULT_GOAL := help
.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: test
test: ## Run `go test {Package list}` on the packages
go test $(PKG_LIST)
.PHONY: lint
lint: ## Run `golint {Package list}`
golint $(PKG_LIST)

View File

@@ -1,3 +1,22 @@
## 1.27.10
### Fixes
- fix: go 1.21 adding goroutine ID to creator+location (#685) [bdc7803]
## 1.27.9
### Fixes
- Prevent nil-dereference in format.Object for boxed nil error (#681) [3b31fc3]
### Maintenance
- Bump golang.org/x/net from 0.11.0 to 0.12.0 (#679) [360849b]
- chore: use String() instead of fmt.Sprintf (#678) [86f3659]
- Bump golang.org/x/net from 0.10.0 to 0.11.0 (#674) [642ead0]
- chore: unnecessary use of fmt.Sprintf (#677) [ceb9ca6]
- Bump github.com/onsi/ginkgo/v2 from 2.10.0 to 2.11.0 (#675) [a2087d8]
- docs: fix ContainSubstring references (#673) [fc9a89f]
- Bump github.com/onsi/ginkgo/v2 from 2.9.7 to 2.10.0 (#671) [9076019]
## 1.27.8
### Fixes

View File

@@ -259,7 +259,7 @@ func Object(object interface{}, indentation uint) string {
indent := strings.Repeat(Indent, int(indentation))
value := reflect.ValueOf(object)
commonRepresentation := ""
if err, ok := object.(error); ok {
if err, ok := object.(error); ok && !isNilValue(value) { // isNilValue check needed here to avoid nil deref due to boxed nil
commonRepresentation += "\n" + IndentString(err.Error(), indentation) + "\n" + indent
}
return fmt.Sprintf("%s<%s>: %s%s", indent, formatType(value), commonRepresentation, formatValue(value, indentation))
@@ -302,7 +302,7 @@ func formatType(v reflect.Value) string {
case reflect.Map:
return fmt.Sprintf("%s | len:%d", v.Type(), v.Len())
default:
return fmt.Sprintf("%s", v.Type())
return v.Type().String()
}
}

View File

@@ -22,7 +22,7 @@ import (
"github.com/onsi/gomega/types"
)
const GOMEGA_VERSION = "1.27.8"
const GOMEGA_VERSION = "1.27.10"
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
If you're using Ginkgo then you probably forgot to put your assertion in an It().

View File

@@ -94,7 +94,7 @@ func Succeed() types.GomegaMatcher {
//
// Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
// Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
// Expect(err).Should(MatchError(ContainsSubstring("sprocket not found"))) // asserts that edrr.Error() contains substring "sprocket not found"
// Expect(err).Should(MatchError(ContainSubstring("sprocket not found"))) // asserts that edrr.Error() contains substring "sprocket not found"
//
// It is an error for err to be nil or an object that does not implement the
// Error interface

View File

@@ -52,5 +52,5 @@ func (matcher *BeADirectoryMatcher) FailureMessage(actual interface{}) (message
}
func (matcher *BeADirectoryMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("not be a directory"))
return format.Message(actual, "not be a directory")
}

View File

@@ -52,5 +52,5 @@ func (matcher *BeARegularFileMatcher) FailureMessage(actual interface{}) (messag
}
func (matcher *BeARegularFileMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("not be a regular file"))
return format.Message(actual, "not be a regular file")
}

View File

@@ -32,9 +32,9 @@ func (matcher *BeAnExistingFileMatcher) Match(actual interface{}) (success bool,
}
func (matcher *BeAnExistingFileMatcher) FailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("to exist"))
return format.Message(actual, "to exist")
}
func (matcher *BeAnExistingFileMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("not to exist"))
return format.Message(actual, "not to exist")
}

View File

@@ -2,14 +2,13 @@ linters:
enable:
- asciicheck
- bodyclose
- deadcode
- depguard
- dogsled
- durationcheck
- errcheck
- errorlint
- exportloopref
- gci
- ginkgolinter
- gofmt
- gofumpt
- goimports
@@ -24,10 +23,18 @@ linters:
- nolintlint
- revive
- staticcheck
- structcheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- wastedassign
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/securego)
run:
timeout: 5m

View File

@@ -26,6 +26,11 @@ builds:
signs:
- cmd: cosign
stdin: '{{ .Env.COSIGN_PASSWORD}}'
args: ["sign-blob", "--key=/tmp/cosign.key", "--output=${signature}", "${artifact}"]
args:
- "sign-blob"
- "--key=/tmp/cosign.key"
- "--output=${signature}"
- "${artifact}"
- "--yes"
artifacts: all

View File

@@ -1,11 +1,11 @@
ARG GO_VERSION
FROM golang:${GO_VERSION}-alpine AS builder
RUN apk add --no-cache ca-certificates make git curl gcc libc-dev
RUN mkdir -p /build
RUN apk add --no-cache ca-certificates make git curl gcc libc-dev \
&& mkdir -p /build
WORKDIR /build
COPY . /build/
RUN go mod download
RUN make build-linux
RUN go mod download \
&& make build-linux
FROM golang:${GO_VERSION}-alpine
RUN apk add --no-cache ca-certificates bash git gcc libc-dev openssh

View File

@@ -87,4 +87,7 @@ image-push: image
docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG)
docker push $(IMAGE_REPO)/$(BIN):latest
.PHONY: test build clean release image image-push
tlsconfig:
go generate ./...
.PHONY: test build clean release image image-push tlsconfig

View File

@@ -68,7 +68,7 @@ jobs:
GO111MODULE: on
steps:
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
@@ -98,7 +98,7 @@ jobs:
GO111MODULE: on
steps:
- name: Checkout Source
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Run Gosec Security Scanner
uses: securego/gosec@master
with:
@@ -157,7 +157,6 @@ directory you can supply `./...` as the input argument.
- G304: File path provided as taint input
- G305: File traversal when extracting zip/tar archive
- G306: Poor file permissions used when writing to a new file
- G307: Deferring a method which returns an error
- G401: Detect the usage of DES, RC4, MD5 or SHA1
- G402: Look for bad TLS connection settings
- G403: Ensure minimum RSA key length of 2048 bits
@@ -168,10 +167,12 @@ directory you can supply `./...` as the input argument.
- G504: Import blocklist: net/http/cgi
- G505: Import blocklist: crypto/sha1
- G601: Implicit memory aliasing of items from a range statement
- G602: Slice access out of bounds
### Retired rules
- G105: Audit the use of math/big.Int.Exp - [CVE is fixed](https://github.com/golang/go/issues/15184)
- G307: Deferring a method which returns an error - causing more inconvenience than fixing a security issue, despite the details from this [blog post](https://www.joeshaw.org/dont-defer-close-on-writable-files/)
### Selecting rules
@@ -188,7 +189,7 @@ $ gosec -exclude=G303 ./...
### CWE Mapping
Every issue detected by `gosec` is mapped to a [CWE (Common Weakness Enumeration)](http://cwe.mitre.org/data/index.html) which describes in more generic terms the vulnerability. The exact mapping can be found [here](https://github.com/securego/gosec/blob/master/issue.go#L50).
Every issue detected by `gosec` is mapped to a [CWE (Common Weakness Enumeration)](http://cwe.mitre.org/data/index.html) which describes in more generic terms the vulnerability. The exact mapping can be found [here](https://github.com/securego/gosec/blob/master/issue/issue.go#L50).
### Configuration

View File

@@ -10,7 +10,7 @@ inputs:
runs:
using: 'docker'
image: 'docker://securego/gosec'
image: 'docker://securego/gosec:2.16.0'
args:
- ${{ inputs.args }}

View File

@@ -31,6 +31,10 @@ import (
"strings"
"sync"
"github.com/securego/gosec/v2/analyzers"
"github.com/securego/gosec/v2/issue"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/packages"
)
@@ -42,7 +46,10 @@ const LoadMode = packages.NeedName |
packages.NeedTypes |
packages.NeedTypesSizes |
packages.NeedTypesInfo |
packages.NeedSyntax
packages.NeedSyntax |
packages.NeedModule |
packages.NeedEmbedFiles |
packages.NeedEmbedPatterns
const externalSuppressionJustification = "Globally suppressed."
@@ -52,7 +59,7 @@ var generatedCodePattern = regexp.MustCompile(`^// Code generated .* DO NOT EDIT
// The Context is populated with data parsed from the source code as it is scanned.
// It is passed through to all rule functions as they are called. Rules may use
// this data in conjunction withe the encountered AST node.
// this data in conjunction with the encountered AST node.
type Context struct {
FileSet *token.FileSet
Comments ast.CommentMap
@@ -60,12 +67,24 @@ type Context struct {
Pkg *types.Package
PkgFiles []*ast.File
Root *ast.File
Config Config
Imports *ImportTracker
Ignores []map[string][]SuppressionInfo
Config Config
Ignores []map[string][]issue.SuppressionInfo
PassedValues map[string]interface{}
}
// GetFileAtNodePos returns the file at the node position in the file set available in the context.
func (ctx *Context) GetFileAtNodePos(node ast.Node) *token.File {
return ctx.FileSet.File(node.Pos())
}
// NewIssue creates a new issue
func (ctx *Context) NewIssue(node ast.Node, ruleID, desc string,
severity, confidence issue.Score,
) *issue.Issue {
return issue.New(ctx.GetFileAtNodePos(node), node, ruleID, desc, severity, confidence)
}
// Metrics used when reporting information about a scanning run.
type Metrics struct {
NumFiles int `json:"files"`
@@ -82,7 +101,7 @@ type Analyzer struct {
context *Context
config Config
logger *log.Logger
issues []*Issue
issues []*issue.Issue
stats *Metrics
errors map[string][]Error // keys are file paths; values are the golang errors in those files
tests bool
@@ -90,13 +109,7 @@ type Analyzer struct {
showIgnored bool
trackSuppressions bool
concurrency int
}
// SuppressionInfo object is to record the kind and the justification that used
// to suppress violations.
type SuppressionInfo struct {
Kind string `json:"kind"`
Justification string `json:"justification"`
analyzerList []*analysis.Analyzer
}
// NewAnalyzer builds a new analyzer.
@@ -119,13 +132,14 @@ func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressio
context: &Context{},
config: conf,
logger: logger,
issues: make([]*Issue, 0, 16),
issues: make([]*issue.Issue, 0, 16),
stats: &Metrics{},
errors: make(map[string][]Error),
tests: tests,
concurrency: concurrency,
excludeGenerated: excludeGenerated,
trackSuppressions: trackSuppressions,
analyzerList: analyzers.BuildDefaultAnalyzers(),
}
}
@@ -216,7 +230,10 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
wg.Wait() // wait for the goroutines to stop
return fmt.Errorf("parsing errors in pkg %q: %w", pkg.Name, err)
}
gosec.Check(pkg)
gosec.CheckRules(pkg)
if on, err := gosec.config.IsGlobalEnabled(SSA); err == nil && on {
gosec.CheckAnalyzers(pkg)
}
}
}
}
@@ -267,8 +284,8 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
return pkgs, nil
}
// Check runs analysis on the given package
func (gosec *Analyzer) Check(pkg *packages.Package) {
// CheckRules runs analysis on the given package
func (gosec *Analyzer) CheckRules(pkg *packages.Package) {
gosec.logger.Println("Checking package:", pkg.Name)
for _, file := range pkg.Syntax {
fp := pkg.Fset.File(file.Pos())
@@ -303,6 +320,70 @@ func (gosec *Analyzer) Check(pkg *packages.Package) {
}
}
// CheckAnalyzers runs analyzers on a given package
func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
ssaPass := &analysis.Pass{
Analyzer: buildssa.Analyzer,
Fset: pkg.Fset,
Files: pkg.Syntax,
OtherFiles: pkg.OtherFiles,
IgnoredFiles: pkg.IgnoredFiles,
Pkg: pkg.Types,
TypesInfo: pkg.TypesInfo,
TypesSizes: pkg.TypesSizes,
ResultOf: nil,
Report: nil,
ImportObjectFact: nil,
ExportObjectFact: nil,
ImportPackageFact: nil,
ExportPackageFact: nil,
AllObjectFacts: nil,
AllPackageFacts: nil,
}
ssaResult, err := ssaPass.Analyzer.Run(ssaPass)
if err != nil {
gosec.logger.Printf("Error running SSA analyser on package %q: %s", pkg.Name, err)
return
}
resultMap := map[*analysis.Analyzer]interface{}{
buildssa.Analyzer: &analyzers.SSAAnalyzerResult{
Config: gosec.Config(),
Logger: gosec.logger,
SSA: ssaResult.(*buildssa.SSA),
},
}
for _, analyzer := range gosec.analyzerList {
pass := &analysis.Pass{
Analyzer: analyzer,
Fset: pkg.Fset,
Files: pkg.Syntax,
OtherFiles: pkg.OtherFiles,
IgnoredFiles: pkg.IgnoredFiles,
Pkg: pkg.Types,
TypesInfo: pkg.TypesInfo,
TypesSizes: pkg.TypesSizes,
ResultOf: resultMap,
Report: func(d analysis.Diagnostic) {},
ImportObjectFact: nil,
ExportObjectFact: nil,
ImportPackageFact: nil,
ExportPackageFact: nil,
AllObjectFacts: nil,
AllPackageFacts: nil,
}
result, err := pass.Analyzer.Run(pass)
if err != nil {
gosec.logger.Printf("Error running analyzer %s: %s\n", analyzer.Name, err)
continue
}
if result != nil {
if aissue, ok := result.(*issue.Issue); ok {
gosec.updateIssues(aissue, false, []issue.SuppressionInfo{})
}
}
}
}
func isGeneratedFile(file *ast.File) bool {
for _, comment := range file.Comments {
for _, row := range comment.List {
@@ -364,14 +445,16 @@ func (gosec *Analyzer) AppendError(file string, err error) {
}
// ignore a node (and sub-tree) if it is tagged with a nosec tag comment
func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {
// Checks if an alternative for #nosec is set and, if not, uses the default.
noSecDefaultTag := "#nosec"
noSecDefaultTag := NoSecTag(string(Nosec))
noSecAlternativeTag, err := gosec.config.GetGlobal(NoSecAlternative)
if err != nil {
noSecAlternativeTag = noSecDefaultTag
} else {
noSecAlternativeTag = NoSecTag(noSecAlternativeTag)
}
for _, group := range groups {
@@ -401,13 +484,13 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
re := regexp.MustCompile(`(G\d{3})`)
matches := re.FindAllStringSubmatch(directive, -1)
suppression := SuppressionInfo{
suppression := issue.SuppressionInfo{
Kind: "inSource",
Justification: justification,
}
// Find the rule IDs to ignore.
ignores := make(map[string]SuppressionInfo)
ignores := make(map[string]issue.SuppressionInfo)
for _, v := range matches {
ignores[v[1]] = suppression
}
@@ -426,25 +509,42 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
// Visit runs the gosec visitor logic over an AST created by parsing go code.
// Rule methods added with AddRule will be invoked as necessary.
func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
// If we've reached the end of this branch, pop off the ignores stack.
ignores, ok := gosec.updateIgnoredRules(n)
if !ok {
return gosec
}
// Using ast.File instead of ast.ImportSpec, so that we can track all imports at once.
switch i := n.(type) {
case *ast.File:
gosec.context.Imports.TrackFile(i)
}
for _, rule := range gosec.ruleset.RegisteredFor(n) {
suppressions, ignored := gosec.updateSuppressions(rule.ID(), ignores)
issue, err := rule.Match(n, gosec.context)
if err != nil {
file, line := GetLocation(n, gosec.context)
file = path.Base(file)
gosec.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
}
gosec.updateIssues(issue, ignored, suppressions)
}
return gosec
}
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]issue.SuppressionInfo, bool) {
if n == nil {
if len(gosec.context.Ignores) > 0 {
gosec.context.Ignores = gosec.context.Ignores[1:]
}
return gosec
return nil, false
}
switch i := n.(type) {
case *ast.File:
// Using ast.File instead of ast.ImportSpec, so that we can track
// all imports at once.
gosec.context.Imports.TrackFile(i)
}
// Get any new rule exclusions.
ignoredRules := gosec.ignore(n)
// Now create the union of exclusions.
ignores := map[string][]SuppressionInfo{}
ignores := map[string][]issue.SuppressionInfo{}
if len(gosec.context.Ignores) > 0 {
for k, v := range gosec.context.Ignores[0] {
ignores[k] = v
@@ -456,32 +556,32 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
}
// Push the new set onto the stack.
gosec.context.Ignores = append([]map[string][]SuppressionInfo{ignores}, gosec.context.Ignores...)
gosec.context.Ignores = append([]map[string][]issue.SuppressionInfo{ignores}, gosec.context.Ignores...)
for _, rule := range gosec.ruleset.RegisteredFor(n) {
return ignores, true
}
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.SuppressionInfo) ([]issue.SuppressionInfo, bool) {
// Check if all rules are ignored.
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
// Check if the specific rule is ignored
ruleSuppressions, ruleIgnored := ignores[rule.ID()]
ruleSuppressions, ruleIgnored := ignores[id]
ignored := generalIgnored || ruleIgnored
suppressions := append(generalSuppressions, ruleSuppressions...)
// Track external suppressions.
if gosec.ruleset.IsRuleSuppressed(rule.ID()) {
if gosec.ruleset.IsRuleSuppressed(id) {
ignored = true
suppressions = append(suppressions, SuppressionInfo{
suppressions = append(suppressions, issue.SuppressionInfo{
Kind: "external",
Justification: externalSuppressionJustification,
})
}
return suppressions, ignored
}
issue, err := rule.Match(n, gosec.context)
if err != nil {
file, line := GetLocation(n, gosec.context)
file = path.Base(file)
gosec.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
}
func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressions []issue.SuppressionInfo) {
if issue != nil {
if gosec.showIgnored {
issue.NoSec = ignored
@@ -496,19 +596,17 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
gosec.issues = append(gosec.issues, issue)
}
}
}
return gosec
}
// Report returns the current issues discovered and the metrics about the scan
func (gosec *Analyzer) Report() ([]*Issue, *Metrics, map[string][]Error) {
func (gosec *Analyzer) Report() ([]*issue.Issue, *Metrics, map[string][]Error) {
return gosec.issues, gosec.stats, gosec.errors
}
// Reset clears state such as context, issues and metrics from the configured analyzer
func (gosec *Analyzer) Reset() {
gosec.context = &Context{}
gosec.issues = make([]*Issue, 0, 16)
gosec.issues = make([]*issue.Issue, 0, 16)
gosec.stats = &Metrics{}
gosec.ruleset = NewRuleSet()
}

57
vendor/github.com/securego/gosec/v2/analyzers/ssrf.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
// (c) Copyright gosec's 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 analyzers
import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/ssa"
"github.com/securego/gosec/v2/issue"
)
func newSSRFAnalyzer(id string, description string) *analysis.Analyzer {
return &analysis.Analyzer{
Name: id,
Doc: description,
Run: runSSRF,
Requires: []*analysis.Analyzer{buildssa.Analyzer},
}
}
func runSSRF(pass *analysis.Pass) (interface{}, error) {
ssaResult, err := getSSAResult(pass)
if err != nil {
return nil, err
}
// TODO: implement the analysis
for _, fn := range ssaResult.SSA.SrcFuncs {
for _, block := range fn.DomPreorder() {
for _, instr := range block.Instrs {
switch instr := instr.(type) {
case *ssa.Call:
callee := instr.Call.StaticCallee()
if callee != nil {
ssaResult.Logger.Printf("callee: %s\n", callee)
return newIssue(pass.Analyzer.Name,
"not implemented",
pass.Fset, instr.Call.Pos(), issue.Low, issue.High), nil
}
}
}
}
}
return nil, nil
}

98
vendor/github.com/securego/gosec/v2/analyzers/util.go generated vendored Normal file
View File

@@ -0,0 +1,98 @@
// (c) Copyright gosec's 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 analyzers
import (
"fmt"
"go/token"
"log"
"os"
"strconv"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"github.com/securego/gosec/v2/issue"
)
// SSAAnalyzerResult contains various information returned by the
// SSA analysis along with some configuration
type SSAAnalyzerResult struct {
Config map[string]interface{}
Logger *log.Logger
SSA *buildssa.SSA
}
// BuildDefaultAnalyzers returns the default list of analyzers
func BuildDefaultAnalyzers() []*analysis.Analyzer {
return []*analysis.Analyzer{
newSSRFAnalyzer("G107", "URL provided to HTTP request as taint input"),
}
}
// getSSAResult retrieves the SSA result from analysis pass
func getSSAResult(pass *analysis.Pass) (*SSAAnalyzerResult, error) {
result, ok := pass.ResultOf[buildssa.Analyzer]
if !ok {
return nil, fmt.Errorf("no SSA result found in the analysis pass")
}
ssaResult, ok := result.(*SSAAnalyzerResult)
if !ok {
return nil, fmt.Errorf("the analysis pass result is not of type SSA")
}
return ssaResult, nil
}
// newIssue creates a new gosec issue
func newIssue(analyzerID string, desc string, fileSet *token.FileSet,
pos token.Pos, severity, confidence issue.Score,
) *issue.Issue {
file := fileSet.File(pos)
line := file.Line(pos)
col := file.Position(pos).Column
return &issue.Issue{
RuleID: analyzerID,
File: file.Name(),
Line: strconv.Itoa(line),
Col: strconv.Itoa(col),
Severity: severity,
Confidence: confidence,
What: desc,
Cwe: issue.GetCweByRule(analyzerID),
Code: issueCodeSnippet(fileSet, pos),
}
}
func issueCodeSnippet(fileSet *token.FileSet, pos token.Pos) string {
file := fileSet.File(pos)
start := (int64)(file.Line(pos))
if start-issue.SnippetOffset > 0 {
start = start - issue.SnippetOffset
}
end := (int64)(file.Line(pos))
end = end + issue.SnippetOffset
var code string
if file, err := os.Open(file.Name()); err == nil {
defer file.Close() // #nosec
code, err = issue.CodeSnippet(file, start, end)
if err != nil {
return err.Error()
}
}
return code
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/cmd/vflag"
"github.com/securego/gosec/v2/issue"
"github.com/securego/gosec/v2/report"
"github.com/securego/gosec/v2/rules"
)
@@ -142,7 +143,10 @@ var (
// output suppression information for auditing purposes
flagTrackSuppressions = flag.Bool("track-suppressions", false, "Output suppression information, including its kind and justification")
// exlude the folders from scan
// flagTerse shows only the summary of scan discarding all the logs
flagTerse = flag.Bool("terse", false, "Shows only the results and summary")
// exclude the folders from scan
flagDirsExclude arrayFlags
logger *log.Logger
@@ -265,22 +269,22 @@ func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.R
return nil
}
func convertToScore(value string) (gosec.Score, error) {
func convertToScore(value string) (issue.Score, error) {
value = strings.ToLower(value)
switch value {
case "low":
return gosec.Low, nil
return issue.Low, nil
case "medium":
return gosec.Medium, nil
return issue.Medium, nil
case "high":
return gosec.High, nil
return issue.High, nil
default:
return gosec.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
return issue.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
}
}
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) ([]*gosec.Issue, int) {
result := make([]*gosec.Issue, 0)
func filterIssues(issues []*issue.Issue, severity issue.Score, confidence issue.Score) ([]*issue.Issue, int) {
result := make([]*issue.Issue, 0)
trueIssues := 0
for _, issue := range issues {
if issue.Severity >= severity && issue.Confidence >= confidence {
@@ -293,7 +297,7 @@ func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.
return result, trueIssues
}
func exit(issues []*gosec.Issue, errors map[string][]gosec.Error, noFail bool) {
func exit(issues []*issue.Issue, errors map[string][]gosec.Error, noFail bool) {
nsi := 0
for _, issue := range issues {
if len(issue.Suppressions) == 0 {
@@ -353,7 +357,7 @@ func main() {
}
}
if *flagQuiet {
if *flagQuiet || *flagTerse {
logger = log.New(io.Discard, "", 0)
} else {
logger = log.New(logWriter, "[gosec] ", log.LstdFlags)

View File

@@ -5,7 +5,7 @@ import (
"strconv"
"strings"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
// handle ranges
@@ -14,7 +14,7 @@ func extractLineNumber(s string) int {
return lineNumber
}
type sortBySeverity []*gosec.Issue
type sortBySeverity []*issue.Issue
func (s sortBySeverity) Len() int { return len(s) }
@@ -34,6 +34,6 @@ func (s sortBySeverity) Less(i, j int) bool {
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// sortIssues sorts the issues by severity in descending order
func sortIssues(issues []*gosec.Issue) {
func sortIssues(issues []*issue.Issue) {
sort.Sort(sortBySeverity(issues))
}

View File

@@ -29,8 +29,15 @@ const (
ExcludeRules GlobalOption = "exclude"
// IncludeRules global option for should be load
IncludeRules GlobalOption = "include"
// SSA global option to enable go analysis framework with SSA support
SSA GlobalOption = "ssa"
)
// NoSecTag returns the tag used to disable gosec for a line of code.
func NoSecTag(tag string) string {
return fmt.Sprintf("%s%s", "#", tag)
}
// Config is used to provide configuration and customization to each of the rules.
type Config map[string]interface{}

View File

@@ -96,11 +96,46 @@ func GetChar(n ast.Node) (byte, error) {
return 0, fmt.Errorf("Unexpected AST node type: %T", n)
}
// GetStringRecursive will recursively walk down a tree of *ast.BinaryExpr. It will then concat the results, and return.
// Unlike the other getters, it does _not_ raise an error for unknown ast.Node types. At the base, the recursion will hit a non-BinaryExpr type,
// either BasicLit or other, so it's not an error case. It will only error if `strconv.Unquote` errors. This matters, because there's
// currently functionality that relies on error values being returned by GetString if and when it hits a non-basiclit string node type,
// hence for cases where recursion is needed, we use this separate function, so that we can still be backwards compatbile.
//
// This was added to handle a SQL injection concatenation case where the injected value is infixed between two strings, not at the start or end. See example below
//
// Do note that this will omit non-string values. So for example, if you were to use this node:
// ```go
// q := "SELECT * FROM foo WHERE name = '" + os.Args[0] + "' AND 1=1" // will result in "SELECT * FROM foo WHERE ” AND 1=1"
func GetStringRecursive(n ast.Node) (string, error) {
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.STRING {
return strconv.Unquote(node.Value)
}
if expr, ok := n.(*ast.BinaryExpr); ok {
x, err := GetStringRecursive(expr.X)
if err != nil {
return "", err
}
y, err := GetStringRecursive(expr.Y)
if err != nil {
return "", err
}
return x + y, nil
}
return "", nil
}
// GetString will read and return a string value from an ast.BasicLit
func GetString(n ast.Node) (string, error) {
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.STRING {
return strconv.Unquote(node.Value)
}
return "", fmt.Errorf("Unexpected AST node type: %T", n)
}
@@ -182,7 +217,7 @@ func GetCallInfo(n ast.Node, ctx *Context) (string, string, error) {
}
// GetCallStringArgsValues returns the values of strings arguments if they can be resolved
func GetCallStringArgsValues(n ast.Node, ctx *Context) []string {
func GetCallStringArgsValues(n ast.Node, _ *Context) []string {
values := []string{}
switch node := n.(type) {
case *ast.CallExpr:
@@ -201,22 +236,21 @@ func GetCallStringArgsValues(n ast.Node, ctx *Context) []string {
return values
}
// GetIdentStringValues return the string values of an Ident if they can be resolved
func GetIdentStringValues(ident *ast.Ident) []string {
func getIdentStringValues(ident *ast.Ident, stringFinder func(ast.Node) (string, error)) []string {
values := []string{}
obj := ident.Obj
if obj != nil {
switch decl := obj.Decl.(type) {
case *ast.ValueSpec:
for _, v := range decl.Values {
value, err := GetString(v)
value, err := stringFinder(v)
if err == nil {
values = append(values, value)
}
}
case *ast.AssignStmt:
for _, v := range decl.Rhs {
value, err := GetString(v)
value, err := stringFinder(v)
if err == nil {
values = append(values, value)
}
@@ -226,6 +260,18 @@ func GetIdentStringValues(ident *ast.Ident) []string {
return values
}
// getIdentStringRecursive returns the string of values of an Ident if they can be resolved
// The difference between this and GetIdentStringValues is that it will attempt to resolve the strings recursively,
// if it is passed a *ast.BinaryExpr. See GetStringRecursive for details
func GetIdentStringValuesRecursive(ident *ast.Ident) []string {
return getIdentStringValues(ident, GetStringRecursive)
}
// GetIdentStringValues return the string values of an Ident if they can be resolved
func GetIdentStringValues(ident *ast.Ident) []string {
return getIdentStringValues(ident, GetString)
}
// GetBinaryExprOperands returns all operands of a binary expression by traversing
// the expression tree
func GetBinaryExprOperands(be *ast.BinaryExpr) []ast.Node {
@@ -301,7 +347,7 @@ func Getenv(key, userDefault string) string {
return userDefault
}
// GetPkgRelativePath returns the Go relative relative path derived
// GetPkgRelativePath returns the Go relative path derived
// form the given path
func GetPkgRelativePath(path string) (string, error) {
abspath, err := filepath.Abs(path)

View File

@@ -51,9 +51,7 @@ func (t *ImportTracker) TrackPackages(pkgs ...*types.Package) {
func (t *ImportTracker) TrackImport(imported *ast.ImportSpec) {
importPath := strings.Trim(imported.Path.Value, `"`)
if imported.Name != nil {
if imported.Name.Name == "_" {
// Initialization only import
} else {
if imported.Name.Name != "_" {
// Aliased import
t.Imported[importPath] = append(t.Imported[importPath], imported.Name.String())
}

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package gosec
package issue
import (
"bufio"
@@ -77,7 +77,6 @@ var ruleToCWE = map[string]string{
"G304": "22",
"G305": "22",
"G306": "276",
"G307": "703",
"G401": "326",
"G402": "295",
"G403": "310",
@@ -88,6 +87,7 @@ var ruleToCWE = map[string]string{
"G504": "327",
"G505": "327",
"G601": "118",
"G602": "118",
}
// Issue is returned by a gosec rule if it discovers an issue with the scanned code.
@@ -105,8 +105,15 @@ type Issue struct {
Suppressions []SuppressionInfo `json:"suppressions"` // Suppression info of the issue
}
// SuppressionInfo object is to record the kind and the justification that used
// to suppress violations.
type SuppressionInfo struct {
Kind string `json:"kind"`
Justification string `json:"justification"`
}
// FileLocation point out the file path and line number in file
func (i Issue) FileLocation() string {
func (i *Issue) FileLocation() string {
return fmt.Sprintf("%s:%s", i.File, i.Line)
}
@@ -137,11 +144,8 @@ func (c Score) String() string {
return "UNDEFINED"
}
// codeSnippet extracts a code snippet based on the ast reference
func codeSnippet(file *os.File, start int64, end int64, n ast.Node) (string, error) {
if n == nil {
return "", fmt.Errorf("invalid AST node provided")
}
// CodeSnippet extracts a code snippet based on the ast reference
func CodeSnippet(file *os.File, start int64, end int64) (string, error) {
var pos int64
var buf bytes.Buffer
scanner := bufio.NewScanner(file)
@@ -171,9 +175,8 @@ func codeSnippetEndLine(node ast.Node, fobj *token.File) int64 {
return e + SnippetOffset
}
// NewIssue creates a new Issue
func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score, confidence Score) *Issue {
fobj := ctx.FileSet.File(node.Pos())
// New creates a new Issue
func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
name := fobj.Name()
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
line := strconv.Itoa(start)
@@ -183,11 +186,14 @@ func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score,
col := strconv.Itoa(fobj.Position(node.Pos()).Column)
var code string
if file, err := os.Open(fobj.Name()); err == nil {
if node == nil {
code = "invalid AST node provided"
}
if file, err := os.Open(fobj.Name()); err == nil && node != nil {
defer file.Close() // #nosec
s := codeSnippetStartLine(node, fobj)
e := codeSnippetEndLine(node, fobj)
code, err = codeSnippet(file, s, e, node)
code, err = CodeSnippet(file, s, e)
if err != nil {
code = err.Error()
}

View File

@@ -1,15 +1,19 @@
package gosec
import (
"github.com/securego/gosec/v2/issue"
)
// ReportInfo this is report information
type ReportInfo struct {
Errors map[string][]Error `json:"Golang errors"`
Issues []*Issue
Issues []*issue.Issue
Stats *Metrics
GosecVersion string
}
// NewReportInfo instantiate a ReportInfo
func NewReportInfo(issues []*Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo {
func NewReportInfo(issues []*issue.Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo {
return &ReportInfo{
Errors: errors,
Issues: issues,

View File

@@ -18,6 +18,7 @@ import (
"io"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
"github.com/securego/gosec/v2/report/csv"
"github.com/securego/gosec/v2/report/golint"
"github.com/securego/gosec/v2/report/html"
@@ -81,8 +82,8 @@ func CreateReport(w io.Writer, format string, enableColor bool, rootPaths []stri
return err
}
func filterOutSuppressedIssues(issues []*gosec.Issue) []*gosec.Issue {
nonSuppressedIssues := []*gosec.Issue{}
func filterOutSuppressedIssues(issues []*issue.Issue) []*issue.Issue {
nonSuppressedIssues := []*issue.Issue{}
for _, issue := range issues {
if len(issue.Suppressions) == 0 {
nonSuppressedIssues = append(nonSuppressedIssues, issue)

View File

@@ -5,12 +5,12 @@
<title>Golang Security Checker</title>
<link rel="shortcut icon" type="image/png" href="https://securego.io/img/favicon.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.4/css/bulma.min.css" integrity="sha512-HqxHUkJM0SYcbvxUw5P60SzdOTy/QVwA1JJrvaXJv4q7lmbDZCmZaqz01UPOaQveoxfYRv1tHozWGPMcuTBuvQ==" crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js" integrity="sha512-bgHRAiTjGrzHzLyKOnpFvaEpGzJet3z4tZnXGjpsCcqOnAH6VGUx9frc5bcIhKTVLEiCO6vEhNAgx5jtLUYrfA==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/go.min.js" integrity="sha512-AzBQVo6m0++RbnY/eU9VbedSeokh6wzxEOTc6XGGjcxdFeKxT43bFyo5sHYEIZe8sf5VfiewyNtwOrhu/Mo55g==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js" integrity="sha512-rdhY3cbXURo13l/WU9VlaRyaIYeJ/KBakckXIvJNAQde8DgpOmE+eZf7ha4vdqVjTtwQt69bD2wH2LXob/LB7Q==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/go.min.js" integrity="sha512-Ea+IN1qMvgwTqOnwxM38Hn54IaDS2buEvMJNTdSB5JOT4njx3RvPij353zbUMpT+zYjDqQDr2UbrbnW5+wE54A==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.7.0/react.min.js" integrity="sha512-+TFn1Gqbwx/qgwW3NU1/YtFYTfHGeD1e/8YfJZzkb6TFEZP4SUwp1Az9DMeWh3qC0F+YPKXbV3YclMUwBTvO3g==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js" integrity="sha512-8C49ZG/SaQnWaUgCHTU1o8uIQNYE6R8me38SwF26g2Q0byEXF4Jlvm+T/JAMHMeTBiEVPslSZRv9Xt4AV0pfmw==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.20.15/babel.min.js" integrity="sha512-Oy8gM3nNZgwbgd81x/VCtGpolDzgHK2Hpbn9nq4YhzDvxI4/ipCnoUeSHozXvTjOkzuZ1qqlUYjroqmclLhknA==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.22.10/babel.min.js" integrity="sha512-UhgUmmslB4Pi7NNyzbscVQPaL3meon1WMwHwHDjCLui/kWpr2Wz4sRZ8HlG4gZIUuKkF+LWYTX55ZVPzra2HTw==" crossorigin="anonymous"></script>
<style>
.field-label {
min-width: 80px;

View File

@@ -5,9 +5,10 @@ import (
"strconv"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
func generatePlaintext(issue *gosec.Issue) string {
func generatePlaintext(issue *issue.Issue) string {
cweID := "CWE"
if issue.Cwe != nil {
cweID = issue.Cwe.ID

View File

@@ -7,24 +7,19 @@ import (
"strings"
"github.com/google/uuid"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/cwe"
"github.com/securego/gosec/v2/issue"
)
// GenerateReport Convert a gosec report to a Sarif Report
// GenerateReport converts a gosec report into a SARIF report
func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error) {
type rule struct {
index int
rule *ReportingDescriptor
}
rules := make([]*ReportingDescriptor, 0)
rulesIndices := make(map[string]rule)
lastRuleIndex := -1
rules := []*ReportingDescriptor{}
results := []*Result{}
cweTaxa := make([]*ReportingDescriptor, 0)
weaknesses := make(map[string]*cwe.Weakness)
cweTaxa := []*ReportingDescriptor{}
weaknesses := map[string]*cwe.Weakness{}
for _, issue := range data.Issues {
if issue.Cwe != nil {
@@ -37,26 +32,26 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
}
}
r, ok := rulesIndices[issue.RuleID]
if !ok {
lastRuleIndex++
r = rule{index: lastRuleIndex, rule: parseSarifRule(issue)}
rulesIndices[issue.RuleID] = r
rules = append(rules, r.rule)
}
rule := parseSarifRule(issue)
var ruleIndex int
rules, ruleIndex = addRuleInOrder(rules, rule)
location, err := parseSarifLocation(issue, rootPaths)
if err != nil {
return nil, err
}
result := NewResult(r.rule.ID, r.index, getSarifLevel(issue.Severity.String()), issue.What, buildSarifSuppressions(issue.Suppressions)).
WithLocations(location)
result := NewResult(
issue.RuleID,
ruleIndex,
getSarifLevel(issue.Severity.String()),
issue.What,
buildSarifSuppressions(issue.Suppressions),
).WithLocations(location)
results = append(results, result)
}
sort.SliceStable(rules, func(i, j int) bool { return rules[i].ID < rules[j].ID })
sort.SliceStable(cweTaxa, func(i, j int) bool { return cweTaxa[i].ID < cweTaxa[j].ID })
tool := NewTool(buildSarifDriver(rules, data.GosecVersion))
@@ -71,29 +66,49 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
WithRuns(run), nil
}
// addRuleInOrder inserts a rule into the rules slice keeping the rules IDs order, it returns the new rules
// slice and the position where the rule was inserted
func addRuleInOrder(rules []*ReportingDescriptor, rule *ReportingDescriptor) ([]*ReportingDescriptor, int) {
position := 0
for i, r := range rules {
if r.ID < rule.ID {
continue
}
if r.ID == rule.ID {
return rules, i
}
position = i
break
}
rules = append(rules, nil)
copy(rules[position+1:], rules[position:])
rules[position] = rule
return rules, position
}
// parseSarifRule return SARIF rule field struct
func parseSarifRule(issue *gosec.Issue) *ReportingDescriptor {
cwe := gosec.GetCweByRule(issue.RuleID)
name := issue.RuleID
func parseSarifRule(i *issue.Issue) *ReportingDescriptor {
cwe := issue.GetCweByRule(i.RuleID)
name := i.RuleID
if cwe != nil {
name = cwe.Name
}
return &ReportingDescriptor{
ID: issue.RuleID,
ID: i.RuleID,
Name: name,
ShortDescription: NewMultiformatMessageString(issue.What),
FullDescription: NewMultiformatMessageString(issue.What),
ShortDescription: NewMultiformatMessageString(i.What),
FullDescription: NewMultiformatMessageString(i.What),
Help: NewMultiformatMessageString(fmt.Sprintf("%s\nSeverity: %s\nConfidence: %s\n",
issue.What, issue.Severity.String(), issue.Confidence.String())),
i.What, i.Severity.String(), i.Confidence.String())),
Properties: &PropertyBag{
"tags": []string{"security", issue.Severity.String()},
"precision": strings.ToLower(issue.Confidence.String()),
"tags": []string{"security", i.Severity.String()},
"precision": strings.ToLower(i.Confidence.String()),
},
DefaultConfiguration: &ReportingConfiguration{
Level: getSarifLevel(issue.Severity.String()),
Level: getSarifLevel(i.Severity.String()),
},
Relationships: []*ReportingDescriptorRelationship{
buildSarifReportingDescriptorRelationship(issue.Cwe),
buildSarifReportingDescriptorRelationship(i.Cwe),
},
}
}
@@ -157,27 +172,27 @@ func uuid3(value string) string {
}
// parseSarifLocation return SARIF location struct
func parseSarifLocation(issue *gosec.Issue, rootPaths []string) (*Location, error) {
region, err := parseSarifRegion(issue)
func parseSarifLocation(i *issue.Issue, rootPaths []string) (*Location, error) {
region, err := parseSarifRegion(i)
if err != nil {
return nil, err
}
artifactLocation := parseSarifArtifactLocation(issue, rootPaths)
artifactLocation := parseSarifArtifactLocation(i, rootPaths)
return NewLocation(NewPhysicalLocation(artifactLocation, region)), nil
}
func parseSarifArtifactLocation(issue *gosec.Issue, rootPaths []string) *ArtifactLocation {
func parseSarifArtifactLocation(i *issue.Issue, rootPaths []string) *ArtifactLocation {
var filePath string
for _, rootPath := range rootPaths {
if strings.HasPrefix(issue.File, rootPath) {
filePath = strings.Replace(issue.File, rootPath+"/", "", 1)
if strings.HasPrefix(i.File, rootPath) {
filePath = strings.Replace(i.File, rootPath+"/", "", 1)
}
}
return NewArtifactLocation(filePath)
}
func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
lines := strings.Split(issue.Line, "-")
func parseSarifRegion(i *issue.Issue) (*Region, error) {
lines := strings.Split(i.Line, "-")
startLine, err := strconv.Atoi(lines[0])
if err != nil {
return nil, err
@@ -189,13 +204,13 @@ func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
return nil, err
}
}
col, err := strconv.Atoi(issue.Col)
col, err := strconv.Atoi(i.Col)
if err != nil {
return nil, err
}
var code string
line := startLine
codeLines := strings.Split(issue.Code, "\n")
codeLines := strings.Split(i.Code, "\n")
for _, codeLine := range codeLines {
lineStart := fmt.Sprintf("%d:", line)
if strings.HasPrefix(codeLine, lineStart) {
@@ -227,7 +242,7 @@ func getSarifLevel(s string) Level {
}
}
func buildSarifSuppressions(suppressions []gosec.SuppressionInfo) []*Suppression {
func buildSarifSuppressions(suppressions []issue.SuppressionInfo) []*Suppression {
var sarifSuppressionList []*Suppression
for _, s := range suppressions {
sarifSuppressionList = append(sarifSuppressionList, NewSuppression(s.Kind, s.Justification))

View File

@@ -5,6 +5,7 @@ import (
"strings"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
const (
@@ -36,7 +37,7 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
return si, nil
}
func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
func parseFilePath(issue *issue.Issue, rootPaths []string) string {
var sonarFilePath string
for _, rootPath := range rootPaths {
if strings.HasPrefix(issue.File, rootPath) {
@@ -46,7 +47,7 @@ func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
return sonarFilePath
}
func parseTextRange(issue *gosec.Issue) (*TextRange, error) {
func parseTextRange(issue *issue.Issue) (*TextRange, error) {
lines := strings.Split(issue.Line, "-")
startLine, err := strconv.Atoi(lines[0])
if err != nil {

View File

@@ -11,7 +11,9 @@ import (
"text/template"
"github.com/gookit/color"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
var (
@@ -49,7 +51,7 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
// by default those functions return the given content untouched
return template.FuncMap{
"highlight": func(t string, s gosec.Score, ignored bool) string {
"highlight": func(t string, s issue.Score, ignored bool) string {
return t
},
"danger": fmt.Sprint,
@@ -60,14 +62,14 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
}
// highlight returns content t colored based on Score
func highlight(t string, s gosec.Score, ignored bool) string {
func highlight(t string, s issue.Score, ignored bool) string {
if ignored {
return defaultTheme.Sprint(t)
}
switch s {
case gosec.High:
case issue.High:
return errorTheme.Sprint(t)
case gosec.Medium:
case issue.Medium:
return warningTheme.Sprint(t)
default:
return defaultTheme.Sprint(t)
@@ -75,7 +77,7 @@ func highlight(t string, s gosec.Score, ignored bool) string {
}
// printCodeSnippet prints the code snippet from the issue by adding a marker to the affected line
func printCodeSnippet(issue *gosec.Issue) string {
func printCodeSnippet(issue *issue.Issue) string {
start, end := parseLine(issue.Line)
scanner := bufio.NewScanner(strings.NewReader(issue.Code))
var buf bytes.Buffer

View File

@@ -3,8 +3,9 @@ package yaml
import (
"io"
"github.com/securego/gosec/v2"
"gopkg.in/yaml.v3"
"github.com/securego/gosec/v2"
)
// WriteReport write a report in yaml format to the output writer

View File

@@ -66,7 +66,7 @@ func resolveBinExpr(n *ast.BinaryExpr, c *Context) bool {
return (TryResolve(n.X, c) && TryResolve(n.Y, c))
}
func resolveCallExpr(n *ast.CallExpr, c *Context) bool {
func resolveCallExpr(_ *ast.CallExpr, _ *Context) bool {
// TODO(tkelsey): next step, full function resolution
return false
}

View File

@@ -15,12 +15,14 @@ package gosec
import (
"go/ast"
"reflect"
"github.com/securego/gosec/v2/issue"
)
// The Rule interface used by all rules supported by gosec.
type Rule interface {
ID() string
Match(ast.Node, *Context) (*Issue, error)
Match(ast.Node, *Context) (*issue.Issue, error)
}
// RuleBuilder is used to register a rule definition with the analyzer
@@ -41,7 +43,7 @@ func NewRuleSet() RuleSet {
return RuleSet{make(map[reflect.Type][]Rule), make(map[string]bool)}
}
// Register adds a trigger for the supplied rule for the the
// Register adds a trigger for the supplied rule for the
// specified ast nodes.
func (r RuleSet) Register(rule Rule, isSuppressed bool, nodes ...ast.Node) {
for _, n := range nodes {

View File

@@ -5,10 +5,11 @@ import (
"go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type archive struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
argTypes []string
}
@@ -18,7 +19,7 @@ func (a *archive) ID() string {
}
// Match inspects AST nodes to determine if the filepath.Joins uses any argument derived from type zip.File or tar.Header
func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (a *archive) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := a.calls.ContainsPkgCallExpr(n, c, false); node != nil {
for _, arg := range node.Args {
var argType types.Type
@@ -38,7 +39,7 @@ func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
if argType != nil {
for _, t := range a.argTypes {
if argType.String() == t {
return gosec.NewIssue(c, n, a.ID(), a.What, a.Severity, a.Confidence), nil
return c.NewIssue(n, a.ID(), a.What, a.Severity, a.Confidence), nil
}
}
}
@@ -48,17 +49,17 @@ func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
}
// NewArchive creates a new rule which detects the file traversal when extracting zip/tar archives
func NewArchive(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewArchive(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := gosec.NewCallList()
calls.Add("path/filepath", "Join")
calls.Add("path", "Join")
return &archive{
calls: calls,
argTypes: []string{"*archive/zip.File", "*archive/tar.Header"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: "File traversal when extracting zip/tar archive",
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -1,96 +0,0 @@
package rules
import (
"fmt"
"go/ast"
"strings"
"github.com/securego/gosec/v2"
)
type deferType struct {
typ string
methods []string
}
type badDefer struct {
gosec.MetaData
types []deferType
}
func (r *badDefer) ID() string {
return r.MetaData.ID
}
func normalize(typ string) string {
return strings.TrimPrefix(typ, "*")
}
func contains(methods []string, method string) bool {
for _, m := range methods {
if m == method {
return true
}
}
return false
}
func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
if deferStmt, ok := n.(*ast.DeferStmt); ok {
for _, deferTyp := range r.types {
if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil {
if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) {
return gosec.NewIssue(c, n, r.ID(), fmt.Sprintf(r.What, method, typ), r.Severity, r.Confidence), nil
}
}
}
}
return nil, nil
}
// NewDeferredClosing detects unsafe defer of error returning methods
func NewDeferredClosing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &badDefer{
types: []deferType{
{
typ: "os.File",
methods: []string{"Close"},
},
{
typ: "io.ReadCloser",
methods: []string{"Close"},
},
{
typ: "io.WriteCloser",
methods: []string{"Close"},
},
{
typ: "io.ReadWriteCloser",
methods: []string{"Close"},
},
{
typ: "io.ReadSeekCloser",
methods: []string{"Close"},
},
{
typ: "io.Closer",
methods: []string{"Close"},
},
{
typ: "net.Conn",
methods: []string{"Close"},
},
{
typ: "net.Listener",
methods: []string{"Close"},
},
},
MetaData: gosec.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
What: "Deferring unsafe method %q on type %q",
},
}, []ast.Node{(*ast.DeferStmt)(nil)}
}

View File

@@ -19,11 +19,12 @@ import (
"regexp"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
type bindsToAllNetworkInterfaces struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
pattern *regexp.Regexp
}
@@ -32,7 +33,7 @@ func (r *bindsToAllNetworkInterfaces) ID() string {
return r.MetaData.ID
}
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
callExpr := r.calls.ContainsPkgCallExpr(n, c, false)
if callExpr == nil {
return nil, nil
@@ -42,14 +43,14 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
if bl, ok := arg.(*ast.BasicLit); ok {
if arg, err := gosec.GetString(bl); err == nil {
if r.pattern.MatchString(arg) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
} else if ident, ok := arg.(*ast.Ident); ok {
values := gosec.GetIdentStringValues(ident)
for _, value := range values {
if r.pattern.MatchString(value) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -57,7 +58,7 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
values := gosec.GetCallStringArgsValues(callExpr.Args[0], c)
for _, value := range values {
if r.pattern.MatchString(value) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -66,17 +67,17 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
// NewBindsToAllNetworkInterfaces detects socket connections that are setup to
// listen on all network interfaces.
func NewBindsToAllNetworkInterfaces(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewBindsToAllNetworkInterfaces(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := gosec.NewCallList()
calls.Add("net", "Listen")
calls.Add("crypto/tls", "Listen")
return &bindsToAllNetworkInterfaces{
calls: calls,
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: "Binds to all network interfaces",
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -19,27 +19,28 @@ import (
"strings"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type blocklistedImport struct {
gosec.MetaData
issue.MetaData
Blocklisted map[string]string
}
func unquote(original string) string {
copy := strings.TrimSpace(original)
copy = strings.TrimLeft(copy, `"`)
return strings.TrimRight(copy, `"`)
cleaned := strings.TrimSpace(original)
cleaned = strings.TrimLeft(cleaned, `"`)
return strings.TrimRight(cleaned, `"`)
}
func (r *blocklistedImport) ID() string {
return r.MetaData.ID
}
func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node, ok := n.(*ast.ImportSpec); ok {
if description, ok := r.Blocklisted[unquote(node.Path.Value)]; ok {
return gosec.NewIssue(c, node, r.ID(), description, r.Severity, r.Confidence), nil
return c.NewIssue(node, r.ID(), description, r.Severity, r.Confidence), nil
}
}
return nil, nil
@@ -47,12 +48,12 @@ func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, e
// NewBlocklistedImports reports when a blocklisted import is being used.
// Typically when a deprecated technology is being used.
func NewBlocklistedImports(id string, conf gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) {
func NewBlocklistedImports(id string, _ gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) {
return &blocklistedImport{
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
},
Blocklisted: blocklist,
}, []ast.Node{(*ast.ImportSpec)(nil)}

View File

@@ -19,10 +19,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type decompressionBombCheck struct {
gosec.MetaData
issue.MetaData
readerCalls gosec.CallList
copyCalls gosec.CallList
}
@@ -40,7 +41,7 @@ func containsReaderCall(node ast.Node, ctx *gosec.Context, list gosec.CallList)
return list.Contains(s, idt)
}
func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
var readerVarObj map[*ast.Object]struct{}
// To check multiple lines, ctx.PassedValues is used to store temporary data.
@@ -72,7 +73,7 @@ func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gose
if idt, ok := n.Args[1].(*ast.Ident); ok {
if _, ok := readerVarObj[idt.Obj]; ok {
// Detect io.Copy(x, r)
return gosec.NewIssue(ctx, n, d.ID(), d.What, d.Severity, d.Confidence), nil
return ctx.NewIssue(n, d.ID(), d.What, d.Severity, d.Confidence), nil
}
}
}
@@ -82,7 +83,7 @@ func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gose
}
// NewDecompressionBombCheck detects if there is potential DoS vulnerability via decompression bomb
func NewDecompressionBombCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewDecompressionBombCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
readerCalls := gosec.NewCallList()
readerCalls.Add("compress/gzip", "NewReader")
readerCalls.AddAll("compress/zlib", "NewReader", "NewReaderDict")
@@ -98,10 +99,10 @@ func NewDecompressionBombCheck(id string, conf gosec.Config) (gosec.Rule, []ast.
copyCalls.Add("io", "CopyBuffer")
return &decompressionBombCheck{
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.Medium,
Severity: issue.Medium,
Confidence: issue.Medium,
What: "Potential DoS vulnerability via decompression bomb",
},
readerCalls: readerCalls,

View File

@@ -5,18 +5,19 @@ import (
"regexp"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type traversal struct {
pattern *regexp.Regexp
gosec.MetaData
issue.MetaData
}
func (r *traversal) ID() string {
return r.MetaData.ID
}
func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) {
case *ast.CallExpr:
return r.matchCallExpr(node, ctx)
@@ -24,14 +25,14 @@ func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error)
return nil, nil
}
func (r *traversal) matchCallExpr(assign *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *traversal) matchCallExpr(assign *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
for _, i := range assign.Args {
if basiclit, ok1 := i.(*ast.BasicLit); ok1 {
if fun, ok2 := assign.Fun.(*ast.SelectorExpr); ok2 {
if x, ok3 := fun.X.(*ast.Ident); ok3 {
string := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")"
if r.pattern.MatchString(string) {
return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil
str := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")"
if r.pattern.MatchString(str) {
return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -54,11 +55,11 @@ func NewDirectoryTraversal(id string, conf gosec.Config) (gosec.Rule, []ast.Node
return &traversal{
pattern: regexp.MustCompile(pattern),
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Potential directory traversal",
Confidence: gosec.Medium,
Severity: gosec.Medium,
Confidence: issue.Medium,
Severity: issue.Medium,
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

View File

@@ -19,10 +19,11 @@ import (
"go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type noErrorCheck struct {
gosec.MetaData
issue.MetaData
whitelist gosec.CallList
}
@@ -49,7 +50,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gosec.Context) int {
return -1
}
func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch stmt := n.(type) {
case *ast.AssignStmt:
cfg := ctx.Config
@@ -61,7 +62,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
return nil, nil
}
if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" {
return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return ctx.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -70,7 +71,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
pos := returnsError(callExpr, ctx)
if pos >= 0 {
return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return ctx.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -100,10 +101,10 @@ func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
}
return &noErrorCheck{
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Low,
Confidence: gosec.High,
Severity: issue.Low,
Confidence: issue.High,
What: "Errors unhandled.",
},
whitelist: whitelist,

View File

@@ -20,10 +20,11 @@ import (
"strconv"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type filePermissions struct {
gosec.MetaData
issue.MetaData
mode int64
pkgs []string
calls []string
@@ -54,12 +55,12 @@ func modeIsSubset(subset int64, superset int64) bool {
return (subset | superset) == superset
}
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, pkg := range r.pkgs {
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
modeArg := callexpr.Args[len(callexpr.Args)-1]
if mode, err := gosec.GetInt(modeArg); err == nil && !modeIsSubset(mode, r.mode) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -73,10 +74,10 @@ func NewWritePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode: mode,
pkgs: []string{"io/ioutil", "os"},
calls: []string{"WriteFile"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode),
},
}, []ast.Node{(*ast.CallExpr)(nil)}
@@ -90,10 +91,10 @@ func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode: mode,
pkgs: []string{"os"},
calls: []string{"OpenFile", "Chmod"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
},
}, []ast.Node{(*ast.CallExpr)(nil)}
@@ -107,10 +108,10 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode: mode,
pkgs: []string{"os"},
calls: []string{"Mkdir", "MkdirAll"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -20,13 +20,16 @@ import (
"regexp"
"strconv"
zxcvbn "github.com/nbutton23/zxcvbn-go"
zxcvbn "github.com/ccojocar/zxcvbn-go"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type credentials struct {
gosec.MetaData
issue.MetaData
pattern *regexp.Regexp
patternValue *regexp.Regexp // Pattern for matching string values (LHS on assign statements)
entropyThreshold float64
perCharThreshold float64
truncate int
@@ -53,7 +56,7 @@ func (r *credentials) isHighEntropyString(str string) bool {
entropyPerChar >= r.perCharThreshold))
}
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) {
case *ast.AssignStmt:
return r.matchAssign(node, ctx)
@@ -65,24 +68,41 @@ func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error
return nil, nil
}
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*issue.Issue, error) {
for _, i := range assign.Lhs {
if ident, ok := i.(*ast.Ident); ok {
// First check LHS to find anything being assigned to variables whose name appears to be a cred
if r.pattern.MatchString(ident.Name) {
for _, e := range assign.Rhs {
if val, err := gosec.GetString(e); err == nil {
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil
return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
}
// Now that no names were matched, match the RHS to see if the actual values being assigned are creds
for _, e := range assign.Rhs {
val, err := gosec.GetString(e)
if err != nil {
continue
}
if r.patternValue.MatchString(val) {
if r.ignoreEntropy || r.isHighEntropyString(val) {
return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
}
}
return nil, nil
}
func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*issue.Issue, error) {
// Running match against the variable name(s) first. Will catch any creds whose var name matches the pattern,
// then will go back over to check the values themselves.
for index, ident := range valueSpec.Names {
if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil {
// const foo, bar = "same value"
@@ -91,15 +111,27 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
}
if val, err := gosec.GetString(valueSpec.Values[index]); err == nil {
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
return gosec.NewIssue(ctx, valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
return ctx.NewIssue(valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
}
// Now that no variable names have been matched, match the actual values to find any creds
for _, ident := range valueSpec.Values {
if val, err := gosec.GetString(ident); err == nil {
if r.patternValue.MatchString(val) {
if r.ignoreEntropy || r.isHighEntropyString(val) {
return ctx.NewIssue(valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
}
return nil, nil
}
func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*issue.Issue, error) {
if binaryExpr.Op == token.EQL || binaryExpr.Op == token.NEQ {
ident, ok := binaryExpr.X.(*ast.Ident)
if !ok {
@@ -113,7 +145,23 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
}
if val, err := gosec.GetString(valueNode); err == nil {
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
return gosec.NewIssue(ctx, binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
return ctx.NewIssue(binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
// Now that the variable names have been checked, and no matches were found, make sure that
// either the left or right operands is a string literal so we can match the value.
identStrConst, ok := binaryExpr.X.(*ast.BasicLit)
if !ok {
identStrConst, ok = binaryExpr.Y.(*ast.BasicLit)
}
if ok && identStrConst.Kind == token.STRING {
s, _ := gosec.GetString(identStrConst)
if r.patternValue.MatchString(s) {
if r.ignoreEntropy || r.isHighEntropyString(s) {
return ctx.NewIssue(binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -125,6 +173,7 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
// assigned to variables that appear to be related to credentials.
func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
pattern := `(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred`
patternValue := "(?i)(^(.*[:;,](\\s)*)?[a-f0-9]{64}$)|(AIza[0-9A-Za-z-_]{35})|(^(.*[:;,](\\s)*)?github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}$)|(^(.*[:;,](\\s)*)?[0-9a-zA-Z-_]{24}$)"
entropyThreshold := 80.0
perCharThreshold := 3.0
ignoreEntropy := false
@@ -136,6 +185,13 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
pattern = cfgPattern
}
}
if configPatternValue, ok := conf["patternValue"]; ok {
if cfgPatternValue, ok := configPatternValue.(string); ok {
patternValue = cfgPatternValue
}
}
if configIgnoreEntropy, ok := conf["ignore_entropy"]; ok {
if cfgIgnoreEntropy, ok := configIgnoreEntropy.(bool); ok {
ignoreEntropy = cfgIgnoreEntropy
@@ -166,15 +222,16 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
return &credentials{
pattern: regexp.MustCompile(pattern),
patternValue: regexp.MustCompile(patternValue),
entropyThreshold: entropyThreshold,
perCharThreshold: perCharThreshold,
ignoreEntropy: ignoreEntropy,
truncate: truncateString,
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Potential hardcoded credentials",
Confidence: gosec.Low,
Severity: gosec.High,
Confidence: issue.Low,
Severity: issue.High,
},
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)}
}

View File

@@ -4,10 +4,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type httpServeWithoutTimeouts struct {
gosec.MetaData
issue.MetaData
pkg string
calls []string
}
@@ -16,23 +17,23 @@ func (r *httpServeWithoutTimeouts) ID() string {
return r.MetaData.ID
}
func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
return nil, nil
}
// NewHTTPServeWithoutTimeouts detects use of net/http serve functions that have no support for setting timeouts.
func NewHTTPServeWithoutTimeouts(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewHTTPServeWithoutTimeouts(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &httpServeWithoutTimeouts{
pkg: "net/http",
calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Use of net/http serve function that has no support for setting timeouts",
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

View File

@@ -5,10 +5,11 @@ import (
"go/token"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type implicitAliasing struct {
gosec.MetaData
issue.MetaData
aliases map[*ast.Object]struct{}
rightBrace token.Pos
acceptableAlias []*ast.UnaryExpr
@@ -27,7 +28,27 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
return false
}
func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func getIdentExpr(expr ast.Expr) *ast.Ident {
switch node := expr.(type) {
case *ast.Ident:
return node
case *ast.SelectorExpr:
return getIdentExpr(node.X)
case *ast.UnaryExpr:
switch e := node.X.(type) {
case *ast.Ident:
return e
case *ast.SelectorExpr:
return getIdentExpr(e.X)
default:
return nil
}
default:
return nil
}
}
func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) {
case *ast.RangeStmt:
// When presented with a range statement, get the underlying Object bound to
@@ -71,9 +92,9 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, er
}
// If we find a unary op of & (reference) of an object within r.aliases, complain.
if ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" {
if _, contains := r.aliases[ident.Obj]; contains {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
if identExpr := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" {
if _, contains := r.aliases[identExpr.Obj]; contains {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
case *ast.ReturnStmt:
@@ -89,15 +110,15 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, er
}
// NewImplicitAliasing detects implicit memory aliasing of type: for blah := SomeCall() {... SomeOtherCall(&blah) ...}
func NewImplicitAliasing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewImplicitAliasing(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &implicitAliasing{
aliases: make(map[*ast.Object]struct{}),
rightBrace: token.NoPos,
acceptableAlias: make([]*ast.UnaryExpr, 0),
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.Medium,
Severity: issue.Medium,
Confidence: issue.Medium,
What: "Implicit memory aliasing in for loop.",
},
}, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)}

View File

@@ -19,10 +19,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type integerOverflowCheck struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
}
@@ -30,7 +31,7 @@ func (i *integerOverflowCheck) ID() string {
return i.MetaData.ID
}
func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
var atoiVarObj map[*ast.Object]ast.Node
// To check multiple lines, ctx.PassedValues is used to store temporary data.
@@ -63,7 +64,7 @@ func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.
if idt, ok := n.Args[0].(*ast.Ident); ok {
if _, ok := atoiVarObj[idt.Obj]; ok {
// Detect int32(v) and int16(v)
return gosec.NewIssue(ctx, n, i.ID(), i.What, i.Severity, i.Confidence), nil
return ctx.NewIssue(n, i.ID(), i.What, i.Severity, i.Confidence), nil
}
}
}
@@ -74,14 +75,14 @@ func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.
}
// NewIntegerOverflowCheck detects if there is potential Integer OverFlow
func NewIntegerOverflowCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewIntegerOverflowCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := gosec.NewCallList()
calls.Add("strconv", "Atoi")
return &integerOverflowCheck{
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.High,
Confidence: gosec.Medium,
Severity: issue.High,
Confidence: issue.Medium,
What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32",
},
calls: calls,

View File

@@ -4,10 +4,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type usingOldMathBig struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
}
@@ -15,18 +16,18 @@ func (r *usingOldMathBig) ID() string {
return r.MetaData.ID
}
func (r *usingOldMathBig) Match(node ast.Node, ctx *gosec.Context) (gi *gosec.Issue, err error) {
func (r *usingOldMathBig) Match(node ast.Node, ctx *gosec.Context) (gi *issue.Issue, err error) {
if callExpr := r.calls.ContainsPkgCallExpr(node, ctx, false); callExpr == nil {
return nil, nil
}
confidence := gosec.Low
confidence := issue.Low
major, minor, build := gosec.GoVersion()
if major == 1 && (minor == 16 && build < 14 || minor == 17 && build < 7) {
confidence = gosec.Medium
confidence = issue.Medium
}
return gosec.NewIssue(ctx, node, r.ID(), r.What, r.Severity, confidence), nil
return ctx.NewIssue(node, r.ID(), r.What, r.Severity, confidence), nil
}
// NewUsingOldMathBig rule detects the use of Rat.SetString from math/big.
@@ -35,10 +36,10 @@ func NewUsingOldMathBig(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls.Add("math/big.Rat", "SetString")
return &usingOldMathBig{
calls: calls,
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)",
Severity: gosec.High,
Severity: issue.High,
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

View File

@@ -4,10 +4,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type pprofCheck struct {
gosec.MetaData
issue.MetaData
importPath string
importName string
}
@@ -18,22 +19,22 @@ func (p *pprofCheck) ID() string {
}
// Match checks for pprof imports
func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node, ok := n.(*ast.ImportSpec); ok {
if p.importPath == unquote(node.Path.Value) && node.Name != nil && p.importName == node.Name.Name {
return gosec.NewIssue(c, node, p.ID(), p.What, p.Severity, p.Confidence), nil
return c.NewIssue(node, p.ID(), p.What, p.Severity, p.Confidence), nil
}
}
return nil, nil
}
// NewPprofCheck detects when the profiling endpoint is automatically exposed
func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewPprofCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &pprofCheck{
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.High,
Confidence: gosec.High,
Severity: issue.High,
Confidence: issue.High,
What: "Profiling endpoint is automatically exposed on /debug/pprof",
},
importPath: "net/http/pprof",

View File

@@ -18,10 +18,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type weakRand struct {
gosec.MetaData
issue.MetaData
funcNames []string
packagePath string
}
@@ -30,10 +31,10 @@ func (w *weakRand) ID() string {
return w.MetaData.ID
}
func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, funcName := range w.funcNames {
if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil
return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
}
}
@@ -41,17 +42,17 @@ func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
}
// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
func NewWeakRandCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewWeakRandCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &weakRand{
funcNames: []string{
"New", "Read", "Float32", "Float64", "Int", "Int31",
"Int31n", "Int63", "Int63n", "Intn", "NormalFloat64", "Uint32", "Uint64",
},
packagePath: "math/rand",
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.High,
Confidence: gosec.Medium,
Severity: issue.High,
Confidence: issue.Medium,
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -19,10 +19,11 @@ import (
"go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type readfile struct {
gosec.MetaData
issue.MetaData
gosec.CallList
pathJoin gosec.CallList
clean gosec.CallList
@@ -80,13 +81,17 @@ func (r *readfile) isFilepathClean(n *ast.Ident, c *gosec.Context) bool {
func (r *readfile) trackFilepathClean(n ast.Node) {
if clean, ok := n.(*ast.CallExpr); ok && len(clean.Args) > 0 {
if ident, ok := clean.Args[0].(*ast.Ident); ok {
// ident.Obj may be nil if the referenced declaration is in another file. It also may be incorrect.
// if it is nil, do not follow it.
if ident.Obj != nil {
r.cleanedVar[ident.Obj.Decl] = n
}
}
}
}
// Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile`
func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := r.clean.ContainsPkgCallExpr(n, c, false); node != nil {
r.trackFilepathClean(n)
return nil, nil
@@ -96,14 +101,14 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
// eg. os.Open(filepath.Join("/tmp/", file))
if callExpr, ok := arg.(*ast.CallExpr); ok {
if r.isJoinFunc(callExpr, c) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
if binExp, ok := arg.(*ast.BinaryExpr); ok {
// resolve all found identities from the BinaryExpr
if _, ok := gosec.FindVarIdentities(binExp, c); ok {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
@@ -112,7 +117,7 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
if _, ok := obj.(*types.Var); ok &&
!gosec.TryResolve(ident, c) &&
!r.isFilepathClean(ident, c) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -121,16 +126,16 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
}
// NewReadFile detects cases where we read files
func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewReadFile(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
rule := &readfile{
pathJoin: gosec.NewCallList(),
clean: gosec.NewCallList(),
CallList: gosec.NewCallList(),
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Potential file inclusion via variable",
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
},
cleanedVar: map[any]ast.Node{},
}

View File

@@ -19,10 +19,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type weakKeyStrength struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
bits int
}
@@ -31,27 +32,27 @@ func (w *weakKeyStrength) ID() string {
return w.MetaData.ID
}
func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if callExpr := w.calls.ContainsPkgCallExpr(n, c, false); callExpr != nil {
if bits, err := gosec.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil
return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
}
}
return nil, nil
}
// NewWeakKeyStrength builds a rule that detects RSA keys < 2048 bits
func NewWeakKeyStrength(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewWeakKeyStrength(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := gosec.NewCallList()
calls.Add("crypto/rsa", "GenerateKey")
bits := 2048
return &weakKeyStrength{
calls: calls,
bits: bits,
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -91,7 +91,6 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
{"G304", "File path provided as taint input", NewReadFile},
{"G305", "File path traversal when extracting zip archive", NewArchive},
{"G306", "Poor file permissions used when writing to a file", NewWritePerms},
{"G307", "Unsafe defer call of a method returning an error", NewDeferredClosing},
// crypto
{"G401", "Detect the usage of DES, RC4, MD5 or SHA1", NewUsesWeakCryptography},
@@ -108,6 +107,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
// memory safety
{"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing},
{"G602", "Slice access out of bounds", NewSliceBoundCheck},
}
ruleMap := make(map[string]RuleDefinition)

View File

@@ -0,0 +1,405 @@
package rules
import (
"fmt"
"go/ast"
"go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
// sliceOutOfBounds is a rule which checks for slices which are accessed outside their capacity,
// either through indexing it out of bounds or through slice expressions whose low or high index
// are out of bounds.
type sliceOutOfBounds struct {
sliceCaps map[*ast.CallExpr]map[string]*int64 // Capacities of slices. Maps function call -> var name -> value.
currentScope *types.Scope // Current scope. Map is cleared when scope changes.
currentFuncName string // Current function.
funcCallArgs map[string][]*int64 // Caps to load once a func declaration is scanned.
issue.MetaData // Metadata for this rule.
}
// ID returns the rule ID for sliceOutOfBounds: G602.
func (s *sliceOutOfBounds) ID() string {
return s.MetaData.ID
}
func (s *sliceOutOfBounds) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
if s.currentScope == nil {
s.currentScope = ctx.Pkg.Scope()
} else if s.currentScope != ctx.Pkg.Scope() {
s.currentScope = ctx.Pkg.Scope()
// Clear slice map, since we are in a new scope
sliceMapNil := make(map[string]*int64)
sliceCaps := make(map[*ast.CallExpr]map[string]*int64)
sliceCaps[nil] = sliceMapNil
s.sliceCaps = sliceCaps
}
switch node := node.(type) {
case *ast.AssignStmt:
return s.matchAssign(node, ctx)
case *ast.SliceExpr:
return s.matchSliceExpr(node, ctx)
case *ast.IndexExpr:
return s.matchIndexExpr(node, ctx)
case *ast.FuncDecl:
s.currentFuncName = node.Name.Name
s.loadArgCaps(node)
case *ast.CallExpr:
if _, ok := node.Fun.(*ast.FuncLit); ok {
// Do nothing with func literals for now.
break
}
sliceMap := make(map[string]*int64)
s.sliceCaps[node] = sliceMap
s.setupCallArgCaps(node, ctx)
}
return nil, nil
}
// updateSliceCaps takes in a variable name and a map of calls we are updating the variables for to the updated values
// and will add it to the sliceCaps map.
func (s *sliceOutOfBounds) updateSliceCaps(varName string, caps map[*ast.CallExpr]*int64) {
for callExpr, cap := range caps {
s.sliceCaps[callExpr][varName] = cap
}
}
// getAllCalls returns all CallExprs that are calls to the given function.
func (s *sliceOutOfBounds) getAllCalls(funcName string, ctx *gosec.Context) []*ast.CallExpr {
calls := []*ast.CallExpr{}
for callExpr := range s.sliceCaps {
if callExpr != nil {
// Compare the names of the function the code is scanning with the current call we are iterating over
_, callFuncName, err := gosec.GetCallInfo(callExpr, ctx)
if err != nil {
continue
}
if callFuncName == funcName {
calls = append(calls, callExpr)
}
}
}
return calls
}
// getSliceCapsForFunc gets all the capacities for slice with given name that are stored for each call to the passed function.
func (s *sliceOutOfBounds) getSliceCapsForFunc(funcName string, varName string, ctx *gosec.Context) map[*ast.CallExpr]*int64 {
caps := make(map[*ast.CallExpr]*int64)
calls := s.getAllCalls(funcName, ctx)
for _, call := range calls {
if callCaps, ok := s.sliceCaps[call]; ok {
caps[call] = callCaps[varName]
}
}
return caps
}
// setupCallArgCaps evaluates and saves the caps for any slices in the args so they can be validated when the function is scanned.
func (s *sliceOutOfBounds) setupCallArgCaps(callExpr *ast.CallExpr, ctx *gosec.Context) {
// Array of caps to be loaded once the function declaration is scanned
funcCallArgs := []*int64{}
// Get function name
_, funcName, err := gosec.GetCallInfo(callExpr, ctx)
if err != nil {
return
}
for _, arg := range callExpr.Args {
switch node := arg.(type) {
case *ast.SliceExpr:
caps := s.evaluateSliceExpr(node, ctx)
// Simplifying assumption: use the lowest capacity. Storing all possible capacities for slices passed
// to a function call would catch the most issues, but would require a data structure like a stack and a
// reworking of the code for scanning itself. Use the lowest capacity, as this would be more likely to
// raise an issue for being out of bounds.
var lowestCap *int64
for _, cap := range caps {
if cap == nil {
continue
}
if lowestCap == nil {
lowestCap = cap
} else if *lowestCap > *cap {
lowestCap = cap
}
}
if lowestCap == nil {
funcCallArgs = append(funcCallArgs, nil)
continue
}
// Now create a map of just this value to add it to the sliceCaps
funcCallArgs = append(funcCallArgs, lowestCap)
case *ast.Ident:
ident := arg.(*ast.Ident)
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
var lowestCap *int64
for _, cap := range caps {
if cap == nil {
continue
}
if lowestCap == nil {
lowestCap = cap
} else if *lowestCap > *cap {
lowestCap = cap
}
}
if lowestCap == nil {
funcCallArgs = append(funcCallArgs, nil)
continue
}
// Now create a map of just this value to add it to the sliceCaps
funcCallArgs = append(funcCallArgs, lowestCap)
default:
funcCallArgs = append(funcCallArgs, nil)
}
}
s.funcCallArgs[funcName] = funcCallArgs
}
// loadArgCaps loads caps that were saved for a call to this function.
func (s *sliceOutOfBounds) loadArgCaps(funcDecl *ast.FuncDecl) {
sliceMap := make(map[string]*int64)
funcName := funcDecl.Name.Name
// Create a dummmy call expr for the new function. This is so we can still store args for
// functions which are not explicitly called in the code by other functions (specifically, main).
ident := ast.NewIdent(funcName)
dummyCallExpr := ast.CallExpr{
Fun: ident,
}
argCaps, ok := s.funcCallArgs[funcName]
if !ok || len(argCaps) == 0 {
s.sliceCaps[&dummyCallExpr] = sliceMap
return
}
params := funcDecl.Type.Params.List
if len(params) > len(argCaps) {
return // Length of params and args doesn't match, so don't do anything with this.
}
for it := range params {
capacity := argCaps[it]
if capacity == nil {
continue
}
if len(params[it].Names) == 0 {
continue
}
if paramName := params[it].Names[0]; paramName != nil {
sliceMap[paramName.Name] = capacity
}
}
s.sliceCaps[&dummyCallExpr] = sliceMap
}
// matchSliceMake matches calls to make() and stores the capacity of the new slice in the map to compare against future slice usage.
func (s *sliceOutOfBounds) matchSliceMake(funcCall *ast.CallExpr, sliceName string, ctx *gosec.Context) (*issue.Issue, error) {
_, funcName, err := gosec.GetCallInfo(funcCall, ctx)
if err != nil || funcName != "make" {
return nil, nil
}
var capacityArg int
if len(funcCall.Args) < 2 {
return nil, nil // No size passed
} else if len(funcCall.Args) == 2 {
capacityArg = 1
} else if len(funcCall.Args) == 3 {
capacityArg = 2
} else {
return nil, nil // Unexpected, args should always be 2 or 3
}
// Check and get the capacity of the slice passed to make. It must be a literal value, since we aren't evaluating the expression.
sliceCapLit, ok := funcCall.Args[capacityArg].(*ast.BasicLit)
if !ok {
return nil, nil
}
capacity, err := gosec.GetInt(sliceCapLit)
if err != nil {
return nil, nil
}
caps := s.getSliceCapsForFunc(s.currentFuncName, sliceName, ctx)
for callExpr := range caps {
caps[callExpr] = &capacity
}
s.updateSliceCaps(sliceName, caps)
return nil, nil
}
// evaluateSliceExpr takes a slice expression and evaluates what the capacity of said slice is for each of the
// calls to the current function. Returns map of the call expressions of each call to the current function to
// the evaluated capacities.
func (s *sliceOutOfBounds) evaluateSliceExpr(node *ast.SliceExpr, ctx *gosec.Context) map[*ast.CallExpr]*int64 {
// Get ident to get name
ident, ok := node.X.(*ast.Ident)
if !ok {
return nil
}
// Get cap of old slice to calculate this new slice's cap
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
for callExpr, oldCap := range caps {
if oldCap == nil {
continue
}
// Get and check low value
lowIdent, ok := node.Low.(*ast.BasicLit)
if ok && lowIdent != nil {
low, _ := gosec.GetInt(lowIdent)
newCap := *oldCap - low
caps[callExpr] = &newCap
} else if lowIdent == nil { // If no lower bound, capacity will be same
continue
}
}
return caps
}
// matchSliceAssignment matches slice assignments, calculates capacity of slice if possible to store it in map.
func (s *sliceOutOfBounds) matchSliceAssignment(node *ast.SliceExpr, sliceName string, ctx *gosec.Context) (*issue.Issue, error) {
// First do the normal match that verifies the slice expr is not out of bounds
if i, err := s.matchSliceExpr(node, ctx); err != nil {
return i, fmt.Errorf("There was an error while matching a slice expression to check slice bounds for %s: %w", sliceName, err)
}
// Now that the assignment is (presumably) successfully, we can calculate the capacity and add this new slice to the map
caps := s.evaluateSliceExpr(node, ctx)
s.updateSliceCaps(sliceName, caps)
return nil, nil
}
// matchAssign matches checks if an assignment statement is making a slice, or if it is assigning a slice.
func (s *sliceOutOfBounds) matchAssign(node *ast.AssignStmt, ctx *gosec.Context) (*issue.Issue, error) {
// Check RHS for calls to make() so we can get the actual size of the slice
for it, i := range node.Rhs {
// Get the slice name so we can associate the cap with the slice in the map
sliceIdent, ok := node.Lhs[it].(*ast.Ident)
if !ok {
return nil, nil
}
sliceName := sliceIdent.Name
switch expr := i.(type) {
case *ast.CallExpr: // Check for and handle call to make()
return s.matchSliceMake(expr, sliceName, ctx)
case *ast.SliceExpr: // Handle assignments to a slice
return s.matchSliceAssignment(expr, sliceName, ctx)
}
}
return nil, nil
}
// matchSliceExpr validates that a given slice expression (eg, slice[10:30]) is not out of bounds.
func (s *sliceOutOfBounds) matchSliceExpr(node *ast.SliceExpr, ctx *gosec.Context) (*issue.Issue, error) {
// First get the slice name so we can check the size in our map
ident, ok := node.X.(*ast.Ident)
if !ok {
return nil, nil
}
// Get slice cap from the map to compare it against high and low
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
for _, cap := range caps {
if cap == nil {
continue
}
// Get and check high value
highIdent, ok := node.High.(*ast.BasicLit)
if ok && highIdent != nil {
high, _ := gosec.GetInt(highIdent)
if high > *cap {
return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
}
}
// Get and check low value
lowIdent, ok := node.Low.(*ast.BasicLit)
if ok && lowIdent != nil {
low, _ := gosec.GetInt(lowIdent)
if low > *cap {
return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
}
}
}
return nil, nil
}
// matchIndexExpr validates that an index into a slice is not out of bounds.
func (s *sliceOutOfBounds) matchIndexExpr(node *ast.IndexExpr, ctx *gosec.Context) (*issue.Issue, error) {
// First get the slice name so we can check the size in our map
ident, ok := node.X.(*ast.Ident)
if !ok {
return nil, nil
}
// Get slice cap from the map to compare it against high and low
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
for _, cap := range caps {
if cap == nil {
continue
}
// Get the index literal
indexIdent, ok := node.Index.(*ast.BasicLit)
if ok && indexIdent != nil {
index, _ := gosec.GetInt(indexIdent)
if index >= *cap {
return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
}
}
}
return nil, nil
}
// NewSliceBoundCheck attempts to find any slices being accessed out of bounds
// by reslicing or by being indexed.
func NewSliceBoundCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
sliceMap := make(map[*ast.CallExpr]map[string]*int64)
return &sliceOutOfBounds{
sliceCaps: sliceMap,
currentFuncName: "",
funcCallArgs: make(map[string][]*int64),
MetaData: issue.MetaData{
ID: id,
Severity: issue.Medium,
Confidence: issue.Medium,
What: "Potentially accessing slice out of bounds",
},
}, []ast.Node{(*ast.CallExpr)(nil), (*ast.FuncDecl)(nil), (*ast.AssignStmt)(nil), (*ast.SliceExpr)(nil), (*ast.IndexExpr)(nil)}
}

View File

@@ -18,10 +18,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type slowloris struct {
gosec.MetaData
issue.MetaData
}
func (r *slowloris) ID() string {
@@ -44,13 +45,13 @@ func containsReadHeaderTimeout(node *ast.CompositeLit) bool {
return false
}
func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) {
case *ast.CompositeLit:
actualType := ctx.Info.TypeOf(node.Type)
if actualType != nil && actualType.String() == "net/http.Server" {
if !containsReadHeaderTimeout(node) {
return gosec.NewIssue(ctx, node, r.ID(), r.What, r.Severity, r.Confidence), nil
return ctx.NewIssue(node, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
@@ -58,13 +59,13 @@ func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error)
}
// NewSlowloris attempts to find the http.Server struct and check if the ReadHeaderTimeout is configured.
func NewSlowloris(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewSlowloris(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &slowloris{
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server",
Confidence: gosec.Low,
Severity: gosec.Medium,
Confidence: issue.Low,
Severity: issue.Medium,
},
}, []ast.Node{(*ast.CompositeLit)(nil)}
}

View File

@@ -20,10 +20,11 @@ import (
"regexp"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type sqlStatement struct {
gosec.MetaData
issue.MetaData
gosec.CallList
// Contains a list of patterns which must all match for the rule to match.
@@ -97,6 +98,32 @@ func (s *sqlStrConcat) ID() string {
return s.MetaData.ID
}
// findInjectionInBranch walks diwb a set if expressions, and will create new issues if it finds SQL injections
// This method assumes you've already verified that the branch contains SQL syntax
func (s *sqlStrConcat) findInjectionInBranch(ctx *gosec.Context, branch []ast.Expr) *ast.BinaryExpr {
for _, node := range branch {
be, ok := node.(*ast.BinaryExpr)
if !ok {
continue
}
operands := gosec.GetBinaryExprOperands(be)
for _, op := range operands {
if _, ok := op.(*ast.BasicLit); ok {
continue
}
if ident, ok := op.(*ast.Ident); ok && s.checkObject(ident, ctx) {
continue
}
return be
}
}
return nil
}
// see if we can figure out what it is
func (s *sqlStrConcat) checkObject(n *ast.Ident, c *gosec.Context) bool {
if n.Obj != nil {
@@ -113,7 +140,7 @@ func (s *sqlStrConcat) checkObject(n *ast.Ident, c *gosec.Context) bool {
}
// checkQuery verifies if the query parameters is a string concatenation
func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) {
func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
query, err := findQueryArg(call, ctx)
if err != nil {
return nil, err
@@ -134,7 +161,29 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
if op, ok := op.(*ast.Ident); ok && s.checkObject(op, ctx) {
continue
}
return gosec.NewIssue(ctx, be, s.ID(), s.What, s.Severity, s.Confidence), nil
return ctx.NewIssue(be, s.ID(), s.What, s.Severity, s.Confidence), nil
}
}
}
// Handle the case where an injection occurs as an infixed string concatenation, ie "SELECT * FROM foo WHERE name = '" + os.Args[0] + "' AND 1=1"
if id, ok := query.(*ast.Ident); ok {
var match bool
for _, str := range gosec.GetIdentStringValuesRecursive(id) {
if s.MatchPatterns(str) {
match = true
break
}
}
if !match {
return nil, nil
}
switch decl := id.Obj.Decl.(type) {
case *ast.AssignStmt:
if injection := s.findInjectionInBranch(ctx, decl.Rhs); injection != nil {
return ctx.NewIssue(injection, s.ID(), s.What, s.Severity, s.Confidence), nil
}
}
}
@@ -143,7 +192,7 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
}
// Checks SQL query concatenation issues such as "SELECT * FROM table WHERE " + " ' OR 1=1"
func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch stmt := n.(type) {
case *ast.AssignStmt:
for _, expr := range stmt.Rhs {
@@ -156,20 +205,21 @@ func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
return s.checkQuery(sqlQueryCall, ctx)
}
}
return nil, nil
}
// NewSQLStrConcat looks for cases where we are building SQL strings via concatenation
func NewSQLStrConcat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewSQLStrConcat(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
rule := &sqlStrConcat{
sqlStatement: sqlStatement{
patterns: []*regexp.Regexp{
regexp.MustCompile(`(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
regexp.MustCompile("(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE)( |\n|\r|\t)"),
},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: "SQL string concatenation",
},
CallList: gosec.NewCallList(),
@@ -212,7 +262,7 @@ func (s *sqlStrFormat) constObject(e ast.Expr, c *gosec.Context) bool {
return false
}
func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) {
func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
query, err := findQueryArg(call, ctx)
if err != nil {
return nil, err
@@ -233,7 +283,7 @@ func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
return nil, nil
}
func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *gosec.Issue {
func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *issue.Issue {
// argIndex changes the function argument which gets matched to the regex
argIndex := 0
if node := s.fmtCalls.ContainsPkgCallExpr(n, ctx, false); node != nil {
@@ -286,14 +336,14 @@ func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *gosec.Is
}
}
if s.MatchPatterns(formatter) {
return gosec.NewIssue(ctx, n, s.ID(), s.What, s.Severity, s.Confidence)
return ctx.NewIssue(n, s.ID(), s.What, s.Severity, s.Confidence)
}
}
return nil
}
// Check SQL query formatting issues such as "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch stmt := n.(type) {
case *ast.AssignStmt:
for _, expr := range stmt.Rhs {
@@ -323,7 +373,7 @@ func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
}
// NewSQLStrFormat looks for cases where we're building SQL query strings using format strings
func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewSQLStrFormat(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
rule := &sqlStrFormat{
CallList: gosec.NewCallList(),
fmtCalls: gosec.NewCallList(),
@@ -334,10 +384,10 @@ func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
regexp.MustCompile("(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE)( |\n|\r|\t)"),
regexp.MustCompile("%[^bdoxXfFp]"),
},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: "SQL string formatting",
},
},

View File

@@ -4,10 +4,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type sshHostKey struct {
gosec.MetaData
issue.MetaData
pkg string
calls []string
}
@@ -16,23 +17,23 @@ func (r *sshHostKey) ID() string {
return r.MetaData.ID
}
func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
return nil, nil
}
// NewSSHHostKey rule detects the use of insecure ssh HostKeyCallback.
func NewSSHHostKey(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewSSHHostKey(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &sshHostKey{
pkg: "golang.org/x/crypto/ssh",
calls: []string{"InsecureIgnoreHostKey"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Use of ssh InsecureIgnoreHostKey should be audited",
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

View File

@@ -5,10 +5,11 @@ import (
"go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type ssrf struct {
gosec.MetaData
issue.MetaData
gosec.CallList
}
@@ -40,25 +41,25 @@ func (r *ssrf) ResolveVar(n *ast.CallExpr, c *gosec.Context) bool {
}
// Match inspects AST nodes to determine if certain net/http methods are called with variable input
func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
// Call expression is using http package directly
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
if r.ResolveVar(node, c) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
return nil, nil
}
// NewSSRFCheck detects cases where HTTP requests are sent
func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewSSRFCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
rule := &ssrf{
CallList: gosec.NewCallList(),
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Potential HTTP request made with variable url",
Severity: gosec.Medium,
Confidence: gosec.Medium,
Severity: issue.Medium,
Confidence: issue.Medium,
},
}
rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")

View File

@@ -19,10 +19,11 @@ import (
"go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type subprocess struct {
gosec.MetaData
issue.MetaData
gosec.CallList
}
@@ -39,7 +40,7 @@ func (r *subprocess) ID() string {
// is unsafe. For example:
//
// syscall.Exec("echo", "foobar" + tainted)
func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
args := node.Args
if r.isContext(n, c) {
@@ -64,7 +65,7 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
_, assignment := ident.Obj.Decl.(*ast.AssignStmt)
if variable && assignment {
if !gosec.TryResolve(ident, c) {
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
}
}
case *ast.Field:
@@ -74,21 +75,21 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
vv, vvok := obj.(*types.Var)
if vvok && vv.Parent().Lookup(ident.Name) == nil {
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
}
}
case *ast.ValueSpec:
_, valueSpec := ident.Obj.Decl.(*ast.ValueSpec)
if variable && valueSpec {
if !gosec.TryResolve(ident, c) {
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
}
}
}
}
} else if !gosec.TryResolve(arg, c) {
// the arg is not a constant or a variable but instead a function call or os.Args[i]
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", gosec.Medium, gosec.High), nil
return c.NewIssue(n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", issue.Medium, issue.High), nil
}
}
}
@@ -96,7 +97,7 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
}
// isContext checks whether or not the node is a CommandContext call or not
// Thi is required in order to skip the first argument from the check.
// This is required in order to skip the first argument from the check.
func (r *subprocess) isContext(n ast.Node, ctx *gosec.Context) bool {
selector, indent, err := gosec.GetCallInfo(n, ctx)
if err != nil {
@@ -109,8 +110,8 @@ func (r *subprocess) isContext(n ast.Node, ctx *gosec.Context) bool {
}
// NewSubproc detects cases where we are forking out to an external process
func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
rule := &subprocess{gosec.MetaData{ID: id}, gosec.NewCallList()}
func NewSubproc(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
rule := &subprocess{issue.MetaData{ID: id}, gosec.NewCallList()}
rule.Add("os/exec", "Command")
rule.Add("os/exec", "CommandContext")
rule.Add("syscall", "Exec")

View File

@@ -19,10 +19,11 @@ import (
"regexp"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type badTempFile struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
args *regexp.Regexp
argCalls gosec.CallList
@@ -33,15 +34,15 @@ func (t *badTempFile) ID() string {
return t.MetaData.ID
}
func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.Node) *gosec.Issue {
func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.Node) *issue.Issue {
if s, e := gosec.GetString(suspect); e == nil {
if t.args.MatchString(s) {
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence)
return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence)
}
return nil
}
if ce := t.argCalls.ContainsPkgCallExpr(suspect, c, false); ce != nil {
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence)
return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence)
}
if be, ok := suspect.(*ast.BinaryExpr); ok {
if ops := gosec.GetBinaryExprOperands(be); len(ops) != 0 {
@@ -55,7 +56,7 @@ func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.
return nil
}
func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
return t.findTempDirArgs(n, c, node.Args[0]), nil
}
@@ -63,7 +64,7 @@ func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err
}
// NewBadTempFile detects direct writes to predictable path in temporary directory
func NewBadTempFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewBadTempFile(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := gosec.NewCallList()
calls.Add("io/ioutil", "WriteFile")
calls.AddAll("os", "Create", "WriteFile")
@@ -77,10 +78,10 @@ func NewBadTempFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
args: regexp.MustCompile(`^(/(usr|var))?/tmp(/.*)?$`),
argCalls: argCalls,
nestedCalls: nestedCalls,
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.High,
Severity: issue.Medium,
Confidence: issue.High,
What: "File creation in shared tmp directory without using ioutil.Tempfile",
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -18,10 +18,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type templateCheck struct {
gosec.MetaData
issue.MetaData
calls gosec.CallList
}
@@ -29,11 +30,11 @@ func (t *templateCheck) ID() string {
return t.MetaData.ID
}
func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
for _, arg := range node.Args {
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence), nil
return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence), nil
}
}
}
@@ -42,7 +43,7 @@ func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error
// NewTemplateCheck constructs the template check rule. This rule is used to
// find use of templates where HTML/JS escaping is not being used
func NewTemplateCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewTemplateCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := gosec.NewCallList()
calls.Add("html/template", "HTML")
calls.Add("html/template", "HTMLAttr")
@@ -50,10 +51,10 @@ func NewTemplateCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
calls.Add("html/template", "URL")
return &templateCheck{
calls: calls,
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
Severity: gosec.Medium,
Confidence: gosec.Low,
Severity: issue.Medium,
Confidence: issue.Low,
What: "The used method does not auto-escape HTML. This can potentially lead to 'Cross-site Scripting' vulnerabilities, in case the attacker controls the input.",
},
}, []ast.Node{(*ast.CallExpr)(nil)}

View File

@@ -24,10 +24,11 @@ import (
"strconv"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type insecureConfigTLS struct {
gosec.MetaData
issue.MetaData
MinVersion int64
MaxVersion int64
requiredType string
@@ -49,13 +50,13 @@ func stringInSlice(a string, list []string) bool {
return false
}
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *gosec.Issue {
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *issue.Issue {
if ciphers, ok := n.(*ast.CompositeLit); ok {
for _, cipher := range ciphers.Elts {
if ident, ok := cipher.(*ast.SelectorExpr); ok {
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
return gosec.NewIssue(c, ident, t.ID(), err, gosec.High, gosec.High)
return c.NewIssue(ident, t.ID(), err, issue.High, issue.High)
}
}
}
@@ -63,7 +64,7 @@ func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context)
return nil
}
func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.Issue {
func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *issue.Issue {
if kve, ok := n.(*ast.KeyValueExpr); ok {
issue := t.processTLSConfVal(kve.Key, kve.Value, c)
if issue != nil {
@@ -83,27 +84,27 @@ func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.
return nil
}
func (t *insecureConfigTLS) processTLSConfVal(key ast.Expr, value ast.Expr, c *gosec.Context) *gosec.Issue {
func (t *insecureConfigTLS) processTLSConfVal(key ast.Expr, value ast.Expr, c *gosec.Context) *issue.Issue {
if ident, ok := key.(*ast.Ident); ok {
switch ident.Name {
case "InsecureSkipVerify":
if node, ok := value.(*ast.Ident); ok {
if node.Name != "false" {
return gosec.NewIssue(c, value, t.ID(), "TLS InsecureSkipVerify set true.", gosec.High, gosec.High)
return c.NewIssue(value, t.ID(), "TLS InsecureSkipVerify set true.", issue.High, issue.High)
}
} else {
// TODO(tk): symbol tab look up to get the actual value
return gosec.NewIssue(c, value, t.ID(), "TLS InsecureSkipVerify may be true.", gosec.High, gosec.Low)
return c.NewIssue(value, t.ID(), "TLS InsecureSkipVerify may be true.", issue.High, issue.Low)
}
case "PreferServerCipherSuites":
if node, ok := value.(*ast.Ident); ok {
if node.Name == "false" {
return gosec.NewIssue(c, value, t.ID(), "TLS PreferServerCipherSuites set false.", gosec.Medium, gosec.High)
return c.NewIssue(value, t.ID(), "TLS PreferServerCipherSuites set false.", issue.Medium, issue.High)
}
} else {
// TODO(tk): symbol tab look up to get the actual value
return gosec.NewIssue(c, value, t.ID(), "TLS PreferServerCipherSuites may be false.", gosec.Medium, gosec.Low)
return c.NewIssue(value, t.ID(), "TLS PreferServerCipherSuites may be false.", issue.Medium, issue.Low)
}
case "MinVersion":
@@ -188,16 +189,16 @@ func (t *insecureConfigTLS) mapVersion(version string) int64 {
return v
}
func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *gosec.Issue {
func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *issue.Issue {
if t.actualMaxVersion == 0 && t.actualMinVersion >= t.MinVersion {
// no warning is generated since the min version is greater than the secure min version
return nil
}
if t.actualMinVersion < t.MinVersion {
return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gosec.High, gosec.High)
return c.NewIssue(n, t.ID(), "TLS MinVersion too low.", issue.High, issue.High)
}
if t.actualMaxVersion < t.MaxVersion {
return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gosec.High, gosec.High)
return c.NewIssue(n, t.ID(), "TLS MaxVersion too low.", issue.High, issue.High)
}
return nil
}
@@ -207,7 +208,7 @@ func (t *insecureConfigTLS) resetVersion() {
t.actualMinVersion = 0
}
func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
actualType := c.Info.TypeOf(complit.Type)
if actualType != nil && actualType.String() == t.requiredType {

View File

@@ -4,13 +4,14 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
// NewModernTLSCheck creates a check for Modern TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool
func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewModernTLSCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id},
MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config",
MinVersion: 0x0304,
MaxVersion: 0x0304,
@@ -24,9 +25,9 @@ func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
// NewIntermediateTLSCheck creates a check for Intermediate TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool
func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewIntermediateTLSCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id},
MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config",
MinVersion: 0x0303,
MaxVersion: 0x0304,
@@ -50,9 +51,9 @@ func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.No
// NewOldTLSCheck creates a check for Old TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool
func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewOldTLSCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id},
MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config",
MinVersion: 0x0301,
MaxVersion: 0x0304,

View File

@@ -18,10 +18,11 @@ import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type usingUnsafe struct {
gosec.MetaData
issue.MetaData
pkg string
calls []string
}
@@ -30,24 +31,24 @@ func (r *usingUnsafe) ID() string {
return r.MetaData.ID
}
func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
return nil, nil
}
// NewUsingUnsafe rule detects the use of the unsafe package. This is only
// really useful for auditing purposes.
func NewUsingUnsafe(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
func NewUsingUnsafe(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &usingUnsafe{
pkg: "unsafe",
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
MetaData: gosec.MetaData{
MetaData: issue.MetaData{
ID: id,
What: "Use of unsafe calls should be audited",
Severity: gosec.Low,
Confidence: gosec.High,
Severity: issue.Low,
Confidence: issue.High,
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

Some files were not shown because too many files have changed in this diff Show More