Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
K
koko
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
koko
Commits
d80a7d05
Unverified
Commit
d80a7d05
authored
Jul 18, 2019
by
Eric_Lee
Committed by
GitHub
Jul 18, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sftp优化 (#37)
* [update]sftp优化 * 调整sftp结构 * 优化sftp code
parent
0c876a8e
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
887 additions
and
1293 deletions
+887
-1293
go.mod
go.mod
+1
-1
go.sum
go.sum
+4
-2
session.go
pkg/handler/session.go
+1
-1
sftp.go
pkg/handler/sftp.go
+58
-446
elfhandler.go
pkg/httpd/elfhandler.go
+8
-1
sftpvolume.go
pkg/httpd/sftpvolume.go
+126
-832
volumemanager.go
pkg/httpd/volumemanager.go
+10
-3
task.go
pkg/koko/task.go
+1
-1
assets.go
pkg/model/assets.go
+1
-0
connection.go
pkg/model/connection.go
+10
-0
recorder.go
pkg/proxy/recorder.go
+4
-4
perms.go
pkg/service/perms.go
+4
-1
sftpconn.go
pkg/srvconn/sftpconn.go
+657
-0
utils.go
pkg/srvconn/utils.go
+2
-1
No files found.
go.mod
View file @
d80a7d05
...
@@ -5,7 +5,7 @@ go 1.12
...
@@ -5,7 +5,7 @@ go 1.12
require (
require (
github.com/Azure/azure-pipeline-go v0.1.9 // indirect
github.com/Azure/azure-pipeline-go v0.1.9 // indirect
github.com/Azure/azure-storage-blob-go v0.6.0
github.com/Azure/azure-storage-blob-go v0.6.0
github.com/LeeEirc/elfinder v0.0.0-20190
604073433-f4f8357e9220
github.com/LeeEirc/elfinder v0.0.0-20190
718024942-8893ec7a969f
github.com/aliyun/aliyun-oss-go-sdk v1.9.8
github.com/aliyun/aliyun-oss-go-sdk v1.9.8
github.com/aws/aws-sdk-go v1.19.46
github.com/aws/aws-sdk-go v1.19.46
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
...
...
go.sum
View file @
d80a7d05
...
@@ -15,6 +15,10 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
...
@@ -15,6 +15,10 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/LeeEirc/elfinder v0.0.0-20190604073433-f4f8357e9220 h1:U865EO8YNrjZIGNp7O8QEYLZFDJ8zcooD73BiAqgDg4=
github.com/LeeEirc/elfinder v0.0.0-20190604073433-f4f8357e9220 h1:U865EO8YNrjZIGNp7O8QEYLZFDJ8zcooD73BiAqgDg4=
github.com/LeeEirc/elfinder v0.0.0-20190604073433-f4f8357e9220/go.mod h1:ApL/XFs34Gvqinex9Z1sZdsp3Jeu26nNuEsf1wQFx8s=
github.com/LeeEirc/elfinder v0.0.0-20190604073433-f4f8357e9220/go.mod h1:ApL/XFs34Gvqinex9Z1sZdsp3Jeu26nNuEsf1wQFx8s=
github.com/LeeEirc/elfinder v0.0.0-20190718023636-5679c8bdb7bf h1:dZipr1cwienSKNTXsveMmyd7VFY3v/eMHNl/vueN10s=
github.com/LeeEirc/elfinder v0.0.0-20190718023636-5679c8bdb7bf/go.mod h1:ApL/XFs34Gvqinex9Z1sZdsp3Jeu26nNuEsf1wQFx8s=
github.com/LeeEirc/elfinder v0.0.0-20190718024942-8893ec7a969f h1:xhKgvkrt+lR8IRL+YzmeebV0dlrOiFj1i4UfwSEPVSc=
github.com/LeeEirc/elfinder v0.0.0-20190718024942-8893ec7a969f/go.mod h1:ApL/XFs34Gvqinex9Z1sZdsp3Jeu26nNuEsf1wQFx8s=
github.com/LeeEirc/go-socket.io v1.4.2-0.20190610105739-e344e8b5a55a h1:l5fhBUD24xuw9S4yCUd6hD7OFjYXiJiALT1aqQ4LLfA=
github.com/LeeEirc/go-socket.io v1.4.2-0.20190610105739-e344e8b5a55a h1:l5fhBUD24xuw9S4yCUd6hD7OFjYXiJiALT1aqQ4LLfA=
github.com/LeeEirc/go-socket.io v1.4.2-0.20190610105739-e344e8b5a55a/go.mod h1:yjlQxKcAZXZjpGwQVW/y1sgyL1ou+DdCpkswURDCRrU=
github.com/LeeEirc/go-socket.io v1.4.2-0.20190610105739-e344e8b5a55a/go.mod h1:yjlQxKcAZXZjpGwQVW/y1sgyL1ou+DdCpkswURDCRrU=
github.com/aliyun/aliyun-oss-go-sdk v1.9.8 h1:BOflvK0Zs/zGmoabyFIzTg5c3kguktWTXEwewwbuba0=
github.com/aliyun/aliyun-oss-go-sdk v1.9.8 h1:BOflvK0Zs/zGmoabyFIzTg5c3kguktWTXEwewwbuba0=
...
@@ -66,8 +70,6 @@ github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH
...
@@ -66,8 +70,6 @@ github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/ibuler/crypto v0.0.0-20190509101200-a7099eef26a7 h1:1wAr7VKNYJw3mhTTU1Ztu5lyJKHzHmjlA9n+LV09z8E=
github.com/ibuler/crypto v0.0.0-20190509101200-a7099eef26a7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
github.com/ibuler/crypto v0.0.0-20190715092645-911d13b3bf6e h1:QnLvABxtQH9BFja0P/wEjeTPABqvvwIz+to52VNn170=
github.com/ibuler/crypto v0.0.0-20190715092645-911d13b3bf6e h1:QnLvABxtQH9BFja0P/wEjeTPABqvvwIz+to52VNn170=
github.com/ibuler/crypto v0.0.0-20190715092645-911d13b3bf6e/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
github.com/ibuler/crypto v0.0.0-20190715092645-911d13b3bf6e/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
github.com/ibuler/go-engine.io v1.4.2-0.20190529094538-7786d3a289b9 h1:8vjRBcvQ50mYr5y9jQWbYXOew3nn3+eF2YNpaAcFrAU=
github.com/ibuler/go-engine.io v1.4.2-0.20190529094538-7786d3a289b9 h1:8vjRBcvQ50mYr5y9jQWbYXOew3nn3+eF2YNpaAcFrAU=
...
...
pkg/handler/session.go
View file @
d80a7d05
...
@@ -323,7 +323,7 @@ func (h *interactiveHandler) refreshAssetsAndNodesData() {
...
@@ -323,7 +323,7 @@ func (h *interactiveHandler) refreshAssetsAndNodesData() {
}
}
func
(
h
*
interactiveHandler
)
loadUserAssets
(
cachePolicy
string
)
{
func
(
h
*
interactiveHandler
)
loadUserAssets
(
cachePolicy
string
)
{
assets
:=
service
.
GetUserAssets
(
h
.
user
.
ID
,
cachePolicy
)
assets
:=
service
.
GetUserAssets
(
h
.
user
.
ID
,
cachePolicy
,
""
)
userAssetsCached
.
SetValue
(
h
.
user
.
ID
,
assets
)
userAssetsCached
.
SetValue
(
h
.
user
.
ID
,
assets
)
h
.
mu
.
Lock
()
h
.
mu
.
Lock
()
h
.
assets
=
assets
h
.
assets
=
assets
...
...
pkg/handler/sftp.go
View file @
d80a7d05
package
handler
package
handler
import
(
import
(
"fmt"
"io"
"io"
"net"
"net"
"os"
"os"
"strings"
"sync"
"sync"
"syscall"
"syscall"
"time"
"time"
...
@@ -14,8 +12,6 @@ import (
...
@@ -14,8 +12,6 @@ import (
"github.com/pkg/sftp"
"github.com/pkg/sftp"
"github.com/jumpserver/koko/pkg/cctx"
"github.com/jumpserver/koko/pkg/cctx"
"github.com/jumpserver/koko/pkg/common"
"github.com/jumpserver/koko/pkg/config"
"github.com/jumpserver/koko/pkg/logger"
"github.com/jumpserver/koko/pkg/logger"
"github.com/jumpserver/koko/pkg/model"
"github.com/jumpserver/koko/pkg/model"
"github.com/jumpserver/koko/pkg/service"
"github.com/jumpserver/koko/pkg/service"
...
@@ -26,498 +22,94 @@ func SftpHandler(sess ssh.Session) {
...
@@ -26,498 +22,94 @@ func SftpHandler(sess ssh.Session) {
ctx
,
cancel
:=
cctx
.
NewContext
(
sess
)
ctx
,
cancel
:=
cctx
.
NewContext
(
sess
)
defer
cancel
()
defer
cancel
()
host
,
_
,
_
:=
net
.
SplitHostPort
(
sess
.
RemoteAddr
()
.
String
())
host
,
_
,
_
:=
net
.
SplitHostPort
(
sess
.
RemoteAddr
()
.
String
())
handler
:=
&
sftpHandler
{
user
:
ctx
.
User
(),
addr
:
host
}
userSftp
:=
NewSFTPHandler
(
ctx
.
User
(),
host
)
handler
.
initial
()
handlers
:=
sftp
.
Handlers
{
handlers
:=
sftp
.
Handlers
{
FileGet
:
handler
,
FileGet
:
userSftp
,
FilePut
:
handler
,
FilePut
:
userSftp
,
FileCmd
:
handler
,
FileCmd
:
userSftp
,
FileList
:
handler
,
FileList
:
userSftp
,
}
}
req
:=
sftp
.
NewRequestServer
(
sess
,
handlers
)
req
:=
sftp
.
NewRequestServer
(
sess
,
handlers
)
if
err
:=
req
.
Serve
();
err
==
io
.
EOF
{
if
err
:=
req
.
Serve
();
err
==
io
.
EOF
{
_
=
req
.
Close
()
_
=
req
.
Close
()
handler
.
Close
()
userSftp
.
Close
()
logger
.
Info
(
"sftp client exited session."
)
logger
.
Info
(
"sftp client exited session."
)
}
else
if
err
!=
nil
{
}
else
if
err
!=
nil
{
logger
.
Error
(
"sftp server completed with error:"
,
err
)
logger
.
Error
(
"sftp server completed with error:"
,
err
)
}
}
}
}
type
sftpHandler
struct
{
func
NewSFTPHandler
(
user
*
model
.
User
,
addr
string
)
*
sftpHandler
{
user
*
model
.
User
assets
:=
service
.
GetUserAssets
(
user
.
ID
,
"1"
,
""
)
addr
string
return
&
sftpHandler
{
srvconn
.
NewUserSFTP
(
user
,
addr
,
assets
...
)}
assets
model
.
AssetList
rootPath
string
// tmp || home || ~
hosts
map
[
string
]
*
HostNameDir
permCache
map
[
string
]
bool
}
}
func
(
fs
*
sftpHandler
)
initial
()
{
type
sftpHandler
struct
{
fs
.
loadAssets
()
*
srvconn
.
UserSftp
fs
.
hosts
=
make
(
map
[
string
]
*
HostNameDir
)
fs
.
rootPath
=
config
.
GetConf
()
.
SftpRoot
fs
.
permCache
=
make
(
map
[
string
]
bool
)
for
i
,
item
:=
range
fs
.
assets
{
tmpDir
:=
&
HostNameDir
{
rootPath
:
fs
.
rootPath
,
hostname
:
item
.
Hostname
,
asset
:
&
fs
.
assets
[
i
],
time
:
time
.
Now
()
.
UTC
(),
}
fs
.
hosts
[
item
.
Hostname
]
=
tmpDir
}
}
func
(
fs
*
sftpHandler
)
loadAssets
()
{
fs
.
assets
=
service
.
GetUserAssets
(
fs
.
user
.
ID
,
"1"
)
}
}
func
(
fs
*
sftpHandler
)
Filelist
(
r
*
sftp
.
Request
)
(
sftp
.
ListerAt
,
error
)
{
func
(
fs
*
sftpHandler
)
Filelist
(
r
*
sftp
.
Request
)
(
sftp
.
ListerAt
,
error
)
{
var
fileInfos
=
listerat
{}
var
err
error
logger
.
Debug
(
"list path: "
,
r
.
Filepath
)
if
r
.
Filepath
==
"/"
{
for
_
,
v
:=
range
fs
.
hosts
{
fileInfos
=
append
(
fileInfos
,
v
)
}
logger
.
Debug
(
fileInfos
)
return
fileInfos
,
err
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
r
.
Filepath
,
"/"
),
"/"
)
hostDir
,
ok
:=
fs
.
hosts
[
pathNames
[
0
]]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
hostDir
.
suMaps
==
nil
{
hostDir
.
suMaps
=
make
(
map
[
string
]
*
SysUserDir
)
systemUsers
:=
hostDir
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostDir
.
suMaps
[
sysUser
.
Name
]
=
&
SysUserDir
{
time
:
time
.
Now
()
.
UTC
(),
rootPath
:
fs
.
rootPath
,
systemUser
:
&
systemUsers
[
i
],
prefix
:
fmt
.
Sprintf
(
"/%s/%s"
,
hostDir
.
asset
.
Hostname
,
sysUser
.
Name
),
}
}
}
if
len
(
pathNames
)
==
1
{
for
_
,
v
:=
range
hostDir
.
suMaps
{
fileInfos
=
append
(
fileInfos
,
v
)
}
return
fileInfos
,
err
}
var
realPath
string
var
sysUserDir
*
SysUserDir
sysUserDir
,
ok
=
hostDir
.
suMaps
[
pathNames
[
1
]]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
fs
.
validatePermission
(
hostDir
.
asset
.
ID
,
sysUserDir
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
if
sysUserDir
.
client
==
nil
{
client
,
conn
,
err
:=
fs
.
GetSftpClient
(
hostDir
.
asset
,
sysUserDir
.
systemUser
)
if
err
!=
nil
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
sysUserDir
.
homeDirPath
,
err
=
client
.
Getwd
()
if
err
!=
nil
{
return
nil
,
err
}
sysUserDir
.
client
=
client
sysUserDir
.
conn
=
conn
}
realPath
=
sysUserDir
.
ParsePath
(
r
.
Filepath
)
switch
r
.
Method
{
switch
r
.
Method
{
case
"List"
:
case
"List"
:
logger
.
Debug
(
"List method
"
)
logger
.
Debug
(
"List method
: "
,
r
.
Filepath
)
fileInfos
,
err
=
sysUserDir
.
client
.
ReadDir
(
realP
ath
)
res
,
err
:=
fs
.
ReadDir
(
r
.
Filep
ath
)
wraperFiles
:=
make
([]
os
.
FileInfo
,
0
,
len
(
fileInfo
s
))
fileInfos
:=
make
(
listerat
,
0
,
len
(
re
s
))
for
i
:=
0
;
i
<
len
(
fileInfo
s
);
i
++
{
for
i
:=
0
;
i
<
len
(
re
s
);
i
++
{
wraperFiles
=
append
(
wraperFiles
,
&
wrapperFileInfo
{
f
:
fileInfo
s
[
i
]})
fileInfos
=
append
(
fileInfos
,
&
wrapperSFTPFileInfo
{
f
:
re
s
[
i
]})
}
}
return
listerat
(
wraperFiles
)
,
err
return
fileInfos
,
err
case
"Stat"
:
case
"Stat"
:
logger
.
Debug
(
"stat method"
)
logger
.
Debug
(
"stat method: "
,
r
.
Filepath
)
fsInfo
,
err
:=
sysUserDir
.
client
.
Stat
(
realPath
)
fsInfo
,
err
:=
fs
.
Stat
(
r
.
Filepath
)
return
listerat
([]
os
.
FileInfo
{
&
wrapperFileInfo
{
f
:
fsInfo
}}),
err
case
"Readlink"
:
logger
.
Debug
(
"Readlink method"
)
filename
,
err
:=
sysUserDir
.
client
.
ReadLink
(
realPath
)
fsInfo
:=
&
FakeFile
{
name
:
filename
,
modtime
:
time
.
Now
()
.
UTC
()}
return
listerat
([]
os
.
FileInfo
{
fsInfo
}),
err
return
listerat
([]
os
.
FileInfo
{
fsInfo
}),
err
case
"Readlink"
:
logger
.
Debug
(
"Readlink method"
,
r
.
Filepath
)
filename
,
err
:=
fs
.
ReadLink
(
r
.
Filepath
)
fsInfo
:=
srvconn
.
NewFakeSymFile
(
filename
)
return
listerat
([]
os
.
FileInfo
{
&
wrapperSFTPFileInfo
{
f
:
fsInfo
}}),
err
}
}
return
fileInfos
,
err
return
nil
,
sftp
.
ErrSshFxOpUnsupported
}
}
func
(
fs
*
sftpHandler
)
Filecmd
(
r
*
sftp
.
Request
)
(
err
error
)
{
func
(
fs
*
sftpHandler
)
Filecmd
(
r
*
sftp
.
Request
)
(
err
error
)
{
logger
.
Debug
(
"File cmd: "
,
r
.
Filepath
)
logger
.
Debug
(
"File cmd: "
,
r
.
Filepath
)
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
r
.
Filepath
,
"/"
),
"/"
)
if
len
(
pathNames
)
<=
2
{
return
sftp
.
ErrSshFxPermissionDenied
}
hostDir
,
ok
:=
fs
.
hosts
[
pathNames
[
0
]]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
hostDir
.
suMaps
==
nil
{
hostDir
.
suMaps
=
make
(
map
[
string
]
*
SysUserDir
)
systemUsers
:=
hostDir
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostDir
.
suMaps
[
sysUser
.
Name
]
=
&
SysUserDir
{
time
:
time
.
Now
()
.
UTC
(),
rootPath
:
fs
.
rootPath
,
systemUser
:
&
systemUsers
[
i
],
prefix
:
fmt
.
Sprintf
(
"/%s/%s"
,
hostDir
.
asset
.
Hostname
,
sysUser
.
Name
),
}
}
}
suDir
,
ok
:=
hostDir
.
suMaps
[
pathNames
[
1
]]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
!
fs
.
validatePermission
(
hostDir
.
asset
.
ID
,
suDir
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
sftp
.
ErrSshFxPermissionDenied
}
if
suDir
.
client
==
nil
{
client
,
conn
,
err
:=
fs
.
GetSftpClient
(
hostDir
.
asset
,
suDir
.
systemUser
)
if
err
!=
nil
{
return
sftp
.
ErrSshFxPermissionDenied
}
suDir
.
homeDirPath
,
err
=
client
.
Getwd
()
if
err
!=
nil
{
return
err
}
suDir
.
client
=
client
suDir
.
conn
=
conn
}
realPathName
:=
suDir
.
ParsePath
(
r
.
Filepath
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
fs
.
user
.
Name
,
fs
.
user
.
Username
),
Hostname
:
hostDir
.
asset
.
Hostname
,
OrgID
:
hostDir
.
asset
.
OrgID
,
SystemUser
:
suDir
.
systemUser
.
Name
,
RemoteAddr
:
fs
.
addr
,
Operate
:
r
.
Method
,
Path
:
realPathName
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
fs
.
CreateFTPLog
(
logData
)
switch
r
.
Method
{
switch
r
.
Method
{
case
"Setstat"
:
case
"Setstat"
:
return
return
case
"Rename"
:
case
"Rename"
:
realNewName
:=
suDir
.
ParsePath
(
r
.
Target
)
logger
.
Debug
(
"%s=>%s"
,
r
.
Filepath
,
r
.
Target
)
logData
.
Path
=
fmt
.
Sprintf
(
"%s=>%s"
,
realPathName
,
realNewName
)
return
fs
.
Rename
(
r
.
Filepath
,
r
.
Target
)
err
=
suDir
.
client
.
Rename
(
realPathName
,
realNewName
)
case
"Rmdir"
:
case
"Rmdir"
:
err
=
suDir
.
client
.
RemoveDirectory
(
realPathName
)
err
=
fs
.
RemoveDirectory
(
r
.
Filepath
)
case
"Remove"
:
case
"Remove"
:
err
=
suDir
.
client
.
Remove
(
realPathName
)
err
=
fs
.
Remove
(
r
.
Filepath
)
case
"Mkdir"
:
case
"Mkdir"
:
err
=
suDir
.
client
.
MkdirAll
(
realPathName
)
err
=
fs
.
MkdirAll
(
r
.
Filepath
)
case
"Symlink"
:
case
"Symlink"
:
realNewName
:=
suDir
.
ParsePath
(
r
.
Target
)
logger
.
Debug
(
"%s=>%s"
,
r
.
Filepath
,
r
.
Target
)
logData
.
Path
=
fmt
.
Sprintf
(
"%s=>%s"
,
realPathName
,
realNewName
)
err
=
fs
.
Symlink
(
r
.
Filepath
,
r
.
Target
)
err
=
suDir
.
client
.
Symlink
(
realPathName
,
realNewName
)
default
:
default
:
return
return
}
}
if
err
==
nil
{
logData
.
IsSuccess
=
true
}
return
return
}
}
func
(
fs
*
sftpHandler
)
Filewrite
(
r
*
sftp
.
Request
)
(
io
.
WriterAt
,
error
)
{
func
(
fs
*
sftpHandler
)
Filewrite
(
r
*
sftp
.
Request
)
(
io
.
WriterAt
,
error
)
{
logger
.
Debug
(
"File write: "
,
r
.
Filepath
)
logger
.
Debug
(
"File write: "
,
r
.
Filepath
)
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
r
.
Filepath
,
"/"
),
"/"
)
f
,
err
:=
fs
.
Create
(
r
.
Filepath
)
if
len
(
pathNames
)
<=
2
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
hostDir
,
ok
:=
fs
.
hosts
[
pathNames
[
0
]]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
hostDir
.
suMaps
==
nil
{
hostDir
.
suMaps
=
make
(
map
[
string
]
*
SysUserDir
)
systemUsers
:=
hostDir
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostDir
.
suMaps
[
sysUser
.
Name
]
=
&
SysUserDir
{
time
:
time
.
Now
()
.
UTC
(),
rootPath
:
fs
.
rootPath
,
systemUser
:
&
systemUsers
[
i
],
prefix
:
fmt
.
Sprintf
(
"/%s/%s"
,
hostDir
.
asset
.
Hostname
,
sysUser
.
Name
),
}
}
}
suDir
,
ok
:=
hostDir
.
suMaps
[
pathNames
[
1
]]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
fs
.
validatePermission
(
hostDir
.
asset
.
ID
,
suDir
.
systemUser
.
ID
,
model
.
UploadAction
)
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
if
suDir
.
client
==
nil
{
client
,
conn
,
err
:=
fs
.
GetSftpClient
(
hostDir
.
asset
,
suDir
.
systemUser
)
if
err
!=
nil
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
suDir
.
homeDirPath
,
err
=
client
.
Getwd
()
if
err
!=
nil
{
return
nil
,
err
}
suDir
.
client
=
client
suDir
.
conn
=
conn
}
realPathName
:=
suDir
.
ParsePath
(
r
.
Filepath
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
fs
.
user
.
Name
,
fs
.
user
.
Username
),
Hostname
:
hostDir
.
asset
.
Hostname
,
OrgID
:
hostDir
.
asset
.
OrgID
,
SystemUser
:
suDir
.
systemUser
.
Name
,
RemoteAddr
:
fs
.
addr
,
Operate
:
"Upload"
,
Path
:
realPathName
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
fs
.
CreateFTPLog
(
logData
)
f
,
err
:=
suDir
.
client
.
Create
(
realPathName
)
if
err
==
nil
{
logData
.
IsSuccess
=
true
}
return
NewWriterAt
(
f
),
err
return
NewWriterAt
(
f
),
err
}
}
func
(
fs
*
sftpHandler
)
Fileread
(
r
*
sftp
.
Request
)
(
io
.
ReaderAt
,
error
)
{
func
(
fs
*
sftpHandler
)
Fileread
(
r
*
sftp
.
Request
)
(
io
.
ReaderAt
,
error
)
{
logger
.
Debug
(
"File read: "
,
r
.
Filepath
)
logger
.
Debug
(
"File read: "
,
r
.
Filepath
)
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
r
.
Filepath
,
"/"
),
"/"
)
f
,
err
:=
fs
.
Open
(
r
.
Filepath
)
if
len
(
pathNames
)
<=
2
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
hostDir
,
ok
:=
fs
.
hosts
[
pathNames
[
0
]]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
hostDir
.
suMaps
==
nil
{
hostDir
.
suMaps
=
make
(
map
[
string
]
*
SysUserDir
)
systemUsers
:=
hostDir
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostDir
.
suMaps
[
sysUser
.
Name
]
=
&
SysUserDir
{
time
:
time
.
Now
()
.
UTC
(),
rootPath
:
fs
.
rootPath
,
systemUser
:
&
systemUsers
[
i
],
prefix
:
fmt
.
Sprintf
(
"/%s/%s"
,
hostDir
.
asset
.
Hostname
,
sysUser
.
Name
),
}
}
}
suDir
,
ok
:=
hostDir
.
suMaps
[
pathNames
[
1
]]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
fs
.
validatePermission
(
hostDir
.
asset
.
ID
,
suDir
.
systemUser
.
ID
,
model
.
DownloadAction
)
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
if
suDir
.
client
==
nil
{
ftpClient
,
client
,
err
:=
fs
.
GetSftpClient
(
hostDir
.
asset
,
suDir
.
systemUser
)
if
err
!=
nil
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
suDir
.
homeDirPath
,
err
=
ftpClient
.
Getwd
()
if
err
!=
nil
{
return
nil
,
err
}
suDir
.
client
=
ftpClient
suDir
.
conn
=
client
}
realPathName
:=
suDir
.
ParsePath
(
r
.
Filepath
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
fs
.
user
.
Name
,
fs
.
user
.
Username
),
Hostname
:
hostDir
.
asset
.
Hostname
,
OrgID
:
hostDir
.
asset
.
OrgID
,
SystemUser
:
suDir
.
systemUser
.
Name
,
RemoteAddr
:
fs
.
addr
,
Operate
:
"Download"
,
Path
:
realPathName
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
fs
.
CreateFTPLog
(
logData
)
f
,
err
:=
suDir
.
client
.
Open
(
realPathName
)
if
err
!=
nil
{
return
nil
,
err
}
logData
.
IsSuccess
=
true
return
NewReaderAt
(
f
),
err
return
NewReaderAt
(
f
),
err
}
}
func
(
fs
*
sftpHandler
)
GetSftpClient
(
asset
*
model
.
Asset
,
sysUser
*
model
.
SystemUser
)
(
sftpClient
*
sftp
.
Client
,
sshClient
*
srvconn
.
SSHClient
,
err
error
)
{
sshClient
,
err
=
srvconn
.
NewClient
(
fs
.
user
,
asset
,
sysUser
,
config
.
GetConf
()
.
SSHTimeout
*
time
.
Second
)
if
err
!=
nil
{
return
}
sftpClient
,
err
=
sftp
.
NewClient
(
sshClient
.
Client
)
if
err
!=
nil
{
return
}
return
sftpClient
,
sshClient
,
err
}
func
(
fs
*
sftpHandler
)
CreateFTPLog
(
data
*
model
.
FTPLog
)
{
for
i
:=
0
;
i
<
4
;
i
++
{
err
:=
service
.
PushFTPLog
(
data
)
if
err
==
nil
{
break
}
logger
.
Debugf
(
"create FTP log err: %s"
,
err
.
Error
())
}
}
func
(
fs
*
sftpHandler
)
Close
()
{
func
(
fs
*
sftpHandler
)
Close
()
{
for
_
,
dir
:=
range
fs
.
hosts
{
fs
.
UserSftp
.
Close
()
if
dir
.
suMaps
==
nil
{
continue
}
for
_
,
d
:=
range
dir
.
suMaps
{
if
d
.
client
!=
nil
{
_
=
d
.
client
.
Close
()
srvconn
.
RecycleClient
(
d
.
conn
)
}
}
}
}
func
(
fs
*
sftpHandler
)
validatePermission
(
aid
,
suid
,
operate
string
)
bool
{
permKey
:=
fmt
.
Sprintf
(
"%s_%s_%s"
,
aid
,
suid
,
operate
)
permission
,
ok
:=
fs
.
permCache
[
permKey
]
if
ok
{
return
permission
}
permission
=
service
.
ValidateUserAssetPermission
(
fs
.
user
.
ID
,
aid
,
suid
,
operate
,
)
fs
.
permCache
[
permKey
]
=
permission
return
permission
}
type
HostNameDir
struct
{
rootPath
string
hostname
string
time
time
.
Time
asset
*
model
.
Asset
suMaps
map
[
string
]
*
SysUserDir
}
func
(
h
*
HostNameDir
)
Name
()
string
{
return
h
.
hostname
}
func
(
h
*
HostNameDir
)
Size
()
int64
{
return
int64
(
0
)
}
func
(
h
*
HostNameDir
)
Mode
()
os
.
FileMode
{
return
os
.
FileMode
(
0400
)
|
os
.
ModeDir
}
func
(
h
*
HostNameDir
)
ModTime
()
time
.
Time
{
return
h
.
time
}
func
(
h
*
HostNameDir
)
IsDir
()
bool
{
return
true
}
func
(
h
*
HostNameDir
)
Sys
()
interface
{}
{
// fake current dir sys info
fakeInfo
,
_
:=
os
.
Stat
(
"."
)
return
fakeInfo
.
Sys
()
}
type
SysUserDir
struct
{
ID
string
prefix
string
rootPath
string
systemUser
*
model
.
SystemUser
time
time
.
Time
homeDirPath
string
client
*
sftp
.
Client
conn
*
srvconn
.
SSHClient
}
func
(
su
*
SysUserDir
)
Name
()
string
{
return
su
.
systemUser
.
Name
}
func
(
su
*
SysUserDir
)
Size
()
int64
{
return
int64
(
0
)
}
func
(
su
*
SysUserDir
)
Mode
()
os
.
FileMode
{
return
os
.
FileMode
(
0400
)
|
os
.
ModeDir
}
func
(
su
*
SysUserDir
)
ModTime
()
time
.
Time
{
return
su
.
time
}
func
(
su
*
SysUserDir
)
IsDir
()
bool
{
return
true
}
func
(
su
*
SysUserDir
)
Sys
()
interface
{}
{
// fake current dir sys info
fakeInfo
,
_
:=
os
.
Stat
(
"."
)
return
fakeInfo
.
Sys
()
}
func
(
su
*
SysUserDir
)
ParsePath
(
path
string
)
string
{
var
realPath
string
switch
strings
.
ToLower
(
su
.
rootPath
)
{
case
"home"
,
"~"
,
""
:
realPath
=
strings
.
ReplaceAll
(
path
,
su
.
prefix
,
su
.
homeDirPath
)
default
:
realPath
=
strings
.
ReplaceAll
(
path
,
su
.
prefix
,
su
.
rootPath
)
}
logger
.
Debug
(
"real path: "
,
realPath
)
return
realPath
}
type
FakeFile
struct
{
name
string
modtime
time
.
Time
symlink
string
}
func
(
f
*
FakeFile
)
Name
()
string
{
return
f
.
name
}
func
(
f
*
FakeFile
)
Size
()
int64
{
return
int64
(
0
)
}
func
(
f
*
FakeFile
)
Mode
()
os
.
FileMode
{
ret
:=
os
.
FileMode
(
0644
)
if
f
.
symlink
!=
""
{
ret
=
os
.
FileMode
(
0777
)
|
os
.
ModeSymlink
}
return
ret
}
func
(
f
*
FakeFile
)
ModTime
()
time
.
Time
{
return
f
.
modtime
}
func
(
f
*
FakeFile
)
IsDir
()
bool
{
return
false
}
func
(
f
*
FakeFile
)
Sys
()
interface
{}
{
fakeInfo
,
_
:=
os
.
Stat
(
"."
)
return
fakeInfo
.
Sys
()
}
type
wrapperFileInfo
struct
{
f
os
.
FileInfo
}
func
(
w
*
wrapperFileInfo
)
Name
()
string
{
return
w
.
f
.
Name
()
}
func
(
w
*
wrapperFileInfo
)
Size
()
int64
{
return
w
.
f
.
Size
()
}
func
(
w
*
wrapperFileInfo
)
Mode
()
os
.
FileMode
{
return
w
.
f
.
Mode
()
}
func
(
w
*
wrapperFileInfo
)
ModTime
()
time
.
Time
{
return
w
.
f
.
ModTime
()
}
func
(
w
*
wrapperFileInfo
)
IsDir
()
bool
{
return
w
.
f
.
IsDir
()
}
func
(
w
*
wrapperFileInfo
)
Sys
()
interface
{}
{
if
statInfo
,
ok
:=
w
.
f
.
Sys
()
.
(
*
sftp
.
FileStat
);
ok
{
return
&
syscall
.
Stat_t
{
Uid
:
statInfo
.
UID
,
Gid
:
statInfo
.
GID
}
}
else
{
fakeInfo
,
_
:=
os
.
Stat
(
"."
)
return
fakeInfo
.
Sys
()
}
}
}
type
listerat
[]
os
.
FileInfo
type
listerat
[]
os
.
FileInfo
...
@@ -553,7 +145,6 @@ func (c *clientReadWritAt) WriteAt(p []byte, off int64) (n int, err error) {
...
@@ -553,7 +145,6 @@ func (c *clientReadWritAt) WriteAt(p []byte, off int64) (n int, err error) {
c
.
mu
.
Lock
()
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
defer
c
.
mu
.
Unlock
()
if
c
.
closed
{
if
c
.
closed
{
logger
.
Debug
(
"WriteAt: "
,
off
)
return
0
,
c
.
firstErr
return
0
,
c
.
firstErr
}
}
if
_
,
err
=
c
.
f
.
Seek
(
off
,
0
);
err
!=
nil
{
if
_
,
err
=
c
.
f
.
Seek
(
off
,
0
);
err
!=
nil
{
...
@@ -575,7 +166,6 @@ func (c *clientReadWritAt) ReadAt(p []byte, off int64) (n int, err error) {
...
@@ -575,7 +166,6 @@ func (c *clientReadWritAt) ReadAt(p []byte, off int64) (n int, err error) {
c
.
mu
.
Lock
()
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
defer
c
.
mu
.
Unlock
()
if
c
.
closed
{
if
c
.
closed
{
logger
.
Debug
(
"ReadAt: "
,
off
)
return
0
,
c
.
firstErr
return
0
,
c
.
firstErr
}
}
if
_
,
err
=
c
.
f
.
Seek
(
off
,
0
);
err
!=
nil
{
if
_
,
err
=
c
.
f
.
Seek
(
off
,
0
);
err
!=
nil
{
...
@@ -590,6 +180,28 @@ func (c *clientReadWritAt) ReadAt(p []byte, off int64) (n int, err error) {
...
@@ -590,6 +180,28 @@ func (c *clientReadWritAt) ReadAt(p []byte, off int64) (n int, err error) {
c
.
closed
=
true
c
.
closed
=
true
_
=
c
.
f
.
Close
()
_
=
c
.
f
.
Close
()
}
}
return
nr
,
err
return
nr
,
err
}
}
type
wrapperSFTPFileInfo
struct
{
f
os
.
FileInfo
}
func
(
w
*
wrapperSFTPFileInfo
)
Name
()
string
{
return
w
.
f
.
Name
()
}
func
(
w
*
wrapperSFTPFileInfo
)
Size
()
int64
{
return
w
.
f
.
Size
()
}
func
(
w
*
wrapperSFTPFileInfo
)
Mode
()
os
.
FileMode
{
return
w
.
f
.
Mode
()
}
func
(
w
*
wrapperSFTPFileInfo
)
ModTime
()
time
.
Time
{
return
w
.
f
.
ModTime
()
}
func
(
w
*
wrapperSFTPFileInfo
)
IsDir
()
bool
{
return
w
.
f
.
IsDir
()
}
func
(
w
*
wrapperSFTPFileInfo
)
Sys
()
interface
{}
{
if
statInfo
,
ok
:=
w
.
f
.
Sys
()
.
(
*
sftp
.
FileStat
);
ok
{
return
&
syscall
.
Stat_t
{
Uid
:
statInfo
.
UID
,
Gid
:
statInfo
.
GID
}
}
if
statInfo
,
ok
:=
w
.
f
.
Sys
()
.
(
*
syscall
.
Stat_t
);
ok
{
return
&
syscall
.
Stat_t
{
Uid
:
statInfo
.
Uid
,
Gid
:
statInfo
.
Gid
}
}
return
&
syscall
.
Stat_t
{
Uid
:
0
,
Gid
:
0
}
}
pkg/httpd/elfhandler.go
View file @
d80a7d05
...
@@ -74,6 +74,8 @@ func sftpFinder(wr http.ResponseWriter, req *http.Request) {
...
@@ -74,6 +74,8 @@ func sftpFinder(wr http.ResponseWriter, req *http.Request) {
}
}
func
sftpHostConnectorView
(
wr
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
sftpHostConnectorView
(
wr
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
vars
:=
mux
.
Vars
(
req
)
hostID
:=
vars
[
"host"
]
user
:=
req
.
Context
()
.
Value
(
cctx
.
ContextKeyUser
)
.
(
*
model
.
User
)
user
:=
req
.
Context
()
.
Value
(
cctx
.
ContextKeyUser
)
.
(
*
model
.
User
)
remoteIP
:=
req
.
Context
()
.
Value
(
cctx
.
ContextKeyRemoteAddr
)
.
(
string
)
remoteIP
:=
req
.
Context
()
.
Value
(
cctx
.
ContextKeyRemoteAddr
)
.
(
string
)
switch
req
.
Method
{
switch
req
.
Method
{
...
@@ -92,7 +94,12 @@ func sftpHostConnectorView(wr http.ResponseWriter, req *http.Request) {
...
@@ -92,7 +94,12 @@ func sftpHostConnectorView(wr http.ResponseWriter, req *http.Request) {
sid
:=
req
.
Form
.
Get
(
"sid"
)
sid
:=
req
.
Form
.
Get
(
"sid"
)
userV
,
ok
:=
GetUserVolume
(
sid
)
userV
,
ok
:=
GetUserVolume
(
sid
)
if
!
ok
{
if
!
ok
{
userV
=
NewUserVolume
(
user
,
remoteIP
)
switch
strings
.
TrimSpace
(
hostID
)
{
case
"_"
:
userV
=
NewUserVolume
(
user
,
remoteIP
,
""
)
default
:
userV
=
NewUserVolume
(
user
,
remoteIP
,
hostID
)
}
addUserVolume
(
sid
,
userV
)
addUserVolume
(
sid
,
userV
)
}
}
logger
.
Debugf
(
"sid: %s"
,
sid
)
logger
.
Debugf
(
"sid: %s"
,
sid
)
...
...
pkg/httpd/sftpvolume.go
View file @
d80a7d05
...
@@ -5,11 +5,8 @@ import (
...
@@ -5,11 +5,8 @@ import (
"io"
"io"
"os"
"os"
"path/filepath"
"path/filepath"
"strings"
"time"
"github.com/LeeEirc/elfinder"
"github.com/LeeEirc/elfinder"
"github.com/pkg/sftp"
"github.com/jumpserver/koko/pkg/common"
"github.com/jumpserver/koko/pkg/common"
"github.com/jumpserver/koko/pkg/config"
"github.com/jumpserver/koko/pkg/config"
...
@@ -19,383 +16,138 @@ import (
...
@@ -19,383 +16,138 @@ import (
"github.com/jumpserver/koko/pkg/srvconn"
"github.com/jumpserver/koko/pkg/srvconn"
)
)
var
(
func
NewUserVolume
(
user
*
model
.
User
,
addr
,
hostId
string
)
*
UserVolume
{
defaultHomeName
=
"Home"
var
assets
[]
model
.
Asset
)
var
homename
string
switch
hostId
{
func
NewUserVolume
(
user
*
model
.
User
,
addr
string
)
*
UserVolume
{
case
""
:
rawID
:=
fmt
.
Sprintf
(
"'%s@%s"
,
user
.
Username
,
addr
)
assets
=
service
.
GetUserAssets
(
user
.
ID
,
"1"
,
""
)
homename
=
"Home"
default
:
assets
=
service
.
GetUserAssets
(
user
.
ID
,
"1"
,
hostId
)
if
len
(
assets
)
==
1
{
homename
=
assets
[
0
]
.
Hostname
if
assets
[
0
]
.
OrgID
!=
""
{
homename
=
fmt
.
Sprintf
(
"%s.%s"
,
assets
[
0
]
.
Hostname
,
assets
[
0
]
.
OrgName
)
}
}
}
conf
:=
config
.
GetConf
()
rawID
:=
fmt
.
Sprintf
(
"%s@%s"
,
user
.
Username
,
addr
)
uVolume
:=
&
UserVolume
{
uVolume
:=
&
UserVolume
{
Uuid
:
elfinder
.
GenerateID
(
rawID
),
Uuid
:
elfinder
.
GenerateID
(
rawID
),
Addr
:
addr
,
UserSftp
:
srvconn
.
NewUserSFTP
(
user
,
addr
,
assets
...
)
,
user
:
user
,
Homename
:
homename
,
Name
:
defaultHomeName
,
basePath
:
filepath
.
Join
(
"/"
,
homename
)
,
basePath
:
fmt
.
Sprintf
(
"/%s"
,
defaultHomeName
),
localTmpPath
:
filepath
.
Join
(
conf
.
RootPath
,
"data"
,
"tmp"
),
}
}
uVolume
.
initial
()
return
uVolume
return
uVolume
}
}
type
UserVolume
struct
{
type
UserVolume
struct
{
Uuid
string
Uuid
string
Addr
string
*
srvconn
.
UserSftp
Name
string
basePath
string
user
*
model
.
User
assets
model
.
AssetList
rootPath
string
// tmp || home || ~
hosts
map
[
string
]
*
hostnameVolume
localTmpPath
string
localTmpPath
string
Homename
string
permCache
map
[
string
]
bool
basePath
string
}
func
(
u
*
UserVolume
)
initial
()
{
conf
:=
config
.
GetConf
()
u
.
loadAssets
()
u
.
rootPath
=
conf
.
SftpRoot
u
.
localTmpPath
=
filepath
.
Join
(
conf
.
RootPath
,
"data"
,
"tmp"
)
u
.
permCache
=
make
(
map
[
string
]
bool
)
_
=
common
.
EnsureDirExist
(
u
.
localTmpPath
)
u
.
hosts
=
make
(
map
[
string
]
*
hostnameVolume
)
for
i
,
item
:=
range
u
.
assets
{
tmpDir
:=
&
hostnameVolume
{
VID
:
u
.
ID
(),
homePath
:
u
.
basePath
,
hostPath
:
filepath
.
Join
(
u
.
basePath
,
item
.
Hostname
),
asset
:
&
u
.
assets
[
i
],
time
:
time
.
Now
()
.
UTC
(),
}
u
.
hosts
[
item
.
Hostname
]
=
tmpDir
}
}
func
(
u
*
UserVolume
)
loadAssets
()
{
u
.
assets
=
service
.
GetUserAssets
(
u
.
user
.
ID
,
"1"
)
}
}
func
(
u
*
UserVolume
)
ID
()
string
{
func
(
u
*
UserVolume
)
ID
()
string
{
return
u
.
Uuid
return
u
.
Uuid
}
}
func
(
u
*
UserVolume
)
Info
(
path
string
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
Info
(
path
string
)
(
elfinder
.
FileDir
,
error
)
{
var
rest
elfinder
.
FileDir
logger
.
Debug
(
"volume Info: "
,
path
)
if
path
==
""
||
path
==
"/"
{
path
=
u
.
basePath
}
if
path
==
u
.
basePath
{
return
u
.
RootFileDir
(),
nil
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
hostPath
==
path
{
return
hostVol
.
info
(),
nil
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
path
==
sysUserVol
.
suPath
{
return
sysUserVol
.
info
(),
nil
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
rest
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
if
path
==
"/"
{
return
u
.
RootFileDir
(),
nil
}
}
realPath
:=
sysUserVol
.
ParsePath
(
path
)
var
rest
elfinder
.
FileDir
dirname
:=
filepath
.
Dir
(
path
)
originFileInfo
,
err
:=
u
.
Stat
(
path
)
fileInfos
,
err
:=
sysUserVol
.
client
.
Stat
(
realPath
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
rest
.
Name
=
fileInfos
.
Name
()
dirPath
:=
filepath
.
Dir
(
path
)
rest
.
Hash
=
hashPath
(
u
.
ID
(),
path
)
filename
:=
filepath
.
Base
(
path
)
rest
.
Phash
=
hashPath
(
u
.
ID
(),
dirname
)
rest
.
Read
,
rest
.
Write
=
elfinder
.
ReadWritePem
(
originFileInfo
.
Mode
())
rest
.
Size
=
fileInfos
.
Size
()
if
filename
!=
originFileInfo
.
Name
()
{
rest
.
Volumeid
=
u
.
ID
()
rest
.
Read
,
rest
.
Write
=
1
,
1
if
fileInfos
.
IsDir
()
{
}
if
filename
==
"."
{
filename
=
originFileInfo
.
Name
()
fmt
.
Println
(
"askldkasdlala"
)
}
rest
.
Name
=
filename
rest
.
Hash
=
hashPath
(
u
.
Uuid
,
filepath
.
Join
(
dirPath
,
filename
))
rest
.
Phash
=
hashPath
(
u
.
Uuid
,
dirPath
)
if
rest
.
Hash
==
rest
.
Phash
{
rest
.
Phash
=
""
}
rest
.
Size
=
originFileInfo
.
Size
()
rest
.
Volumeid
=
u
.
Uuid
if
originFileInfo
.
IsDir
()
{
rest
.
Mime
=
"directory"
rest
.
Mime
=
"directory"
rest
.
Dirs
=
1
rest
.
Dirs
=
1
}
else
{
}
else
{
rest
.
Mime
=
"file"
rest
.
Mime
=
"file"
rest
.
Dirs
=
0
rest
.
Dirs
=
0
}
}
rest
.
Read
,
rest
.
Write
=
elfinder
.
ReadWritePem
(
fileInfos
.
Mode
())
return
rest
,
err
return
rest
,
nil
}
}
func
(
u
*
UserVolume
)
List
(
path
string
)
[]
elfinder
.
FileDir
{
func
(
u
*
UserVolume
)
List
(
path
string
)
[]
elfinder
.
FileDir
{
var
dirs
[]
elfinder
.
FileDir
dirs
:=
make
([]
elfinder
.
FileDir
,
0
)
if
path
==
""
||
path
==
"/"
{
logger
.
Debug
(
"volume List: "
,
path
)
path
=
u
.
basePath
dirInfo
,
err
:=
u
.
Info
(
path
)
}
if
err
!=
nil
{
if
path
==
u
.
basePath
{
dirs
=
make
([]
elfinder
.
FileDir
,
0
,
len
(
u
.
hosts
))
for
_
,
item
:=
range
u
.
hosts
{
dirs
=
append
(
dirs
,
item
.
info
())
}
return
dirs
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
dirs
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
if
hostVol
.
hostPath
==
path
{
dirs
=
make
([]
elfinder
.
FileDir
,
0
,
len
(
hostVol
.
suMaps
))
for
_
,
item
:=
range
hostVol
.
suMaps
{
dirs
=
append
(
dirs
,
item
.
info
())
}
return
dirs
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
dirs
return
dirs
}
}
dirs
=
append
(
dirs
,
dirInfo
)
if
sysUserVol
.
client
==
nil
{
originFileInfolist
,
err
:=
u
.
UserSftp
.
ReadDir
(
path
)
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
dirs
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
dirs
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
path
)
subFiles
,
err
:=
sysUserVol
.
client
.
ReadDir
(
realPath
)
if
err
!=
nil
{
if
err
!=
nil
{
return
dirs
return
dirs
}
}
dirs
=
make
([]
elfinder
.
FileDir
,
0
,
len
(
subFiles
))
for
i
:=
0
;
i
<
len
(
originFileInfolist
);
i
++
{
for
_
,
fInfo
:=
range
subFiles
{
dirs
=
append
(
dirs
,
NewElfinderFileInfo
(
u
.
Uuid
,
path
,
originFileInfolist
[
i
]))
fileDir
,
err
:=
u
.
Info
(
filepath
.
Join
(
path
,
fInfo
.
Name
()))
if
err
!=
nil
{
continue
}
dirs
=
append
(
dirs
,
fileDir
)
}
}
return
dirs
return
dirs
}
}
func
(
u
*
UserVolume
)
Parents
(
path
string
,
dep
int
)
[]
elfinder
.
FileDir
{
func
(
u
*
UserVolume
)
Parents
(
path
string
,
dep
int
)
[]
elfinder
.
FileDir
{
relativepath
:=
strings
.
TrimPrefix
(
strings
.
TrimPrefix
(
path
,
u
.
basePath
),
"/"
)
logger
.
Debug
(
"volume Parents: "
,
path
)
relativePaths
:=
strings
.
Split
(
relativepath
,
"/"
)
dirs
:=
make
([]
elfinder
.
FileDir
,
0
)
dirs
:=
make
([]
elfinder
.
FileDir
,
0
,
len
(
relativePaths
))
dirPath
:=
path
for
{
for
i
:=
range
relativePaths
{
tmps
:=
u
.
List
(
dirPath
)
realDirPath
:=
filepath
.
Join
(
u
.
basePath
,
filepath
.
Join
(
relativePaths
[
:
i
]
...
))
dirs
=
append
(
dirs
,
tmps
...
)
result
,
err
:=
u
.
Info
(
realDirPath
)
if
dirPath
==
"/"
{
if
err
!=
nil
{
break
continue
}
dirs
=
append
(
dirs
,
result
)
tmpDir
:=
u
.
List
(
realDirPath
)
for
j
,
item
:=
range
tmpDir
{
if
item
.
Dirs
==
1
{
dirs
=
append
(
dirs
,
tmpDir
[
j
])
}
}
}
dirPath
=
filepath
.
Dir
(
dirPath
)
}
}
return
dirs
return
dirs
}
}
func
(
u
*
UserVolume
)
GetFile
(
path
string
)
(
reader
io
.
ReadCloser
,
err
error
)
{
func
(
u
*
UserVolume
)
GetFile
(
path
string
)
(
reader
io
.
ReadCloser
,
err
error
)
{
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
,
"/"
),
"/"
)
return
u
.
UserSftp
.
Open
(
path
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
nil
,
os
.
ErrNotExist
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
nil
,
os
.
ErrNotExist
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
DownloadAction
)
{
return
nil
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
nil
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
nil
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
path
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Download"
,
Path
:
realPath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
reader
,
err
=
sysUserVol
.
client
.
Open
(
realPath
)
if
err
!=
nil
{
return
}
logData
.
IsSuccess
=
true
return
}
}
func
(
u
*
UserVolume
)
UploadFile
(
dir
,
filename
string
,
reader
io
.
Reader
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
UploadFile
(
dir
,
filename
string
,
reader
io
.
Reader
)
(
elfinder
.
FileDir
,
error
)
{
path
:=
filepath
.
Join
(
dir
,
filename
)
logger
.
Debug
(
"Volume upload file path: "
,
path
)
var
rest
elfinder
.
FileDir
var
rest
elfinder
.
FileDir
var
err
error
fd
,
err
:=
u
.
UserSftp
.
Create
(
path
)
if
dir
==
""
||
dir
==
"/"
{
dir
=
u
.
basePath
}
if
dir
==
u
.
basePath
{
return
rest
,
os
.
ErrPermission
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
dir
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
hostPath
==
dir
{
return
rest
,
os
.
ErrPermission
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
dir
)
realFilenamePath
:=
filepath
.
Join
(
realPath
,
filename
)
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
UploadAction
)
{
return
rest
,
os
.
ErrPermission
}
fd
,
err
:=
sysUserVol
.
client
.
Create
(
realFilenamePath
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
defer
fd
.
Close
()
defer
fd
.
Close
()
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Upload"
,
Path
:
realFilenamePath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
_
,
err
=
io
.
Copy
(
fd
,
reader
)
_
,
err
=
io
.
Copy
(
fd
,
reader
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
logData
.
IsSuccess
=
true
return
u
.
Info
(
path
)
return
u
.
Info
(
filepath
.
Join
(
dir
,
filename
))
}
}
func
(
u
*
UserVolume
)
UploadChunk
(
cid
int
,
dirPath
,
chunkName
string
,
reader
io
.
Reader
)
error
{
func
(
u
*
UserVolume
)
UploadChunk
(
cid
int
,
dirPath
,
chunkName
string
,
reader
io
.
Reader
)
error
{
...
@@ -419,76 +171,16 @@ func (u *UserVolume) UploadChunk(cid int, dirPath, chunkName string, reader io.R
...
@@ -419,76 +171,16 @@ func (u *UserVolume) UploadChunk(cid int, dirPath, chunkName string, reader io.R
}
}
func
(
u
*
UserVolume
)
MergeChunk
(
cid
,
total
int
,
dirPath
,
filename
string
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
MergeChunk
(
cid
,
total
int
,
dirPath
,
filename
string
)
(
elfinder
.
FileDir
,
error
)
{
path
:=
filepath
.
Join
(
dirPath
,
filename
)
logger
.
Debug
(
"merge chunk path: "
,
path
)
var
rest
elfinder
.
FileDir
var
rest
elfinder
.
FileDir
if
u
.
basePath
==
dirPath
{
fd
,
err
:=
u
.
UserSftp
.
Create
(
path
)
return
rest
,
os
.
ErrPermission
if
err
!=
nil
{
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
dirPath
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
hostPath
==
dirPath
{
return
rest
,
os
.
ErrPermission
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
UploadAction
)
{
for
i
:=
0
;
i
<=
total
;
i
++
{
for
i
:=
0
;
i
<=
total
;
i
++
{
partPath
:=
fmt
.
Sprintf
(
"%s.%d_%d.part_%d"
,
partPath
:=
fmt
.
Sprintf
(
"%s.%d_%d.part_%d"
,
filepath
.
Join
(
u
.
localTmpPath
,
dirPath
,
filename
),
i
,
total
,
cid
)
filepath
.
Join
(
u
.
localTmpPath
,
dirPath
,
filename
),
i
,
total
,
cid
)
_
=
os
.
Remove
(
partPath
)
_
=
os
.
Remove
(
partPath
)
}
}
return
rest
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realDirPath
:=
sysUserVol
.
ParsePath
(
dirPath
)
filenamePath
:=
filepath
.
Join
(
realDirPath
,
filename
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Upload"
,
Path
:
filenamePath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
fd
,
err
:=
sysUserVol
.
client
.
OpenFile
(
filenamePath
,
os
.
O_WRONLY
|
os
.
O_APPEND
|
os
.
O_CREATE
|
os
.
O_TRUNC
)
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
defer
fd
.
Close
()
defer
fd
.
Close
()
...
@@ -510,8 +202,7 @@ func (u *UserVolume) MergeChunk(cid, total int, dirPath, filename string) (elfin
...
@@ -510,8 +202,7 @@ func (u *UserVolume) MergeChunk(cid, total int, dirPath, filename string) (elfin
_
=
partFD
.
Close
()
_
=
partFD
.
Close
()
_
=
os
.
Remove
(
partPath
)
_
=
os
.
Remove
(
partPath
)
}
}
logData
.
IsSuccess
=
true
return
u
.
Info
(
path
)
return
u
.
Info
(
filepath
.
Join
(
dirPath
,
filename
))
}
}
func
(
u
*
UserVolume
)
CompleteChunk
(
cid
,
total
int
,
dirPath
,
filename
string
)
bool
{
func
(
u
*
UserVolume
)
CompleteChunk
(
cid
,
total
int
,
dirPath
,
filename
string
)
bool
{
...
@@ -527,362 +218,48 @@ func (u *UserVolume) CompleteChunk(cid, total int, dirPath, filename string) boo
...
@@ -527,362 +218,48 @@ func (u *UserVolume) CompleteChunk(cid, total int, dirPath, filename string) boo
}
}
func
(
u
*
UserVolume
)
MakeDir
(
dir
,
newDirname
string
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
MakeDir
(
dir
,
newDirname
string
)
(
elfinder
.
FileDir
,
error
)
{
path
:=
filepath
.
Join
(
dir
,
newDirname
)
var
rest
elfinder
.
FileDir
var
rest
elfinder
.
FileDir
if
dir
==
""
||
dir
==
"/"
{
err
:=
u
.
UserSftp
.
MkdirAll
(
path
)
dir
=
u
.
basePath
}
if
dir
==
u
.
basePath
{
return
rest
,
os
.
ErrPermission
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
dir
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
hostPath
==
dir
{
return
rest
,
os
.
ErrPermission
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
rest
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
dir
)
realDirPath
:=
filepath
.
Join
(
realPath
,
newDirname
)
err
:=
sysUserVol
.
client
.
MkdirAll
(
realDirPath
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Mkdir"
,
Path
:
realDirPath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
logData
.
IsSuccess
=
true
return
u
.
Info
(
path
)
return
u
.
Info
(
filepath
.
Join
(
dir
,
newDirname
))
}
}
func
(
u
*
UserVolume
)
MakeFile
(
dir
,
newFilename
string
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
MakeFile
(
dir
,
newFilename
string
)
(
elfinder
.
FileDir
,
error
)
{
path
:=
filepath
.
Join
(
dir
,
newFilename
)
var
rest
elfinder
.
FileDir
var
rest
elfinder
.
FileDir
if
dir
==
""
||
dir
==
"/"
{
fd
,
err
:=
u
.
UserSftp
.
Create
(
path
)
dir
=
u
.
basePath
}
if
dir
==
u
.
basePath
{
return
rest
,
os
.
ErrPermission
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
dir
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
hostPath
==
dir
{
return
rest
,
os
.
ErrPermission
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
rest
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
dir
)
realFilePath
:=
filepath
.
Join
(
realPath
,
newFilename
)
_
,
err
:=
sysUserVol
.
client
.
Create
(
realFilePath
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Append"
,
Path
:
realFilePath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
logData
.
IsSuccess
=
true
defer
fd
.
Close
()
return
u
.
Info
(
filepath
.
Join
(
dir
,
newFilename
)
)
return
u
.
Info
(
path
)
}
}
func
(
u
*
UserVolume
)
Rename
(
oldNamePath
,
newName
string
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
Rename
(
oldNamePath
,
newName
string
)
(
elfinder
.
FileDir
,
error
)
{
var
rest
elfinder
.
FileDir
var
rest
elfinder
.
FileDir
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
oldNamePath
,
"/"
),
"/"
)
newNamePath
:=
filepath
.
Join
(
filepath
.
Dir
(
oldNamePath
),
newName
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
err
:=
u
.
UserSftp
.
Rename
(
oldNamePath
,
newNamePath
)
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
sysUserVol
.
suPath
==
oldNamePath
{
return
rest
,
os
.
ErrPermission
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
rest
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
oldNamePath
)
dirpath
:=
filepath
.
Dir
(
realPath
)
newFilePath
:=
filepath
.
Join
(
dirpath
,
newName
)
err
:=
sysUserVol
.
client
.
Rename
(
oldNamePath
,
newFilePath
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Rename"
,
Path
:
fmt
.
Sprintf
(
"%s=>%s"
,
oldNamePath
,
newFilePath
),
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
logData
.
IsSuccess
=
true
return
u
.
Info
(
newNamePath
)
return
u
.
Info
(
newFilePath
)
}
}
func
(
u
*
UserVolume
)
Remove
(
path
string
)
error
{
func
(
u
*
UserVolume
)
Remove
(
path
string
)
error
{
if
path
==
""
||
path
==
"/"
{
return
u
.
UserSftp
.
Remove
(
path
)
path
=
u
.
basePath
}
if
path
==
u
.
basePath
{
return
os
.
ErrPermission
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
os
.
ErrNotExist
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
os
.
ErrNotExist
}
if
sysUserVol
.
suPath
==
path
{
return
os
.
ErrPermission
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
ConnectAction
)
{
return
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
path
)
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Delete"
,
Path
:
realPath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
defer
u
.
CreateFTPLog
(
logData
)
err
:=
sysUserVol
.
client
.
Remove
(
realPath
)
if
err
==
nil
{
logData
.
IsSuccess
=
true
}
return
err
}
}
func
(
u
*
UserVolume
)
Paste
(
dir
,
filename
,
suffix
string
,
reader
io
.
ReadCloser
)
(
elfinder
.
FileDir
,
error
)
{
func
(
u
*
UserVolume
)
Paste
(
dir
,
filename
,
suffix
string
,
reader
io
.
ReadCloser
)
(
elfinder
.
FileDir
,
error
)
{
var
rest
elfinder
.
FileDir
var
rest
elfinder
.
FileDir
if
dir
==
""
||
dir
==
"/"
{
path
:=
filepath
.
Join
(
dir
,
filename
)
dir
=
u
.
basePath
rest
,
err
:=
u
.
Info
(
path
)
}
if
dir
==
u
.
basePath
{
return
rest
,
os
.
ErrPermission
}
pathNames
:=
strings
.
Split
(
strings
.
TrimPrefix
(
dir
,
"/"
),
"/"
)
hostVol
,
ok
:=
u
.
hosts
[
pathNames
[
1
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
hostVol
.
hostPath
==
dir
{
return
rest
,
os
.
ErrPermission
}
if
hostVol
.
suMaps
==
nil
{
hostVol
.
suMaps
=
make
(
map
[
string
]
*
sysUserVolume
)
systemUsers
:=
hostVol
.
asset
.
SystemUsers
for
i
,
sysUser
:=
range
systemUsers
{
hostVol
.
suMaps
[
sysUser
.
Name
]
=
&
sysUserVolume
{
VID
:
u
.
ID
(),
hostpath
:
hostVol
.
hostPath
,
suPath
:
filepath
.
Join
(
hostVol
.
hostPath
,
sysUser
.
Name
),
systemUser
:
&
systemUsers
[
i
],
rootPath
:
u
.
rootPath
,
}
}
}
sysUserVol
,
ok
:=
hostVol
.
suMaps
[
pathNames
[
2
]]
if
!
ok
{
return
rest
,
os
.
ErrNotExist
}
if
!
u
.
validatePermission
(
hostVol
.
asset
.
ID
,
sysUserVol
.
systemUser
.
ID
,
model
.
UploadAction
)
{
return
rest
,
os
.
ErrPermission
}
if
sysUserVol
.
client
==
nil
{
sftClient
,
conn
,
err
:=
u
.
GetSftpClient
(
hostVol
.
asset
,
sysUserVol
.
systemUser
)
if
err
!=
nil
{
return
rest
,
os
.
ErrPermission
}
sysUserVol
.
homeDirPath
,
err
=
sftClient
.
Getwd
()
if
err
!=
nil
{
return
rest
,
err
}
sysUserVol
.
client
=
sftClient
sysUserVol
.
conn
=
conn
}
realPath
:=
sysUserVol
.
ParsePath
(
dir
)
realFilePath
:=
filepath
.
Join
(
realPath
,
filename
)
_
,
err
:=
sysUserVol
.
client
.
Stat
(
realFilePath
)
if
err
!=
nil
{
if
err
!=
nil
{
realFilePath
+=
suffix
path
+=
suffix
}
logData
:=
&
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
user
.
Name
,
u
.
user
.
Username
),
Hostname
:
hostVol
.
asset
.
Hostname
,
OrgID
:
hostVol
.
asset
.
OrgID
,
SystemUser
:
sysUserVol
.
systemUser
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
"Append"
,
Path
:
realFilePath
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
false
,
}
}
defer
u
.
CreateFTPLog
(
logData
)
fd
,
err
:=
u
.
UserSftp
.
Create
(
path
)
fd
,
err
:=
sysUserVol
.
client
.
OpenFile
(
realPath
,
os
.
O_RDWR
|
os
.
O_CREATE
)
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
...
@@ -891,130 +268,47 @@ func (u *UserVolume) Paste(dir, filename, suffix string, reader io.ReadCloser) (
...
@@ -891,130 +268,47 @@ func (u *UserVolume) Paste(dir, filename, suffix string, reader io.ReadCloser) (
if
err
!=
nil
{
if
err
!=
nil
{
return
rest
,
err
return
rest
,
err
}
}
logData
.
IsSuccess
=
true
return
u
.
Info
(
path
)
return
u
.
Info
(
realPath
)
}
}
func
(
u
*
UserVolume
)
RootFileDir
()
elfinder
.
FileDir
{
func
(
u
*
UserVolume
)
RootFileDir
()
elfinder
.
FileDir
{
var
resFDir
=
elfinder
.
FileDir
{}
logger
.
Debug
(
"Root File Dir"
)
resFDir
.
Name
=
u
.
Name
fInfo
,
_
:=
u
.
UserSftp
.
Info
()
resFDir
.
Hash
=
hashPath
(
u
.
Uuid
,
u
.
basePath
)
var
rest
elfinder
.
FileDir
resFDir
.
Mime
=
"directory"
rest
.
Name
=
u
.
Homename
resFDir
.
Volumeid
=
u
.
Uuid
rest
.
Hash
=
hashPath
(
u
.
Uuid
,
"/"
)
resFDir
.
Dirs
=
1
rest
.
Size
=
fInfo
.
Size
()
resFDir
.
Read
,
resFDir
.
Write
=
1
,
1
rest
.
Volumeid
=
u
.
Uuid
resFDir
.
Locked
=
1
rest
.
Mime
=
"directory"
return
resFDir
rest
.
Dirs
=
1
}
rest
.
Read
,
rest
.
Write
=
1
,
1
rest
.
Locked
=
1
func
(
u
*
UserVolume
)
GetSftpClient
(
asset
*
model
.
Asset
,
sysUser
*
model
.
SystemUser
)
(
sftpClient
*
sftp
.
Client
,
sshClient
*
srvconn
.
SSHClient
,
err
error
)
{
return
rest
sshClient
,
err
=
srvconn
.
NewClient
(
u
.
user
,
asset
,
sysUser
,
config
.
GetConf
()
.
SSHTimeout
*
time
.
Second
)
if
err
!=
nil
{
return
}
sftpClient
,
err
=
sftp
.
NewClient
(
sshClient
.
Client
)
if
err
!=
nil
{
return
}
return
sftpClient
,
sshClient
,
nil
}
}
func
(
u
*
UserVolume
)
Close
()
{
func
(
u
*
UserVolume
)
Close
()
{
for
_
,
host
:=
range
u
.
hosts
{
u
.
UserSftp
.
Close
()
if
host
.
suMaps
==
nil
{
continue
}
for
_
,
su
:=
range
host
.
suMaps
{
su
.
Close
()
}
}
}
func
(
u
*
UserVolume
)
CreateFTPLog
(
data
*
model
.
FTPLog
)
{
for
i
:=
0
;
i
<
4
;
i
++
{
err
:=
service
.
PushFTPLog
(
data
)
if
err
==
nil
{
break
}
logger
.
Debugf
(
"create FTP log err: %s"
,
err
.
Error
())
}
}
func
(
u
*
UserVolume
)
validatePermission
(
aid
,
suid
,
operate
string
)
bool
{
permKey
:=
fmt
.
Sprintf
(
"%s_%s_%s"
,
aid
,
suid
,
operate
)
permission
,
ok
:=
u
.
permCache
[
permKey
]
if
ok
{
return
permission
}
permission
=
service
.
ValidateUserAssetPermission
(
u
.
user
.
ID
,
aid
,
suid
,
operate
,
)
u
.
permCache
[
permKey
]
=
permission
return
permission
}
type
hostnameVolume
struct
{
VID
string
homePath
string
hostPath
string
// /home/hostname/
time
time
.
Time
asset
*
model
.
Asset
suMaps
map
[
string
]
*
sysUserVolume
}
func
(
h
*
hostnameVolume
)
info
()
elfinder
.
FileDir
{
var
resFDir
=
elfinder
.
FileDir
{}
resFDir
.
Name
=
h
.
asset
.
Hostname
resFDir
.
Hash
=
hashPath
(
h
.
VID
,
h
.
hostPath
)
resFDir
.
Phash
=
hashPath
(
h
.
VID
,
h
.
homePath
)
resFDir
.
Mime
=
"directory"
resFDir
.
Volumeid
=
h
.
VID
resFDir
.
Dirs
=
1
resFDir
.
Read
,
resFDir
.
Write
=
1
,
1
return
resFDir
}
type
sysUserVolume
struct
{
VID
string
hostpath
string
suPath
string
rootPath
string
systemUser
*
model
.
SystemUser
homeDirPath
string
client
*
sftp
.
Client
conn
*
srvconn
.
SSHClient
}
func
(
su
*
sysUserVolume
)
info
()
elfinder
.
FileDir
{
var
resFDir
=
elfinder
.
FileDir
{}
resFDir
.
Name
=
su
.
systemUser
.
Name
resFDir
.
Hash
=
hashPath
(
su
.
VID
,
su
.
suPath
)
resFDir
.
Phash
=
hashPath
(
su
.
VID
,
su
.
hostpath
)
resFDir
.
Mime
=
"directory"
resFDir
.
Volumeid
=
su
.
VID
resFDir
.
Dirs
=
1
resFDir
.
Read
,
resFDir
.
Write
=
1
,
1
return
resFDir
}
func
(
su
*
sysUserVolume
)
ParsePath
(
path
string
)
string
{
var
realPath
string
switch
strings
.
ToLower
(
su
.
rootPath
)
{
case
"home"
,
"~"
,
""
:
realPath
=
strings
.
ReplaceAll
(
path
,
su
.
suPath
,
su
.
homeDirPath
)
default
:
realPath
=
strings
.
ReplaceAll
(
path
,
su
.
suPath
,
su
.
rootPath
)
}
logger
.
Debug
(
"real path: "
,
realPath
)
return
realPath
}
}
func
(
su
*
sysUserVolume
)
Close
()
{
func
NewElfinderFileInfo
(
id
,
dirPath
string
,
originFileInfo
os
.
FileInfo
)
elfinder
.
FileDir
{
if
su
.
client
!=
nil
{
var
rest
elfinder
.
FileDir
_
=
su
.
client
.
Close
()
rest
.
Name
=
originFileInfo
.
Name
()
rest
.
Hash
=
hashPath
(
id
,
filepath
.
Join
(
dirPath
,
originFileInfo
.
Name
()))
rest
.
Phash
=
hashPath
(
id
,
dirPath
)
if
rest
.
Hash
==
rest
.
Phash
{
rest
.
Phash
=
""
}
rest
.
Size
=
originFileInfo
.
Size
()
rest
.
Volumeid
=
id
if
originFileInfo
.
IsDir
()
{
rest
.
Mime
=
"directory"
rest
.
Dirs
=
1
}
else
{
rest
.
Mime
=
"file"
rest
.
Dirs
=
0
}
}
srvconn
.
RecycleClient
(
su
.
conn
)
rest
.
Read
,
rest
.
Write
=
elfinder
.
ReadWritePem
(
originFileInfo
.
Mode
())
return
rest
}
}
func
hashPath
(
id
,
path
string
)
string
{
func
hashPath
(
id
,
path
string
)
string
{
...
...
pkg/httpd/volumemanager.go
View file @
d80a7d05
...
@@ -2,12 +2,19 @@ package httpd
...
@@ -2,12 +2,19 @@ package httpd
import
(
import
(
"sync"
"sync"
"github.com/LeeEirc/elfinder"
)
)
var
userVolumes
=
make
(
map
[
string
]
*
UserVolume
)
type
VolumeCloser
interface
{
elfinder
.
Volume
Close
()
}
var
userVolumes
=
make
(
map
[
string
]
VolumeCloser
)
var
volumeLock
=
new
(
sync
.
RWMutex
)
var
volumeLock
=
new
(
sync
.
RWMutex
)
func
addUserVolume
(
sid
string
,
v
*
UserVolume
)
{
func
addUserVolume
(
sid
string
,
v
VolumeCloser
)
{
volumeLock
.
Lock
()
volumeLock
.
Lock
()
defer
volumeLock
.
Unlock
()
defer
volumeLock
.
Unlock
()
userVolumes
[
sid
]
=
v
userVolumes
[
sid
]
=
v
...
@@ -27,7 +34,7 @@ func removeUserVolume(sid string) {
...
@@ -27,7 +34,7 @@ func removeUserVolume(sid string) {
}
}
func
GetUserVolume
(
sid
string
)
(
*
UserVolume
,
bool
)
{
func
GetUserVolume
(
sid
string
)
(
VolumeCloser
,
bool
)
{
volumeLock
.
RLock
()
volumeLock
.
RLock
()
defer
volumeLock
.
RUnlock
()
defer
volumeLock
.
RUnlock
()
v
,
ok
:=
userVolumes
[
sid
]
v
,
ok
:=
userVolumes
[
sid
]
...
...
pkg/koko/task.go
View file @
d80a7d05
...
@@ -70,7 +70,7 @@ func uploadRemainReplay(rootPath string) {
...
@@ -70,7 +70,7 @@ func uploadRemainReplay(rootPath string) {
}
}
_
=
os
.
Remove
(
path
)
_
=
os
.
Remove
(
path
)
}
}
relayRecord
:=
&
proxy
.
ReplyRecorder
{}
relayRecord
:=
&
proxy
.
ReplyRecorder
{
SessionID
:
sid
}
relayRecord
.
AbsGzFilePath
=
absGzPath
relayRecord
.
AbsGzFilePath
=
absGzPath
relayRecord
.
Target
,
_
=
filepath
.
Rel
(
path
,
rootPath
)
relayRecord
.
Target
,
_
=
filepath
.
Rel
(
path
,
rootPath
)
relayRecord
.
UploadGzipFile
(
3
)
relayRecord
.
UploadGzipFile
(
3
)
...
...
pkg/model/assets.go
View file @
d80a7d05
...
@@ -220,6 +220,7 @@ func SortAssetNodesByKey(assetNodes []Node) {
...
@@ -220,6 +220,7 @@ func SortAssetNodesByKey(assetNodes []Node) {
const
LoginModeManual
=
"manual"
const
LoginModeManual
=
"manual"
const
(
const
(
AllAction
=
"all"
ConnectAction
=
"connect"
ConnectAction
=
"connect"
UploadAction
=
"upload_file"
UploadAction
=
"upload_file"
DownloadAction
=
"download_file"
DownloadAction
=
"download_file"
...
...
pkg/model/connection.go
View file @
d80a7d05
package
model
package
model
const
(
OperateRemoveDir
=
"Rmdir"
OperateDownaload
=
"Download"
OperateUpload
=
"Upload"
OperateRename
=
"Rename"
OperateMkdir
=
"Mkdir"
OperateDelete
=
"Delete"
OperateSymlink
=
"Symlink"
)
pkg/proxy/recorder.go
View file @
d80a7d05
...
@@ -22,7 +22,7 @@ func NewCommandRecorder(sid string) (recorder *CommandRecorder) {
...
@@ -22,7 +22,7 @@ func NewCommandRecorder(sid string) (recorder *CommandRecorder) {
}
}
func
NewReplyRecord
(
sid
string
)
(
recorder
*
ReplyRecorder
)
{
func
NewReplyRecord
(
sid
string
)
(
recorder
*
ReplyRecorder
)
{
recorder
=
&
ReplyRecorder
{
s
essionID
:
sid
}
recorder
=
&
ReplyRecorder
{
S
essionID
:
sid
}
recorder
.
initial
()
recorder
.
initial
()
return
recorder
return
recorder
}
}
...
@@ -93,7 +93,7 @@ func (c *CommandRecorder) record() {
...
@@ -93,7 +93,7 @@ func (c *CommandRecorder) record() {
}
}
type
ReplyRecorder
struct
{
type
ReplyRecorder
struct
{
s
essionID
string
S
essionID
string
absFilePath
string
absFilePath
string
AbsGzFilePath
string
AbsGzFilePath
string
...
@@ -119,7 +119,7 @@ func (r *ReplyRecorder) Record(b []byte) {
...
@@ -119,7 +119,7 @@ func (r *ReplyRecorder) Record(b []byte) {
}
}
func
(
r
*
ReplyRecorder
)
prepare
()
{
func
(
r
*
ReplyRecorder
)
prepare
()
{
sessionID
:=
r
.
s
essionID
sessionID
:=
r
.
S
essionID
rootPath
:=
config
.
GetConf
()
.
RootPath
rootPath
:=
config
.
GetConf
()
.
RootPath
today
:=
time
.
Now
()
.
UTC
()
.
Format
(
"2006-01-02"
)
today
:=
time
.
Now
()
.
UTC
()
.
Format
(
"2006-01-02"
)
gzFileName
:=
sessionID
+
".replay.gz"
gzFileName
:=
sessionID
+
".replay.gz"
...
@@ -179,7 +179,7 @@ func (r *ReplyRecorder) UploadGzipFile(maxRetry int) {
...
@@ -179,7 +179,7 @@ func (r *ReplyRecorder) UploadGzipFile(maxRetry int) {
err
:=
r
.
storage
.
Upload
(
r
.
AbsGzFilePath
,
r
.
Target
)
err
:=
r
.
storage
.
Upload
(
r
.
AbsGzFilePath
,
r
.
Target
)
if
err
==
nil
{
if
err
==
nil
{
_
=
os
.
Remove
(
r
.
AbsGzFilePath
)
_
=
os
.
Remove
(
r
.
AbsGzFilePath
)
service
.
FinishReply
(
r
.
s
essionID
)
service
.
FinishReply
(
r
.
S
essionID
)
break
break
}
}
// 如果还是失败,使用备用storage再传一次
// 如果还是失败,使用备用storage再传一次
...
...
pkg/service/perms.go
View file @
d80a7d05
...
@@ -7,11 +7,14 @@ import (
...
@@ -7,11 +7,14 @@ import (
"github.com/jumpserver/koko/pkg/model"
"github.com/jumpserver/koko/pkg/model"
)
)
func
GetUserAssets
(
userID
,
cachePolicy
string
)
(
assets
model
.
AssetList
)
{
func
GetUserAssets
(
userID
,
cachePolicy
,
assetId
string
)
(
assets
model
.
AssetList
)
{
if
cachePolicy
==
""
{
if
cachePolicy
==
""
{
cachePolicy
=
"1"
cachePolicy
=
"1"
}
}
payload
:=
map
[
string
]
string
{
"cache_policy"
:
cachePolicy
}
payload
:=
map
[
string
]
string
{
"cache_policy"
:
cachePolicy
}
if
assetId
!=
""
{
payload
[
"id"
]
=
assetId
}
Url
:=
fmt
.
Sprintf
(
UserAssetsURL
,
userID
)
Url
:=
fmt
.
Sprintf
(
UserAssetsURL
,
userID
)
err
:=
authClient
.
Get
(
Url
,
&
assets
,
payload
)
err
:=
authClient
.
Get
(
Url
,
&
assets
,
payload
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
pkg/srvconn/sftpconn.go
0 → 100644
View file @
d80a7d05
package
srvconn
import
(
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"syscall"
"time"
"github.com/pkg/sftp"
"github.com/jumpserver/koko/pkg/common"
"github.com/jumpserver/koko/pkg/config"
"github.com/jumpserver/koko/pkg/logger"
"github.com/jumpserver/koko/pkg/model"
"github.com/jumpserver/koko/pkg/service"
)
func
NewUserSFTP
(
user
*
model
.
User
,
addr
string
,
assets
...
model
.
Asset
)
*
UserSftp
{
u
:=
UserSftp
{
User
:
user
,
Addr
:
addr
,
}
u
.
initial
(
assets
)
return
&
u
}
type
UserSftp
struct
{
User
*
model
.
User
Addr
string
RootPath
string
hosts
map
[
string
]
*
HostnameDir
// key hostname or hostname.orgName
sftpClients
map
[
string
]
*
SftpConn
// key %s@%s suName hostName
LogChan
chan
*
model
.
FTPLog
}
func
(
u
*
UserSftp
)
initial
(
assets
[]
model
.
Asset
)
{
u
.
RootPath
=
config
.
GetConf
()
.
SftpRoot
u
.
hosts
=
make
(
map
[
string
]
*
HostnameDir
)
u
.
sftpClients
=
make
(
map
[
string
]
*
SftpConn
)
u
.
LogChan
=
make
(
chan
*
model
.
FTPLog
,
10
)
for
i
:=
0
;
i
<
len
(
assets
);
i
++
{
if
!
assets
[
i
]
.
IsSupportProtocol
(
"ssh"
)
{
continue
}
key
:=
assets
[
i
]
.
Hostname
if
assets
[
i
]
.
OrgID
!=
""
{
key
=
fmt
.
Sprintf
(
"%s.%s"
,
assets
[
i
]
.
Hostname
,
assets
[
i
]
.
OrgName
)
}
u
.
hosts
[
key
]
=
NewHostnameDir
(
&
assets
[
i
])
}
go
u
.
LoopPushFTPLog
()
}
func
(
u
*
UserSftp
)
ReadDir
(
path
string
)
(
res
[]
os
.
FileInfo
,
err
error
)
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
u
.
RootDirInfo
()
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
res
,
sftp
.
ErrSshFxNoSuchFile
}
if
req
.
su
==
""
{
for
_
,
su
:=
range
host
.
GetSystemUsers
()
{
res
=
append
(
res
,
NewFakeFile
(
su
.
Name
,
true
))
}
return
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
res
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
ConnectAction
)
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
logger
.
Debug
(
"intersftp read dir real path: "
,
realPath
)
res
,
err
=
conn
.
client
.
ReadDir
(
realPath
)
return
res
,
err
}
func
(
u
*
UserSftp
)
Stat
(
path
string
)
(
res
os
.
FileInfo
,
err
error
)
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
u
.
Info
()
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
res
,
sftp
.
ErrSshFxNoSuchFile
}
if
req
.
su
==
""
{
res
=
NewFakeFile
(
req
.
host
,
true
)
return
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
res
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
ConnectAction
)
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
return
conn
.
client
.
Stat
(
realPath
)
}
func
(
u
*
UserSftp
)
ReadLink
(
path
string
)
(
res
string
,
err
error
)
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
if
req
.
su
==
""
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
res
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
ConnectAction
)
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
res
,
sftp
.
ErrSshFxPermissionDenied
}
return
conn
.
client
.
ReadLink
(
realPath
)
}
func
(
u
*
UserSftp
)
RemoveDirectory
(
path
string
)
error
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
sftp
.
ErrSshFxPermissionDenied
}
if
req
.
su
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
UploadAction
)
{
return
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
sftp
.
ErrSshFxPermissionDenied
}
err
:=
conn
.
client
.
RemoveDirectory
(
realPath
)
filename
:=
realPath
isSucess
:=
false
operate
:=
model
.
OperateRemoveDir
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
err
}
func
(
u
*
UserSftp
)
Remove
(
path
string
)
error
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
sftp
.
ErrSshFxPermissionDenied
}
if
req
.
su
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
UploadAction
)
{
return
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
sftp
.
ErrSshFxPermissionDenied
}
err
:=
conn
.
client
.
Remove
(
realPath
)
filename
:=
realPath
isSucess
:=
false
operate
:=
model
.
OperateDelete
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
err
}
func
(
u
*
UserSftp
)
MkdirAll
(
path
string
)
error
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
sftp
.
ErrSshFxPermissionDenied
}
if
req
.
su
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
UploadAction
)
{
return
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
sftp
.
ErrSshFxPermissionDenied
}
err
:=
conn
.
client
.
MkdirAll
(
realPath
)
filename
:=
realPath
isSucess
:=
false
operate
:=
model
.
OperateMkdir
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
err
}
func
(
u
*
UserSftp
)
Rename
(
oldNamePath
,
newNamePath
string
)
error
{
req1
:=
u
.
ParsePath
(
oldNamePath
)
req2
:=
u
.
ParsePath
(
newNamePath
)
if
req1
.
host
==
""
||
req2
.
host
==
""
||
req1
.
su
==
""
||
req2
.
su
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
else
if
req1
.
host
!=
req2
.
host
||
req1
.
su
!=
req2
.
su
{
return
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req1
.
host
]
if
!
ok
{
return
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req1
.
su
]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
UploadAction
)
{
return
sftp
.
ErrSshFxPermissionDenied
}
conn1
,
oldRealPath
:=
u
.
GetSFTPAndRealPath
(
req1
)
conn2
,
newRealPath
:=
u
.
GetSFTPAndRealPath
(
req2
)
if
conn1
!=
conn2
{
return
sftp
.
ErrSshFxOpUnsupported
}
err
:=
conn1
.
client
.
Rename
(
oldRealPath
,
newRealPath
)
filename
:=
fmt
.
Sprintf
(
"%s=>%s"
,
oldRealPath
,
newRealPath
)
isSucess
:=
false
operate
:=
model
.
OperateRename
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
err
}
func
(
u
*
UserSftp
)
Symlink
(
oldNamePath
,
newNamePath
string
)
error
{
req1
:=
u
.
ParsePath
(
oldNamePath
)
req2
:=
u
.
ParsePath
(
newNamePath
)
if
req1
.
host
==
""
||
req2
.
host
==
""
||
req1
.
su
==
""
||
req2
.
su
==
""
{
return
sftp
.
ErrSshFxPermissionDenied
}
else
if
req1
.
host
!=
req2
.
host
||
req1
.
su
!=
req2
.
su
{
return
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req1
.
host
]
if
!
ok
{
return
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req1
.
su
]
if
!
ok
{
return
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
UploadAction
)
{
return
sftp
.
ErrSshFxPermissionDenied
}
conn1
,
oldRealPath
:=
u
.
GetSFTPAndRealPath
(
req1
)
conn2
,
newRealPath
:=
u
.
GetSFTPAndRealPath
(
req2
)
if
conn1
!=
conn2
{
return
sftp
.
ErrSshFxOpUnsupported
}
err
:=
conn1
.
client
.
Symlink
(
oldRealPath
,
newRealPath
)
filename
:=
fmt
.
Sprintf
(
"%s=>%s"
,
oldRealPath
,
newRealPath
)
isSucess
:=
false
operate
:=
model
.
OperateSymlink
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
err
}
func
(
u
*
UserSftp
)
Create
(
path
string
)
(
*
sftp
.
File
,
error
)
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
if
req
.
su
==
""
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
UploadAction
)
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
sf
,
err
:=
conn
.
client
.
Create
(
realPath
)
filename
:=
realPath
isSucess
:=
false
operate
:=
model
.
OperateUpload
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
sf
,
err
}
func
(
u
*
UserSftp
)
Open
(
path
string
)
(
*
sftp
.
File
,
error
)
{
req
:=
u
.
ParsePath
(
path
)
if
req
.
host
==
""
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
host
,
ok
:=
u
.
hosts
[
req
.
host
]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
if
req
.
su
==
""
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
su
,
ok
:=
host
.
suMaps
[
req
.
su
]
if
!
ok
{
return
nil
,
sftp
.
ErrSshFxNoSuchFile
}
if
!
u
.
validatePermission
(
su
,
model
.
DownloadAction
)
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
conn
,
realPath
:=
u
.
GetSFTPAndRealPath
(
req
)
if
conn
==
nil
{
return
nil
,
sftp
.
ErrSshFxPermissionDenied
}
sf
,
err
:=
conn
.
client
.
Open
(
realPath
)
filename
:=
realPath
isSucess
:=
false
operate
:=
model
.
OperateDownaload
if
err
==
nil
{
isSucess
=
true
}
u
.
CreateFTPLog
(
host
.
asset
,
su
,
operate
,
filename
,
isSucess
)
return
sf
,
err
}
func
(
u
*
UserSftp
)
Info
()
(
os
.
FileInfo
,
error
)
{
return
NewFakeFile
(
"/"
,
true
),
nil
}
func
(
u
*
UserSftp
)
RootDirInfo
()
([]
os
.
FileInfo
,
error
)
{
hostDirs
:=
make
([]
os
.
FileInfo
,
0
,
len
(
u
.
hosts
))
for
key
:=
range
u
.
hosts
{
hostDirs
=
append
(
hostDirs
,
NewFakeFile
(
key
,
true
))
}
sort
.
Sort
(
FileInfoList
(
hostDirs
))
return
hostDirs
,
nil
}
func
(
u
*
UserSftp
)
ParsePath
(
path
string
)
(
req
requestMessage
)
{
data
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
,
"/"
),
"/"
)
if
len
(
data
)
==
0
{
return
}
host
,
pathArray
:=
data
[
0
],
data
[
1
:
]
req
.
host
=
host
if
suName
,
unique
:=
u
.
HostHasUniqueSu
(
host
);
unique
{
req
.
suUnique
=
true
req
.
su
=
suName
}
else
{
if
len
(
pathArray
)
==
0
{
req
.
su
=
""
}
else
{
req
.
su
,
pathArray
=
pathArray
[
0
],
pathArray
[
1
:
]
}
}
req
.
dpath
=
strings
.
Join
(
pathArray
,
"/"
)
return
}
func
(
u
*
UserSftp
)
GetSFTPAndRealPath
(
req
requestMessage
)
(
conn
*
SftpConn
,
realPath
string
)
{
if
host
,
ok
:=
u
.
hosts
[
req
.
host
];
ok
{
if
su
,
ok
:=
host
.
suMaps
[
req
.
su
];
ok
{
key
:=
fmt
.
Sprintf
(
"%s@%s"
,
su
.
Name
,
req
.
host
)
conn
,
ok
:=
u
.
sftpClients
[
key
]
if
!
ok
{
var
err
error
conn
,
err
=
u
.
GetSftpClient
(
host
.
asset
,
su
)
if
err
!=
nil
{
logger
.
Debug
(
"Get Sftp Client err: "
,
err
.
Error
())
return
nil
,
""
}
u
.
sftpClients
[
key
]
=
conn
}
switch
strings
.
ToLower
(
u
.
RootPath
)
{
case
"home"
,
"~"
,
""
:
realPath
=
filepath
.
Join
(
conn
.
HomeDirPath
,
strings
.
TrimPrefix
(
req
.
dpath
,
"/"
))
default
:
realPath
=
filepath
.
Join
(
u
.
RootPath
,
strings
.
TrimPrefix
(
req
.
dpath
,
"/"
))
}
return
conn
,
realPath
}
}
return
}
func
(
u
*
UserSftp
)
HostHasUniqueSu
(
hostKey
string
)
(
string
,
bool
)
{
if
host
,
ok
:=
u
.
hosts
[
hostKey
];
ok
{
return
host
.
HasUniqueSu
()
}
return
""
,
false
}
func
(
u
*
UserSftp
)
validatePermission
(
su
*
model
.
SystemUser
,
action
string
)
bool
{
for
_
,
pemAction
:=
range
su
.
Actions
{
if
pemAction
==
action
||
pemAction
==
model
.
AllAction
{
return
true
}
}
return
false
}
func
(
u
*
UserSftp
)
CreateFTPLog
(
asset
*
model
.
Asset
,
su
*
model
.
SystemUser
,
operate
,
filename
string
,
isSuccess
bool
)
{
data
:=
model
.
FTPLog
{
User
:
fmt
.
Sprintf
(
"%s (%s)"
,
u
.
User
.
Name
,
u
.
User
.
Username
),
Hostname
:
asset
.
Hostname
,
OrgID
:
asset
.
OrgID
,
SystemUser
:
su
.
Name
,
RemoteAddr
:
u
.
Addr
,
Operate
:
operate
,
Path
:
filename
,
DataStart
:
common
.
CurrentUTCTime
(),
IsSuccess
:
isSuccess
,
}
u
.
LogChan
<-
&
data
}
func
(
u
*
UserSftp
)
LoopPushFTPLog
()
{
ftpLogList
:=
make
([]
*
model
.
FTPLog
,
0
,
1024
)
dataChan
:=
make
(
chan
*
model
.
FTPLog
)
go
u
.
SendFTPLog
(
dataChan
)
defer
close
(
dataChan
)
for
{
select
{
case
<-
time
.
After
(
time
.
Second
*
5
)
:
case
logData
,
ok
:=
<-
u
.
LogChan
:
if
!
ok
{
return
}
ftpLogList
=
append
(
ftpLogList
,
logData
)
}
if
len
(
ftpLogList
)
>
0
{
select
{
case
dataChan
<-
ftpLogList
[
len
(
ftpLogList
)
-
1
]
:
ftpLogList
=
ftpLogList
[
:
len
(
ftpLogList
)
-
1
]
default
:
}
}
}
}
func
(
u
*
UserSftp
)
SendFTPLog
(
dataChan
<-
chan
*
model
.
FTPLog
)
{
for
data
:=
range
dataChan
{
for
i
:=
0
;
i
<
4
;
i
++
{
err
:=
service
.
PushFTPLog
(
data
)
if
err
==
nil
{
break
}
logger
.
Debugf
(
"create FTP log err: %s"
,
err
.
Error
())
}
}
}
func
(
u
*
UserSftp
)
GetSftpClient
(
asset
*
model
.
Asset
,
sysUser
*
model
.
SystemUser
)
(
conn
*
SftpConn
,
err
error
)
{
sshClient
,
err
:=
NewClient
(
u
.
User
,
asset
,
sysUser
,
config
.
GetConf
()
.
SSHTimeout
*
time
.
Second
)
if
err
!=
nil
{
return
}
sftpClient
,
err
:=
sftp
.
NewClient
(
sshClient
.
Client
)
if
err
!=
nil
{
return
}
HomeDirPath
,
err
:=
sftpClient
.
Getwd
()
if
err
!=
nil
{
return
}
conn
=
&
SftpConn
{
client
:
sftpClient
,
conn
:
sshClient
,
HomeDirPath
:
HomeDirPath
}
return
conn
,
err
}
func
(
u
*
UserSftp
)
Close
()
{
for
_
,
client
:=
range
u
.
sftpClients
{
client
.
Close
()
}
close
(
u
.
LogChan
)
}
type
requestMessage
struct
{
host
string
su
string
dpath
string
suUnique
bool
}
func
NewHostnameDir
(
asset
*
model
.
Asset
)
*
HostnameDir
{
sus
:=
make
(
map
[
string
]
*
model
.
SystemUser
)
for
i
:=
0
;
i
<
len
(
asset
.
SystemUsers
);
i
++
{
if
asset
.
SystemUsers
[
i
]
.
Protocol
==
"ssh"
{
sus
[
asset
.
SystemUsers
[
i
]
.
Name
]
=
&
asset
.
SystemUsers
[
i
]
}
}
h
:=
HostnameDir
{
asset
:
asset
,
suMaps
:
sus
}
return
&
h
}
type
HostnameDir
struct
{
asset
*
model
.
Asset
suMaps
map
[
string
]
*
model
.
SystemUser
}
func
(
h
*
HostnameDir
)
HasUniqueSu
()
(
string
,
bool
)
{
sus
:=
h
.
GetSystemUsers
()
if
len
(
sus
)
==
1
{
return
sus
[
0
]
.
Name
,
true
}
return
""
,
false
}
func
(
h
*
HostnameDir
)
GetSystemUsers
()
(
sus
[]
model
.
SystemUser
)
{
sus
=
make
([]
model
.
SystemUser
,
0
,
len
(
h
.
suMaps
))
for
_
,
item
:=
range
h
.
suMaps
{
sus
=
append
(
sus
,
*
item
)
}
model
.
SortSystemUserByPriority
(
sus
)
return
sus
}
type
SftpConn
struct
{
HomeDirPath
string
client
*
sftp
.
Client
conn
*
SSHClient
}
func
(
s
*
SftpConn
)
Close
()
{
_
=
s
.
client
.
Close
()
RecycleClient
(
s
.
conn
)
}
func
NewFakeFile
(
name
string
,
isDir
bool
)
*
FakeFileInfo
{
return
&
FakeFileInfo
{
name
:
name
,
modtime
:
time
.
Now
()
.
UTC
(),
isDir
:
isDir
,
size
:
int64
(
0
),
}
}
func
NewFakeSymFile
(
name
string
)
*
FakeFileInfo
{
return
&
FakeFileInfo
{
name
:
name
,
modtime
:
time
.
Now
()
.
UTC
(),
size
:
int64
(
0
),
symlink
:
name
,
}
}
type
FakeFileInfo
struct
{
name
string
isDir
bool
size
int64
modtime
time
.
Time
symlink
string
}
func
(
f
*
FakeFileInfo
)
Name
()
string
{
return
f
.
name
}
func
(
f
*
FakeFileInfo
)
Size
()
int64
{
return
f
.
size
}
func
(
f
*
FakeFileInfo
)
Mode
()
os
.
FileMode
{
ret
:=
os
.
FileMode
(
0644
)
if
f
.
isDir
{
ret
=
os
.
FileMode
(
0755
)
|
os
.
ModeDir
}
if
f
.
symlink
!=
""
{
ret
=
os
.
FileMode
(
0777
)
|
os
.
ModeSymlink
}
return
ret
}
func
(
f
*
FakeFileInfo
)
ModTime
()
time
.
Time
{
return
f
.
modtime
}
func
(
f
*
FakeFileInfo
)
IsDir
()
bool
{
return
f
.
isDir
}
func
(
f
*
FakeFileInfo
)
Sys
()
interface
{}
{
return
&
syscall
.
Stat_t
{
Uid
:
0
,
Gid
:
0
}
}
type
FileInfoList
[]
os
.
FileInfo
func
(
fl
FileInfoList
)
Len
()
int
{
return
len
(
fl
)
}
func
(
fl
FileInfoList
)
Swap
(
i
,
j
int
)
{
fl
[
i
],
fl
[
j
]
=
fl
[
j
],
fl
[
i
]
}
func
(
fl
FileInfoList
)
Less
(
i
,
j
int
)
bool
{
return
fl
[
i
]
.
Name
()
<
fl
[
j
]
.
Name
()
}
pkg/srvconn/utils.go
View file @
d80a7d05
package
srvconn
package
srvconn
import
(
import
(
"golang.org/x/crypto/ssh"
"io/ioutil"
"io/ioutil"
"golang.org/x/crypto/ssh"
)
)
func
GetPubKeyFromFile
(
keypath
string
)
(
ssh
.
Signer
,
error
)
{
func
GetPubKeyFromFile
(
keypath
string
)
(
ssh
.
Signer
,
error
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment