Compare commits

..
14 Commits
10 changed files with 170 additions and 116 deletions
+4 -9
View File
@@ -6,20 +6,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.23.0
id: go
- name: deps
run: npm i -g standard
- name: Check out code into the Go module directory
uses: actions/checkout@v1
with:
submodules: true
- name: Run
run: make ci
+11 -17
View File
@@ -10,33 +10,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
with:
submodules: true
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.23.0
id: go
uses: actions/checkout@v4
- name: Set env
run: echo "GIT_TAG=`echo $(git describe --tags --abbrev=0)`" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1.6.0
uses: docker/setup-qemu-action@v3
- name: Login to DockerHub
uses: docker/login-action@v1.10.0
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and release on dockerhub
uses: docker/build-push-action@v2.7.0
uses: docker/build-push-action@v6
with:
file: support/build.Dockerfile
push: true
@@ -47,17 +39,19 @@ jobs:
run: make build-all
- name: "Release gh release versioned"
uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37
uses: ncipollo/release-action@v1
with:
allowUpdates: true
artifacts: "builds/*"
bodyFile: "builds/buildout"
token: ${{ secrets.GITHUB_TOKEN }}
- name: "Release gh release latest"
uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37
uses: ncipollo/release-action@v1
with:
tag: latest
name: Latest
allowUpdates: true
artifacts: "builds/*"
bodyFile: "builds/buildout"
token: ${{ secrets.GITHUB_TOKEN }}
-39
View File
@@ -1,39 +0,0 @@
name: rc
on:
push:
branches:
- 'rc/**'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.23.0
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v1
with:
submodules: true
- name: Run
run: make ci
- name: Build all artifacts
run: make build-all
- name: "Release gh release prerelease"
uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37
with:
allowUpdates: true
prerelease: true
tag: "rc"
artifacts: "builds/*"
token: ${{ secrets.GITHUB_TOKEN }}
+2 -5
View File
@@ -17,10 +17,7 @@ run-ro::
run-extra::
./gossa -verb=true -prefix="/fancy-path/" -k=false -symlinks=true test-fixture
lint-js::
standard
ci:: build-all test lint-js
ci:: build-all test
echo "done"
test::
@@ -66,7 +63,7 @@ build-all:: build
${NOCGO} GOOS=darwin GOARCH=amd64 go build ${FLAGS} -o builds/gossa-mac-x64
${NOCGO} GOOS=darwin GOARCH=arm64 go build ${FLAGS} -o builds/gossa-mac-arm64
${NOCGO} GOOS=windows GOARCH=amd64 go build ${FLAGS} -o builds/gossa-windows.exe
sha256sum builds/*
sha256sum builds/* | tee builds/buildout
clean::
rm -f gossa
+37 -9
View File
@@ -3,11 +3,17 @@ package main
import (
"archive/zip"
"compress/gzip"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
_ "embed"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"hash"
"html"
"html/template"
"io"
@@ -100,8 +106,9 @@ func replyList(w http.ResponseWriter, r *http.Request, fullPath string, path str
p.Title = template.HTML(html.EscapeString(title))
for _, el := range files {
info, err := el.Info()
if err != nil {
info, errInfo := el.Info()
el, err := os.Stat(fullPath + "/" + el.Name())
if err != nil || errInfo != nil {
log.Println("error - cant stat a file", err)
continue
}
@@ -109,7 +116,7 @@ func replyList(w http.ResponseWriter, r *http.Request, fullPath string, path str
if *skipHidden && strings.HasPrefix(el.Name(), ".") {
continue // dont print hidden files if we're not allowed
}
if *symlinks && info.Mode()&os.ModeSymlink != 0 {
if !*symlinks && info.Mode()&os.ModeSymlink != 0 {
continue // dont follow symlinks if we're not allowed
}
@@ -126,7 +133,7 @@ func replyList(w http.ResponseWriter, r *http.Request, fullPath string, path str
} else {
sl := strings.Split(name, ".")
ext := strings.ToLower(sl[len(sl)-1])
row := rowTemplate{name, template.URL(href), humanize(info.Size()), ext}
row := rowTemplate{name, template.URL(href), humanize(el.Size()), ext}
p.RowsFiles = append(p.RowsFiles, row)
}
}
@@ -226,21 +233,42 @@ func zipRPC(w http.ResponseWriter, r *http.Request) {
func rpc(w http.ResponseWriter, r *http.Request) {
var err error
var rpc rpcCall
defer exitPath(w, "rpc", rpc)
defer exitPath(w, "rpc", &rpc)
bodyBytes, err := io.ReadAll(r.Body)
check(err)
json.Unmarshal(bodyBytes, &rpc)
ret := []byte("ok")
if rpc.Call == "mkdirp" {
switch rpc.Call {
case "mkdirp":
err = os.MkdirAll(enforcePath(rpc.Args[0]), os.ModePerm)
} else if rpc.Call == "mv" {
case "mv":
err = os.Rename(enforcePath(rpc.Args[0]), enforcePath(rpc.Args[1]))
} else if rpc.Call == "rm" {
case "rm":
err = os.RemoveAll(enforcePath(rpc.Args[0]))
case "sum":
file, err := os.Open(enforcePath(rpc.Args[0]))
check(err)
var hash hash.Hash
switch rpc.Args[1] {
case "md5":
hash = md5.New()
case "sha1":
hash = sha1.New()
case "sha256":
hash = sha256.New()
case "sha512":
hash = sha512.New()
}
_, err = io.Copy(hash, file)
check(err)
checksum := hash.Sum(nil)
ret = make([]byte, hex.EncodedLen(len(checksum)))
hex.Encode(ret, checksum)
}
check(err)
w.Write([]byte("ok"))
w.Write(ret)
}
func enforcePath(p string) string {
+7
View File
@@ -238,6 +238,8 @@ func doTestRegular(t *testing.T, url string, testExtra bool) {
hasListing := strings.Contains(body0, `readme.md`)
body1 = get(t, url+"/support/readme.md")
hasReadme := strings.Contains(body1, `the master branch is automatically built and pushed`)
body2 = get(t, url)
hasMainListing := strings.Contains(body2, `href="support">support/</a>`)
if !testExtra && hasReadme {
t.Fatal("error symlink file reached where illegal")
@@ -249,6 +251,11 @@ func doTestRegular(t *testing.T, url string, testExtra bool) {
} else if testExtra && !hasListing {
t.Fatal("error symlink folder unreachable")
}
if !testExtra && hasMainListing {
t.Fatal("error symlink folder where illegal")
} else if testExtra && !hasMainListing {
t.Fatal("error symlink folder unreachable")
}
if testExtra {
fmt.Println("\r\n~~~~~~~~~~ test symlink mkdir & cleanup")
+2 -1
View File
@@ -1,4 +1,5 @@
FROM golang:1.23.0 as builder
FROM docker.io/library/golang:1.23.0-alpine AS builder
RUN apk add --no-cache make
WORKDIR /gossaSrc
COPY . /gossaSrc
RUN make
+89 -25
View File
@@ -160,6 +160,7 @@ function rpc (call, args, cb) {
const mkdirCall = (path, cb) => rpc('mkdirp', [prependPath(path)], cb)
const rmCall = (path1, cb) => rpc('rm', [prependPath(path1)], cb)
const mvCall = (path1, path2, cb) => rpc('mv', [path1, path2], cb)
const sumCall = (path, type, cb) => rpc('sum', [prependPath(path), type], cb)
// File upload
let totalDone = 0
@@ -383,7 +384,7 @@ function resetView () {
scrollToArrow()
}
window.quitAll = () => helpOff() || picsOff() || videosOff() || padOff() || pdfOff()
window.quitAll = () => helpOff() || sumsOff() || picsOff() || videosOff() || padOff() || pdfOff()
// Mkdir icon
window.mkdirBtn = function () {
@@ -659,6 +660,40 @@ function helpOff () {
return true
}
// checksums
function getSum (type) {
upBarPc.style.display = 'block'
upBarPc.innerText = 'computing checksum...'
upBarPc.style.width = '100%'
sumsOff()
sumCall(getASelected().innerText, type, loaded => {
navigator.clipboard.writeText(loaded.target.responseText)
upBarPc.style.display = 'none'
flicker(okBadge)
})
}
const isSumsMode = () => sums.style.display === 'block'
const sumsToggle = () => isSumsMode() ? sumsOff() : sumsOn()
function sumsOn () {
if (isFolder(getASelected())) {
alert('cannot checksum a directory')
return
}
sums.style.display = 'block'
table.style.display = 'none'
}
window.sumsOff = sumsOff
function sumsOff () {
if (!isSumsMode()) return
sums.style.display = 'none'
table.style.display = 'table'
return true
}
// Paste handler
const cuts = []
function onPaste () {
@@ -749,40 +784,69 @@ document.body.addEventListener('keydown', e => {
return
}
// Ctrl keys
if ((e.ctrlKey || e.metaKey) && !e.shiftKey) {
switch (e.code) {
case 'KeyC':
return prevent(e) || isRo() || cpPath()
// Modifier keys
if (!e.shiftKey) {
if (e.ctrlKey || e.metaKey) {
switch (e.code) {
case 'KeyC':
return prevent(e) || isRo() || cpPath()
case 'KeyH':
return prevent(e) || isRo() || helpToggle()
case 'KeyH':
return prevent(e) || isRo() || helpToggle()
case 'KeyX':
return prevent(e) || isRo() || onCut()
case 'KeyZ':
return prevent(e) || isRo() || sumsToggle()
case 'KeyR':
return prevent(e) || refresh()
case 'KeyX':
return prevent(e) || isRo() || onCut()
case 'KeyV':
return prevent(e) || isRo() || ensureMove() || onPaste()
case 'KeyR':
return prevent(e) || refresh()
case 'Backspace':
return prevent(e) || isRo() || window.rm(e)
case 'KeyV':
return prevent(e) || isRo() || ensureMove() || onPaste()
case 'KeyE':
return prevent(e) || isRo() || window.rename(e)
case 'Backspace':
return prevent(e) || isRo() || window.rm(e)
case 'KeyM':
return prevent(e) || isRo() || window.mkdirBtn()
case 'KeyE':
return prevent(e) || isRo() || window.rename(e)
case 'KeyU':
return prevent(e) || isRo() || manualUpload.click()
case 'KeyM':
return prevent(e) || isRo() || window.mkdirBtn()
case 'Enter':
case 'ArrowRight':
return prevent(e) || dl(getASelected())
case 'KeyU':
return prevent(e) || isRo() || manualUpload.click()
case 'Enter':
case 'ArrowRight':
return prevent(e) || dl(getASelected())
}
} else if (isSumsMode()) {
switch (e.code) {
case 'Digit1':
return prevent(e) || isRo() || getSum('sha1')
case 'Digit2':
return prevent(e) || isRo() || getSum('sha256')
case 'Digit3':
return prevent(e) || isRo() || getSum('sha512')
case 'Digit5':
return prevent(e) || isRo() || getSum('md5')
}
}
} else {
// Workaround Firefox requirement for transient activation
// https://developer.mozilla.org/en-US/docs/Web/Security/User_activation
// Firefox requires user interaction (that is not reserved by the user agent)
// before a file picker can be displayed. This means that ctrl/meta are not
// usable as modifiers until the user clicks the page or presses another
// non-modifier key. To work around this, the shift key can be used, instead.
if (e.code == 'KeyU') {
return prevent(e) || isRo() || manualUpload.click()
}
}
switch (e.code) {
+6 -8
View File
@@ -344,12 +344,8 @@ h1 > span:hover {
right: 30px;
}
#helpHead {
margin-top: 60px;
text-align: center;
}
#helpTable {
#helpTable,
#sumsTable {
border-collapse: collapse;
width: 70%;
max-width: 790px;
@@ -360,7 +356,8 @@ h1 > span:hover {
overflow-y: auto;
}
#helpTable td {
#helpTable td,
#sumsTable td {
width: 200px;
padding: 9px;
border: 1px solid #fff;
@@ -369,7 +366,8 @@ h1 > span:hover {
margin: 0;
}
#help {
#help,
#sums {
background-color: black;
position: absolute;
top: 0px;
Vendored
+12 -3
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta name="theme-color" content="rgb(45,52,54)">
<meta name="msapplication-navbutton-color" content="rgb(45,52,54)">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width">
<link rel="manifest" href='data:application/manifest+json,{"name":"{{.Title}}","short_name":"{{.Title}}","description":" ","icons":[{"src":"data:image/svg+xml;base64,favicon_will_be_here","sizes":"150x150","type":"image/svg+xml"}],"background":"rgb(45,52,54)","theme_color":"rgb(45,52,54)","display":"standalone"}' />
@@ -26,10 +26,11 @@
<tr><td>Ctrl/Meta + C</td><td>copy URL to clipboard</td></tr>
<tr><td>Ctrl/Meta + E</td><td>rename item</td></tr>
<tr><td>Ctrl/Meta + Backspace</td><td>delete item</td></tr>
<tr><td>Ctrl/Meta + U</td><td>upload new file/folder</td></tr>
<tr><td>Ctrl/Meta/Shift + U</td><td>upload new file/folder</td></tr>
<tr><td>Ctrl/Meta + M</td><td>create a new directory</td></tr>
<tr><td>Ctrl/Meta + X</td><td>cut selected path</td></tr>
<tr><td>Ctrl/Meta + V</td><td>paste previously selected paths to directory</td></tr>
<tr><td>Ctrl/Meta + Z</td><td>copy checksums of selected file</td></tr>
<tr><td>Ctrl + click</td><td>download selected item as archive</td></tr>
<tr><td>click file icon </td><td>rename item</td></tr>
<tr><td>double click file icon</td><td>delete item</td></tr>
@@ -38,10 +39,18 @@
<tr><td>any other letter</td><td>fuzzy search</td></tr>
</tbody></table></div>
<div onclick="window.sumsOff()" style="display: none;" id="sums"><table id="sumsTable"><tbody>
<tr><td>Key</td><td>Hash Algorithm</td></tr>
<tr><td>1</td><td>copy sha1 sum</td></tr>
<tr><td>2</td><td>copy sha256 sum</td></tr>
<tr><td>3</td><td>copy sha512 sum</td></tr>
<tr><td>5</td><td>copy md5 sum</td></tr>
</tbody></table></div>
<div style="display: none;" onclick="window.quitAll()" id="quitAll"><i style="display: none;" id="toast">cant reach server</i></div>
<textarea style="display: none;" id="text-editor"></textarea>
<div id="drop-grid"></div>
<input type="file" id="clickupload" style="display:none"/>
<input type="file" id="clickupload" multiple style="display:none"/>
<h1 onclick="return titleClick(event)">.{{.Title}}</h1>