Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev to Main Sync #144

Merged
merged 8 commits into from
Jan 13, 2025
Merged
1 change: 1 addition & 0 deletions .github/workflows/aws-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,5 @@ jobs:
-e ALLOWED_ORIGINS=${{vars.ALLOWED_ORIGINS}} \
-e TOKEN_VALIDITY_IN_SECONDS=${{vars.TOKEN_VALIDITY_IN_SECONDS}} \
-e USER_MAX_URL_COUNT=${{vars.USER_MAX_URL_COUNT}} \
-e WEB_APP_BASE_URL=${{vars.WEB_APP_BASE_URL}} \
${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}
47 changes: 28 additions & 19 deletions config/core-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,40 @@ import (
)

var (
Env string
UserMaxUrlCount int
Domain string
AuthRedirectUrl string
DbUrl string
Env string
UserMaxUrlCount int
Domain string
AuthRedirectUrl string
DbUrl string
DbMaxOpenConnections int
GoogleClientId string
GoogleClientSecret string
GoogleRedirectUrl string
TokenValidity int
JwtSecret string
JwtValidity int
JwtIssuer string
AllowedOrigin string
Port string
GoogleClientId string
GoogleClientSecret string
GoogleRedirectUrl string
TokenValidity int
JwtSecret string
JwtValidity int
JwtIssuer string
AllowedOrigin string
Port string
WebAppBaseUrl string
)

func findAndLoadEnv(envFile string) {
func findAndLoadEnv(envFile string) error {
cwd, err := os.Getwd()
if err != nil {
logger.Fatal("Could not get current working directory:", err)
}

logger.Info("Starting search for .env file from:", cwd)

for {
envPath := filepath.Join(cwd, envFile)
if _, err := os.Stat(envPath); err == nil {
if err := godotenv.Load(envPath); err != nil {
logger.Fatal("Error loading .env file:", err)
logger.Error("Error loading .env file:", err)
}
logger.Info("Loaded environment variables from:", envPath)
return
return nil
}

parent := filepath.Dir(cwd)
Expand All @@ -51,7 +54,7 @@ func findAndLoadEnv(envFile string) {
cwd = parent
}

logger.Fatal("Could not find .env file at:", envFile)
return fmt.Errorf("could not find .env file: %s", envFile)
}

func loadEnv() {
Expand All @@ -65,7 +68,10 @@ func loadEnv() {
envFile = "environments/test.env"
}

findAndLoadEnv(envFile)
if err := findAndLoadEnv(envFile); err != nil {
logger.Error("Failed to load .env file:", err)
return
}
}

func init() {
Expand Down Expand Up @@ -103,12 +109,15 @@ func loadConfig() {

Port = getEnvVar("PORT")
JwtValidity = getEnvInt("JWT_VALIDITY_IN_HOURS")

WebAppBaseUrl = getEnvVar("WEB_APP_BASE_URL")
}

func getEnvVar(key string) string {
value := os.Getenv(key)
if value == "" {
logger.Fatal(fmt.Sprintf("Environment variable %s not set", key))
os.Exit(1)
}
return value
}
Expand Down
28 changes: 28 additions & 0 deletions controllers/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"net/http"
"net/url"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -92,12 +93,39 @@ func CreateTinyURL(ctx *gin.Context, db *bun.DB) {
return
}


if count >= config.UserMaxUrlCount {
ctx.JSON(http.StatusForbidden, dtos.URLCreationResponse{
Message: "You've reached the limit of " + strconv.Itoa(config.UserMaxUrlCount) + " for URLs. Delete one to add a new one !!",
})
return
}

parsedUrl,err := url.Parse(body.OriginalUrl);

if err != nil {
return
}

parseConfig,err := url.Parse(config.WebAppBaseUrl);

if err != nil {
return;
}

if strings.Contains(strings.ToLower(parsedUrl.Host),strings.ToLower(parseConfig.Host)) {

path :=parsedUrl.Path

if len(path) >=1 {

ctx.JSON(http.StatusForbidden, dtos.URLCreationResponse{
Message: "Cannot create a tiny url for " + config.WebAppBaseUrl,
})

return
}
}

newTinyURL := models.Tinyurl{
OriginalUrl: body.OriginalUrl,
Expand Down
41 changes: 31 additions & 10 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,38 @@ services:
target: final
ports:
- 4001:4001

# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
depends_on:
db:
condition: service_healthy
environment:
- DB_HOST=db
- DB_PORT=5432
- DB_USER=tinysite
- DB_PASSWORD=tinysite
- DB_NAME=tinysite
- JWT_SECRET=secret
- JWT_ISSUER=tinysite
- DOMAIN=localhost
- PORT=4001
- AUTH_REDIRECT_URL=http://localhost:4001/auth/callback
- DB_URL=postgres://tinysite:tinysite@db:5432/tinysite?sslmode=disable
- DB_MAX_OPEN_CONNECTIONS=20
- GOOGLE_CLIENT_ID=1234567890
- GOOGLE_CLIENT_SECRET=1234567890
- ALLOWED_ORIGINS=http://localhost:3000
- TOKEN_VALIDITY_IN_SECONDS=3600
- JWT_VALIDITY_IN_HOURS=1
- USER_MAX_URL_COUNT=100
- GOOGLE_REDIRECT_URL=http://localhost:4001/auth/callback
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
db:
image: postgres
user: postgres
Expand All @@ -45,15 +67,14 @@ services:
interval: 10s
timeout: 5s
retries: 5

adminer:
image: adminer
ports:
- 9091:8080

# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt

2 changes: 2 additions & 0 deletions environments/test.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ JWT_ISSUER="tiny-site-backend"
DOMAIN="localhost"
AUTH_REDIRECT_URL="http://localhost:3000"

WEB_APP_BASE_URL='http://localhost:3000'

DB_URL="postgresql://postgres:postgres@localhost:5432/tiny-site?sslmode=disable"
TEST_DB_URL="postgresql://postgres:postgres@localhost:5432/tiny-site-test?sslmode=disable"
DB_MAX_OPEN_CONNECTIONS=10
Expand Down
30 changes: 30 additions & 0 deletions tests/integration/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,33 @@ func (suite *AppTestSuite) TestGetURLDetailsSuccess() {
// Assert the status code is 200 for successful retrieval of URL details
assert.Equal(suite.T(), http.StatusOK, w.Code, "Expected status code to be 200 for successful retrieval of URL details")
}

//TestForbidTinyURLChaining forbids the creation of tiny url of existing tiny url
func (suite *AppTestSuite) TestForbidTinyURLChaining() {

router := gin.Default();

router.Use(func(ctx *gin.Context) {
ctx.Set("userID", int64(1))
ctx.Next()
})

router.POST("/v1/tinyurl", func(ctx *gin.Context) {
controller.CreateTinyURL(ctx, suite.db)
})

requestBody := map[string]interface{}{
"OriginalUrl": "https://localhost:3000/abcde",
"UserId": 1,
}

requestJSON, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", "/v1/tinyurl", bytes.NewBuffer(requestJSON))
req.Header.Set("Content-Type", "application/json")

w := httptest.NewRecorder()
router.ServeHTTP(w, req)

assert.Equal(suite.T(), http.StatusForbidden, w.Code, "Expected status code to be 403 for restricting chaining of tiny urls")

}
Loading