diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..69d9543 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" + commit-message: + prefix: "chore" + include: "scope" + + # Maintain dependencies for go modules + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" + commit-message: + prefix: "chore" + include: "scope" + + # Maintain dependencies for docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" + commit-message: + prefix: "chore" + include: "scope" \ No newline at end of file diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000..3db5da8 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,27 @@ +name: 🔨 Build Test +on: + push: + pull_request: + workflow_dispatch: + + +jobs: + build: + name: Test Builds + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.15 + + - name: Check out code + uses: actions/checkout@v2 + + - name: Test + run: go test . + working-directory: cmd/notify/ + + - name: Build + run: go build . + working-directory: cmd/notify/ \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml deleted file mode 100644 index 2e7c3f4..0000000 --- a/.github/workflows/build.yaml +++ /dev/null @@ -1,48 +0,0 @@ -name: Build -on: - push: - branches: - - master - pull_request: - -jobs: - lint: - name: golangci-lint - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Run golangci-lint - uses: golangci/golangci-lint-action@v2.2.0 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.31 - args: --timeout 5m - - # Optional: working directory, useful for monorepos - # working-directory: somedir - - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true - build: - name: Build - runs-on: ubuntu-latest - steps: - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.14 - - - name: Check out code - uses: actions/checkout@v2 - - - name: Test - run: go test . - working-directory: cmd/notify/ - - - name: Build - run: go build . - working-directory: cmd/notify/ diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..545cdea --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,38 @@ +name: 🚨 CodeQL Analysis + +on: + workflow_dispatch: + pull_request: + branches: + - dev + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 \ No newline at end of file diff --git a/.github/workflows/dockerhub-push.yml b/.github/workflows/dockerhub-push.yml index 4f7b62a..b0d4933 100644 --- a/.github/workflows/dockerhub-push.yml +++ b/.github/workflows/dockerhub-push.yml @@ -1,17 +1,34 @@ -# dockerhub-push pushes docker build to dockerhub automatically -# on the creation of a new release -name: Publish to Dockerhub on creation of a new release -on: +name: 🌥 Docker Push + +on: release: types: [published] + workflow_dispatch: + jobs: - build: + docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - - name: Publish to Dockerhub Registry - uses: elgohr/Publish-Docker-Github-Action@master - with: - name: projectdiscovery/notify - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} \ No newline at end of file + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm64,linux/arm + push: true + tags: projectdiscovery/notify:latest \ No newline at end of file diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml new file mode 100644 index 0000000..794d073 --- /dev/null +++ b/.github/workflows/lint-test.yml @@ -0,0 +1,19 @@ +name: 🙏🏻 Lint Test +on: + push: + pull_request: + workflow_dispatch: + +jobs: + lint: + name: Lint Test + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: latest + args: --timeout 5m + working-directory: . \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release-binary.yml similarity index 80% rename from .github/workflows/release.yml rename to .github/workflows/release-binary.yml index 70cb60a..6fe8c82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release-binary.yml @@ -1,8 +1,9 @@ -name: Release +name: 🎉 Release Binary on: create: tags: - v* + workflow_dispatch: jobs: release: @@ -17,7 +18,7 @@ jobs: name: "Set up Go" uses: actions/setup-go@v2 with: - go-version: 1.14 + go-version: 1.16 - env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" @@ -25,4 +26,5 @@ jobs: uses: goreleaser/goreleaser-action@v2 with: args: "release --rm-dist" - version: latest \ No newline at end of file + version: latest + workdir: . \ No newline at end of file diff --git a/.gitignore b/.gitignore index bef0f48..b762b24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ cmd/notify/notify -cmd/intercept/intercept .DS_Store dist \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index d5e9089..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,122 +0,0 @@ -linters-settings: - dupl: - threshold: 100 - exhaustive: - default-signifies-exhaustive: false - # funlen: - # lines: 100 - # statements: 50 - goconst: - min-len: 2 - min-occurrences: 2 - gocritic: - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style - disabled-checks: - - dupImport # https://github.com/go-critic/go-critic/issues/845 - - ifElseChain - # gocyclo: - # min-complexity: 15 - goimports: - local-prefixes: github.com/golangci/golangci-lint - golint: - min-confidence: 0 - gomnd: - settings: - mnd: - # don't include the "operation" and "assign" - checks: argument,case,condition,return - govet: - check-shadowing: true - settings: - printf: - funcs: - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - # lll: - # line-length: 140 - maligned: - suggest-new: true - misspell: - locale: US - nolintlint: - allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) - allow-unused: false # report any unused nolint directives - require-explanation: false # don't require an explanation for nolint directives - require-specific: false # don't require nolint directives to be specific about which linter is being skipped - -linters: - # please, do not use `enable-all`: it's deprecated and will be removed soon. - # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint - disable-all: true - enable: - - bodyclose - - deadcode - - dogsled - - dupl - - errcheck - - exhaustive - - gochecknoinits - - goconst - - gocritic - - gofmt - - goimports - - golint - - gomnd - - goprintffuncname - - gosimple - - govet - - ineffassign - - interfacer - - maligned - - misspell - - nakedret - - noctx - - nolintlint - - rowserrcheck - - scopelint - - staticcheck - - structcheck - - stylecheck - - typecheck - - unconvert - - unparam - - unused - - varcheck - - whitespace - - # don't enable: - # - depguard - # - asciicheck - # - funlen - # - gochecknoglobals - # - gocognit - # - gocyclo - # - godot - # - godox - # - goerr113 - # - gosec - # - lll - # - nestif - # - prealloc - # - testpackage - # - wsl - -issues: - exclude-use-default: false - exclude: - # should have a package comment, unless it's in another file for this package (golint) - - 'in another file for this package' - -# golangci.com configuration -# https://github.com/golangci/golangci/wiki/Configuration -service: - golangci-lint-version: 1.31.x # use the fixed version to not introduce new linters unexpectedly - prepare: - - echo "here I can run custom commands, but no preparation needed for this repo" diff --git a/.goreleaser.yml b/.goreleaser.yml index 5b8fad0..5db099b 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,21 +1,33 @@ +before: + hooks: + - go mod tidy + builds: - - binary: notify - main: cmd/notify/notify.go - goos: - - linux - - windows - - darwin - goarch: - - amd64 - - 386 - - arm - - arm64 - +- env: + - CGO_ENABLED=0 + goos: + - windows + - linux + - darwin + goarch: + - amd64 + - 386 + - arm + - arm64 + + ignore: + - goos: darwin + goarch: '386' + - goos: windows + goarch: 'arm' + + binary: '{{ .ProjectName }}' + main: cmd/notify/notify.go + archives: - - id: tgz - format: tar.gz - replacements: - darwin: macOS - format_overrides: - - goos: windows - format: zip \ No newline at end of file +- format: zip + replacements: + darwin: macOS + +checksum: + algorithm: sha256 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index edfe285..17a3756 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,7 @@ -FROM golang:1.14-alpine AS builder -RUN apk add --no-cache git -RUN GO111MODULE=auto go get -u -v github.com/projectdiscovery/notify/cmd/notify +FROM golang:1.16.0-alpine as build-env +RUN GO111MODULE=on go get -v github.com/projectdiscovery/notify/cmd/notify FROM alpine:latest -COPY --from=builder /go/bin/notify /usr/local/bin/ +COPY --from=build-env /go/bin/notify /usr/local/bin/notify ENTRYPOINT ["notify"] diff --git a/README.md b/README.md index e39e871..a4bfa3c 100644 --- a/README.md +++ b/README.md @@ -1,250 +1,219 @@ -

- notify +

+ notify

