Compare commits

..
Author SHA1 Message Date
Pierre Dubouilh 67b2019a56 bump golang release 2025-01-19 20:58:20 +01:00
7 changed files with 37 additions and 61 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.23.0
go-version: 1.23.4
id: go
- name: Run
+1 -1
View File
@@ -1,4 +1,4 @@
FLAGS := -trimpath
FLAGS := -trimpath -ldflags="-w -s"
NOCGO := CGO_ENABLED=0
build::
+1 -1
View File
@@ -1,3 +1,3 @@
module github.com/pldubouilh/gossa
go 1.23.0
go 1.23.4
+20 -32
View File
@@ -45,6 +45,11 @@ var verb = flag.Bool("verb", false, "verbosity")
var skipHidden = flag.Bool("k", true, "\nskip hidden files")
var ro = flag.Bool("ro", false, "read only mode (no upload, rename, move, etc...)")
type rpcCall struct {
Call string `json:"call"`
Args []string `json:"args"`
}
var rootPath = ""
var handler http.Handler
@@ -129,7 +134,7 @@ func replyList(w http.ResponseWriter, r *http.Request, fullPath string, path str
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Type", "text/html")
w.Header().Add("Content-Encoding", "gzip")
gz, err := gzip.NewWriterLevel(w, gzip.BestSpeed) // BestSpeed is Much Faster than default - base on a very unscientific local test
gz, err := gzip.NewWriterLevel(w, gzip.BestSpeed) // BestSpeed is Much Faster than default - base on a very unscientific local test, and only ~30% larger (compression remains still very effective, ~6x)
check(err)
defer gz.Close()
tmpl.Execute(gz, p)
@@ -146,8 +151,7 @@ func doContent(w http.ResponseWriter, r *http.Request) {
path := html.UnescapeString(r.URL.Path)
defer exitPath(w, "get content", path)
fullPath, err := enforcePath(path)
check(err)
fullPath := enforcePath(path)
stat, errStat := os.Stat(fullPath)
check(errStat)
@@ -170,9 +174,7 @@ func upload(w http.ResponseWriter, r *http.Request) {
if err != nil && err != io.EOF { // errs EOF when no more parts to process
check(err)
}
path, err = enforcePath(path)
check(err)
dst, err := os.Create(path)
dst, err := os.Create(enforcePath(path))
check(err)
io.Copy(dst, part)
w.Write([]byte("ok"))
@@ -182,9 +184,8 @@ func zipRPC(w http.ResponseWriter, r *http.Request) {
zipPath := r.URL.Query().Get("zipPath")
zipName := r.URL.Query().Get("zipName")
defer exitPath(w, "zip", zipPath)
zipFullPath, err := enforcePath(zipPath)
check(err)
_, err = os.Lstat(zipFullPath)
zipFullPath := enforcePath(zipPath)
_, err := os.Lstat(zipFullPath)
check(err)
w.Header().Add("Content-Disposition", "attachment; filename=\""+zipName+".zip\"")
zipWriter := zip.NewWriter(w)
@@ -202,7 +203,7 @@ func zipRPC(w http.ResponseWriter, r *http.Request) {
return nil // hidden files not allowed
}
if f.Mode()&os.ModeSymlink != 0 {
check(errors.New("symlink not allowed in zip downloads")) // filepath.Walk doesnt support symlinks
panic(errors.New("symlink not allowed in zip downloads")) // filepath.Walk doesnt support symlinks
}
header, err := zip.FileInfoHeader(f)
@@ -223,52 +224,39 @@ func zipRPC(w http.ResponseWriter, r *http.Request) {
}
func rpc(w http.ResponseWriter, r *http.Request) {
type rpcCall struct {
Call string `json:"call"`
Args []string `json:"args"`
}
var err error
var rpc rpcCall
defer exitPath(w, "rpc", rpc)
bodyBytes, err := io.ReadAll(r.Body)
check(err)
json.Unmarshal(bodyBytes, &rpc)
path0, err := enforcePath(rpc.Args[0])
path1 := ""
check(err)
if len(rpc.Args) > 1 {
path1, err = enforcePath(rpc.Args[1])
check(err)
}
if rpc.Call == "mkdirp" {
err = os.MkdirAll(path0, os.ModePerm)
} else if rpc.Call == "mv" && len(rpc.Args) == 2 {
err = os.Rename(path0, path1)
err = os.MkdirAll(enforcePath(rpc.Args[0]), os.ModePerm)
} else if rpc.Call == "mv" {
err = os.Rename(enforcePath(rpc.Args[0]), enforcePath(rpc.Args[1]))
} else if rpc.Call == "rm" {
err = os.RemoveAll(path0)
} else {
err = errors.New("invalid rpc call")
err = os.RemoveAll(enforcePath(rpc.Args[0]))
}
check(err)
w.Write([]byte("ok"))
}
func enforcePath(p string) (string, error) {
func enforcePath(p string) string {
joined := filepath.Join(rootPath, strings.TrimPrefix(p, *extraPath))
fp, err := filepath.Abs(joined)
sl, _ := filepath.EvalSymlinks(fp) // err skipped as it would error for inexistent files (RPC check). The actual behaviour is tested below
sl, _ := filepath.EvalSymlinks(fp) // err skipped as it would error for unexistent files (RPC check). The actual behaviour is tested below
// panic if we had a error getting absolute path,
// ... or if path doesnt contain the prefix path we expect,
// ... or if we're skipping hidden folders, and one is requested,
// ... or if we're skipping symlinks, path exists, and a symlink out of bound requested
if err != nil || !strings.HasPrefix(fp, rootPath) || *skipHidden && strings.Contains(p, "/.") || !*symlinks && len(sl) > 0 && !strings.HasPrefix(sl, rootPath) {
return "", errors.New("invalid path")
panic(errors.New("invalid path"))
}
return fp, nil
return fp
}
func main() {
+1 -1
View File
@@ -1,4 +1,4 @@
FROM docker.io/library/golang:1.23.0-alpine AS builder
FROM docker.io/library/golang:1.23.4-alpine AS builder
RUN apk add --no-cache make
WORKDIR /gossaSrc
COPY . /gossaSrc
+1 -2
View File
@@ -1,2 +1 @@
B!!!
test
B!!!
+12 -23
View File
@@ -153,11 +153,8 @@ function rpc (call, args, cb) {
xhr.open('POST', location.origin + window.extraPath + '/rpc')
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
xhr.send(JSON.stringify({ call, args }))
xhr.onload = () => cb(false)
xhr.onerror = () => {
flicker(sadBadge)
cb(true)
}
xhr.onload = cb
xhr.onerror = () => flicker(sadBadge)
}
const mkdirCall = (path, cb) => rpc('mkdirp', [prependPath(path)], cb)
@@ -318,36 +315,28 @@ const textTypes = ['.txt', '.rtf', '.md', '.markdown', '.log', '.yaml', '.yml']
const isTextFile = src => src && textTypes.find(type => src.toLocaleLowerCase().includes(type))
let fileEdited
function saveText (cb) {
function saveText (quitting) {
const formData = new FormData()
formData.append(fileEdited, editor.value)
const fname = fileEdited + ".swp"
const path = encodeURIComponent(decodeURI(location.pathname) + fname)
const path = encodeURIComponent(decodeURI(location.pathname) + fileEdited)
upload(0, formData, path, () => {
toast.style.display = 'none'
cb()
if (!quitting) return
clearInterval(window.padTimer)
window.onbeforeunload = null
resetView()
softPrev()
refresh()
}, () => {
toast.style.display = 'block'
if (!quitting) return
alert('cant save!\r\nleave window open to resume saving\r\nwhen connection back up')
})
}
function padOff () {
if (!isEditorMode()) { return }
const swapfile = fileEdited + ".swp"
saveText(() => {
mvCall(prependPath(swapfile), prependPath(fileEdited), err => {
if (err) {
alert('cant save!\r\nleave window open to resume saving\r\nwhen connection back up')
return
}
clearInterval(window.padTimer)
window.onbeforeunload = null
resetView()
softPrev()
refresh()
})
})
saveText(true)
return true
}