Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
BINARY_NAME=funURL
INSTALL_DIR=/usr/local/bin
USER_BIN=$(HOME)/.local/bin
OS=$(shell uname -s)

.PHONY: all build clean

Comment on lines +6 to +7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add banner to .PHONY so it always runs
The banner target isn’t declared phony, so if a file named banner exists, Make will skip it. Including it in .PHONY ensures the ASCII art always prints.

-.PHONY: all build clean
+.PHONY: all banner build clean
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.PHONY: all build clean
.PHONY: all banner build clean

all: banner build

banner:
@echo "\033[0;32m"
@echo " __ _ _ ___ _ "
@echo " / _|_ _ _ _ | | | | _ \ | "
@echo " | _| || | ' \\| |__| | / |__ "
@echo " |_| \\_,_|_||_|____|_|_|_\\____|"
@echo "\033[0m"
@echo "A Swiss Army Knife for URLs"
@echo ""

build:
@echo "Building $(BINARY_NAME) for $(OS)..."
ifeq ($(OS), Windows_NT)
GOOS=windows GOARCH=amd64 go build -o $(BINARY_NAME).exe cmd/main.go
else ifeq ($(OS), Linux)
GOOS=linux GOARCH=amd64 go build -o $(BINARY_NAME) cmd/main.go
else ifeq ($(OS), Darwin)
GOOS=darwin GOARCH=amd64 go build -o $(BINARY_NAME) cmd/main.go
else
@echo "Unsupported OS: $(OS)"
exit 1
endif

clean:
@echo "Cleaning up..."
ifeq ($(OS), Windows_NT)
@rm -f $(BINARY_NAME).exe
else
@rm -f $(BINARY_NAME)
endif
@echo "Done."
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<img src="https://madewithlove.now.sh/af?text=Happy+Hackking+Space" alt="Made with love in Happy Hackking Space">

# funURL

<img src="img/image.png"> <br>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add descriptive alt text for the inline illustration
The <img src="img/image.png"> lacks alt text, which is important for accessibility and linting (MD045).

-<img src="img/image.png"> <br>
+<img src="img/image.png" alt="funURL usage illustration"> <br>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<img src="img/image.png"> <br>
<img src="img/image.png" alt="funURL usage illustration"> <br>
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

5-5: Images should have alternate text (alt text)
null

(MD045, no-alt-text)

funURL is a command-line tool designed as a Swiss Army knife for URLs. It takes a URL as input (via stdin, command-line flags, or arguments) and provides a range of operations for parsing, validation, modification, encoding/decoding, and handling URLs efficiently.

## Requirements

- Golang 1.18+

## Installation