-[![License](https://img.shields.io/badge/license-MIT-_red.svg)](https://opensource.org/licenses/MIT) -[![Go Report Card](https://goreportcard.com/badge/github.com/projectdiscovery/notify)](https://goreportcard.com/report/github.com/projectdiscovery/notify) -[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/projectdiscovery/notify/issues) -[![GitHub Release](https://img.shields.io/github/release/projectdiscovery/notify)](https://github.com/projectdiscovery/notify/releases) -[![Follow on Twitter](https://img.shields.io/twitter/follow/pdiscoveryio.svg?logo=twitter)](https://twitter.com/pdiscoveryio) -[![Chat on Discord](https://img.shields.io/discord/695645237418131507.svg?logo=discord)](https://discord.gg/KECAGdH) - -Notify is an helper utility written in Go that allows you to pull results from burp collaborator instances and post to CLI, also sends the notification via webhooks to Slack and Discord. - -# Resources -- [Resources](#resources) -- [Features](#features) -- [Usage](#usage) -- [Installation Instructions](#installation-instructions) - - [From Binary](#from-binary) - - [From Source](#from-source) - - [From Github](#from-github) -- [Intercept BIID](#intercept-biid) -- [Config File](#config-file) -- [Running notify](#running-notify) - - [CLI](#cli) - - [Slack notification](#slack-notification) - - [Discord notification](#discord-notification) - - [General purpose use](#using-notify-with-other-tools) +

+ + + + + + + +

+ +

+ Features • + Installation • + Providers • + Usage • + Running Notify • + Notes • + Join Discord +

-# Features + +Notify is a Go-based assistance package that enables you to stream the output of several tools (or read from a file) and publish it to a variety of supported platforms.

- notify + notify-httpx

-- 💥 Automatic Burp Collaborator BIID interception. -- 💥 Burp Collaborator Slack / Discord notification support. -- 💥 Redirect output of any tool to Slack / Discord / Telegram. +# Features + +- Supports for Slack / Discord / Telegram +- Supports for Pushover / Email / Teams +- Supports for File / Pipe output +- Supports Line by Line / Bulk Post +- Supports using Single / Multiple providers +- Supports Custom Web-hooks +- Supports Custom data formatting + # Usage ```sh -▶ notify -h +notify -h ``` This will display help for the tool. Here are all the switches it supports. -| Flag | Description | Example | -|------|-------------|---------| -| -biid | burp private key | notify -biid 123456789 | -| -slack-webhook-url | Slack Webhook URL | notify -slack-webhook-url hxxp://a.b.c | -| -slack-username | Slack Username | notify -slack-username test | -| -slack-channel | Slack Channel | notify -slack-channel test | -| -slack | Enable Slack | notify -slack | -| -discord-webhook-url | Discord Webhook URL | notify -discord-webhook-url hxxp://a.b.c | -| -discord-username | Discord Username | notify -discord-username test | -| -discord-avatar | Discord Avatar Url | notify -discord-avatar hxxp://a.b.c | -| -discord | Enable Discord | notify -discord | -| -silent | Silent mode | notify -silent | -| -version | Show version of notify | notify -version | -| -interval | Polling interval in seconds | notify -interval 5 | -| -intercept-biid | Attempt to intercept biid (needs sudo) | notify -intercept-biid | -| -intercept-biid-timeout | Timeout for biid interception in seconds | notify -intercept-biid-timeout 120 | -| -http-message | HTTP Message | notify -http-message test | -| -dns-message | DNS Message | notify -dns-message test | - -# Installation Instructions - -### From Binary - -The installation is easy. You can download the pre-built binaries for your platform from the [releases](https://github.com/projectdiscovery/notify/releases/) page. Extract them using tar, move it to your `$PATH`and you're ready to go. +| Flag | Description | Example | +| ---------------- | ----------------------------------------------- | --------------------------------- | +| -config | Notify configuration file | notify -config config.yaml | +| -silent | Don't print the banner | notify -silent | +| -version | Show version of notify | notify -version | +| -v | Show Verbose output | notify -v | +| -no-color | Don't Use colors in output | notify -no-color | +| -data | File path to read data from | notify -data test.txt | +| -bulk | Read and send data in bulk from file. | notify -bulk | +| -char-limit | Character limit for message (default 4000) | notify -char-limit 2000 | +| -provider-config | provider config path | notify -provider-config conf.yaml | +| -provider | provider to send the notification to (optional) | notify -provider slack,telegram | +| -id | id to send the notification to (optional) | notify -id recon,scans | -```sh -Download latest binary from https://github.com/projectdiscovery/notify/releases - -▶ tar -xvf notify-linux-amd64.tar -▶ mv notify-linux-amd64 /usr/local/bin/notify -▶ notify -version -``` -### From Source - -Notify requires **go1.14+** to install successfully. Run the following command to get the repo - - -Installing Notify - +# Notify Installation ```sh -▶ GO111MODULE=on go get -v github.com/projectdiscovery/notify/cmd/notify +GO111MODULE=on go get -v github.com/projectdiscovery/notify/cmd/notify ``` -Installing Intercept - +### Provider Config -```sh -▶ GO111MODULE=on go get -v github.com/projectdiscovery/notify/cmd/intercept -``` +The default provider config file can be created at `$HOME/.config/notify/provider-config.yaml` and can have the following contents: -### From Github +```yaml +slack: + - id: "slack" + slack_channel: "recon" + slack_username: "test" + slack_format: "{{data}}" + slack_webhook_url: "https://hooks.slack.com/services/XXXXXX" + + - id: "vulns" + slack_channel: "vulns" + slack_username: "test" + slack_format: "{{data}}" + slack_webhook_url: "https://hooks.slack.com/services/XXXXXX" + +discord: + - id: "crawl" + discord_channel: "crawl" + discord_username: "test" + discord_format: "{{data}}" + discord_webhook_url: "https://discord.com/api/webhooks/XXXXXXXX" + + - id: "subs" + discord_channel: "subs" + discord_username: "test" + discord_format: "{{data}}" + discord_webhook_url: "https://discord.com/api/webhooks/XXXXXXXX" + +telegram: + - id: "tel" + telegram_api_key: "XXXXXXXXXXXX" + telegram_chat_id: "XXXXXXXX" + telegram_format: "{{data}}" + +pushover: + - id: "push" + pushover_user_key: "XXXX" + pushover_api_token: "YYYY" + pushover_format: "{{data}}" + pushover_devices: + - "iphone" + +smtp: + - id: email + smtp_server: mail.example.com + smtp_username: test@example.com + smtp_password: password + from_address: from@email.com + smtp_cc: + - to@email.com + smtp_format: "{{data}}" + +custom: + - id: webhook + custom_webook_url: http://host/api/webhook + custom_method: GET + custom_format: '{{data}}' + custom_headers: + Content-Type: application/json + X-Api-Key: XXXXX +``` -Installing Notify - +# Running Notify -```sh -▶ git clone https://github.com/projectdiscovery/notify.git; cd notify/cmd/notify; go build; mv notify /usr/local/bin/; notify -version -``` +Notify supports piping output of any tool or output file and send it to configured provider/s (e.g, discord, slack channel) as notification. -Installing Intercept - +### Send notification using piped(stdin) output ```sh -▶ git clone https://github.com/projectdiscovery/notify.git; cd notify/cmd/intercept; go build; mv intercept /usr/local/bin/; +subfinder -d hackerone.com | notify ``` -# Intercept BIID - -- Run intercept as root `sudo intercept` -- Open Burp Suite => Project Options => Misc -- Tick `Poll over unencrypted HTTP` (in v2020.12.1) -- Generate **new** collaborator, click on **Poll now**. -- Intercept will capture `biid` that can be used with `notify` - -```sh -sudo ./intercept -Attempting to intercept BIID -BIID found: o%2JREfoFxWfdk4i1VOvPQiX96MfpZ7qlZ6kXiGeHbjvJ%3d -``` +

+notify-subfinder -# Running notify -## CLI +### Send notification using output file -You can use **notify** to receive burp collaborator interaction on your CLI, following command accepts `biid` as input and post all incoming interaction over CLI. ```sh -notify -biid 132456789 +subfinder -d hackerone.com -o h1.txt; notify -data h1.txt ``` -## Slack notification +### Send notification using output file in bulk mode -The tool accept parameters from a config file located at `$HOME/.config/notify/notify.conf` or either via CLI. - -To run the tool just use the following command. ```sh -▶ notify -biid 132456789 -slack -slack-webhook-url https://a.b.c -slack-username test -slack-channel test-channel +subfinder -d hackerone.com -o h1.txt; notify -data h1.txt -bulk ``` -If you already configured the config file, you can simply run following command and `notify` will start receiving burp collaborator interaction on CLI and sends notification to slack / discord. +### Send notification using output file to specific provider's -```sh -▶ notify -``` - -## Discord notification - -Similarly to slack, in order to use discord ```sh -▶ notify -biid 132456789 -discord -discord-webhook-url https://a.b.c -discord-username notify-bot +subfinder -d hackerone.com -o h1.txt; notify -data h1.txt -bulk -provider discord,slack ``` -## Telegram notification +### Send notification using output file to specific ID's -Similarly to slack, in order to use discord ```sh -▶ notify -biid 132456789 -telegram -telegram-api-key 119489xxxx-:AAF4OV9 -telegram-chat-id 1231434 +subfinder -d hackerone.com -o h1.txt; notify -data h1.txt -bulk -id recon,vulns,scan ``` -## Using notify with other tools +### Example Uses -Notify also supports piping output of any tool and send it over discord/slack channel as notification. +Following command will enumerate subdomains using [SubFinder](https://github.com/projectdiscovery/subfinder) and probe alive URLs using [httpx](https://github.com/projectdiscovery/httpx), runs [Nuclei](https://github.com/projectdiscovery/nuclei) templates and send the nuclei results as a notifications to configured provider/s. -Following command will enumerate subdomains using [SubFinder](https://github.com/projectdiscovery/subfinder) and probe for alive URLs and sends the notifications of alive URLs using [httpx](https://github.com/projectdiscovery/httpx) to configured discord / slack channel. -``` -subfinder -d hackerone.com | httpx | notify +```sh +subfinder -d intigriti.com | httpx | nuclei -tags exposure -o output.txt; notify -bulk -data output.txt ``` -

- notify-httpx -
-

-Following command will enumerate subdomains using [SubFinder](https://github.com/projectdiscovery/subfinder) and probe alive URLs using [httpx](https://github.com/projectdiscovery/httpx), runs [Nuclei](https://github.com/projectdiscovery/nuclei) templates and send the nuclei results as a notifications to configured discord / slack channel. +### Provider Config -``` -subfinder -d intigriti.com | httpx | nuclei -t files | notify -``` - -In similar manner, output (stdout) of any tool can be piped to **notify** for posting data into slack/discord. +The tool tries to use the default provider config (`$HOME/.config/notify/provider-config.yaml`), it can also be specified via CLI by using **provider-config** flag. -# Config File -The default config file should be located in `$HOME/.config/notify/notify.conf` and has the following contents: +To run the tool with custom providers config, just use the following command. -```yaml -burp_biid: 132465789 -# Slack -slack: true -slack_webhook_url: https://a.b.c -slack_username: test -slack_channel: test - -# Discord -discord: true -discord_webhook_url: https://a.b.c -discord_username: test -discord_avatar: https://a.b.c/avatar - -# Telegram -telegram: true -telegram_apikey: 119489xxxx-:AAF4OV9cdCEzq3tQ3aMtVyzHaRV3a1M7Ow4 -telegram_chat_id: 36808xxxx - -# General Settings -interval: 2 # seconds - -http_message: | - The collaborator server received an {{protocol}} request from {{from}} at {{time}}: - - ```http - {{request}} - - {{response}} - ``` - -dns_message: | - The collaborator server received a DNS lookup of type {{type}} for the domain name {{domain}} from {{from}} at {{time}}: - - ``` - {{request}} - ``` -``` +```sh +notify -provider-config providers.yaml +``` +### Notify Config -📋 Notes +Notify flags can be configured at default config (`$HOME/.config/notify/config.yaml`) or custom config can be also provided using `config` flag. -- You can obtain the **biid** with wireshark on any platform and configure it within the config file. -- Burp collaborator server allow to fetch results only for once, so if you are using this, you will **not** see results in burp collaborator window. -- Config file has priority over CLI arguments. -- Telegram notification does not support burp collaborator. +## Notes +- As default notify sends notification line by line +- **bulk** flag is supported with data flag. +- stdin/pipe input doesn't support **bulk** posting. -## References:- +## References - [Creating Slack webhook](https://slack.com/intl/en-it/help/articles/115005265063-Incoming-webhooks-for-Slack) - [Creating Discord webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) - [Creating Telegram bot](https://core.telegram.org/bots#3-how-do-i-create-a-bot) +- [Creating Pushover Token](https://github.com/containrrr/shoutrrr/blob/main/docs/services/pushover.md) -Notify is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team. +Notify is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team. \ No newline at end of file diff --git a/cmd/intercept/go.mod b/cmd/intercept/go.mod deleted file mode 100644 index 977a5fa..0000000 --- a/cmd/intercept/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/projectdiscovery/notify/cmd/intercept - -go 1.14 - -require ( - github.com/projectdiscovery/collaborator v0.0.0-20201107213304-6ecca25af99b - github.com/projectdiscovery/gologger v1.0.1 -) diff --git a/cmd/intercept/go.sum b/cmd/intercept/go.sum deleted file mode 100644 index e317038..0000000 --- a/cmd/intercept/go.sum +++ /dev/null @@ -1,42 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= -github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/miekg/dns v1.1.34 h1:SgTzfkN+oLoIHF1bgUP+C71mzuDl3AhLApHzCCIAMWM= -github.com/miekg/dns v1.1.34/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/projectdiscovery/collaborator v0.0.0-20201106184455-1739c0140e53 h1:jJGYzegxz43KMq4iXY4zfPSflmF+LFyxM2/bYja39kQ= -github.com/projectdiscovery/collaborator v0.0.0-20201106184455-1739c0140e53/go.mod h1:pT+nfywyhy3cJacTU6PLUbE/uHqabzoN4xp4DcF9qoY= -github.com/projectdiscovery/collaborator v0.0.0-20201106184551-efd6773a9479 h1:2K1Vg9jh6bX5fBz05y45VGE2K3TgPXOkGu/EevCbrBs= -github.com/projectdiscovery/collaborator v0.0.0-20201106184551-efd6773a9479/go.mod h1:pT+nfywyhy3cJacTU6PLUbE/uHqabzoN4xp4DcF9qoY= -github.com/projectdiscovery/collaborator v0.0.0-20201107213304-6ecca25af99b h1:hFAaqKrJC1VpmKU2GEoLz9udekOm1so+/Bw/sCOUkzM= -github.com/projectdiscovery/collaborator v0.0.0-20201107213304-6ecca25af99b/go.mod h1:pT+nfywyhy3cJacTU6PLUbE/uHqabzoN4xp4DcF9qoY= -github.com/projectdiscovery/gologger v1.0.1 h1:FzoYQZnxz9DCvSi/eg5A6+ET4CQ0CDUs27l6Exr8zMQ= -github.com/projectdiscovery/gologger v1.0.1/go.mod h1:Ok+axMqK53bWNwDSU1nTNwITLYMXMdZtRc8/y1c7sWE= -github.com/projectdiscovery/retryablehttp-go v1.0.1 h1:V7wUvsZNq1Rcz7+IlcyoyQlNwshuwptuBVYWw9lx8RE= -github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1D+SBxoqfAF4nyzvmevkTkWsek= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/cmd/intercept/intercept.go b/cmd/intercept/intercept.go deleted file mode 100644 index 7b2566a..0000000 --- a/cmd/intercept/intercept.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "os/signal" - "syscall" - "time" - - "github.com/projectdiscovery/collaborator/biid" - "github.com/projectdiscovery/gologger" -) - -// Options to handle intercept -type Options struct { - InterceptBIIDTimeout int -} - -func main() { - var options Options - flag.IntVar(&options.InterceptBIIDTimeout, "intercept-biid-timeout", 600, "Automatic BIID intercept Timeout") - - // Setup close handler - go func() { - c := make(chan os.Signal) - signal.Notify(c, os.Interrupt, syscall.SIGTERM) - go func() { - <-c - fmt.Println("\r- Ctrl+C pressed in Terminal") - os.Exit(0) - }() - }() - - if os.Getuid() != 0 { - gologger.Fatalf("The program is not running as root and unable to access raw sockets") - } - gologger.Printf("Attempting to intercept BIID") - // otherwise attempt to retrieve it - interceptedBiid, err := biid.Intercept(time.Duration(options.InterceptBIIDTimeout) * time.Second) - if err != nil { - gologger.Fatalf("%s", err) - } - if interceptedBiid == "" { - gologger.Fatalf("BIID not found") - } - gologger.Printf("BIID found: %s", interceptedBiid) -} diff --git a/cmd/notify/notify.go b/cmd/notify/notify.go index 73ea88a..106c509 100644 --- a/cmd/notify/notify.go +++ b/cmd/notify/notify.go @@ -6,21 +6,30 @@ import ( "os/signal" "syscall" + "github.com/projectdiscovery/goflags" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/notify/internal/runner" + "github.com/projectdiscovery/notify/pkg/types" +) + +var ( + cfgFile string + options = &types.Options{} ) func main() { - options := runner.ParseConfigFileOrOptions() + readConfig() + + runner.ParseOptions(options) notifyRunner, err := runner.NewRunner(options) if err != nil { - gologger.Fatalf("Could not create runner: %s\n", err) + gologger.Fatal().Msgf("Could not create runner: %s\n", err) } // Setup close handler go func() { - c := make(chan os.Signal) + c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c @@ -32,6 +41,33 @@ func main() { err = notifyRunner.Run() if err != nil { - gologger.Fatalf("Could not run notifier: %s\n", err) + gologger.Fatal().Msgf("Could not run notifier: %s\n", err) + } +} + +func readConfig() { + set := goflags.NewFlagSet() + set.Marshal = true + set.SetDescription(`Notify is a general notification tool`) + set.StringVar(&cfgFile, "config", "", "Notify configuration file") + set.BoolVar(&options.Silent, "silent", false, "Don't print the banner") + set.BoolVar(&options.Version, "version", false, "Show version of notify") + set.BoolVar(&options.Verbose, "v", false, "Show Verbose output") + set.BoolVar(&options.NoColor, "no-color", false, "Don't Use colors in output") + set.StringVar(&options.Data, "data", "", "File path to read data from") + set.BoolVar(&options.Bulk, "bulk", false, "Read the input and send it in bulk, character limit can be set using char-limit flag") + set.IntVar(&options.CharLimit, "char-limit", 4000, "Character limit for message") + set.StringVar(&options.ProviderConfig, "provider-config", "", "provider config path (default: $HOME/.config/notify/provider-config.yaml)") + set.NormalizedStringSliceVar(&options.Providers, "provider", []string{}, "provider to send the notification to (optional)") + set.NormalizedStringSliceVar(&options.IDs, "id", []string{}, "id to send the notification to (optional)") + set.StringVar(&options.MessageFormat, "msg-format", "{{data}}", "apply custom formatting to the text") + set.StringVar(&options.Proxy, "proxy", "", "Set http proxy to be used by notify") + + _ = set.Parse() + + if cfgFile != "" { + if err := set.MergeConfigFile(cfgFile); err != nil { + gologger.Fatal().Msgf("Could not read config: %s\n", err) + } } } diff --git a/const.go b/const.go deleted file mode 100644 index 436ce2b..0000000 --- a/const.go +++ /dev/null @@ -1,5 +0,0 @@ -package notify - -const ( - ok = "ok" -) diff --git a/discord.go b/discord.go deleted file mode 100644 index a17ae4d..0000000 --- a/discord.go +++ /dev/null @@ -1,76 +0,0 @@ -package notify - -// From https://dev.to/arunx2/simple-slack-notification-with-golang-55i2 - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "net/http" - "time" - - "github.com/projectdiscovery/retryablehttp-go" -) - -// DefaultDiscordTimeout to conclude operations -const DefaultDiscordTimeout = 5 * time.Second - -// DiscordClient handling webhooks -type DiscordClient struct { - client *retryablehttp.Client - WebHookURL string - UserName string - Avatar string - TimeOut time.Duration -} - -// DiscordMessage json structure -type DiscordMessage struct { - Username string `json:"username,omitempty"` - AvatarURL string `json:"avatar_url,omitempty"` - Content string `json:"content,omitempty"` -} - -// SendInfo to discord -func (dc *DiscordClient) SendInfo(message string) (err error) { - return dc.SendDiscordNotification(&DiscordMessage{ - Content: message, - Username: dc.UserName, - AvatarURL: dc.Avatar, - }) -} - -// SendDiscordNotification with json structure -func (dc *DiscordClient) SendDiscordNotification(discordMessage *DiscordMessage) error { - return dc.sendHTTPRequest(discordMessage) -} - -func (dc *DiscordClient) sendHTTPRequest(discordMessage *DiscordMessage) error { - discordBody, err := json.Marshal(discordMessage) - if err != nil { - return err - } - - req, err := retryablehttp.NewRequest(http.MethodPost, dc.WebHookURL, bytes.NewBuffer(discordBody)) - if err != nil { - return err - } - req.Header.Add("Content-Type", "application/json") - resp, err := dc.client.Do(req) - if err != nil { - return err - } - - buf, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - //nolint:errcheck // silent fail - defer resp.Body.Close() - - if string(buf) != ok { - return err - } - - return nil -} diff --git a/doc.go b/doc.go deleted file mode 100644 index 78ba0ac..0000000 --- a/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package notify notifies out of band interactions via webhook -package notify diff --git a/go.mod b/go.mod index f6b1562..1170b8b 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,27 @@ module github.com/projectdiscovery/notify -go 1.14 +go 1.15 require ( - github.com/Shopify/yaml v2.1.0+incompatible github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d - github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/projectdiscovery/collaborator v0.0.1 - github.com/projectdiscovery/gologger v1.0.1 + github.com/containrrr/shoutrrr v0.4.5-0.20210707101419-8018a476b557 + github.com/fatih/color v1.12.0 // indirect + github.com/golang/protobuf v1.4.3 // indirect + github.com/google/go-cmp v0.5.4 // indirect + github.com/google/uuid v1.2.0 // indirect + github.com/json-iterator/go v1.1.11 + github.com/klauspost/compress v1.13.1 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/gomega v1.10.5 // indirect + github.com/pkg/errors v0.9.1 + github.com/projectdiscovery/goflags v0.0.7 + github.com/projectdiscovery/gologger v1.1.4 github.com/projectdiscovery/retryablehttp-go v1.0.1 - golang.org/x/crypto v0.0.0-20201116153603-4be66e5b6582 // indirect - golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect - golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48 // indirect + go.uber.org/multierr v1.1.0 + golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect + google.golang.org/protobuf v1.25.0 // indirect + gopkg.in/yaml.v2 v2.4.0 + nhooyr.io/websocket v1.8.7 // indirect ) diff --git a/go.sum b/go.sum index 9460a9a..4f61cc1 100644 --- a/go.sum +++ b/go.sum @@ -1,55 +1,409 @@ -github.com/Shopify/yaml v2.1.0+incompatible h1:Y7Wj6eQo5Byeaxb2M9FiPdKBQ3ooLsRIEmUZMMxCI8g= -github.com/Shopify/yaml v2.1.0+incompatible/go.mod h1:Mrsv1G5Osez+VdHYcSI2zfaUzPu4lCdO9cW8R2lHPEc= +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= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chromedp/cdproto v0.0.0-20190614062957-d6d2f92b486d/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw= +github.com/chromedp/cdproto v0.0.0-20190621002710-8cbd498dd7a0/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw= +github.com/chromedp/cdproto v0.0.0-20190812224334-39ef923dcb8d/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0= +github.com/chromedp/cdproto v0.0.0-20190926234355-1b4886c6fad6/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0= +github.com/chromedp/chromedp v0.3.1-0.20190619195644-fd957a4d2901/go.mod h1:mJdvfrVn594N9tfiPecUidF6W5jPRKHymqHfzbobPsM= +github.com/chromedp/chromedp v0.4.0/go.mod h1:DC3QUn4mJ24dwjcaGQLoZrhm4X/uPHZ6spDbS2uFhm4= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= +github.com/containrrr/shoutrrr v0.4.5-0.20210707101419-8018a476b557 h1:TvIiq3pBYX9D25mu1jZvCezS2FjoVvCS320pWytJkXI= +github.com/containrrr/shoutrrr v0.4.5-0.20210707101419-8018a476b557/go.mod h1:zqL2BvfC1W4FujrT4b3/ZCLxvD+uoeEpBL7rg9Dqpbg= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +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/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-interpreter/wagon v0.5.1-0.20190713202023-55a163980b6c/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= +github.com/go-interpreter/wagon v0.6.0/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +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.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.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +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.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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.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.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190908185732-236ed259b199/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= +github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ= +github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.6/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/projectdiscovery/collaborator v0.0.1 h1:dbQ5BCL/a3c+BB9cGtrGgiLs23+EfSzoaTzX/pxqiTI= -github.com/projectdiscovery/collaborator v0.0.1/go.mod h1:J1z0fC7Svutz3LJqoRyTHA3F0Suh4livmkYv8MnKw20= -github.com/projectdiscovery/gologger v1.0.1 h1:FzoYQZnxz9DCvSi/eg5A6+ET4CQ0CDUs27l6Exr8zMQ= -github.com/projectdiscovery/gologger v1.0.1/go.mod h1:Ok+axMqK53bWNwDSU1nTNwITLYMXMdZtRc8/y1c7sWE= +github.com/projectdiscovery/goflags v0.0.7 h1:aykmRkrOgDyRwcvGrK3qp+9aqcjGfAMs/+LtRmtyxwk= +github.com/projectdiscovery/goflags v0.0.7/go.mod h1:Jjwsf4eEBPXDSQI2Y+6fd3dBumJv/J1U0nmpM+hy2YY= +github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI= +github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY= github.com/projectdiscovery/retryablehttp-go v1.0.1 h1:V7wUvsZNq1Rcz7+IlcyoyQlNwshuwptuBVYWw9lx8RE= github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1D+SBxoqfAF4nyzvmevkTkWsek= +github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe h1:tQTgf5XLBgZbkJDPtnV3SfdP9tzz5ZWeDBwv8WhnH9Q= +github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/twitchyliquid64/golang-asm v0.0.0-20190126203739-365674df15fc/go.mod h1:NoCfSFWosfqMqmmD7hApkirIK9ozpHjxRnRxs1l413A= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16/go.mod h1:iKV5yK9t+J5nG9O3uF6KYdPEz3dyfMyB15MN1rbQ8Qw= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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-20201116153603-4be66e5b6582 h1:0WDrJ1E7UolDk1KhTXxxw3Fc8qtk5x7dHP431KHEJls= -golang.org/x/crypto v0.0.0-20201116153603-4be66e5b6582/go.mod h1:tCqSYrHVcf3i63Co2FzBkTCo2gdF6Zak62921dSfraU= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-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-20190522155817-f3200d17e092/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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20181221193216-37e7f081c4d4/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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190306220234-b354f8bf4d9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48 h1:AYCWBZhgIw6XobZ5CibNJr0Rc4ZofGGKvWa1vcx2IGk= -golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201113234701-d7a72108b828/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +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= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +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-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/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.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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gosrc.io/xmpp v0.5.1 h1:Rgrm5s2rt+npGggJH3HakQxQXR8ZZz3+QRzakRQqaq4= +gosrc.io/xmpp v0.5.1/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY= +gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +mvdan.cc/sh v2.6.4+incompatible/go.mod h1:IeeQbZq+x2SUGBensq/jge5lLQbS3XT2ktyp3wrt4x8= +nhooyr.io/websocket v1.6.5/go.mod h1:F259lAzPRAH0htX2y3ehpJe09ih1aSHN7udWki1defY= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/internal/runner/banner.go b/internal/runner/banner.go index b6c764a..4c4beb8 100644 --- a/internal/runner/banner.go +++ b/internal/runner/banner.go @@ -8,18 +8,18 @@ const banner = ` __ _ ___ ___ ___ / /_(_) _/_ __ / _ \/ _ \/ __/ / _/ // / -/_//_/\___/\__/_/_/ \_, / 0.0.2 +/_//_/\___/\__/_/_/ \_, / v1.0.0 /___/ ` // Version is the current version -const Version = `0.0.2` +const Version = `1.0.0` // showBanner is used to show the banner to the user func showBanner() { - gologger.Printf("%s\n", banner) - gologger.Printf("\t\tprojectdiscovery.io\n\n") + gologger.Print().Msgf("%s\n", banner) + gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") - gologger.Labelf("Use with caution. You are responsible for your actions\n") - gologger.Labelf("Developers assume no liability and are not responsible for any misuse or damage.\n") + gologger.Print().Msgf("Use with caution. You are responsible for your actions\n") + gologger.Print().Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n") } diff --git a/internal/runner/config.go b/internal/runner/config.go deleted file mode 100644 index dbf10c5..0000000 --- a/internal/runner/config.go +++ /dev/null @@ -1,105 +0,0 @@ -package runner - -import ( - "os" - "path" - - "github.com/Shopify/yaml" -) - -// ConfigDefaultFilename containing configuration -const ConfigDefaultFilename = "notify.conf" - -// ConfigFile structure -//nolint:maligned // used once -type ConfigFile struct { - BIID string `yaml:"burp_biid,omitempty"` - // Slack - SlackWebHookURL string `yaml:"slack_webhook_url,omitempty"` - SlackUsername string `yaml:"slack_username,omitempty"` - SlackChannel string `yaml:"slack_channel,omitempty"` - Slack bool `yaml:"slack,omitempty"` - - // Discord - DiscordWebHookURL string `yaml:"discord_webhook_url,omitempty"` - DiscordWebHookUsername string `yaml:"discord_username,omitempty"` - DiscordWebHookAvatarURL string `yaml:"discord_avatar,omitempty"` - Discord bool `yaml:"discord,omitempty"` - - // Telegram - TelegramAPIKey string `yaml:"telegram_apikey,omitempty"` - TelegramChatID string `yaml:"telegram_chat_id,omitempty"` - Telegram bool `yaml:"telegram,omitempty"` - - Interval int `yaml:"interval,omitempty"` - HTTPMessage string `yaml:"http_message,omitempty"` - DNSMessage string `yaml:"dns_message,omitempty"` - CLIMessage string `yaml:"cli_message,omitempty"` -} - -// GetConfigDirectory from the system -func GetConfigDirectory() (string, error) { - var config string - - directory, err := os.UserHomeDir() - if err != nil { - return config, err - } - config = directory + "/.config/notify" - - // Create All directory for notify even if they exist - err = os.MkdirAll(config, os.ModePerm) - if err != nil { - return config, err - } - - return config, nil -} - -// CheckConfigExists in the specified path -func CheckConfigExists(configPath string) bool { - if _, err := os.Stat(configPath); err == nil { - return true - } else if os.IsNotExist(err) { - return false - } - return false -} - -// MarshalWrite to location -func (c *ConfigFile) MarshalWrite(file string) error { - f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE, 0755) - if err != nil { - return err - } - - // Indent the spaces too - enc := yaml.NewEncoder(f) - err = enc.Encode(&c) - - //nolint:errcheck // silent fail - f.Close() - return err -} - -// UnmarshalRead the config file from location -func UnmarshalRead(file string) (ConfigFile, error) { - config := ConfigFile{} - - f, err := os.Open(file) - if err != nil { - return config, err - } - err = yaml.NewDecoder(f).Decode(&config) - //nolint:errcheck // silent fail - f.Close() - return config, err -} - -func getDefaultConfigFile() (string, error) { - directory, err := GetConfigDirectory() - if err != nil { - return "", err - } - return path.Join(directory, ConfigDefaultFilename), nil -} diff --git a/internal/runner/options.go b/internal/runner/options.go index 74abbe3..df83300 100644 --- a/internal/runner/options.go +++ b/internal/runner/options.go @@ -1,240 +1,70 @@ package runner import ( - "bufio" - "flag" - "io/ioutil" - "log" + "errors" "os" "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/gologger/formatter" + "github.com/projectdiscovery/gologger/levels" + "github.com/projectdiscovery/notify/pkg/types" ) -// Options of the internal runner -//nolint:maligned // used once -type Options struct { - BIID string - SlackWebHookURL string - SlackUsername string - SlackChannel string - Slack bool - DiscordWebHookURL string - DiscordWebHookUsername string - DiscordWebHookAvatarURL string - Discord bool - TelegramAPIKey string - TelegramChatID string - Telegram bool - Verbose bool - NoColor bool - Silent bool - Version bool - Interval int - HTTPMessage string - DNSMessage string - CLIMessage string -} - -// ParseConfigFileOrOptions combining all settings -func ParseConfigFileOrOptions() *Options { - options := &Options{} - - flag.StringVar(&options.BIID, "biid", "", "burp collaborator unique id") - flag.StringVar(&options.SlackWebHookURL, "slack-webhook-url", "", "Slack Webhook URL") - flag.StringVar(&options.SlackUsername, "slack-username", "", "Slack Username") - flag.StringVar(&options.SlackChannel, "slack-channel", "", "Slack Channel") - flag.BoolVar(&options.Slack, "slack", false, "Enable Slack") - flag.StringVar(&options.DiscordWebHookURL, "discord-webhook-url", "", "Discord Webhook URL") - flag.StringVar(&options.DiscordWebHookUsername, "discord-username", "", "Discord Username") - flag.StringVar(&options.DiscordWebHookAvatarURL, "discord-channel", "", "Discord Channel") - flag.BoolVar(&options.Discord, "discord", false, "Enable Discord") - flag.StringVar(&options.TelegramAPIKey, "telegram-api-key", "", "Telegram API Key") - flag.StringVar(&options.TelegramChatID, "telegram-chat-id", "", "Telegram Chat ID") - flag.BoolVar(&options.Telegram, "telegram", false, "Enable Telegram") - flag.BoolVar(&options.Silent, "silent", false, "Don't print the banner") - flag.BoolVar(&options.Version, "version", false, "Show version of notify") - flag.BoolVar(&options.Verbose, "v", false, "Show Verbose output") - flag.BoolVar(&options.NoColor, "no-color", false, "Don't Use colors in output") - flag.IntVar(&options.Interval, "interval", 2, "Polling interval in seconds") - flag.StringVar(&options.HTTPMessage, "message-http", defaultHTTPMessage, "HTTP Message") - flag.StringVar(&options.DNSMessage, "message-dns", defaultDNSMessage, "DNS Message") - flag.StringVar(&options.CLIMessage, "message-cli", defaultCLIMessage, "CLI Message") - - flag.Parse() +// ParseOptions parses the command line flags provided by a user +func ParseOptions(options *types.Options) { + // Check if stdin pipe was given + options.Stdin = hasStdin() // Read the inputs and configure the logging - options.configureOutput() + configureOutput(options) - // write default conf file template if it doesn't exist - options.writeDefaultConfig() + // Show the user the banner + showBanner() if options.Version { - gologger.Infof("Current Version: %s\n", Version) + gologger.Info().Msgf("Current Version: %s\n", Version) os.Exit(0) } - // If a config file is provided, merge the options - defaultConfigPath, err := getDefaultConfigFile() - if err != nil { - gologger.Errorf("Program exiting: %s\n", err) + // Validate the options passed by the user and if any + // invalid options have been used, exit. + if err := validateOptions(options); err != nil { + gologger.Fatal().Msgf("Program exiting: %s\n", err) } - options.MergeFromConfig(defaultConfigPath, true) - - // Show the user the banner - showBanner() - - return options } -func (options *Options) configureOutput() { +// configureOutput configures the output on the screen +func configureOutput(options *types.Options) { if options.Verbose { - gologger.MaxLevel = gologger.Verbose + gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose) } if options.NoColor { - gologger.UseColors = false + gologger.DefaultLogger.SetFormatter(formatter.NewCLI(true)) } if options.Silent { - gologger.MaxLevel = gologger.Silent + gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent) } } -func (options *Options) writeDefaultConfig() { - configFile, err := getDefaultConfigFile() - if err != nil { - gologger.Printf("Could not get default configuration file: %s\n", err) - } - - if fileExists(configFile) { - gologger.Printf("Found existing config file: %s\n", configFile) - return +// validateOptions validates the configuration options passed +func validateOptions(options *types.Options) error { + // Both verbose and silent flags were used + if options.Verbose && options.Silent { + return errors.New("both verbose and silent mode specified") } - // Skip config file creation if run as root to avoid permission issues - if os.Getuid() == 0 { - gologger.Printf("Running as root, skipping config file write to avoid permissions issues: %s\n", configFile) - return - } - - var dummyConfig ConfigFile - dummyConfig.BIID = "123456798" - dummyConfig.SlackWebHookURL = "https://a.b.c/slack" - //nolint:goconst // test data - dummyConfig.SlackUsername = "test" - //nolint:goconst // test data - dummyConfig.SlackChannel = "test" - dummyConfig.Slack = true - dummyConfig.DiscordWebHookURL = "https://a.b.c/discord" - //nolint:goconst // test data - dummyConfig.DiscordWebHookUsername = "test" - //nolint:goconst // test data - dummyConfig.DiscordWebHookAvatarURL = "test" - dummyConfig.Discord = true - dummyConfig.TelegramAPIKey = "123456879" - dummyConfig.TelegramChatID = "123" - dummyConfig.Telegram = true - dummyConfig.Interval = 2 - dummyConfig.HTTPMessage = "The collaborator server received an {{protocol}} request from {{from}} at {{time}}:\n" + - "```\n" + - "{{request}}\n" + - "{{response}}\n" + - "```" - dummyConfig.DNSMessage = "The collaborator server received a DNS lookup of type {{type}} for the domain name {{domain}} from {{from}} at {{time}}:\n" + - "```\n" + - "{{request}}\n" + - "```" - dummyConfig.CLIMessage = "{{data}}" - - err = dummyConfig.MarshalWrite(configFile) - if err != nil { - gologger.Printf("Could not write configuration file to %s: %s\n", configFile, err) - return - } - - // turn all lines into comments - origFile, err := os.Open(configFile) - if err != nil { - gologger.Printf("Could not process temporary file: %s\n", err) - return - } - tmpFile, err := ioutil.TempFile("", "") - if err != nil { - log.Println(err) - gologger.Printf("Could not process temporary file: %s\n", err) - return - } - sc := bufio.NewScanner(origFile) - for sc.Scan() { - //nolint:errcheck // silent fail - tmpFile.WriteString("# " + sc.Text() + "\n") - } - //nolint:errcheck // silent fail - origFile.Close() - tmpFileName := tmpFile.Name() - //nolint:errcheck // silent fail - tmpFile.Close() - //nolint:errcheck // silent fail - os.Rename(tmpFileName, configFile) - - gologger.Printf("Configuration file saved to %s\n", configFile) + return nil } -// MergeFromConfig with existing options -func (options *Options) MergeFromConfig(configFileName string, ignoreError bool) { - configFile, err := UnmarshalRead(configFileName) +// hasStdin returns true if we have stdin input +func hasStdin() bool { + stat, err := os.Stdin.Stat() if err != nil { - if ignoreError { - gologger.Printf("Could not read configuration file %s - ignoring error: %s\n", configFileName, err) - return - } - gologger.Fatalf("Could not read configuration file %s: %s\n", configFileName, err) + return false } - if configFile.BIID != "" { - options.BIID = configFile.BIID - } - if configFile.SlackWebHookURL != "" { - options.SlackWebHookURL = configFile.SlackWebHookURL - } - if configFile.SlackUsername != "" { - options.SlackUsername = configFile.SlackUsername - } - if configFile.SlackChannel != "" { - options.SlackChannel = configFile.SlackChannel - } - if configFile.Slack { - options.Slack = configFile.Slack - } - if configFile.DiscordWebHookURL != "" { - options.DiscordWebHookURL = configFile.DiscordWebHookURL - } - if configFile.DiscordWebHookUsername != "" { - options.DiscordWebHookUsername = configFile.DiscordWebHookUsername - } - if configFile.DiscordWebHookAvatarURL != "" { - options.DiscordWebHookAvatarURL = configFile.DiscordWebHookAvatarURL - } - if configFile.Discord { - options.Discord = configFile.Discord - } - if configFile.TelegramAPIKey != "" { - options.TelegramAPIKey = configFile.TelegramAPIKey - } - if configFile.TelegramChatID != "" { - options.TelegramChatID = configFile.TelegramChatID - } - if configFile.Telegram { - options.Telegram = configFile.Telegram - } - if configFile.HTTPMessage != "" { - options.HTTPMessage = configFile.HTTPMessage - } - if configFile.DNSMessage != "" { - options.DNSMessage = configFile.DNSMessage - } - if configFile.CLIMessage != "" { - options.CLIMessage = configFile.CLIMessage - } - if configFile.Interval > 0 { - options.Interval = configFile.Interval - } + isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0 + isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0 + + return isPipedFromChrDev || isPipedFromFIFO } diff --git a/internal/runner/runner.go b/internal/runner/runner.go index d85fe76..73f6765 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -2,137 +2,149 @@ package runner import ( "bufio" - "fmt" + "crypto/tls" + "io/ioutil" + "log" + "net/http" + "net/url" "os" - "strconv" - "strings" - "time" + "path" - "github.com/projectdiscovery/collaborator" + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" "github.com/projectdiscovery/gologger" - "github.com/projectdiscovery/notify" -) - -const ( - defaultHTTPMessage = "The collaborator server received an {{protocol}} request from {{from}} at {{time}}:\n```\n{{request}}\n{{response}}```" - defaultDNSMessage = "The collaborator server received a DNS lookup of type {{type}} for the domain name {{domain}} from {{from}} at {{time}}:\n```{{request}}```" - defaultCLIMessage = "{{data}}" + "github.com/projectdiscovery/notify/pkg/providers" + "github.com/projectdiscovery/notify/pkg/types" + "gopkg.in/yaml.v2" ) // Runner contains the internal logic of the program type Runner struct { - options *Options - burpcollab *collaborator.BurpCollaborator - notifier *notify.Notify + options *types.Options + providers *providers.Client } // NewRunner instance -func NewRunner(options *Options) (*Runner, error) { - burpcollab := collaborator.NewBurpCollaborator() - - notifier, err := notify.NewWithOptions(¬ify.Options{ - SlackWebHookURL: options.SlackWebHookURL, - SlackUsername: options.SlackUsername, - SlackChannel: options.SlackChannel, - Slack: options.Slack, - DiscordWebHookURL: options.DiscordWebHookURL, - DiscordWebHookUsername: options.DiscordWebHookUsername, - DiscordWebHookAvatarURL: options.DiscordWebHookAvatarURL, - Discord: options.Discord, - TelegramAPIKey: options.TelegramAPIKey, - TelegramChatID: options.TelegramChatID, - Telegram: options.Telegram, - }) +func NewRunner(options *types.Options) (*Runner, error) { + var providerOptions providers.ProviderOptions + + if options.ProviderConfig == "" { + home, err := os.UserHomeDir() + if err != nil { + return nil, err + } + options.ProviderConfig = path.Join(home, types.DefaultProviderConfigLocation) + gologger.Print().Msgf("Using default provider config: %s\n", options.ProviderConfig) + } + + file, err := os.Open(options.ProviderConfig) + if err != nil { + return nil, errors.Wrap(err, "could not open provider config file") + } + if parseErr := yaml.NewDecoder(file).Decode(&providerOptions); parseErr != nil { + file.Close() + return nil, errors.Wrap(parseErr, "could not parse provider config file") + } + + // Discard all internal logs + shoutrrr.SetLogger(log.New(ioutil.Discard, "", 0)) + + prClient, err := providers.New(&providerOptions, options) if err != nil { return nil, err } - return &Runner{options: options, burpcollab: burpcollab, notifier: notifier}, nil + return &Runner{options: options, providers: prClient}, nil } // Run polling and notification func (r *Runner) Run() error { - // If stdin is present pass everything to webhooks and exit - if hasStdin() { - br := bufio.NewScanner(os.Stdin) - for br.Scan() { - msg := br.Text() - rr := strings.NewReplacer( - "{{data}}", msg, - ) - msg = rr.Replace(r.options.CLIMessage) - gologger.Printf(msg) - //nolint:errcheck // silent fail - r.notifier.SendNotification(msg) + + if r.options.Proxy != "" { + proxyurl, err := url.Parse(r.options.Proxy) + if err != nil || proxyurl == nil { + gologger.Warning().Msgf("supplied proxy '%s' is not valid", r.options.Proxy) + } else { + http.DefaultClient.Transport = &http.Transport{ + Proxy: http.ProxyURL(proxyurl), + ForceAttemptHTTP2: true, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } } - os.Exit(0) } - // otherwise works as long term collaborator poll and notify via webhook - // If BIID passed via cli - if r.options.BIID != "" { - gologger.Printf("Using BIID: %s", r.options.BIID) - r.burpcollab.AddBIID(r.options.BIID) - } + var inFile *os.File + var err error - if r.options.BIID == "" { - return fmt.Errorf("BIID not specified or not found") - } + switch { + case hasStdin(): + if r.options.Bulk { + gologger.Error().Msgf("bulk flag is not supported with stdin") + os.Exit(1) + } + inFile = os.Stdin - err := r.burpcollab.Poll() - if err != nil { - return err + case r.options.Data != "": + inFile, err = os.Open(r.options.Data) + if err != nil { + gologger.Fatal().Msgf("%s\n", err) + } + default: + return errors.New("notify works with stdin or file using -data flag") } - pollTime := time.Duration(r.options.Interval) * time.Second - for { - time.Sleep(pollTime) - //nolint:errcheck // silent fail - r.burpcollab.Poll() - - for _, httpresp := range r.burpcollab.RespBuffer { - for i := range httpresp.Responses { - resp := httpresp.Responses[i] - var at int64 - at, _ = strconv.ParseInt(resp.Time, 10, 64) - atTime := time.Unix(0, at*int64(time.Millisecond)) - if resp.Protocol == "http" || resp.Protocol == "https" { - rr := strings.NewReplacer( - "{{protocol}}", strings.ToUpper(resp.Protocol), - "{{from}}", resp.Client, - "{{time}}", atTime.String(), - "{{request}}", resp.Data.RequestDecoded, - "{{response}}", resp.Data.ResponseDecoded, - ) - - msg := rr.Replace(r.options.HTTPMessage) - gologger.Printf(msg) - - //nolint:errcheck // silent fail - r.notifier.SendNotification(msg) - } - if resp.Protocol == "dns" { - rr := strings.NewReplacer( - "{{type}}", resp.Data.RequestType, - "{{domain}} ", resp.Data.SubDomain, - "{{from}}", resp.Client, - "{{time}}", atTime.String(), - "{{request}}", resp.Data.RawRequestDecoded, - ) - msg := rr.Replace(r.options.DNSMessage) - gologger.Printf(msg) - - //nolint:errcheck // silent fail - r.notifier.SendNotification(msg) - } + if r.options.Bulk { + fi, err := inFile.Stat() + if err != nil { + gologger.Fatal().Msgf("%s\n", err) + } + + msgB := make([]byte, fi.Size()) + + n, err := inFile.Read(msgB) + if err != nil || n == 0 { + gologger.Fatal().Msgf("%s\n", err) + } + + // char limit to search for a split + searchLimit := 250 + if r.options.CharLimit < searchLimit { + searchLimit = r.options.CharLimit + } + + items := SplitText(string(msgB), r.options.CharLimit, searchLimit) + + for _, v := range items { + if err := r.sendMessage(v); err != nil { + gologger.Fatal().Msgf("%s\n", err) } } - r.burpcollab.Empty() + os.Exit(0) } + + br := bufio.NewScanner(inFile) + for br.Scan() { + msg := br.Text() + //nolint:errcheck + r.sendMessage(msg) + + } + return nil } -// Close the runner instance -func (r *Runner) Close() { - r.burpcollab.Empty() +func (r *Runner) sendMessage(msg string) error { + if len(msg) > 0 { + gologger.Print().Msgf(msg) + err := r.providers.Send(msg) + if err != nil { + return err + } + } + return nil } + +// Close the runner instance +func (r *Runner) Close() {} diff --git a/internal/runner/util.go b/internal/runner/util.go index d2912a3..b103497 100644 --- a/internal/runner/util.go +++ b/internal/runner/util.go @@ -1,23 +1,59 @@ package runner -import "os" +import ( + "math" +) -func fileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} +// SplitText tries to split a string by line while keeping the chunk size as close to maxChunkSize as possible (equal or less than maxChunkSize) +func SplitText(in string, maxChunkSize, searchLimit int) (chunks []string) { + runes := []rune(in) + totalSize := len(runes) + minChunkSize := 1 + chunkOffset := 0 -func hasStdin() bool { - stat, err := os.Stdin.Stat() - if err != nil { - return false + if maxChunkSize > searchLimit { + minChunkSize = maxChunkSize - searchLimit } + maxPossibleChunks := int(math.Ceil(float64(totalSize) / float64(minChunkSize))) + + for i := 0; i <= maxPossibleChunks; i++ { + + chunkEnd := chunkOffset + maxChunkSize + nextChunkStart := chunkEnd + + // Check if it is the last chunk (chunkEnd is greater or equal to total size) + if chunkEnd >= totalSize { + chunkEnd = totalSize + nextChunkStart = totalSize + } else { + + //Check for a line break + for j := 0; j < searchLimit; j++ { + + sp := chunkEnd - j - isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0 - isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0 + if sp < 0 { + break + } + // Check if sp is the suitable split point + if runes[sp] == '\n' { + + chunkEnd = sp + nextChunkStart = chunkEnd + 1 + + break + } + } + + } + + chunks = append(chunks, string(runes[chunkOffset:chunkEnd])) + + chunkOffset = nextChunkStart + if chunkOffset >= totalSize { + break + } + } - return isPipedFromChrDev || isPipedFromFIFO + return chunks } diff --git a/notify.go b/notify.go deleted file mode 100644 index deff75e..0000000 --- a/notify.go +++ /dev/null @@ -1,76 +0,0 @@ -package notify - -import ( - "github.com/acarl005/stripansi" - "github.com/projectdiscovery/retryablehttp-go" -) - -// Notify handles the notification engine -type Notify struct { - options *Options - client *retryablehttp.Client - slackClient *SlackClient - discordClient *DiscordClient - telegramClient *TelegramClient -} - -// New notify instance -func New() (*Notify, error) { - retryhttp := retryablehttp.NewClient(retryablehttp.DefaultOptionsSingle) - return &Notify{client: retryhttp}, nil -} - -// NewWithOptions create a new instance of notify with options -func NewWithOptions(options *Options) (*Notify, error) { - notifier, err := New() - if err != nil { - return nil, err - } - SlackClient := &SlackClient{ - client: notifier.client, - WebHookURL: options.SlackWebHookURL, - UserName: options.SlackUsername, - Channel: options.SlackUsername, - TimeOut: DefaultSlackTimeout, - } - discordClient := &DiscordClient{ - client: notifier.client, - WebHookURL: options.DiscordWebHookURL, - UserName: options.DiscordWebHookUsername, - Avatar: options.DiscordWebHookAvatarURL, - } - telegramClient := &TelegramClient{ - client: notifier.client, - apiKEY: options.TelegramAPIKey, - chatID: options.TelegramChatID, - } - return &Notify{options: options, slackClient: SlackClient, discordClient: discordClient, telegramClient: telegramClient}, nil -} - -// SendNotification to registered webhooks -func (n *Notify) SendNotification(message string) error { - // strip unsupported color control chars - message = stripansi.Strip(message) - if n.options.Slack { - err := n.slackClient.SendInfo(message) - if err != nil { - return err - } - } - - if n.options.Discord { - err := n.discordClient.SendInfo(message) - if err != nil { - return err - } - } - - if n.options.Telegram { - err := n.telegramClient.SendInfo(message) - if err != nil { - return err - } - } - - return nil -} diff --git a/options.go b/options.go deleted file mode 100644 index 2d442bd..0000000 --- a/options.go +++ /dev/null @@ -1,22 +0,0 @@ -package notify - -// Options of internal webhooks -//nolint:maligned // used once -type Options struct { - // Slack - SlackWebHookURL string - SlackUsername string - SlackChannel string - Slack bool - - // Discord - DiscordWebHookURL string - DiscordWebHookUsername string - DiscordWebHookAvatarURL string - Discord bool - - // Telegram - TelegramAPIKey string - TelegramChatID string - Telegram bool -} diff --git a/pkg/providers/custom/custom.go b/pkg/providers/custom/custom.go new file mode 100644 index 0000000..890c61a --- /dev/null +++ b/pkg/providers/custom/custom.go @@ -0,0 +1,67 @@ +package custom + +import ( + "bytes" + "fmt" + "net/http" + + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "github.com/projectdiscovery/notify/pkg/utils/httpreq" + "go.uber.org/multierr" +) + +type Provider struct { + Custom []*Options `yaml:"custom,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + CustomWebhookURL string `yaml:"custom_webook_url,omitempty"` + CustomMethod string `yaml:"custom_method,omitempty"` + CustomHeaders map[string]string `yaml:"custom_headers,omitempty"` + CustomFormat string `yaml:"custom_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.Custom = append(provider.Custom, o) + } + } + + return provider, nil +} + +func (p *Provider) Send(message, CliFormat string) error { + var CustomErr error + + for _, pr := range p.Custom { + + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.CustomFormat)) + body := bytes.NewBufferString(msg) + + r, err := http.NewRequest(pr.CustomMethod, pr.CustomWebhookURL, body) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send custom notification for id: %s ", pr.ID)) + CustomErr = multierr.Append(CustomErr, err) + continue + } + + for k, v := range pr.CustomHeaders { + r.Header.Set(k, v) + } + + _, err = httpreq.NewClient().Do(r) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send custom notification for id: %s ", pr.ID)) + CustomErr = multierr.Append(CustomErr, err) + continue + } + gologger.Verbose().Msgf("custom notification sent for id: %s", pr.ID) + } + return CustomErr +} diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go new file mode 100644 index 0000000..5a47b1c --- /dev/null +++ b/pkg/providers/discord/discord.go @@ -0,0 +1,61 @@ +package discord + +import ( + "fmt" + "strings" + + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +type Provider struct { + Discord []*Options `yaml:"discord,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + DiscordWebHookURL string `yaml:"discord_webhook_url,omitempty"` + DiscordWebHookUsername string `yaml:"discord_username,omitempty"` + DiscordWebHookAvatarURL string `yaml:"discord_avatar,omitempty"` + DiscordFormat string `yaml:"discord_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.Discord = append(provider.Discord, o) + } + } + + return provider, nil +} +func (p *Provider) Send(message, CliFormat string) error { + var DiscordErr error + + for _, pr := range p.Discord { + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.DiscordFormat)) + + discordTokens := strings.TrimPrefix(pr.DiscordWebHookURL, "https://discord.com/api/webhooks/") + tokens := strings.Split(discordTokens, "/") + if len(tokens) < 2 { + err := fmt.Errorf("incorrect discord configuration for id: %s ", pr.ID) + DiscordErr = multierr.Append(DiscordErr, err) + continue + } + webhookID, token := tokens[0], tokens[1] + url := fmt.Sprintf("discord://%s@%s?splitlines=no", token, webhookID) + err := shoutrrr.Send(url, msg) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send discord notification for id: %s ", pr.ID)) + DiscordErr = multierr.Append(DiscordErr, err) + continue + } + gologger.Verbose().Msgf("discord notification sent for id: %s", pr.ID) + } + return DiscordErr +} diff --git a/pkg/providers/providers.go b/pkg/providers/providers.go new file mode 100644 index 0000000..01ade2c --- /dev/null +++ b/pkg/providers/providers.go @@ -0,0 +1,121 @@ +package providers + +import ( + "github.com/acarl005/stripansi" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/providers/custom" + "github.com/projectdiscovery/notify/pkg/providers/discord" + "github.com/projectdiscovery/notify/pkg/providers/pushover" + "github.com/projectdiscovery/notify/pkg/providers/slack" + "github.com/projectdiscovery/notify/pkg/providers/smtp" + "github.com/projectdiscovery/notify/pkg/providers/teams" + "github.com/projectdiscovery/notify/pkg/providers/telegram" + "github.com/projectdiscovery/notify/pkg/types" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +// ProviderOptions is configuration for notify providers +type ProviderOptions struct { + Slack []*slack.Options `yaml:"slack,omitempty"` + Discord []*discord.Options `yaml:"discord,omitempty"` + Pushover []*pushover.Options `yaml:"pushover,omitempty"` + SMTP []*smtp.Options `yaml:"smtp,omitempty"` + Teams []*teams.Options `yaml:"teams,omitempty"` + Telegram []*telegram.Options `yaml:"telegram,omitempty"` + Custom []*custom.Options `yaml:"custom,omitempty"` +} + +// Provider is an interface implemented by providers +type Provider interface { + Send(message, CliFormat string) error +} + +type Client struct { + providers []Provider + providerOptions *ProviderOptions + options *types.Options +} + +func New(providerOptions *ProviderOptions, options *types.Options) (*Client, error) { + + client := &Client{providerOptions: providerOptions, options: options} + + if providerOptions.Slack != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "slack")) { + + provider, err := slack.New(providerOptions.Slack, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create slack provider client") + } + + client.providers = append(client.providers, provider) + } + if providerOptions.Discord != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "discord")) { + + provider, err := discord.New(providerOptions.Discord, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create discord provider client") + } + client.providers = append(client.providers, provider) + } + if providerOptions.Pushover != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "pushover")) { + + provider, err := pushover.New(providerOptions.Pushover, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create pushover provider client") + } + client.providers = append(client.providers, provider) + } + if providerOptions.SMTP != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "smtp")) { + + provider, err := smtp.New(providerOptions.SMTP, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create smtp provider client") + } + client.providers = append(client.providers, provider) + } + if providerOptions.Teams != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "teams")) { + + provider, err := teams.New(providerOptions.Teams, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create teams provider client") + } + client.providers = append(client.providers, provider) + } + if providerOptions.Telegram != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "telegram")) { + + provider, err := telegram.New(providerOptions.Telegram, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create telegram provider client") + } + client.providers = append(client.providers, provider) + } + + if providerOptions.Custom != nil && (len(options.Providers) == 0 || utils.Contains(options.Providers, "custom")) { + + provider, err := custom.New(providerOptions.Custom, options.IDs) + if err != nil { + return nil, errors.Wrap(err, "could not create custom provider client") + } + client.providers = append(client.providers, provider) + } + + return client, nil +} + +func (p *Client) Send(message string) error { + + // strip unsupported color control chars + message = stripansi.Strip(message) + + for _, v := range p.providers { + if err := v.Send(message, p.options.MessageFormat); err != nil { + for _, v := range multierr.Errors(err) { + gologger.Error().Msgf("%s", v) + } + } + } + + return nil +} diff --git a/pkg/providers/pushover/pushover.go b/pkg/providers/pushover/pushover.go new file mode 100644 index 0000000..5fdce66 --- /dev/null +++ b/pkg/providers/pushover/pushover.go @@ -0,0 +1,53 @@ +package pushover + +import ( + "fmt" + "strings" + + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +type Provider struct { + Pushover []*Options `yaml:"pushover,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + PushoverApiToken string `yaml:"pushover_api_token,omitempty"` + UserKey string `yaml:"pushover_user_key,omitempty"` + PushoverDevices []string `yaml:"pushover_devices,omitempty"` + PushoverFormat string `yaml:"pushover_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.Pushover = append(provider.Pushover, o) + } + } + + return provider, nil +} + +func (p *Provider) Send(message, CliFormat string) error { + var PushoverErr error + for _, pr := range p.Pushover { + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.PushoverFormat)) + + url := fmt.Sprintf("pushover://shoutrrr:%s@%s/?devices=%s", pr.PushoverApiToken, pr.UserKey, strings.Join(pr.PushoverDevices, ",")) + err := shoutrrr.Send(url, msg) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send pushover notification for id: %s ", pr.ID)) + PushoverErr = multierr.Append(PushoverErr, err) + continue + } + gologger.Verbose().Msgf("pushover notification sent for id: %s", pr.ID) + } + return PushoverErr +} diff --git a/pkg/providers/slack/slack.go b/pkg/providers/slack/slack.go new file mode 100644 index 0000000..43d5272 --- /dev/null +++ b/pkg/providers/slack/slack.go @@ -0,0 +1,85 @@ +package slack + +import ( + "fmt" + "net/url" + "strings" + + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +type Provider struct { + Slack []*Options `yaml:"slack,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + SlackWebHookURL string `yaml:"slack_webhook_url,omitempty"` + SlackUsername string `yaml:"slack_username,omitempty"` + SlackChannel string `yaml:"slack_channel,omitempty"` + SlackThreads bool `yaml:"slack_threads,omitempty"` + SlackThreadTS string `yaml:"slack_thread_ts,omitempty"` + SlackToken string `yaml:"slack_token,omitempty"` + SlackFormat string `yaml:"slack_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.Slack = append(provider.Slack, o) + } + } + + return provider, nil +} + +func (p *Provider) Send(message, CliFormat string) error { + var SlackErr error + for _, pr := range p.Slack { + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.SlackFormat)) + + if pr.SlackThreads { + if pr.SlackToken == "" { + err := errors.Wrap(fmt.Errorf("slack_token value is required to start a thread"), + fmt.Sprintf("failed to send slack notification for id: %s ", pr.ID)) + SlackErr = multierr.Append(SlackErr, err) + continue + } + if pr.SlackChannel == "" { + err := errors.Wrap(fmt.Errorf("slack_channel value is required to start a thread"), + fmt.Sprintf("failed to send slack notification for id: %s ", pr.ID)) + SlackErr = multierr.Append(SlackErr, err) + continue + } + if err := pr.SendThreaded(msg); err != nil { + err = errors.Wrap(err, + fmt.Sprintf("failed to send slack notification for id: %s ", pr.ID)) + SlackErr = multierr.Append(SlackErr, err) + continue + } + } else { + slackTokens := strings.TrimPrefix(pr.SlackWebHookURL, "https://hooks.slack.com/services/") + url := &url.URL{ + Scheme: "slack", + Path: slackTokens, + } + + err := shoutrrr.Send(url.String(), msg) + if err != nil { + err = errors.Wrap(err, + fmt.Sprintf("failed to send slack notification for id: %s ", pr.ID)) + SlackErr = multierr.Append(SlackErr, err) + continue + } + } + gologger.Verbose().Msgf("Slack notification sent successfully for id: %s", pr.ID) + + } + return SlackErr +} diff --git a/pkg/providers/slack/slack_api.go b/pkg/providers/slack/slack_api.go new file mode 100644 index 0000000..5bb0743 --- /dev/null +++ b/pkg/providers/slack/slack_api.go @@ -0,0 +1,39 @@ +package slack + +import ( + "fmt" + "net/http" + + "github.com/projectdiscovery/notify/pkg/utils/httpreq" +) + +const SlackPostMessageAPI = "https://slack.com/api/chat.postMessage" + +func (options *Options) SendThreaded(message string) error { + + payload := APIRequest{ + Channel: options.SlackChannel, + Text: message, + TS: options.SlackThreadTS, + } + + headers := http.Header{ + "Content-Type": {"application/json"}, + "Authorization": {fmt.Sprintf("Bearer %s", options.SlackToken)}, + } + + var response *APIResponse + + err := httpreq.NewClient().Post(SlackPostMessageAPI, &payload, headers, &response) + if err != nil { + return err + } + if !response.Ok { + return fmt.Errorf("error while sending slack message: %s ", response.Error) + } + + if options.SlackThreadTS == "" { + options.SlackThreadTS = response.TS + } + return nil +} diff --git a/pkg/providers/slack/slack_types.go b/pkg/providers/slack/slack_types.go new file mode 100644 index 0000000..7231c9a --- /dev/null +++ b/pkg/providers/slack/slack_types.go @@ -0,0 +1,13 @@ +package slack + +type APIRequest struct { + Channel string `json:"channel,omitempty"` + Text string `json:"text,omitempty"` + TS string `json:"thread_ts,omitempty"` +} + +type APIResponse struct { + Ok bool `json:"ok,omitempty"` + TS string `json:"ts,omitempty"` + Error string `json:"error,omitempty"` +} diff --git a/pkg/providers/smtp/smtp.go b/pkg/providers/smtp/smtp.go new file mode 100644 index 0000000..4b68ea8 --- /dev/null +++ b/pkg/providers/smtp/smtp.go @@ -0,0 +1,55 @@ +package smtp + +import ( + "fmt" + "strings" + + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +type Provider struct { + SMTP []*Options `yaml:"smtp,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + Server string `yaml:"smtp_server,omitempty"` + Username string `yaml:"smtp_username,omitempty"` + Password string `yaml:"smtp_password,omitempty"` + FromAddress string `yaml:"from_address,omitempty"` + SMTPCC []string `yaml:"smtp_cc,omitempty"` + SMTPFormat string `yaml:"smtp_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.SMTP = append(provider.SMTP, o) + } + } + + return provider, nil +} + +func (p *Provider) Send(message, CliFormat string) error { + var SmtpErr error + for _, pr := range p.SMTP { + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.SMTPFormat)) + + url := fmt.Sprintf("smtp://%s:%s@%s/?fromAddress=%s&toAddresses=%s", pr.Username, pr.Password, pr.Server, pr.FromAddress, strings.Join(pr.SMTPCC, ",")) + err := shoutrrr.Send(url, msg) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send smtp notification for id: %s ", pr.ID)) + SmtpErr = multierr.Append(SmtpErr, err) + continue + } + gologger.Verbose().Msgf("smtp notification sent for id: %s", pr.ID) + } + return SmtpErr +} diff --git a/pkg/providers/teams/teams.go b/pkg/providers/teams/teams.go new file mode 100644 index 0000000..57c6c1c --- /dev/null +++ b/pkg/providers/teams/teams.go @@ -0,0 +1,53 @@ +package teams + +import ( + "fmt" + "strings" + + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +type Provider struct { + Teams []*Options `yaml:"teams,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + TeamsWebHookURL string `yaml:"teams_webhook_url,omitempty"` + TeamsFormat string `yaml:"teams_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.Teams = append(provider.Teams, o) + } + } + + return provider, nil +} + +func (p *Provider) Send(message, CliFormat string) error { + var TeamsErr error + for _, pr := range p.Teams { + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.TeamsFormat)) + + teamsTokens := strings.TrimPrefix(pr.TeamsWebHookURL, "https://outlook.office.com/webhook/") + teamsTokens = strings.ReplaceAll(teamsTokens, "IncomingWebhook/", "") + url := fmt.Sprintf("teams://%s", teamsTokens) + err := shoutrrr.Send(url, msg) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send teams notification for id: %s ", pr.ID)) + TeamsErr = multierr.Append(TeamsErr, err) + continue + } + gologger.Verbose().Msgf("teams notification sent for id: %s", pr.ID) + } + return TeamsErr +} diff --git a/pkg/providers/telegram/telegram.go b/pkg/providers/telegram/telegram.go new file mode 100644 index 0000000..7c70043 --- /dev/null +++ b/pkg/providers/telegram/telegram.go @@ -0,0 +1,51 @@ +package telegram + +import ( + "fmt" + + "github.com/containrrr/shoutrrr" + "github.com/pkg/errors" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/notify/pkg/utils" + "go.uber.org/multierr" +) + +type Provider struct { + Telegram []*Options `yaml:"telegram,omitempty"` +} + +type Options struct { + ID string `yaml:"id,omitempty"` + TelegramAPIKey string `yaml:"telegram_api_key,omitempty"` + TelegramChatID string `yaml:"telegram_chat_id,omitempty"` + TelegramFormat string `yaml:"telegram_format,omitempty"` +} + +func New(options []*Options, ids []string) (*Provider, error) { + provider := &Provider{} + + for _, o := range options { + if len(ids) == 0 || utils.Contains(ids, o.ID) { + provider.Telegram = append(provider.Telegram, o) + } + } + + return provider, nil +} + +func (p *Provider) Send(message, CliFormat string) error { + var TelegramErr error + for _, pr := range p.Telegram { + msg := utils.FormatMessage(message, utils.SelectFormat(CliFormat, pr.TelegramFormat)) + + url := fmt.Sprintf("telegram://%s@telegram?channels=%s", pr.TelegramAPIKey, pr.TelegramChatID) + err := shoutrrr.Send(url, msg) + if err != nil { + err = errors.Wrap(err, fmt.Sprintf("failed to send telegram notification for id: %s ", pr.ID)) + TelegramErr = multierr.Append(TelegramErr, err) + continue + } + gologger.Verbose().Msgf("telegram notification sent for id: %s", pr.ID) + } + return TelegramErr +} diff --git a/pkg/types/default.go b/pkg/types/default.go new file mode 100644 index 0000000..aaf75ee --- /dev/null +++ b/pkg/types/default.go @@ -0,0 +1,5 @@ +package types + +const ( + DefaultProviderConfigLocation = ".config/notify/provider-config.yaml" +) diff --git a/pkg/types/types.go b/pkg/types/types.go new file mode 100644 index 0000000..b3606af --- /dev/null +++ b/pkg/types/types.go @@ -0,0 +1,21 @@ +package types + +import "github.com/projectdiscovery/goflags" + +type Options struct { + Verbose bool `yaml:"verbose,omitempty"` + NoColor bool `yaml:"no_color,omitempty"` + Silent bool `yaml:"silent,omitempty"` + Version bool `yaml:"version,omitempty"` + ProviderConfig string `yaml:"provider_config,omitempty"` + Providers goflags.NormalizedStringSlice `yaml:"providers,omitempty"` + IDs goflags.NormalizedStringSlice `yaml:"ids,omitempty"` + Proxy string `yaml:"proxy,omitempty"` + + MessageFormat string `yaml:"message_format,omitempty"` + + Stdin bool + Bulk bool `yaml:"bulk,omitempty"` + CharLimit int `yaml:"char_limit,omitempty"` + Data string `yaml:"data,omitempty"` +} diff --git a/pkg/utils/httpreq/httpreq.go b/pkg/utils/httpreq/httpreq.go new file mode 100644 index 0000000..017d50f --- /dev/null +++ b/pkg/utils/httpreq/httpreq.go @@ -0,0 +1,61 @@ +package httpreq + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + jsoniter "github.com/json-iterator/go" +) + +type Client struct { + httpClient *http.Client +} + +func NewClient() *Client { + return &Client{ + httpClient: http.DefaultClient, + } +} + +func (c *Client) Get(url string, response interface{}) error { + res, err := c.httpClient.Get(url) + if err != nil { + return fmt.Errorf("error creating request: %v", err) + } + if err := jsoniter.NewDecoder(res.Body).Decode(&response); err != nil { + return fmt.Errorf("error trying to unmarshal the response: %v", err) + } + return nil +} + +func (c *Client) Post(url string, requestBody interface{}, headers http.Header, response interface{}) error { + body, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("error creating payload: %v", err) + } + + req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + return fmt.Errorf("error creating request: %v", err) + } + + for key, val := range headers { + req.Header.Set(key, val[0]) + } + + res, err := c.httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send payload: %v", err) + } + + if err = jsoniter.NewDecoder(res.Body).Decode(&response); err != nil { + return fmt.Errorf("error trying to unmarshal the response: %v", err) + } + return nil +} + +func (c *Client) Do(req *http.Request) (*http.Response, error) { + return c.httpClient.Do(req) +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go new file mode 100644 index 0000000..97e5737 --- /dev/null +++ b/pkg/utils/utils.go @@ -0,0 +1,31 @@ +package utils + +import ( + "strings" +) + +const defaultFormat = "{{data}}" + +func Contains(slice []string, item string) bool { + set := make(map[string]struct{}, len(slice)) + for _, s := range slice { + set[s] = struct{}{} + } + + _, ok := set[item] + return ok + +} + +func FormatMessage(msg, format string) string { + return strings.Replace(format, defaultFormat, msg, -1) +} + +func SelectFormat(cliFormat, configFormat string) string { + if cliFormat != "" && cliFormat != defaultFormat { + return cliFormat + } else if configFormat != "" && configFormat != defaultFormat { + return configFormat + } + return defaultFormat +} diff --git a/slack.go b/slack.go deleted file mode 100644 index 02bee75..0000000 --- a/slack.go +++ /dev/null @@ -1,161 +0,0 @@ -package notify - -// From https://dev.to/arunx2/simple-slack-notification-with-golang-55i2 - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "net/http" - "strconv" - "time" - - "github.com/projectdiscovery/retryablehttp-go" -) - -// DefaultSlackTimeout to conclude operations -const DefaultSlackTimeout = 5 * time.Second - -// SlackClient holding the slack communication logic -type SlackClient struct { - client *retryablehttp.Client - WebHookURL string - UserName string - Channel string - TimeOut time.Duration -} - -// SimpleSlackRequest basic request -type SimpleSlackRequest struct { - Text string - IconEmoji string -} - -// SlackJobNotification structure -type SlackJobNotification struct { - Color string - IconEmoji string - Details string - Text string -} - -// SlackMessage structure -type SlackMessage struct { - Username string `json:"username,omitempty"` - IconEmoji string `json:"icon_emoji,omitempty"` - Channel string `json:"channel,omitempty"` - Text string `json:"text,omitempty"` - Attachments []Attachment `json:"attachments,omitempty"` -} - -// Attachment of slack message -type Attachment struct { - Color string `json:"color,omitempty"` - Fallback string `json:"fallback,omitempty"` - CallbackID string `json:"callback_id,omitempty"` - ID int `json:"id,omitempty"` - AuthorID string `json:"author_id,omitempty"` - AuthorName string `json:"author_name,omitempty"` - AuthorSubname string `json:"author_subname,omitempty"` - AuthorLink string `json:"author_link,omitempty"` - AuthorIcon string `json:"author_icon,omitempty"` - Title string `json:"title,omitempty"` - TitleLink string `json:"title_link,omitempty"` - Pretext string `json:"pretext,omitempty"` - Text string `json:"text,omitempty"` - ImageURL string `json:"image_url,omitempty"` - ThumbURL string `json:"thumb_url,omitempty"` - // Fields and actions are not defined. - MarkdownIn []string `json:"mrkdwn_in,omitempty"` - TS json.Number `json:"ts,omitempty"` -} - -// SendSlackNotification will post to an 'Incoming Webook' url setup in Slack Apps. It accepts -// some text and the slack channel is saved within Slack. -func (sc *SlackClient) SendSlackNotification(sr SimpleSlackRequest) error { - slackRequest := &SlackMessage{ - Text: sr.Text, - Username: sc.UserName, - IconEmoji: sr.IconEmoji, - Channel: sc.Channel, - } - return sc.sendHTTPRequest(slackRequest) -} - -// SendJobNotification will post a job notification to slack -func (sc *SlackClient) SendJobNotification(job SlackJobNotification) error { - attachment := Attachment{ - Color: job.Color, - Text: job.Details, - TS: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), - } - slackRequest := &SlackMessage{ - Text: job.Text, - Username: sc.UserName, - IconEmoji: job.IconEmoji, - Channel: sc.Channel, - Attachments: []Attachment{attachment}, - } - return sc.sendHTTPRequest(slackRequest) -} - -// SendError message -func (sc *SlackClient) SendError(message string, options ...string) (err error) { - return sc.funcName("danger", message, options) -} - -// SendInfo message -func (sc *SlackClient) SendInfo(message string, options ...string) (err error) { - return sc.funcName("good", message, options) -} - -// SendWarning message -func (sc *SlackClient) SendWarning(message string, options ...string) (err error) { - return sc.funcName("warning", message, options) -} - -func (sc *SlackClient) funcName(color, message string, options []string) error { - emoji := ":hammer_and_wrench" - if len(options) > 0 { - emoji = options[0] - } - sjn := SlackJobNotification{ - Color: color, - IconEmoji: emoji, - Details: message, - } - return sc.SendJobNotification(sjn) -} - -func (sc *SlackClient) sendHTTPRequest(slackRequest *SlackMessage) error { - slackBody, err := json.Marshal(slackRequest) - if err != nil { - return err - } - req, err := retryablehttp.NewRequest(http.MethodPost, sc.WebHookURL, bytes.NewBuffer(slackBody)) - if err != nil { - return err - } - req.Header.Add("Content-Type", "application/json") - if sc.TimeOut == 0 { - sc.TimeOut = DefaultSlackTimeout - } - - resp, err := sc.client.Do(req) - if err != nil { - return err - } - - buf, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - //nolint:errcheck // silent fail - defer resp.Body.Close() - - if string(buf) != ok { - return err - } - return nil -} diff --git a/telegram.go b/telegram.go deleted file mode 100644 index 2801ba3..0000000 --- a/telegram.go +++ /dev/null @@ -1,75 +0,0 @@ -package notify - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "strings" - "time" - - "github.com/projectdiscovery/retryablehttp-go" -) - -// DefaultTelegraTimeout to conclude operations -const ( - DefaultTelegraTimeout = 5 * time.Second - Endpoint = "https://api.telegram.org/bot{{apikey}}/sendMessage?chat_id={{chatid}}&text={{message}}" -) - -// TelegramClient handling webhooks -type TelegramClient struct { - client *retryablehttp.Client - apiKEY string - chatID string - TimeOut time.Duration -} - -// SendInfo to telegram -func (dc *TelegramClient) SendInfo(message string) (err error) { - return dc.sendHTTPRequest(message) -} - -func (dc *TelegramClient) sendHTTPRequest(message string) error { - r := strings.NewReplacer( - "{{apikey}}", dc.apiKEY, - "{{chatid}}", dc.chatID, - "{{message}}", message, - ) - URL := r.Replace(Endpoint) - req, err := retryablehttp.NewRequest(http.MethodGet, URL, nil) - if err != nil { - return err - } - resp, err := dc.client.Do(req) - if err != nil { - return err - } - - buf, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - //nolint:errcheck // silent fail - defer resp.Body.Close() - - var tgresponse TelegramResponse - - err = json.Unmarshal(buf, &tgresponse) - if err != nil { - return err - } - - if !tgresponse.Ok { - return fmt.Errorf("%s", tgresponse.Description) - } - - return nil -} - -// TelegramResponse structure -type TelegramResponse struct { - Ok bool `json:"ok"` - ErrorCode int `json:"error_code,omitempty"` - Description string `json:"description,omitempty"` -}