fixes #34 「动态指令」多行指令会被当作一行执行

fixes #32 会话无法维持,1分钟左右自动断开
fixes #31 更新"资产"会清空"标签"
fixes #13 建议添加用户权限功能、隐藏授权账户信息
This commit is contained in:
dushixiang
2021-01-18 18:28:33 +08:00
parent c93e03e951
commit c98b3adbe6
26 changed files with 642 additions and 378 deletions

View File

@ -49,7 +49,7 @@ func LoginEndpoint(c echo.Context) error {
return Fail(c, -1, "您输入的账号或密码不正确")
}
if user.TOTPSecret != "" {
if user.TOTPSecret != "" && user.TOTPSecret != "-" {
return Fail(c, 0, "")
}

View File

@ -1,9 +1,11 @@
package api
import (
"fmt"
"github.com/labstack/echo/v4"
"github.com/sirupsen/logrus"
"next-terminal/pkg/global"
"next-terminal/pkg/model"
"strings"
"time"
)
@ -12,6 +14,12 @@ func ErrorHandler(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if err := next(c); err != nil {
if he, ok := err.(*echo.HTTPError); ok {
message := fmt.Sprintf("%v", he.Message)
return Fail(c, he.Code, message)
}
return Fail(c, 0, err.Error())
}
return nil
@ -21,9 +29,6 @@ func ErrorHandler(next echo.HandlerFunc) echo.HandlerFunc {
func Auth(next echo.HandlerFunc) echo.HandlerFunc {
urls := []string{"download", "recording", "login", "static", "favicon", "logo"}
permissionUrls := H{
"/users": "admin",
}
return func(c echo.Context) error {
// 路由拦截 - 登录身份、资源权限判断等
@ -43,14 +48,6 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc {
return Fail(c, 401, "您的登录信息已失效,请重新登录后再试。")
}
for url := range permissionUrls {
if strings.HasPrefix(c.Request().RequestURI, url) {
if authorization.(Authorization).User.Type != permissionUrls[url] {
return Fail(c, 403, "permission denied")
}
}
}
if authorization.(Authorization).Remember {
// 记住登录有效期两周
global.Cache.Set(token, authorization, time.Hour*time.Duration(24*14))
@ -61,3 +58,16 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc {
return next(c)
}
}
func Admin(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
account, _ := GetCurrentAccount(c)
if account.Type != model.TypeAdmin {
return Fail(c, 403, "permission denied")
}
return next(c)
}
}

View File

@ -3,7 +3,6 @@ package api
import (
"github.com/labstack/echo/v4"
"next-terminal/pkg/model"
"strings"
)
type RU struct {
@ -12,8 +11,14 @@ type RU struct {
ResourceIds []string `json:"resourceIds"`
}
func ResourceGetAssignEndPoint(c echo.Context) error {
resourceId := c.Param("id")
type UR struct {
ResourceId string `json:"resourceId"`
ResourceType string `json:"resourceType"`
UserIds []string `json:"userIds"`
}
func RSGetSharersEndPoint(c echo.Context) error {
resourceId := c.QueryParam("resourceId")
userIds, err := model.FindUserIdsByResourceId(resourceId)
if err != nil {
return err
@ -21,13 +26,15 @@ func ResourceGetAssignEndPoint(c echo.Context) error {
return Success(c, userIds)
}
func ResourceOverwriteAssignEndPoint(c echo.Context) error {
resourceId := c.Param("id")
userIds := c.QueryParam("userIds")
resourceType := c.QueryParam("type")
uIds := strings.Split(userIds, ",")
func RSOverwriteSharersEndPoint(c echo.Context) error {
var ur UR
if err := c.Bind(&ur); err != nil {
return err
}
model.OverwriteUserIdsByResourceId(resourceId, resourceType, uIds)
if err := model.OverwriteUserIdsByResourceId(ur.ResourceId, ur.ResourceType, ur.UserIds); err != nil {
return err
}
return Success(c, "")
}

View File

@ -44,20 +44,22 @@ func SetupRoutes() *echo.Echo {
users := e.Group("/users")
{
users.POST("", UserCreateEndpoint)
users.POST("", Admin(UserCreateEndpoint))
users.GET("/paging", UserPagingEndpoint)
users.PUT("/:id", UserUpdateEndpoint)
users.DELETE("/:id", UserDeleteEndpoint)
users.GET("/:id", UserGetEndpoint)
users.PUT("/:id", Admin(UserUpdateEndpoint))
users.DELETE("/:id", Admin(UserDeleteEndpoint))
users.GET("/:id", Admin(UserGetEndpoint))
users.POST("/:id/change-password", Admin(UserChangePasswordEndpoint))
users.POST("/:id/reset-totp", Admin(UserResetTotpEndpoint))
}
userGroups := e.Group("/user-groups")
{
userGroups.POST("", UserGroupCreateEndpoint)
userGroups.GET("/paging", UserGroupPagingEndpoint)
userGroups.PUT("/:id", UserGroupUpdateEndpoint)
userGroups.DELETE("/:id", UserGroupDeleteEndpoint)
userGroups.GET("/:id", UserGroupGetEndpoint)
userGroups.POST("", Admin(UserGroupCreateEndpoint))
userGroups.GET("/paging", Admin(UserGroupPagingEndpoint))
userGroups.PUT("/:id", Admin(UserGroupUpdateEndpoint))
userGroups.DELETE("/:id", Admin(UserGroupDeleteEndpoint))
userGroups.GET("/:id", Admin(UserGroupGetEndpoint))
//userGroups.POST("/:id/members", UserGroupAddMembersEndpoint)
//userGroups.DELETE("/:id/members/:memberId", UserGroupDelMembersEndpoint)
}
@ -71,7 +73,7 @@ func SetupRoutes() *echo.Echo {
assets.PUT("/:id", AssetUpdateEndpoint)
assets.DELETE("/:id", AssetDeleteEndpoint)
assets.GET("/:id", AssetGetEndpoint)
assets.POST("/:id/change-owner", AssetChangeOwnerEndpoint)
assets.POST("/:id/change-owner", Admin(AssetChangeOwnerEndpoint))
}
e.GET("/tags", AssetTagsEndpoint)
@ -83,7 +85,7 @@ func SetupRoutes() *echo.Echo {
commands.PUT("/:id", CommandUpdateEndpoint)
commands.DELETE("/:id", CommandDeleteEndpoint)
commands.GET("/:id", CommandGetEndpoint)
commands.POST("/:id/change-owner", CommandChangeOwnerEndpoint)
commands.POST("/:id/change-owner", Admin(CommandChangeOwnerEndpoint))
}
credentials := e.Group("/credentials")
@ -94,7 +96,7 @@ func SetupRoutes() *echo.Echo {
credentials.PUT("/:id", CredentialUpdateEndpoint)
credentials.DELETE("/:id", CredentialDeleteEndpoint)
credentials.GET("/:id", CredentialGetEndpoint)
credentials.POST("/:id/change-owner", CredentialChangeOwnerEndpoint)
credentials.POST("/:id/change-owner", Admin(CredentialChangeOwnerEndpoint))
}
sessions := e.Group("/sessions")
@ -102,7 +104,7 @@ func SetupRoutes() *echo.Echo {
sessions.POST("", SessionCreateEndpoint)
sessions.GET("/paging", SessionPagingEndpoint)
sessions.POST("/:id/content", SessionContentEndpoint)
sessions.POST("/:id/discontent", SessionDiscontentEndpoint)
sessions.POST("/:id/discontent", Admin(SessionDiscontentEndpoint))
sessions.POST("/:id/resize", SessionResizeEndpoint)
sessions.POST("/:id/upload", SessionUploadEndpoint)
sessions.GET("/:id/download", SessionDownloadEndpoint)
@ -111,20 +113,20 @@ func SetupRoutes() *echo.Echo {
sessions.DELETE("/:id/rmdir", SessionRmDirEndpoint)
sessions.DELETE("/:id/rm", SessionRmEndpoint)
sessions.DELETE("/:id", SessionDeleteEndpoint)
sessions.GET("/:id/recording", SessionRecordingEndpoint)
sessions.GET("/:id/recording", Admin(SessionRecordingEndpoint))
sessions.GET("/:id", SessionGetEndpoint)
}
resources := e.Group("/resources")
resourceSharers := e.Group("/resource-sharers")
{
resources.GET("/:id/assign", ResourceGetAssignEndPoint)
resources.POST("/:id/assign", ResourceOverwriteAssignEndPoint)
resources.POST("/remove", ResourceRemoveByUserIdAssignEndPoint)
resources.POST("/add", ResourceAddByUserIdAssignEndPoint)
resourceSharers.GET("/sharers", RSGetSharersEndPoint)
resourceSharers.POST("/overwrite-sharers", RSOverwriteSharersEndPoint)
resourceSharers.POST("/remove-resources", Admin(ResourceRemoveByUserIdAssignEndPoint))
resourceSharers.POST("/add-resources", Admin(ResourceAddByUserIdAssignEndPoint))
}
e.GET("/properties", PropertyGetEndpoint)
e.PUT("/properties", PropertyUpdateEndpoint)
e.PUT("/properties", Admin(PropertyUpdateEndpoint))
e.GET("/overview/counter", OverviewCounterEndPoint)
e.GET("/overview/sessions", OverviewSessionPoint)
@ -174,15 +176,16 @@ func GetCurrentAccount(c echo.Context) (model.User, bool) {
}
func HasPermission(c echo.Context, owner string) bool {
// 检测是否为创建者
// 检测是否登录
account, found := GetCurrentAccount(c)
if !found {
return false
}
// 检测是否为管理人员
if model.TypeAdmin == account.Type {
return true
}
// 检测是否为所有者
if owner == account.ID {
return true
}

View File

@ -103,6 +103,15 @@ func CloseSessionById(sessionId string, code int, reason string) {
CloseSessionByWebSocket(tun.WebSocket, code, reason)
}
s, err := model.FindSessionById(sessionId)
if err != nil {
return
}
if s.Status == model.Disconnected {
return
}
global.Store.Del(sessionId)
session := model.Session{}
session.ID = sessionId

View File

@ -27,7 +27,6 @@ func UserCreateEndpoint(c echo.Context) error {
if err := model.CreateNewUser(&item); err != nil {
return err
}
return Success(c, item)
}
@ -89,3 +88,27 @@ func UserGetEndpoint(c echo.Context) error {
return Success(c, item)
}
func UserChangePasswordEndpoint(c echo.Context) error {
id := c.Param("id")
password := c.QueryParam("password")
passwd, err := utils.Encoder.Encode([]byte(password))
if err != nil {
return err
}
u := &model.User{
Password: string(passwd),
}
model.UpdateUserById(u, id)
return Success(c, "")
}
func UserResetTotpEndpoint(c echo.Context) error {
id := c.Param("id")
u := &model.User{
TOTPSecret: "-",
}
model.UpdateUserById(u, id)
return Success(c, "")
}