```bash
Expand Down Expand Up @@ -113,4 +121,5 @@ funURL modify -c https -p /new/path http://vulnerabletarget.com/old
Hack! don't forget to follow [CONTRIBUTING](./CONTRIBUTING)

---
Happy Hacking!

<img src="img/hhs.svg" alt="Made with love in Happy Hackking Space">
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ module HappyHackingSpace/funURL

go 1.24.1

require github.com/spf13/cobra v1.9.1
require (
github.com/fatih/color v1.18.0
github.com/spf13/cobra v1.9.1
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/spf13/pflag v1.0.6 // indirect
golang.org/x/sys v0.25.0 // indirect
)
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
1 change: 1 addition & 0 deletions img/hhs.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 0 additions & 101 deletions install.sh

This file was deleted.

37 changes: 28 additions & 9 deletions internal/cli/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ var decodeCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
urlString, _ := cmd.Flags().GetString("url")
component, _ := cmd.Flags().GetBool("component")
doubled, _ := cmd.Flags().GetBool("double")
if urlString != "" {
decodeURL(urlString, component)
decodeURL(urlString, component, doubled)
} else if len(args) > 0 {
decodeURL(args[0], component)
decodeURL(args[0], component, doubled)
} else {
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
input := strings.TrimSpace(scanner.Text())
decodeURL(input, component)
decodeURL(input, component, doubled)
} else {
fmt.Println("Error: No input provided")
os.Exit(1)
Expand All @@ -36,19 +37,37 @@ var decodeCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(decodeCmd)
decodeCmd.Flags().BoolP("component", "c", false, "Use QueryUnescape instead of PathUnescape (for query components)")
decodeCmd.Flags().BoolP("double", "d", false, "Use double decoding")
}

func decodeURL(input string, component bool) {
func decodeURL(input string, component bool, doubled bool) {
var decoded string
var err error
if component {
if doubled {
// First decode
decoded, err = url.QueryUnescape(input)
if err != nil {
fmt.Fprintf(os.Stderr, "Error decoding URL (1st pass): %v\n", err)
os.Exit(1)
}
// Second decode
decoded, err = url.QueryUnescape(decoded)
if err != nil {
fmt.Fprintf(os.Stderr, "Error decoding URL (2nd pass): %v\n", err)
os.Exit(1)
}
} else if component {
decoded, err = url.QueryUnescape(input)
if err != nil {
fmt.Fprintf(os.Stderr, "Error decoding query component: %v\n", err)
os.Exit(1)
}
} else {
decoded, err = url.PathUnescape(input)
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error decoding URL: %v\n", err)
os.Exit(1)
if err != nil {
fmt.Fprintf(os.Stderr, "Error decoding path: %v\n", err)
os.Exit(1)
}
}
fmt.Println(decoded)
}
13 changes: 9 additions & 4 deletions internal/cli/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ var encodeCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
urlString, _ := cmd.Flags().GetString("url")
component, _ := cmd.Flags().GetBool("component")
doubled, _ := cmd.Flags().GetBool("double")

if urlString != "" {
encodeURL(urlString, component)
encodeURL(urlString, component, doubled)
} else if len(args) > 0 {
encodeURL(args[0], component)
encodeURL(args[0], component, doubled)
} else {
scanner := bufio.NewScanner(os.Stdin)
if scanner.Scan() {
input := strings.TrimSpace(scanner.Text())
encodeURL(input, component)
encodeURL(input, component, doubled)
} else {
fmt.Println("Error: No input provided")
os.Exit(1)
Expand All @@ -36,13 +38,16 @@ var encodeCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(encodeCmd)
encodeCmd.Flags().BoolP("component", "c", false, "Use QueryEscape instead of PathEscape (for query components)")
encodeCmd.Flags().BoolP("double", "d", false, "Use double encoding")
}

func encodeURL(input string, component bool) {
func encodeURL(input string, component bool, doubled bool) {
var encoded string

if component {
encoded = url.QueryEscape(input)
} else if doubled {
encoded = url.QueryEscape(url.QueryEscape(input))
} else {
encoded = url.PathEscape(input)
}
Expand Down
25 changes: 21 additions & 4 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,36 @@ package cli

import (
"os"
"github.com/spf13/cobra"
"fmt"
"github.com/fatih/color"
)

"github.com/spf13/cobra"
)


var rootCmd = &cobra.Command{
Use: "funURL",
Short: "A Swiss Army Knife for URLs",
Long: `funURL is a command-line tool designed as a Swiss Army knife for URL.
Long: GetBanner() + `
funURL is a command-line tool designed as a Swiss Army knife for URL.
It takes a URL as input (via stdin, command-line flags, or arguments) and provides
a range of operations for parsing, validation, modification, encoding/decoding,
and handling URLs efficiently.`,
}

func GetBanner() string {
green := color.New(color.FgGreen).SprintFunc()
reset := color.New(color.Reset).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
fmt.Println(reset(`
__ _ _ ___ _
/ _|_ _ _ _ | | | | _ \ |
| _| || | ' \| |__| | / |__
|_| \_,_|_||_|____|_|_|_\____|`))
fmt.Printf(" %s <3 %s \n", green("A Swiss Army Knife for URLs"), red("@HappyHackingSpace"))
fmt.Println(reset(""))
return ""
}
Comment on lines +21 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve function naming and consider environment detection.

The function name GetBanner() suggests it returns the banner as a string, but it actually prints to stdout and returns an empty string.

Consider these improvements:

  1. Rename the function to PrintBanner() to match its behavior
  2. Add terminal detection to avoid printing in non-interactive environments
-func GetBanner() string {
+func PrintBanner() {
	green := color.New(color.FgGreen).SprintFunc()
	reset := color.New(color.Reset).SprintFunc()
	red := color.New(color.FgRed).SprintFunc()
+	
+	// Skip banner in non-interactive environments
+	if fileInfo, _ := os.Stdout.Stat(); (fileInfo.Mode() & os.ModeCharDevice) == 0 {
+		return
+	}
+	
	fmt.Println(reset(`
   __           _    _ ___ _    
  / _|_  _ _ _ | |  | | _ \ |   
 |  _| || | ' \| |__| |   / |__ 
 |_|  \_,_|_||_|____|_|_|_\____|`))
	fmt.Printf(" %s <3 %s \n", green("A Swiss Army Knife for URLs"), red("@HappyHackingSpace"))
	fmt.Println(reset(""))	
-	return ""
}

Committable suggestion skipped: line range outside the PR's diff.


func Execute() {
err := rootCmd.Execute()
if err != nil {
Expand Down