mirror of
https://github.com/ngoduykhanh/wireguard-ui.git
synced 2025-04-21 20:12:33 +03:00
Merge branch 'email-settings-UI' into email-settings-UI-old
This commit is contained in:
commit
10fc8903e4
16 changed files with 102 additions and 721 deletions
|
@ -78,34 +78,6 @@ function renderClientList(data) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderUserList(data) {
|
|
||||||
$.each(data, function(index, obj) {
|
|
||||||
let clientStatusHtml = '>'
|
|
||||||
|
|
||||||
// render user html content
|
|
||||||
let html = `<div class="col-sm-6 col-md-6 col-lg-4" id="user_${obj.username}">
|
|
||||||
<div class="info-box">
|
|
||||||
<div class="info-box-content">
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modal_edit_user" data-username="${obj.username}">Edit</button>
|
|
||||||
</div>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal"
|
|
||||||
data-target="#modal_remove_user" data-username="${obj.username}">Delete</button>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<span class="info-box-text"><i class="fas fa-user"></i> ${obj.username}</span>
|
|
||||||
<span class="info-box-text"><i class="fas fa-terminal"></i> ${obj.admin? 'Administrator':'Manager'}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`
|
|
||||||
|
|
||||||
// add the user html elements to the list
|
|
||||||
$('#users-list').append(html);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function prettyDateTime(timeStr) {
|
function prettyDateTime(timeStr) {
|
||||||
const dt = new Date(timeStr);
|
const dt = new Date(timeStr);
|
||||||
const offsetMs = dt.getTimezoneOffset() * 60 * 1000;
|
const offsetMs = dt.getTimezoneOffset() * 60 * 1000;
|
||||||
|
|
|
@ -42,54 +42,39 @@ func LoginPage() echo.HandlerFunc {
|
||||||
// Login for signing in handler
|
// Login for signing in handler
|
||||||
func Login(db store.IStore) echo.HandlerFunc {
|
func Login(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
data := make(map[string]interface{})
|
user := new(model.User)
|
||||||
err := json.NewDecoder(c.Request().Body).Decode(&data)
|
c.Bind(user)
|
||||||
|
|
||||||
if err != nil {
|
dbuser, err := db.GetUser()
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"})
|
|
||||||
}
|
|
||||||
|
|
||||||
username := data["username"].(string)
|
|
||||||
password := data["password"].(string)
|
|
||||||
rememberMe := data["rememberMe"].(bool)
|
|
||||||
|
|
||||||
dbuser, err := db.GetUserByName(username)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot query user from DB"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot query user from DB"})
|
||||||
}
|
}
|
||||||
|
|
||||||
userCorrect := subtle.ConstantTimeCompare([]byte(username), []byte(dbuser.Username)) == 1
|
userCorrect := subtle.ConstantTimeCompare([]byte(user.Username), []byte(dbuser.Username)) == 1
|
||||||
|
|
||||||
var passwordCorrect bool
|
var passwordCorrect bool
|
||||||
if dbuser.PasswordHash != "" {
|
if dbuser.PasswordHash != "" {
|
||||||
match, err := util.VerifyHash(dbuser.PasswordHash, password)
|
match, err := util.VerifyHash(dbuser.PasswordHash, user.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify password"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify password"})
|
||||||
}
|
}
|
||||||
passwordCorrect = match
|
passwordCorrect = match
|
||||||
} else {
|
} else {
|
||||||
passwordCorrect = subtle.ConstantTimeCompare([]byte(password), []byte(dbuser.Password)) == 1
|
passwordCorrect = subtle.ConstantTimeCompare([]byte(user.Password), []byte(dbuser.Password)) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if userCorrect && passwordCorrect {
|
if userCorrect && passwordCorrect {
|
||||||
// TODO: refresh the token
|
// TODO: refresh the token
|
||||||
ageMax := 0
|
|
||||||
expiration := time.Now().Add(24 * time.Hour)
|
|
||||||
if rememberMe {
|
|
||||||
ageMax = 86400
|
|
||||||
expiration.Add(144 * time.Hour)
|
|
||||||
}
|
|
||||||
sess, _ := session.Get("session", c)
|
sess, _ := session.Get("session", c)
|
||||||
sess.Options = &sessions.Options{
|
sess.Options = &sessions.Options{
|
||||||
Path: util.BasePath,
|
Path: util.BasePath,
|
||||||
MaxAge: ageMax,
|
MaxAge: 86400,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// set session_token
|
// set session_token
|
||||||
tokenUID := xid.New().String()
|
tokenUID := xid.New().String()
|
||||||
sess.Values["username"] = dbuser.Username
|
sess.Values["username"] = user.Username
|
||||||
sess.Values["admin"] = dbuser.Admin
|
|
||||||
sess.Values["session_token"] = tokenUID
|
sess.Values["session_token"] = tokenUID
|
||||||
sess.Save(c.Request(), c.Response())
|
sess.Save(c.Request(), c.Response())
|
||||||
|
|
||||||
|
@ -97,7 +82,7 @@ func Login(db store.IStore) echo.HandlerFunc {
|
||||||
cookie := new(http.Cookie)
|
cookie := new(http.Cookie)
|
||||||
cookie.Name = "session_token"
|
cookie.Name = "session_token"
|
||||||
cookie.Value = tokenUID
|
cookie.Value = tokenUID
|
||||||
cookie.Expires = expiration
|
cookie.Expires = time.Now().Add(24 * time.Hour)
|
||||||
c.SetCookie(cookie)
|
c.SetCookie(cookie)
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Logged in successfully"})
|
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Logged in successfully"})
|
||||||
|
@ -107,40 +92,6 @@ func Login(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsers handler return a JSON list of all users
|
|
||||||
func GetUsers(db store.IStore) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
|
|
||||||
usersList, err := db.GetUsers()
|
|
||||||
if err != nil {
|
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
|
|
||||||
false, fmt.Sprintf("Cannot get user list: %v", err),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, usersList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUser handler returns a JSON object of single user
|
|
||||||
func GetUser(db store.IStore) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
|
|
||||||
username := c.Param("username")
|
|
||||||
|
|
||||||
if !isAdmin(c) && (username != currentUser(c)) {
|
|
||||||
return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "Manager cannot access other user data"})
|
|
||||||
}
|
|
||||||
|
|
||||||
userData, err := db.GetUserByName(username)
|
|
||||||
if err != nil {
|
|
||||||
return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "User not found"})
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, userData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logout to log a user out
|
// Logout to log a user out
|
||||||
func Logout() echo.HandlerFunc {
|
func Logout() echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
@ -152,23 +103,21 @@ func Logout() echo.HandlerFunc {
|
||||||
// LoadProfile to load user information
|
// LoadProfile to load user information
|
||||||
func LoadProfile(db store.IStore) echo.HandlerFunc {
|
func LoadProfile(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
|
||||||
|
userInfo, err := db.GetUser()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Cannot get user information: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "profile.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "profile.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c)},
|
||||||
|
"userInfo": userInfo,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UsersSettings handler
|
// UpdateProfile to update user information
|
||||||
func UsersSettings(db store.IStore) echo.HandlerFunc {
|
func UpdateProfile(db store.IStore) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
|
||||||
return c.Render(http.StatusOK, "users_settings.html", map[string]interface{}{
|
|
||||||
"baseData": model.BaseData{Active: "users-settings", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateUser to update user information
|
|
||||||
func UpdateUser(db store.IStore) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
err := json.NewDecoder(c.Request().Body).Decode(&data)
|
err := json.NewDecoder(c.Request().Body).Decode(&data)
|
||||||
|
@ -179,18 +128,8 @@ func UpdateUser(db store.IStore) echo.HandlerFunc {
|
||||||
|
|
||||||
username := data["username"].(string)
|
username := data["username"].(string)
|
||||||
password := data["password"].(string)
|
password := data["password"].(string)
|
||||||
previousUsername := data["previous_username"].(string)
|
|
||||||
admin := data["admin"].(bool)
|
|
||||||
|
|
||||||
if !isAdmin(c) && (previousUsername != currentUser(c)) {
|
user, err := db.GetUser()
|
||||||
return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "Manager cannot access other user data"})
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isAdmin(c) {
|
|
||||||
admin = false
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := db.GetUserByName(previousUsername)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, err.Error()})
|
return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, err.Error()})
|
||||||
}
|
}
|
||||||
|
@ -201,13 +140,6 @@ func UpdateUser(db store.IStore) echo.HandlerFunc {
|
||||||
user.Username = username
|
user.Username = username
|
||||||
}
|
}
|
||||||
|
|
||||||
if username != previousUsername {
|
|
||||||
_, err := db.GetUserByName(username)
|
|
||||||
if err == nil {
|
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "This username is taken"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if password != "" {
|
if password != "" {
|
||||||
hash, err := util.HashPassword(password)
|
hash, err := util.HashPassword(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -216,96 +148,12 @@ func UpdateUser(db store.IStore) echo.HandlerFunc {
|
||||||
user.PasswordHash = hash
|
user.PasswordHash = hash
|
||||||
}
|
}
|
||||||
|
|
||||||
if previousUsername != currentUser(c) {
|
|
||||||
user.Admin = admin
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := db.DeleteUser(previousUsername); err != nil {
|
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()})
|
|
||||||
}
|
|
||||||
if err := db.SaveUser(user); err != nil {
|
if err := db.SaveUser(user); err != nil {
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()})
|
||||||
}
|
}
|
||||||
log.Infof("Updated user information successfully")
|
log.Infof("Updated admin user information successfully")
|
||||||
|
|
||||||
if previousUsername == currentUser(c) {
|
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated admin user information successfully"})
|
||||||
setUser(c, user.Username, user.Admin)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated user information successfully"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateUser to create new user
|
|
||||||
func CreateUser(db store.IStore) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
data := make(map[string]interface{})
|
|
||||||
err := json.NewDecoder(c.Request().Body).Decode(&data)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"})
|
|
||||||
}
|
|
||||||
|
|
||||||
var user model.User
|
|
||||||
username := data["username"].(string)
|
|
||||||
password := data["password"].(string)
|
|
||||||
admin := data["admin"].(bool)
|
|
||||||
|
|
||||||
if username == "" {
|
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"})
|
|
||||||
} else {
|
|
||||||
user.Username = username
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
_, err := db.GetUserByName(username)
|
|
||||||
if err == nil {
|
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "This username is taken"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hash, err := util.HashPassword(password)
|
|
||||||
if err != nil {
|
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()})
|
|
||||||
}
|
|
||||||
user.PasswordHash = hash
|
|
||||||
|
|
||||||
user.Admin = admin
|
|
||||||
|
|
||||||
if err := db.SaveUser(user); err != nil {
|
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()})
|
|
||||||
}
|
|
||||||
log.Infof("Created user successfully")
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Created user successfully"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveUser handler
|
|
||||||
func RemoveUser(db store.IStore) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
data := make(map[string]interface{})
|
|
||||||
err := json.NewDecoder(c.Request().Body).Decode(&data)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"})
|
|
||||||
}
|
|
||||||
|
|
||||||
username := data["username"].(string)
|
|
||||||
|
|
||||||
if username == currentUser(c) {
|
|
||||||
return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "User cannot delete itself"})
|
|
||||||
}
|
|
||||||
// delete user from database
|
|
||||||
|
|
||||||
if err := db.DeleteUser(username); err != nil {
|
|
||||||
log.Error("Cannot delete user: ", err)
|
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot delete user from database"})
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Removed user: %s", username)
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "User removed"})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +169,7 @@ func WireGuardClients(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "clients.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "clients.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "", CurrentUser: currentUser(c)},
|
||||||
"clientDataList": clientDataList,
|
"clientDataList": clientDataList,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -683,7 +531,7 @@ func WireGuardServer(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "server.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "server.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "wg-server", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "wg-server", CurrentUser: currentUser(c)},
|
||||||
"serverInterface": server.Interface,
|
"serverInterface": server.Interface,
|
||||||
"serverKeyPair": server.KeyPair,
|
"serverKeyPair": server.KeyPair,
|
||||||
})
|
})
|
||||||
|
@ -751,7 +599,7 @@ func GlobalSettings(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "global_settings.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "global_settings.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "global-settings", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "global-settings", CurrentUser: currentUser(c)},
|
||||||
"globalSettings": globalSettings,
|
"globalSettings": globalSettings,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -837,7 +685,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
wgClient, err := wgctrl.New()
|
wgClient, err := wgctrl.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"devices": nil,
|
"devices": nil,
|
||||||
})
|
})
|
||||||
|
@ -846,7 +694,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
devices, err := wgClient.Devices()
|
devices, err := wgClient.Devices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"devices": nil,
|
"devices": nil,
|
||||||
})
|
})
|
||||||
|
@ -858,7 +706,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
clients, err := db.GetClients(false)
|
clients, err := db.GetClients(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
"devices": nil,
|
"devices": nil,
|
||||||
})
|
})
|
||||||
|
@ -895,7 +743,7 @@ func Status(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "status.html", map[string]interface{}{
|
return c.Render(http.StatusOK, "status.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)},
|
||||||
"devices": devicesVm,
|
"devices": devicesVm,
|
||||||
"error": "",
|
"error": "",
|
||||||
})
|
})
|
||||||
|
@ -1009,12 +857,6 @@ func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get client config"})
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get client config"})
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := db.GetUsers()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Cannot get users config: ", err)
|
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get users config"})
|
|
||||||
}
|
|
||||||
|
|
||||||
settings, err := db.GetGlobalSettings()
|
settings, err := db.GetGlobalSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot get global settings: ", err)
|
log.Error("Cannot get global settings: ", err)
|
||||||
|
@ -1022,7 +864,7 @@ func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write config file
|
// Write config file
|
||||||
err = util.WriteWireGuardServerConfig(tmplBox, server, clients, users, settings)
|
err = util.WriteWireGuardServerConfig(tmplBox, server, clients, settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Cannot apply server config: ", err)
|
log.Error("Cannot apply server config: ", err)
|
||||||
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
|
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
|
||||||
|
|
|
@ -37,7 +37,7 @@ func GetWakeOnLanHosts(db store.IStore) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Render(http.StatusOK, "wake_on_lan_hosts.html", map[string]interface{}{
|
err = c.Render(http.StatusOK, "wake_on_lan_hosts.html", map[string]interface{}{
|
||||||
"baseData": model.BaseData{Active: "wake_on_lan_hosts", CurrentUser: currentUser(c), Admin: isAdmin(c)},
|
"baseData": model.BaseData{Active: "wake_on_lan_hosts", CurrentUser: currentUser(c)},
|
||||||
"hosts": hosts,
|
"hosts": hosts,
|
||||||
"error": "",
|
"error": "",
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,24 +14,15 @@ func ValidSession(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
if !isValidSession(c) {
|
if !isValidSession(c) {
|
||||||
nextURL := c.Request().URL
|
nextURL := c.Request().URL
|
||||||
if nextURL != nil && c.Request().Method == http.MethodGet {
|
if nextURL != nil && c.Request().Method == http.MethodGet {
|
||||||
return c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf(util.BasePath+"/login?next=%s", c.Request().URL))
|
return c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf(util.BasePath + "/login?next=%s", c.Request().URL))
|
||||||
} else {
|
} else {
|
||||||
return c.Redirect(http.StatusTemporaryRedirect, util.BasePath+"/login")
|
return c.Redirect(http.StatusTemporaryRedirect, util.BasePath + "/login")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NeedsAdmin(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
if !isAdmin(c) {
|
|
||||||
return c.Redirect(http.StatusTemporaryRedirect, util.BasePath+"/")
|
|
||||||
}
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValidSession(c echo.Context) bool {
|
func isValidSession(c echo.Context) bool {
|
||||||
if util.DisableLogin {
|
if util.DisableLogin {
|
||||||
return true
|
return true
|
||||||
|
@ -55,29 +46,10 @@ func currentUser(c echo.Context) string {
|
||||||
return username
|
return username
|
||||||
}
|
}
|
||||||
|
|
||||||
// isAdmin to get user type: admin or manager
|
|
||||||
func isAdmin(c echo.Context) bool {
|
|
||||||
if util.DisableLogin {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
sess, _ := session.Get("session", c)
|
|
||||||
admin := fmt.Sprintf("%t", sess.Values["admin"])
|
|
||||||
return admin == "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUser(c echo.Context, username string, admin bool) {
|
|
||||||
sess, _ := session.Get("session", c)
|
|
||||||
sess.Values["username"] = username
|
|
||||||
sess.Values["admin"] = admin
|
|
||||||
sess.Save(c.Request(), c.Response())
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearSession to remove current session
|
// clearSession to remove current session
|
||||||
func clearSession(c echo.Context) {
|
func clearSession(c echo.Context) {
|
||||||
sess, _ := session.Get("session", c)
|
sess, _ := session.Get("session", c)
|
||||||
sess.Values["username"] = ""
|
sess.Values["username"] = ""
|
||||||
sess.Values["admin"] = false
|
|
||||||
sess.Values["session_token"] = ""
|
sess.Values["session_token"] = ""
|
||||||
sess.Save(c.Request(), c.Response())
|
sess.Save(c.Request(), c.Response())
|
||||||
}
|
}
|
||||||
|
|
28
main.go
28
main.go
|
@ -157,12 +157,7 @@ func main() {
|
||||||
app.POST(util.BasePath+"/login", handler.Login(db))
|
app.POST(util.BasePath+"/login", handler.Login(db))
|
||||||
app.GET(util.BasePath+"/logout", handler.Logout(), handler.ValidSession)
|
app.GET(util.BasePath+"/logout", handler.Logout(), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/profile", handler.LoadProfile(db), handler.ValidSession)
|
app.GET(util.BasePath+"/profile", handler.LoadProfile(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/users-settings", handler.UsersSettings(db), handler.ValidSession, handler.NeedsAdmin)
|
app.POST(util.BasePath+"/profile", handler.UpdateProfile(db), handler.ValidSession)
|
||||||
app.POST(util.BasePath+"/update-user", handler.UpdateUser(db), handler.ValidSession)
|
|
||||||
app.POST(util.BasePath+"/create-user", handler.CreateUser(db), handler.ValidSession, handler.NeedsAdmin)
|
|
||||||
app.POST(util.BasePath+"/remove-user", handler.RemoveUser(db), handler.ValidSession, handler.NeedsAdmin)
|
|
||||||
app.GET(util.BasePath+"/getusers", handler.GetUsers(db), handler.ValidSession, handler.NeedsAdmin)
|
|
||||||
app.GET(util.BasePath+"/api/user/:username", handler.GetUser(db), handler.ValidSession)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.GET(util.BasePath+"/_health", handler.Health())
|
app.GET(util.BasePath+"/_health", handler.Health())
|
||||||
|
@ -172,13 +167,13 @@ func main() {
|
||||||
app.POST(util.BasePath+"/client/set-status", handler.SetClientStatus(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/client/set-status", handler.SetClientStatus(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/remove-client", handler.RemoveClient(db), handler.ValidSession, handler.ContentTypeJson)
|
app.POST(util.BasePath+"/remove-client", handler.RemoveClient(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.GET(util.BasePath+"/download", handler.DownloadClient(db), handler.ValidSession)
|
app.GET(util.BasePath+"/download", handler.DownloadClient(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/wg-server", handler.WireGuardServer(db), handler.ValidSession, handler.NeedsAdmin)
|
app.GET(util.BasePath+"/wg-server", handler.WireGuardServer(db), handler.ValidSession)
|
||||||
app.POST(util.BasePath+"/wg-server/interfaces", handler.WireGuardServerInterfaces(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
|
app.POST(util.BasePath+"/wg-server/interfaces", handler.WireGuardServerInterfaces(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
|
app.POST(util.BasePath+"/wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession, handler.NeedsAdmin)
|
app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/email-settings", handler.EmailSettings(db), handler.ValidSession, handler.NeedsAdmin)
|
app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson)
|
||||||
app.POST(util.BasePath+"/email-settings", handler.EmailSettingsSubmit(db), handler.ValidSession, handler.NeedsAdmin)
|
app.GET(util.BasePath+"/email-settings", handler.EmailSettings(db), handler.ValidSession)
|
||||||
app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
|
app.POST(util.BasePath+"/email-settings", handler.EmailSettingsSubmit(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/status", handler.Status(db), handler.ValidSession)
|
app.GET(util.BasePath+"/status", handler.Status(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/api/clients", handler.GetClients(db), handler.ValidSession)
|
app.GET(util.BasePath+"/api/clients", handler.GetClients(db), handler.ValidSession)
|
||||||
app.GET(util.BasePath+"/api/client/:id", handler.GetClient(db), handler.ValidSession)
|
app.GET(util.BasePath+"/api/client/:id", handler.GetClient(db), handler.ValidSession)
|
||||||
|
@ -217,13 +212,8 @@ func initServerConfig(db store.IStore, tmplBox *rice.Box) {
|
||||||
log.Fatalf("Cannot get client config: ", err)
|
log.Fatalf("Cannot get client config: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := db.GetUsers()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Cannot get user config: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// write config file
|
// write config file
|
||||||
err = util.WriteWireGuardServerConfig(tmplBox, server, clients, users, settings)
|
err = util.WriteWireGuardServerConfig(tmplBox, server, clients, settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Cannot create server config: ", err)
|
log.Fatalf("Cannot create server config: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,4 @@ type Interface struct {
|
||||||
type BaseData struct {
|
type BaseData struct {
|
||||||
Active string
|
Active string
|
||||||
CurrentUser string
|
CurrentUser string
|
||||||
Admin bool
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,4 @@ type User struct {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
// PasswordHash takes precedence over Password.
|
// PasswordHash takes precedence over Password.
|
||||||
PasswordHash string `json:"password_hash"`
|
PasswordHash string `json:"password_hash"`
|
||||||
Admin bool `json:"admin"`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,6 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmplUsersSettingsString, err := tmplBox.String("users_settings.html")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmplStatusString, err := tmplBox.String("status.html")
|
tmplStatusString, err := tmplBox.String("status.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -114,7 +109,6 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec
|
||||||
templates["server.html"] = template.Must(template.New("server").Funcs(funcs).Parse(tmplBaseString + tmplServerString))
|
templates["server.html"] = template.Must(template.New("server").Funcs(funcs).Parse(tmplBaseString + tmplServerString))
|
||||||
templates["global_settings.html"] = template.Must(template.New("global_settings").Funcs(funcs).Parse(tmplBaseString + tmplGlobalSettingsString))
|
templates["global_settings.html"] = template.Must(template.New("global_settings").Funcs(funcs).Parse(tmplBaseString + tmplGlobalSettingsString))
|
||||||
templates["email_settings.html"] = template.Must(template.New("email_settings").Funcs(funcs).Parse(tmplBaseString + tmplEmailSettingsString))
|
templates["email_settings.html"] = template.Must(template.New("email_settings").Funcs(funcs).Parse(tmplBaseString + tmplEmailSettingsString))
|
||||||
templates["users_settings.html"] = template.Must(template.New("users_settings").Funcs(funcs).Parse(tmplBaseString + tmplUsersSettingsString))
|
|
||||||
templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString))
|
templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString))
|
||||||
templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString))
|
templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString))
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,8 @@ func (o *JsonDB) Init() error {
|
||||||
var serverKeyPairPath string = path.Join(serverPath, "keypair.json")
|
var serverKeyPairPath string = path.Join(serverPath, "keypair.json")
|
||||||
var globalSettingPath string = path.Join(serverPath, "global_settings.json")
|
var globalSettingPath string = path.Join(serverPath, "global_settings.json")
|
||||||
var emailSettingPath string = path.Join(serverPath, "email_settings.json")
|
var emailSettingPath string = path.Join(serverPath, "email_settings.json")
|
||||||
var userPath string = path.Join(o.dbPath, "users")
|
var userPath string = path.Join(serverPath, "users.json")
|
||||||
|
|
||||||
// create directories if they do not exist
|
// create directories if they do not exist
|
||||||
if _, err := os.Stat(clientPath); os.IsNotExist(err) {
|
if _, err := os.Stat(clientPath); os.IsNotExist(err) {
|
||||||
os.MkdirAll(clientPath, os.ModePerm)
|
os.MkdirAll(clientPath, os.ModePerm)
|
||||||
|
@ -54,9 +55,6 @@ func (o *JsonDB) Init() error {
|
||||||
if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) {
|
if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) {
|
||||||
os.MkdirAll(wakeOnLanHostsPath, os.ModePerm)
|
os.MkdirAll(wakeOnLanHostsPath, os.ModePerm)
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(userPath); os.IsNotExist(err) {
|
|
||||||
os.MkdirAll(userPath, os.ModePerm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// server's interface
|
// server's interface
|
||||||
if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) {
|
if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) {
|
||||||
|
@ -128,11 +126,9 @@ func (o *JsonDB) Init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// user info
|
// user info
|
||||||
results, err := o.conn.ReadAll("users")
|
if _, err := os.Stat(userPath); os.IsNotExist(err) {
|
||||||
if err != nil || len(results) < 1 {
|
|
||||||
user := new(model.User)
|
user := new(model.User)
|
||||||
user.Username = util.LookupEnvOrString(util.UsernameEnvVar, util.DefaultUsername)
|
user.Username = util.LookupEnvOrString(util.UsernameEnvVar, util.DefaultUsername)
|
||||||
user.Admin = util.DefaultIsAdmin
|
|
||||||
user.PasswordHash = util.LookupEnvOrString(util.PasswordHashEnvVar, "")
|
user.PasswordHash = util.LookupEnvOrString(util.PasswordHashEnvVar, "")
|
||||||
if user.PasswordHash == "" {
|
if user.PasswordHash == "" {
|
||||||
plaintext := util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword)
|
plaintext := util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword)
|
||||||
|
@ -142,7 +138,7 @@ func (o *JsonDB) Init() error {
|
||||||
}
|
}
|
||||||
user.PasswordHash = hash
|
user.PasswordHash = hash
|
||||||
}
|
}
|
||||||
o.conn.Write("users", user.Username, user)
|
o.conn.Write("server", "users", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -154,44 +150,9 @@ func (o *JsonDB) GetUser() (model.User, error) {
|
||||||
return user, o.conn.Read("server", "users", &user)
|
return user, o.conn.Read("server", "users", &user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsers func to get all users from the database
|
// SaveUser func to user info to the database
|
||||||
func (o *JsonDB) GetUsers() ([]model.User, error) {
|
|
||||||
var users []model.User
|
|
||||||
results, err := o.conn.ReadAll("users")
|
|
||||||
if err != nil {
|
|
||||||
return users, err
|
|
||||||
}
|
|
||||||
for _, i := range results {
|
|
||||||
user := model.User{}
|
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(i), &user); err != nil {
|
|
||||||
return users, fmt.Errorf("cannot decode user json structure: %v", err)
|
|
||||||
}
|
|
||||||
users = append(users, user)
|
|
||||||
|
|
||||||
}
|
|
||||||
return users, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByName func to get single user from the database
|
|
||||||
func (o *JsonDB) GetUserByName(username string) (model.User, error) {
|
|
||||||
user := model.User{}
|
|
||||||
|
|
||||||
if err := o.conn.Read("users", username, &user); err != nil {
|
|
||||||
return user, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveUser func to save user in the database
|
|
||||||
func (o *JsonDB) SaveUser(user model.User) error {
|
func (o *JsonDB) SaveUser(user model.User) error {
|
||||||
return o.conn.Write("users", user.Username, user)
|
return o.conn.Write("server", "users", user)
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteUser func to remove user from the database
|
|
||||||
func (o *JsonDB) DeleteUser(username string) error {
|
|
||||||
return o.conn.Delete("users", username)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGlobalSettings func to query global settings from the database
|
// GetGlobalSettings func to query global settings from the database
|
||||||
|
@ -275,7 +236,7 @@ func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSetti
|
||||||
server, _ := o.GetServer()
|
server, _ := o.GetServer()
|
||||||
globalSettings, _ := o.GetGlobalSettings()
|
globalSettings, _ := o.GetGlobalSettings()
|
||||||
client := client
|
client := client
|
||||||
if !qrCodeSettings.IncludeDNS {
|
if !qrCodeSettings.IncludeDNS{
|
||||||
globalSettings.DNSServers = []string{}
|
globalSettings.DNSServers = []string{}
|
||||||
}
|
}
|
||||||
if !qrCodeSettings.IncludeMTU {
|
if !qrCodeSettings.IncludeMTU {
|
||||||
|
|
|
@ -6,10 +6,8 @@ import (
|
||||||
|
|
||||||
type IStore interface {
|
type IStore interface {
|
||||||
Init() error
|
Init() error
|
||||||
GetUsers() ([]model.User, error)
|
GetUser() (model.User, error)
|
||||||
GetUserByName(username string) (model.User, error)
|
|
||||||
SaveUser(user model.User) error
|
SaveUser(user model.User) error
|
||||||
DeleteUser(username string) error
|
|
||||||
GetGlobalSettings() (model.GlobalSetting, error)
|
GetGlobalSettings() (model.GlobalSetting, error)
|
||||||
GetEmailSettings() (model.EmailSetting, error)
|
GetEmailSettings() (model.EmailSetting, error)
|
||||||
GetServer() (model.Server, error)
|
GetServer() (model.Server, error)
|
||||||
|
|
|
@ -88,13 +88,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
{{if .baseData.CurrentUser}}
|
{{if .baseData.CurrentUser}}
|
||||||
|
<a href="{{.basePath}}/profile" class="d-block">{{.baseData.CurrentUser}}</a>
|
||||||
{{if .baseData.Admin}}
|
|
||||||
<a href="{{.basePath}}/profile" class="d-block">Administrator: {{.baseData.CurrentUser}}</a>
|
|
||||||
{{else}}
|
|
||||||
<a href="{{.basePath}}/profile" class="d-block">Manager: {{.baseData.CurrentUser}}</a>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="#" class="d-block">Administrator</a>
|
<a href="#" class="d-block">Administrator</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -113,8 +107,6 @@
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{{if .baseData.Admin}}
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{.basePath}}/wg-server" class="nav-link {{if eq .baseData.Active "wg-server" }}active{{end}}">
|
<a href="{{.basePath}}/wg-server" class="nav-link {{if eq .baseData.Active "wg-server" }}active{{end}}">
|
||||||
<i class="nav-icon fas fa-server"></i>
|
<i class="nav-icon fas fa-server"></i>
|
||||||
|
@ -123,8 +115,6 @@
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="nav-header">SETTINGS</li>
|
<li class="nav-header">SETTINGS</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{.basePath}}/global-settings" class="nav-link {{if eq .baseData.Active "global-settings" }}active{{end}}">
|
<a href="{{.basePath}}/global-settings" class="nav-link {{if eq .baseData.Active "global-settings" }}active{{end}}">
|
||||||
|
@ -142,16 +132,6 @@
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
|
||||||
<a href="{{.basePath}}/users-settings" class="nav-link {{if eq .baseData.Active "users-settings" }}active{{end}}">
|
|
||||||
<i class="nav-icon fas fa-cog"></i>
|
|
||||||
<p>
|
|
||||||
Users Settings
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<li class="nav-header">UTILITIES</li>
|
<li class="nav-header">UTILITIES</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{{.basePath}}/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}">
|
<a href="{{.basePath}}/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}">
|
||||||
|
|
|
@ -99,11 +99,7 @@
|
||||||
$("#btn_login").click(function () {
|
$("#btn_login").click(function () {
|
||||||
const username = $("#username").val();
|
const username = $("#username").val();
|
||||||
const password = $("#password").val();
|
const password = $("#password").val();
|
||||||
let rememberMe = false;
|
const data = {"username": username, "password": password}
|
||||||
if ($("#remember").is(':checked')){
|
|
||||||
rememberMe = true;
|
|
||||||
}
|
|
||||||
const data = {"username": username, "password": password, "rememberMe": rememberMe}
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
cache: false,
|
cache: false,
|
||||||
|
|
|
@ -31,7 +31,7 @@ Profile
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="username" class="control-label">Username</label>
|
<label for="username" class="control-label">Username</label>
|
||||||
<input type="text" class="form-control" name="username" id="username"
|
<input type="text" class="form-control" name="username" id="username"
|
||||||
value="">
|
value="{{ .userInfo.Username }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password" class="control-label">Password</label>
|
<label for="password" class="control-label">Password</label>
|
||||||
|
@ -55,82 +55,56 @@ Profile
|
||||||
|
|
||||||
{{ define "bottom_js"}}
|
{{ define "bottom_js"}}
|
||||||
<script>
|
<script>
|
||||||
{
|
function updateUserInfo() {
|
||||||
var previous_username;
|
const username = $("#username").val();
|
||||||
var admin;
|
const password = $("#password").val();
|
||||||
}
|
const data = {"username": username, "password": password};
|
||||||
$(document).ready(function () {
|
$.ajax({
|
||||||
$.ajax({
|
cache: false,
|
||||||
cache: false,
|
method: 'POST',
|
||||||
method: 'GET',
|
url: '{{.basePath}}/profile',
|
||||||
url: '{{.basePath}}/api/user/{{.baseData.CurrentUser}}',
|
dataType: 'json',
|
||||||
dataType: 'json',
|
contentType: "application/json",
|
||||||
contentType: "application/json",
|
data: JSON.stringify(data),
|
||||||
success: function (resp) {
|
success: function (data) {
|
||||||
const user = resp;
|
toastr.success("Updated admin user information successfully");
|
||||||
$("#username").val(user.username);
|
},
|
||||||
previous_username = user.username;
|
error: function (jqXHR, exception) {
|
||||||
admin = user.admin;
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
||||||
},
|
toastr.error(responseJson['message']);
|
||||||
error: function (jqXHR, exception) {
|
}
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
function updateUserInfo() {
|
$.validator.setDefaults({
|
||||||
const username = $("#username").val();
|
submitHandler: function () {
|
||||||
const password = $("#password").val();
|
updateUserInfo();
|
||||||
const data = {"username": username, "password": password, "previous_username": previous_username, "admin":admin};
|
}
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
method: 'POST',
|
|
||||||
url: '{{.basePath}}/update-user',
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
data: JSON.stringify(data),
|
|
||||||
success: function (data) {
|
|
||||||
toastr.success("Updated user information successfully");
|
|
||||||
location.reload();
|
|
||||||
},
|
|
||||||
error: function (jqXHR, exception) {
|
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
$.validator.setDefaults({
|
|
||||||
submitHandler: function () {
|
|
||||||
updateUserInfo();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$("#frm_profile").validate({
|
|
||||||
rules: {
|
|
||||||
username: {
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messages: {
|
|
||||||
username: {
|
|
||||||
required: "Please enter a username",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
errorElement: 'span',
|
|
||||||
errorPlacement: function (error, element) {
|
|
||||||
error.addClass('invalid-feedback');
|
|
||||||
element.closest('.form-group').append(error);
|
|
||||||
},
|
|
||||||
highlight: function (element, errorClass, validClass) {
|
|
||||||
$(element).addClass('is-invalid');
|
|
||||||
},
|
|
||||||
unhighlight: function (element, errorClass, validClass) {
|
|
||||||
$(element).removeClass('is-invalid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
$("#frm_profile").validate({
|
||||||
|
rules: {
|
||||||
|
username: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
username: {
|
||||||
|
required: "Please enter a username",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorElement: 'span',
|
||||||
|
errorPlacement: function (error, element) {
|
||||||
|
error.addClass('invalid-feedback');
|
||||||
|
element.closest('.form-group').append(error);
|
||||||
|
},
|
||||||
|
highlight: function (element, errorClass, validClass) {
|
||||||
|
$(element).addClass('is-invalid');
|
||||||
|
},
|
||||||
|
unhighlight: function (element, errorClass, validClass) {
|
||||||
|
$(element).removeClass('is-invalid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -1,294 +0,0 @@
|
||||||
{{define "title"}}
|
|
||||||
Users Settings
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "top_css"}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "username"}}
|
|
||||||
{{ .username }}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "page_title"}}
|
|
||||||
Users Settings
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "page_content"}}
|
|
||||||
<section class="content">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row" id="users-list">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<div class="modal fade" id="modal_edit_user">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title">Edit User</h4>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<form name="frm_edit_user" id="frm_edit_user">
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-group" style="display:none">
|
|
||||||
<input type="text" style="display:none" class="form-control" id="_previous_user_name"
|
|
||||||
name="_previous_user_name">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="_user_name" class="control-label">Name</label>
|
|
||||||
<input type="text" class="form-control" id="_user_name" name="_user_name">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="_user_password" class="control-label">Password</label>
|
|
||||||
<input type="text" class="form-control" id="_user_password" name="_user_password" value=""
|
|
||||||
placeholder="Leave empty to keep the password unchanged">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="icheck-primary d-inline">
|
|
||||||
<input type="checkbox" id="_admin">
|
|
||||||
<label for="_admin">
|
|
||||||
Admin
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer justify-content-between">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
|
||||||
<button type="submit" class="btn btn-success">Save</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-content -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-dialog -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal -->
|
|
||||||
|
|
||||||
<div class="modal fade" id="modal_remove_user">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content bg-danger">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title">Remove</h4>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer justify-content-between">
|
|
||||||
<button type="button" class="btn btn-outline-dark" data-dismiss="modal">Cancel</button>
|
|
||||||
<button type="button" class="btn btn-outline-dark" id="remove_user_confirm">Apply</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-content -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal-dialog -->
|
|
||||||
</div>
|
|
||||||
<!-- /.modal -->
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{define "bottom_js"}}
|
|
||||||
<script>
|
|
||||||
function populateUsersList() {
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
method: 'GET',
|
|
||||||
url: '{{.basePath}}/getusers',
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
success: function (data) {
|
|
||||||
renderUserList(data);
|
|
||||||
},
|
|
||||||
error: function (jqXHR, exception) {
|
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
// load user list
|
|
||||||
$(document).ready(function () {
|
|
||||||
populateUsersList();
|
|
||||||
let newUserHtml = '<div class="col-sm-2 offset-md-4" style=" text-align: right;">' +
|
|
||||||
'<button style="" id="btn_new_user" type="button" class="btn btn-outline-primary btn-sm" ' +
|
|
||||||
'data-toggle="modal" data-target="#modal_edit_user" data-username="">' +
|
|
||||||
'<i class="nav-icon fas fa-plus"></i> New User</button></div>';
|
|
||||||
$('h1').parents(".row").append(newUserHtml);
|
|
||||||
})
|
|
||||||
|
|
||||||
// modal_remove_user modal event
|
|
||||||
$("#modal_remove_user").on('show.bs.modal', function (event) {
|
|
||||||
const button = $(event.relatedTarget);
|
|
||||||
const user_name = button.data('username');
|
|
||||||
const modal = $(this);
|
|
||||||
modal.find('.modal-body').text("You are about to remove user " + user_name);
|
|
||||||
modal.find('#remove_user_confirm').val(user_name);
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove_user_confirm button event
|
|
||||||
$(document).ready(function () {
|
|
||||||
$("#remove_user_confirm").click(function () {
|
|
||||||
const user_name = $(this).val();
|
|
||||||
const data = {"username": user_name};
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
method: 'POST',
|
|
||||||
url: '{{.basePath}}/remove-user',
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
data: JSON.stringify(data),
|
|
||||||
success: function (data) {
|
|
||||||
$("#modal_remove_user").modal('hide');
|
|
||||||
toastr.success('Removed user successfully');
|
|
||||||
const divElement = document.getElementById('user_' + user_name);
|
|
||||||
divElement.style.display = "none";
|
|
||||||
location.reload()
|
|
||||||
},
|
|
||||||
error: function (jqXHR, exception) {
|
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Edit user modal event
|
|
||||||
$(document).ready(function () {
|
|
||||||
$("#modal_edit_user").on('show.bs.modal', function (event) {
|
|
||||||
let modal = $(this);
|
|
||||||
const button = $(event.relatedTarget);
|
|
||||||
const user_name = button.data('username');
|
|
||||||
|
|
||||||
// update user modal data
|
|
||||||
if (user_name !== "") {
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
method: 'GET',
|
|
||||||
url: '{{.basePath}}/api/user/' + user_name,
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
success: function (resp) {
|
|
||||||
const user = resp;
|
|
||||||
|
|
||||||
modal.find(".modal-title").text("Edit user " + user.username);
|
|
||||||
modal.find("#_user_name").val(user.username);
|
|
||||||
modal.find("#_previous_user_name").val(user.username);
|
|
||||||
modal.find("#_user_password").val("");
|
|
||||||
modal.find("#_user_password").prop("placeholder", "Leave empty to keep the password unchanged")
|
|
||||||
modal.find("#_admin").prop("checked", user.admin);
|
|
||||||
},
|
|
||||||
error: function (jqXHR, exception) {
|
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
modal.find(".modal-title").text("Add new user");
|
|
||||||
modal.find("#_user_name").val("");
|
|
||||||
modal.find("#_previous_user_name").val("");
|
|
||||||
modal.find("#_user_password").val("");
|
|
||||||
modal.find("#_user_password").prop("placeholder", "")
|
|
||||||
modal.find("#_admin").prop("checked", false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateUserInfo() {
|
|
||||||
const username = $("#_user_name").val();
|
|
||||||
const previous_username = $("#_previous_user_name").val();
|
|
||||||
const password = $("#_user_password").val();
|
|
||||||
let admin = false;
|
|
||||||
if ($("#_admin").is(':checked')) {
|
|
||||||
admin = true;
|
|
||||||
}
|
|
||||||
const data = {
|
|
||||||
"username": username,
|
|
||||||
"password": password,
|
|
||||||
"previous_username": previous_username,
|
|
||||||
"admin": admin
|
|
||||||
};
|
|
||||||
|
|
||||||
if (previous_username !== "") {
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
method: 'POST',
|
|
||||||
url: '{{.basePath}}/update-user',
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
data: JSON.stringify(data),
|
|
||||||
success: function (data) {
|
|
||||||
toastr.success("Updated user information successfully");
|
|
||||||
location.reload();
|
|
||||||
},
|
|
||||||
error: function (jqXHR, exception) {
|
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$.ajax({
|
|
||||||
cache: false,
|
|
||||||
method: 'POST',
|
|
||||||
url: '{{.basePath}}/create-user',
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: "application/json",
|
|
||||||
data: JSON.stringify(data),
|
|
||||||
success: function (data) {
|
|
||||||
toastr.success("Created user successfully");
|
|
||||||
location.reload();
|
|
||||||
},
|
|
||||||
error: function (jqXHR, exception) {
|
|
||||||
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
||||||
toastr.error(responseJson['message']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
$.validator.setDefaults({
|
|
||||||
submitHandler: function (form) {
|
|
||||||
updateUserInfo();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Edit user form validation
|
|
||||||
$("#frm_edit_user").validate({
|
|
||||||
rules: {
|
|
||||||
_user_name: {
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
_user_password: {
|
|
||||||
required: function () {
|
|
||||||
return $("#_previous_user_name").val() === "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
messages: {
|
|
||||||
_user_name: {
|
|
||||||
required: "Please enter a username"
|
|
||||||
},
|
|
||||||
_user_password: {
|
|
||||||
required: "Please input a password"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
errorElement: 'span',
|
|
||||||
errorPlacement: function (error, element) {
|
|
||||||
error.addClass('invalid-feedback');
|
|
||||||
element.closest('.form-group').append(error);
|
|
||||||
},
|
|
||||||
highlight: function (element, errorClass, validClass) {
|
|
||||||
$(element).addClass('is-invalid');
|
|
||||||
},
|
|
||||||
unhighlight: function (element, errorClass, validClass) {
|
|
||||||
$(element).removeClass('is-invalid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{end}}
|
|
|
@ -24,7 +24,6 @@ var (
|
||||||
const (
|
const (
|
||||||
DefaultUsername = "admin"
|
DefaultUsername = "admin"
|
||||||
DefaultPassword = "admin"
|
DefaultPassword = "admin"
|
||||||
DefaultIsAdmin = true
|
|
||||||
DefaultServerAddress = "10.252.1.0/24"
|
DefaultServerAddress = "10.252.1.0/24"
|
||||||
DefaultServerPort = 51820
|
DefaultServerPort = 51820
|
||||||
DefaultDNS = "1.1.1.1"
|
DefaultDNS = "1.1.1.1"
|
||||||
|
|
|
@ -381,7 +381,7 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteWireGuardServerConfig to write Wireguard server config. e.g. wg0.conf
|
// WriteWireGuardServerConfig to write Wireguard server config. e.g. wg0.conf
|
||||||
func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, clientDataList []model.ClientData, usersList []model.User, globalSettings model.GlobalSetting) error {
|
func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, clientDataList []model.ClientData, globalSettings model.GlobalSetting) error {
|
||||||
var tmplWireguardConf string
|
var tmplWireguardConf string
|
||||||
|
|
||||||
// if set, read wg.conf template from WgConfTemplate
|
// if set, read wg.conf template from WgConfTemplate
|
||||||
|
@ -416,7 +416,6 @@ func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, cl
|
||||||
"serverConfig": serverConfig,
|
"serverConfig": serverConfig,
|
||||||
"clientDataList": clientDataList,
|
"clientDataList": clientDataList,
|
||||||
"globalSettings": globalSettings,
|
"globalSettings": globalSettings,
|
||||||
"usersList": usersList,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = t.Execute(f, config)
|
err = t.Execute(f, config)
|
||||||
|
|
Loading…
Add table
Reference in a new issue