Add version lock to dockerfile and hide password

This commit is contained in:
Owen Schwartz 2025-01-12 10:39:27 -05:00
parent f5fda5d8ea
commit 84ee25e441
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
4 changed files with 72 additions and 25 deletions

View file

@ -1,6 +1,6 @@
services: services:
pangolin: pangolin:
image: fosrl/pangolin:latest image: fosrl/pangolin:{{.PangolinVersion}}
container_name: pangolin container_name: pangolin
restart: unless-stopped restart: unless-stopped
volumes: volumes:
@ -12,7 +12,7 @@ services:
retries: 5 retries: 5
gerbil: gerbil:
image: fosrl/gerbil:latest image: fosrl/gerbil:{{.GerbilVersion}}
container_name: gerbil container_name: gerbil
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:

View file

@ -1,3 +1,8 @@
module installer module installer
go 1.23.0 go 1.23.0
require (
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
)

View file

@ -0,0 +1,4 @@
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=

View file

@ -10,27 +10,37 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"syscall"
"text/template" "text/template"
"unicode" "unicode"
"golang.org/x/term"
) )
func loadVersions(config *Config) {
config.PangolinVersion = "1.0.0-beta.4"
config.GerbilVersion = "1.0.0-beta.1"
}
//go:embed fs/* //go:embed fs/*
var configFiles embed.FS var configFiles embed.FS
type Config struct { type Config struct {
BaseDomain string `yaml:"baseDomain"` PangolinVersion string
DashboardDomain string `yaml:"dashboardUrl"` GerbilVersion string
LetsEncryptEmail string `yaml:"letsEncryptEmail"` BaseDomain string
AdminUserEmail string `yaml:"adminUserEmail"` DashboardDomain string
AdminUserPassword string `yaml:"adminUserPassword"` LetsEncryptEmail string
DisableSignupWithoutInvite bool `yaml:"disableSignupWithoutInvite"` AdminUserEmail string
DisableUserCreateOrg bool `yaml:"disableUserCreateOrg"` AdminUserPassword string
EnableEmail bool `yaml:"enableEmail"` DisableSignupWithoutInvite bool
EmailSMTPHost string `yaml:"emailSMTPHost"` DisableUserCreateOrg bool
EmailSMTPPort int `yaml:"emailSMTPPort"` EnableEmail bool
EmailSMTPUser string `yaml:"emailSMTPUser"` EmailSMTPHost string
EmailSMTPPass string `yaml:"emailSMTPPass"` EmailSMTPPort int
EmailNoReply string `yaml:"emailNoReply"` EmailSMTPUser string
EmailSMTPPass string
EmailNoReply string
} }
func main() { func main() {
@ -45,6 +55,9 @@ func main() {
// check if there is already a config file // check if there is already a config file
if _, err := os.Stat("config/config.yml"); err != nil { if _, err := os.Stat("config/config.yml"); err != nil {
config := collectUserInput(reader) config := collectUserInput(reader)
loadVersions(&config)
if err := createConfigFiles(config); err != nil { if err := createConfigFiles(config); err != nil {
fmt.Printf("Error creating config files: %v\n", err) fmt.Printf("Error creating config files: %v\n", err)
os.Exit(1) os.Exit(1)
@ -82,6 +95,24 @@ func readString(reader *bufio.Reader, prompt string, defaultValue string) string
return input return input
} }
func readPassword(prompt string) string {
fmt.Print(prompt + ": ")
// Read password without echo
password, err := term.ReadPassword(int(syscall.Stdin))
fmt.Println() // Add a newline since ReadPassword doesn't add one
if err != nil {
return ""
}
input := strings.TrimSpace(string(password))
if input == "" {
return readPassword(prompt)
}
return input
}
func readBool(reader *bufio.Reader, prompt string, defaultValue bool) bool { func readBool(reader *bufio.Reader, prompt string, defaultValue bool) bool {
defaultStr := "no" defaultStr := "no"
if defaultValue { if defaultValue {
@ -114,16 +145,23 @@ func collectUserInput(reader *bufio.Reader) Config {
fmt.Println("\n=== Admin User Configuration ===") fmt.Println("\n=== Admin User Configuration ===")
config.AdminUserEmail = readString(reader, "Enter admin user email", "admin@"+config.BaseDomain) config.AdminUserEmail = readString(reader, "Enter admin user email", "admin@"+config.BaseDomain)
for { for {
config.AdminUserPassword = readString(reader, "Enter admin user password", "") pass1 := readPassword("Create admin user password")
if valid, message := validatePassword(config.AdminUserPassword); valid { pass2 := readPassword("Confirm admin user password")
break
if pass1 != pass2 {
fmt.Println("Passwords do not match")
} else { } else {
fmt.Println("Invalid password:", message) config.AdminUserPassword = pass1
fmt.Println("Password requirements:") if valid, message := validatePassword(config.AdminUserPassword); valid {
fmt.Println("- At least one uppercase English letter") break
fmt.Println("- At least one lowercase English letter") } else {
fmt.Println("- At least one digit") fmt.Println("Invalid password:", message)
fmt.Println("- At least one special character") fmt.Println("Password requirements:")
fmt.Println("- At least one uppercase English letter")
fmt.Println("- At least one lowercase English letter")
fmt.Println("- At least one digit")
fmt.Println("- At least one special character")
}
} }
} }