mirror of
https://github.com/pldubouilh/gossa
synced 2025-12-06 00:12:36 +01:00
Compare commits
6 commits
c4d52d7ffb
...
dcb40c7985
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcb40c7985 | ||
|
|
d17040df0b | ||
|
|
1cac56abfa | ||
|
|
ad423948cc | ||
|
|
da7f84f5c9 | ||
|
|
0400476f0b |
5 changed files with 109 additions and 16 deletions
39
gossa.go
39
gossa.go
|
|
@ -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,10 +233,11 @@ 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")
|
||||
|
||||
switch rpc.Call {
|
||||
case "mkdirp":
|
||||
|
|
@ -238,10 +246,29 @@ func rpc(w http.ResponseWriter, r *http.Request) {
|
|||
err = os.Rename(enforcePath(rpc.Args[0]), enforcePath(rpc.Args[1]))
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
56
ui/script.js
vendored
56
ui/script.js
vendored
|
|
@ -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 () {
|
||||
|
|
@ -582,7 +583,7 @@ picsHolder.addEventListener('touchend', e => {
|
|||
}, false)
|
||||
|
||||
// Video player
|
||||
const videosTypes = ['.mp4', '.webm', '.ogv', '.ogg', '.mp3', '.flac', '.wav']
|
||||
const videosTypes = ['.mkv', '.mp4', '.webm', '.ogv', '.ogg', '.mp3', '.flac', '.wav']
|
||||
const isVideo = src => src && videosTypes.find(type => src.toLocaleLowerCase().includes(type))
|
||||
const isVideoMode = () => video.style.display === 'flex'
|
||||
const videoFs = () => video.requestFullscreen()
|
||||
|
|
@ -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 () {
|
||||
|
|
@ -759,6 +794,9 @@ document.body.addEventListener('keydown', e => {
|
|||
case 'KeyH':
|
||||
return prevent(e) || isRo() || helpToggle()
|
||||
|
||||
case 'KeyZ':
|
||||
return prevent(e) || isRo() || sumsToggle()
|
||||
|
||||
case 'KeyX':
|
||||
return prevent(e) || isRo() || onCut()
|
||||
|
||||
|
|
@ -784,6 +822,20 @@ document.body.addEventListener('keydown', e => {
|
|||
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
|
||||
|
|
|
|||
14
ui/style.css
vendored
14
ui/style.css
vendored
|
|
@ -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;
|
||||
|
|
|
|||
9
ui/ui.tmpl
vendored
9
ui/ui.tmpl
vendored
|
|
@ -30,6 +30,7 @@
|
|||
<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,6 +39,14 @@
|
|||
<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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue