diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8fffaf9d..97591a01 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -38,16 +38,21 @@ jobs: sudo mkdir -p /tmp/trasa/accessproxy/ssh sudo chmod 777 /tmp/trasa/accessproxy/ssh + + - name: Go get + working-directory: ./server + run: go get -v ./... + - name: Unit Test - working-directory: ./tests - run: make unit-test + working-directory: ./server + run: go test -v ./... - name: Integration Test working-directory: ./tests - run: make integration-test + run: cd build/integration && docker-compose up --build -d && cd ../.. && go test -v ./server - name: Clean - working-directory: ./tests - run: make clear + working-directory: ./tests/build/integration + run: docker-compose down diff --git a/.gitignore b/.gitignore index 887ef370..8e325c45 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ trasa-server server/server +devenv/ + .vscode/ .idea/ diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..66a59b08 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +.PHONY: dependency unit-test integration-test docker-up-all docker-down-all docker-up-db docker-down-db clear + + +dev-setup: + @mkdir -p devenv/var/log && cp -r build/etc devenv/ && touch devenv/var/log/trasa.log + +dev-run: + @cd build/docker && docker-compose up --build + +clear: + @cd build/docker && docker-compose down diff --git a/build/docker/dev/Dockerfile b/build/docker/dev/Dockerfile index d21ce975..3a8d8afe 100644 --- a/build/docker/dev/Dockerfile +++ b/build/docker/dev/Dockerfile @@ -30,11 +30,13 @@ RUN yarn run build FROM ubuntu:xenial-20200706 WORKDIR /trasa +ENV GUACENC_INSTALLED=true RUN apt-get update RUN apt-get install -y --no-install-recommends ca-certificates RUN update-ca-certificates COPY --from=gobuilder /go/src/seknox/trasa/server/server . COPY --from=dashbuilder /trasa/build /var/trasa/dashboard +COPY --from=seknox/guacd:v0.0.1 /usr/local/guacamole/bin/guacenc /usr/local/guacamole/bin/guacenc COPY build/etc/trasa /etc/trasa COPY build/docker/wait-for-it.sh . CMD ["/trasa/wait-for-it.sh","db:5432", "--","/trasa/server"] diff --git a/dashboard/src/pages/Control/policies/newCreatePolicy.tsx b/dashboard/src/pages/Control/policies/newCreatePolicy.tsx index e8a484de..17425399 100644 --- a/dashboard/src/pages/Control/policies/newCreatePolicy.tsx +++ b/dashboard/src/pages/Control/policies/newCreatePolicy.tsx @@ -630,7 +630,7 @@ function PolicyTab(props: any) { aria-label="styled tabs example" > - + - + {/* Basic Policy */} diff --git a/dashboard/src/pages/Providers/CryptoOps/CertificateAuthority/index.tsx b/dashboard/src/pages/Providers/CryptoOps/CertificateAuthority/index.tsx index b2c75e32..b494c46e 100644 --- a/dashboard/src/pages/Providers/CryptoOps/CertificateAuthority/index.tsx +++ b/dashboard/src/pages/Providers/CryptoOps/CertificateAuthority/index.tsx @@ -130,7 +130,7 @@ export default function CA(props: any) { const generateSSHCA = (type: any) => () => { axios - .post(`${Constants.TRASA_HOSTNAME}/api/v1/system/sshca/init/${type}`) + .post(`${Constants.TRASA_HOSTNAME}/api/v1/providers/ca/tsxca/ssh/init/${type}`) .then((response) => {}); }; @@ -336,7 +336,7 @@ function CATable(props: any) { const downloadCA = (name: any, type: any) => () => { switch (type) { case 'SSH_CA': - axios.get(`${Constants.TRASA_HOSTNAME}/api/v1/system/ca/ssh/${name}`).then((response) => { + axios.get(`${Constants.TRASA_HOSTNAME}/api/v1/providers/ca/tsxca/ssh/${name}`).then((response) => { fileDownload(response.data, 'ca-cert.pem', 'application/x-pem-file'); }); break; diff --git a/dashboard/src/pages/Services/Service/Settings/ServiceSetting.tsx b/dashboard/src/pages/Services/Service/Settings/ServiceSetting.tsx index 4eb0fd7e..0d717a85 100644 --- a/dashboard/src/pages/Services/Service/Settings/ServiceSetting.tsx +++ b/dashboard/src/pages/Services/Service/Settings/ServiceSetting.tsx @@ -271,7 +271,7 @@ export default function Servicesetting(props: ServicesettingProps) {
SSH
-
HTTP
+
HTTP (Beta)
diff --git a/go.mod b/go.mod index b4b5ed66..85fa4682 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,6 @@ require ( github.com/hashicorp/vault/api v1.0.5-0.20200317185738-82f498082f02 github.com/huandu/go-sqlbuilder v1.8.0 github.com/jinzhu/now v1.1.1 - github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 github.com/lib/pq v1.8.0 github.com/manifoldco/promptui v0.7.0 github.com/mholt/archiver v3.1.1+incompatible diff --git a/go.sum b/go.sum index 78383c0b..d36af8ef 100644 --- a/go.sum +++ b/go.sum @@ -501,8 +501,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 h1:Iy7Ifq2ysilWU4QlCx/97OoI4xT1IV7i8byT/EyIT/M= -github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= diff --git a/server/accessproxy/http/logger.go b/server/accessproxy/http/logger.go index 05e65a7d..ce07ab7f 100644 --- a/server/accessproxy/http/logger.go +++ b/server/accessproxy/http/logger.go @@ -2,11 +2,12 @@ package http import ( "fmt" + "github.com/seknox/trasa/server/utils" "github.com/sirupsen/logrus" - "net/http" "net/http/httputil" "os" + "path/filepath" "time" ) @@ -27,14 +28,14 @@ func passwordManAndLogger(r *http.Request, sessionID, csrfToken, userName string return err } - directoryBuilder := fmt.Sprintf("/tmp/trasa/accessproxy/http/%s", sessionID) + directoryBuilder := fmt.Sprintf(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "http", sessionID)) err = createDirIfNotExist(directoryBuilder) if err != nil { return err } - logPath := fmt.Sprintf("%s/%s.http-raw", directoryBuilder, sessionID) + logPath := filepath.Join(directoryBuilder, fmt.Sprintf("%s.http-raw", sessionID)) file, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755) if err != nil { logrus.Error(err) diff --git a/server/accessproxy/rdpproxy/session.go b/server/accessproxy/rdpproxy/session.go index 0cd1617f..7e9fedfe 100644 --- a/server/accessproxy/rdpproxy/session.go +++ b/server/accessproxy/rdpproxy/session.go @@ -169,7 +169,7 @@ func (s *Session) Start(ws *websocket.Conn) (errcode string, err error) { reader := s.tunnel.AcquireReader() defer s.tunnel.ReleaseReader() - errcode, err = catchInitialErrors(*ws, writer, reader) + errcode, err = catchInitialErrors(ws, writer, reader) if err != nil { logrus.Error(errcode, err) if errcode == "519" || errcode == "769" { @@ -235,13 +235,13 @@ func (s *Session) Start(ws *websocket.Conn) (errcode string, err error) { //It will listen for error within first few instructions //If everything seem fine continue to serveIO -func catchInitialErrors(ws websocket.Conn, guacdWriter io.Writer, guacdReader guacamole.InstructionReader) (errcode string, err error) { +func catchInitialErrors(ws *websocket.Conn, guacdWriter io.Writer, guacdReader guacamole.InstructionReader) (errcode string, err error) { wg := sync.WaitGroup{} exit := make(chan error, 2) wg.Add(2) var done = false - go func(conn guacamole.InstructionReader, ws websocket.Conn) { + go func(conn guacamole.InstructionReader, ws *websocket.Conn) { var err error var raw []byte var inst *guacamole.Instruction @@ -279,7 +279,7 @@ func catchInitialErrors(ws websocket.Conn, guacdWriter io.Writer, guacdReader gu wg.Done() }(guacdReader, ws) - go func(conn io.Writer, ws websocket.Conn) { + go func(conn io.Writer, ws *websocket.Conn) { var err error var buf []byte for !done { diff --git a/server/accessproxy/rdpproxy/store.go b/server/accessproxy/rdpproxy/store.go index 4c78b381..a8d47266 100644 --- a/server/accessproxy/rdpproxy/store.go +++ b/server/accessproxy/rdpproxy/store.go @@ -2,9 +2,11 @@ package rdpproxy import ( "fmt" + "github.com/seknox/trasa/server/utils" "os" "os/exec" "path/filepath" + "runtime" "time" "github.com/pkg/errors" @@ -20,15 +22,20 @@ func (s GWStore) CheckPolicy(params *models.ConnectionParams, policy *models.Pol func (s GWStore) uploadSessionLog(authlog *logs.AuthLog) error { - tempFileDir := "/tmp/trasa/accessproxy/guac" + tempFileDir := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac") bucketName := "trasa-guac-logs" sessionID := authlog.SessionID logrus.Debugf("sessionID is %s", sessionID) loginTime := time.Unix(0, authlog.LoginTime) - guacencCmdStr := fmt.Sprintf("sudo docker exec guacd /usr/local/guacamole/bin/guacenc -f /tmp/trasa/accessproxy/guac/%s.guac", sessionID) - guacenc := exec.Command("/bin/bash", "-c", guacencCmdStr) + //TODO @sshahcodes + + //sudo docker exec guacd /usr/local/guacamole/bin/guacenc -f /tmp/trasa/accessproxy/guac/%s.guac + //here guacd is container name + + guacenc := getGuacencCmd(sessionID) + ll, err := guacenc.CombinedOutput() // logger.Debug(string(ll)) if err != nil { @@ -42,8 +49,7 @@ func (s GWStore) uploadSessionLog(authlog *logs.AuthLog) error { } - ffmpegCmdStr := fmt.Sprintf("sudo ffmpeg -i %s/%s.guac.m4v %s/%s.mp4", tempFileDir, sessionID, tempFileDir, sessionID) - ffmpeg := exec.Command("/bin/bash", "-c", ffmpegCmdStr) + ffmpeg := getFFMPEGcmd(tempFileDir, sessionID) ll, err = ffmpeg.CombinedOutput() //logger.Debug(string(ll)) if err != nil { @@ -57,8 +63,9 @@ func (s GWStore) uploadSessionLog(authlog *logs.AuthLog) error { } + //don't use fileapth.join in object name objectName := fmt.Sprintf("%s/%d/%d/%d/%s.guac", authlog.OrgID, loginTime.Year(), int(loginTime.Month()), loginTime.Day(), sessionID) - filePath := fmt.Sprintf("%s/%s.mp4", tempFileDir, sessionID) + filePath := filepath.Join(tempFileDir, fmt.Sprintf("%s.mp4", sessionID)) // Upload log file to minio uploadErr := logs.Store.PutIntoMinio(objectName, filePath, bucketName) @@ -77,3 +84,38 @@ func (s GWStore) uploadSessionLog(authlog *logs.AuthLog) error { return uploadErr } + +func getGuacencCmd(sessionID string) *exec.Cmd { + if os.Getenv("GUACENC_INSTALLED") == "true" { + guacencCmdStr := fmt.Sprintf( + "/usr/local/guacamole/bin/guacenc -f /tmp/trasa/accessproxy/guac/%s.guac", sessionID) + + return exec.Command("/bin/sh", "-c", guacencCmdStr) + + } + + if runtime.GOOS == "windows" { + guacencCmdStr := fmt.Sprintf( + "docker.exe exec guacd /usr/local/guacamole/bin/guacenc -f /tmp/trasa/accessproxy/guac/%s.guac", sessionID) + + return exec.Command("powershell", "-c", guacencCmdStr) + } + + guacencCmdStr := fmt.Sprintf( + "sudo docker exec guacd /usr/local/guacamole/bin/guacenc -f /tmp/trasa/accessproxy/guac/%s.guac", sessionID) + return exec.Command("/bin/bash", "-c", guacencCmdStr) + +} + +func getFFMPEGcmd(tempFileDir, sessionID string) *exec.Cmd { + + if runtime.GOOS == "windows" { + ffmpegCmdStr := fmt.Sprintf(`ffmpeg.exe -i %s\%s.guac.m4v %s\%s.mp4`, tempFileDir, sessionID, tempFileDir, sessionID) + return exec.Command("powershell", "-c", ffmpegCmdStr) + + } + + ffmpegCmdStr := fmt.Sprintf("sudo ffmpeg -i %s/%s.guac.m4v %s/%s.mp4", tempFileDir, sessionID, tempFileDir, sessionID) + return exec.Command("/bin/bash", "-c", ffmpegCmdStr) + +} diff --git a/server/accessproxy/sshproxy/listner.go b/server/accessproxy/sshproxy/listner.go index 560ad44f..7f440e48 100644 --- a/server/accessproxy/sshproxy/listner.go +++ b/server/accessproxy/sshproxy/listner.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" "io/ioutil" "net" + "path/filepath" ) func ListenSSH(closeChan chan bool) error { @@ -18,7 +19,7 @@ func ListenSSH(closeChan chan bool) error { // } //}() - privateBytes, err := ioutil.ReadFile("/etc/trasa/certs/id_rsa") + privateBytes, err := ioutil.ReadFile(filepath.Join(utils.GetETCDir(), "trasa", "certs", "id_rsa")) if err != nil { pkey, err := utils.GeneratePrivateKey(4082) if err != nil { diff --git a/server/accessproxy/sshproxy/multiwriter.go b/server/accessproxy/sshproxy/multiwriter.go index 7a4793b0..ceb1baf0 100644 --- a/server/accessproxy/sshproxy/multiwriter.go +++ b/server/accessproxy/sshproxy/multiwriter.go @@ -3,9 +3,11 @@ package sshproxy import ( "fmt" "github.com/gorilla/websocket" + "github.com/seknox/trasa/server/utils" "github.com/sirupsen/logrus" "io" "os" + "path/filepath" "runtime/debug" ) @@ -21,7 +23,7 @@ type WrappedTunnel struct { func NewWrappedTunnel(sessionID string, sessionRecord bool, backendReader io.Reader, backendWriter io.WriteCloser, guestChan chan GuestClient) (*WrappedTunnel, error) { - err := os.MkdirAll("/tmp/trasa/accessproxy/ssh/", 0644) + err := os.MkdirAll(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "ssh"), 0644) if err != nil { logrus.Error(err) return nil, err @@ -35,7 +37,7 @@ func NewWrappedTunnel(sessionID string, sessionRecord bool, backendReader io.Rea } if sessionRecord { - tunn.tempLogFile, err = os.OpenFile("/tmp/trasa/accessproxy/ssh/"+sessionID+".session", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + tunn.tempLogFile, err = os.OpenFile(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "ssh", sessionID+".session"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { logrus.Error(err) return nil, err diff --git a/server/accessproxy/sshproxy/store.go b/server/accessproxy/sshproxy/store.go index f318e130..02975f41 100644 --- a/server/accessproxy/sshproxy/store.go +++ b/server/accessproxy/sshproxy/store.go @@ -7,6 +7,7 @@ import ( "fmt" "net" "os" + "path/filepath" "strings" "time" @@ -293,15 +294,15 @@ func (s Store) deleteGuestChannel(sessionID string) { func (s Store) uploadSessionLog(authlog *logs.AuthLog) error { - tempFileDir := "/tmp/trasa/accessproxy/ssh" + tempFileDir := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "ssh") bucketName := "trasa-ssh-logs" sessionID := authlog.SessionID loginTime := time.Unix(0, authlog.LoginTime) authlog.LogoutTime = time.Now().UnixNano() - objectName := fmt.Sprintf("%s/%d/%d/%d/%s.session", authlog.OrgID, loginTime.Year(), int(loginTime.Month()), loginTime.Day(), sessionID) - filePath := fmt.Sprintf("%s/%s.session", tempFileDir, sessionID) + objectName := filepath.Join(authlog.OrgID, fmt.Sprintf("%d", loginTime.Year()), fmt.Sprintf("%d", int(loginTime.Month())), fmt.Sprintf("%d", loginTime.Day()), fmt.Sprintf("%s.session", sessionID)) + filePath := filepath.Join(tempFileDir, fmt.Sprintf("%s.session", sessionID)) // Upload log file to minio uploadErr := logs.Store.PutIntoMinio(objectName, filePath, bucketName) diff --git a/server/api/auth/serviceauth/hHTTPSession.go b/server/api/auth/serviceauth/hHTTPSession.go index d4ceff2a..68824355 100644 --- a/server/api/auth/serviceauth/hHTTPSession.go +++ b/server/api/auth/serviceauth/hHTTPSession.go @@ -9,6 +9,7 @@ import ( "net/http" "os" "os/exec" + "path/filepath" "runtime/debug" "strings" "sync" @@ -225,10 +226,10 @@ func AuthHTTPAccessProxy(w http.ResponseWriter, r *http.Request) { sessionIdentifiers.SessionRecord = policy.RecordSession if policy.RecordSession { - directoryBuilder := fmt.Sprintf("/tmp/trasa/accessproxy/http/%s", encodedSession) + directoryBuilder := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "http", encodedSession) logger.Tracef("Logging to : %s", directoryBuilder) utils.CreateDirIfNotExist(directoryBuilder) - logPath := fmt.Sprintf("%s/%s.http-raw", directoryBuilder, encodedSession) + logPath := filepath.Join(directoryBuilder, fmt.Sprintf("%s.http-raw", encodedSession)) file, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755) if err != nil { logger.Error(err) @@ -322,7 +323,7 @@ func sessionWriter(sessionID, shots string) { if len(counterAndImage) == 2 { videoRecord := logStruct.SessionRecord //strings.Split(logStruct.AppID, ":") //home, _ := hdir.Dir() - directoryBuilder := fmt.Sprintf("/tmp/trasa/accessproxy/http/%s", sessionID) + directoryBuilder := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "http", sessionID) if videoRecord == true { // convert to png @@ -339,7 +340,7 @@ func sessionWriter(sessionID, shots string) { utils.CreateDirIfNotExist(directoryBuilder) - filenameBuilder := fmt.Sprintf("%s/%s.png", directoryBuilder, counterAndImage[0]) + filenameBuilder := filepath.Join(directoryBuilder, fmt.Sprintf("%s.png", counterAndImage[0])) //fmt.Println("writing to file: ", filenameBuilder) outputFile, err := os.Create(filenameBuilder) @@ -359,7 +360,7 @@ func sessionWriter(sessionID, shots string) { outputFile.Close() // return at last } - logPath := fmt.Sprintf("%s/%s.http-raw", directoryBuilder, sessionID) + logPath := filepath.Join(directoryBuilder, fmt.Sprintf("%s.http-raw", sessionID)) file, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755) if err != nil { logger.Debug(err) @@ -417,7 +418,7 @@ func logoutSequence(sessionID string) { // 3) create video file from image file deleteDirectory := false - directory := fmt.Sprintf("/tmp/trasa/accessproxy/http/%s", sessionID) + directory := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "http", sessionID) SessionRecord := logStruct.SessionRecord if SessionRecord == true { @@ -438,7 +439,7 @@ func logoutSequence(sessionID string) { if err != nil { logger.Error(err) } - videoSource := fmt.Sprintf("%s/%s", directory, videoFileName) + videoSource := filepath.Join(directory, videoFileName) // 4) upload video file to minio err = uploadToMinio(videoSource, logStruct) @@ -446,7 +447,7 @@ func logoutSequence(sessionID string) { logger.Error(err) } - rawSource := fmt.Sprintf("%s/%s", directory, rawFileName) + rawSource := filepath.Join(directory, rawFileName) // 5) upload raw log file to minio err = uploadToMinio(rawSource, logStruct) diff --git a/server/api/logs/store.go b/server/api/logs/store.go index 0ca13cea..fd297b8d 100644 --- a/server/api/logs/store.go +++ b/server/api/logs/store.go @@ -295,7 +295,8 @@ func (s logStore) GetFromMinio(path, bucketName string) (object io.ReadSeeker, e if global.GetConfig().Minio.Status { return s.MinioClient.GetObject(bucketName, path, minio.GetObjectOptions{}) } - filename := fmt.Sprintf(`/var/trasa/minio/%s/%s`, bucketName, path) + + filename := filepath.Join(utils.GetVarDir(), "trasa", "minio", bucketName, path) return os.OpenFile(filename, os.O_RDONLY, os.ModePerm) } @@ -305,7 +306,7 @@ func (s logStore) PutIntoMinio(objectName, logfilepath, bucketName string) error _, err := s.MinioClient.FPutObject(bucketName, objectName, logfilepath, minio.PutObjectOptions{}) return err } - newpath := fmt.Sprintf(`/var/trasa/minio/%s/%s`, bucketName, objectName) + newpath := filepath.Join(utils.GetVarDir(), "trasa", "minio", bucketName, objectName) dir, _ := filepath.Split(newpath) err := os.MkdirAll(dir, os.ModePerm) if err != nil { @@ -321,7 +322,7 @@ func (s logStore) UploadHTTPLogToMinio(file *os.File, login AuthLog) error { bucketName := "trasa-https-logs" filePath := file.Name() loginTime := time.Unix(0, login.LoginTime) - objectNamePrefix := login.OrgID + "/" + strconv.Itoa(loginTime.Year()) + "/" + strconv.Itoa(int(loginTime.Month())) + "/" + strconv.Itoa(loginTime.Day()) + "/" + objectNamePrefix := filepath.Join(login.OrgID, strconv.Itoa(loginTime.Year()), strconv.Itoa(int(loginTime.Month())), strconv.Itoa(loginTime.Day())) objectName := objectNamePrefix + filepath.Base(file.Name()) diff --git a/server/api/my/hndlFileBrowser.go b/server/api/my/hndlFileBrowser.go index 79249893..660fcb97 100644 --- a/server/api/my/hndlFileBrowser.go +++ b/server/api/my/hndlFileBrowser.go @@ -47,14 +47,14 @@ func FileUploadHandler(w http.ResponseWriter, r *http.Request) { // Create a temporary file within our temp-images directory that follows // a particular naming pattern - err = os.MkdirAll(filepath.Join("/tmp/trasa/accessproxy/guac/shared/", userContext.User.ID), os.ModePerm) + err = os.MkdirAll(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac", "shared", userContext.User.ID), os.ModePerm) if err != nil { logrus.Error(err) utils.TrasaResponse(w, 200, "failed", "could not create shared directory ", "File not uploaded", nil) return } - f, err := os.Create(filepath.Join("/tmp/trasa/accessproxy/guac/shared/", userContext.User.ID, handler.Filename)) + f, err := os.Create(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac", "shared", userContext.User.ID, handler.Filename)) if err != nil { logrus.Error(err) utils.TrasaResponse(w, 200, "failed", "could not create a file", "File not uploaded", nil) @@ -69,7 +69,7 @@ func FileUploadHandler(w http.ResponseWriter, r *http.Request) { func GetDownloadableFileList(w http.ResponseWriter, r *http.Request) { userContext := r.Context().Value("user").(models.UserContext) - userDir := filepath.Join("/tmp/trasa/accessproxy/guac/shared/", userContext.User.ID) + userDir := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac", "shared", userContext.User.ID) fileList, err := ioutil.ReadDir(userDir) if err != nil { logrus.Error(err) @@ -124,7 +124,7 @@ func FileDownloadHandler(w http.ResponseWriter, r *http.Request) { return } - filePath := filepath.Join("/tmp/trasa/accessproxy/guac/shared/", userID, fileName) + filePath := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac", "shared", userID, fileName) w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName)) http.ServeFile(w, r, filePath) @@ -146,7 +146,7 @@ func FileDeleteHandler(w http.ResponseWriter, r *http.Request) { return } - filePath := filepath.Join("/tmp/trasa/accessproxy/guac/shared/", userID, fileName) + filePath := filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac", "shared", userID, fileName) err = os.Remove(filePath) if err != nil { logrus.Error(err) diff --git a/server/global/config.go b/server/global/config.go index adbd469f..808cabea 100644 --- a/server/global/config.go +++ b/server/global/config.go @@ -1,6 +1,7 @@ package global import ( + "github.com/seknox/trasa/server/utils" "path/filepath" "github.com/sirupsen/logrus" @@ -9,9 +10,9 @@ import ( // ParseConfig uses viper to parse TRASA config file. func ParseConfig() (config Config) { - absPath, err := filepath.Abs("/etc/trasa/config") + absPath, err := filepath.Abs(filepath.Join(utils.GetETCDir(), "trasa", "config")) if err != nil { - panic("config file not found in /etc/trasa/config") + panic("config file not found in " + filepath.Join(utils.GetETCDir(), "trasa", "config")) } //viper.SetConfigType("toml") viper.SetConfigName("config") @@ -111,7 +112,7 @@ type Config struct { // UpdateTRASACPxyAddr updates TRASA cloud proxy server address. func UpdateTRASACPxyAddr(serverAddr string) { - absPath, err := filepath.Abs("/etc/trasa/config") + absPath, err := filepath.Abs(filepath.Join(utils.GetETCDir(), "trasa", "config")) if err != nil { logrus.Error(err) } diff --git a/server/global/global.go b/server/global/global.go index 5dc9dc9d..8be5ce2c 100644 --- a/server/global/global.go +++ b/server/global/global.go @@ -6,6 +6,7 @@ import ( "database/sql" "flag" "fmt" + "github.com/seknox/trasa/server/utils" "github.com/spf13/viper" "net" "net/http" @@ -94,8 +95,7 @@ func InitDBSTOREWithConfig(conf Config) *State { flag.Parse() if *logOutputToFile { - - f, err := os.OpenFile("/var/log/trasa.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + f, err := os.OpenFile(filepath.Join(utils.GetVarDir(), "log", "trasa.log"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { panic(err) } @@ -126,7 +126,7 @@ func InitDBSTOREWithConfig(conf Config) *State { //elasticUrl, authUser, authPass := elasticon() // initialize geoIP connection - absPath, err := filepath.Abs("/etc/trasa/static/GeoLite2-City.mmdb") + absPath, err := filepath.Abs(filepath.Join(utils.GetETCDir(), "trasa", "static", "GeoLite2-City.mmdb")) if err != nil { panic("geodb file not found: " + err.Error()) } @@ -134,7 +134,7 @@ func InitDBSTOREWithConfig(conf Config) *State { if err != nil { panic(err) } - absPath, err = filepath.Abs("/etc/trasa/config/key.json") + absPath, err = filepath.Abs(filepath.Join(utils.GetETCDir(), "trasa", "config", "key.json")) if err != nil { logrus.Errorf("firebase key not found: %v", err) } @@ -329,45 +329,45 @@ func newRedisClient(config Config) *redis.Client { } func checkInitDirsAndFiles() { - err := os.MkdirAll("/var/tmp/trasa/accessproxy/guac/shared", 0600) + err := os.MkdirAll(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "guac", "shared"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/var/tmp/trasa/accessproxy/ssh", 0600) + err = os.MkdirAll(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "ssh"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/var/tmp/trasa/accessproxy/http", 0600) + err = os.MkdirAll(filepath.Join(utils.GetTmpDir(), "trasa", "accessproxy", "http"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/var/trasa/crdb", 0600) + err = os.MkdirAll(filepath.Join(utils.GetVarDir(), "trasa", "crdb"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/var/trasa/minio", 0600) + err = os.MkdirAll(filepath.Join(utils.GetVarDir(), "trasa", "minio"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/etc/trasa/certs", 0600) + err = os.MkdirAll(filepath.Join(utils.GetETCDir(), "trasa", "certs"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/etc/trasa/config", 0600) + err = os.MkdirAll(filepath.Join(utils.GetETCDir(), "trasa", "config"), 0600) if err != nil { panic(err) } - err = os.MkdirAll("/etc/trasa/static", 0600) + err = os.MkdirAll(filepath.Join(utils.GetETCDir(), "trasa", "static"), 0600) if err != nil { panic(err) } //create config file if no exist - _, err = os.Stat("/etc/trasa/config/config.toml") + _, err = os.Stat(filepath.Join(utils.GetETCDir(), "trasa", "config", "config.toml")) if err != nil { - f, err := os.OpenFile("/etc/trasa/config/config.toml", os.O_CREATE|os.O_WRONLY, os.ModePerm) + f, err := os.OpenFile(filepath.Join(utils.GetETCDir(), "trasa", "config", "config.toml"), os.O_CREATE|os.O_WRONLY, os.ModePerm) if err != nil { panic(err) } @@ -430,5 +430,14 @@ func checkInitDirsAndFiles() { `) } +} +//Gstate is a global state struct which contains database connections, configurations etc +type Gstate struct { + db *sql.DB + geoip *geoip2.Reader + firebaseClient *firebase.App + minioClient *minio.Client + config Config + redisClient *redis.Client } diff --git a/server/models/models.go b/server/models/models.go index dbaf93c0..010e81c1 100644 --- a/server/models/models.go +++ b/server/models/models.go @@ -1,32 +1,15 @@ package models import ( - "database/sql" "database/sql/driver" "encoding/json" "errors" "github.com/seknox/trasa/server/consts" - firebase "firebase.google.com/go" - "github.com/minio/minio-go" - "github.com/oschwald/geoip2-golang" - "github.com/seknox/trasa/server/global" "github.com/tstranex/u2f" - - "github.com/go-redis/redis/v8" ) -//Gstate is a global state struct which contains database connections, configurations etc -type Gstate struct { - db *sql.DB - geoip *geoip2.Reader - firebaseClient *firebase.App - minioClient *minio.Client - config global.Config - redisClient *redis.Client -} - type GeoLocation struct { IsoCountryCode string `json:"isoCountryCode"` City string `json:"city"` diff --git a/server/server.go b/server/server.go index a852526f..cafa7954 100644 --- a/server/server.go +++ b/server/server.go @@ -8,6 +8,7 @@ import ( "net/url" "os" "os/signal" + "path/filepath" "strings" "time" @@ -19,15 +20,13 @@ import ( "github.com/seknox/trasa/server/api/auth/serviceauth" - "github.com/seknox/trasa/server/api/accesscontrol" - "github.com/seknox/trasa/server/api/system" - "github.com/go-chi/chi" "github.com/go-chi/hostrouter" "github.com/rs/cors" webproxy "github.com/seknox/trasa/server/accessproxy/http" "github.com/seknox/trasa/server/accessproxy/rdpproxy" "github.com/seknox/trasa/server/accessproxy/sshproxy" + "github.com/seknox/trasa/server/api/accesscontrol" "github.com/seknox/trasa/server/api/accessmap" "github.com/seknox/trasa/server/api/auth" "github.com/seknox/trasa/server/api/devices" @@ -45,8 +44,10 @@ import ( "github.com/seknox/trasa/server/api/redis" "github.com/seknox/trasa/server/api/services" "github.com/seknox/trasa/server/api/stats" + "github.com/seknox/trasa/server/api/system" "github.com/seknox/trasa/server/api/users" "github.com/seknox/trasa/server/global" + "github.com/seknox/trasa/server/utils" "github.com/sirupsen/logrus" ) @@ -143,16 +144,19 @@ func StartServr() { if global.GetConfig().Trasa.AutoCert { err = s.Serve(autocert.NewListener(trasaListenAddr)) } else { - err = checkIfCertExists("/etc/trasa/certs/trasa-server.crt", "/etc/trasa/certs/trasa-server.key") + certPath := filepath.Join(utils.GetETCDir(), "trasa", "certs", "trasa-server.crt") + keyPath := filepath.Join(utils.GetETCDir(), "trasa", "certs", "trasa-server.key") + + err = checkIfCertExists(certPath, keyPath) // If they are not available, generate new ones. if err != nil { - err = generateCerts("/etc/trasa/certs/trasa-server.crt", "/etc/trasa/certs/trasa-server.key", trasaListenAddr) + err = generateCerts(certPath, keyPath, trasaListenAddr) if err != nil { logrus.Fatal("Error: Couldn't create https certs.") } } - err = s.ListenAndServeTLS("/etc/trasa/certs/trasa-server.crt", "/etc/trasa/certs/trasa-server.key") + err = s.ListenAndServeTLS(certPath, keyPath) } if err != nil { @@ -265,25 +269,25 @@ func CoreAPIRouter(r *chi.Mux) chi.Router { r.Get("/", func(w http.ResponseWriter, req *http.Request) { logrus.Trace("Not Found ROOT URL: serving ROOT: ", req.URL.Path) w.Header().Set("Cache-Control", "public, max-age=8176000") - http.FileServer(http.Dir("/var/trasa/dashboard")).ServeHTTP(w, req) + http.FileServer(http.Dir(filepath.Join(utils.GetVarDir(), "trasa", "dashboard"))).ServeHTTP(w, req) }) r.Get("/static*", func(w http.ResponseWriter, req *http.Request) { logrus.Trace("Found static URL: serving STATIC : ", req.URL.Path) w.Header().Set("Cache-Control", "public, max-age=8176000") - http.FileServer(http.Dir("/var/trasa/dashboard")).ServeHTTP(w, req) + http.FileServer(http.Dir(filepath.Join(utils.GetVarDir(), "trasa", "dashboard"))).ServeHTTP(w, req) }) r.Get("/assets*", func(w http.ResponseWriter, req *http.Request) { logrus.Trace("Found static URL: serving ASSETS : ", req.URL.Path) w.Header().Set("Cache-Control", "public, max-age=8176000") - http.FileServer(http.Dir("/var/trasa/dashboard")).ServeHTTP(w, req) + http.FileServer(http.Dir(filepath.Join(utils.GetVarDir(), "trasa", "dashboard"))).ServeHTTP(w, req) }) r.NotFound(func(w http.ResponseWriter, req *http.Request) { logrus.Trace("Not Found URL: serving Index File : ", req.URL.Path) w.Header().Set("Cache-Control", "no-store") - http.ServeFile(w, req, "/var/trasa/dashboard/index.html") + http.ServeFile(w, req, filepath.Join(utils.GetVarDir(), "trasa", "dashboard", "index.html")) }) @@ -308,7 +312,7 @@ func FileServer(r chi.Router, path string) { r.NotFound(func(w http.ResponseWriter, req *http.Request) { fmt.Println("Reached not found in File server ") fmt.Println(req.URL) - http.ServeFile(w, req, "/var/trasa/dashboard/index.html") + http.ServeFile(w, req, filepath.Join(utils.GetVarDir(), "trasa", "dashboard", "index.html")) }) } @@ -317,12 +321,12 @@ func serveFile(w http.ResponseWriter, r *http.Request) { //workDir, _ := os.Getwd() - // filesDir := http.Dir(filepath.Join(workDir, "/var/trasa/dashboard")) + // filesDir := http.Dir(filepath.Join(workDir, filepath.Join(utils.GetVarDir(),"trasa","dashboard"))) //fmt.Println("context: ", rctx.RoutePattern()) pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*") // fmt.Println("serving: ", pathPrefix) - fs := http.StripPrefix(pathPrefix, http.FileServer(http.Dir("/var/trasa/dashboard"))) + fs := http.StripPrefix(pathPrefix, http.FileServer(http.Dir(filepath.Join(utils.GetVarDir(), "trasa", "dashboard")))) fs.ServeHTTP(w, r) } diff --git a/server/utils/filesystem.go b/server/utils/filesystem.go index 9a7f109b..eb1b1aa3 100644 --- a/server/utils/filesystem.go +++ b/server/utils/filesystem.go @@ -2,6 +2,7 @@ package utils import ( "os" + "runtime" logger "github.com/sirupsen/logrus" ) @@ -15,3 +16,31 @@ func CreateDirIfNotExist(dir string) { } } } + +func GetETCDir() string { + switch runtime.GOOS { + case "windows": + //TODO @sshahcodes + return "" + default: + return "/etc" + } +} + +func GetVarDir() string { + switch runtime.GOOS { + case "windows": + return `%APPDATA%\` + default: + return "/var" + } +} + +func GetTmpDir() string { + switch runtime.GOOS { + case "windows": + return `C:\\Windows\TEMP` + default: + return "/tmp" + } +}