feat: file manager

This commit is contained in:
ttk
2024-04-02 16:18:13 +08:00
parent f74244865c
commit a9c1036338
10 changed files with 1132 additions and 117 deletions

View File

@@ -1,9 +1,7 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT // Package docs Code generated by swaggo/swag. DO NOT EDIT
package docs package docs
import ( import "github.com/swaggo/swag"
"github.com/swaggo/swag"
)
const docTemplate = `{ const docTemplate = `{
"schemes": {{ marshal .Schemes }}, "schemes": {{ marshal .Schemes }},
@@ -38,7 +36,7 @@ const docTemplate = `{
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or account", "description": "name or account",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -211,7 +209,7 @@ const docTemplate = `{
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or ip", "description": "name or ip",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -485,7 +483,7 @@ const docTemplate = `{
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or cmds", "description": "name or cmds",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -719,6 +717,12 @@ const docTemplate = `{
"description": "height", "description": "height",
"name": "h", "name": "h",
"in": "query" "in": "query"
},
{
"type": "integer",
"description": "dpi",
"name": "dpi",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -733,7 +737,7 @@ const docTemplate = `{
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/model.Session" "$ref": "#/definitions/session.Session"
} }
} }
} }
@@ -749,6 +753,24 @@ const docTemplate = `{
"connect" "connect"
], ],
"parameters": [ "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", "type": "integer",
"description": "session id", "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": { "/gateway": {
"get": { "get": {
"tags": [ "tags": [
@@ -818,7 +1105,7 @@ const docTemplate = `{
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or host or account or port", "description": "name or host or account or port",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -1033,6 +1320,12 @@ const docTemplate = `{
"description": "end time, RFC3339", "description": "end time, RFC3339",
"name": "end", "name": "end",
"in": "query" "in": "query"
},
{
"type": "string",
"description": "search",
"name": "search",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -1296,7 +1589,7 @@ const docTemplate = `{
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or mac", "description": "name or mac",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -2613,6 +2906,9 @@ const docTemplate = `{
"count": { "count": {
"type": "integer" "type": "integer"
}, },
"id": {
"type": "integer"
},
"name": { "name": {
"type": "string" "type": "string"
} }
@@ -2681,6 +2977,68 @@ const docTemplate = `{
"type": "integer" "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"
}
}
} }
} }
}` }`

View File

@@ -25,7 +25,7 @@
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or account", "description": "name or account",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -198,7 +198,7 @@
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or ip", "description": "name or ip",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -472,7 +472,7 @@
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or cmds", "description": "name or cmds",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -706,6 +706,12 @@
"description": "height", "description": "height",
"name": "h", "name": "h",
"in": "query" "in": "query"
},
{
"type": "integer",
"description": "dpi",
"name": "dpi",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -720,7 +726,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/model.Session" "$ref": "#/definitions/session.Session"
} }
} }
} }
@@ -736,6 +742,24 @@
"connect" "connect"
], ],
"parameters": [ "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", "type": "integer",
"description": "session id", "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": { "/gateway": {
"get": { "get": {
"tags": [ "tags": [
@@ -805,7 +1094,7 @@
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or host or account or port", "description": "name or host or account or port",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -1020,6 +1309,12 @@
"description": "end time, RFC3339", "description": "end time, RFC3339",
"name": "end", "name": "end",
"in": "query" "in": "query"
},
{
"type": "string",
"description": "search",
"name": "search",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -1283,7 +1578,7 @@
"required": true "required": true
}, },
{ {
"type": "integer", "type": "string",
"description": "name or mac", "description": "name or mac",
"name": "search", "name": "search",
"in": "query" "in": "query"
@@ -2600,6 +2895,9 @@
"count": { "count": {
"type": "integer" "type": "integer"
}, },
"id": {
"type": "integer"
},
"name": { "name": {
"type": "string" "type": "string"
} }
@@ -2668,6 +2966,68 @@
"type": "integer" "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"
}
}
} }
} }
} }

View File

@@ -372,6 +372,8 @@ definitions:
properties: properties:
count: count:
type: integer type: integer
id:
type: integer
name: name:
type: string type: string
type: object type: object
@@ -417,6 +419,47 @@ definitions:
type_id: type_id:
type: integer type: integer
type: object 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: info:
contact: {} contact: {}
paths: paths:
@@ -436,7 +479,7 @@ paths:
- description: name or account - description: name or account
in: query in: query
name: search name: search
type: integer type: string
- description: account id - description: account id
in: query in: query
name: id name: id
@@ -542,7 +585,7 @@ paths:
- description: name or ip - description: name or ip
in: query in: query
name: search name: search
type: integer type: string
- description: asset id - description: asset id
in: query in: query
name: id name: id
@@ -708,7 +751,7 @@ paths:
- description: name or cmds - description: name or cmds
in: query in: query
name: search name: search
type: integer type: string
- description: command id - description: command id
in: query in: query
name: id name: id
@@ -847,6 +890,10 @@ paths:
in: query in: query
name: h name: h
type: integer type: integer
- description: dpi
in: query
name: dpi
type: integer
responses: responses:
"200": "200":
description: OK description: OK
@@ -855,13 +902,25 @@ paths:
- $ref: '#/definitions/controller.HttpResponse' - $ref: '#/definitions/controller.HttpResponse'
- properties: - properties:
data: data:
$ref: '#/definitions/model.Session' $ref: '#/definitions/session.Session'
type: object type: object
tags: tags:
- connect - connect
/connect/:session_id: /connect/:session_id:
get: get:
parameters: 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 - description: session id
in: path in: path
name: session_id name: session_id
@@ -892,6 +951,175 @@ paths:
$ref: '#/definitions/controller.HttpResponse' $ref: '#/definitions/controller.HttpResponse'
tags: tags:
- connect - 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: /gateway:
get: get:
parameters: parameters:
@@ -908,7 +1136,7 @@ paths:
- description: name or host or account or port - description: name or host or account or port
in: query in: query
name: search name: search
type: integer type: string
- description: gateway id - description: gateway id
in: query in: query
name: id name: id
@@ -1042,6 +1270,10 @@ paths:
in: query in: query
name: end name: end
type: string type: string
- description: search
in: query
name: search
type: string
responses: responses:
"200": "200":
description: OK description: OK
@@ -1199,7 +1431,7 @@ paths:
- description: name or mac - description: name or mac
in: query in: query
name: search name: search
type: integer type: string
- description: publicKey id - description: publicKey id
in: query in: query
name: id name: id

View File

@@ -10,10 +10,12 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/samber/lo" "github.com/samber/lo"
"go.uber.org/zap"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/veops/oneterm/pkg/conf" "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/auth/acl"
"github.com/veops/oneterm/pkg/server/model" "github.com/veops/oneterm/pkg/server/model"
"github.com/veops/oneterm/pkg/server/storage/db/mysql" "github.com/veops/oneterm/pkg/server/storage/db/mysql"
@@ -151,3 +153,15 @@ func GetAutorizationResourceIds(ctx *gin.Context) (resourceIds []int, err error)
return 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
}

View File

@@ -22,7 +22,7 @@ import (
// GetFileHistory godoc // GetFileHistory godoc
// //
// @Tags session // @Tags file
// @Param page_index query int true "page_index" // @Param page_index query int true "page_index"
// @Param page_size query int true "page_size" // @Param page_size query int true "page_size"
// @Param search query string false "search" // @Param search query string false "search"
@@ -53,21 +53,27 @@ func (c *Controller) GetFileHistory(ctx *gin.Context) {
// FileLS godoc // FileLS godoc
// //
// @Tags account // @Tags file
// @Param asset_id path int true "asset_id" // @Param asset_id path int true "asset_id"
// @Param account_id path int true "account_id" // @Param account_id path int true "account_id"
// @Param dir query string true "dir" // @Param dir query string true "dir"
// @Success 200 {object} HttpResponse // @Success 200 {object} HttpResponse
// @Router /file/ls/:asset_id/:account_id [post] // @Router /file/ls/:asset_id/:account_id [post]
func (c *Controller) FileLS(ctx *gin.Context) { 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"))) cli, err := file.GetFileManager().GetFileClient(cast.ToInt(ctx.Param("asset_id")), cast.ToInt(ctx.Param("account_id")))
if err != nil { 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 return
} }
info, err := cli.ReadDir(ctx.Query("dir")) info, err := cli.ReadDir(ctx.Query("dir"))
if err != nil { 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 return
} }
@@ -85,7 +91,7 @@ func (c *Controller) FileLS(ctx *gin.Context) {
ctx.JSON(http.StatusOK, NewHttpResponseWithData(res)) ctx.JSON(http.StatusOK, NewHttpResponseWithData(res))
} }
// FileMkdir godoc // FileMkdir file
// //
// @Tags account // @Tags account
// @Param asset_id path int true "asset_id" // @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] // @Router /file/mkdir/:asset_id/:account_id [post]
func (c *Controller) FileMkdir(ctx *gin.Context) { func (c *Controller) FileMkdir(ctx *gin.Context) {
currentUser, _ := acl.GetSessionFromCtx(ctx) 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"))) cli, err := file.GetFileManager().GetFileClient(cast.ToInt(ctx.Param("asset_id")), cast.ToInt(ctx.Param("account_id")))
if err != nil { if err != nil {
@@ -123,7 +133,7 @@ func (c *Controller) FileMkdir(ctx *gin.Context) {
// FileUpload godoc // FileUpload godoc
// //
// @Tags account // @Tags file
// @Param asset_id path int true "asset_id" // @Param asset_id path int true "asset_id"
// @Param account_id path int true "account_id" // @Param account_id path int true "account_id"
// @Param path query string true "path" // @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] // @Router /file/upload/:asset_id/:account_id [post]
func (c *Controller) FileUpload(ctx *gin.Context) { func (c *Controller) FileUpload(ctx *gin.Context) {
currentUser, _ := acl.GetSessionFromCtx(ctx) 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") f, fh, err := ctx.Request.FormFile("file")
if err != nil { if err != nil {
@@ -178,15 +192,19 @@ func (c *Controller) FileUpload(ctx *gin.Context) {
// FileDownload godoc // FileDownload godoc
// //
// @Tags account // @Tags file
// @Param asset_id path int true "asset_id" // @Param asset_id path int true "asset_id"
// @Param account_id path int true "account_id" // @Param account_id path int true "account_id"
// @Param dir query string true "dir" // @Param dir query string true "dir"
// @Param failename query string true "filename" // @Param filename query string true "filename"
// @Success 200 {object} HttpResponse // @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) { func (c *Controller) FileDownload(ctx *gin.Context) {
currentUser, _ := acl.GetSessionFromCtx(ctx) 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"))) cli, err := file.GetFileManager().GetFileClient(cast.ToInt(ctx.Param("asset_id")), cast.ToInt(ctx.Param("account_id")))
if err != nil { if err != nil {

View File

@@ -14,6 +14,7 @@ import (
ggateway "github.com/veops/oneterm/pkg/server/global/gateway" ggateway "github.com/veops/oneterm/pkg/server/global/gateway"
"github.com/veops/oneterm/pkg/server/model" "github.com/veops/oneterm/pkg/server/model"
"github.com/veops/oneterm/pkg/server/storage/db/mysql" "github.com/veops/oneterm/pkg/server/storage/db/mysql"
"github.com/veops/oneterm/pkg/util"
) )
var ( 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 { if err = mysql.DB.Model(account).Where("id = ?", accountId).First(account).Error; err != nil {
return return
} }
account.Password = util.DecryptAES(account.Password)
account.Pk = util.DecryptAES(account.Pk)
account.Phrase = util.DecryptAES(account.Phrase)
if asset.GatewayId != 0 { if asset.GatewayId != 0 {
if err = mysql.DB.Model(gateway).Where("id = ?", asset.GatewayId).First(gateway).Error; err != nil { if err = mysql.DB.Model(gateway).Where("id = ?", asset.GatewayId).First(gateway).Error; err != nil {
return 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 { for _, p := range asset.Protocols {
if strings.HasPrefix(p, "sftp") { if strings.HasPrefix(p, "sftp") {
port = cast.ToInt(strings.Split(p, ":")[1]) port = cast.ToInt(strings.Split(p, ":")[1])
break 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 { if asset.GatewayId != 0 {
sid, _ := uuid.NewUUID() sid, _ := uuid.NewUUID()
var g *ggateway.GatewayTunnel var g *ggateway.GatewayTunnel
@@ -106,7 +122,7 @@ func (fm *FileManager) GetFileClient(assetId, accountId int) (cli *sftp.Client,
return return
} }
sshCli, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", ip, port), &ssh.ClientConfig{ sshCli, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", ip, port), &ssh.ClientConfig{
User: gateway.Account, User: account.Account,
Auth: []ssh.AuthMethod{auth}, Auth: []ssh.AuthMethod{auth},
Timeout: time.Second * 3, Timeout: time.Second * 3,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), HostKeyCallback: ssh.InsecureIgnoreHostKey(),

View File

@@ -1,78 +1,31 @@
package model package model
import ( import (
"strings"
"time" "time"
) )
const ( const (
SESSIONTYPE_WEB = iota + 1 FILE_ACTION_LS = iota + 1
SESSIONTYPE_CLIENT FILE_ACTION_MKDIR
FILE_ACTION_UPLOAD
FILE_ACTION_DOWNLOAD
) )
const ( type FileHistory struct {
SESSIONSTATUS_ONLINE = iota + 1 Id int `json:"id" gorm:"column:id;primarykey"`
SESSIONSTATUS_OFFLINE 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"`
const ( AccountId int `json:"account_id" gorm:"column:account_id"`
SESSIONACTION_NEW = iota + 1 ClientIp string `json:"client_ip" gorm:"column:client_ip"`
SESSIONACTION_MONITOR Action int `json:"action" gorm:"column:action"`
SESSIONACTION_CLOSE Dir string `json:"dir" gorm:"column:dir"`
) Filename string `json:"filename" gorm:"column:filename"`
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"` CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"` UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
CmdCount int64 `json:"cmd_count" gorm:"-"`
} }
func (m *Session) TableName() string { func (m *FileHistory) TableName() string {
return "filehistory" return "file_history"
}
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"`
} }

View File

@@ -1,31 +1,78 @@
package model package model
import ( import (
"strings"
"time" "time"
) )
const ( const (
FILE_ACTION_LS = iota + 1 SESSIONTYPE_WEB = iota + 1
FILE_ACTION_MKDIR SESSIONTYPE_CLIENT
FILE_ACTION_UPLOAD
FILE_ACTION_DOWNLOAD
) )
type FileHistory struct { const (
Id int `json:"id" gorm:"column:id;primarykey"` SESSIONSTATUS_ONLINE = iota + 1
Uid int `json:"uid" gorm:"column:uid"` SESSIONSTATUS_OFFLINE
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"` const (
ClientIp string `json:"client_ip" gorm:"column:client_ip"` SESSIONACTION_NEW = iota + 1
Action int `json:"action" gorm:"column:action"` SESSIONACTION_MONITOR
Dir string `json:"dir" gorm:"column:dir"` SESSIONACTION_CLOSE
Filename string `json:"filename" gorm:"column:filename"` )
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"` CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_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" 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"`
}

View File

@@ -404,29 +404,29 @@ var (
{ {
Name: "file action ls", Name: "file action ls",
Method: "GET", Method: "GET",
Pattern: "file/ls/:asset_id:/:account_id", Pattern: "file/ls/:asset_id/:account_id",
HandlerFunc: c.FileLS, HandlerFunc: c.FileLS,
Middleware: gin.HandlersChain{middleware.Auth()}, Middleware: gin.HandlersChain{middleware.Auth()},
}, },
{ {
Name: "file action mkdir", Name: "file action mkdir",
Method: "POST", Method: "POST",
Pattern: "file/mkdir/:asset_id:/:account_id", Pattern: "file/mkdir/:asset_id/:account_id",
HandlerFunc: c.FileMkdir, HandlerFunc: c.FileMkdir,
Middleware: gin.HandlersChain{middleware.Auth()}, Middleware: gin.HandlersChain{middleware.Auth()},
}, },
{ {
Name: "file action upload", Name: "file action upload",
Method: "POST", Method: "POST",
Pattern: "file/upload/:asset_id:/:account_id", Pattern: "file/upload/:asset_id/:account_id",
HandlerFunc: c.FileUpload, HandlerFunc: c.FileUpload,
Middleware: gin.HandlersChain{middleware.Auth()}, Middleware: gin.HandlersChain{middleware.Auth()},
}, },
{ {
Name: "file action download", Name: "file action download",
Method: "Get", Method: "GET",
Pattern: "file/upload/:asset_id:/:account_id", Pattern: "file/download/:asset_id/:account_id",
HandlerFunc: c.FileUpload, HandlerFunc: c.FileDownload,
Middleware: gin.HandlersChain{middleware.Auth()}, Middleware: gin.HandlersChain{middleware.Auth()},
}, },
} }

View File

@@ -214,4 +214,21 @@ CREATE TABLE
UNIQUE KEY `deleted_at` (`deleted_at`) UNIQUE KEY `deleted_at` (`deleted_at`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
INSERT INTO oneterm.config (timeout) VALUES (7200); 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;