diff --git a/backend/docs/docs.go b/backend/docs/docs.go index e475607..429d183 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -1,9 +1,7 @@ // Package docs Code generated by swaggo/swag. DO NOT EDIT package docs -import ( - "github.com/swaggo/swag" -) +import "github.com/swaggo/swag" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, @@ -38,7 +36,7 @@ const docTemplate = `{ "required": true }, { - "type": "integer", + "type": "string", "description": "name or account", "name": "search", "in": "query" @@ -211,7 +209,7 @@ const docTemplate = `{ "required": true }, { - "type": "integer", + "type": "string", "description": "name or ip", "name": "search", "in": "query" @@ -485,7 +483,7 @@ const docTemplate = `{ "required": true }, { - "type": "integer", + "type": "string", "description": "name or cmds", "name": "search", "in": "query" @@ -719,6 +717,12 @@ const docTemplate = `{ "description": "height", "name": "h", "in": "query" + }, + { + "type": "integer", + "description": "dpi", + "name": "dpi", + "in": "query" } ], "responses": { @@ -733,7 +737,7 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "$ref": "#/definitions/model.Session" + "$ref": "#/definitions/session.Session" } } } @@ -749,6 +753,24 @@ const docTemplate = `{ "connect" ], "parameters": [ + { + "type": "integer", + "description": "width", + "name": "w", + "in": "query" + }, + { + "type": "integer", + "description": "height", + "name": "h", + "in": "query" + }, + { + "type": "integer", + "description": "dpi", + "name": "dpi", + "in": "query" + }, { "type": "integer", "description": "session id", @@ -797,6 +819,271 @@ const docTemplate = `{ } } }, + "/file/download/:asset_id/:account_id": { + "get": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "dir", + "name": "dir", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "filename", + "name": "filename", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/file/history": { + "get": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "page_index", + "name": "page_index", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "page_size", + "name": "page_size", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "search", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "saction", + "name": "action", + "in": "query" + }, + { + "type": "string", + "description": "start, RFC3339", + "name": "start", + "in": "query" + }, + { + "type": "string", + "description": "end, RFC3339", + "name": "end", + "in": "query" + }, + { + "type": "integer", + "description": "uid", + "name": "uid", + "in": "query" + }, + { + "type": "integer", + "description": "asset id", + "name": "asset_id", + "in": "query" + }, + { + "type": "integer", + "description": "account id", + "name": "accout_id", + "in": "query" + }, + { + "type": "string", + "description": "client_ip", + "name": "client_ip", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controller.HttpResponse" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/controller.ListData" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Session" + } + } + } + } + ] + } + } + } + ] + } + } + } + } + }, + "/file/ls/:asset_id/:account_id": { + "post": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "dir", + "name": "dir", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/file/mkdir/:asset_id/:account_id": { + "post": { + "tags": [ + "account" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "dir ", + "name": "dir", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/file/upload/:asset_id/:account_id": { + "post": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "path", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, "/gateway": { "get": { "tags": [ @@ -818,7 +1105,7 @@ const docTemplate = `{ "required": true }, { - "type": "integer", + "type": "string", "description": "name or host or account or port", "name": "search", "in": "query" @@ -1033,6 +1320,12 @@ const docTemplate = `{ "description": "end time, RFC3339", "name": "end", "in": "query" + }, + { + "type": "string", + "description": "search", + "name": "search", + "in": "query" } ], "responses": { @@ -1296,7 +1589,7 @@ const docTemplate = `{ "required": true }, { - "type": "integer", + "type": "string", "description": "name or mac", "name": "search", "in": "query" @@ -2613,6 +2906,9 @@ const docTemplate = `{ "count": { "type": "integer" }, + "id": { + "type": "integer" + }, "name": { "type": "string" } @@ -2681,6 +2977,68 @@ const docTemplate = `{ "type": "integer" } } + }, + "session.Session": { + "type": "object", + "properties": { + "account_id": { + "type": "integer" + }, + "account_info": { + "type": "string" + }, + "asset_id": { + "type": "integer" + }, + "asset_info": { + "type": "string" + }, + "client_ip": { + "type": "string" + }, + "closed_at": { + "type": "string" + }, + "cmd_count": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "gateway_id": { + "type": "integer" + }, + "gateway_info": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "session_type": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "uid": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_name": { + "type": "string" + } + } } } }` diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 7a66f53..2ef879d 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -25,7 +25,7 @@ "required": true }, { - "type": "integer", + "type": "string", "description": "name or account", "name": "search", "in": "query" @@ -198,7 +198,7 @@ "required": true }, { - "type": "integer", + "type": "string", "description": "name or ip", "name": "search", "in": "query" @@ -472,7 +472,7 @@ "required": true }, { - "type": "integer", + "type": "string", "description": "name or cmds", "name": "search", "in": "query" @@ -706,6 +706,12 @@ "description": "height", "name": "h", "in": "query" + }, + { + "type": "integer", + "description": "dpi", + "name": "dpi", + "in": "query" } ], "responses": { @@ -720,7 +726,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/model.Session" + "$ref": "#/definitions/session.Session" } } } @@ -736,6 +742,24 @@ "connect" ], "parameters": [ + { + "type": "integer", + "description": "width", + "name": "w", + "in": "query" + }, + { + "type": "integer", + "description": "height", + "name": "h", + "in": "query" + }, + { + "type": "integer", + "description": "dpi", + "name": "dpi", + "in": "query" + }, { "type": "integer", "description": "session id", @@ -784,6 +808,271 @@ } } }, + "/file/download/:asset_id/:account_id": { + "get": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "dir", + "name": "dir", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "filename", + "name": "filename", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/file/history": { + "get": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "page_index", + "name": "page_index", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "page_size", + "name": "page_size", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "search", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "saction", + "name": "action", + "in": "query" + }, + { + "type": "string", + "description": "start, RFC3339", + "name": "start", + "in": "query" + }, + { + "type": "string", + "description": "end, RFC3339", + "name": "end", + "in": "query" + }, + { + "type": "integer", + "description": "uid", + "name": "uid", + "in": "query" + }, + { + "type": "integer", + "description": "asset id", + "name": "asset_id", + "in": "query" + }, + { + "type": "integer", + "description": "account id", + "name": "accout_id", + "in": "query" + }, + { + "type": "string", + "description": "client_ip", + "name": "client_ip", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controller.HttpResponse" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/controller.ListData" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/model.Session" + } + } + } + } + ] + } + } + } + ] + } + } + } + } + }, + "/file/ls/:asset_id/:account_id": { + "post": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "dir", + "name": "dir", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/file/mkdir/:asset_id/:account_id": { + "post": { + "tags": [ + "account" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "dir ", + "name": "dir", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, + "/file/upload/:asset_id/:account_id": { + "post": { + "tags": [ + "file" + ], + "parameters": [ + { + "type": "integer", + "description": "asset_id", + "name": "asset_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "account_id", + "name": "account_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "path", + "name": "path", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.HttpResponse" + } + } + } + } + }, "/gateway": { "get": { "tags": [ @@ -805,7 +1094,7 @@ "required": true }, { - "type": "integer", + "type": "string", "description": "name or host or account or port", "name": "search", "in": "query" @@ -1020,6 +1309,12 @@ "description": "end time, RFC3339", "name": "end", "in": "query" + }, + { + "type": "string", + "description": "search", + "name": "search", + "in": "query" } ], "responses": { @@ -1283,7 +1578,7 @@ "required": true }, { - "type": "integer", + "type": "string", "description": "name or mac", "name": "search", "in": "query" @@ -2600,6 +2895,9 @@ "count": { "type": "integer" }, + "id": { + "type": "integer" + }, "name": { "type": "string" } @@ -2668,6 +2966,68 @@ "type": "integer" } } + }, + "session.Session": { + "type": "object", + "properties": { + "account_id": { + "type": "integer" + }, + "account_info": { + "type": "string" + }, + "asset_id": { + "type": "integer" + }, + "asset_info": { + "type": "string" + }, + "client_ip": { + "type": "string" + }, + "closed_at": { + "type": "string" + }, + "cmd_count": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "duration": { + "type": "integer" + }, + "gateway_id": { + "type": "integer" + }, + "gateway_info": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "session_type": { + "type": "integer" + }, + "status": { + "type": "integer" + }, + "uid": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "user_name": { + "type": "string" + } + } } } } \ No newline at end of file diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 5a3c284..37345b1 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -372,6 +372,8 @@ definitions: properties: count: type: integer + id: + type: integer name: type: string type: object @@ -417,6 +419,47 @@ definitions: type_id: type: integer type: object + session.Session: + properties: + account_id: + type: integer + account_info: + type: string + asset_id: + type: integer + asset_info: + type: string + client_ip: + type: string + closed_at: + type: string + cmd_count: + type: integer + created_at: + type: string + duration: + type: integer + gateway_id: + type: integer + gateway_info: + type: string + id: + type: integer + protocol: + type: string + session_id: + type: string + session_type: + type: integer + status: + type: integer + uid: + type: integer + updated_at: + type: string + user_name: + type: string + type: object info: contact: {} paths: @@ -436,7 +479,7 @@ paths: - description: name or account in: query name: search - type: integer + type: string - description: account id in: query name: id @@ -542,7 +585,7 @@ paths: - description: name or ip in: query name: search - type: integer + type: string - description: asset id in: query name: id @@ -708,7 +751,7 @@ paths: - description: name or cmds in: query name: search - type: integer + type: string - description: command id in: query name: id @@ -847,6 +890,10 @@ paths: in: query name: h type: integer + - description: dpi + in: query + name: dpi + type: integer responses: "200": description: OK @@ -855,13 +902,25 @@ paths: - $ref: '#/definitions/controller.HttpResponse' - properties: data: - $ref: '#/definitions/model.Session' + $ref: '#/definitions/session.Session' type: object tags: - connect /connect/:session_id: get: parameters: + - description: width + in: query + name: w + type: integer + - description: height + in: query + name: h + type: integer + - description: dpi + in: query + name: dpi + type: integer - description: session id in: path name: session_id @@ -892,6 +951,175 @@ paths: $ref: '#/definitions/controller.HttpResponse' tags: - connect + /file/download/:asset_id/:account_id: + get: + parameters: + - description: asset_id + in: path + name: asset_id + required: true + type: integer + - description: account_id + in: path + name: account_id + required: true + type: integer + - description: dir + in: query + name: dir + required: true + type: string + - description: filename + in: query + name: filename + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + tags: + - file + /file/history: + get: + parameters: + - description: page_index + in: query + name: page_index + required: true + type: integer + - description: page_size + in: query + name: page_size + required: true + type: integer + - description: search + in: query + name: search + type: string + - description: saction + in: query + name: action + type: integer + - description: start, RFC3339 + in: query + name: start + type: string + - description: end, RFC3339 + in: query + name: end + type: string + - description: uid + in: query + name: uid + type: integer + - description: asset id + in: query + name: asset_id + type: integer + - description: account id + in: query + name: accout_id + type: integer + - description: client_ip + in: query + name: client_ip + type: string + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/controller.HttpResponse' + - properties: + data: + allOf: + - $ref: '#/definitions/controller.ListData' + - properties: + list: + items: + $ref: '#/definitions/model.Session' + type: array + type: object + type: object + tags: + - file + /file/ls/:asset_id/:account_id: + post: + parameters: + - description: asset_id + in: path + name: asset_id + required: true + type: integer + - description: account_id + in: path + name: account_id + required: true + type: integer + - description: dir + in: query + name: dir + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + tags: + - file + /file/mkdir/:asset_id/:account_id: + post: + parameters: + - description: asset_id + in: path + name: asset_id + required: true + type: integer + - description: account_id + in: path + name: account_id + required: true + type: integer + - description: 'dir ' + in: query + name: dir + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + tags: + - account + /file/upload/:asset_id/:account_id: + post: + parameters: + - description: asset_id + in: path + name: asset_id + required: true + type: integer + - description: account_id + in: path + name: account_id + required: true + type: integer + - description: path + in: query + name: path + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.HttpResponse' + tags: + - file /gateway: get: parameters: @@ -908,7 +1136,7 @@ paths: - description: name or host or account or port in: query name: search - type: integer + type: string - description: gateway id in: query name: id @@ -1042,6 +1270,10 @@ paths: in: query name: end type: string + - description: search + in: query + name: search + type: string responses: "200": description: OK @@ -1199,7 +1431,7 @@ paths: - description: name or mac in: query name: search - type: integer + type: string - description: publicKey id in: query name: id diff --git a/backend/pkg/server/controller/authorization.go b/backend/pkg/server/controller/authorization.go index bd6eab3..d0837ab 100644 --- a/backend/pkg/server/controller/authorization.go +++ b/backend/pkg/server/controller/authorization.go @@ -10,10 +10,12 @@ import ( "github.com/gin-gonic/gin" "github.com/samber/lo" + "go.uber.org/zap" "golang.org/x/sync/errgroup" "gorm.io/gorm" "github.com/veops/oneterm/pkg/conf" + "github.com/veops/oneterm/pkg/logger" "github.com/veops/oneterm/pkg/server/auth/acl" "github.com/veops/oneterm/pkg/server/model" "github.com/veops/oneterm/pkg/server/storage/db/mysql" @@ -151,3 +153,15 @@ func GetAutorizationResourceIds(ctx *gin.Context) (resourceIds []int, err error) return } + +func HasAuthorization(ctx *gin.Context) (ok bool) { + currentUser, _ := acl.GetSessionFromCtx(ctx) + rs, err := acl.GetRoleResources(ctx, currentUser.Acl.Rid, conf.RESOURCE_AUTHORIZATION) + if err != nil { + logger.L.Error("check authorization failed", zap.Error(err)) + return + } + k := fmt.Sprintf("%d-%d", ctx.Param("asset_id"), ctx.Param("account_id")) + _, ok = lo.Find(rs, func(r *acl.Resource) bool { return k == r.Name }) + return +} diff --git a/backend/pkg/server/controller/file.go b/backend/pkg/server/controller/file.go index 16d4db4..a279a6d 100644 --- a/backend/pkg/server/controller/file.go +++ b/backend/pkg/server/controller/file.go @@ -22,7 +22,7 @@ import ( // GetFileHistory godoc // -// @Tags session +// @Tags file // @Param page_index query int true "page_index" // @Param page_size query int true "page_size" // @Param search query string false "search" @@ -53,21 +53,27 @@ func (c *Controller) GetFileHistory(ctx *gin.Context) { // FileLS godoc // -// @Tags account +// @Tags file // @Param asset_id path int true "asset_id" // @Param account_id path int true "account_id" // @Param dir query string true "dir" // @Success 200 {object} HttpResponse // @Router /file/ls/:asset_id/:account_id [post] func (c *Controller) FileLS(ctx *gin.Context) { + currentUser, _ := acl.GetSessionFromCtx(ctx) + if !acl.IsAdmin(currentUser) && !HasAuthorization(ctx) { + ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) + return + } + cli, err := file.GetFileManager().GetFileClient(cast.ToInt(ctx.Param("asset_id")), cast.ToInt(ctx.Param("account_id"))) if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{}}) + ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}}) return } info, err := cli.ReadDir(ctx.Query("dir")) if err != nil { - ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) + ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}}) return } @@ -85,7 +91,7 @@ func (c *Controller) FileLS(ctx *gin.Context) { ctx.JSON(http.StatusOK, NewHttpResponseWithData(res)) } -// FileMkdir godoc +// FileMkdir file // // @Tags account // @Param asset_id path int true "asset_id" @@ -95,6 +101,10 @@ func (c *Controller) FileLS(ctx *gin.Context) { // @Router /file/mkdir/:asset_id/:account_id [post] func (c *Controller) FileMkdir(ctx *gin.Context) { currentUser, _ := acl.GetSessionFromCtx(ctx) + if !acl.IsAdmin(currentUser) && !HasAuthorization(ctx) { + ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) + return + } cli, err := file.GetFileManager().GetFileClient(cast.ToInt(ctx.Param("asset_id")), cast.ToInt(ctx.Param("account_id"))) if err != nil { @@ -123,7 +133,7 @@ func (c *Controller) FileMkdir(ctx *gin.Context) { // FileUpload godoc // -// @Tags account +// @Tags file // @Param asset_id path int true "asset_id" // @Param account_id path int true "account_id" // @Param path query string true "path" @@ -131,6 +141,10 @@ func (c *Controller) FileMkdir(ctx *gin.Context) { // @Router /file/upload/:asset_id/:account_id [post] func (c *Controller) FileUpload(ctx *gin.Context) { currentUser, _ := acl.GetSessionFromCtx(ctx) + if !acl.IsAdmin(currentUser) && !HasAuthorization(ctx) { + ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) + return + } f, fh, err := ctx.Request.FormFile("file") if err != nil { @@ -178,15 +192,19 @@ func (c *Controller) FileUpload(ctx *gin.Context) { // FileDownload godoc // -// @Tags account +// @Tags file // @Param asset_id path int true "asset_id" // @Param account_id path int true "account_id" // @Param dir query string true "dir" -// @Param failename query string true "filename" +// @Param filename query string true "filename" // @Success 200 {object} HttpResponse -// @Router /file/ls/:asset_id/:account_id [get] +// @Router /file/download/:asset_id/:account_id [get] func (c *Controller) FileDownload(ctx *gin.Context) { currentUser, _ := acl.GetSessionFromCtx(ctx) + if !acl.IsAdmin(currentUser) && !HasAuthorization(ctx) { + ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{}}) + return + } cli, err := file.GetFileManager().GetFileClient(cast.ToInt(ctx.Param("asset_id")), cast.ToInt(ctx.Param("account_id"))) if err != nil { diff --git a/backend/pkg/server/global/file/file.go b/backend/pkg/server/global/file/file.go index 584dd2f..076a8f1 100644 --- a/backend/pkg/server/global/file/file.go +++ b/backend/pkg/server/global/file/file.go @@ -14,6 +14,7 @@ import ( ggateway "github.com/veops/oneterm/pkg/server/global/gateway" "github.com/veops/oneterm/pkg/server/model" "github.com/veops/oneterm/pkg/server/storage/db/mysql" + "github.com/veops/oneterm/pkg/util" ) var ( @@ -80,18 +81,33 @@ func (fm *FileManager) GetFileClient(assetId, accountId int) (cli *sftp.Client, if err = mysql.DB.Model(account).Where("id = ?", accountId).First(account).Error; err != nil { return } + account.Password = util.DecryptAES(account.Password) + account.Pk = util.DecryptAES(account.Pk) + account.Phrase = util.DecryptAES(account.Phrase) if asset.GatewayId != 0 { if err = mysql.DB.Model(gateway).Where("id = ?", asset.GatewayId).First(gateway).Error; err != nil { return } + gateway.Password = util.DecryptAES(gateway.Password) + gateway.Pk = util.DecryptAES(gateway.Pk) + gateway.Phrase = util.DecryptAES(gateway.Phrase) } - ip, port := asset.Ip, 22 + ip, port := asset.Ip, 0 for _, p := range asset.Protocols { if strings.HasPrefix(p, "sftp") { port = cast.ToInt(strings.Split(p, ":")[1]) break } } + if port == 0 { + for _, p := range asset.Protocols { + if strings.HasPrefix(p, "ssh") { + port = cast.ToInt(strings.Split(p, ":")[1]) + break + } + } + } + if asset.GatewayId != 0 { sid, _ := uuid.NewUUID() var g *ggateway.GatewayTunnel @@ -106,7 +122,7 @@ func (fm *FileManager) GetFileClient(assetId, accountId int) (cli *sftp.Client, return } sshCli, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", ip, port), &ssh.ClientConfig{ - User: gateway.Account, + User: account.Account, Auth: []ssh.AuthMethod{auth}, Timeout: time.Second * 3, HostKeyCallback: ssh.InsecureIgnoreHostKey(), diff --git a/backend/pkg/server/model/fileHistory.go b/backend/pkg/server/model/fileHistory.go index d9ad9da..4aedf2b 100644 --- a/backend/pkg/server/model/fileHistory.go +++ b/backend/pkg/server/model/fileHistory.go @@ -1,78 +1,31 @@ package model import ( - "strings" "time" ) const ( - SESSIONTYPE_WEB = iota + 1 - SESSIONTYPE_CLIENT + FILE_ACTION_LS = iota + 1 + FILE_ACTION_MKDIR + FILE_ACTION_UPLOAD + FILE_ACTION_DOWNLOAD ) -const ( - SESSIONSTATUS_ONLINE = iota + 1 - SESSIONSTATUS_OFFLINE -) - -const ( - SESSIONACTION_NEW = iota + 1 - SESSIONACTION_MONITOR - SESSIONACTION_CLOSE -) - -type Session struct { - Id int `json:"id" gorm:"column:id;primarykey"` - SessionType int `json:"session_type" gorm:"column:session_type"` - SessionId string `json:"session_id" gorm:"column:session_id"` - Uid int `json:"uid" gorm:"column:uid"` - UserName string `json:"user_name" gorm:"column:user_name"` - AssetId int `json:"asset_id" gorm:"column:asset_id"` - AssetInfo string `json:"asset_info" gorm:"column:asset_info"` - AccountId int `json:"account_id" gorm:"column:account_id"` - AccountInfo string `json:"account_info" gorm:"column:account_info"` - GatewayId int `json:"gateway_id" gorm:"column:gateway_id"` - GatewayInfo string `json:"gateway_info" gorm:"column:gateway_info"` - ClientIp string `json:"client_ip" gorm:"column:client_ip"` - Protocol string `json:"protocol" gorm:"column:protocol"` - Status int `json:"status" gorm:"column:status"` - Duration int64 `json:"duration" gorm:"-"` - ClosedAt *time.Time `json:"closed_at" gorm:"column:closed_at"` +type FileHistory struct { + Id int `json:"id" gorm:"column:id;primarykey"` + Uid int `json:"uid" gorm:"column:uid"` + UserName string `json:"user_name" gorm:"column:user_name"` + AssetId int `json:"asset_id" gorm:"column:asset_id"` + AccountId int `json:"account_id" gorm:"column:account_id"` + ClientIp string `json:"client_ip" gorm:"column:client_ip"` + Action int `json:"action" gorm:"column:action"` + Dir string `json:"dir" gorm:"column:dir"` + Filename string `json:"filename" gorm:"column:filename"` CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"` - - CmdCount int64 `json:"cmd_count" gorm:"-"` } -func (m *Session) TableName() string { - return "filehistory" -} - -type SessionCmd struct { - Id int `json:"id" gorm:"column:id;primarykey"` - SessionId string `json:"session_id" gorm:"column:session_id"` - Cmd string `json:"cmd" gorm:"column:cmd"` - Result string `json:"result" gorm:"column:result"` - Level int `json:"level" gorm:"column:level"` - - CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` -} - -func (m *SessionCmd) TableName() string { - return "session_cmd" -} - -func (m *Session) IsSsh() bool { - return strings.HasPrefix(m.Protocol, "ssh") -} - -type CmdCount struct { - SessionId string `gorm:"column:session_id"` - Count int64 `gorm:"column:count"` -} - -type SessionOptionAsset struct { - Id int `json:"id" gorm:"column:id;primarykey"` - Name string `json:"name" gorm:"column:name"` +func (m *FileHistory) TableName() string { + return "file_history" } diff --git a/backend/pkg/server/model/session.go b/backend/pkg/server/model/session.go index 4b43573..3f1ee02 100644 --- a/backend/pkg/server/model/session.go +++ b/backend/pkg/server/model/session.go @@ -1,31 +1,78 @@ package model import ( + "strings" "time" ) const ( - FILE_ACTION_LS = iota + 1 - FILE_ACTION_MKDIR - FILE_ACTION_UPLOAD - FILE_ACTION_DOWNLOAD + SESSIONTYPE_WEB = iota + 1 + SESSIONTYPE_CLIENT ) -type FileHistory struct { - Id int `json:"id" gorm:"column:id;primarykey"` - Uid int `json:"uid" gorm:"column:uid"` - UserName string `json:"user_name" gorm:"column:user_name"` - AssetId int `json:"asset_id" gorm:"column:asset_id"` - AccountId int `json:"account_id" gorm:"column:account_id"` - ClientIp string `json:"client_ip" gorm:"column:client_ip"` - Action int `json:"action" gorm:"column:action"` - Dir string `json:"dir" gorm:"column:dir"` - Filename string `json:"filename" gorm:"column:filename"` +const ( + SESSIONSTATUS_ONLINE = iota + 1 + SESSIONSTATUS_OFFLINE +) + +const ( + SESSIONACTION_NEW = iota + 1 + SESSIONACTION_MONITOR + SESSIONACTION_CLOSE +) + +type Session struct { + Id int `json:"id" gorm:"column:id;primarykey"` + SessionType int `json:"session_type" gorm:"column:session_type"` + SessionId string `json:"session_id" gorm:"column:session_id"` + Uid int `json:"uid" gorm:"column:uid"` + UserName string `json:"user_name" gorm:"column:user_name"` + AssetId int `json:"asset_id" gorm:"column:asset_id"` + AssetInfo string `json:"asset_info" gorm:"column:asset_info"` + AccountId int `json:"account_id" gorm:"column:account_id"` + AccountInfo string `json:"account_info" gorm:"column:account_info"` + GatewayId int `json:"gateway_id" gorm:"column:gateway_id"` + GatewayInfo string `json:"gateway_info" gorm:"column:gateway_info"` + ClientIp string `json:"client_ip" gorm:"column:client_ip"` + Protocol string `json:"protocol" gorm:"column:protocol"` + Status int `json:"status" gorm:"column:status"` + Duration int64 `json:"duration" gorm:"-"` + ClosedAt *time.Time `json:"closed_at" gorm:"column:closed_at"` CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"` + + CmdCount int64 `json:"cmd_count" gorm:"-"` } -func (m *FileHistory) TableName() string { +func (m *Session) TableName() string { return "session" } + +type SessionCmd struct { + Id int `json:"id" gorm:"column:id;primarykey"` + SessionId string `json:"session_id" gorm:"column:session_id"` + Cmd string `json:"cmd" gorm:"column:cmd"` + Result string `json:"result" gorm:"column:result"` + Level int `json:"level" gorm:"column:level"` + + CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` +} + +func (m *SessionCmd) TableName() string { + return "session_cmd" +} + +func (m *Session) IsSsh() bool { + return strings.HasPrefix(m.Protocol, "ssh") +} + +type CmdCount struct { + SessionId string `gorm:"column:session_id"` + Count int64 `gorm:"column:count"` +} + +type SessionOptionAsset struct { + Id int `json:"id" gorm:"column:id;primarykey"` + Name string `json:"name" gorm:"column:name"` +} diff --git a/backend/pkg/server/router/routers.go b/backend/pkg/server/router/routers.go index 0616643..cb2c75a 100644 --- a/backend/pkg/server/router/routers.go +++ b/backend/pkg/server/router/routers.go @@ -404,29 +404,29 @@ var ( { Name: "file action ls", Method: "GET", - Pattern: "file/ls/:asset_id:/:account_id", + Pattern: "file/ls/:asset_id/:account_id", HandlerFunc: c.FileLS, Middleware: gin.HandlersChain{middleware.Auth()}, }, { Name: "file action mkdir", Method: "POST", - Pattern: "file/mkdir/:asset_id:/:account_id", + Pattern: "file/mkdir/:asset_id/:account_id", HandlerFunc: c.FileMkdir, Middleware: gin.HandlersChain{middleware.Auth()}, }, { Name: "file action upload", Method: "POST", - Pattern: "file/upload/:asset_id:/:account_id", + Pattern: "file/upload/:asset_id/:account_id", HandlerFunc: c.FileUpload, Middleware: gin.HandlersChain{middleware.Auth()}, }, { Name: "file action download", - Method: "Get", - Pattern: "file/upload/:asset_id:/:account_id", - HandlerFunc: c.FileUpload, + Method: "GET", + Pattern: "file/download/:asset_id/:account_id", + HandlerFunc: c.FileDownload, Middleware: gin.HandlersChain{middleware.Auth()}, }, } diff --git a/docs/api.sql b/docs/api.sql index 07c4cf7..082131b 100644 --- a/docs/api.sql +++ b/docs/api.sql @@ -214,4 +214,21 @@ CREATE TABLE UNIQUE KEY `deleted_at` (`deleted_at`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; -INSERT INTO oneterm.config (timeout) VALUES (7200); \ No newline at end of file +INSERT INTO oneterm.config (timeout) VALUES (7200); + + +CREATE TABLE + IF NOT EXISTS oneterm.file_history( + `id` INT NOT NULL AUTO_INCREMENT, + `uid` INT NOT NULL DEFAULT 0, + `user_name` VARCHAR(64) NOT NULL DEFAULT '', + `asset_id` INT NOT NULL DEFAULT 0, + `account_id` INT NOT NULL DEFAULT 0, + `client_ip` VARCHAR(64) NOT NULL DEFAULT '', + `action` INT NOT NULL DEFAULT 0, + `dir` VARCHAR(256) NOT NULL DEFAULT '', + `filename` VARCHAR(256) NOT NULL DEFAULT '', + `created_at` TIMESTAMP NOT NULL, + `updated_at` TIMESTAMP NOT NULL, + PRIMARY KEY(`id`) + ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; \ No newline at end of file