2023-01-19 20:42:46 +05:30
|
|
|
package pages
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"regexp"
|
|
|
|
"runtime"
|
2023-07-14 15:54:20 +05:30
|
|
|
"sort"
|
2023-01-23 20:30:41 +05:30
|
|
|
"strconv"
|
2023-01-19 20:42:46 +05:30
|
|
|
"strings"
|
2023-07-11 02:53:29 +05:30
|
|
|
|
2024-09-28 23:41:58 +05:30
|
|
|
log "log/slog"
|
|
|
|
|
2023-07-11 02:53:29 +05:30
|
|
|
"github.com/ProjectSegfault/publapi/utils"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"github.com/spf13/viper"
|
2023-01-19 20:42:46 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
type Userstruct struct {
|
|
|
|
Status int `json:"status"`
|
|
|
|
Online int `json:"online"`
|
|
|
|
Total int `json:"total"`
|
|
|
|
Users []Userinfo `json:"users"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Userinfo struct {
|
2023-01-21 16:55:08 +05:30
|
|
|
Name string `json:"name"`
|
|
|
|
FullName string `json:"fullName"`
|
|
|
|
Desc string `json:"desc"`
|
|
|
|
Online bool `json:"online"`
|
2023-01-23 19:30:34 +05:30
|
|
|
Op bool `json:"op"`
|
2023-01-23 20:30:41 +05:30
|
|
|
Created int `json:"created"`
|
2023-01-21 16:55:08 +05:30
|
|
|
Email string `json:"email"`
|
|
|
|
Matrix string `json:"matrix"`
|
|
|
|
Fediverse string `json:"fediverse"`
|
|
|
|
Website string `json:"website"`
|
|
|
|
Capsule string `json:"capsule"`
|
|
|
|
Loc string `json:"loc"`
|
2023-01-19 20:42:46 +05:30
|
|
|
}
|
|
|
|
|
2023-07-14 15:54:20 +05:30
|
|
|
type ByAdminAndName []Userinfo
|
|
|
|
|
|
|
|
func (a ByAdminAndName) Len() int { return len(a) }
|
|
|
|
func (a ByAdminAndName) Less(i, j int) bool {
|
|
|
|
// If one person is an admin and the other is not, place the admin first
|
|
|
|
if a[i].Op && !a[j].Op {
|
|
|
|
return true
|
|
|
|
} else if !a[i].Op && a[j].Op {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// If both persons are admins or both are not, sort by name
|
|
|
|
return a[i].Name < a[j].Name
|
|
|
|
}
|
|
|
|
func (a ByAdminAndName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
|
2024-09-28 23:41:58 +05:30
|
|
|
func UserError(message string, username string, err error) {
|
|
|
|
log.Error("error", message, log.Any("err", err), "username", username)
|
|
|
|
}
|
|
|
|
|
2023-01-23 19:30:34 +05:30
|
|
|
func userdata(username, usersonline, ops string) Userinfo {
|
2023-01-19 20:42:46 +05:30
|
|
|
regex := "(^| )" + username + "($| )"
|
|
|
|
isonline, err := regexp.MatchString(string(regex), string(usersonline))
|
|
|
|
if err != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
UserError("couldn't get online status for user", username, err)
|
2023-01-19 20:42:46 +05:30
|
|
|
}
|
2023-01-23 20:23:05 +05:30
|
|
|
isop, operr := regexp.MatchString(string(regex), string(ops))
|
|
|
|
if operr != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
UserError("couldn't get op status for user", username, operr)
|
2023-01-23 20:23:05 +05:30
|
|
|
}
|
|
|
|
cmd := "/usr/bin/stat -c %W /home/" + username
|
|
|
|
crd, crerr := exec.Command("bash", "-c", cmd).Output()
|
|
|
|
if crerr != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
UserError("couldn't stat user", username, crerr)
|
2023-01-23 20:23:05 +05:30
|
|
|
}
|
|
|
|
crdstr := string(crd)
|
2023-01-23 20:30:41 +05:30
|
|
|
crdstr = strings.TrimSuffix(crdstr, "\n")
|
2023-02-26 20:46:38 +05:30
|
|
|
filename := "/home/" + username + "/meta-info.toml"
|
2023-01-23 20:23:05 +05:30
|
|
|
_, error := os.Stat(filename)
|
2023-01-19 20:42:46 +05:30
|
|
|
if error != nil {
|
|
|
|
if os.IsNotExist(error) {
|
2023-02-26 20:46:38 +05:30
|
|
|
log.Error(username + " does not have a meta-info.toml")
|
2023-01-19 20:42:46 +05:30
|
|
|
var user Userinfo
|
|
|
|
user.Name = username
|
2023-01-23 20:30:41 +05:30
|
|
|
user.Created, _ = strconv.Atoi(crdstr)
|
2024-09-28 23:41:58 +05:30
|
|
|
if isonline {
|
2023-01-19 20:42:46 +05:30
|
|
|
user.Online = true
|
|
|
|
} else {
|
|
|
|
user.Online = false
|
|
|
|
}
|
2024-09-28 23:41:58 +05:30
|
|
|
if isop {
|
2023-01-23 19:30:34 +05:30
|
|
|
user.Op = true
|
|
|
|
} else {
|
|
|
|
user.Op = false
|
|
|
|
}
|
2023-01-19 20:42:46 +05:30
|
|
|
return user
|
|
|
|
}
|
|
|
|
}
|
|
|
|
viper.SetConfigFile(filename)
|
2024-09-28 21:28:17 +05:30
|
|
|
if err := viper.ReadInConfig(); err != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
log.Error("message", "Couldn't read a users meta-info.toml file.", "error", log.Any("err", err), "user", username)
|
2024-09-28 21:28:17 +05:30
|
|
|
user := Userinfo{
|
|
|
|
Name: username,
|
|
|
|
}
|
|
|
|
user.Created, _ = strconv.Atoi(crdstr)
|
|
|
|
if isonline {
|
|
|
|
user.Online = true
|
|
|
|
} else {
|
|
|
|
user.Online = false
|
|
|
|
}
|
|
|
|
if isop {
|
|
|
|
user.Op = true
|
|
|
|
} else {
|
|
|
|
user.Op = false
|
|
|
|
}
|
|
|
|
return user
|
|
|
|
}
|
2023-01-19 20:42:46 +05:30
|
|
|
var user Userinfo
|
2023-02-26 21:21:10 +05:30
|
|
|
user = Userinfo{}
|
2023-01-19 20:42:46 +05:30
|
|
|
user.Name = username
|
2023-01-23 20:30:41 +05:30
|
|
|
user.Created, _ = strconv.Atoi(crdstr)
|
2023-02-26 20:46:38 +05:30
|
|
|
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")
|
2024-09-28 23:41:58 +05:30
|
|
|
if isop {
|
2023-01-23 19:30:34 +05:30
|
|
|
user.Op = true
|
|
|
|
} else {
|
|
|
|
user.Op = false
|
|
|
|
}
|
2024-09-28 23:41:58 +05:30
|
|
|
if isonline {
|
2023-01-19 20:42:46 +05:30
|
|
|
user.Online = true
|
|
|
|
} else {
|
|
|
|
user.Online = false
|
|
|
|
}
|
|
|
|
return user
|
|
|
|
}
|
|
|
|
|
|
|
|
func UsersPage(c *fiber.Ctx) error {
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
return c.JSON(fiber.Map{
|
|
|
|
"message": "/users is not supported on Windows",
|
|
|
|
"status": c.Response().StatusCode(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
// Get the number of users online
|
|
|
|
usersonline, err := exec.Command("bash", "-c", "/usr/bin/users").Output()
|
|
|
|
if err != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
log.Error("error", log.Any("error", err))
|
2023-01-19 20:42:46 +05:30
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
usersonlinestr := string(usersonline)
|
|
|
|
usersonlinededup := utils.Dedup(usersonlinestr)
|
|
|
|
var output int
|
2023-01-21 17:13:29 +05:30
|
|
|
if strings.Contains(usersonlinededup, " ") {
|
|
|
|
outputa := int(strings.Count(usersonlinededup, " "))
|
|
|
|
output = outputa + 1
|
|
|
|
} else if usersonlinededup == "" {
|
|
|
|
output = 0
|
|
|
|
} else {
|
|
|
|
output = 1
|
|
|
|
}
|
2023-01-23 19:30:34 +05:30
|
|
|
// Get OPs
|
|
|
|
ops, opserr := exec.Command("bash", "-c", "/usr/bin/members sudo").Output()
|
|
|
|
if opserr != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
log.Error("couldn't get ops", "error", log.Any("err", err))
|
2023-01-23 19:30:34 +05:30
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
opstr := string(ops)
|
|
|
|
// Get all users
|
2023-01-19 20:42:46 +05:30
|
|
|
users, err2 := exec.Command("bash", "-c", "/usr/bin/ls /home").Output()
|
|
|
|
if err2 != nil {
|
2024-09-28 23:41:58 +05:30
|
|
|
log.Error("couldn't get all users", "error", log.Any("err", err2))
|
2023-01-19 20:42:46 +05:30
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
userstr := string(users)
|
|
|
|
userstr2 := strings.TrimSuffix(userstr, "\n")
|
|
|
|
usersarr := strings.Split(userstr2, "\n")
|
2023-01-23 19:30:34 +05:30
|
|
|
// Fill user info
|
2023-01-19 20:42:46 +05:30
|
|
|
var userinfostruct []Userinfo
|
|
|
|
for i := 0; i < len(usersarr); i++ {
|
|
|
|
uname := string(usersarr[i])
|
2023-07-11 02:53:29 +05:30
|
|
|
userinfostruct = append(
|
|
|
|
userinfostruct,
|
|
|
|
userdata(
|
|
|
|
uname,
|
|
|
|
strings.TrimSuffix(usersonlinededup, "\n"),
|
|
|
|
strings.TrimSuffix(opstr, "\n"),
|
|
|
|
),
|
|
|
|
)
|
2023-01-19 20:42:46 +05:30
|
|
|
}
|
2023-07-14 15:54:20 +05:30
|
|
|
sort.Sort(ByAdminAndName(userinfostruct))
|
2023-01-19 20:42:46 +05:30
|
|
|
data := Userstruct{
|
|
|
|
Status: c.Response().StatusCode(),
|
|
|
|
Online: output,
|
|
|
|
Users: userinfostruct,
|
|
|
|
Total: int(strings.Count(userstr, "\n")),
|
|
|
|
}
|
|
|
|
return c.JSON(data)
|
|
|
|
}
|