From 54e67e3c8d49cad1e243ab8e4fa84d007f3ad29b Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Fri, 24 Jan 2025 13:51:15 +0530 Subject: [PATCH 1/4] fix to match string in set domain --- hossted/setDomain.go | 65 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/hossted/setDomain.go b/hossted/setDomain.go index f718557..3dbf3a2 100644 --- a/hossted/setDomain.go +++ b/hossted/setDomain.go @@ -1,8 +1,8 @@ package hossted import ( + "bufio" "context" - "errors" "fmt" "log" "net/http" @@ -196,30 +196,67 @@ func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) er return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) } -func ChangeMOTD(domain string) error { - filepath := "/etc/motd" +// ChangeMOTD updates the domain in lines that contain "is", "available", and "under" and have a URL or a plain domain. +func ChangeMOTD(newDomain string) error { + // Hardcoded file path + filePath := "/etc/motd" - // Read the file - b, err := readProtected(filepath) + // Open the file for reading + file, err := os.Open(filePath) if err != nil { - return fmt.Errorf("unable to read the /etc/motd file. Please check %s and contact administrator: %w", filepath, err) + return fmt.Errorf("failed to open file: %w", err) } - content := string(b) + defer file.Close() - // Match and update any URL that starts with https:// followed by a domain - re := regexp.MustCompile(`https://[\w\.\-]+\.\w+`) - updatedContent := re.ReplaceAllString(content, fmt.Sprintf("https://%s", domain)) + // Prepare to read the file line by line + var updatedLines []string + scanner := bufio.NewScanner(file) - if updatedContent == content { - return errors.New("no matching pattern found in /etc/motd. Please ensure the content is formatted correctly") + // Regex to match URLs and plain domains (e.g., abc.com, xyz.io, example.dev) + re := regexp.MustCompile(`https?://\S+|[a-zA-Z0-9.-]+\.(com|io|dev)`) + + // Process each line + for scanner.Scan() { + line := scanner.Text() + + // Check if the line contains "is", "available", and "under" + if strings.Contains(line, "is") && strings.Contains(line, "available") && strings.Contains(line, "under") { + // If the regex matches, replace the URL or domain + if re.MatchString(line) { + line = re.ReplaceAllString(line, newDomain) + } + } + + updatedLines = append(updatedLines, line) + } + + // Check for scanner errors + if err := scanner.Err(); err != nil { + return fmt.Errorf("failed to read file: %w", err) } // Write the updated content back to the file - err = writeProtected(filepath, []byte(updatedContent)) + file, err = os.Create(filePath) + if err != nil { + return fmt.Errorf("failed to open file for writing: %w", err) + } + defer file.Close() + + writer := bufio.NewWriter(file) + for _, line := range updatedLines { + _, err := writer.WriteString(line + "\n") + if err != nil { + return fmt.Errorf("failed to write to file: %w", err) + } + } + + // Flush the writer to ensure all content is written + err = writer.Flush() if err != nil { - return fmt.Errorf("failed to write to the /etc/motd file: %w", err) + return fmt.Errorf("failed to flush content to file: %w", err) } + fmt.Println("Successfully updated the MOTD file.") return nil } From abcb28cf98644ddac267f345944d997d38d3c897 Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Fri, 24 Jan 2025 15:01:22 +0530 Subject: [PATCH 2/4] update regex --- hossted/setDomain.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hossted/setDomain.go b/hossted/setDomain.go index 3dbf3a2..e3c2a08 100644 --- a/hossted/setDomain.go +++ b/hossted/setDomain.go @@ -196,6 +196,7 @@ func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) er return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) } +// ChangeMOTD updates the domain in lines that contain "is", "available", and "under" and have a URL or a plain domain. // ChangeMOTD updates the domain in lines that contain "is", "available", and "under" and have a URL or a plain domain. func ChangeMOTD(newDomain string) error { // Hardcoded file path @@ -212,8 +213,8 @@ func ChangeMOTD(newDomain string) error { var updatedLines []string scanner := bufio.NewScanner(file) - // Regex to match URLs and plain domains (e.g., abc.com, xyz.io, example.dev) - re := regexp.MustCompile(`https?://\S+|[a-zA-Z0-9.-]+\.(com|io|dev)`) + // Regex to match URLs and domains with optional paths (e.g., abc.com/guacamole) + re := regexp.MustCompile(`(https?://[a-zA-Z0-9.-]+\.(com|io|dev)(/[^\s]*)?|[a-zA-Z0-9.-]+\.(com|io|dev)(/[^\s]*)?)`) // Process each line for scanner.Scan() { @@ -221,10 +222,15 @@ func ChangeMOTD(newDomain string) error { // Check if the line contains "is", "available", and "under" if strings.Contains(line, "is") && strings.Contains(line, "available") && strings.Contains(line, "under") { - // If the regex matches, replace the URL or domain - if re.MatchString(line) { - line = re.ReplaceAllString(line, newDomain) - } + // If the regex matches, replace the domain and retain the path + line = re.ReplaceAllStringFunc(line, func(match string) string { + // Extract the path (if any) and append it to the new domain + matches := re.FindStringSubmatch(match) + if len(matches) > 4 && matches[5] != "" { // If there's a path, retain it + return newDomain + matches[5] + } + return newDomain + }) } updatedLines = append(updatedLines, line) From 0b02bb9afd9b6cabe5757baee9a498a1261b67ec Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Tue, 28 Jan 2025 00:36:31 +0530 Subject: [PATCH 3/4] update logic for set domain --- hossted/setDomain.go | 167 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 14 deletions(-) diff --git a/hossted/setDomain.go b/hossted/setDomain.go index e3c2a08..71caf7b 100644 --- a/hossted/setDomain.go +++ b/hossted/setDomain.go @@ -7,7 +7,6 @@ import ( "log" "net/http" "os" - "os/exec" "path/filepath" "regexp" "strings" @@ -102,11 +101,6 @@ func SetDomain(env, app, domain string) error { return fmt.Errorf("\n\n%w", err) } - err = ChangeMOTD(domain) - if err != nil { - return err - } - check := verifyInputFormat(domain, "domain") if !check { return fmt.Errorf("invalid domain input. Expecting domain name (e.g. example.com). input - %s", domain) @@ -118,16 +112,42 @@ func SetDomain(env, app, domain string) error { return err } - // Use sed to change the domain - // TODO: check if the line really exists in the file first - fmt.Println("Changing settings...") - text := fmt.Sprintf("s/(PROJECT_BASE_URL=)(.*)/\\1%s/", domain) - cmd := exec.Command("sudo", "sed", "-i", "-E", text, envPath) - _, err = cmd.Output() + // Read the existing PROJECT_BASE_URL + existingDomain, err := GetProjectBaseURL(envPath) if err != nil { - return err + return fmt.Errorf("error reading PROJECT_BASE_URL: %v", err) + } + + fmt.Println("Current PROJECT_BASE_URL:", existingDomain) + + // Update the PROJECT_BASE_URL with a new domain + //newDomain := "new-domain.com" + err = UpdateProjectBaseURL(envPath, domain) + if err != nil { + return fmt.Errorf("error updating PROJECT_BASE_URL: %v", err) + } + + // Update the MOTD file with the new domain + err = UpdateMOTD(existingDomain, domain) + if err != nil { + return fmt.Errorf("error updating MOTD: %v", err) } + // // Use sed to change the domain + // // TODO: check if the line really exists in the file first + // fmt.Println("Changing settings...") + // text := fmt.Sprintf("s/(PROJECT_BASE_URL=)(.*)/\\1%s/", domain) + // cmd := exec.Command("sudo", "sed", "-i", "-E", text, envPath) + // _, err = cmd.Output() + // if err != nil { + // return err + // } + + // err = ChangeMOTD(domain) + // if err != nil { + // return err + // } + // Try command fmt.Println("Stopping traefik...") err = stopTraefik(appDir) @@ -196,7 +216,6 @@ func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) er return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) } -// ChangeMOTD updates the domain in lines that contain "is", "available", and "under" and have a URL or a plain domain. // ChangeMOTD updates the domain in lines that contain "is", "available", and "under" and have a URL or a plain domain. func ChangeMOTD(newDomain string) error { // Hardcoded file path @@ -335,3 +354,123 @@ func getProjectName() (string, error) { } return "", nil } + +// GetProjectBaseURL reads the PROJECT_BASE_URL value from the .env file. +func GetProjectBaseURL(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", fmt.Errorf("failed to open .env file: %w", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "PROJECT_BASE_URL=") { + // Extract and return the value after "PROJECT_BASE_URL=" + return strings.TrimPrefix(line, "PROJECT_BASE_URL="), nil + } + } + + if err := scanner.Err(); err != nil { + return "", fmt.Errorf("failed to read .env file: %w", err) + } + + return "", fmt.Errorf("PROJECT_BASE_URL not found in .env file") +} + +// UpdateProjectBaseURL updates the PROJECT_BASE_URL value in the .env file while preserving any existing path. +func UpdateProjectBaseURL(filePath, newDomain string) error { + // Open the .env file for reading + file, err := os.Open(filePath) + if err != nil { + return fmt.Errorf("failed to open .env file: %w", err) + } + defer file.Close() + + var updatedLines []string + scanner := bufio.NewScanner(file) + updated := false + + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "PROJECT_BASE_URL=") { + // Extract the existing value of PROJECT_BASE_URL + existingDomain := strings.TrimPrefix(line, "PROJECT_BASE_URL=") + + // Use preservePath to update the domain while retaining the path + updatedDomain := preservePath(existingDomain, newDomain) + line = fmt.Sprintf("PROJECT_BASE_URL=%s", updatedDomain) + updated = true + } + updatedLines = append(updatedLines, line) + } + + if err := scanner.Err(); err != nil { + return fmt.Errorf("failed to read .env file: %w", err) + } + + if !updated { + return fmt.Errorf("PROJECT_BASE_URL not found in .env file") + } + + // Write the updated content back to the file + err = os.WriteFile(filePath, []byte(strings.Join(updatedLines, "\n")+"\n"), 0644) + if err != nil { + return fmt.Errorf("failed to write updated .env file: %w", err) + } + + fmt.Println("Successfully updated PROJECT_BASE_URL in .env file.") + return nil +} + +// UpdateMOTD searches for the existing domain in the MOTD file and replaces it with the new domain, preserving paths. +func UpdateMOTD(existingDomain, newDomain string) error { + const motdFilePath = "/etc/motd" + + // Open the MOTD file for reading + file, err := os.Open(motdFilePath) + if err != nil { + return fmt.Errorf("failed to open MOTD file: %w", err) + } + defer file.Close() + + var updatedLines []string + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + line := scanner.Text() + + // Check if the line contains the existing domain + if strings.Contains(line, existingDomain) { + // Replace only the domain part, preserving any path + line = strings.ReplaceAll(line, existingDomain, preservePath(existingDomain, newDomain)) + } + + updatedLines = append(updatedLines, line) + } + + if err := scanner.Err(); err != nil { + return fmt.Errorf("failed to read MOTD file: %w", err) + } + + // Write the updated content back to the MOTD file + err = os.WriteFile(motdFilePath, []byte(strings.Join(updatedLines, "\n")+"\n"), 0644) + if err != nil { + return fmt.Errorf("failed to write updated MOTD file: %w", err) + } + + fmt.Println("Successfully updated the MOTD file.") + return nil +} + +// preservePath replaces the domain in a URL while preserving the path. +func preservePath(existingDomain, newDomain string) string { + // Check if the existing domain contains a path + if idx := strings.Index(existingDomain, "/"); idx != -1 { + // Extract the path and append it to the new domain + return newDomain + existingDomain[idx:] + } + // If no path exists, just return the new domain + return newDomain +} From 5a8553f7158ccfbfaa4d7a32ed8970951f14d78b Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Tue, 28 Jan 2025 00:42:50 +0530 Subject: [PATCH 4/4] update comments --- hossted/setDomain.go | 85 -------------------------------------------- 1 file changed, 85 deletions(-) diff --git a/hossted/setDomain.go b/hossted/setDomain.go index 71caf7b..8eca15a 100644 --- a/hossted/setDomain.go +++ b/hossted/setDomain.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "path/filepath" - "regexp" "strings" "github.com/hossted/cli/hossted/service/compose" @@ -133,21 +132,6 @@ func SetDomain(env, app, domain string) error { return fmt.Errorf("error updating MOTD: %v", err) } - // // Use sed to change the domain - // // TODO: check if the line really exists in the file first - // fmt.Println("Changing settings...") - // text := fmt.Sprintf("s/(PROJECT_BASE_URL=)(.*)/\\1%s/", domain) - // cmd := exec.Command("sudo", "sed", "-i", "-E", text, envPath) - // _, err = cmd.Output() - // if err != nil { - // return err - // } - - // err = ChangeMOTD(domain) - // if err != nil { - // return err - // } - // Try command fmt.Println("Stopping traefik...") err = stopTraefik(appDir) @@ -216,75 +200,6 @@ func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) er return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) } -// ChangeMOTD updates the domain in lines that contain "is", "available", and "under" and have a URL or a plain domain. -func ChangeMOTD(newDomain string) error { - // Hardcoded file path - filePath := "/etc/motd" - - // Open the file for reading - file, err := os.Open(filePath) - if err != nil { - return fmt.Errorf("failed to open file: %w", err) - } - defer file.Close() - - // Prepare to read the file line by line - var updatedLines []string - scanner := bufio.NewScanner(file) - - // Regex to match URLs and domains with optional paths (e.g., abc.com/guacamole) - re := regexp.MustCompile(`(https?://[a-zA-Z0-9.-]+\.(com|io|dev)(/[^\s]*)?|[a-zA-Z0-9.-]+\.(com|io|dev)(/[^\s]*)?)`) - - // Process each line - for scanner.Scan() { - line := scanner.Text() - - // Check if the line contains "is", "available", and "under" - if strings.Contains(line, "is") && strings.Contains(line, "available") && strings.Contains(line, "under") { - // If the regex matches, replace the domain and retain the path - line = re.ReplaceAllStringFunc(line, func(match string) string { - // Extract the path (if any) and append it to the new domain - matches := re.FindStringSubmatch(match) - if len(matches) > 4 && matches[5] != "" { // If there's a path, retain it - return newDomain + matches[5] - } - return newDomain - }) - } - - updatedLines = append(updatedLines, line) - } - - // Check for scanner errors - if err := scanner.Err(); err != nil { - return fmt.Errorf("failed to read file: %w", err) - } - - // Write the updated content back to the file - file, err = os.Create(filePath) - if err != nil { - return fmt.Errorf("failed to open file for writing: %w", err) - } - defer file.Close() - - writer := bufio.NewWriter(file) - for _, line := range updatedLines { - _, err := writer.WriteString(line + "\n") - if err != nil { - return fmt.Errorf("failed to write to file: %w", err) - } - } - - // Flush the writer to ensure all content is written - err = writer.Flush() - if err != nil { - return fmt.Errorf("failed to flush content to file: %w", err) - } - - fmt.Println("Successfully updated the MOTD file.") - return nil -} - // CheckHosstedAuthFiles checks if the files ~/.hossted/auth.json and ~/.hossted/authresp.json exist. func CheckHosstedAuthFiles() error { // Get the home directory