diff --git a/.docker/alpine.docker b/.docker/alpine.docker index dcb7e1b..f9c6f81 100644 --- a/.docker/alpine.docker +++ b/.docker/alpine.docker @@ -4,18 +4,17 @@ ARG REGISTRY="docker.io" ## BUILDER ##################################################################### -FROM golang:alpine3.17 as builder +FROM ${REGISTRY}/essentialkaos/golang:alpine3.18 as builder WORKDIR /go/src/github.com/essentialkaos/subdy COPY . . -# hadolint ignore=DL3018 -RUN apk add --no-cache git make && make deps && make all +RUN make deps && make all ## FINAL IMAGE ################################################################# -FROM ${REGISTRY}/essentialkaos/alpine:3.17 +FROM ${REGISTRY}/essentialkaos/alpine:3.18 LABEL org.opencontainers.image.title="subdy" \ org.opencontainers.image.description="CLI for subdomain.center API" \ diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fc51337..d0ad1de 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,6 +14,12 @@ updates: - "andyone" reviewers: - "andyone" + groups: + all: + applies-to: version-updates + update-types: + - "minor" + - "patch" - package-ecosystem: "github-actions" directory: "/" diff --git a/.github/images/card.svg b/.github/images/card.svg new file mode 100644 index 0000000..7246238 --- /dev/null +++ b/.github/images/card.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.github/images/license.svg b/.github/images/license.svg new file mode 100644 index 0000000..8990e77 --- /dev/null +++ b/.github/images/license.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.github/images/subdy.png b/.github/images/subdy.png new file mode 100644 index 0000000..311d671 Binary files /dev/null and b/.github/images/subdy.png differ diff --git a/.github/images/usage.svg b/.github/images/usage.svg new file mode 100644 index 0000000..2499ac0 --- /dev/null +++ b/.github/images/usage.svg @@ -0,0 +1,74 @@ + + diff --git a/.github/workflows/docker-push.yml b/.github/workflows/docker-push.yml index 758de78..5980e6b 100644 --- a/.github/workflows/docker-push.yml +++ b/.github/workflows/docker-push.yml @@ -135,7 +135,7 @@ jobs: - name: Build and push Docker images (Docker) if: ${{ steps.build_check.outputs.build == 'true' }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: push: true context: . @@ -148,7 +148,7 @@ jobs: - name: Build and push Docker images (GHCR) if: ${{ steps.build_check.outputs.build == 'true' }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: push: true context: . diff --git a/Makefile b/Makefile index 3ad4c03..4d878ae 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,40 @@ ################################################################################ -# This Makefile generated by GoMakeGen 2.2.0 using next command: +# This Makefile generated by GoMakeGen 3.0.2 using next command: # gomakegen --mod . # # More info: https://kaos.sh/gomakegen ################################################################################ -export GO111MODULE=on - ifdef VERBOSE ## Print verbose information (Flag) VERBOSE_FLAG = -v endif +COMPAT ?= 1.19 MAKEDIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) GITREV ?= $(shell test -s $(MAKEDIR)/.git && git rev-parse --short HEAD) ################################################################################ .DEFAULT_GOAL := help -.PHONY = fmt vet all clean deps update init vendor mod-init mod-update mod-download mod-vendor help +.PHONY = fmt vet all install uninstall clean deps update init vendor mod-init mod-update mod-download mod-vendor help ################################################################################ all: subdy ## Build all binaries subdy: - go build $(VERBOSE_FLAG) -ldflags="-X main.gitrev=$(GITREV)" subdy.go + @echo "[36;1mBuilding subdy…[0m" + @go build $(VERBOSE_FLAG) -ldflags="-X main.gitrev=$(GITREV)" subdy.go install: ## Install all binaries - cp subdy /usr/bin/subdy + @echo "[36;1mInstalling binaries…[0m" + @cp subdy /usr/bin/subdy uninstall: ## Uninstall all binaries - rm -f /usr/bin/subdy + @echo "[36;1mRemoving installed binaries…[0m" + @rm -f /usr/bin/subdy init: mod-init ## Initialize new module @@ -43,57 +45,70 @@ update: mod-update ## Update dependencies to the latest versions vendor: mod-vendor ## Make vendored copy of dependencies mod-init: + @echo "[37m[1/2][0m [36;1mModules initialization…[0m" ifdef MODULE_PATH ## Module path for initialization (String) - go mod init $(MODULE_PATH) + @go mod init $(MODULE_PATH) else - go mod init + @go mod init endif + @echo "[37m[2/2][0m [36;1mDependencies cleanup…[0m" ifdef COMPAT ## Compatible Go version (String) - go mod tidy $(VERBOSE_FLAG) -compat=$(COMPAT) + @go mod tidy $(VERBOSE_FLAG) -compat=$(COMPAT) -go=$(COMPAT) else - go mod tidy $(VERBOSE_FLAG) + @go mod tidy $(VERBOSE_FLAG) endif mod-update: + @echo "[37m[1/4][0m [36;1mUpdating dependencies…[0m" ifdef UPDATE_ALL ## Update all dependencies (Flag) - go get -u $(VERBOSE_FLAG) all + @go get -u $(VERBOSE_FLAG) all else - go get -u $(VERBOSE_FLAG) ./... + @go get -u $(VERBOSE_FLAG) ./... endif + @echo "[37m[2/4][0m [36;1mStripping toolchain info…[0m" + @grep -q 'toolchain ' go.mod && go mod edit -toolchain=none || : + + @echo "[37m[3/4][0m [36;1mDependencies cleanup…[0m" ifdef COMPAT - go mod tidy $(VERBOSE_FLAG) -compat=$(COMPAT) + @go mod tidy $(VERBOSE_FLAG) -compat=$(COMPAT) else - go mod tidy $(VERBOSE_FLAG) + @go mod tidy $(VERBOSE_FLAG) endif - test -d vendor && rm -rf vendor && go mod vendor $(VERBOSE_FLAG) || : + @echo "[37m[4/4][0m [36;1mUpdating vendored dependencies…[0m" + @test -d vendor && rm -rf vendor && go mod vendor $(VERBOSE_FLAG) || : mod-download: - go mod download + @echo "[36;1mDownloading dependencies…[0m" + @go mod download mod-vendor: - rm -rf vendor && go mod vendor $(VERBOSE_FLAG) + @echo "[36;1mVendoring dependencies…[0m" + @rm -rf vendor && go mod vendor $(VERBOSE_FLAG) || : fmt: ## Format source code with gofmt - find . -name "*.go" -exec gofmt -s -w {} \; + @echo "[36;1mFormatting sources…[0m" + @find . -name "*.go" -exec gofmt -s -w {} \; vet: ## Runs 'go vet' over sources - go vet -composites=false -printfuncs=LPrintf,TLPrintf,TPrintf,log.Debug,log.Info,log.Warn,log.Error,log.Critical,log.Print ./... + @echo "[36;1mRunning 'go vet' over sources…[0m" + @go vet -composites=false -printfuncs=LPrintf,TLPrintf,TPrintf,log.Debug,log.Info,log.Warn,log.Error,log.Critical,log.Print ./... clean: ## Remove generated files - rm -f subdy + @echo "[36;1mRemoving built binaries…[0m" + @rm -f subdy help: ## Show this info @echo -e '\n\033[1mTargets:\033[0m\n' @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ - | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[33m%-14s\033[0m %s\n", $$1, $$2}' + | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[33m%-9s\033[0m %s\n", $$1, $$2}' @echo -e '\n\033[1mVariables:\033[0m\n' @grep -E '^ifdef [A-Z_]+ .*?## .*$$' $(abspath $(lastword $(MAKEFILE_LIST))) \ | sed 's/ifdef //' \ - | awk 'BEGIN {FS = " .*?## "}; {printf " \033[32m%-14s\033[0m %s\n", $$1, $$2}' + | awk 'BEGIN {FS = " .*?## "}; {printf " \033[32m%-11s\033[0m %s\n", $$1, $$2}' @echo -e '' - @echo -e '\033[90mGenerated by GoMakeGen 2.2.0\033[0m\n' + @echo -e '\033[90mGenerated by GoMakeGen 3.0.2\033[0m\n' ################################################################################ diff --git a/README.md b/README.md index 950d57b..b1f3611 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,23 @@ -
+Screenshots • Installation • Usage • CI Status • Contributing • License
- +
### Installation @@ -78,28 +77,7 @@ subdy --generate-man | sudo gzip > /usr/share/man/man1/subdy.1.gz ### Usage -``` -Usage: subdy {options} domain - -Options - - --ip, -I Resolve subdomains IP - --dns, -D name-or-url DoH provider (cloudflare|google|url) - --no-color, -nc Disable colors in output - --help, -h Show this help message - --version, -v Show version - -Examples - - subdy go.dev - Find all subdomains of go.dev - - subdy -I go.dev - Find all subdomains of go.dev and resolve their IPs - - subdy -I -D google go.dev - Find all subdomains of go.dev and resolve their IPs using Google DNS -``` + ### CI Status diff --git a/cli/cli.go b/cli/cli.go index c535bf9..07ab356 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -18,6 +18,7 @@ import ( "github.com/essentialkaos/ek/v12/strutil" "github.com/essentialkaos/ek/v12/support" "github.com/essentialkaos/ek/v12/support/deps" + "github.com/essentialkaos/ek/v12/terminal" "github.com/essentialkaos/ek/v12/terminal/tty" "github.com/essentialkaos/ek/v12/usage" "github.com/essentialkaos/ek/v12/usage/completion/bash" @@ -35,7 +36,7 @@ import ( // Basic utility info const ( APP = "subdy" - VER = "0.1.0" + VER = "0.2.0" DESC = "CLI for subdomain.center API" ) @@ -82,6 +83,7 @@ var dohProviders = map[string]string{ "cf": dns.CLOUDFLARE, "cloudflare": dns.CLOUDFLARE, "google": dns.GOOGLE, + "quad9": dns.QUAD9, } // useRawOutput is raw output flag (for cli command) @@ -95,8 +97,9 @@ func Run(gitRev string, gomod []byte) { args, errs := options.Parse(optMap) - if len(errs) != 0 { - printError(errs[0].Error()) + if !errs.IsEmpty() { + terminal.Error("Options parsing errors:") + terminal.Error(errs.String()) os.Exit(1) } @@ -123,10 +126,17 @@ func Run(gitRev string, gomod []byte) { os.Exit(0) } - err := process(args) + err := validateOptionsAndArgs(args) if err != nil { - printError(err.Error()) + terminal.Error(err) + os.Exit(1) + } + + err = process(args) + + if err != nil { + terminal.Error(err) os.Exit(1) } } @@ -149,17 +159,30 @@ func configureUI() { req.SetUserAgent(APP, VER) } -// process starts arguments processing -func process(args options.Arguments) error { +// validateOptionsAndArgs validates options and arguments +func validateOptionsAndArgs(args options.Arguments) error { domain := args.Get(0).String() if !strings.Contains(domain, ".") { return fmt.Errorf("%q is not valid domain", domain) } + if options.Has(OPT_DNS) { + dns := options.GetS(OPT_DNS) + + if !strings.Contains(dns, ".") && dohProviders[dns] == "" { + return fmt.Errorf("Unknown DNS-over-HTTPS provider %q", dns) + } + } + + return nil +} + +// process starts arguments processing +func process(args options.Arguments) error { fmtc.If(!useRawOutput).TPrintf("{s-}Searching subdomains…{!}") - subdomains, err := subdomains.Find(domain) + subdomains, err := subdomains.Find(args.Get(0).String()) if err != nil { fmtc.TPrintf("") @@ -168,7 +191,7 @@ func process(args options.Arguments) error { if len(subdomains) == 0 { fmtc.TPrintf("") - printWarn("There are no subdomains for this domain") + terminal.Warn("There are no subdomains for this domain") return nil } @@ -243,24 +266,6 @@ func getDoHResolver() *dns.Resolver { return &dns.Resolver{resolverURL} } -// printError prints error message to console -func printError(f string, a ...interface{}) { - if len(a) == 0 { - fmtc.Fprintln(os.Stderr, "{r}"+f+"{!}") - } else { - fmtc.Fprintf(os.Stderr, "{r}"+f+"{!}\n", a...) - } -} - -// printError prints warning message to console -func printWarn(f string, a ...interface{}) { - if len(a) == 0 { - fmtc.Fprintln(os.Stderr, "{y}"+f+"{!}") - } else { - fmtc.Fprintf(os.Stderr, "{y}"+f+"{!}\n", a...) - } -} - // ////////////////////////////////////////////////////////////////////////////////// // // checkAPIAvailability checks API availability @@ -294,11 +299,11 @@ func printCompletion() int { switch options.GetS(OPT_COMPLETION) { case "bash": - fmt.Print(bash.Generate(info, "subdy")) + fmt.Print(bash.Generate(info, APP)) case "fish": - fmt.Print(fish.Generate(info, "subdy")) + fmt.Print(fish.Generate(info, APP)) case "zsh": - fmt.Print(zsh.Generate(info, optMap, "subdy")) + fmt.Print(zsh.Generate(info, optMap, APP)) default: return 1 } @@ -308,12 +313,7 @@ func printCompletion() int { // printMan prints man page func printMan() { - fmt.Println( - man.Generate( - genUsage(), - genAbout(""), - ), - ) + fmt.Println(man.Generate(genUsage(), genAbout(""))) } // genUsage generates usage info @@ -321,7 +321,7 @@ func genUsage() *usage.Info { info := usage.NewInfo("", "domain") info.AddOption(OPT_IP, "Resolve subdomains IP") - info.AddOption(OPT_DNS, "DoH provider {s-}({_}cloudflare{!_}|google|url){!}", "name-or-url") + info.AddOption(OPT_DNS, "DoH JSON provider {s-}({_}cloudflare{!_}|google|quad9|custom-url){!}", "name-or-url") info.AddOption(OPT_NO_COLOR, "Disable colors in output") info.AddOption(OPT_HELP, "Show this help message") info.AddOption(OPT_VER, "Show version") @@ -352,6 +352,8 @@ func genAbout(gitRev string) *usage.About { License: "Apache License, Version 2.0