add error handling for reading configuration #1

Merged
arya merged 9 commits from odyseusz/publapi:master into master 2024-11-04 20:20:30 +05:30
3 changed files with 80 additions and 71 deletions
Showing only changes of commit 2f4cbc6e1e - Show all commits

View File

@ -14,40 +14,54 @@ import (
log "github.com/sirupsen/logrus"
)
// SignupPage is the signup page handler
type formValues struct {
Username string
Email string
SshPublicKey string
IPAddress string
CaptchaResponse string
}
type CaptchaResponse struct {
Success bool `json:"success"`
}
// SignupPage is the signup page handler
func SignupPage(c *fiber.Ctx) error {
SignupIP, SignupIPExists := os.LookupEnv("PUBLAPI_SIGNUP_IP")
if SignupIPExists == true {
if SignupIPExists {
if c.IP() != SignupIP {
log.Info("Request made from invalid IP: ", c.IP())
return c.SendStatus(fiber.StatusForbidden)
}
}
username := c.FormValue("username")
email := c.FormValue("email")
ssh := c.FormValue("ssh")
ip := c.FormValue("ip")
captchaResp := c.FormValue("h-captcha-response")
if captchaResp == "" {
formValues := formValues{
Username: c.FormValue("username"),
Email: c.FormValue("email"),
SshPublicKey: c.FormValue("ssh"),
IPAddress: c.FormValue("ip"),
CaptchaResponse: c.FormValue("h-captcha-response"),
}
if formValues.CaptchaResponse == "" {
log.Error("Nice try, but the registration won't work unless you answer the captcha.")
return c.SendStatus(fiber.StatusBadRequest)
}
if username == "" || email == "" || ssh == "" || ip == "" {
log.Error("username, email, ssh and ip must be filled", username, email, ssh, ip)
if formValues.Username == "" || formValues.Email == "" || formValues.SshPublicKey == "" || formValues.IPAddress == "" {
log.Error("username, email, ssh and ip must be filled", formValues.Username, formValues.Email, formValues.SshPublicKey, formValues.IPAddress)
return c.SendStatus(fiber.StatusBadRequest)
}
raid, ok := os.LookupEnv("PUBLAPI_RAID_MODE")
if !ok || raid == "1" {
log.Warn(
"PUBLAPI_RAID_MODE is on, accepting every request as OK and not doing anything...\n User info: ",
username,
formValues.Username,
" ",
email,
formValues.Email,
" ",
ip,
formValues.IPAddress,
" ",
)
return c.SendStatus(fiber.StatusOK)
@ -55,10 +69,10 @@ func SignupPage(c *fiber.Ctx) error {
// Check the captcha validation.
captchaSecret, ok := os.LookupEnv("PUBLAPI_CAPTCHA_SECRET")
captchaSecret, _ := os.LookupEnv("PUBLAPI_CAPTCHA_SECRET")
params := url.Values{}
params.Add("response", captchaResp)
params.Add("response", formValues.CaptchaResponse)
params.Add("secret", captchaSecret)
body := strings.NewReader(params.Encode())
@ -82,30 +96,27 @@ func SignupPage(c *fiber.Ctx) error {
sb := string(bod)
log.Info("Captcha response: ", sb)
type CaptchaResponse struct {
Success bool `json:"success"`
}
var captchaResponse CaptchaResponse
captchaResponse := CaptchaResponse{}
err = json.Unmarshal([]byte(sb), &captchaResponse)
if err != nil {
log.Error("Error unmarshalling captcha response", err)
}
if captchaResponse.Success == false {
if !captchaResponse.Success {
log.Error("Captcha validation failed")
return c.JSON(fiber.Map{
"username": username,
"message": "Sorry! But the captcha validation failed. Please try again.",
"username": formValues.CaptchaResponse,
"message": "Sorry, but the captcha validation failed. Please try again.",
"status": c.Response().StatusCode(),
})
} else {
// Check if user already exists
// We'll check the home folder and see if the username folder exists.
_, err := os.Stat("/home/" + username)
_, err := os.Stat("/home/" + formValues.Username)
if err == nil {
log.Error("User already exists : ", username)
log.Error("User already exists : ", formValues.Username)
return c.JSON(fiber.Map{
"username": username,
"username": formValues.Username,
"message": "User already exists. Please choose a different username.",
"status": c.Response().StatusCode(),
})
@ -113,28 +124,28 @@ func SignupPage(c *fiber.Ctx) error {
// create user file
f, err := os.Create("/var/publapi/users/" + username + ".sh")
f, err := os.Create("/var/publapi/users/" + formValues.Username + ".sh")
if err != nil {
log.Error("Error creating user file", err)
return c.SendStatus(fiber.StatusInternalServerError)
}
defer f.Close()
chmoderr := os.Chmod("/var/publapi/users/"+username+".sh", 0700)
chmoderr := os.Chmod("/var/publapi/users/"+formValues.Username+".sh", 0700)
if chmoderr != nil {
log.Error(err)
}
Bashscript := strings.ReplaceAll(utils.Bashscript, "{{sshkey}}", ssh)
Bashscript = strings.ReplaceAll(Bashscript, "{{email}}", email)
Bashscript = strings.ReplaceAll(Bashscript, "{{username}}", username)
bashScript := strings.ReplaceAll(utils.BashScript, "{{sshkey}}", formValues.SshPublicKey)
bashScript = strings.ReplaceAll(bashScript, "{{email}}", formValues.Email)
bashScript = strings.ReplaceAll(bashScript, "{{username}}", formValues.Username)
// write to file
_, err = f.WriteString(Bashscript)
_, err = f.WriteString(bashScript)
if err != nil {
log.Error("Error writing to user file", err)
return c.SendStatus(fiber.StatusInternalServerError)
}
log.Info(
"Registration request for " + username + " has been submitted by the frontend and has been written to /var/publapi/users/" + username + ".sh",
"Registration request for " + formValues.Username + " has been submitted by the frontend and has been written to /var/publapi/users/" + formValues.Username + ".sh",
)
// send notification to user that their reg request was sent
@ -150,14 +161,14 @@ func SignupPage(c *fiber.Ctx) error {
shoutrrrUrl := os.Getenv("PUBLAPI_NOTIFY_SHOUTRRRURL") + os.Getenv("PUBLAPI_NOTIFY_ROOMS")
err = shoutrrr.Send(
shoutrrrUrl,
"New user signup! Please review /var/publapi/users/"+username+".sh to approve or deny the user. IP: "+ip+" Email: "+email,
"New user signup! Please review /var/publapi/users/"+formValues.Username+".sh to approve or deny the user. IP: "+formValues.IPAddress+" Email: "+formValues.Email,
)
if err != nil {
log.Error("Error sending notification to admins", err)
//return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(fiber.Map{
"username": username,
"username": formValues.Username,
"message": "User created! Please allow us 24 hours or more to review your account.",
"status": c.Response().StatusCode(),
})

View File

@ -16,14 +16,14 @@ import (
"github.com/spf13/viper"
)
type Userstruct struct {
type UserStruct struct {
Status int `json:"status"`
Online int `json:"online"`
Total int `json:"total"`
Users []Userinfo `json:"users"`
Users []UserInfo `json:"users"`
}
type Userinfo struct {
type UserInfo struct {
Name string `json:"name"`
FullName string `json:"fullName"`
Desc string `json:"desc"`
@ -38,7 +38,7 @@ type Userinfo struct {
Loc string `json:"loc"`
}
type ByAdminAndName []Userinfo
type ByAdminAndName []UserInfo
func (a ByAdminAndName) Len() int { return len(a) }
func (a ByAdminAndName) Less(i, j int) bool {
@ -58,7 +58,7 @@ func UserError(message string, username string, err error) {
log.Error("error", message, log.Any("err", err), "username", username)
}
func userdata(username, usersonline, ops string) Userinfo {
func userData(username, usersonline, ops string) UserInfo {
regex := "(^| )" + username + "($| )"
isonline, err := regexp.MatchString(string(regex), string(usersonline))
if err != nil {
@ -80,7 +80,7 @@ func userdata(username, usersonline, ops string) Userinfo {
if error != nil {
if os.IsNotExist(error) {
log.Error(username + " does not have a meta-info.toml")
var user Userinfo
var user UserInfo
user.Name = username
user.Created, _ = strconv.Atoi(crdstr)
if isonline {
@ -99,7 +99,7 @@ func userdata(username, usersonline, ops string) Userinfo {
viper.SetConfigFile(filename)
if err := viper.ReadInConfig(); err != nil {
log.Error("message", "Couldn't read a users meta-info.toml file.", "error", log.Any("err", err), "user", username)
user := Userinfo{
user := UserInfo{
Name: username,
}
user.Created, _ = strconv.Atoi(crdstr)
@ -115,27 +115,25 @@ func userdata(username, usersonline, ops string) Userinfo {
}
return user
}
var user Userinfo
user = Userinfo{}
user.Name = username
user := UserInfo{
Name: username,
FullName: viper.GetString("fullname"),
Capsule: viper.GetString("gemini"),
Website: viper.GetString("website"),
Desc: viper.GetString("description"),
Email: viper.GetString("email"),
Matrix: viper.GetString("matrix"),
Fediverse: viper.GetString("fediverse"),
Loc: viper.GetString("location"),
Op: false,
Online: false,
}
user.Created, _ = strconv.Atoi(crdstr)
user.FullName = viper.GetString("fullname")
user.Capsule = viper.GetString("gemini")
user.Website = viper.GetString("website")
user.Desc = viper.GetString("description")
user.Email = viper.GetString("email")
user.Matrix = viper.GetString("matrix")
user.Fediverse = viper.GetString("fediverse")
user.Loc = viper.GetString("location")
if isop {
user.Op = true
} else {
user.Op = false
}
if isonline {
user.Online = true
} else {
user.Online = false
}
return user
}
@ -148,18 +146,18 @@ func UsersPage(c *fiber.Ctx) error {
})
}
// Get the number of users online
usersonline, err := exec.Command("bash", "-c", "/usr/bin/users").Output()
usersOnline, err := exec.Command("bash", "-c", "/usr/bin/users").Output()
if err != nil {
log.Error("error", log.Any("error", err))
return c.SendStatus(fiber.StatusInternalServerError)
}
usersonlinestr := string(usersonline)
usersonlinededup := utils.Dedup(usersonlinestr)
usersOnlineStr := string(usersOnline)
usersOnlineDedup := utils.Dedup(usersOnlineStr)
var output int
if strings.Contains(usersonlinededup, " ") {
outputa := int(strings.Count(usersonlinededup, " "))
if strings.Contains(usersOnlineDedup, " ") {
outputa := int(strings.Count(usersOnlineDedup, " "))
output = outputa + 1
} else if usersonlinededup == "" {
} else if usersOnlineDedup == "" {
output = 0
} else {
output = 1
@ -181,23 +179,23 @@ func UsersPage(c *fiber.Ctx) error {
userstr2 := strings.TrimSuffix(userstr, "\n")
usersarr := strings.Split(userstr2, "\n")
// Fill user info
var userinfostruct []Userinfo
var userInfoStruct []UserInfo
for i := 0; i < len(usersarr); i++ {
uname := string(usersarr[i])
userinfostruct = append(
userinfostruct,
userdata(
userInfoStruct = append(
userInfoStruct,
userData(
uname,
strings.TrimSuffix(usersonlinededup, "\n"),
strings.TrimSuffix(usersOnlineDedup, "\n"),
strings.TrimSuffix(opstr, "\n"),
),
)
}
sort.Sort(ByAdminAndName(userinfostruct))
data := Userstruct{
sort.Sort(ByAdminAndName(userInfoStruct))
data := UserStruct{
Status: c.Response().StatusCode(),
Online: output,
Users: userinfostruct,
Users: userInfoStruct,
Total: int(strings.Count(userstr, "\n")),
}
return c.JSON(data)

View File

@ -6,7 +6,7 @@ import (
)
//go:embed signup-script-template
var Bashscript string
var BashScript string
func Dedup(input string) string {
unique := []string{}