remove remote state

This commit is contained in:
Pierre Dubouilh 2019-12-13 00:45:21 +01:00
parent 5096f46ba4
commit dc1011bb5f
No known key found for this signature in database
GPG key ID: 10E1A7CE67E74C0F
7 changed files with 20 additions and 68 deletions

View file

@ -8,7 +8,7 @@ gossa
[![docker pulls](https://img.shields.io/docker/pulls/pldubouilh/gossa.svg?logo=docker)](https://hub.docker.com/r/pldubouilh/gossa) [![docker pulls](https://img.shields.io/docker/pulls/pldubouilh/gossa.svg?logo=docker)](https://hub.docker.com/r/pldubouilh/gossa)
[![github downloads](https://img.shields.io/github/downloads/pldubouilh/gossa/total.svg?logo=github)](https://github.com/pldubouilh/gossa/releases) [![github downloads](https://img.shields.io/github/downloads/pldubouilh/gossa/total.svg?logo=github)](https://github.com/pldubouilh/gossa/releases)
a fast and simple webserver for your files, that's dependency-free and with 200 lines of code, easy to review. a fast and simple webserver for your files, that's dependency-free and with under 200 lines of code, easy to review.
a [simple UI](https://github.com/pldubouilh/gossa-ui) comes as default, featuring : a [simple UI](https://github.com/pldubouilh/gossa-ui) comes as default, featuring :

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"crypto/sha256"
"encoding/json" "encoding/json"
"errors" "errors"
"flag" "flag"
@ -17,7 +16,6 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync"
) )
var host = flag.String("h", "127.0.0.1", "host to listen to") var host = flag.String("h", "127.0.0.1", "host to listen to")
@ -26,21 +24,17 @@ var history = flag.Bool("history", true, "keep history for paths visited. defaul
var extraPath = flag.String("prefix", "/", "url prefix at which gossa can be reached, e.g. /gossa/ (slashes of importance)") var extraPath = flag.String("prefix", "/", "url prefix at which gossa can be reached, e.g. /gossa/ (slashes of importance)")
var symlinks = flag.Bool("symlinks", false, "follow symlinks \033[4mWARNING\033[0m: symlinks will by nature allow to escape the defined path (default: false)") var symlinks = flag.Bool("symlinks", false, "follow symlinks \033[4mWARNING\033[0m: symlinks will by nature allow to escape the defined path (default: false)")
var verb = flag.Bool("verb", false, "verbosity") var verb = flag.Bool("verb", false, "verbosity")
var skipHidden = flag.Bool("k", true, "skip hidden files") var skipHidden = flag.Bool("k", true, "\nskip hidden files")
var initPath = "." var initPath = "."
var historyPath = ""
var state = make(map[string]string)
var stateLock = sync.RWMutex{}
var fs http.Handler var fs http.Handler
var page, _ = template.New("pageTemplate").Parse(`template_will_be_here`) var page, _ = template.New("pageTemplate").Parse(`template_will_be_here`)
type rowTemplate struct { type rowTemplate struct {
Name string Name string
Href template.HTML Href template.HTML
Size string Size string
Ext string Ext string
Selected bool
} }
type pageTemplate struct { type pageTemplate struct {
@ -61,10 +55,6 @@ func check(e error) {
} }
} }
func hash(s string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(s)))
}
func exitPath(w http.ResponseWriter, s ...interface{}) { func exitPath(w http.ResponseWriter, s ...interface{}) {
if r := recover(); r != nil { if r := recover(); r != nil {
log.Println("error", s, r) log.Println("error", s, r)
@ -97,13 +87,10 @@ func replyList(w http.ResponseWriter, r *http.Request, fullPath string, path str
title := "/" + strings.TrimPrefix(path, *extraPath) title := "/" + strings.TrimPrefix(path, *extraPath)
p := pageTemplate{} p := pageTemplate{}
if path != *extraPath { if path != *extraPath {
p.RowsFolders = append(p.RowsFolders, rowTemplate{"../", "../", "", "folder", false}) p.RowsFolders = append(p.RowsFolders, rowTemplate{"../", "../", "", "folder"})
} }
p.ExtraPath = template.HTML(html.EscapeString(*extraPath)) p.ExtraPath = template.HTML(html.EscapeString(*extraPath))
p.Title = template.HTML(html.EscapeString(title)) p.Title = template.HTML(html.EscapeString(title))
stateLock.Lock()
loc := state[hash(r.Header.Get("Authorization")+path)]
stateLock.Unlock()
for _, el := range _files { for _, el := range _files {
if *skipHidden && strings.HasPrefix(el.Name(), ".") { if *skipHidden && strings.HasPrefix(el.Name(), ".") {
@ -115,10 +102,10 @@ func replyList(w http.ResponseWriter, r *http.Request, fullPath string, path str
href = strings.Replace(href, "/", "", 1) href = strings.Replace(href, "/", "", 1)
} }
if el.IsDir() { if el.IsDir() {
p.RowsFolders = append(p.RowsFolders, rowTemplate{el.Name() + "/", template.HTML(href), "", "folder", loc == hash(el.Name()+"/")}) p.RowsFolders = append(p.RowsFolders, rowTemplate{el.Name() + "/", template.HTML(href), "", "folder"})
} else { } else {
sl := strings.Split(el.Name(), ".") sl := strings.Split(el.Name(), ".")
p.RowsFiles = append(p.RowsFiles, rowTemplate{el.Name(), template.HTML(href), humanize(el.Size()), strings.ToLower(sl[len(sl)-1]), loc == hash(el.Name())}) p.RowsFiles = append(p.RowsFiles, rowTemplate{el.Name(), template.HTML(href), humanize(el.Size()), strings.ToLower(sl[len(sl)-1])})
} }
} }
@ -160,10 +147,7 @@ func rpc(w http.ResponseWriter, r *http.Request) {
bodyBytes, _ := ioutil.ReadAll(r.Body) bodyBytes, _ := ioutil.ReadAll(r.Body)
json.Unmarshal(bodyBytes, &rpc) json.Unmarshal(bodyBytes, &rpc)
defer exitPath(w, "rpc", rpc) defer exitPath(w, "rpc", rpc)
stateLock.Lock()
defer stateLock.Unlock()
ret := "ok" ret := "ok"
key := hash(r.Header.Get("Authorization") + rpc.Args[0])
if rpc.Call == "mkdirp" { if rpc.Call == "mkdirp" {
err = os.MkdirAll(checkPath(rpc.Args[0]), os.ModePerm) err = os.MkdirAll(checkPath(rpc.Args[0]), os.ModePerm)
@ -171,16 +155,6 @@ func rpc(w http.ResponseWriter, r *http.Request) {
err = os.Rename(checkPath(rpc.Args[0]), checkPath(rpc.Args[1])) err = os.Rename(checkPath(rpc.Args[0]), checkPath(rpc.Args[1]))
} else if rpc.Call == "rm" { } else if rpc.Call == "rm" {
err = os.RemoveAll(checkPath(rpc.Args[0])) err = os.RemoveAll(checkPath(rpc.Args[0]))
} else if rpc.Call == "historySet" && *history {
if rpc.Args[2] == "hash" {
state[key] = hash(rpc.Args[1])
} else {
state[key] = rpc.Args[1]
}
f, _ := json.MarshalIndent(state, "", " ")
ioutil.WriteFile(historyPath, f, 0644)
} else if rpc.Call == "historyGet" && *history {
ret = state[key]
} }
check(err) check(err)
@ -205,14 +179,12 @@ func main() {
fmt.Printf("\nusage: ./gossa ~/directory-to-share\n\n") fmt.Printf("\nusage: ./gossa ~/directory-to-share\n\n")
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.Parse() flag.Parse()
if len(flag.Args()) > 0 { if len(flag.Args()) > 0 {
initPath = flag.Args()[0] initPath = flag.Args()[0]
} }
historyPath = filepath.Join(initPath, ".gossa_history")
h, _ := ioutil.ReadFile(historyPath)
_ = json.Unmarshal(h, &state)
initPath, err = filepath.Abs(initPath) initPath, err = filepath.Abs(initPath)
check(err) check(err)

View file

@ -61,7 +61,7 @@ func fetchAndTestDefault(t *testing.T, url string) string {
t.Fatal("error title") t.Fatal("error title")
} }
if !strings.Contains(body0, `<h1>./</h1>`) { if !strings.Contains(body0, `<h1 onclick="return titleClick(event)">./</h1>`) {
t.Fatal("error header") t.Fatal("error header")
} }
@ -163,21 +163,6 @@ func doTest(t *testing.T, url string, testExtra bool) {
t.Fatal("mv rpc errored") t.Fatal("mv rpc errored")
} }
// ~~~~~~~~~~~~~~~~~
// Test where auth header unset, otherwise it'd be apended to the first arg
fmt.Println("\r\n~~~~~~~~~~ test history rpc")
body0 = postJSON(t, url+"rpc", `{"call":"historySet","args":["a", "123", "skipHash"]}`)
body1 = postJSON(t, url+"rpc", `{"call":"historyGet","args":["a"]}`)
if body0 != `ok` || body1 != `123` {
t.Fatal("error history get/set unhashed")
}
body0 = postJSON(t, url+"rpc", `{"call":"historySet","args":["b", "a", "hash"]}`)
body1 = postJSON(t, url+"rpc", `{"call":"historyGet","args":["b"]}`)
if body0 != `ok` || body1 != `ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb` {
t.Fatal("error history get/set hashed")
}
// ~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~
fmt.Println("\r\n~~~~~~~~~~ test upload in new folder") fmt.Println("\r\n~~~~~~~~~~ test upload in new folder")
payload = "test" payload = "test"

View file

@ -1,8 +1,8 @@
# Caddy config # Caddy config
# to enable https just set a valid domain instead of mydomain.com - how simple ! # to enable https just set a valid domain (e.g. mydomain.com) instead of :8080 - how simple !
# authentication has been setup with 2 users, alice and bob # authentication has been setup with 2 users, alice and bob
mydomain.com :8080
basicauth / alice paul basicauth / alice paul
basicauth / bob dylan basicauth / bob dylan
proxy / 127.0.0.1:8001 proxy / 127.0.0.1:8001

View file

@ -3,9 +3,9 @@ COPY . /gossaSrc
RUN cd /gossaSrc && make RUN cd /gossaSrc && make
FROM alpine FROM alpine
ENV UID="1000" GID="1000" HOST="0.0.0.0" PORT="8001" PREFIX="/" HISTORY="true" FOLLOW_SYMLINKS="false" SKIP_HIDDEN_FILES="true" DATADIR="/shared" ENV UID="1000" GID="1000" HOST="0.0.0.0" PORT="8001" PREFIX="/" FOLLOW_SYMLINKS="false" SKIP_HIDDEN_FILES="true" DATADIR="/shared"
EXPOSE 8001 EXPOSE 8001
RUN apk add --no-cache su-exec RUN apk add --no-cache su-exec
COPY --from=builder /gossaSrc/gossa /gossa COPY --from=builder /gossaSrc/gossa /gossa
RUN echo -e 'exec su-exec ${UID}:${GID} /gossa -h ${HOST} -p ${PORT} -k=${SKIP_HIDDEN_FILES} --history=${HISTORY} --symlinks=${FOLLOW_SYMLINKS} --prefix=${PREFIX} ${DATADIR}'>> /start.sh RUN echo -e 'exec su-exec ${UID}:${GID} /gossa -h ${HOST} -p ${PORT} -k=${SKIP_HIDDEN_FILES} --symlinks=${FOLLOW_SYMLINKS} --prefix=${PREFIX} ${DATADIR}'>> /start.sh
ENTRYPOINT [ "sh", "/start.sh" ] ENTRYPOINT [ "sh", "/start.sh" ]

View file

@ -1,13 +1,8 @@
FROM pldubouilh/gossa FROM pldubouilh/gossa
# download and prepare caddy RUN apk update && apk add curl ca-certificates caddy
RUN apk update && apk add curl ca-certificates
RUN curl -L -o caddy.tar.gz "https://github.com/caddyserver/caddy/releases/download/v1.0.3/caddy_v1.0.3_linux_amd64.tar.gz"
RUN tar xvzf caddy.tar.gz && mv caddy /caddy
COPY Caddyfile / ENV UID="1000" GID="1000" HOST="127.0.0.1" PORT="8001" PREFIX="/" FOLLOW_SYMLINKS="false" SKIP_HIDDEN_FILES="true" DATADIR="/shared"
ENV UID="1000" GID="1000" HOST="127.0.0.1" PORT="8001" PREFIX="/" HISTORY="true" FOLLOW_SYMLINKS="false" SKIP_HIDDEN_FILES="true" DATADIR="/shared"
EXPOSE 443 EXPOSE 443
RUN echo -e 'exec su-exec ${UID}:${GID} /gossa -h ${HOST} -p ${PORT} -k=${SKIP_HIDDEN_FILES} --history=${HISTORY} --symlinks=${FOLLOW_SYMLINKS} --prefix=${PREFIX} ${DATADIR} & \n /caddy'>> /start.sh RUN echo -e 'exec su-exec ${UID}:${GID} /gossa -h ${HOST} -p ${PORT} -k=${SKIP_HIDDEN_FILES} --symlinks=${FOLLOW_SYMLINKS} --prefix=${PREFIX} ${DATADIR} & \n caddy' > /start.sh
ENTRYPOINT [ "sh", "/start.sh" ] ENTRYPOINT [ "sh", "/start.sh" ]

View file

@ -15,13 +15,13 @@ if you prefer building the image yourself :
the options are settable through environment variables that can be passed starting off the docker image. the options are settable through environment variables that can be passed starting off the docker image.
a fancy docker image using [Caddy](https://caddyserver.com/) is also provided. a simple config is embedded in the docker file, and shows how to use http basic authentication, and automatic TLS for hands-free https 🎉 a fancy docker image using [Caddy](https://caddyserver.com/) is also provided. have a look at the simple config file `Caddyfile`, it shows how to use http basic authentication, and automatic TLS for hands-free https 🎉
```sh ```sh
# checkout the caddy config, build, and run docker image # checkout the caddy config, build, and run docker image
% vim caddy.Dockerfile % vim caddy.Dockerfile
% docker build -t gossa-caddy -f caddy.Dockerfile . % docker build -t gossa-caddy -f caddy.Dockerfile .
% sudo docker run -v ~/LocalDirToShare:/shared --net=host gossa-caddy % sudo docker run -v ~/LocalDirToShare:/shared -v `pwd`/Caddyfile:/Caddyfile --net=host gossa-caddy
``` ```
a docker-compose example image is also provided. running docker compose should be straightforward : `docker-compose up .` have a look in `docker-compose.yml` for further configuration. a docker-compose example image is also provided. running docker compose should be straightforward : `docker-compose up .` have a look in `docker-compose.yml` for further configuration.