Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bbc35e5be |
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- v*
|
- v*
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -15,9 +17,9 @@ jobs:
|
|||||||
name: lint
|
name: lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.18'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
@@ -28,7 +30,10 @@ jobs:
|
|||||||
# working-directory: somedir
|
# working-directory: somedir
|
||||||
|
|
||||||
# Optional: golangci-lint command line arguments.
|
# Optional: golangci-lint command line arguments.
|
||||||
args: --enable bodyclose --enable exportloopref --timeout 10m
|
args: --enable bodyclose --timeout 10m
|
||||||
|
|
||||||
|
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||||
|
only-new-issues: true
|
||||||
|
|
||||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||||
# skip-pkg-cache: true
|
# skip-pkg-cache: true
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
name: Performance Test
|
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
speed:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Install Go
|
|
||||||
uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: '1.18'
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ github.head_ref }}
|
|
||||||
|
|
||||||
- name: Run Head
|
|
||||||
run: |
|
|
||||||
go build -o current .
|
|
||||||
repo_tmp=$(mktemp -d)
|
|
||||||
git clone https://github.com/trufflesecurity/trufflehog.git $repo_tmp
|
|
||||||
|
|
||||||
user_time_sum=0
|
|
||||||
|
|
||||||
for i in {1..5}
|
|
||||||
do
|
|
||||||
tmpfile=$(mktemp)
|
|
||||||
/usr/bin/time -o $tmpfile $GITHUB_WORKSPACE/current git "file://$repo_tmp" --no-verification --no-update > out.txt
|
|
||||||
cat $tmpfile
|
|
||||||
time_output=$(cat $tmpfile)
|
|
||||||
rm $tmpfile
|
|
||||||
user_time=$(echo $time_output | awk '{print $1}' | sed 's/user//')
|
|
||||||
|
|
||||||
# Add the user time to the sum
|
|
||||||
user_time_sum=$(echo "$user_time_sum + $user_time" | bc)
|
|
||||||
done
|
|
||||||
|
|
||||||
average_user_time=$(echo "scale=3; $user_time_sum / 5" | bc)
|
|
||||||
echo HEAD_TIME=$average_user_time >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Figure out previous tag
|
|
||||||
run: |
|
|
||||||
git fetch --tags
|
|
||||||
git tag -l --sort=-v:refname | head -n 1 > previous_tag.txt
|
|
||||||
echo PREVIOUS_TAG=$(cat previous_tag.txt) >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ env.PREVIOUS_TAG }}
|
|
||||||
|
|
||||||
- name: Run Previous
|
|
||||||
run: |
|
|
||||||
go build -o previous .
|
|
||||||
repo_tmp=$(mktemp -d)
|
|
||||||
git clone https://github.com/trufflesecurity/trufflehog.git $repo_tmp
|
|
||||||
|
|
||||||
user_time_sum=0
|
|
||||||
|
|
||||||
for i in {1..5}
|
|
||||||
do
|
|
||||||
tmpfile=$(mktemp)
|
|
||||||
/usr/bin/time -o $tmpfile $GITHUB_WORKSPACE/previous git "file://$repo_tmp" --no-verification --no-update > out.txt
|
|
||||||
cat $tmpfile
|
|
||||||
time_output=$(cat $tmpfile)
|
|
||||||
rm $tmpfile
|
|
||||||
user_time=$(echo $time_output | awk '{print $1}' | sed 's/user//')
|
|
||||||
|
|
||||||
# Add the user time to the sum
|
|
||||||
user_time_sum=$(echo "$user_time_sum + $user_time" | bc)
|
|
||||||
done
|
|
||||||
|
|
||||||
average_user_time=$(echo "scale=3; $user_time_sum / 5" | bc)
|
|
||||||
echo PREVIOUS_TIME=$average_user_time >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Compare Results
|
|
||||||
run: |
|
|
||||||
echo "head ($GITHUB_SHA) avg time (n=5): $HEAD_TIME"
|
|
||||||
echo "$PREVIOUS_TAG avg time (n=5): $PREVIOUS_TIME"
|
|
||||||
if [ $(echo "$HEAD_TIME > $PREVIOUS_TIME * 1.1" | bc) -eq 1 ]
|
|
||||||
then
|
|
||||||
echo "HEAD run time is at least 10% slower than PREVIOUS run time"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -33,9 +33,9 @@ jobs:
|
|||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.18'
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v4
|
uses: goreleaser/goreleaser-action@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ on:
|
|||||||
- v*
|
- v*
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.18'
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
@@ -29,4 +29,3 @@ jobs:
|
|||||||
path: ./
|
path: ./
|
||||||
base: ${{ github.event.repository.default_branch }}
|
base: ${{ github.event.repository.default_branch }}
|
||||||
head: HEAD
|
head: HEAD
|
||||||
extra_args: --only-verified
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.18'
|
go-version: '1.18'
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ jobs:
|
|||||||
name: Run Snifftest
|
name: Run Snifftest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.18'
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Run Snifftest
|
- name: Run Snifftest
|
||||||
run: make snifftest
|
run: make snifftest
|
||||||
@@ -13,14 +13,13 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
actions: 'read'
|
|
||||||
contents: 'read'
|
contents: 'read'
|
||||||
id-token: 'write'
|
id-token: 'write'
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.18'
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- id: 'auth'
|
- id: 'auth'
|
||||||
@@ -33,14 +32,13 @@ jobs:
|
|||||||
test-detectors:
|
test-detectors:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
actions: 'read'
|
|
||||||
contents: 'read'
|
contents: 'read'
|
||||||
id-token: 'write'
|
id-token: 'write'
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.18'
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- id: 'auth'
|
- id: 'auth'
|
||||||
@@ -51,3 +49,4 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
run: make test-detectors
|
run: make test-detectors
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
repos:
|
|
||||||
- repo: https://github.com/rhysd/actionlint
|
|
||||||
rev: v1.6.24
|
|
||||||
hooks:
|
|
||||||
- id: actionlint
|
|
||||||
|
|
||||||
- repo: https://github.com/mpalmer/action-validator
|
|
||||||
rev: v0.5.1
|
|
||||||
hooks:
|
|
||||||
- id: action-validator
|
|
||||||
@@ -22,7 +22,7 @@ check:
|
|||||||
go vet $(shell go list ./... | grep -v /vendor/)
|
go vet $(shell go list ./... | grep -v /vendor/)
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
golangci-lint run --enable bodyclose --enable exportloopref --out-format=colored-line-number --timeout 10m
|
golangci-lint run --enable bodyclose --out-format=colored-line-number --timeout 10m
|
||||||
|
|
||||||
test-failing:
|
test-failing:
|
||||||
CGO_ENABLED=0 go test -timeout=5m $(shell go list ./... | grep -v /vendor/) | grep FAIL
|
CGO_ENABLED=0 go test -timeout=5m $(shell go list ./... | grep -v /vendor/) | grep FAIL
|
||||||
|
|||||||
@@ -17,25 +17,13 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# :mag_right: _Now Scanning_
|
## Join The Slack
|
||||||
|
Have questions? Feedback? Jump in slack and hang out with us
|
||||||
|
|
||||||
<div align="center">
|
https://join.slack.com/t/trufflehog-community/shared_invite/zt-pw2qbi43-Aa86hkiimstfdKH9UCpPzQ
|
||||||
|
|
||||||
<img src="assets/scanning_logos.svg">
|
|
||||||
|
|
||||||
**...and more**
|
## Demo
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# :loudspeaker: Join Our Community
|
|
||||||
|
|
||||||
Have questions? Feedback? Jump in slack or discord and hang out with us
|
|
||||||
|
|
||||||
Join our [Slack Community](https://join.slack.com/t/trufflehog-community/shared_invite/zt-pw2qbi43-Aa86hkiimstfdKH9UCpPzQ)
|
|
||||||
|
|
||||||
Join the [Secret Scanning Discord](https://discord.gg/zpB2jDhr)
|
|
||||||
|
|
||||||
# :tv: Demo
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -43,30 +31,9 @@ Join the [Secret Scanning Discord](https://discord.gg/zpB2jDhr)
|
|||||||
docker run --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --org=trufflesecurity
|
docker run --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --org=trufflesecurity
|
||||||
```
|
```
|
||||||
|
|
||||||
# :floppy_disk: Installation
|
## Examples
|
||||||
|
|
||||||
Several options available for you:
|
### Example 1: Scan a repo for only verified secrets
|
||||||
```bash
|
|
||||||
# MacOS users
|
|
||||||
brew install trufflesecurity/trufflehog/trufflehog
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker run --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --repo https://github.com/trufflesecurity/test_keys
|
|
||||||
|
|
||||||
# Docker for M1 and M2 Mac
|
|
||||||
docker run --platform linux/arm64 --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --repo https://github.com/trufflesecurity/test_keys
|
|
||||||
|
|
||||||
# Binary releases
|
|
||||||
Download and unpack from https://github.com/trufflesecurity/trufflehog/releases
|
|
||||||
|
|
||||||
# Compile from source
|
|
||||||
git clone https://github.com/trufflesecurity/trufflehog.git
|
|
||||||
cd trufflehog; go install
|
|
||||||
```
|
|
||||||
|
|
||||||
# :rocket: Quick Start
|
|
||||||
|
|
||||||
## 1: Scan a repo for only verified secrets
|
|
||||||
|
|
||||||
Command:
|
Command:
|
||||||
|
|
||||||
@@ -91,13 +58,13 @@ Timestamp: 2022-06-16 10:17:40 -0700 PDT
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2: Scan a GitHub Org for only verified secrets
|
### Example 2: Scan a GitHub Org for only verified secrets
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
trufflehog github --org=trufflesecurity --only-verified
|
trufflehog github --org=trufflesecurity --only-verified
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3: Scan a GitHub Repo for only verified keys and get JSON output
|
### Example 3: Scan a GitHub Repo for only verified keys and get JSON output
|
||||||
|
|
||||||
Command:
|
Command:
|
||||||
|
|
||||||
@@ -111,31 +78,13 @@ Expected output:
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4: Scan an S3 bucket for verified keys
|
### Example 4: Scan an S3 bucket for verified keys
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
trufflehog s3 --bucket=<bucket name> --only-verified
|
trufflehog s3 --bucket=<bucket name> --only-verified
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5: Scan a Github Repo using SSH authentication in docker
|
### FAQ
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --rm -v "$HOME/.ssh:/root/.ssh:ro" trufflesecurity/trufflehog:latest git ssh://github.com/trufflesecurity/test_keys
|
|
||||||
```
|
|
||||||
|
|
||||||
## 6: Scan individual files or directories
|
|
||||||
|
|
||||||
```bash
|
|
||||||
trufflehog filesystem path/to/file1.txt path/to/file2.txt path/to/dir
|
|
||||||
```
|
|
||||||
|
|
||||||
## 7: Scan GCS buckets for verified secrets.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
trufflehog gcs --project-id=<project-ID> --cloud-environment --only-verified
|
|
||||||
```
|
|
||||||
|
|
||||||
# :question: FAQ
|
|
||||||
|
|
||||||
+ All I see is `🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷` and the program exits, what gives?
|
+ All I see is `🐷🔑🐷 TruffleHog. Unearth your secrets. 🐷🔑🐷` and the program exits, what gives?
|
||||||
+ That means no secrets were detected
|
+ That means no secrets were detected
|
||||||
@@ -145,21 +94,78 @@ trufflehog gcs --project-id=<project-ID> --cloud-environment --only-verified
|
|||||||
+ Check out our Driftwood blog post to learn how to do this, in short we've confirmed the key can be used live for SSH or SSL [Blog post](https://trufflesecurity.com/blog/driftwood-know-if-private-keys-are-sensitive/)
|
+ Check out our Driftwood blog post to learn how to do this, in short we've confirmed the key can be used live for SSH or SSL [Blog post](https://trufflesecurity.com/blog/driftwood-know-if-private-keys-are-sensitive/)
|
||||||
|
|
||||||
|
|
||||||
# :newspaper: What's new in v3?
|
### Example 5: Scan a Github Repo using SSH authentication in docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -v "$HOME/.ssh:/root/.ssh:ro" trufflesecurity/trufflehog:latest git ssh://github.com/trufflesecurity/test_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 6: Scan individual files or directories
|
||||||
|
|
||||||
|
```bash
|
||||||
|
trufflehog filesystem path/to/file1.txt path/to/file2.txt path/to/dir
|
||||||
|
```
|
||||||
|
|
||||||
|
# What's new in v3?
|
||||||
|
|
||||||
TruffleHog v3 is a complete rewrite in Go with many new powerful features.
|
TruffleHog v3 is a complete rewrite in Go with many new powerful features.
|
||||||
|
|
||||||
- We've **added over 700 credential detectors that support active verification against their respective APIs**.
|
- We've **added over 700 credential detectors that support active verification against their respective APIs**.
|
||||||
- We've also added native **support for scanning GitHub, GitLab, filesystems, S3, GCS and Circle CI**.
|
- We've also added native **support for scanning GitHub, GitLab, filesystems, S3, and Circle CI**.
|
||||||
- **Instantly verify private keys** against millions of github users and **billions** of TLS certificates using our [Driftwood](https://trufflesecurity.com/blog/driftwood) technology.
|
- **Instantly verify private keys** against millions of github users and **billions** of TLS certificates using our [Driftwood](https://trufflesecurity.com/blog/driftwood) technology.
|
||||||
- Scan binaries and other file formats
|
|
||||||
- Available as a GitHub Action and a pre-commit hook
|
|
||||||
|
|
||||||
|
|
||||||
## What is credential verification?
|
## What is credential verification?
|
||||||
For every potential credential that is detected, we've painstakingly implemented programmatic verification against the API that we think it belongs to. Verification eliminates false positives. For example, the [AWS credential detector](pkg/detectors/aws/aws.go) performs a `GetCallerIdentity` API call against the AWS API to verify if an AWS credential is active.
|
For every potential credential that is detected, we've painstakingly implemented programmatic verification against the API that we think it belongs to. Verification eliminates false positives. For example, the [AWS credential detector](pkg/detectors/aws/aws.go) performs a `GetCallerIdentity` API call against the AWS API to verify if an AWS credential is active.
|
||||||
|
|
||||||
# :memo: Usage
|
## Installation
|
||||||
|
|
||||||
|
Several options:
|
||||||
|
|
||||||
|
### 1. Go
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/trufflesecurity/trufflehog.git
|
||||||
|
|
||||||
|
cd trufflehog; go install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. [Release binaries](https://github.com/trufflesecurity/trufflehog/releases)
|
||||||
|
|
||||||
|
### 3. Docker
|
||||||
|
|
||||||
|
|
||||||
|
> Note: Apple M1 hardware users should run with `docker run --rm --platform linux/arm64` for better performance.
|
||||||
|
|
||||||
|
#### **Most users**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --repo https://github.com/trufflesecurity/test_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **Apple M1 users**
|
||||||
|
|
||||||
|
The `linux/arm64` image is better to run on the M1 than the amd64 image.
|
||||||
|
Even better is running the native darwin binary available, but there is no container image for that.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm --platform linux/arm64 -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --repo https://github.com/trufflesecurity/test_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Pip (help wanted)
|
||||||
|
|
||||||
|
It's possible to distribute binaries in pip wheels.
|
||||||
|
|
||||||
|
Here is an example of a [project that does it](https://github.com/Yelp/dumb-init).
|
||||||
|
|
||||||
|
Help with setting up this packaging would be appreciated!
|
||||||
|
|
||||||
|
### 5. Brew
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install trufflesecurity/trufflehog/trufflehog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
TruffleHog has a sub-command for each source of data that you may want to scan:
|
TruffleHog has a sub-command for each source of data that you may want to scan:
|
||||||
|
|
||||||
@@ -170,7 +176,6 @@ TruffleHog has a sub-command for each source of data that you may want to scan:
|
|||||||
- filesystem (files and directories)
|
- filesystem (files and directories)
|
||||||
- syslog
|
- syslog
|
||||||
- circleci
|
- circleci
|
||||||
- GCS (Google Cloud Storage)
|
|
||||||
- stdin (coming soon)
|
- stdin (coming soon)
|
||||||
|
|
||||||
Each subcommand can have options that you can see with the `--help` flag provided to the sub command:
|
Each subcommand can have options that you can see with the `--help` flag provided to the sub command:
|
||||||
@@ -213,10 +218,18 @@ Exit Codes:
|
|||||||
- 1: An error was encountered. Sources may not have completed scans.
|
- 1: An error was encountered. Sources may not have completed scans.
|
||||||
- 183: No errors were encountered, but results were found. Will only be returned if `--fail` flag is used.
|
- 183: No errors were encountered, but results were found. Will only be returned if `--fail` flag is used.
|
||||||
|
|
||||||
# :octocat: TruffleHog Github Action
|
#### Scanning an organization
|
||||||
|
|
||||||
|
Try scanning an entire GitHub organization with the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest github --org=trufflesecurity
|
||||||
|
```
|
||||||
|
|
||||||
|
### TruffleHog OSS Github Action
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: TruffleHog
|
- name: TruffleHog OSS
|
||||||
uses: trufflesecurity/trufflehog@main
|
uses: trufflesecurity/trufflehog@main
|
||||||
with:
|
with:
|
||||||
# Repository path
|
# Repository path
|
||||||
@@ -234,7 +247,7 @@ any results are found.
|
|||||||
|
|
||||||
For example, to scan the contents of pull requests you could use the following workflow:
|
For example, to scan the contents of pull requests you could use the following workflow:
|
||||||
```yaml
|
```yaml
|
||||||
name: TruffleHog Secrets Scan
|
name: Leaked Secrets Scan
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
TruffleHog:
|
TruffleHog:
|
||||||
@@ -253,7 +266,7 @@ jobs:
|
|||||||
extra_args: --debug --only-verified
|
extra_args: --debug --only-verified
|
||||||
```
|
```
|
||||||
|
|
||||||
# Precommit Hook
|
### Precommit Hook
|
||||||
|
|
||||||
Trufflehog can be used in a precommit hook to prevent credentials from leaking before they ever leave your computer.
|
Trufflehog can be used in a precommit hook to prevent credentials from leaking before they ever leave your computer.
|
||||||
An example `.pre-commit-config.yaml` is provided (see [pre-commit.com](https://pre-commit.com/) for installation).
|
An example `.pre-commit-config.yaml` is provided (see [pre-commit.com](https://pre-commit.com/) for installation).
|
||||||
@@ -272,7 +285,7 @@ repos:
|
|||||||
stages: ["commit", "push"]
|
stages: ["commit", "push"]
|
||||||
```
|
```
|
||||||
|
|
||||||
# Regex Detector (alpha)
|
## Regex Detector (alpha)
|
||||||
|
|
||||||
Trufflehog supports detection and verification of custom regular expressions.
|
Trufflehog supports detection and verification of custom regular expressions.
|
||||||
For detection, at least one **regular expression** and **keyword** is required.
|
For detection, at least one **regular expression** and **keyword** is required.
|
||||||
@@ -286,7 +299,7 @@ status code, the secret is considered verified.
|
|||||||
|
|
||||||
**NB:** This feature is alpha and subject to change.
|
**NB:** This feature is alpha and subject to change.
|
||||||
|
|
||||||
## Regex Detector Example
|
### Regex Detector Example
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# config.yaml
|
# config.yaml
|
||||||
@@ -315,7 +328,7 @@ Raw result: hogs are cool
|
|||||||
File: /tmp/hog-facts.txt
|
File: /tmp/hog-facts.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Verification Server Example (Python)
|
#### Verification Server Example (Python)
|
||||||
|
|
||||||
Unless you run a verification server, secrets found by the custom regex
|
Unless you run a verification server, secrets found by the custom regex
|
||||||
detector will be unverified. Here is an example Python implementation of a
|
detector will be unverified. Here is an example Python implementation of a
|
||||||
@@ -365,7 +378,12 @@ with HTTPServer(('', 8000), Verifier) as server:
|
|||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
# :heart: Contributors
|
## Use as a library
|
||||||
|
|
||||||
|
Currently, trufflehog is in heavy development and no guarantees can be made on
|
||||||
|
the stability of the public APIs at this time.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||||
|
|
||||||
@@ -375,28 +393,22 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
# :computer: Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are very welcome! Please see our [contribution guidelines first](CONTRIBUTING.md).
|
Contributions are very welcome! Please see our [contribution guidelines first](CONTRIBUTING.md).
|
||||||
|
|
||||||
We no longer accept contributions to TruffleHog v2, but that code is available in the `v2` branch.
|
We no longer accept contributions to TruffleHog v2, but that code is available in the `v2` branch.
|
||||||
|
|
||||||
|
### Adding new secret detectors
|
||||||
## Adding new secret detectors
|
|
||||||
|
|
||||||
We have published some [documentation and tooling to get started on adding new secret detectors](hack/docs/Adding_Detectors_external.md). Let's improve detection together!
|
We have published some [documentation and tooling to get started on adding new secret detectors](hack/docs/Adding_Detectors_external.md). Let's improve detection together!
|
||||||
|
|
||||||
|
## License Change
|
||||||
# Use as a library
|
|
||||||
|
|
||||||
Currently, trufflehog is in heavy development and no guarantees can be made on
|
|
||||||
the stability of the public APIs at this time.
|
|
||||||
# License Change
|
|
||||||
|
|
||||||
Since v3.0, TruffleHog is released under a AGPL 3 license, included in [`LICENSE`](LICENSE). TruffleHog v3.0 uses none of the previous codebase, but care was taken to preserve backwards compatibility on the command line interface. The work previous to this release is still available licensed under GPL 2.0 in the history of this repository and the previous package releases and tags. A completed CLA is required for us to accept contributions going forward.
|
Since v3.0, TruffleHog is released under a AGPL 3 license, included in [`LICENSE`](LICENSE). TruffleHog v3.0 uses none of the previous codebase, but care was taken to preserve backwards compatibility on the command line interface. The work previous to this release is still available licensed under GPL 2.0 in the history of this repository and the previous package releases and tags. A completed CLA is required for us to accept contributions going forward.
|
||||||
|
|
||||||
|
|
||||||
# :money_with_wings: Enterprise product
|
## Enterprise product
|
||||||
|
|
||||||
Are you interested in continously monitoring your Git, Jira, Slack, Confluence, etc.. for credentials? We have an enterprise product that can help. Reach out here to learn more https://trufflesecurity.com/contact/
|
Are you interested in continously monitoring your Git, Jira, Slack, Confluence, etc.. for credentials? We have an enterprise product that can help. Reach out here to learn more https://trufflesecurity.com/contact/
|
||||||
|
|
||||||
|
|||||||
@@ -32,5 +32,4 @@ runs:
|
|||||||
- ${{ inputs.head }}
|
- ${{ inputs.head }}
|
||||||
- --fail
|
- --fail
|
||||||
- --no-update
|
- --no-update
|
||||||
- --github-actions
|
|
||||||
- ${{ inputs.extra_args }}
|
- ${{ inputs.extra_args }}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 814 B |
@@ -1,167 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="173.78879mm"
|
|
||||||
height="26.198219mm"
|
|
||||||
viewBox="0 0 173.78879 26.198219"
|
|
||||||
version="1.1"
|
|
||||||
id="svg5"
|
|
||||||
xml:space="preserve"
|
|
||||||
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
|
|
||||||
sodipodi:docname="scanning_logos.svg"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
|
||||||
id="namedview7"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#999999"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="0.67348485"
|
|
||||||
inkscape:cx="376.40045"
|
|
||||||
inkscape:cy="538.98763"
|
|
||||||
inkscape:window-width="1250"
|
|
||||||
inkscape:window-height="906"
|
|
||||||
inkscape:window-x="1226"
|
|
||||||
inkscape:window-y="265"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1" /><defs
|
|
||||||
id="defs2"><style
|
|
||||||
id="style344">.cls-1{fill:#e24329;}.cls-2{fill:#fc6d26;}.cls-3{fill:#fca326;}</style><style
|
|
||||||
id="style433">
|
|
||||||
.cls-1 {
|
|
||||||
fill: #e25444;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cls-1, .cls-2, .cls-3 {
|
|
||||||
fill-rule: evenodd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cls-2 {
|
|
||||||
fill: #7b1d13;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cls-3 {
|
|
||||||
fill: #58150d;
|
|
||||||
}
|
|
||||||
</style><path
|
|
||||||
d="M 27.791,115.217 1.541,69.749 a 11.499,11.499 0 0 1 0,-11.499 l 26.25,-45.467 a 11.499,11.499 0 0 1 9.959,-5.75 h 52.5 a 11.5,11.5 0 0 1 9.96,5.75 l 26.25,45.467 a 11.499,11.499 0 0 1 0,11.5 l -26.25,45.466 a 11.499,11.499 0 0 1 -9.96,5.75 h -52.5 a 11.499,11.499 0 0 1 -9.959,-5.75 z"
|
|
||||||
id="b" /></defs><g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-5.467857,-5.738096)"><g
|
|
||||||
id="g706"><path
|
|
||||||
fill="#f05133"
|
|
||||||
d="M 88.304634,18.167061 77.689818,7.5527709 c -0.611187,-0.611452 -1.602581,-0.611452 -2.214298,0 l -2.203979,2.204508 2.795852,2.7958521 c 0.649817,-0.219604 1.394883,-0.07223 1.912673,0.445823 0.520965,0.521229 0.667015,1.272646 0.441854,1.924844 l 2.695045,2.694781 c 0.652198,-0.224895 1.404144,-0.07938 1.924844,0.442119 0.727604,0.727604 0.727604,1.906588 0,2.634721 -0.728134,0.727869 -1.907117,0.727869 -2.635515,0 -0.547157,-0.547688 -0.682624,-1.352021 -0.405077,-2.026179 l -2.513541,-2.513277 v 6.613789 c 0.177271,0.08784 0.344753,0.204788 0.49239,0.352425 0.727604,0.727604 0.727604,1.906588 0,2.634986 -0.727604,0.727339 -1.907381,0.727339 -2.634456,0 -0.727604,-0.728663 -0.727604,-1.907646 0,-2.634986 0.179916,-0.179652 0.388144,-0.315648 0.610394,-0.406664 v -6.675438 c -0.22225,-0.09102 -0.429948,-0.225689 -0.610394,-0.406664 -0.551127,-0.550863 -0.683684,-1.359959 -0.401109,-2.036763 l -2.756164,-2.756694 -7.278688,7.277894 c -0.611452,0.611981 -0.611452,1.603375 0,2.214827 l 10.615348,10.614554 c 0.611188,0.611452 1.602317,0.611452 2.214298,0 L 88.304634,20.381888 c 0.61145,-0.611452 0.61145,-1.603375 0,-2.214827 z"
|
|
||||||
id="path79"
|
|
||||||
style="stroke-width:0.264583" /><path
|
|
||||||
d="m 17.874996,7.9032889 c -6.850808,0 -12.407139,5.3892601 -12.407139,12.0363631 0,5.318065 3.554648,9.829669 8.485453,11.421504 0.619321,0.111453 0.819902,-0.261967 0.819902,-0.578771 v -2.240776 c -3.451252,0.728214 -4.169831,-1.420293 -4.169831,-1.420293 -0.564526,-1.391177 -1.378228,-1.76129 -1.378228,-1.76129 -1.125947,-0.747278 0.08582,-0.731237 0.08582,-0.731237 1.245884,0.08414 1.901392,1.240753 1.901392,1.240753 1.106307,1.83957 2.902239,1.307954 3.610476,1.000022 0.110631,-0.777343 0.432184,-1.308957 0.787857,-1.608858 -2.75542,-0.305935 -5.652486,-1.338031 -5.652486,-5.948955 0,-1.314982 0.484911,-2.38821 1.277936,-3.230747 -0.128214,-0.304036 -0.553152,-1.528637 0.120985,-3.185643 0,0 1.0422,-0.322993 3.412995,1.233734 0.989472,-0.266877 2.050281,-0.400211 3.104887,-0.405253 1.054607,0.0033 2.116454,0.138376 3.107992,0.405253 2.368727,-1.556727 3.408859,-1.233734 3.408859,-1.233734 0.675156,1.657988 0.250214,2.882698 0.122,3.185643 0.796124,0.842537 1.276903,1.916758 1.276903,3.230747 0,4.62295 -2.902238,5.641012 -5.664896,5.938948 0.444591,0.373028 0.850923,1.105332 0.850923,2.228716 v 3.30297 c 0,0.319958 0.198515,0.696095 0.828178,0.577744 4.926667,-1.593809 8.477177,-6.104433 8.477177,-11.420477 0,-6.647103 -5.555295,-12.0363631 -12.407141,-12.0363631 z"
|
|
||||||
id="path286"
|
|
||||||
style="stroke-width:1.01836" /><g
|
|
||||||
id="LOGO"
|
|
||||||
transform="matrix(0.12753077,0,0,0.12866528,23.501297,-4.4119714)"><path
|
|
||||||
class="cls-1"
|
|
||||||
d="m 282.83,170.73 -0.27,-0.69 -26.14,-68.22 a 6.81,6.81 0 0 0 -2.69,-3.24 7,7 0 0 0 -8,0.43 7,7 0 0 0 -2.32,3.52 l -17.65,54 h -71.47 l -17.65,-54 a 6.86,6.86 0 0 0 -2.32,-3.53 7,7 0 0 0 -8,-0.43 6.87,6.87 0 0 0 -2.69,3.24 L 97.44,170 l -0.26,0.69 a 48.54,48.54 0 0 0 16.1,56.1 l 0.09,0.07 0.24,0.17 39.82,29.82 19.7,14.91 12,9.06 a 8.07,8.07 0 0 0 9.76,0 l 12,-9.06 19.7,-14.91 40.06,-30 0.1,-0.08 a 48.56,48.56 0 0 0 16.08,-56.04 z"
|
|
||||||
id="path348" /><path
|
|
||||||
class="cls-2"
|
|
||||||
d="m 282.83,170.73 -0.27,-0.69 a 88.3,88.3 0 0 0 -35.15,15.8 L 190,229.25 c 19.55,14.79 36.57,27.64 36.57,27.64 l 40.06,-30 0.1,-0.08 a 48.56,48.56 0 0 0 16.1,-56.08 z"
|
|
||||||
id="path350" /><path
|
|
||||||
class="cls-3"
|
|
||||||
d="m 153.43,256.89 19.7,14.91 12,9.06 a 8.07,8.07 0 0 0 9.76,0 l 12,-9.06 19.7,-14.91 c 0,0 -17.04,-12.89 -36.59,-27.64 -19.55,14.75 -36.57,27.64 -36.57,27.64 z"
|
|
||||||
id="path352" /><path
|
|
||||||
class="cls-2"
|
|
||||||
d="M 132.58,185.84 A 88.19,88.19 0 0 0 97.44,170 l -0.26,0.69 a 48.54,48.54 0 0 0 16.1,56.1 l 0.09,0.07 0.24,0.17 39.82,29.82 c 0,0 17,-12.85 36.57,-27.64 z"
|
|
||||||
id="path354" /></g><g
|
|
||||||
id="g481"
|
|
||||||
transform="matrix(0.06220237,0,0,0.05342262,92.880356,5.1809529)"><path
|
|
||||||
class="cls-1"
|
|
||||||
d="m 378,99 -83,158 83,158 34,-19 V 118 Z"
|
|
||||||
id="path437" /><path
|
|
||||||
class="cls-2"
|
|
||||||
d="M 378,99 212,118 127.5,257 212,396 378,415 Z"
|
|
||||||
id="path439" /><path
|
|
||||||
class="cls-3"
|
|
||||||
d="M 43,99 16,111 V 403 L 43,415 212,257 Z"
|
|
||||||
id="path441" /><path
|
|
||||||
class="cls-1"
|
|
||||||
d="m 42.637,98.667 169.587,47.111 V 372.444 L 42.637,415.111 Z"
|
|
||||||
id="path443" /><path
|
|
||||||
class="cls-3"
|
|
||||||
d="m 212.313,170.667 -72.008,-11.556 72.008,-81.778 71.83,81.778 z"
|
|
||||||
id="path445" /><path
|
|
||||||
class="cls-3"
|
|
||||||
d="m 284.143,159.111 -71.919,11.733 -71.919,-11.733 V 77.333"
|
|
||||||
id="path447" /><path
|
|
||||||
class="cls-3"
|
|
||||||
d="m 212.313,342.222 -72.008,13.334 72.008,70.222 71.83,-70.222 z"
|
|
||||||
id="path449" /><path
|
|
||||||
class="cls-2"
|
|
||||||
d="m 212,16 -72,38 v 105 l 72.224,-20.333 z"
|
|
||||||
id="path451" /><path
|
|
||||||
class="cls-2"
|
|
||||||
d="m 212.224,196.444 -71.919,7.823 v 104.838 l 71.919,8.228 z"
|
|
||||||
id="path453" /><path
|
|
||||||
class="cls-2"
|
|
||||||
d="M 212.224,373.333 140.305,355.3 V 458.363 L 212.224,496 Z"
|
|
||||||
id="path455" /><path
|
|
||||||
class="cls-1"
|
|
||||||
d="m 284.143,355.3 -71.919,18.038 V 496 l 71.919,-37.637 z"
|
|
||||||
id="path457" /><path
|
|
||||||
class="cls-1"
|
|
||||||
d="m 212.224,196.444 71.919,7.823 v 104.838 l -71.919,8.228 z"
|
|
||||||
id="path459" /><path
|
|
||||||
class="cls-1"
|
|
||||||
d="m 212,16 72,38 v 105 l -72,-20 z"
|
|
||||||
id="path461" /></g><g
|
|
||||||
id="g583"
|
|
||||||
transform="matrix(0.20423993,0,0,0.21790562,123.68704,6.5803506)"><g
|
|
||||||
transform="translate(0,-7.034)"
|
|
||||||
id="g549"><linearGradient
|
|
||||||
y2="120.789"
|
|
||||||
x2="64"
|
|
||||||
y1="7.0339999"
|
|
||||||
x1="64"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
id="a"><stop
|
|
||||||
offset="0"
|
|
||||||
stop-color="#4387fd"
|
|
||||||
id="stop542" /><stop
|
|
||||||
offset="1"
|
|
||||||
stop-color="#4683ea"
|
|
||||||
id="stop544" /></linearGradient><path
|
|
||||||
d="M 27.79,115.217 1.54,69.749 a 11.499,11.499 0 0 1 0,-11.499 L 27.79,12.783 a 11.5,11.5 0 0 1 9.96,-5.75 h 52.5 a 11.5,11.5 0 0 1 9.959,5.75 l 26.25,45.467 a 11.499,11.499 0 0 1 0,11.5 l -26.25,45.466 a 11.5,11.5 0 0 1 -9.959,5.75 h -52.5 a 11.499,11.499 0 0 1 -9.96,-5.75 z"
|
|
||||||
fill="url(#a)"
|
|
||||||
id="path547"
|
|
||||||
style="fill:url(#a)" /></g><g
|
|
||||||
transform="translate(0,-7.034)"
|
|
||||||
id="g559"><defs
|
|
||||||
id="defs552"><path
|
|
||||||
d="M 27.791,115.217 1.541,69.749 a 11.499,11.499 0 0 1 0,-11.499 l 26.25,-45.467 a 11.499,11.499 0 0 1 9.959,-5.75 h 52.5 a 11.5,11.5 0 0 1 9.96,5.75 l 26.25,45.467 a 11.499,11.499 0 0 1 0,11.5 l -26.25,45.466 a 11.499,11.499 0 0 1 -9.96,5.75 h -52.5 a 11.499,11.499 0 0 1 -9.959,-5.75 z"
|
|
||||||
id="path575" /></defs><clipPath
|
|
||||||
id="c"><use
|
|
||||||
height="100%"
|
|
||||||
width="100%"
|
|
||||||
xlink:href="#b"
|
|
||||||
overflow="visible"
|
|
||||||
id="use554" /></clipPath><path
|
|
||||||
clip-path="url(#c)"
|
|
||||||
opacity="0.07"
|
|
||||||
d="m 49.313,53.875 -7.01,6.99 5.957,5.958 -5.898,10.476 44.635,44.636 10.816,0.002 L 118.936,84 85.489,50.55 Z"
|
|
||||||
id="path557" /></g><path
|
|
||||||
d="M 84.7,43.236 H 43.264 c -0.667,0 -1.212,0.546 -1.212,1.214 v 8.566 c 0,0.666 0.546,1.212 1.212,1.212 H 84.7 c 0.667,0 1.213,-0.546 1.213,-1.212 v -8.568 c 0,-0.666 -0.545,-1.213 -1.212,-1.213 m -6.416,7.976 a 2.484,2.484 0 0 1 -2.477,-2.48 2.475,2.475 0 0 1 2.477,-2.477 c 1.37,0 2.48,1.103 2.48,2.477 a 2.48,2.48 0 0 1 -2.48,2.48 m 6.415,8.491 -41.436,0.002 c -0.667,0 -1.212,0.546 -1.212,1.214 v 8.565 c 0,0.666 0.546,1.213 1.212,1.213 H 84.7 c 0.667,0 1.213,-0.547 1.213,-1.213 v -8.567 c 0,-0.666 -0.545,-1.214 -1.212,-1.214 m -6.416,7.976 a 2.483,2.483 0 0 1 -2.477,-2.48 2.475,2.475 0 0 1 2.477,-2.477 2.48,2.48 0 1 1 0,4.956"
|
|
||||||
fill="#ffffff"
|
|
||||||
id="path561" /></g><g
|
|
||||||
style="fill:#000000"
|
|
||||||
id="g668"
|
|
||||||
transform="matrix(1.0414114,0,0,1.0768849,154.45231,5.738096)"><path
|
|
||||||
d="m 8.963,12 c 0,-1.584 1.284,-2.855 2.855,-2.855 1.572,0 2.856,1.284 2.856,2.855 0,1.572 -1.284,2.856 -2.856,2.856 -1.57,0 -2.855,-1.284 -2.855,-2.856 z M 11.818,0 C 6.215,0 1.522,3.84 0.19,9.025 0.18,9.061 0.18,9.095 0.18,9.145 c 0,0.313 0.252,0.576 0.575,0.576 H 5.59 c 0.23,0 0.433,-0.13 0.517,-0.333 0.997,-2.16 3.18,-3.672 5.712,-3.672 3.466,0 6.286,2.82 6.286,6.287 0,3.47 -2.82,6.29 -6.29,6.29 -2.53,0 -4.714,-1.5 -5.71,-3.673 C 6.008,14.43 5.815,14.284 5.588,14.284 H 0.755 c -0.312,0 -0.575,0.253 -0.575,0.576 0,0.037 0.014,0.072 0.014,0.12 1.32,5.18 6.02,9.02 11.624,9.02 6.624,0 12,-5.375 12,-12 0,-6.623 -5.376,-12 -12,-12 z"
|
|
||||||
id="path659" /></g></g></g></svg>
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,74 +1,72 @@
|
|||||||
module github.com/trufflesecurity/trufflehog/v3
|
module github.com/trufflesecurity/trufflehog/v3
|
||||||
|
|
||||||
go 1.20
|
go 1.18
|
||||||
|
|
||||||
replace github.com/jpillora/overseer => github.com/trufflesecurity/overseer v1.1.7-custom5
|
replace github.com/jpillora/overseer => github.com/trufflesecurity/overseer v1.1.7-custom5
|
||||||
|
|
||||||
|
replace github.com/zricethezav/gitleaks/v8 => github.com/trufflesecurity/gitleaks/v8 v8.6.1-custom10
|
||||||
|
|
||||||
|
replace github.com/gitleaks/go-gitdiff => github.com/trufflesecurity/go-gitdiff v0.7.6-zombies2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/secretmanager v1.10.1
|
cloud.google.com/go/secretmanager v1.10.0
|
||||||
cloud.google.com/go/storage v1.29.0
|
|
||||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
|
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11
|
||||||
github.com/TheZeroSlave/zapsentry v1.15.0
|
github.com/TheZeroSlave/zapsentry v1.14.0
|
||||||
github.com/aws/aws-sdk-go v1.44.83
|
github.com/aws/aws-sdk-go v1.44.83
|
||||||
github.com/bill-rich/disk-buffer-reader v0.1.7
|
github.com/bill-rich/disk-buffer-reader v0.1.7
|
||||||
github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c
|
github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c
|
||||||
github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb
|
github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb
|
||||||
github.com/bradleyfalzon/ghinstallation/v2 v2.4.0
|
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0
|
||||||
github.com/crewjam/rfc5424 v0.1.0
|
github.com/crewjam/rfc5424 v0.1.0
|
||||||
github.com/denisenkom/go-mssqldb v0.12.3
|
github.com/denisenkom/go-mssqldb v0.12.3
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.1
|
github.com/envoyproxy/protoc-gen-validate v0.9.1
|
||||||
github.com/fatih/color v1.15.0
|
github.com/fatih/color v1.13.0
|
||||||
github.com/felixge/fgprof v0.9.3
|
github.com/felixge/fgprof v0.9.3
|
||||||
github.com/getsentry/sentry-go v0.21.0
|
github.com/getsentry/sentry-go v0.18.0
|
||||||
github.com/go-errors/errors v1.4.2
|
github.com/go-errors/errors v1.4.2
|
||||||
github.com/go-git/go-git/v5 v5.6.1
|
github.com/go-git/go-git/v5 v5.5.2
|
||||||
github.com/go-ldap/ldap/v3 v3.4.4
|
github.com/go-ldap/ldap/v3 v3.4.4
|
||||||
github.com/go-logr/logr v1.2.4
|
github.com/go-logr/logr v1.2.3
|
||||||
github.com/go-logr/zapr v1.2.4
|
github.com/go-logr/zapr v1.2.3
|
||||||
github.com/go-redis/redis v6.15.9+incompatible
|
github.com/go-redis/redis v6.15.9+incompatible
|
||||||
github.com/go-sql-driver/mysql v1.7.1
|
github.com/go-sql-driver/mysql v1.7.0
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/google/go-cmp v0.5.9
|
github.com/google/go-cmp v0.5.9
|
||||||
github.com/google/go-github/v42 v42.0.0
|
github.com/google/go-github/v42 v42.0.0
|
||||||
github.com/googleapis/gax-go/v2 v2.9.1
|
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2
|
github.com/hashicorp/go-retryablehttp v0.7.2
|
||||||
github.com/jlaffaye/ftp v0.1.0
|
github.com/jlaffaye/ftp v0.1.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/jpillora/overseer v1.1.6
|
github.com/jpillora/overseer v1.1.6
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.7
|
||||||
github.com/mattn/go-sqlite3 v1.14.17
|
github.com/mattn/go-sqlite3 v1.14.16
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
|
||||||
github.com/paulbellamy/ratecounter v0.2.0
|
github.com/paulbellamy/ratecounter v0.2.0
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9
|
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rabbitmq/amqp091-go v1.8.1
|
github.com/rabbitmq/amqp091-go v1.7.0
|
||||||
github.com/sergi/go-diff v1.3.1
|
github.com/sergi/go-diff v1.3.1
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.2
|
||||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502
|
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502
|
||||||
github.com/xanzy/go-gitlab v0.83.0
|
github.com/xanzy/go-gitlab v0.80.2
|
||||||
go.mongodb.org/mongo-driver v1.11.6
|
go.mongodb.org/mongo-driver v1.11.2
|
||||||
go.uber.org/zap v1.24.0
|
go.uber.org/zap v1.24.0
|
||||||
golang.org/x/crypto v0.9.0
|
golang.org/x/crypto v0.6.0
|
||||||
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7
|
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7
|
||||||
golang.org/x/oauth2 v0.8.0
|
golang.org/x/oauth2 v0.5.0
|
||||||
golang.org/x/sync v0.2.0
|
golang.org/x/sync v0.1.0
|
||||||
golang.org/x/text v0.9.0
|
golang.org/x/text v0.7.0
|
||||||
google.golang.org/api v0.123.0
|
google.golang.org/protobuf v1.28.1
|
||||||
google.golang.org/protobuf v1.30.0
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
gopkg.in/h2non/gock.v1 v1.1.2
|
gopkg.in/h2non/gock.v1 v1.1.2
|
||||||
sigs.k8s.io/yaml v1.3.0
|
sigs.k8s.io/yaml v1.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.110.0 // indirect
|
cloud.google.com/go/compute v1.12.1 // indirect
|
||||||
cloud.google.com/go/compute v1.19.0 // indirect
|
cloud.google.com/go/compute/metadata v0.2.1 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/iam v0.8.0 // indirect
|
||||||
cloud.google.com/go/iam v0.13.0 // indirect
|
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||||
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||||
@@ -78,37 +76,32 @@ require (
|
|||||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
||||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
|
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
|
||||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||||
github.com/bodgit/plumbing v1.2.0 // indirect
|
github.com/cloudflare/circl v1.1.0 // indirect
|
||||||
github.com/bodgit/sevenzip v1.3.0 // indirect
|
|
||||||
github.com/bodgit/windows v1.0.0 // indirect
|
|
||||||
github.com/cloudflare/circl v1.3.3 // indirect
|
|
||||||
github.com/connesc/cipherio v0.2.1 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||||
github.com/dsnet/compress v0.0.1 // indirect
|
github.com/dsnet/compress v0.0.1 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
github.com/go-git/go-billy/v5 v5.4.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/go-github/v52 v52.0.0 // indirect
|
github.com/google/go-github/v45 v45.2.0 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
|
||||||
github.com/google/s2a-go v0.1.3 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
||||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
@@ -118,17 +111,18 @@ require (
|
|||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/jpillora/s3 v1.1.4 // indirect
|
github.com/jpillora/s3 v1.1.4 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.16.0 // indirect
|
github.com/klauspost/compress v1.15.11 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/onsi/gomega v1.23.0 // indirect
|
github.com/onsi/gomega v1.23.0 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||||
|
github.com/pjbgf/sha1cd v0.2.3 // indirect
|
||||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 // indirect
|
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/skeema/knownhosts v1.1.0 // indirect
|
github.com/skeema/knownhosts v1.1.0 // indirect
|
||||||
@@ -143,16 +137,15 @@ require (
|
|||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
golang.org/x/mod v0.7.0 // indirect
|
||||||
golang.org/x/mod v0.10.0 // indirect
|
golang.org/x/net v0.7.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/tools v0.8.0 // indirect
|
golang.org/x/tools v0.3.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
google.golang.org/api v0.103.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect
|
||||||
google.golang.org/grpc v1.55.0 // indirect
|
google.golang.org/grpc v1.51.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
@@ -1,33 +1,14 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk=
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
|
||||||
cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
|
cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60=
|
||||||
cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
|
cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
|
||||||
cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ=
|
|
||||||
cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
|
|
||||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
|
||||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
|
|
||||||
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
|
||||||
cloud.google.com/go/secretmanager v1.10.1 h1:9QwQ3oMurvmPEmM80spGe2SFGDa+RRgkLIdTm3gMWO8=
|
|
||||||
cloud.google.com/go/secretmanager v1.10.1/go.mod h1:pxG0NLpcK6OMy54kfZgQmsKTPxJem708X1es7xv8n60=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
|
||||||
cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI=
|
|
||||||
cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||||
@@ -52,24 +33,22 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
|
|||||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
|
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
|
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
|
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
|
||||||
github.com/TheZeroSlave/zapsentry v1.15.0 h1:w/YglG4Hc2L2VoEH6JKC+3YzhUL18/OZRjJRSvyXZp4=
|
github.com/TheZeroSlave/zapsentry v1.14.0 h1:z6H0lIyKVpdXsP5K8J11b4/+V+QCDLDslZmtXsnduMk=
|
||||||
github.com/TheZeroSlave/zapsentry v1.15.0/go.mod h1:D1YMfSuu6xnkhwFXxrronesmsiyDhIqo+86I3Ok+r64=
|
github.com/TheZeroSlave/zapsentry v1.14.0/go.mod h1:0hUR1Et5tSroEYhWOZcxE2iBqcFkuG7jGGlUmOA7XAs=
|
||||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/aws/aws-sdk-go v1.44.83 h1:7+Rtc2Eio6EKUNoZeMV/IVxzVrY5oBQcNPtCcgIHYJA=
|
github.com/aws/aws-sdk-go v1.44.83 h1:7+Rtc2Eio6EKUNoZeMV/IVxzVrY5oBQcNPtCcgIHYJA=
|
||||||
@@ -82,32 +61,17 @@ github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c h1:tSME5FDS02q
|
|||||||
github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c/go.mod h1:+sCc6hztur+oZCLOsNk6wCCy+GLrnSNHSRmTnnL+8iQ=
|
github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c/go.mod h1:+sCc6hztur+oZCLOsNk6wCCy+GLrnSNHSRmTnnL+8iQ=
|
||||||
github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb h1:9v7Bzlg+1EBYi2IYcUmOwHReBEfqBbYIj3ZCi9cIe1Q=
|
github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb h1:9v7Bzlg+1EBYi2IYcUmOwHReBEfqBbYIj3ZCi9cIe1Q=
|
||||||
github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb/go.mod h1:EkOqCuelvo7DY8vCOoZ09p7pHvAK9B1PHI9GeM4Rdxc=
|
github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb/go.mod h1:EkOqCuelvo7DY8vCOoZ09p7pHvAK9B1PHI9GeM4Rdxc=
|
||||||
github.com/bodgit/plumbing v1.2.0 h1:gg4haxoKphLjml+tgnecR4yLBV5zo4HAZGCtAh3xCzM=
|
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 h1:5+NghM1Zred9Z078QEZtm28G/kfDfZN/92gkDlLwGVA=
|
||||||
github.com/bodgit/plumbing v1.2.0/go.mod h1:b9TeRi7Hvc6Y05rjm8VML3+47n4XTZPtQ/5ghqic2n8=
|
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0/go.mod h1:Xg3xPRN5Mcq6GDqeUVhFbjEWMb4JHCyWEeeBGEYQoTU=
|
||||||
github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY=
|
|
||||||
github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM=
|
|
||||||
github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA=
|
|
||||||
github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
|
||||||
github.com/bradleyfalzon/ghinstallation/v2 v2.4.0 h1:zYSzkoIwekCQAr6GT6KxISLt4YRS6kd4/ixfzMN+7yc=
|
|
||||||
github.com/bradleyfalzon/ghinstallation/v2 v2.4.0/go.mod h1:4MwZLSgBJJgg4i3nJwZJ95AMooSqN8fJDmegLVn9Q2U=
|
|
||||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
|
||||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
|
||||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw=
|
|
||||||
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/crewjam/rfc5424 v0.1.0 h1:MSeXJm22oKovLzWj44AHwaItjIMUMugYGkEzfa831H8=
|
github.com/crewjam/rfc5424 v0.1.0 h1:MSeXJm22oKovLzWj44AHwaItjIMUMugYGkEzfa831H8=
|
||||||
github.com/crewjam/rfc5424 v0.1.0/go.mod h1:RCi9M3xHVOeerf6ULZzqv2xOGRO/zYaVUeRyPnBW3gQ=
|
github.com/crewjam/rfc5424 v0.1.0/go.mod h1:RCi9M3xHVOeerf6ULZzqv2xOGRO/zYaVUeRyPnBW3gQ=
|
||||||
@@ -127,21 +91,18 @@ github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.1 h1:kt9FtLiooDc0vbwTLhdg3dyNX1K9Qwa1EK9LcD4jVUQ=
|
github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs=
|
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
|
||||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/getsentry/sentry-go v0.21.0 h1:c9l5F1nPF30JIppulk4veau90PK6Smu3abgVtVQWon4=
|
github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
|
||||||
github.com/getsentry/sentry-go v0.21.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||||
@@ -151,26 +112,25 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop
|
|||||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
github.com/go-git/go-billy/v5 v5.4.0 h1:Vaw7LaSTRJOUric7pe4vnzBSgyuf2KrLsu2Y4ZpQBDE=
|
||||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
|
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||||
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
|
github.com/go-git/go-git/v5 v5.5.2 h1:v8lgZa5k9ylUw+OR/roJHTxR4QItsNFI5nKtAXFuynw=
|
||||||
github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
|
github.com/go-git/go-git/v5 v5.5.2/go.mod h1:BE5hUJ5yaV2YMxhmaP4l6RBQ08kMxKSPD4BlxtH7OjI=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
|
github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
|
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
|
||||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||||
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
|
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
||||||
|
github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
@@ -181,28 +141,19 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL
|
|||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
@@ -212,14 +163,11 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -233,34 +181,20 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec=
|
github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec=
|
||||||
github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg=
|
github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg=
|
||||||
github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M=
|
github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI=
|
||||||
github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4=
|
github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE=
|
|
||||||
github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
|
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.9.1 h1:DpTpJqzZ3NvX9zqjhIuI1oVzYZMvboZe+3LoeEIJjHM=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.9.1/go.mod h1:4FG3gMrVZlyMp5itSYKMU9z/lBE7+SbnUOvzH2HqbEY=
|
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
@@ -273,10 +207,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
|||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
|
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||||
@@ -293,15 +224,12 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
|||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/jpillora/s3 v1.1.4 h1:YCCKDWzb/Ye9EBNd83ATRF/8wPEy0xd43Rezb6u6fzc=
|
github.com/jpillora/s3 v1.1.4 h1:YCCKDWzb/Ye9EBNd83ATRF/8wPEy0xd43Rezb6u6fzc=
|
||||||
github.com/jpillora/s3 v1.1.4/go.mod h1:yedE603V+crlFi1Kl/5vZJaBu9pUzE9wvKegU/lF2zs=
|
github.com/jpillora/s3 v1.1.4/go.mod h1:yedE603V+crlFi1Kl/5vZJaBu9pUzE9wvKegU/lF2zs=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
|
||||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
|
||||||
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
@@ -314,22 +242,23 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7 h1:xzByj8G8tj0Oq7ZYYU4+ixL/CVb5ruWCm0EZQ1PjOkE=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mholt/archiver/v4 v4.0.0-alpha.7/go.mod h1:Fs8qUkO74HHaidabihzYephJH8qmGD/nCP6tE5xC9BM=
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
|
|
||||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
|
||||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||||
@@ -350,17 +279,15 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
|||||||
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
|
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
|
||||||
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
|
||||||
github.com/paulbellamy/ratecounter v0.2.0 h1:2L/RhJq+HA8gBQImDXtLPrDXK5qAj6ozWVK/zFXVJGs=
|
github.com/paulbellamy/ratecounter v0.2.0 h1:2L/RhJq+HA8gBQImDXtLPrDXK5qAj6ozWVK/zFXVJGs=
|
||||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 h1:lL+y4Xv20pVlCGyLzNHRC0I0rIHhIL1lTvHizoS/dU8=
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 h1:lL+y4Xv20pVlCGyLzNHRC0I0rIHhIL1lTvHizoS/dU8=
|
||||||
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
|
github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI=
|
||||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M=
|
||||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 h1:+/+DxvQaYifJ+grD4klzrS5y+KJXldn/2YTl5JG+vZ8=
|
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 h1:+/+DxvQaYifJ+grD4klzrS5y+KJXldn/2YTl5JG+vZ8=
|
||||||
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
|
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
|
||||||
@@ -370,11 +297,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/rabbitmq/amqp091-go v1.8.1 h1:RejT1SBUim5doqcL6s7iN6SBmsQqyTgXb1xMlH0h1hA=
|
github.com/rabbitmq/amqp091-go v1.7.0 h1:V5CF5qPem5OGSnEo8BoSbsDGwejg6VUJsKEdneaoTUo=
|
||||||
github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
github.com/rabbitmq/amqp091-go v1.7.0/go.mod h1:wfClAtY0C7bOHxd3GjmF26jEHn+rR/0B3+YV+Vn9/NI=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
@@ -399,8 +323,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 h1:34icjjmqJ2HPjrSuJYEkdZ+0ItmGQAQ75cRHIiftIyE=
|
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 h1:34icjjmqJ2HPjrSuJYEkdZ+0ItmGQAQ75cRHIiftIyE=
|
||||||
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8=
|
||||||
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
|
||||||
@@ -412,8 +336,8 @@ github.com/trufflesecurity/overseer v1.1.7-custom5/go.mod h1:nT9w37AiO1Nop2VhVhN
|
|||||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/xanzy/go-gitlab v0.83.0 h1:37p0MpTPNbsTMKX/JnmJtY8Ch1sFiJzVF342+RvZEGw=
|
github.com/xanzy/go-gitlab v0.80.2 h1:CH1Q7NDklqZllox4ICVF4PwlhQGfPtE+w08Jsb74ZX0=
|
||||||
github.com/xanzy/go-gitlab v0.83.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
|
github.com/xanzy/go-gitlab v0.80.2/go.mod h1:DlByVTSXhPsJMYL6+cm8e8fTJjeBmhrXdC/yvkKKt6M=
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
@@ -429,96 +353,55 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o=
|
go.mongodb.org/mongo-driver v1.11.2 h1:+1v2rDQUWNcGW7/7E0Jvdz51V38XXxJfhzbV17aNHCw=
|
||||||
go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
|
go.mongodb.org/mongo-driver v1.11.2/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
|
|
||||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
|
||||||
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
|
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
|
||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
|
||||||
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7 h1:lhh9BuEmjIBOdOhMIGSQzdW5LbTtFbUV1k9O/Rlq3SE=
|
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7 h1:lhh9BuEmjIBOdOhMIGSQzdW5LbTtFbUV1k9O/Rlq3SE=
|
||||||
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
golang.org/x/exp v0.0.0-20221018205818-5c77f4b2bbd7/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
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.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
|
||||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
@@ -528,51 +411,30 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.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.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
|
||||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
|
||||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
|
||||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -586,6 +448,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -594,124 +457,60 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
|
||||||
golang.org/x/sys v0.8.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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
|
||||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
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.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
|
||||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.123.0 h1:yHVU//vA+qkOhm4reEC9LtzHVUCN/IqqNRl1iQ9xE20=
|
|
||||||
google.golang.org/api v0.123.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c h1:S34D59DS2GWOEwWNt4fYmTcFrtlOgukG2k9WsomZ7tg=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
|
||||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -723,9 +522,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -734,7 +532,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
|
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
|
||||||
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
|
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
|
||||||
@@ -743,7 +540,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@@ -755,13 +551,6 @@ gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
set terminal png size 800,600
|
|
||||||
set output "hack/bench/versions.png"
|
|
||||||
|
|
||||||
set title "User Time vs. Version"
|
|
||||||
set xlabel "Version"
|
|
||||||
set ylabel "Average User Time (s)"
|
|
||||||
|
|
||||||
set xtics rotate by -45
|
|
||||||
|
|
||||||
plot "hack/bench/plot.txt" using 2:xtic(1) with linespoints linestyle 1 notitle
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "Usage: $0 <repository to clone> <number_of_versions_back_to_test>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the number of versions back to test from command line argument
|
|
||||||
num_versions="$2"
|
|
||||||
|
|
||||||
test_repo="$1"
|
|
||||||
|
|
||||||
bash hack/bench/versions.sh $test_repo $num_versions | tee hack/bench/plot.txt
|
|
||||||
|
|
||||||
gnuplot hack/bench/plot.gp
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
v3.33.0: 1.402
|
|
||||||
v3.32.2: 1.298
|
|
||||||
v3.32.1: 1.332
|
|
||||||
v3.32.0: 1.348
|
|
||||||
v3.31.6: 2.470
|
|
||||||
v3.31.5: 2.462
|
|
||||||
v3.31.4: 2.460
|
|
||||||
v3.31.3: 2.418
|
|
||||||
v3.31.2: 1.384
|
|
||||||
v3.31.1: 1.344
|
|
||||||
v3.31.0: 1.354
|
|
||||||
v3.30.0: 1.392
|
|
||||||
v3.29.1: 1.382
|
|
||||||
v3.29.0: 1.340
|
|
||||||
v3.28.7: 1.380
|
|
||||||
v3.28.6: 1.308
|
|
||||||
v3.28.5: 2.596
|
|
||||||
v3.28.4: 2.554
|
|
||||||
v3.28.3: 2.582
|
|
||||||
v3.28.1: 2.578
|
|
||||||
v3.28.2: 2.566
|
|
||||||
v3.28.0: 2.552
|
|
||||||
v3.27.1: 2.574
|
|
||||||
v3.26.0: 2.538
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.3 KiB |
@@ -1,80 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "Usage: $0 <repository to clone> <number_of_versions_back_to_test>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the number of versions back to test from command line argument
|
|
||||||
num_versions="$2"
|
|
||||||
|
|
||||||
test_repo="$1"
|
|
||||||
|
|
||||||
num_iterations=5
|
|
||||||
|
|
||||||
# Create a temporary folder to clone the repository
|
|
||||||
repo_tmp=$(mktemp -d)
|
|
||||||
# Set up a trap to remove the temporary folder on exit or failure
|
|
||||||
trap "rm -rf $repo_tmp" EXIT
|
|
||||||
# Clone the test repository to a temporary folder
|
|
||||||
git clone --quiet "$test_repo" $repo_tmp
|
|
||||||
|
|
||||||
|
|
||||||
# Get list of git tags, sorted from newest to oldest
|
|
||||||
tags=$(git tag --sort=-creatordate)
|
|
||||||
|
|
||||||
# Counter to keep track of number of tags checked out
|
|
||||||
count=0
|
|
||||||
|
|
||||||
|
|
||||||
# Loop over tags and checkout each one in turn, up to the specified number of versions
|
|
||||||
for tag in $tags
|
|
||||||
do
|
|
||||||
if [[ $count -eq $num_versions ]]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Skip RC tags
|
|
||||||
if [[ $tag == *"rc"* ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Skip alpha tags
|
|
||||||
if [[ $tag == *"alpha"* ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use git checkout with the quiet flag to suppress output
|
|
||||||
git checkout $tag --quiet
|
|
||||||
|
|
||||||
# Run make install with suppressed output
|
|
||||||
make install > /dev/null
|
|
||||||
|
|
||||||
# Initialize the variable to store the sum of user times
|
|
||||||
user_time_sum=0
|
|
||||||
|
|
||||||
# Run each iteration 5 times and calculate the average user time
|
|
||||||
for i in {1..$num_iterations}
|
|
||||||
do
|
|
||||||
# Run trufflehog with suppressed output and capture user time with /usr/bin/time
|
|
||||||
tmpfile=$(mktemp)
|
|
||||||
/usr/bin/time -o $tmpfile trufflehog git "file://$repo_tmp" --no-verification --no-update >/dev/null 2>&1
|
|
||||||
time_output=$(cat $tmpfile)
|
|
||||||
rm $tmpfile
|
|
||||||
|
|
||||||
# Extract the user time from the output
|
|
||||||
user_time=$(echo $time_output | awk '{print $3}')
|
|
||||||
|
|
||||||
# Add the user time to the sum
|
|
||||||
user_time_sum=$(echo "$user_time_sum + $user_time" | bc)
|
|
||||||
done
|
|
||||||
|
|
||||||
# Calculate the average user time
|
|
||||||
average_user_time=$(echo "scale=3; $user_time_sum / $num_iterations" | bc)
|
|
||||||
|
|
||||||
# Print the average user time output for this iteration in the specified format
|
|
||||||
echo "$tag: $average_user_time"
|
|
||||||
|
|
||||||
# Increment the counter
|
|
||||||
count=$((count+1))
|
|
||||||
done
|
|
||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/handlers"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/handlers"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/log"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/log"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/output"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/output"
|
||||||
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources/git"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/updater"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/updater"
|
||||||
@@ -33,24 +34,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cli = kingpin.New("TruffleHog", "TruffleHog is a tool for finding credentials.")
|
cli = kingpin.New("TruffleHog", "TruffleHog is a tool for finding credentials.")
|
||||||
cmd string
|
cmd string
|
||||||
debug = cli.Flag("debug", "Run in debug mode.").Bool()
|
debug = cli.Flag("debug", "Run in debug mode.").Bool()
|
||||||
trace = cli.Flag("trace", "Run in trace mode.").Bool()
|
trace = cli.Flag("trace", "Run in trace mode.").Bool()
|
||||||
profile = cli.Flag("profile", "Enables profiling and sets a pprof and fgprof server on :18066.").Bool()
|
profile = cli.Flag("profile", "Enables profiling and sets a pprof and fgprof server on :18066.").Bool()
|
||||||
jsonOut = cli.Flag("json", "Output in JSON format.").Short('j').Bool()
|
jsonOut = cli.Flag("json", "Output in JSON format.").Short('j').Bool()
|
||||||
jsonLegacy = cli.Flag("json-legacy", "Use the pre-v3.0 JSON format. Only works with git, gitlab, and github sources.").Bool()
|
jsonLegacy = cli.Flag("json-legacy", "Use the pre-v3.0 JSON format. Only works with git, gitlab, and github sources.").Bool()
|
||||||
gitHubActionsFormat = cli.Flag("github-actions", "Output in GitHub Actions format.").Bool()
|
concurrency = cli.Flag("concurrency", "Number of concurrent workers.").Default(strconv.Itoa(runtime.NumCPU())).Int()
|
||||||
concurrency = cli.Flag("concurrency", "Number of concurrent workers.").Default(strconv.Itoa(runtime.NumCPU())).Int()
|
noVerification = cli.Flag("no-verification", "Don't verify the results.").Bool()
|
||||||
noVerification = cli.Flag("no-verification", "Don't verify the results.").Bool()
|
onlyVerified = cli.Flag("only-verified", "Only output verified results.").Bool()
|
||||||
onlyVerified = cli.Flag("only-verified", "Only output verified results.").Bool()
|
filterUnverified = cli.Flag("filter-unverified", "Only output first unverified result per chunk per detector if there are more than one results.").Bool()
|
||||||
filterUnverified = cli.Flag("filter-unverified", "Only output first unverified result per chunk per detector if there are more than one results.").Bool()
|
configFilename = cli.Flag("config", "Path to configuration file.").ExistingFile()
|
||||||
configFilename = cli.Flag("config", "Path to configuration file.").ExistingFile()
|
|
||||||
// rules = cli.Flag("rules", "Path to file with custom rules.").String()
|
// rules = cli.Flag("rules", "Path to file with custom rules.").String()
|
||||||
printAvgDetectorTime = cli.Flag("print-avg-detector-time", "Print the average time spent on each detector.").Bool()
|
printAvgDetectorTime = cli.Flag("print-avg-detector-time", "Print the average time spent on each detector.").Bool()
|
||||||
noUpdate = cli.Flag("no-update", "Don't check for updates.").Bool()
|
noUpdate = cli.Flag("no-update", "Don't check for updates.").Bool()
|
||||||
fail = cli.Flag("fail", "Exit with code 183 if results are found.").Bool()
|
fail = cli.Flag("fail", "Exit with code 183 if results are found.").Bool()
|
||||||
verifiers = cli.Flag("verifier", "Set custom verification endpoints.").StringMap()
|
|
||||||
archiveMaxSize = cli.Flag("archive-max-size", "Maximum size of archive to scan. (Byte units eg. 512B, 2KB, 4MB)").Bytes()
|
archiveMaxSize = cli.Flag("archive-max-size", "Maximum size of archive to scan. (Byte units eg. 512B, 2KB, 4MB)").Bytes()
|
||||||
archiveMaxDepth = cli.Flag("archive-max-depth", "Maximum depth of archive to scan.").Int()
|
archiveMaxDepth = cli.Flag("archive-max-depth", "Maximum depth of archive to scan.").Int()
|
||||||
archiveTimeout = cli.Flag("archive-timeout", "Maximum time to spend extracting an archive.").Duration()
|
archiveTimeout = cli.Flag("archive-timeout", "Maximum time to spend extracting an archive.").Duration()
|
||||||
@@ -61,7 +60,6 @@ var (
|
|||||||
gitScanURI = gitScan.Arg("uri", "Git repository URL. https://, file://, or ssh:// schema expected.").Required().String()
|
gitScanURI = gitScan.Arg("uri", "Git repository URL. https://, file://, or ssh:// schema expected.").Required().String()
|
||||||
gitScanIncludePaths = gitScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
gitScanIncludePaths = gitScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
||||||
gitScanExcludePaths = gitScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
gitScanExcludePaths = gitScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
||||||
gitScanExcludeGlobs = gitScan.Flag("exclude-globs", "Comma separated list of globs to exclude in scan. This option filters at the `git log` level, resulting in faster scans.").String()
|
|
||||||
gitScanSinceCommit = gitScan.Flag("since-commit", "Commit to start scan from.").String()
|
gitScanSinceCommit = gitScan.Flag("since-commit", "Commit to start scan from.").String()
|
||||||
gitScanBranch = gitScan.Flag("branch", "Branch to scan.").String()
|
gitScanBranch = gitScan.Flag("branch", "Branch to scan.").String()
|
||||||
gitScanMaxDepth = gitScan.Flag("max-depth", "Maximum depth of commits to scan.").Int()
|
gitScanMaxDepth = gitScan.Flag("max-depth", "Maximum depth of commits to scan.").Int()
|
||||||
@@ -98,25 +96,11 @@ var (
|
|||||||
filesystemScanIncludePaths = filesystemScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
filesystemScanIncludePaths = filesystemScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String()
|
||||||
filesystemScanExcludePaths = filesystemScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
filesystemScanExcludePaths = filesystemScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String()
|
||||||
|
|
||||||
s3Scan = cli.Command("s3", "Find credentials in S3 buckets.")
|
s3Scan = cli.Command("s3", "Find credentials in S3 buckets.")
|
||||||
s3ScanKey = s3Scan.Flag("key", "S3 key used to authenticate. Can be provided with environment variable AWS_ACCESS_KEY_ID.").Envar("AWS_ACCESS_KEY_ID").String()
|
s3ScanKey = s3Scan.Flag("key", "S3 key used to authenticate. Can be provided with environment variable AWS_ACCESS_KEY_ID.").Envar("AWS_ACCESS_KEY_ID").String()
|
||||||
s3ScanSecret = s3Scan.Flag("secret", "S3 secret used to authenticate. Can be provided with environment variable AWS_SECRET_ACCESS_KEY.").Envar("AWS_SECRET_ACCESS_KEY").String()
|
s3ScanSecret = s3Scan.Flag("secret", "S3 secret used to authenticate. Can be provided with environment variable AWS_SECRET_ACCESS_KEY.").Envar("AWS_SECRET_ACCESS_KEY").String()
|
||||||
s3ScanSessionToken = s3Scan.Flag("session-token", "S3 session token used to authenticate temporary credentials. Can be provided with environment variable AWS_SESSION_TOKEN.").Envar("AWS_SESSION_TOKEN").String()
|
s3ScanCloudEnv = s3Scan.Flag("cloud-environment", "Use IAM credentials in cloud environment.").Bool()
|
||||||
s3ScanCloudEnv = s3Scan.Flag("cloud-environment", "Use IAM credentials in cloud environment.").Bool()
|
s3ScanBuckets = s3Scan.Flag("bucket", "Name of S3 bucket to scan. You can repeat this flag.").Strings()
|
||||||
s3ScanBuckets = s3Scan.Flag("bucket", "Name of S3 bucket to scan. You can repeat this flag.").Strings()
|
|
||||||
s3ScanMaxObjectSize = s3Scan.Flag("max-object-size", "Maximum size of objects to scan. Objects larger than this will be skipped. (Byte units eg. 512B, 2KB, 4MB)").Default("250MB").Bytes()
|
|
||||||
|
|
||||||
gcsScan = cli.Command("gcs", "Find credentials in GCS buckets.")
|
|
||||||
gcsProjectID = gcsScan.Flag("project-id", "GCS project ID used to authenticate. Can NOT be used with unauth scan. Can be provided with environment variable GOOGLE_CLOUD_PROJECT.").Envar("GOOGLE_CLOUD_PROJECT").String()
|
|
||||||
gcsCloudEnv = gcsScan.Flag("cloud-environment", "Use Application Default Credentials, IAM credentials to authenticate.").Bool()
|
|
||||||
gcsServiceAccount = gcsScan.Flag("service-account", "Path to GCS service account JSON file.").ExistingFile()
|
|
||||||
gcsWithoutAuth = gcsScan.Flag("without-auth", "Scan GCS buckets without authentication. This will only work for public buckets").Bool()
|
|
||||||
gcsAPIKey = gcsScan.Flag("api-key", "GCS API key used to authenticate. Can be provided with environment variable GOOGLE_API_KEY.").Envar("GOOGLE_API_KEY").String()
|
|
||||||
gcsIncludeBuckets = gcsScan.Flag("include-buckets", "Buckets to scan. Comma seperated list of buckets. You can repeat this flag. Globs are supported").Short('I').Strings()
|
|
||||||
gcsExcludeBuckets = gcsScan.Flag("exclude-buckets", "Buckets to exclude from scan. Comma separated list of buckets. Globs are supported").Short('X').Strings()
|
|
||||||
gcsIncludeObjects = gcsScan.Flag("include-objects", "Objects to scan. Comma separated list of objects. you can repeat this flag. Globs are supported").Short('i').Strings()
|
|
||||||
gcsExcludeObjects = gcsScan.Flag("exclude-objects", "Objects to exclude from scan. Comma separated list of objects. You can repeat this flag. Globs are supported").Short('x').Strings()
|
|
||||||
gcsMaxObjectSize = gcsScan.Flag("max-object-size", "Maximum size of objects to scan. Objects larger than this will be skipped. (Byte units eg. 512B, 2KB, 4MB)").Default("10MB").Bytes()
|
|
||||||
|
|
||||||
syslogScan = cli.Command("syslog", "Scan syslog")
|
syslogScan = cli.Command("syslog", "Scan syslog")
|
||||||
syslogAddress = syslogScan.Flag("address", "Address and port to listen on for syslog. Example: 127.0.0.1:514").String()
|
syslogAddress = syslogScan.Flag("address", "Address and port to listen on for syslog. Example: 127.0.0.1:514").String()
|
||||||
@@ -231,85 +215,53 @@ func run(state overseer.State) {
|
|||||||
handlers.SetArchiveMaxTimeout(*archiveTimeout)
|
handlers.SetArchiveMaxTimeout(*archiveTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build include and exclude detector sets for filtering on engine initialization.
|
// Build include and exclude detector filter sets.
|
||||||
// Exit if there was an error to inform the user of the misconfiguration.
|
var includeDetectorTypes, excludeDetectorTypes map[detectorspb.DetectorType]config.DetectorID
|
||||||
var includeDetectorSet, excludeDetectorSet map[config.DetectorID]struct{}
|
|
||||||
var detectorsWithCustomVerifierEndpoints map[config.DetectorID][]string
|
|
||||||
{
|
{
|
||||||
includeList, err := config.ParseDetectors(*includeDetectors)
|
includeList, err := config.ParseDetectors(*includeDetectors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Exit if there was an error to inform the user of the misconfiguration.
|
||||||
logFatal(err, "invalid include list detector configuration")
|
logFatal(err, "invalid include list detector configuration")
|
||||||
}
|
}
|
||||||
excludeList, err := config.ParseDetectors(*excludeDetectors)
|
excludeList, err := config.ParseDetectors(*excludeDetectors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Exit if there was an error to inform the user of the misconfiguration.
|
||||||
logFatal(err, "invalid exclude list detector configuration")
|
logFatal(err, "invalid exclude list detector configuration")
|
||||||
}
|
}
|
||||||
detectorsWithCustomVerifierEndpoints, err = config.ParseVerifierEndpoints(*verifiers)
|
includeDetectorTypes = detectorTypeToMap(includeList)
|
||||||
if err != nil {
|
excludeDetectorTypes = detectorTypeToMap(excludeList)
|
||||||
logFatal(err, "invalid verifier detector configuration")
|
|
||||||
}
|
|
||||||
includeDetectorSet = detectorTypeToSet(includeList)
|
|
||||||
excludeDetectorSet = detectorTypeToSet(excludeList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that all the user-provided detectors support the optional
|
|
||||||
// detector features.
|
|
||||||
{
|
|
||||||
if err, id := verifyDetectorsAreVersioner(includeDetectorSet); err != nil {
|
|
||||||
logFatal(err, "invalid include list detector configuration", "detector", id)
|
|
||||||
}
|
|
||||||
if err, id := verifyDetectorsAreVersioner(excludeDetectorSet); err != nil {
|
|
||||||
logFatal(err, "invalid exclude list detector configuration", "detector", id)
|
|
||||||
}
|
|
||||||
if err, id := verifyDetectorsAreVersioner(detectorsWithCustomVerifierEndpoints); err != nil {
|
|
||||||
logFatal(err, "invalid verifier detector configuration", "detector", id)
|
|
||||||
}
|
|
||||||
// Extra check for endpoint customization.
|
|
||||||
isEndpointCustomizer := engine.DefaultDetectorTypesImplementing[detectors.EndpointCustomizer]()
|
|
||||||
for id := range detectorsWithCustomVerifierEndpoints {
|
|
||||||
if _, ok := isEndpointCustomizer[id.ID]; !ok {
|
|
||||||
logFatal(
|
|
||||||
fmt.Errorf("endpoint provided but detector does not support endpoint customization"),
|
|
||||||
"invalid custom verifier endpoint detector configuration",
|
|
||||||
"detector", id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
includeFilter := func(d detectors.Detector) bool {
|
includeFilter := func(d detectors.Detector) bool {
|
||||||
_, ok := getWithDetectorID(d, includeDetectorSet)
|
id, ok := includeDetectorTypes[d.Type()]
|
||||||
return ok
|
if id.Version == 0 {
|
||||||
}
|
return ok
|
||||||
excludeFilter := func(d detectors.Detector) bool {
|
|
||||||
_, ok := getWithDetectorID(d, excludeDetectorSet)
|
|
||||||
return !ok
|
|
||||||
}
|
|
||||||
// Abuse filter to cause a side-effect.
|
|
||||||
endpointCustomizer := func(d detectors.Detector) bool {
|
|
||||||
urls, ok := getWithDetectorID(d, detectorsWithCustomVerifierEndpoints)
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
id := config.GetDetectorID(d)
|
versionD, ok := d.(detectors.Versioner)
|
||||||
customizer, ok := d.(detectors.EndpointCustomizer)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
// NOTE: We should never reach here due to validation above.
|
// Error: version provided but not a detectors.Versioner
|
||||||
logFatal(
|
logFatal(
|
||||||
fmt.Errorf("failed to configure a detector endpoint"),
|
fmt.Errorf("version provided but detector does not have a version"),
|
||||||
"the provided detector does not support endpoint configuration",
|
"invalid include list detector configuration",
|
||||||
"detector", id,
|
"detector", id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// TODO: Add flag to ignore the default endpoint.
|
return versionD.Version() == id.Version
|
||||||
urls = append(urls, customizer.DefaultEndpoint())
|
}
|
||||||
if err := customizer.SetEndpoints(urls...); err != nil {
|
excludeFilter := func(d detectors.Detector) bool {
|
||||||
logFatal(err, "failed configuring custom endpoint for detector", "detector", id)
|
id, ok := excludeDetectorTypes[d.Type()]
|
||||||
|
if id.Version == 0 {
|
||||||
|
return !ok
|
||||||
}
|
}
|
||||||
logger.Info("configured detector with verification urls",
|
versionD, ok := d.(detectors.Versioner)
|
||||||
"detector", id, "urls", urls,
|
if !ok {
|
||||||
)
|
// Error: version provided but not a detectors.Versioner
|
||||||
return true
|
logFatal(
|
||||||
|
fmt.Errorf("version provided but detector does not have a version"),
|
||||||
|
"invalid exclude list detector configuration",
|
||||||
|
"detector", id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return versionD.Version() != id.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
e := engine.Start(ctx,
|
e := engine.Start(ctx,
|
||||||
@@ -319,7 +271,6 @@ func run(state overseer.State) {
|
|||||||
engine.WithDetectors(!*noVerification, conf.Detectors...),
|
engine.WithDetectors(!*noVerification, conf.Detectors...),
|
||||||
engine.WithFilterDetectors(includeFilter),
|
engine.WithFilterDetectors(includeFilter),
|
||||||
engine.WithFilterDetectors(excludeFilter),
|
engine.WithFilterDetectors(excludeFilter),
|
||||||
engine.WithFilterDetectors(endpointCustomizer),
|
|
||||||
engine.WithFilterUnverified(*filterUnverified),
|
engine.WithFilterUnverified(*filterUnverified),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -338,18 +289,13 @@ func run(state overseer.State) {
|
|||||||
if remote {
|
if remote {
|
||||||
defer os.RemoveAll(repoPath)
|
defer os.RemoveAll(repoPath)
|
||||||
}
|
}
|
||||||
excludedGlobs := []string{}
|
|
||||||
if *gitScanExcludeGlobs != "" {
|
|
||||||
excludedGlobs = strings.Split(*gitScanExcludeGlobs, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := sources.GitConfig{
|
cfg := sources.GitConfig{
|
||||||
RepoPath: repoPath,
|
RepoPath: repoPath,
|
||||||
HeadRef: *gitScanBranch,
|
HeadRef: *gitScanBranch,
|
||||||
BaseRef: *gitScanSinceCommit,
|
BaseRef: *gitScanSinceCommit,
|
||||||
MaxDepth: *gitScanMaxDepth,
|
MaxDepth: *gitScanMaxDepth,
|
||||||
Filter: filter,
|
Filter: filter,
|
||||||
ExcludeGlobs: excludedGlobs,
|
|
||||||
}
|
}
|
||||||
if err = e.ScanGit(ctx, cfg); err != nil {
|
if err = e.ScanGit(ctx, cfg); err != nil {
|
||||||
logFatal(err, "Failed to scan Git.")
|
logFatal(err, "Failed to scan Git.")
|
||||||
@@ -413,12 +359,10 @@ func run(state overseer.State) {
|
|||||||
}
|
}
|
||||||
case s3Scan.FullCommand():
|
case s3Scan.FullCommand():
|
||||||
cfg := sources.S3Config{
|
cfg := sources.S3Config{
|
||||||
Key: *s3ScanKey,
|
Key: *s3ScanKey,
|
||||||
Secret: *s3ScanSecret,
|
Secret: *s3ScanSecret,
|
||||||
SessionToken: *s3ScanSessionToken,
|
Buckets: *s3ScanBuckets,
|
||||||
Buckets: *s3ScanBuckets,
|
CloudCred: *s3ScanCloudEnv,
|
||||||
CloudCred: *s3ScanCloudEnv,
|
|
||||||
MaxObjectSize: int64(*s3ScanMaxObjectSize),
|
|
||||||
}
|
}
|
||||||
if err := e.ScanS3(ctx, cfg); err != nil {
|
if err := e.ScanS3(ctx, cfg); err != nil {
|
||||||
logFatal(err, "Failed to scan S3.")
|
logFatal(err, "Failed to scan S3.")
|
||||||
@@ -439,23 +383,6 @@ func run(state overseer.State) {
|
|||||||
if err := e.ScanCircleCI(ctx, *circleCiScanToken); err != nil {
|
if err := e.ScanCircleCI(ctx, *circleCiScanToken); err != nil {
|
||||||
logFatal(err, "Failed to scan CircleCI.")
|
logFatal(err, "Failed to scan CircleCI.")
|
||||||
}
|
}
|
||||||
case gcsScan.FullCommand():
|
|
||||||
cfg := sources.GCSConfig{
|
|
||||||
ProjectID: *gcsProjectID,
|
|
||||||
CloudCred: *gcsCloudEnv,
|
|
||||||
ServiceAccount: *gcsServiceAccount,
|
|
||||||
WithoutAuth: *gcsWithoutAuth,
|
|
||||||
ApiKey: *gcsAPIKey,
|
|
||||||
IncludeBuckets: commaSeperatedToSlice(*gcsIncludeBuckets),
|
|
||||||
ExcludeBuckets: commaSeperatedToSlice(*gcsExcludeBuckets),
|
|
||||||
IncludeObjects: commaSeperatedToSlice(*gcsIncludeObjects),
|
|
||||||
ExcludeObjects: commaSeperatedToSlice(*gcsExcludeObjects),
|
|
||||||
Concurrency: *concurrency,
|
|
||||||
MaxObjectSize: int64(*gcsMaxObjectSize),
|
|
||||||
}
|
|
||||||
if err := e.ScanGCS(ctx, cfg); err != nil {
|
|
||||||
logFatal(err, "Failed to scan GCS.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// asynchronously wait for scanning to finish and cleanup
|
// asynchronously wait for scanning to finish and cleanup
|
||||||
go e.Finish(ctx)
|
go e.Finish(ctx)
|
||||||
@@ -479,8 +406,6 @@ func run(state overseer.State) {
|
|||||||
err = output.PrintLegacyJSON(ctx, &r)
|
err = output.PrintLegacyJSON(ctx, &r)
|
||||||
case *jsonOut:
|
case *jsonOut:
|
||||||
err = output.PrintJSON(&r)
|
err = output.PrintJSON(&r)
|
||||||
case *gitHubActionsFormat:
|
|
||||||
err = output.PrintGitHubActionsOutput(&r)
|
|
||||||
default:
|
default:
|
||||||
err = output.PrintPlainOutput(&r)
|
err = output.PrintPlainOutput(&r)
|
||||||
}
|
}
|
||||||
@@ -503,20 +428,6 @@ func run(state overseer.State) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func commaSeperatedToSlice(s []string) []string {
|
|
||||||
var result []string
|
|
||||||
for _, items := range s {
|
|
||||||
for _, item := range strings.Split(items, ",") {
|
|
||||||
item = strings.TrimSpace(item)
|
|
||||||
if item == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result = append(result, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func printAverageDetectorTime(e *engine.Engine) {
|
func printAverageDetectorTime(e *engine.Engine) {
|
||||||
fmt.Fprintln(os.Stderr, "Average detector time is the measurement of average time spent on each detector when results are returned.")
|
fmt.Fprintln(os.Stderr, "Average detector time is the measurement of average time spent on each detector when results are returned.")
|
||||||
for detectorName, durations := range e.DetectorAvgTime() {
|
for detectorName, durations := range e.DetectorAvgTime() {
|
||||||
@@ -542,46 +453,10 @@ func logFatalFunc(logger logr.Logger) func(error, string, ...any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// detectorTypeToSet is a helper function to convert a slice of detector IDs into a set.
|
func detectorTypeToMap(detectors []config.DetectorID) map[detectorspb.DetectorType]config.DetectorID {
|
||||||
func detectorTypeToSet(detectors []config.DetectorID) map[config.DetectorID]struct{} {
|
output := make(map[detectorspb.DetectorType]config.DetectorID, len(detectors))
|
||||||
output := make(map[config.DetectorID]struct{}, len(detectors))
|
|
||||||
for _, d := range detectors {
|
for _, d := range detectors {
|
||||||
output[d] = struct{}{}
|
output[d.ID] = d
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// getWithDetectorID is a helper function to get a value from a map using a
|
|
||||||
// detector's ID. This function behaves like a normal map lookup, with an extra
|
|
||||||
// step of checking for the non-specific version of a detector.
|
|
||||||
func getWithDetectorID[T any](d detectors.Detector, data map[config.DetectorID]T) (T, bool) {
|
|
||||||
key := config.GetDetectorID(d)
|
|
||||||
// Check if the specific ID is provided.
|
|
||||||
if t, ok := data[key]; ok || key.Version == 0 {
|
|
||||||
return t, ok
|
|
||||||
}
|
|
||||||
// Check if the generic type is provided without a version.
|
|
||||||
// This means "all" versions of a type.
|
|
||||||
key.Version = 0
|
|
||||||
t, ok := data[key]
|
|
||||||
return t, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyDetectorsAreVersioner checks all keys in a provided map to verify the
|
|
||||||
// provided type is actually a Versioner.
|
|
||||||
func verifyDetectorsAreVersioner[T any](data map[config.DetectorID]T) (error, config.DetectorID) {
|
|
||||||
isVersioner := engine.DefaultDetectorTypesImplementing[detectors.Versioner]()
|
|
||||||
for id := range data {
|
|
||||||
if id.Version == 0 {
|
|
||||||
// Version not provided.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, ok := isVersioner[id.ID]; ok {
|
|
||||||
// Version provided for a Versioner detector.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Version provided on a non-Versioner detector.
|
|
||||||
return fmt.Errorf("version provided but detector does not have a version"), id
|
|
||||||
}
|
|
||||||
return nil, config.DetectorID{}
|
|
||||||
}
|
|
||||||
|
|||||||
Vendored
-24
@@ -1,24 +0,0 @@
|
|||||||
// Package cache provides an interface which can be implemented by different cache types.
|
|
||||||
package cache
|
|
||||||
|
|
||||||
// Cache is used to store key/value pairs.
|
|
||||||
type Cache interface {
|
|
||||||
// Set stores the given key/value pair.
|
|
||||||
Set(string, string)
|
|
||||||
// Get returns the value for the given key and a boolean indicating if the key was found.
|
|
||||||
Get(string) (string, bool)
|
|
||||||
// Exists returns true if the given key exists in the cache.
|
|
||||||
Exists(string) bool
|
|
||||||
// Delete the given key from the cache.
|
|
||||||
Delete(string)
|
|
||||||
// Clear all key/value pairs from the cache.
|
|
||||||
Clear()
|
|
||||||
// Count the number of key/value pairs in the cache.
|
|
||||||
Count() int
|
|
||||||
// Keys returns all keys in the cache.
|
|
||||||
Keys() []string
|
|
||||||
// Values returns all values in the cache.
|
|
||||||
Values() []string
|
|
||||||
// Contents returns all keys in the cache encoded as a string.
|
|
||||||
Contents() string
|
|
||||||
}
|
|
||||||
Vendored
-105
@@ -1,105 +0,0 @@
|
|||||||
package memory
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/patrickmn/go-cache"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
expirationInterval = 12 * time.Hour
|
|
||||||
purgeInterval = 13 * time.Hour
|
|
||||||
defaultExpiration = cache.DefaultExpiration
|
|
||||||
)
|
|
||||||
|
|
||||||
// Cache is a wrapper around the go-cache library.
|
|
||||||
type Cache struct {
|
|
||||||
c *cache.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
// New constructs a new in-memory cache.
|
|
||||||
func New() *Cache {
|
|
||||||
c := cache.New(expirationInterval, purgeInterval)
|
|
||||||
return &Cache{c: c}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWithData constructs a new in-memory cache with existing data.
|
|
||||||
func NewWithData(ctx context.Context, data []string) *Cache {
|
|
||||||
ctx.Logger().V(3).Info("Loading cache", "num-items", len(data))
|
|
||||||
|
|
||||||
items := make(map[string]cache.Item, len(data))
|
|
||||||
for _, d := range data {
|
|
||||||
items[d] = cache.Item{Object: d, Expiration: int64(defaultExpiration)}
|
|
||||||
}
|
|
||||||
|
|
||||||
c := cache.NewFrom(expirationInterval, purgeInterval, items)
|
|
||||||
return &Cache{c: c}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set adds a key-value pair to the cache.
|
|
||||||
func (c *Cache) Set(key, value string) {
|
|
||||||
c.c.Set(key, value, defaultExpiration)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the value for the given key.
|
|
||||||
func (c *Cache) Get(key string) (string, bool) {
|
|
||||||
res, ok := c.c.Get(key)
|
|
||||||
if !ok {
|
|
||||||
return "", ok
|
|
||||||
}
|
|
||||||
return res.(string), ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exists returns true if the given key exists in the cache.
|
|
||||||
func (c *Cache) Exists(key string) bool {
|
|
||||||
_, ok := c.c.Get(key)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes the key-value pair from the cache.
|
|
||||||
func (c *Cache) Delete(key string) {
|
|
||||||
c.c.Delete(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear removes all key-value pairs from the cache.
|
|
||||||
func (c *Cache) Clear() {
|
|
||||||
c.c.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the number of key-value pairs in the cache.
|
|
||||||
func (c *Cache) Count() int {
|
|
||||||
return c.c.ItemCount()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns all keys in the cache.
|
|
||||||
func (c *Cache) Keys() []string {
|
|
||||||
items := c.c.Items()
|
|
||||||
res := make([]string, 0, len(items))
|
|
||||||
for k := range items {
|
|
||||||
res = append(res, k)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values returns all values in the cache.
|
|
||||||
func (c *Cache) Values() []string {
|
|
||||||
items := c.c.Items()
|
|
||||||
res := make([]string, 0, len(items))
|
|
||||||
for _, v := range items {
|
|
||||||
res = append(res, v.Object.(string))
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contents returns all key-value pairs in the cache encodes as a string.
|
|
||||||
func (c *Cache) Contents() string {
|
|
||||||
items := c.c.Items()
|
|
||||||
res := make([]string, 0, len(items))
|
|
||||||
for k := range items {
|
|
||||||
res = append(res, k)
|
|
||||||
}
|
|
||||||
return strings.Join(res, ",")
|
|
||||||
}
|
|
||||||
Vendored
-169
@@ -1,169 +0,0 @@
|
|||||||
package memory
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
|
|
||||||
logContext "github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCache(t *testing.T) {
|
|
||||||
c := New()
|
|
||||||
|
|
||||||
// Test set and get.
|
|
||||||
c.Set("key1", "key1")
|
|
||||||
v, ok := c.Get("key1")
|
|
||||||
if !ok || v != "key1" {
|
|
||||||
t.Fatalf("Unexpected value for key1: %v, %v", v, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test exists.
|
|
||||||
if !c.Exists("key1") {
|
|
||||||
t.Fatalf("Expected key1 to exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test the count.
|
|
||||||
if c.Count() != 1 {
|
|
||||||
t.Fatalf("Unexpected count: %d", c.Count())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test delete.
|
|
||||||
c.Delete("key1")
|
|
||||||
v, ok = c.Get("key1")
|
|
||||||
if ok || v != "" {
|
|
||||||
t.Fatalf("Unexpected value for key1 after delete: %v, %v", v, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test clear.
|
|
||||||
c.Set("key10", "key10")
|
|
||||||
c.Clear()
|
|
||||||
v, ok = c.Get("key10")
|
|
||||||
if ok || v != "" {
|
|
||||||
t.Fatalf("Unexpected value for key10 after clear: %v, %v", v, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test getting only the keys.
|
|
||||||
keys := []string{"key1", "key2", "key3"}
|
|
||||||
values := []string{"value1", "value2", "value3"}
|
|
||||||
for i, k := range keys {
|
|
||||||
c.Set(k, values[i])
|
|
||||||
}
|
|
||||||
k := c.Keys()
|
|
||||||
sort.Strings(keys)
|
|
||||||
sort.Strings(k)
|
|
||||||
if !cmp.Equal(keys, k) {
|
|
||||||
t.Fatalf("Unexpected keys: %v", k)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test getting only the values.
|
|
||||||
vals := c.Values()
|
|
||||||
sort.Strings(vals)
|
|
||||||
sort.Strings(values)
|
|
||||||
if !cmp.Equal(values, vals) {
|
|
||||||
t.Fatalf("Unexpected values: %v", vals)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test contents.
|
|
||||||
items := c.Contents()
|
|
||||||
sort.Strings(keys)
|
|
||||||
res := strings.Split(items, ",")
|
|
||||||
sort.Strings(res)
|
|
||||||
|
|
||||||
if len(keys) != len(res) {
|
|
||||||
t.Fatalf("Unexpected length of items: %d", len(res))
|
|
||||||
}
|
|
||||||
if !cmp.Equal(keys, res) {
|
|
||||||
t.Fatalf("Unexpected items: %v", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCache_NewWithData(t *testing.T) {
|
|
||||||
c := NewWithData(logContext.Background(), []string{"key1", "key2", "key3"})
|
|
||||||
|
|
||||||
// Test the count.
|
|
||||||
if c.Count() != 3 {
|
|
||||||
t.Fatalf("Unexpected count: %d", c.Count())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test contents.
|
|
||||||
keys := []string{"key1", "key2", "key3"}
|
|
||||||
items := c.Contents()
|
|
||||||
sort.Strings(keys)
|
|
||||||
res := strings.Split(items, ",")
|
|
||||||
sort.Strings(res)
|
|
||||||
|
|
||||||
if len(keys) != len(res) {
|
|
||||||
t.Fatalf("Unexpected length of items: %d", len(res))
|
|
||||||
}
|
|
||||||
if !cmp.Equal(keys, res) {
|
|
||||||
t.Fatalf("Unexpected items: %v", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupBenchmarks(b *testing.B) *Cache {
|
|
||||||
b.Helper()
|
|
||||||
|
|
||||||
c := New()
|
|
||||||
|
|
||||||
for i := 0; i < 500_000; i++ {
|
|
||||||
key := fmt.Sprintf("key%d", i)
|
|
||||||
c.Set(key, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSet(b *testing.B) {
|
|
||||||
c := New()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
key := fmt.Sprintf("key%d", i)
|
|
||||||
c.Set(key, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkGet(b *testing.B) {
|
|
||||||
c := setupBenchmarks(b)
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
key := fmt.Sprintf("key%d", i)
|
|
||||||
c.Get(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkDelete(b *testing.B) {
|
|
||||||
c := setupBenchmarks(b)
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
key := fmt.Sprintf("key%d", i)
|
|
||||||
c.Delete(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkCount(b *testing.B) {
|
|
||||||
c := setupBenchmarks(b)
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
c.Count()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkContents(b *testing.B) {
|
|
||||||
c := setupBenchmarks(b)
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
var s string
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
s = c.Contents()
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = s
|
|
||||||
}
|
|
||||||
+3
-4
@@ -2,17 +2,16 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
KB, MB, GB, TB, PB = 1e3, 1e6, 1e9, 1e12, 1e15
|
KB, MB, GB, TB, PB = 1e3, 1e6, 1e9, 1e12, 1e15
|
||||||
IgnoredExtensions = []string{"mp4", "avi", "mpeg", "mpg", "mov", "wmv", "m4p", "swf", "mp2", "flv", "vob", "webm", "hdv", "3gp", "ogg", "mp3", "wav", "flac", "webp"}
|
IGNORED_EXTENSIONS = []string{"mp4", "avi", "mpeg", "mpg", "mov", "wmv", "m4p", "swf", "mp2", "flv", "vob", "webm", "hdv", "3gp", "ogg", "mp3", "wav", "flac", "webp"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func SkipFile(filename string) bool {
|
func SkipFile(filename string) bool {
|
||||||
for _, ext := range IgnoredExtensions {
|
for _, ext := range IGNORED_EXTENSIONS {
|
||||||
if strings.TrimPrefix(filepath.Ext(filename), ".") == ext {
|
if filepath.Ext(filename) == ext {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestSkipFile(t *testing.T) {
|
|
||||||
type testCase struct {
|
|
||||||
file string
|
|
||||||
want bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a test case for each ignored extension.
|
|
||||||
testCases := make([]testCase, 0, len(IgnoredExtensions)+1)
|
|
||||||
for _, ext := range IgnoredExtensions {
|
|
||||||
testCases = append(testCases, testCase{
|
|
||||||
file: "test." + ext,
|
|
||||||
want: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a test case for a file that should not be skipped.
|
|
||||||
testCases = append(testCases, testCase{file: "test.txt", want: false})
|
|
||||||
|
|
||||||
for _, tt := range testCases {
|
|
||||||
t.Run(tt.file, func(t *testing.T) {
|
|
||||||
if got := SkipFile(tt.file); got != tt.want {
|
|
||||||
t.Errorf("SkipFile(%v) got %v, want %v", tt.file, got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSkipFile(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
SkipFile("test.mp4")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-50
@@ -2,12 +2,10 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
dpb "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
dpb "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,26 +31,11 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetectorID identifies a detector type and version. This struct is used as a
|
|
||||||
// way for users to identify detectors, whether unique or not. A DetectorID
|
|
||||||
// with Version = 0 indicates all possible versions of a detector.
|
|
||||||
type DetectorID struct {
|
type DetectorID struct {
|
||||||
ID dpb.DetectorType
|
ID dpb.DetectorType
|
||||||
Version int
|
Version int
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDetectorID extracts the DetectorID from a Detector.
|
|
||||||
func GetDetectorID(d detectors.Detector) DetectorID {
|
|
||||||
var version int
|
|
||||||
if v, ok := d.(detectors.Versioner); ok {
|
|
||||||
version = v.Version()
|
|
||||||
}
|
|
||||||
return DetectorID{
|
|
||||||
ID: d.Type(),
|
|
||||||
Version: version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseDetectors parses user supplied string into a list of detectors types.
|
// ParseDetectors parses user supplied string into a list of detectors types.
|
||||||
// "all" will return the list of all available detectors. The input is comma
|
// "all" will return the list of all available detectors. The input is comma
|
||||||
// separated and may use the case-insensitive detector name defined in the
|
// separated and may use the case-insensitive detector name defined in the
|
||||||
@@ -85,37 +68,6 @@ func ParseDetectors(input string) ([]DetectorID, error) {
|
|||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDetector parses a user supplied string into a single DetectorID. Input
|
|
||||||
// is case-insensitive and either the detector name or ID may be used.
|
|
||||||
func ParseDetector(input string) (DetectorID, error) {
|
|
||||||
return asDetectorID(strings.TrimSpace(input))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseVerifierEndpoints parses a map of user supplied verifier URLs. The
|
|
||||||
// input keys are detector IDs and the values are a comma separated list of
|
|
||||||
// URLs. The URLs are validated as HTTPS endpoints.
|
|
||||||
func ParseVerifierEndpoints(verifierURLs map[string]string) (map[DetectorID][]string, error) {
|
|
||||||
verifiers := make(map[DetectorID][]string, len(verifierURLs))
|
|
||||||
for detectorID, urls := range verifierURLs {
|
|
||||||
key, err := ParseDetector(detectorID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid detector ID for verifier: %w", err)
|
|
||||||
}
|
|
||||||
verifierURLs := strings.Split(urls, ",")
|
|
||||||
for i, rawEndpoint := range verifierURLs {
|
|
||||||
rawEndpoint := strings.TrimSpace(rawEndpoint)
|
|
||||||
verifierURLs[i] = rawEndpoint
|
|
||||||
if endpoint, err := url.Parse(rawEndpoint); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid verifier url %q: %w", rawEndpoint, err)
|
|
||||||
} else if endpoint.Scheme != "https" {
|
|
||||||
return nil, fmt.Errorf("verifier url must be https: %q", rawEndpoint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verifiers[key] = append(verifiers[key], verifierURLs...)
|
|
||||||
}
|
|
||||||
return verifiers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (id DetectorID) String() string {
|
func (id DetectorID) String() string {
|
||||||
name := dpb.DetectorType_name[int32(id.ID)]
|
name := dpb.DetectorType_name[int32(id.ID)]
|
||||||
if name == "" {
|
if name == "" {
|
||||||
@@ -187,8 +139,8 @@ func asRange(input string) ([]DetectorID, error) {
|
|||||||
return append(output, dtEnd), nil
|
return append(output, dtEnd), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// asDetectorID converts the case-insensitive input into a DetectorID. Name or
|
// asDetectorID converts the case-insensitive input into a DetectorID.
|
||||||
// ID may be used. Input is expected to be already trimmed of whitespace.
|
// Name or ID may be used.
|
||||||
func asDetectorID(input string) (DetectorID, error) {
|
func asDetectorID(input string) (DetectorID, error) {
|
||||||
if input == "" {
|
if input == "" {
|
||||||
return DetectorID{}, fmt.Errorf("empty detector")
|
return DetectorID{}, fmt.Errorf("empty detector")
|
||||||
|
|||||||
@@ -94,8 +94,9 @@ func (c *customRegexWebhook) FromData(ctx context.Context, verify bool, data []b
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore any errors and collect as many of the results as we can.
|
if err := g.Wait(); err != nil {
|
||||||
_ = g.Wait()
|
return nil, err
|
||||||
|
}
|
||||||
close(resultsCh)
|
close(resultsCh)
|
||||||
|
|
||||||
for result := range resultsCh {
|
for result := range resultsCh {
|
||||||
@@ -117,7 +118,6 @@ func (c *customRegexWebhook) createResults(ctx context.Context, match map[string
|
|||||||
}
|
}
|
||||||
result := detectors.Result{
|
result := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_CustomRegex,
|
DetectorType: detectorspb.DetectorType_CustomRegex,
|
||||||
DetectorName: c.GetName(),
|
|
||||||
Raw: []byte(raw),
|
Raw: []byte(raw),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,10 +163,9 @@ func (c *customRegexWebhook) createResults(ctx context.Context, match map[string
|
|||||||
// TODO: Read response body.
|
// TODO: Read response body.
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
if res.StatusCode == http.StatusOK {
|
if res.StatusCode == http.StatusOK {
|
||||||
result.Verified = detectors.Verified
|
result.Verified = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
result.Verified = detectors.Unverified
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|||||||
+46
-95
@@ -3,125 +3,76 @@ package decoders
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type Base64 struct{}
|
||||||
Base64 struct{}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
b64Charset = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/-_=")
|
b64Charset = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
|
||||||
b64EndChars = "+/-_="
|
b64EndChars = "+/="
|
||||||
// Given characters are mostly ASCII, we can use a simple array to map.
|
|
||||||
b64CharsetMapping [128]bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func getSubstringsOfCharacterSet(data []byte, charset []byte, threshold int) []string {
|
||||||
// Build an array of all the characters in the base64 charset.
|
count := 0
|
||||||
for _, char := range b64Charset {
|
substrings := []string{}
|
||||||
b64CharsetMapping[char] = true
|
letters := strings.Builder{}
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
for _, char := range string(data) {
|
||||||
|
if bytes.ContainsRune(charset, char) {
|
||||||
|
letters.WriteRune(char)
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
if count > threshold {
|
||||||
|
substrings = appendB64Substring(letters, substrings)
|
||||||
|
}
|
||||||
|
letters.Reset()
|
||||||
|
count = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if count > threshold && len(letters.String()) > 0 {
|
||||||
|
substrings = appendB64Substring(letters, substrings)
|
||||||
|
}
|
||||||
|
|
||||||
|
return substrings
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendB64Substring(letters strings.Builder, substrings []string) []string {
|
||||||
|
|
||||||
|
substring := strings.TrimLeft(letters.String(), b64EndChars)
|
||||||
|
// handle key=value
|
||||||
|
if strings.Contains(strings.TrimRight(substring, b64EndChars), "=") {
|
||||||
|
split := strings.SplitN(substring, "=", 2)
|
||||||
|
substrings = append(substrings, split[len(split)-1])
|
||||||
|
} else {
|
||||||
|
substrings = append(substrings, substring)
|
||||||
|
}
|
||||||
|
return substrings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Base64) FromChunk(chunk *sources.Chunk) *sources.Chunk {
|
func (d *Base64) FromChunk(chunk *sources.Chunk) *sources.Chunk {
|
||||||
encodedSubstrings := getSubstringsOfCharacterSet(chunk.Data, 20, b64CharsetMapping, b64EndChars)
|
|
||||||
decodedSubstrings := make(map[string][]byte)
|
encodedSubstrings := getSubstringsOfCharacterSet(chunk.Data, b64Charset, 20)
|
||||||
|
decodedSubstrings := map[string][]byte{}
|
||||||
|
|
||||||
for _, str := range encodedSubstrings {
|
for _, str := range encodedSubstrings {
|
||||||
dec, err := base64.StdEncoding.DecodeString(str)
|
dec, err := base64.StdEncoding.DecodeString(str)
|
||||||
if err == nil {
|
|
||||||
if len(dec) > 0 {
|
|
||||||
decodedSubstrings[str] = dec
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
dec, err = base64.RawURLEncoding.DecodeString(str)
|
|
||||||
if err == nil && len(dec) > 0 {
|
if err == nil && len(dec) > 0 {
|
||||||
decodedSubstrings[str] = dec
|
decodedSubstrings[str] = dec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(decodedSubstrings) > 0 {
|
if len(decodedSubstrings) > 0 {
|
||||||
var result bytes.Buffer
|
for substring, dec := range decodedSubstrings {
|
||||||
result.Grow(len(chunk.Data))
|
chunk.Data = bytes.Replace(chunk.Data, []byte(substring), dec, 1)
|
||||||
|
|
||||||
start := 0
|
|
||||||
for _, encoded := range encodedSubstrings {
|
|
||||||
if decoded, ok := decodedSubstrings[encoded]; ok {
|
|
||||||
end := bytes.Index(chunk.Data[start:], []byte(encoded))
|
|
||||||
if end != -1 {
|
|
||||||
result.Write(chunk.Data[start : start+end])
|
|
||||||
result.Write(decoded)
|
|
||||||
start += end + len(encoded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result.Write(chunk.Data[start:])
|
|
||||||
chunk.Data = result.Bytes()
|
|
||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSubstringsOfCharacterSet(data []byte, threshold int, charsetMapping [128]bool, endChars string) []string {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
substringsCount := 0
|
|
||||||
|
|
||||||
// Determine the number of substrings that will be returned.
|
|
||||||
// Pre-allocate the slice to avoid reallocations.
|
|
||||||
for _, char := range data {
|
|
||||||
if char < 128 && charsetMapping[char] {
|
|
||||||
count++
|
|
||||||
} else {
|
|
||||||
if count > threshold {
|
|
||||||
substringsCount++
|
|
||||||
}
|
|
||||||
count = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if count > threshold {
|
|
||||||
substringsCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
start := 0
|
|
||||||
substrings := make([]string, 0, substringsCount)
|
|
||||||
|
|
||||||
for i, char := range data {
|
|
||||||
if char < 128 && charsetMapping[char] {
|
|
||||||
if count == 0 {
|
|
||||||
start = i
|
|
||||||
}
|
|
||||||
count++
|
|
||||||
} else {
|
|
||||||
if count > threshold {
|
|
||||||
substrings = appendB64Substring(data, start, count, substrings, endChars)
|
|
||||||
}
|
|
||||||
count = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if count > threshold {
|
|
||||||
substrings = appendB64Substring(data, start, count, substrings, endChars)
|
|
||||||
}
|
|
||||||
|
|
||||||
return substrings
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendB64Substring(data []byte, start, count int, substrings []string, endChars string) []string {
|
|
||||||
substring := bytes.TrimLeft(data[start:start+count], endChars)
|
|
||||||
if idx := bytes.IndexByte(bytes.TrimRight(substring, endChars), '='); idx != -1 {
|
|
||||||
substrings = append(substrings, string(substring[idx+1:]))
|
|
||||||
} else {
|
|
||||||
substrings = append(substrings, string(substring))
|
|
||||||
}
|
|
||||||
return substrings
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
|
|
||||||
func TestBase64_FromChunk(t *testing.T) {
|
func TestBase64_FromChunk(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
name string
|
||||||
chunk *sources.Chunk
|
chunk *sources.Chunk
|
||||||
want *sources.Chunk
|
want *sources.Chunk
|
||||||
name string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "only b64 chunk",
|
name: "only b64 chunk",
|
||||||
@@ -69,60 +69,6 @@ func TestBase64_FromChunk(t *testing.T) {
|
|||||||
but only this encapsulated secret should be decoded.`),
|
but only this encapsulated secret should be decoded.`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "b64-url-safe: only b64 chunk",
|
|
||||||
chunk: &sources.Chunk{
|
|
||||||
Data: []byte(`bG9uZ2VyLWVuY29kZWQtc2VjcmV0LXRlc3Q`),
|
|
||||||
},
|
|
||||||
want: &sources.Chunk{
|
|
||||||
Data: []byte(`longer-encoded-secret-test`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "b64-url-safe: mixed content",
|
|
||||||
chunk: &sources.Chunk{
|
|
||||||
Data: []byte(`token: bG9uZ2VyLWVuY29kZWQtc2VjcmV0LXRlc3Q`),
|
|
||||||
},
|
|
||||||
want: &sources.Chunk{
|
|
||||||
Data: []byte(`token: longer-encoded-secret-test`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "b64-url-safe: env var (looks like all b64 decodable but has `=` in the middle)",
|
|
||||||
chunk: &sources.Chunk{
|
|
||||||
Data: []byte(`some-encoded-secret=dGVzdHNlY3JldA`),
|
|
||||||
},
|
|
||||||
want: &sources.Chunk{
|
|
||||||
Data: []byte(`some-encoded-secret=testsecret`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "b64-url-safe: has longer b64 inside",
|
|
||||||
chunk: &sources.Chunk{
|
|
||||||
Data: []byte(`some-encoded-secret="bG9uZ2VyLWVuY29kZWQtc2VjcmV0LXRlc3Q"`),
|
|
||||||
},
|
|
||||||
want: &sources.Chunk{
|
|
||||||
Data: []byte(`some-encoded-secret="longer-encoded-secret-test"`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "b64-url-safe: hyphen url b64",
|
|
||||||
chunk: &sources.Chunk{
|
|
||||||
Data: []byte(`dHJ1ZmZsZWhvZz4-ZmluZHMtc2VjcmV0cw`),
|
|
||||||
},
|
|
||||||
want: &sources.Chunk{
|
|
||||||
Data: []byte(`trufflehog>>finds-secrets`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "b64-url-safe: underscore url b64",
|
|
||||||
chunk: &sources.Chunk{
|
|
||||||
Data: []byte(`YjY0dXJsc2FmZS10ZXN0LXNlY3JldC11bmRlcnNjb3Jlcz8_`),
|
|
||||||
},
|
|
||||||
want: &sources.Chunk{
|
|
||||||
Data: []byte(`b64urlsafe-test-secret-underscores??`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -144,29 +90,13 @@ func TestBase64_FromChunk(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkFromChunkSmall(b *testing.B) {
|
func BenchmarkFromChunk(benchmark *testing.B) {
|
||||||
d := Base64{}
|
d := Base64{}
|
||||||
data := detectors.MustGetBenchmarkData()["small"]
|
for name, data := range detectors.MustGetBenchmarkData() {
|
||||||
|
benchmark.Run(name, func(b *testing.B) {
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
d.FromChunk(&sources.Chunk{Data: data})
|
d.FromChunk(&sources.Chunk{Data: data})
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
func BenchmarkFromChunkMedium(b *testing.B) {
|
|
||||||
d := Base64{}
|
|
||||||
data := detectors.MustGetBenchmarkData()["medium"]
|
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
d.FromChunk(&sources.Chunk{Data: data})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromChunkLarge(b *testing.B) {
|
|
||||||
d := Base64{}
|
|
||||||
data := detectors.MustGetBenchmarkData()["big"]
|
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
d.FromChunk(&sources.Chunk{Data: data})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ func DefaultDecoders() []Decoder {
|
|||||||
return []Decoder{
|
return []Decoder{
|
||||||
&UTF8{},
|
&UTF8{},
|
||||||
&Base64{},
|
&Base64{},
|
||||||
&UTF16{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
package decoders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UTF16 struct{}
|
|
||||||
|
|
||||||
func (d *UTF16) FromChunk(chunk *sources.Chunk) *sources.Chunk {
|
|
||||||
if chunk == nil || len(chunk.Data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if utf16Data, err := utf16ToUTF8(chunk.Data); err == nil {
|
|
||||||
chunk.Data = utf16Data
|
|
||||||
return chunk
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// utf16ToUTF8 converts a byte slice containing UTF-16 encoded data to a UTF-8 encoded byte slice.
|
|
||||||
func utf16ToUTF8(b []byte) ([]byte, error) {
|
|
||||||
endianness, err := guessUTF16Endianness(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
for i := 0; i < len(b); i += 2 {
|
|
||||||
r := rune(endianness.Uint16(b[i:]))
|
|
||||||
if utf8.ValidRune(r) {
|
|
||||||
buf.WriteRune(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func guessUTF16Endianness(b []byte) (binary.ByteOrder, error) {
|
|
||||||
if len(b) < 2 || len(b)%2 != 0 {
|
|
||||||
return nil, fmt.Errorf("input length must be even and at least 2 bytes long")
|
|
||||||
}
|
|
||||||
|
|
||||||
var evenNullBytes, oddNullBytes int
|
|
||||||
|
|
||||||
for i := 0; i < len(b); i += 2 {
|
|
||||||
if b[i] == 0 {
|
|
||||||
oddNullBytes++
|
|
||||||
}
|
|
||||||
if b[i+1] == 0 {
|
|
||||||
evenNullBytes++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if evenNullBytes > oddNullBytes {
|
|
||||||
return binary.LittleEndian, nil
|
|
||||||
}
|
|
||||||
if oddNullBytes > evenNullBytes {
|
|
||||||
return binary.BigEndian, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("could not determine endianness")
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package decoders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUTF16Decoder(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
input []byte
|
|
||||||
expected []byte
|
|
||||||
expectNil bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Valid UTF-16LE input",
|
|
||||||
input: []byte{72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0},
|
|
||||||
expected: []byte("Hello World"),
|
|
||||||
expectNil: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Valid UTF-16BE input",
|
|
||||||
input: []byte{0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100},
|
|
||||||
expected: []byte("Hello World"),
|
|
||||||
expectNil: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Invalid UTF-16 input (it's UTF-8)",
|
|
||||||
input: []byte("Hello World!"),
|
|
||||||
expected: nil,
|
|
||||||
expectNil: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Invalid UTF-16 input (odd length)",
|
|
||||||
input: []byte{72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 0},
|
|
||||||
expected: nil,
|
|
||||||
expectNil: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
chunk := &sources.Chunk{Data: tc.input}
|
|
||||||
decoder := &UTF16{}
|
|
||||||
decodedChunk := decoder.FromChunk(chunk)
|
|
||||||
|
|
||||||
if tc.expectNil {
|
|
||||||
if decodedChunk != nil {
|
|
||||||
t.Errorf("Expected nil, got chunk with data: %v", decodedChunk.Data)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if decodedChunk == nil {
|
|
||||||
t.Errorf("Expected chunk with data, got nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !bytes.Equal(decodedChunk.Data, tc.expected) {
|
|
||||||
t.Errorf("Expected decoded data: %v, got: %v", tc.expected, decodedChunk.Data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkUtf16ToUtf8(b *testing.B) {
|
|
||||||
// Example UTF-16LE encoded data
|
|
||||||
data := []byte{72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0}
|
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, _ = utf16ToUTF8(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+9
-20
@@ -26,30 +26,19 @@ func (d *UTF8) FromChunk(chunk *sources.Chunk) *sources.Chunk {
|
|||||||
// extacting contigous portions of printable characters that we care
|
// extacting contigous portions of printable characters that we care
|
||||||
// about from some bytes
|
// about from some bytes
|
||||||
func extractSubstrings(b []byte) []byte {
|
func extractSubstrings(b []byte) []byte {
|
||||||
isValidByte := func(c byte) bool {
|
fields := bytes.FieldsFunc(b, func(r rune) bool {
|
||||||
// https://www.rapidtables.com/code/text/ascii-table.html
|
// https://www.rapidtables.com/code/text/ascii-table.html
|
||||||
// split on anything that is not ascii space through tilde
|
// split on anything that is not ascii space through tilde
|
||||||
return c > 31 && c < 127
|
return !(r > 31 && r < 127)
|
||||||
}
|
})
|
||||||
|
|
||||||
field := make([]byte, len(b))
|
keep := [][]byte{}
|
||||||
fieldLen := 0
|
for _, field := range fields {
|
||||||
buf := &bytes.Buffer{}
|
// Remove fields shorter than 6 characters.
|
||||||
for i, c := range b {
|
if bts := bytes.TrimSpace(field); len(bts) > 5 {
|
||||||
if isValidByte(c) {
|
keep = append(keep, bts)
|
||||||
field[fieldLen] = c
|
|
||||||
fieldLen++
|
|
||||||
} else {
|
|
||||||
if fieldLen > 5 {
|
|
||||||
buf.Write(field[:fieldLen])
|
|
||||||
}
|
|
||||||
fieldLen = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == len(b)-1 && fieldLen > 5 {
|
|
||||||
buf.Write(field[:fieldLen])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.Bytes()
|
return bytes.Join(keep, []byte("\n"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package aiven
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"aiven"}) + `([a-zA-Z0-9/+=]{372})`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"aiven"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Aiven secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Aiven,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.aiven.io/v1/project", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("aivenv1 %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Aiven
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package aiven
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAiven_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("AIVEN")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("AIVEN_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a aiven secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Aiven,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a aiven secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Aiven,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Aiven.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Aiven.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package alchemy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"alchemy"}) + `\b([0-9a-zA-Z]{23}_[0-9a-zA-Z]{8})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"alchemy"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Alchemy secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Alchemy,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://eth-mainnet.g.alchemy.com/v2/"+resMatch+"/getNFTs/?owner=vitalik.eth", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Alchemy
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package alchemy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAlchemy_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("ALCHEMY")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("ALCHEMY_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Alchemy,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a alchemy secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Alchemy,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Alchemy.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Alchemy.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,9 @@ package alibaba
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -38,9 +38,10 @@ func (s Scanner) Keywords() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func randString(n int) string {
|
func randString(n int) string {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
const alphanum = "0123456789abcdefghijklmnopqrstuvwxyz"
|
const alphanum = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
var bytes = make([]byte, n)
|
var bytes = make([]byte, n)
|
||||||
_, _ = rand.Read(bytes)
|
rand.Read(bytes)
|
||||||
for i, b := range bytes {
|
for i, b := range bytes {
|
||||||
bytes[i] = alphanum[b%byte(len(alphanum))]
|
bytes[i] = alphanum[b%byte(len(alphanum))]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ func TestAlibaba_FromChunk(t *testing.T) {
|
|||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
t.Fatalf("no raw secret present: \n %+v", got[i])
|
||||||
}
|
}
|
||||||
got[i].Raw = nil
|
got[i].Raw = nil
|
||||||
got[i].RawV2 = nil
|
|
||||||
}
|
}
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
if diff := pretty.Compare(got, tt.want); diff != "" {
|
||||||
t.Errorf("Alibaba.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
t.Errorf("Alibaba.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
||||||
|
|||||||
+21
-22
@@ -172,38 +172,37 @@ func (s scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
req.URL.RawQuery = params.Encode()
|
req.URL.RawQuery = params.Encode()
|
||||||
|
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
continue
|
|
||||||
}
|
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||||
s1.Verified = detectors.Unverified
|
identityInfo := identityRes{}
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
err := json.NewDecoder(res.Body).Decode(&identityInfo)
|
||||||
identityInfo := identityRes{}
|
if err == nil {
|
||||||
err := json.NewDecoder(res.Body).Decode(&identityInfo)
|
s1.Verified = true
|
||||||
if err == nil {
|
s1.ExtraData = map[string]string{
|
||||||
s1.Verified = detectors.Verified
|
"account": identityInfo.GetCallerIdentityResponse.GetCallerIdentityResult.Account,
|
||||||
s1.ExtraData = map[string]string{
|
"user_id": identityInfo.GetCallerIdentityResponse.GetCallerIdentityResult.UserID,
|
||||||
"account": identityInfo.GetCallerIdentityResponse.GetCallerIdentityResult.Account,
|
"arn": identityInfo.GetCallerIdentityResponse.GetCallerIdentityResult.Arn,
|
||||||
"user_id": identityInfo.GetCallerIdentityResponse.GetCallerIdentityResult.UserID,
|
}
|
||||||
"arn": identityInfo.GetCallerIdentityResponse.GetCallerIdentityResult.Arn,
|
}
|
||||||
|
res.Body.Close()
|
||||||
|
} else {
|
||||||
|
// This function will check false positives for common test words, but also it will make sure the key appears "random" enough to be a real key.
|
||||||
|
if detectors.IsKnownFalsePositive(resSecretMatch, detectors.DefaultFalsePositives, true) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
res.Body.Close()
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears "random" enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resSecretMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the result is unverified and matches something like a git hash, don't include it in the results.
|
// If the result is unverified and matches something like a git hash, don't include it in the results.
|
||||||
if s1.Verified == detectors.Unverified && falsePositiveSecretCheck.MatchString(resSecretMatch) {
|
if !s1.Verified && falsePositiveSecretCheck.MatchString(resSecretMatch) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, s1)
|
results = append(results, s1)
|
||||||
// If we've found a verified match with this ID, we don't need to look for any more. So move on to the next ID.
|
// If we've found a verified match with this ID, we don't need to look for any more. So move on to the next ID.
|
||||||
if s1.Verified == detectors.Verified {
|
if s1.Verified {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +219,7 @@ func awsCustomCleanResults(results []detectors.Result) []detectors.Result {
|
|||||||
idResults := map[string]detectors.Result{}
|
idResults := map[string]detectors.Result{}
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
// Always accept the verified result as the result for the given ID.
|
// Always accept the verified result as the result for the given ID.
|
||||||
if result.Verified == detectors.Verified {
|
if result.Verified {
|
||||||
idResults[result.Redacted] = result
|
idResults[result.Redacted] = result
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ func TestAWS_FromChunk(t *testing.T) {
|
|||||||
{
|
{
|
||||||
DetectorType: detectorspb.DetectorType_AWS,
|
DetectorType: detectorspb.DetectorType_AWS,
|
||||||
Verified: true,
|
Verified: true,
|
||||||
Redacted: "AKIASP2TPHJSQH3FJRUX",
|
Redacted: "AKIAWARWQKZNHMZBLY4I",
|
||||||
ExtraData: map[string]string{
|
ExtraData: map[string]string{
|
||||||
"account": "171436882533",
|
"account": "413504919130",
|
||||||
"arn": "arn:aws:iam::171436882533:user/canarytokens.com@@4dxkh0pdeop3bzu9zx5wob793",
|
"arn": "arn:aws:iam::413504919130:root",
|
||||||
"user_id": "AIDASP2TPHJSUFRSTTZX4",
|
"user_id": "413504919130",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -78,7 +78,7 @@ func TestAWS_FromChunk(t *testing.T) {
|
|||||||
{
|
{
|
||||||
DetectorType: detectorspb.DetectorType_AWS,
|
DetectorType: detectorspb.DetectorType_AWS,
|
||||||
Verified: false,
|
Verified: false,
|
||||||
Redacted: "AKIASP2TPHJSQH3FJRUX",
|
Redacted: "AKIAWARWQKZNHMZBLY4I",
|
||||||
ExtraData: nil,
|
ExtraData: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -106,18 +106,18 @@ func TestAWS_FromChunk(t *testing.T) {
|
|||||||
want: []detectors.Result{
|
want: []detectors.Result{
|
||||||
{
|
{
|
||||||
DetectorType: detectorspb.DetectorType_AWS,
|
DetectorType: detectorspb.DetectorType_AWS,
|
||||||
Verified: false,
|
Verified: true,
|
||||||
Redacted: "AKIASP2TPHJSQH3FJXYZ",
|
Redacted: id,
|
||||||
|
ExtraData: map[string]string{
|
||||||
|
"account": "413504919130",
|
||||||
|
"arn": "arn:aws:iam::413504919130:root",
|
||||||
|
"user_id": "413504919130",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
DetectorType: detectorspb.DetectorType_AWS,
|
DetectorType: detectorspb.DetectorType_AWS,
|
||||||
Verified: true,
|
Verified: false,
|
||||||
Redacted: "AKIASP2TPHJSQH3FJRUX",
|
Redacted: inactiveID,
|
||||||
ExtraData: map[string]string{
|
|
||||||
"account": "171436882533",
|
|
||||||
"arn": "arn:aws:iam::171436882533:user/canarytokens.com@@4dxkh0pdeop3bzu9zx5wob793",
|
|
||||||
"user_id": "AIDASP2TPHJSUFRSTTZX4",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
@@ -145,11 +145,11 @@ func TestAWS_FromChunk(t *testing.T) {
|
|||||||
{
|
{
|
||||||
DetectorType: detectorspb.DetectorType_AWS,
|
DetectorType: detectorspb.DetectorType_AWS,
|
||||||
Verified: true,
|
Verified: true,
|
||||||
Redacted: "AKIASP2TPHJSQH3FJRUX",
|
Redacted: id,
|
||||||
ExtraData: map[string]string{
|
ExtraData: map[string]string{
|
||||||
"account": "171436882533",
|
"account": "413504919130",
|
||||||
"arn": "arn:aws:iam::171436882533:user/canarytokens.com@@4dxkh0pdeop3bzu9zx5wob793",
|
"arn": "arn:aws:iam::413504919130:root",
|
||||||
"user_id": "AIDASP2TPHJSUFRSTTZX4",
|
"user_id": "413504919130",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -172,7 +172,7 @@ func TestAWS_FromChunk(t *testing.T) {
|
|||||||
{
|
{
|
||||||
DetectorType: detectorspb.DetectorType_AWS,
|
DetectorType: detectorspb.DetectorType_AWS,
|
||||||
Verified: false,
|
Verified: false,
|
||||||
Redacted: "AKIASP2TPHJSQH3FJRUX",
|
Redacted: "AKIAWARWQKZNHMZBLY4I",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
@@ -181,7 +181,7 @@ func TestAWS_FromChunk(t *testing.T) {
|
|||||||
name: "skipped",
|
name: "skipped",
|
||||||
s: scanner{
|
s: scanner{
|
||||||
skipIDs: map[string]struct{}{
|
skipIDs: map[string]struct{}{
|
||||||
"AKIASP2TPHJSQH3FJRUX": {},
|
"AKIAWARWQKZNHMZBLY4I": {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
s := detectors.Result{
|
s := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_Azure,
|
DetectorType: detectorspb.DetectorType_Azure,
|
||||||
Raw: []byte(clientSecret[2]),
|
Raw: []byte(clientSecret[2]),
|
||||||
RawV2: []byte(clientID[2] + clientSecret[2] + tenantID[2]),
|
|
||||||
Redacted: clientID[2],
|
Redacted: clientID[2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
package blocknative
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"blocknative"}) + `\b([0-9Aa-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"blocknative"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Blocknative secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_BlockNative,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.blocknative.com/gasprices/blockprices", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", resMatch)
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
bodyBytes, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
body := string(bodyBytes)
|
|
||||||
if !strings.Contains(body, "valid") {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_BlockNative
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package blocknative
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBlocknative_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("BLOCKNATIVE")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("BLOCKNATIVE_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a blocknative secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_BlockNative,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a blocknative secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_BlockNative,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Blocknative.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Blocknative.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,8 +20,8 @@ var (
|
|||||||
client = common.SaneHttpClient()
|
client = common.SaneHttpClient()
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"https://", "http://", "hub-cloud.browserstack.com", "accessKey", "\"access_Key\":", "ACCESS_KEY", "key", "browserstackKey", "BS_AUTHKEY", "BROWSERSTACK_ACCESS_KEY"}) + `\b([0-9a-zA-Z]{20})\b`)
|
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"browserstack", "key", "automate", "local"}) + `\b([0-9a-zA-Z]{20})\b`)
|
||||||
userPat = regexp.MustCompile(detectors.PrefixRegex([]string{"https://", "http://", "hub-cloud.browserstack.com", "userName", "\"username\":", "USER_NAME", "user", "browserstackUser", "BS_USERNAME", "BROWSERSTACK_USERNAME"}) + `\b([a-zA-Z\d]{3,18}[._-]+[a-zA-Z\d]{6})\b`)
|
userPat = regexp.MustCompile(detectors.PrefixRegex([]string{"browserstack", "user", "automate", "local"}) + `\b([a-zA-Z\d]{3,18}[._-]?[a-zA-Z\d]{6})\b`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
@@ -56,7 +56,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
}
|
}
|
||||||
|
|
||||||
if verify {
|
if verify {
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://www.browserstack.com/automate/plan.json", nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://api-cloud.browserstack.com/app-automate/espresso/v2/apps", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
package bscscan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"bscscan"}) + `\b([0-9A-Z]{34})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"bscscan"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Bscscan secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_BscScan,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.bscscan.com/api?module=account&action=balance&address=0x70F657164e5b75689b64B7fd1fA275F334f28e18&apikey="+resMatch, nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
bodyBytes, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
body := string(bodyBytes)
|
|
||||||
|
|
||||||
if !strings.Contains(body, "NOTOK") {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sur>
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_BscScan
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package bscscan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBscscan_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("BSCSCAN")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("BSCSCAN_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a bscscan secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_BscScan,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a bscscan secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_BscScan,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Bscscan.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Bscscan.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,11 +14,8 @@ import (
|
|||||||
|
|
||||||
type Scanner struct{}
|
type Scanner struct{}
|
||||||
|
|
||||||
func (s Scanner) Version() int { return 1 }
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
// Ensure the Scanner satisfies the interface at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
var _ detectors.Versioner = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
client = common.SaneHttpClient()
|
client = common.SaneHttpClient()
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
package buildkitev2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
func (s Scanner) Version() int { return 2 }
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
var _ detectors.Versioner = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(`\b(bkua_[a-z0-9]{40})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"bkua_"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Buildkite secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Buildkite,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.buildkite.com/v2/access-token", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Buildkite
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package buildkitev2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBuildkite_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("BUILDKITEV2_TOKEN")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("BUILDKITEV2_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a buildkite secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Buildkite,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a buildkite secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Buildkite,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Buildkite.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Buildkite.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package coinmarketcap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"coinmarketcap", "CMC"}) + `\b([0-9Aa-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"coinmarketcap", "CMC"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Coinmarketcap secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_CoinMarketCap,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=5000&convert=USD", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Accept", "application/json")
|
|
||||||
req.Header.Add("X-CMC_PRO_API_KEY", resMatch)
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_CoinMarketCap
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package coinmarketcap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCoinmarketcap_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("COINMARKETCAP")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("COINMARKETCAP_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a coinmarketcap secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_CoinMarketCap,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a coinmarketcap secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_CoinMarketCap,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Coinmarketcap.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Coinmarketcap.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ var _ detectors.Detector = (*Scanner)(nil)
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
client = common.SaneHttpClient()
|
client = common.SaneHttpClient()
|
||||||
keyPat = regexp.MustCompile(`\b(CFPAT-[a-zA-Z0-9_\-]{43})\b`)
|
keyPat = regexp.MustCompile(`\b([CFPAT\-a-zA-Z-0-9]{49})\b`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
package databrickstoken
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
domain = regexp.MustCompile(`\b(https:\/\/[a-z0-9-]+\.cloud\.databricks\.com)\b`)
|
|
||||||
keyPat = regexp.MustCompile(`\b(dapi[a-z0-9]{32})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"databricks", "dapi"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Databrickstoken secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
domainMatches := domain.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
for _, domainmatch := range domainMatches {
|
|
||||||
if len(domainmatch) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resDomainMatch := strings.TrimSpace(domainmatch[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_DatabricksToken,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
RawV2: []byte(resMatch + resDomainMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", resDomainMatch + "/api/2.0/clusters/list", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_DatabricksToken
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package databrickstoken
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDatabrickstoken_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("DATABRICKSTOKEN")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("DATABRICKSTOKEN_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a databrickstoken secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_DatabricksToken,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a databrickstoken secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_DatabricksToken,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Databrickstoken.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Databrickstoken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -51,7 +51,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
s1 := detectors.Result{
|
s1 := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_DatadogToken,
|
DetectorType: detectorspb.DetectorType_DatadogToken,
|
||||||
Raw: []byte(resMatch),
|
Raw: []byte(resMatch),
|
||||||
RawV2: []byte(resMatch + resApiMatch),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if verify {
|
if verify {
|
||||||
|
|||||||
@@ -14,13 +14,6 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// Convenience consts for implementing detectors.
|
|
||||||
Unknown = detectorspb.VerifiedResult_VERIFIED_UNKNOWN
|
|
||||||
Verified = detectorspb.VerifiedResult_VERIFIED
|
|
||||||
Unverified = detectorspb.VerifiedResult_UNVERIFIED
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detector defines an interface for scanning for and verifying secrets.
|
// Detector defines an interface for scanning for and verifying secrets.
|
||||||
type Detector interface {
|
type Detector interface {
|
||||||
// FromData will scan bytes for results, and optionally verify them.
|
// FromData will scan bytes for results, and optionally verify them.
|
||||||
@@ -38,21 +31,12 @@ type Versioner interface {
|
|||||||
Version() int
|
Version() int
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointCustomizer is an optional interface that a detector can implement to
|
|
||||||
// support verifying against user-supplied endpoints.
|
|
||||||
type EndpointCustomizer interface {
|
|
||||||
SetEndpoints(...string) error
|
|
||||||
DefaultEndpoint() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
// DetectorType is the type of Detector.
|
// DetectorType is the type of Detector.
|
||||||
DetectorType detectorspb.DetectorType
|
DetectorType detectorspb.DetectorType
|
||||||
// DetectorName is the name of the Detector. Used for custom detectors.
|
|
||||||
DetectorName string
|
|
||||||
// DecoderType is the type of Decoder.
|
// DecoderType is the type of Decoder.
|
||||||
DecoderType detectorspb.DecoderType
|
DecoderType detectorspb.DecoderType
|
||||||
Verified detectorspb.VerifiedResult
|
Verified bool
|
||||||
// Raw contains the raw secret identifier data. Prefer IDs over secrets since it is used for deduping after hashing.
|
// Raw contains the raw secret identifier data. Prefer IDs over secrets since it is used for deduping after hashing.
|
||||||
Raw []byte
|
Raw []byte
|
||||||
// RawV2 contains the raw secret identifier that is a combination of both the ID and the secret.
|
// RawV2 contains the raw secret identifier that is a combination of both the ID and the secret.
|
||||||
@@ -75,8 +59,6 @@ type ResultWithMetadata struct {
|
|||||||
// SourceName is the name of the Source.
|
// SourceName is the name of the Source.
|
||||||
SourceName string
|
SourceName string
|
||||||
Result
|
Result
|
||||||
// Data from the sources.Chunk which this result was emitted for
|
|
||||||
Data []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyMetadata returns a detector result with included metadata from the source chunk.
|
// CopyMetadata returns a detector result with included metadata from the source chunk.
|
||||||
@@ -87,7 +69,6 @@ func CopyMetadata(chunk *sources.Chunk, result Result) ResultWithMetadata {
|
|||||||
SourceType: chunk.SourceType,
|
SourceType: chunk.SourceType,
|
||||||
SourceName: chunk.SourceName,
|
SourceName: chunk.SourceName,
|
||||||
Result: result,
|
Result: result,
|
||||||
Data: chunk.Data,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +82,7 @@ func CleanResults(results []Result) []Result {
|
|||||||
var cleaned = make(map[string]Result, 0)
|
var cleaned = make(map[string]Result, 0)
|
||||||
|
|
||||||
for _, s := range results {
|
for _, s := range results {
|
||||||
if s.Verified == Verified {
|
if s.Verified {
|
||||||
cleaned[s.Redacted] = s
|
cleaned[s.Redacted] = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
package detectors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EndpointSetter implements a sensible default for the SetEndpoints function
|
|
||||||
// of the EndpointCustomizer interface. A detector can embed this struct to
|
|
||||||
// gain the functionality.
|
|
||||||
type EndpointSetter struct {
|
|
||||||
endpoints []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EndpointSetter) SetEndpoints(endpoints ...string) error {
|
|
||||||
if len(endpoints) == 0 {
|
|
||||||
return fmt.Errorf("at least one endpoint required")
|
|
||||||
}
|
|
||||||
deduped := make([]string, 0, len(endpoints))
|
|
||||||
for _, endpoint := range endpoints {
|
|
||||||
common.AddStringSliceItem(endpoint, &deduped)
|
|
||||||
}
|
|
||||||
e.endpoints = deduped
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *EndpointSetter) Endpoints(defaultEndpoint string) []string {
|
|
||||||
// The only valid time len(e.endpoints) == 0 is when EndpointSetter is
|
|
||||||
// initializetd to its default state. That means SetEndpoints was never
|
|
||||||
// called and we should use the default.
|
|
||||||
if len(e.endpoints) == 0 {
|
|
||||||
return []string{defaultEndpoint}
|
|
||||||
}
|
|
||||||
return e.endpoints
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package detectors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEmbeddedEndpointSetter(t *testing.T) {
|
|
||||||
type Scanner struct{ EndpointSetter }
|
|
||||||
var s Scanner
|
|
||||||
assert.Equal(t, []string{"baz"}, s.Endpoints("baz"))
|
|
||||||
assert.NoError(t, s.SetEndpoints("foo", "bar"))
|
|
||||||
assert.Error(t, s.SetEndpoints())
|
|
||||||
assert.Equal(t, []string{"foo", "bar"}, s.Endpoints("baz"))
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package etherscan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"etherscan"}) + `\b([0-9A-Z]{34})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"etherscan"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Etherscan secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Etherscan,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.etherscan.io/api?module=account&action=balance&address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae&tag=latest&apikey="+resMatch, nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
bodyBytes, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
body := string(bodyBytes)
|
|
||||||
|
|
||||||
if strings.Contains(body, `"OK"`) {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Etherscan
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package etherscan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEtherscan_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("ETHERSCAN")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("ETHERSCAN_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a etherscan secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Etherscan,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a etherscan secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Etherscan,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Etherscan.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Etherscan.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,7 @@ var (
|
|||||||
client = common.SaneHttpClient()
|
client = common.SaneHttpClient()
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"float"}) + `\b([a-f0-9]{16}[A-Za-z0-9+/]{42,43}=)`)
|
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"float"}) + `\b([a-zA-Z0-9-._+=/]{59,60})\b`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
|
|||||||
@@ -79,16 +79,14 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
raw = []byte(key)
|
raw = []byte(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
credBytes, _ := json.Marshal(creds)
|
|
||||||
|
|
||||||
s := detectors.Result{
|
s := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_GCP,
|
DetectorType: detectorspb.DetectorType_GCP,
|
||||||
Raw: raw,
|
Raw: raw,
|
||||||
RawV2: credBytes,
|
|
||||||
Redacted: creds.ClientEmail,
|
Redacted: creds.ClientEmail,
|
||||||
}
|
}
|
||||||
|
|
||||||
if verify {
|
if verify {
|
||||||
|
credBytes, _ := json.Marshal(creds)
|
||||||
credentials, err := google.CredentialsFromJSON(ctx, credBytes, "https://www.googleapis.com/auth/cloud-platform")
|
credentials, err := google.CredentialsFromJSON(ctx, credBytes, "https://www.googleapis.com/auth/cloud-platform")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func New() Scanner {
|
|||||||
`[A-Z]{2,6}\-[0-9]{2,6}`, // issue tracker
|
`[A-Z]{2,6}\-[0-9]{2,6}`, // issue tracker
|
||||||
`#[a-fA-F0-9]{6}\b`, // hex color code
|
`#[a-fA-F0-9]{6}\b`, // hex color code
|
||||||
`\b[A-Fa-f0-9]{64}\b`, // hex encoded hash
|
`\b[A-Fa-f0-9]{64}\b`, // hex encoded hash
|
||||||
|
`\b[A-Fa-f0-9]{32}\b`, // hex encoded hash
|
||||||
`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`, // http
|
`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`, // http
|
||||||
`\b([/]{0,1}([\w]+[/])+[\w\.]*)\b`, // filepath
|
`\b([/]{0,1}([\w]+[/])+[\w\.]*)\b`, // filepath
|
||||||
`([0-9A-F]{2}[:-]){5}([0-9A-F]{2})`, // MAC addr
|
`([0-9A-F]{2}[:-]){5}([0-9A-F]{2})`, // MAC addr
|
||||||
@@ -27,6 +28,7 @@ func New() Scanner {
|
|||||||
`[v|\-]\d\.\d`, //version
|
`[v|\-]\d\.\d`, //version
|
||||||
`\d\.\d\.\d-`, //version
|
`\d\.\d\.\d-`, //version
|
||||||
`[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}`, // IPs and OIDs
|
`[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}`, // IPs and OIDs
|
||||||
|
`\b[A-Fa-f0-9x]{6,99}\b`, // hex encoding
|
||||||
`[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}`, // hex encoding
|
`[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}`, // hex encoding
|
||||||
`[\w]+\([\w, ]+\)`, // function
|
`[\w]+\([\w, ]+\)`, // function
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,13 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Scanner struct{ detectors.EndpointSetter }
|
type Scanner struct{}
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interfaces at compile time.
|
// Ensure the Scanner satisfies the interfaces at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
var _ detectors.Versioner = (*Scanner)(nil)
|
var _ detectors.Versioner = (*Scanner)(nil)
|
||||||
var _ detectors.EndpointCustomizer = (*Scanner)(nil)
|
|
||||||
|
|
||||||
func (Scanner) Version() int { return 2 }
|
func (s Scanner) Version() int { return 2 }
|
||||||
func (Scanner) DefaultEndpoint() string { return "https://api.github.com" }
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Oauth token
|
// Oauth token
|
||||||
@@ -31,7 +29,7 @@ var (
|
|||||||
// https://github.blog/changelog/2022-10-18-introducing-fine-grained-personal-access-tokens/
|
// https://github.blog/changelog/2022-10-18-introducing-fine-grained-personal-access-tokens/
|
||||||
keyPat = regexp.MustCompile(`\b((?:ghp|gho|ghu|ghs|ghr|github_pat)_[a-zA-Z0-9_]{36,255})\b`)
|
keyPat = regexp.MustCompile(`\b((?:ghp|gho|ghu|ghs|ghr|github_pat)_[a-zA-Z0-9_]{36,255})\b`)
|
||||||
|
|
||||||
// TODO: Oauth2 client_id and client_secret
|
//TODO: Oauth2 client_id and client_secret
|
||||||
// https://developer.github.com/v3/#oauth2-keysecret
|
// https://developer.github.com/v3/#oauth2-keysecret
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -73,29 +71,27 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
if verify {
|
if verify {
|
||||||
client := common.SaneHttpClient()
|
client := common.SaneHttpClient()
|
||||||
// https://developer.github.com/v3/users/#get-the-authenticated-user
|
// https://developer.github.com/v3/users/#get-the-authenticated-user
|
||||||
for _, url := range s.Endpoints(s.DefaultEndpoint()) {
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.github.com/user", nil)
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/user", url), nil)
|
if err != nil {
|
||||||
if err != nil {
|
continue
|
||||||
continue
|
}
|
||||||
}
|
req.Header.Add("Content-Type", "application/json; charset=utf-8")
|
||||||
req.Header.Add("Content-Type", "application/json; charset=utf-8")
|
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
|
res, err := client.Do(req)
|
||||||
res, err := client.Do(req)
|
if err == nil {
|
||||||
if err == nil {
|
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
var userResponse userRes
|
||||||
var userResponse userRes
|
err = json.NewDecoder(res.Body).Decode(&userResponse)
|
||||||
err = json.NewDecoder(res.Body).Decode(&userResponse)
|
res.Body.Close()
|
||||||
res.Body.Close()
|
if err == nil {
|
||||||
if err == nil {
|
s1.Verified = true
|
||||||
s1.Verified = true
|
s1.ExtraData = map[string]string{
|
||||||
s1.ExtraData = map[string]string{
|
"username": userResponse.Login,
|
||||||
"username": userResponse.Login,
|
"url": userResponse.UserURL,
|
||||||
"url": userResponse.UserURL,
|
"account_type": userResponse.Type,
|
||||||
"account_type": userResponse.Type,
|
"site_admin": fmt.Sprintf("%t", userResponse.SiteAdmin),
|
||||||
"site_admin": fmt.Sprintf("%t", userResponse.SiteAdmin),
|
"name": userResponse.Name,
|
||||||
"name": userResponse.Name,
|
"company": userResponse.Company,
|
||||||
"company": userResponse.Company,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,13 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Scanner struct{ detectors.EndpointSetter }
|
type Scanner struct{}
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interfaces at compile time.
|
// Ensure the Scanner satisfies the interfaces at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
var _ detectors.Versioner = (*Scanner)(nil)
|
var _ detectors.Versioner = (*Scanner)(nil)
|
||||||
var _ detectors.EndpointCustomizer = (*Scanner)(nil)
|
|
||||||
|
|
||||||
func (Scanner) Version() int { return 1 }
|
func (s Scanner) Version() int { return 1 }
|
||||||
func (Scanner) DefaultEndpoint() string { return "https://api.github.com" }
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Oauth token
|
// Oauth token
|
||||||
@@ -65,7 +63,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
s1 := detectors.Result{
|
s := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_Github,
|
DetectorType: detectorspb.DetectorType_Github,
|
||||||
Raw: []byte(token),
|
Raw: []byte(token),
|
||||||
}
|
}
|
||||||
@@ -73,32 +71,30 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
if verify {
|
if verify {
|
||||||
client := common.SaneHttpClient()
|
client := common.SaneHttpClient()
|
||||||
// https://developer.github.com/v3/users/#get-the-authenticated-user
|
// https://developer.github.com/v3/users/#get-the-authenticated-user
|
||||||
for _, url := range s.Endpoints(s.DefaultEndpoint()) {
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.github.com/user", nil)
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/user", url), nil)
|
if err != nil {
|
||||||
if err != nil {
|
continue
|
||||||
continue
|
}
|
||||||
}
|
req.Header.Add("Content-Type", "application/json; charset=utf-8")
|
||||||
req.Header.Add("Content-Type", "application/json; charset=utf-8")
|
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
|
res, err := client.Do(req)
|
||||||
res, err := client.Do(req)
|
if err == nil {
|
||||||
if err == nil {
|
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
var userResponse userRes
|
||||||
var userResponse userRes
|
err = json.NewDecoder(res.Body).Decode(&userResponse)
|
||||||
err = json.NewDecoder(res.Body).Decode(&userResponse)
|
res.Body.Close()
|
||||||
res.Body.Close()
|
if err == nil {
|
||||||
if err == nil {
|
s.Verified = true
|
||||||
s1.Verified = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s1.Verified && detectors.IsKnownFalsePositive(token, detectors.DefaultFalsePositives, true) {
|
if !s.Verified && detectors.IsKnownFalsePositive(token, detectors.DefaultFalsePositives, true) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, s1)
|
results = append(results, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
|
|||||||
@@ -12,15 +12,13 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Scanner struct{ detectors.EndpointSetter }
|
type Scanner struct{}
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interfaces at compile time.
|
// Ensure the Scanner satisfies the interfaces at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
var _ detectors.Versioner = (*Scanner)(nil)
|
var _ detectors.Versioner = (*Scanner)(nil)
|
||||||
var _ detectors.EndpointCustomizer = (*Scanner)(nil)
|
|
||||||
|
|
||||||
func (Scanner) Version() int { return 1 }
|
func (s Scanner) Version() int { return 1 }
|
||||||
func (Scanner) DefaultEndpoint() string { return "https://gitlab.com" }
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"gitlab"}) + `\b((?:glpat|)[a-zA-Z0-9\-=_]{20,22})\b`)
|
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"gitlab"}) + `\b((?:glpat|)[a-zA-Z0-9\-=_]{20,22})\b`)
|
||||||
@@ -58,25 +56,24 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
// they all grant access to different parts of the API. I couldn't find an endpoint that every
|
// they all grant access to different parts of the API. I couldn't find an endpoint that every
|
||||||
// one of these scopes has access to, so we just check an example endpoint for each scope. If any
|
// one of these scopes has access to, so we just check an example endpoint for each scope. If any
|
||||||
// of them contain data, we know we have a valid key, but if they all fail, we don't
|
// of them contain data, we know we have a valid key, but if they all fail, we don't
|
||||||
|
baseURL := "https://gitlab.com/api/v4"
|
||||||
|
|
||||||
client := common.SaneHttpClient()
|
client := common.SaneHttpClient()
|
||||||
for _, baseURL := range s.Endpoints(s.DefaultEndpoint()) {
|
// test `read_user` scope
|
||||||
// test `read_user` scope
|
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/user", nil)
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/v4/user", nil)
|
if err != nil {
|
||||||
if err != nil {
|
continue
|
||||||
continue
|
}
|
||||||
}
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
|
res, err := client.Do(req)
|
||||||
res, err := client.Do(req)
|
if err == nil {
|
||||||
if err == nil {
|
res.Body.Close() // The request body is unused.
|
||||||
res.Body.Close() // The request body is unused.
|
|
||||||
|
|
||||||
// 200 means good key and has `read_user` scope
|
// 200 means good key and has `read_user` scope
|
||||||
// 403 means good key but not the right scope
|
// 403 means good key but not the right scope
|
||||||
// 401 is bad key
|
// 401 is bad key
|
||||||
if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusForbidden {
|
if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusForbidden {
|
||||||
secret.Verified = true
|
secret.Verified = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,13 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Scanner struct{ detectors.EndpointSetter }
|
type Scanner struct{}
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interfaces at compile time.
|
// Ensure the Scanner satisfies the interfaces at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
var _ detectors.Versioner = (*Scanner)(nil)
|
var _ detectors.Versioner = (*Scanner)(nil)
|
||||||
var _ detectors.EndpointCustomizer = (*Scanner)(nil)
|
|
||||||
|
|
||||||
func (Scanner) Version() int { return 2 }
|
func (*Scanner) Version() int { return 2 }
|
||||||
func (Scanner) DefaultEndpoint() string { return "https://gitlab.com" }
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
keyPat = regexp.MustCompile(`\b(glpat-[a-zA-Z0-9\-=_]{20,22})\b`)
|
keyPat = regexp.MustCompile(`\b(glpat-[a-zA-Z0-9\-=_]{20,22})\b`)
|
||||||
@@ -52,27 +50,27 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
// they all grant access to different parts of the API. I couldn't find an endpoint that every
|
// they all grant access to different parts of the API. I couldn't find an endpoint that every
|
||||||
// one of these scopes has access to, so we just check an example endpoint for each scope. If any
|
// one of these scopes has access to, so we just check an example endpoint for each scope. If any
|
||||||
// of them contain data, we know we have a valid key, but if they all fail, we don't
|
// of them contain data, we know we have a valid key, but if they all fail, we don't
|
||||||
client := common.SaneHttpClient()
|
baseURL := "https://gitlab.com/api/v4"
|
||||||
for _, baseURL := range s.Endpoints(s.DefaultEndpoint()) {
|
|
||||||
// test `read_user` scope
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/v4/user", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", match[1]))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
res.Body.Close() // The request body is unused.
|
|
||||||
|
|
||||||
// 200 means good key and has `read_user` scope
|
client := common.SaneHttpClient()
|
||||||
// 403 means good key but not the right scope
|
|
||||||
// 401 is bad key
|
// test `read_user` scope
|
||||||
if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusForbidden {
|
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/user", nil)
|
||||||
secret.Verified = true
|
if err != nil {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", match[1]))
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err == nil {
|
||||||
|
res.Body.Close() // The request body is unused.
|
||||||
|
|
||||||
|
// 200 means good key and has `read_user` scope
|
||||||
|
// 403 means good key but not the right scope
|
||||||
|
// 401 is bad key
|
||||||
|
if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusForbidden {
|
||||||
|
secret.Verified = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !secret.Verified && detectors.IsKnownFalsePositive(string(secret.Raw), detectors.DefaultFalsePositives, true) {
|
if !secret.Verified && detectors.IsKnownFalsePositive(string(secret.Raw), detectors.DefaultFalsePositives, true) {
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
package infura
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"infura"}) + `\b([0-9a-z]{32})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"infura"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Infura secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Infura,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
payload := strings.NewReader(`{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}`)
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "POST", "https://mainnet.infura.io/v3/"+resMatch, payload)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
bodyBytes, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
body := string(bodyBytes)
|
|
||||||
if strings.Contains(body, `"result"`) {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Infura
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package infura
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInfura_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("INFURA")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("INFURA_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a infura secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Infura,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a infura secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Infura,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Infura.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Infura.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,7 @@ var (
|
|||||||
client = common.SaneHttpClient()
|
client = common.SaneHttpClient()
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"ipstack"}) + `\b([a-fA-F0-9]{32})\b`)
|
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"ipstack"}) + `\b([a-fA-f0-9]{32})\b`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -13,35 +12,7 @@ import (
|
|||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Scanner struct {
|
type Scanner struct{}
|
||||||
ignorePatterns []regexp.Regexp
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(opts ...func(*Scanner)) *Scanner {
|
|
||||||
scanner := &Scanner{
|
|
||||||
ignorePatterns: []regexp.Regexp{},
|
|
||||||
}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(scanner)
|
|
||||||
}
|
|
||||||
|
|
||||||
return scanner
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithIgnorePattern(ignoreStrings []string) func(*Scanner) {
|
|
||||||
return func(s *Scanner) {
|
|
||||||
ignorePatterns := []regexp.Regexp{}
|
|
||||||
for _, ignoreString := range ignoreStrings {
|
|
||||||
ignorePattern, err := regexp.Compile(ignoreString)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("%s is not a valid regex, error received: %v", ignoreString, err))
|
|
||||||
}
|
|
||||||
ignorePatterns = append(ignorePatterns, *ignorePattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.ignorePatterns = ignorePatterns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
// Ensure the Scanner satisfies the interface at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
@@ -61,15 +32,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
dataStr := string(data)
|
dataStr := string(data)
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
||||||
matchLoop:
|
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
if len(s.ignorePatterns) != 0 {
|
|
||||||
for _, ignore := range s.ignorePatterns {
|
|
||||||
if ignore.MatchString(match[0]) {
|
|
||||||
continue matchLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jdbcConn := match[0]
|
jdbcConn := match[0]
|
||||||
|
|
||||||
s := detectors.Result{
|
s := detectors.Result{
|
||||||
|
|||||||
@@ -156,57 +156,6 @@ func TestJdbc_FromChunk(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJdbc_FromDataWithIgnorePattern(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
ignorePatterns []string
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("jdbc:sqlite::secretpattern:"),
|
|
||||||
verify: false,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
ignorePatterns: []string{
|
|
||||||
".*secretpattern.*",
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := New(WithIgnorePattern(tt.ignorePatterns))
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Jdbc.FromDataWithConfig() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if os.Getenv("FORCE_PASS_DIFF") == "true" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatal("no raw secret present")
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Jdbc.FromDataWithConfig() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
func BenchmarkFromData(benchmark *testing.B) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
s := Scanner{}
|
s := Scanner{}
|
||||||
|
|||||||
@@ -24,12 +24,7 @@ var (
|
|||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||||
tokenPat = regexp.MustCompile(detectors.PrefixRegex([]string{"jira"}) + `\b([a-zA-Z-0-9]{24})\b`)
|
tokenPat = regexp.MustCompile(detectors.PrefixRegex([]string{"jira"}) + `\b([a-zA-Z-0-9]{24})\b`)
|
||||||
domainPat = regexp.MustCompile(detectors.PrefixRegex([]string{"jira"}) + `\b([a-zA-Z-0-9]{5,24}\.[a-zA-Z-0-9]{3,16}\.[a-zA-Z-0-9]{3,16})\b`)
|
domainPat = regexp.MustCompile(detectors.PrefixRegex([]string{"jira"}) + `\b([a-zA-Z-0-9]{5,24}\.[a-zA-Z-0-9]{3,16}\.[a-zA-Z-0-9]{3,16})\b`)
|
||||||
emailPat = regexp.MustCompile(detectors.PrefixRegex([]string{"jira"}) + `\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b`)
|
emailPat = regexp.MustCompile(detectors.PrefixRegex([]string{"jira"}) + `\b([a-zA-Z-0-9]{5,24}\@[a-zA-Z-0-9]{3,16}\.com)\b`)
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
failedAuth = "AUTHENTICATED_FAILED"
|
|
||||||
loginReasonHeaderKey = "X-Seraph-LoginReason"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
@@ -47,7 +42,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
emails := emailPat.FindAllStringSubmatch(dataStr, -1)
|
emails := emailPat.FindAllStringSubmatch(dataStr, -1)
|
||||||
|
|
||||||
for _, email := range emails {
|
for _, email := range emails {
|
||||||
email = strings.Split(email[0], " ")
|
|
||||||
if len(email) != 2 {
|
if len(email) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -66,10 +60,10 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
s1 := detectors.Result{
|
s1 := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_JiraToken,
|
DetectorType: detectorspb.DetectorType_JiraToken,
|
||||||
Raw: []byte(resToken),
|
Raw: []byte(resToken),
|
||||||
RawV2: []byte(fmt.Sprintf("%s:%s:%s", resEmail, resToken, resDomain)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if verify {
|
if verify {
|
||||||
|
|
||||||
data := fmt.Sprintf("%s:%s", resEmail, resToken)
|
data := fmt.Sprintf("%s:%s", resEmail, resToken)
|
||||||
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
|
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://"+resDomain+"/rest/api/3/dashboard", nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://"+resDomain+"/rest/api/3/dashboard", nil)
|
||||||
@@ -81,11 +75,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||||
// If the request is successful and the login reason is not failed authentication, then the token is valid.
|
|
||||||
// This is because Jira returns a 200 status code even if the token is invalid.
|
|
||||||
// Jira returns a default dashboard page.
|
|
||||||
if (res.StatusCode >= 200 && res.StatusCode < 300) && res.Header.Get(loginReasonHeaderKey) != failedAuth {
|
|
||||||
s1.Verified = true
|
s1.Verified = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ func TestJiraToken_FromChunk(t *testing.T) {
|
|||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
t.Fatalf("no raw secret present: \n %+v", got[i])
|
||||||
}
|
}
|
||||||
got[i].Raw = nil
|
got[i].Raw = nil
|
||||||
got[i].RawV2 = nil
|
|
||||||
}
|
}
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
if diff := pretty.Compare(got, tt.want); diff != "" {
|
||||||
t.Errorf("JiraToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
t.Errorf("JiraToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Scanner struct{}
|
type Scanner struct{}
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
// Ensure the Scanner satisfies the interface at compile time.
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
}
|
}
|
||||||
body := string(bodyBytes)
|
body := string(bodyBytes)
|
||||||
|
|
||||||
if !strings.Contains(body, "AUTHFAIL") {
|
if !strings.Contains(body, "INVALIDTOKEN") {
|
||||||
s1.Verified = true
|
s1.Verified = true
|
||||||
} else {
|
} else {
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package mockaroo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -49,19 +47,16 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
}
|
}
|
||||||
|
|
||||||
if verify {
|
if verify {
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.mockaroo.com/api/types?key=%s", resMatch), nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.mockaroo.com/api/types", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
req.Header.Add("X-API-Key", resMatch)
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
||||||
var t typeRes
|
s1.Verified = true
|
||||||
err = json.NewDecoder(res.Body).Decode(&t)
|
|
||||||
if err == nil && len(t.Types) > 0 {
|
|
||||||
s1.Verified = true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
||||||
@@ -80,11 +75,3 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
func (s Scanner) Type() detectorspb.DetectorType {
|
||||||
return detectorspb.DetectorType_Mockaroo
|
return detectorspb.DetectorType_Mockaroo
|
||||||
}
|
}
|
||||||
|
|
||||||
type typeRes struct {
|
|
||||||
Types []struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type interface{} `json:"type"`
|
|
||||||
Parameters []interface{} `json:"parameters"`
|
|
||||||
} `json:"types"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package moralis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"moralis"}) + `\b([0-9a-zA-Z]{64})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"moralis"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Moralis secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Moralis,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://deep-index.moralis.io/api/v2/0xd8da6bf26964af9d7eed9e03e53415d37aa96045/nft?chain=eth&format=decimal", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Accept", "application/json")
|
|
||||||
req.Header.Add("X-API-Key", resMatch)
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Moralis
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package moralis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMoralis_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("MORALIS")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("MORALIS_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a moralis secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Moralis,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a moralis secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Moralis,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Moralis.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Moralis.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package nugetapikey
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"nuget"}) + `\b([a-z0-9]{46})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"nuget"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Nugetapikey secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_NuGetApiKey,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "PUT", "https://www.nuget.org/api/v2/package", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Content-Length", "0")
|
|
||||||
req.Header.Add("X-NuGet-ApiKey", resMatch)
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
// we can either match on response code "400" or "Bad Request" response
|
|
||||||
if res.StatusCode == 400 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_NuGetApiKey
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package nugetapikey
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNugetapikey_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("NUGETAPIKEY")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("NUGETAPIKEY_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a nugetapikey secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_NuGetApiKey,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a nugetapikey secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_NuGetApiKey,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Nugetapikey.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Nugetapikey.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -41,7 +41,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
s := detectors.Result{
|
s := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_Okta,
|
DetectorType: detectorspb.DetectorType_Okta,
|
||||||
Raw: []byte(token),
|
Raw: []byte(token),
|
||||||
RawV2: []byte(fmt.Sprintf("%s:%s", domain, token)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if verify {
|
if verify {
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
s := detectors.Result{
|
s := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_OneLogin,
|
DetectorType: detectorspb.DetectorType_OneLogin,
|
||||||
Raw: []byte(clientID[1]),
|
Raw: []byte(clientID[1]),
|
||||||
RawV2: []byte(fmt.Sprintf("%s:%s", clientID[1], clientSecret[1])),
|
|
||||||
Redacted: clientID[1],
|
Redacted: clientID[1],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
package openai
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
// The magic string T3BlbkFJ is the base64-encoded string: OpenAI
|
|
||||||
var keyPat = regexp.MustCompile(`\b(sk-[[:alnum:]]{20}T3BlbkFJ[[:alnum:]]{20})\b`)
|
|
||||||
|
|
||||||
// TODO: Add secret context?? Information about access, ownership etc
|
|
||||||
type orgResponse struct {
|
|
||||||
Data []organization `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type organization struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
User string `json:"name"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Personal bool `json:"personal"`
|
|
||||||
Default bool `json:"is_default"`
|
|
||||||
Role string `json:"role"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"T3BlbkFJ"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify OpenAI secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
// First match is entire regex, second is the first group.
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
token := match[1]
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_OpenAI,
|
|
||||||
Redacted: token[:3] + "..." + token[47:],
|
|
||||||
Raw: []byte(token),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
client := common.SaneHttpClient()
|
|
||||||
// Undocumented API
|
|
||||||
// https://api.openai.com/v1/organizations
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.openai.com/v1/organizations", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Content-Type", "application/json; charset=utf-8")
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
var orgs orgResponse
|
|
||||||
err = json.NewDecoder(res.Body).Decode(&orgs)
|
|
||||||
res.Body.Close()
|
|
||||||
if err == nil {
|
|
||||||
s1.Verified = true
|
|
||||||
org := orgs.Data[0]
|
|
||||||
s1.ExtraData = map[string]string{
|
|
||||||
"id": org.ID,
|
|
||||||
"title": org.Title,
|
|
||||||
"user": org.User,
|
|
||||||
"description": org.Description,
|
|
||||||
"role": org.Role,
|
|
||||||
"is_personal": strconv.FormatBool(org.Personal),
|
|
||||||
"is_default": strconv.FormatBool(org.Default),
|
|
||||||
"total_orgs": fmt.Sprintf("%d", len(orgs.Data)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s1.Verified && detectors.IsKnownFalsePositive(string(s1.Raw), detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_OpenAI
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package openai
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOpenAI_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oaiUnverified := testSecrets.MustGetField("OPENAI_UNVERIFIED")
|
|
||||||
oaiVerified := testSecrets.MustGetField("OPENAI_VERIFIED")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Found, unverified OpenAI token sk-",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find an OpenAI secret %s within", oaiUnverified)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_OpenAI,
|
|
||||||
Redacted: "sk-...gOPc",
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Found, verified OpenAI token sk-",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find an OpenAI secret %s within", oaiVerified)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_OpenAI,
|
|
||||||
Verified: true,
|
|
||||||
Redacted: "sk-...gOPb",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("OpenAI.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatal("no raw secret present")
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
got[i].ExtraData = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("OpenAI.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package percy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"percy"}) + `\bPERCY_TOKEN=([0-9Aa-f]{64})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"percy"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Percy secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Percy,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://percy.io/api/v1/projects", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Accept", "application/vnd.percy+json; version=3")
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Token %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Percy
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package percy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPercy_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("PERCY_VERIFIED")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("PERCY_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a percy secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Percy,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a percy secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Percy,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Percy.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Percy.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package prefect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(`\b(pnu_[a-zA-Z0-9]{36})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"pnu_"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Prefect secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Prefect,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.prefect.cloud/auth/login", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Prefect
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package prefect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPrefect_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("PREFECT")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("PREFECT_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a prefect secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Prefect,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a prefect secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Prefect,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Prefect.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Prefect.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package pulumi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(`\b(pul-[a-z0-9]{40})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"pul-"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Pulumi secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_Pulumi,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.pulumi.com/api/user/stacks", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Accept", "application/vnd.pulumi+8")
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("token %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_Pulumi
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package pulumi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPulumi_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("PULUMI")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("PULUMI_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a pulumi secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Pulumi,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a pulumi secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_Pulumi,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Pulumi.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Pulumi.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,7 @@ var (
|
|||||||
client = common.SaneHttpClient()
|
client = common.SaneHttpClient()
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
||||||
keyPat = regexp.MustCompile(`(https://hooks\.slack\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]{23,25})`)
|
keyPat = regexp.MustCompile(`(https://hooks\.slack\.com/services/[A-Za-z0-9+/]{44,46})`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
@@ -62,7 +62,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
body := string(bodyBytes)
|
body := string(bodyBytes)
|
||||||
if (res.StatusCode >= 200 && res.StatusCode < 300) || (res.StatusCode == 400 && strings.Contains(body, "no_text")) {
|
if (res.StatusCode >= 200 && res.StatusCode < 300) || (res.StatusCode == 400 && strings.Contains(body, "text")) {
|
||||||
s1.Verified = true
|
s1.Verified = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ var (
|
|||||||
// Keywords are used for efficiently pre-filtering chunks.
|
// Keywords are used for efficiently pre-filtering chunks.
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
// Use identifiers in the secret preferably, or the provider name.
|
||||||
func (s Scanner) Keywords() []string {
|
func (s Scanner) Keywords() []string {
|
||||||
return []string{"sql", "database", "Data Source"}
|
return []string{"sqlserver"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromData will find and optionally verify SpotifyKey secrets in a given set of bytes.
|
// FromData will find and optionally verify SpotifyKey secrets in a given set of bytes.
|
||||||
|
|||||||
@@ -5,15 +5,14 @@ package sqlserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/denisenkom/go-mssqldb/msdsn"
|
"github.com/denisenkom/go-mssqldb/msdsn"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,59 +75,6 @@ func TestSQLServer_FromChunk(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "not found, in XML, missing password param (pwd is not valid)",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(`<add name="Sample2" value="SERVER=server_name;DATABASE=database_name;user=user_name;pwd=plaintextpassword;encrypt=true;Timeout=120;MultipleActiveResultSets=True;" />`),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
mockFunc: func() {
|
|
||||||
ping = func(config msdsn.Config) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, verified, in XML",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(`<add name="test db" value="SERVER=server_name;DATABASE=testdb;user=username;password=badpassword;encrypt=true;Timeout=120;MultipleActiveResultSets=True;" />`),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_SQLServer,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
mockFunc: func() {
|
|
||||||
ping = func(config msdsn.Config) (bool, error) {
|
|
||||||
if config.Host != "server_name" {
|
|
||||||
return false, errors.New("invalid host")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.User != "username" {
|
|
||||||
return false, errors.New("invalid database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Password != "badpassword" {
|
|
||||||
return false, errors.New("invalid password")
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Database != "testdb" {
|
|
||||||
return false, errors.New("invalid database")
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "not found",
|
name: "not found",
|
||||||
s: Scanner{},
|
s: Scanner{},
|
||||||
@@ -173,16 +119,13 @@ func TestSQLServer_FromChunk(t *testing.T) {
|
|||||||
|
|
||||||
func TestSQLServer_pattern(t *testing.T) {
|
func TestSQLServer_pattern(t *testing.T) {
|
||||||
if !pattern.Match([]byte(`builder.Services.AddDbContext<Database>(optionsBuilder => optionsBuilder.UseSqlServer("Server=localhost;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;Persist Security Info=true;MultipleActiveResultSets=true;"));`)) {
|
if !pattern.Match([]byte(`builder.Services.AddDbContext<Database>(optionsBuilder => optionsBuilder.UseSqlServer("Server=localhost;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;Persist Security Info=true;MultipleActiveResultSets=true;"));`)) {
|
||||||
t.Errorf("SQLServer.pattern: did not find connection string from Program.cs")
|
t.Errorf("SQLServer.pattern: did not catched connection string from Program.cs")
|
||||||
}
|
}
|
||||||
if !pattern.Match([]byte(`{"ConnectionStrings": {"Demo": "Server=localhost;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;Persist Security Info=true;MultipleActiveResultSets=true;"}}`)) {
|
if !pattern.Match([]byte(`{"ConnectionStrings": {"Demo": "Server=localhost;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;Persist Security Info=true;MultipleActiveResultSets=true;"}}`)) {
|
||||||
t.Errorf("SQLServer.pattern: did not find connection string from appsettings.json")
|
t.Errorf("SQLServer.pattern: did not catched connection string from appsettings.json")
|
||||||
}
|
}
|
||||||
if !pattern.Match([]byte(`CONNECTION_STRING: Server=localhost;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;Persist Security Info=true;MultipleActiveResultSets=true`)) {
|
if !pattern.Match([]byte(`CONNECTION_STRING: Server=localhost;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;Persist Security Info=true;MultipleActiveResultSets=true`)) {
|
||||||
t.Errorf("SQLServer.pattern: did not find connection string from .env")
|
t.Errorf("SQLServer.pattern: did not catched connection string from .env")
|
||||||
}
|
|
||||||
if !pattern.Match([]byte(`<add name="Sample2" value="SERVER=server_name;DATABASE=database_name;user=user_name;pwd=plaintextpassword;encrypt=true;Timeout=120;MultipleActiveResultSets=True;" />`)) {
|
|
||||||
t.Errorf("SQLServer.pattern: did not find connection string in xml format")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type Scanner struct{}
|
|||||||
var _ detectors.Detector = (*Scanner)(nil)
|
var _ detectors.Detector = (*Scanner)(nil)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// possibly always `sq0csp` for secret
|
//possibly always `sq0csp` for secret
|
||||||
// and `sq0idb` for app
|
// and `sq0idb` for app
|
||||||
keyPat = regexp.MustCompile(`[\w\-]*sq0i[a-z]{2}-[0-9A-Za-z\-_]{22,43}`)
|
keyPat = regexp.MustCompile(`[\w\-]*sq0i[a-z]{2}-[0-9A-Za-z\-_]{22,43}`)
|
||||||
secPat = regexp.MustCompile(`[\w\-]*sq0c[a-z]{2}-[0-9A-Za-z\-_]{40,50}`)
|
secPat = regexp.MustCompile(`[\w\-]*sq0c[a-z]{2}-[0-9A-Za-z\-_]{40,50}`)
|
||||||
@@ -39,6 +39,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
matches := keyPat.FindAllString(dataStr, -1)
|
matches := keyPat.FindAllString(dataStr, -1)
|
||||||
secMatches := secPat.FindAllString(dataStr, -1)
|
secMatches := secPat.FindAllString(dataStr, -1)
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
|
|
||||||
for _, secMatch := range secMatches {
|
for _, secMatch := range secMatches {
|
||||||
|
|
||||||
if detectors.IsKnownFalsePositive(strings.ToLower(secMatch), detectors.DefaultFalsePositives, true) {
|
if detectors.IsKnownFalsePositive(strings.ToLower(secMatch), detectors.DefaultFalsePositives, true) {
|
||||||
@@ -46,7 +47,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := detectors.Result{
|
s := detectors.Result{
|
||||||
DetectorType: detectorspb.DetectorType_SquareApp,
|
DetectorType: detectorspb.DetectorType_Square,
|
||||||
Raw: []byte(match),
|
Raw: []byte(match),
|
||||||
Redacted: match,
|
Redacted: match,
|
||||||
}
|
}
|
||||||
@@ -71,7 +72,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
// unclear if this version needs to be set or matters, seems to work without, but docs want it
|
// unclear if this version needs to be set or matters, seems to work without, but docs want it
|
||||||
// req.Header.Add("Square-Version", "2020-08-12")
|
//req.Header.Add("Square-Version", "2020-08-12")
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
res.Body.Close() // The request body is unused.
|
res.Body.Close() // The request body is unused.
|
||||||
@@ -94,5 +95,5 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
func (s Scanner) Type() detectorspb.DetectorType {
|
||||||
return detectorspb.DetectorType_SquareApp
|
return detectorspb.DetectorType_Square
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package supabasetoken
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct{}
|
|
||||||
|
|
||||||
// Ensure the Scanner satisfies the interface at compile time.
|
|
||||||
var _ detectors.Detector = (*Scanner)(nil)
|
|
||||||
|
|
||||||
var (
|
|
||||||
client = common.SaneHttpClient()
|
|
||||||
|
|
||||||
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
|
|
||||||
keyPat = regexp.MustCompile(`\b(sbp_[a-z0-9]{40})\b`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keywords are used for efficiently pre-filtering chunks.
|
|
||||||
// Use identifiers in the secret preferably, or the provider name.
|
|
||||||
func (s Scanner) Keywords() []string {
|
|
||||||
return []string{"sbp_"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromData will find and optionally verify Supabasetoken secrets in a given set of bytes.
|
|
||||||
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
||||||
dataStr := string(data)
|
|
||||||
|
|
||||||
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
if len(match) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMatch := strings.TrimSpace(match[1])
|
|
||||||
|
|
||||||
s1 := detectors.Result{
|
|
||||||
DetectorType: detectorspb.DetectorType_SupabaseToken,
|
|
||||||
Raw: []byte(resMatch),
|
|
||||||
}
|
|
||||||
|
|
||||||
if verify {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.supabase.com/v1/projects", nil)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err == nil {
|
|
||||||
defer res.Body.Close()
|
|
||||||
if res.StatusCode >= 200 && res.StatusCode < 300 {
|
|
||||||
s1.Verified = true
|
|
||||||
} else {
|
|
||||||
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
|
|
||||||
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, s1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Scanner) Type() detectorspb.DetectorType {
|
|
||||||
return detectorspb.DetectorType_SupabaseToken
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
//go:build detectors
|
|
||||||
// +build detectors
|
|
||||||
|
|
||||||
package supabasetoken
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
||||||
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
||||||
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSupabasetoken_FromChunk(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
|
||||||
defer cancel()
|
|
||||||
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("could not get test secrets from GCP: %s", err)
|
|
||||||
}
|
|
||||||
secret := testSecrets.MustGetField("SUPABASETOKEN")
|
|
||||||
inactiveSecret := testSecrets.MustGetField("SUPABASETOKEN_INACTIVE")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
ctx context.Context
|
|
||||||
data []byte
|
|
||||||
verify bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
s Scanner
|
|
||||||
args args
|
|
||||||
want []detectors.Result
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "found, verified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a supabasetoken secret %s within", secret)),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_SupabaseToken,
|
|
||||||
Verified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "found, unverified",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte(fmt.Sprintf("You can find a supabasetoken secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: []detectors.Result{
|
|
||||||
{
|
|
||||||
DetectorType: detectorspb.DetectorType_SupabaseToken,
|
|
||||||
Verified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not found",
|
|
||||||
s: Scanner{},
|
|
||||||
args: args{
|
|
||||||
ctx: context.Background(),
|
|
||||||
data: []byte("You cannot find the secret within"),
|
|
||||||
verify: true,
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := Scanner{}
|
|
||||||
got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Supabasetoken.FromData() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
if len(got[i].Raw) == 0 {
|
|
||||||
t.Fatalf("no raw secret present: \n %+v", got[i])
|
|
||||||
}
|
|
||||||
got[i].Raw = nil
|
|
||||||
}
|
|
||||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
|
||||||
t.Errorf("Supabasetoken.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFromData(benchmark *testing.B) {
|
|
||||||
ctx := context.Background()
|
|
||||||
s := Scanner{}
|
|
||||||
for name, data := range detectors.MustGetBenchmarkData() {
|
|
||||||
benchmark.Run(name, func(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
_, err := s.FromData(ctx, false, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user