Skip to content
Merged
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
93 changes: 91 additions & 2 deletions hossted/setDomain.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ func SetDomain(env, app, domain string) error {
return fmt.Errorf("error updating MOTD: %v", err)
}

// Update the 404.html file with the new domain
err = Update404(existingDomain, domain)
if err != nil {
return fmt.Errorf("error updating 404.html: %v", err)
}

// Try command
fmt.Println("Stopping traefik...")
err = stopTraefik(appDir)
Expand Down Expand Up @@ -169,7 +175,7 @@ func SetDomain(env, app, domain string) error {

accessInfo := compose.GetAccessInfo("/opt/" + projectName + "/.env")

err = submitPatchRequest(osInfo, *accessInfo)
err = submitPatchRequest(osInfo, *accessInfo, domain)
if err != nil {
return fmt.Errorf("error submitting patch request %v", err)
}
Expand All @@ -180,21 +186,24 @@ func SetDomain(env, app, domain string) error {
}

// submitPatchRequest sends a PATCH request with VM info for marketplace setups.
func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) error {
func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo, domain string) error {
composeUrl := osInfo.HosstedApiUrl + "/compose/hosts/" + osInfo.OsUUID

type req struct {
UUID string `json:"uuid"` // Application UUID
OsUUID string `json:"osuuid"` // Operating System UUID
AccessInfo compose.AccessInfo `json:"access_info"` // Access information for the VM
Type string `json:"type"` // Type of the request, e.g., "vm"
URL string `json:"url"` // Updated url value

}

newReq := req{
UUID: osInfo.AppUUID,
OsUUID: osInfo.OsUUID,
AccessInfo: accessInfo,
Type: "vm",
URL: domain,
}

return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq)
Expand Down Expand Up @@ -389,3 +398,83 @@ func preservePath(existingDomain, newDomain string) string {
// If no path exists, just return the new domain
return newDomain
}

// Update404 searches for the existing domain in the 404.html file and replaces it with the new domain.
func Update404(existingDomain, newDomain string) error {
// Get the project name dynamically
projectName, err := getProjectName()
if err != nil {
return fmt.Errorf("error getting project name: %s", err)
}

// Construct the path to the 404.html file
error404FilePath := filepath.Join("/opt", projectName, "hossted", "error-pages", "404.html")

// Check if the file exists
if _, err := os.Stat(error404FilePath); os.IsNotExist(err) {
fmt.Printf("404.html file not found at %s, skipping update\n", error404FilePath)
return nil
}
Comment on lines +402 to +417
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add check for empty project name

The function correctly handles a non-existent 404.html file, but it doesn't handle the case where getProjectName() returns an empty string without an error (which can happen based on lines 272-275).

// Update404 searches for the existing domain in the 404.html file and replaces it with the new domain.
func Update404(existingDomain, newDomain string) error {
	// Get the project name dynamically
	projectName, err := getProjectName()
	if err != nil {
		return fmt.Errorf("error getting project name: %s", err)
	}

+	// Check if project name is empty
+	if projectName == "" {
+		fmt.Println("Project name is empty, skipping 404.html update")
+		return nil
+	}
+
	// Construct the path to the 404.html file
	error404FilePath := filepath.Join("/opt", projectName, "hossted", "error-pages", "404.html")


// Open the 404.html file for reading
file, err := os.Open(error404FilePath)
if err != nil {
return fmt.Errorf("failed to open 404.html file: %w", err)
}
defer file.Close()

var updatedLines []string
scanner := bufio.NewScanner(file)
updated := false

for scanner.Scan() {
line := scanner.Text()

// Check if the line contains the iframe src with url parameter
if strings.Contains(line, "url=https://") {
// Find the url parameter value and replace the domain
// Look for pattern like url=https://domain.example.com
start := strings.Index(line, "url=https://")
if start != -1 {
// Find the end of the domain (either & or " or end of string)
urlStart := start + len("url=https://")
end := urlStart
for end < len(line) && line[end] != '&' && line[end] != '"' && line[end] != ' ' {
end++
}

if end > urlStart {
oldURL := line[urlStart:end]
// Check if this URL contains our existing domain
if strings.Contains(oldURL, existingDomain) {
// Replace the domain while preserving the URL structure
newURL := strings.Replace(oldURL, existingDomain, newDomain, 1)
line = line[:urlStart] + newURL + line[end:]
updated = true
}
}
}
}

Comment on lines +430 to +458
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve URL parsing and domain replacement logic

The current implementation has some limitations when parsing and replacing domain names in URLs:

  1. It only handles "url=https://" and not "url=http://" links
  2. The URL boundary detection might miss some valid URL formats
  3. It only replaces the first occurrence of the domain in a URL
	for scanner.Scan() {
		line := scanner.Text()

-		// Check if the line contains the iframe src with url parameter
-		if strings.Contains(line, "url=https://") {
+		// Check if the line contains the iframe src with url parameter (both http and https)
+		if strings.Contains(line, "url=http") {
			// Find the url parameter value and replace the domain
-			// Look for pattern like url=https://domain.example.com
-			start := strings.Index(line, "url=https://")
+			// Look for pattern like url=https://domain.example.com or url=http://domain.example.com
+			start := -1
+			if strings.Contains(line, "url=https://") {
+				start = strings.Index(line, "url=https://")
+			} else if strings.Contains(line, "url=http://") {
+				start = strings.Index(line, "url=http://")
+			}
+			
			if start != -1 {
				// Find the end of the domain (either & or " or end of string)
-				urlStart := start + len("url=https://")
+				protocol := "http://"
+				if strings.Contains(line[start:start+12], "https") {
+					protocol = "https://"
+				}
+				urlStart := start + len("url=") + len(protocol)
				end := urlStart
				for end < len(line) && line[end] != '&' && line[end] != '"' && line[end] != ' ' {
					end++
				}

				if end > urlStart {
					oldURL := line[urlStart:end]
					// Check if this URL contains our existing domain
-					if strings.Contains(oldURL, existingDomain) {
+					// More precise check to ensure we're replacing domains, not substrings
+					domainStart := strings.Index(oldURL, existingDomain)
+					if domainStart != -1 && (domainStart == 0 || oldURL[domainStart-1] == '.' || oldURL[domainStart-1] == '/') {
						// Replace the domain while preserving the URL structure
						newURL := strings.Replace(oldURL, existingDomain, newDomain, 1)
						line = line[:urlStart] + newURL + line[end:]
						updated = true
					}
				}

updatedLines = append(updatedLines, line)
}

if err := scanner.Err(); err != nil {
return fmt.Errorf("failed to read 404.html file: %w", err)
}

if !updated {
// This might be okay if the domain wasn't found in this file
fmt.Println("Domain not found in 404.html file, no updates made")
return nil
}

// Write the updated content back to the file
err = os.WriteFile(error404FilePath, []byte(strings.Join(updatedLines, "\n")+"\n"), 0644)
if err != nil {
return fmt.Errorf("failed to write updated 404.html file: %w", err)
}

fmt.Println("Successfully updated the 404.html file.")
return nil
}