init
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
FROM golang:1.17 as go
|
||||
|
||||
COPY xseld /xseld
|
||||
|
||||
COPY fileserver /fileserver
|
||||
|
||||
RUN \
|
||||
apt-get update && \
|
||||
apt-get install -y upx-ucl libx11-dev && \
|
||||
cd /xseld && \
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
|
||||
upx /xseld/xseld && \
|
||||
cd /fileserver && \
|
||||
go test -race && \
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" && \
|
||||
upx /fileserver/fileserver
|
||||
|
||||
FROM ubuntu:20.04
|
||||
|
||||
RUN \
|
||||
apt update && \
|
||||
apt remove -y libcurl4 && \
|
||||
apt install -y apt-transport-https ca-certificates tzdata locales libcurl4 curl gnupg && \
|
||||
DEBIAN_FRONTEND=noninteractive apt -y upgrade && \
|
||||
echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections && \
|
||||
echo 'UTC' | tee /etc/timezone && \
|
||||
dpkg-reconfigure -f noninteractive tzdata && \
|
||||
echo "gtk-cursor-blink=0" > /root/.gtkrc-2.0 && \
|
||||
apt update && \
|
||||
apt install -y ttf-mscorefonts-installer \
|
||||
ttf-dejavu-core \
|
||||
fontconfig \
|
||||
fontconfig-config \
|
||||
fonts-dejavu-core \
|
||||
fonts-liberation \
|
||||
fonts-ubuntu-font-family-console \
|
||||
fonts-wqy-zenhei \
|
||||
fonts-thai-tlwg-ttf \
|
||||
fonts-ipafont-mincho \
|
||||
fonts-sahadeva \
|
||||
fonts-noto-unhinted \
|
||||
fonts-noto-color-emoji \
|
||||
libfontconfig1 \
|
||||
libfontenc1 \
|
||||
libfreetype6 \
|
||||
libxfont2 \
|
||||
libxft2 \
|
||||
libnss3-tools \
|
||||
xfonts-base \
|
||||
xfonts-encodings \
|
||||
xfonts-utils \
|
||||
flashplugin-installer \
|
||||
xvfb \
|
||||
pulseaudio \
|
||||
fluxbox \
|
||||
x11vnc \
|
||||
feh \
|
||||
wmctrl \
|
||||
libnss-wrapper \
|
||||
xsel && \
|
||||
mkdir -p /var/lib/locales/supported.d/ && grep UTF-8 /usr/share/i18n/SUPPORTED > /var/lib/locales/supported.d/all && \
|
||||
locale-gen && update-locale && \
|
||||
fc-cache -f -v && \
|
||||
adduser --system --home /home/selenium --uid 4096 \
|
||||
--ingroup root --disabled-password --shell /bin/bash selenium && \
|
||||
mkdir -p /home/selenium/Downloads && \
|
||||
mkdir -p /home/selenium/.fluxbox && \
|
||||
chgrp -R 0 /home/selenium && \
|
||||
chmod -R g=u /home/selenium && \
|
||||
ln -sf /bin/true /usr/bin/xdg-open && \
|
||||
apt-get clean && \
|
||||
rm -Rf /tmp/* && rm -Rf /var/lib/apt/lists/*
|
||||
|
||||
COPY fluxbox /usr/share/fluxbox/styles/
|
||||
COPY --chown=selenium:root fluxbox /home/selenium/.fluxbox/
|
||||
COPY aerokube.png /usr/share/images/fluxbox/
|
||||
|
||||
COPY --from=go /fileserver/fileserver /usr/bin/
|
||||
COPY --from=go /xseld/xseld /usr/bin/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@@ -0,0 +1,5 @@
|
||||
module fileserver
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e
|
||||
@@ -0,0 +1,2 @@
|
||||
github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e h1:ogUKYFNcdYUIBSLibE4+EjbTJazoHr5JsWWx21Lpn8c=
|
||||
github.com/aandryashin/matchers v0.0.0-20161126170413-435295ea180e/go.mod h1:cbmYNkm9xeQlNoWEPtOUcvNok2gSD7ErMnYkRW+eHi8=
|
||||
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dir, err := downloadsDir()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Fatal(http.ListenAndServe(":8080", mux(dir)))
|
||||
}
|
||||
|
||||
func downloadsDir() (string, error) {
|
||||
homeDir := os.Getenv("HOME")
|
||||
if homeDir == "" {
|
||||
homeDir = "/home/selenium"
|
||||
}
|
||||
dir := filepath.Join(homeDir, "Downloads")
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create downloads dir: %v", err)
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
const jsonParam = "json"
|
||||
|
||||
func mux(dir string) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodDelete {
|
||||
deleteFileIfExists(w, r, dir)
|
||||
return
|
||||
}
|
||||
if _, ok := r.URL.Query()[jsonParam]; ok {
|
||||
listFilesAsJson(w, dir)
|
||||
return
|
||||
}
|
||||
http.FileServer(http.Dir(dir)).ServeHTTP(w, r)
|
||||
})
|
||||
return mux
|
||||
}
|
||||
|
||||
func listFilesAsJson(w http.ResponseWriter, dir string) {
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].ModTime().After(files[j].ModTime())
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
ret := []string{}
|
||||
for _, f := range files {
|
||||
ret = append(ret, f.Name())
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(ret)
|
||||
}
|
||||
|
||||
func deleteFileIfExists(w http.ResponseWriter, r *http.Request, dir string) {
|
||||
fileName := strings.TrimPrefix(r.URL.Path, "/")
|
||||
filePath := filepath.Join(dir, fileName)
|
||||
_, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Unknown file %s", fileName), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
err = os.Remove(filePath)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to delete file %s: %v", fileName, err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
. "github.com/aandryashin/matchers"
|
||||
. "github.com/aandryashin/matchers/httpresp"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
dir string
|
||||
srv *httptest.Server
|
||||
)
|
||||
|
||||
func init() {
|
||||
dir, _ = ioutil.TempDir("", "fileserver")
|
||||
srv = httptest.NewServer(mux(dir))
|
||||
}
|
||||
|
||||
func withUrl(path string) string {
|
||||
return srv.URL + path
|
||||
}
|
||||
|
||||
func TestDownloadAndRemoveFile(t *testing.T) {
|
||||
tempFile, _ := ioutil.TempFile(dir, "fileserver")
|
||||
ioutil.WriteFile(tempFile.Name(), []byte("test-data"), 0644)
|
||||
tempFileName := filepath.Base(tempFile.Name())
|
||||
resp, err := http.Get(withUrl("/" + tempFileName))
|
||||
AssertThat(t, err, Is{nil})
|
||||
AssertThat(t, resp, Code{200})
|
||||
_, err = os.Stat(tempFile.Name())
|
||||
AssertThat(t, err, Is{nil})
|
||||
|
||||
rsp, err := http.Get(withUrl("/?json"))
|
||||
AssertThat(t, err, Is{nil})
|
||||
AssertThat(t, rsp, Code{http.StatusOK})
|
||||
var files []string
|
||||
AssertThat(t, rsp, IsJson{&files})
|
||||
AssertThat(t, files, EqualTo{[]string{tempFileName}})
|
||||
|
||||
req, _ := http.NewRequest(http.MethodDelete, withUrl("/" + tempFileName), nil)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
AssertThat(t, err, Is{nil})
|
||||
AssertThat(t, resp, Code{200})
|
||||
_, err = os.Stat(tempFile.Name())
|
||||
AssertThat(t, err, Not{nil})
|
||||
}
|
||||
|
||||
func TestRemoveMissingFile(t *testing.T) {
|
||||
req, _ := http.NewRequest(http.MethodDelete, withUrl("/missing-file"), nil)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
AssertThat(t, err, Is{nil})
|
||||
AssertThat(t, resp, Code{404})
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
###############################################################################
|
||||
#
|
||||
# name: aerokube (based on ubuntu_light)
|
||||
# made: paultag
|
||||
# date: 16-10-2010
|
||||
# http://pault.ag/
|
||||
#
|
||||
############################################################## BACKGROUND ######
|
||||
|
||||
# background: flat
|
||||
# background.color: #2c001e
|
||||
# background.colorTo: #2c001e
|
||||
|
||||
background: fullscreen
|
||||
background.pixmap: /usr/share/images/fluxbox/aerokube.png
|
||||
|
||||
############################################################## FONTS ##########
|
||||
|
||||
|
||||
menu.frame.font: Ubuntu-10:bold
|
||||
menu.title.font: Ubuntu-12:bold
|
||||
toolbar.clock.font: Ubuntu-10:bold
|
||||
toolbar.workspace.font: Ubuntu-12:bold
|
||||
toolbar.iconbar.focused.font: Ubuntu-10:bold
|
||||
toolbar.iconbar.unfocused.font: Ubuntu-10
|
||||
window.font: Ubuntu-10
|
||||
|
||||
############################################################## MENU ###########
|
||||
|
||||
menu.bevelWidth: 1
|
||||
|
||||
#menu.itemHeight: 35
|
||||
#menu.titleHeight: 21
|
||||
menu.borderColor: #525252
|
||||
menu.borderWidth: 1
|
||||
|
||||
menu.bullet: Triangle
|
||||
menu.bullet.position: Right
|
||||
menu.frame.underlineColor: #ffffff
|
||||
|
||||
menu.title: flat gradient rectangle
|
||||
menu.title.justify: center
|
||||
menu.title.color: #FFFFFF
|
||||
menu.title.colorTo: #FFFFFF
|
||||
menu.title.textColor: #333333
|
||||
|
||||
menu.frame: flat gradient crossdiagonal
|
||||
menu.frame.justify: left
|
||||
menu.frame.color: #FFFFFF
|
||||
menu.frame.colorTo: #FFFFFF
|
||||
menu.frame.textColor: #333333
|
||||
menu.frame.disableColor: #aea79f
|
||||
|
||||
menu.hilite: flat gradient rectangle
|
||||
menu.hilite.color: #aea79f
|
||||
menu.hilite.colorTo: #aea79f
|
||||
menu.hilite.textColor: #000000
|
||||
|
||||
############################################################## TOOLBAR ########
|
||||
|
||||
toolbar.bevelWidth: 0
|
||||
|
||||
toolbar.borderWidth: 1
|
||||
toolbar.borderColor: #aea79f
|
||||
|
||||
toolbar.height: 20
|
||||
|
||||
toolbar.justify: center
|
||||
|
||||
toolbar: flat gradient rectangle
|
||||
toolbar.pixmap:
|
||||
toolbar.color: #aea79f
|
||||
toolbar.colorTo: #aea79f
|
||||
|
||||
toolbar.clock: parentrelative
|
||||
toolbar.clock.justify: center
|
||||
toolbar.clock.color: #
|
||||
toolbar.clock.colorTo: #
|
||||
toolbar.clock.textColor: #333333
|
||||
|
||||
toolbar.workspace: parentrelative
|
||||
toolbar.workspace.justify: Center
|
||||
toolbar.workspace.color: #
|
||||
toolbar.workspace.colorTo: #
|
||||
toolbar.workspace.textColor: #333333
|
||||
|
||||
toolbar.button: parentrelative
|
||||
toolbar.button.color: #333333
|
||||
toolbar.button.colorTo: #333333
|
||||
toolbar.button.picColor: #333333
|
||||
toolbar.button.pressed: parentrelative
|
||||
toolbar.button.pressed.color: #aea79f
|
||||
toolbar.button.pressed.colorTo: #aea79f
|
||||
toolbar.button.pressed.picColor: #000000
|
||||
|
||||
toolbar.iconbar.borderWidth: 1
|
||||
toolbar.iconbar.borderColor: #333333
|
||||
|
||||
toolbar.iconbar.empty: parentrelative
|
||||
toolbar.iconbar.empty.color: #
|
||||
toolbar.iconbar.empty.colorTo: #
|
||||
|
||||
toolbar.iconbar.focused.borderWidth: 1
|
||||
toolbar.iconbar.focused.borderColor: #333333
|
||||
toolbar.iconbar.focused: flat gradient rectangle
|
||||
toolbar.iconbar.focused.color: #FFFFFF
|
||||
toolbar.iconbar.focused.colorTo: #FFFFFF
|
||||
toolbar.iconbar.focused.textColor: #333333
|
||||
toolbar.iconbar.focused.justify: center
|
||||
|
||||
toolbar.iconbar.unfocused.borderWidth: 1
|
||||
toolbar.iconbar.unfocused.borderColor: #525252
|
||||
toolbar.iconbar.unfocused: flat gradient rectangle
|
||||
toolbar.iconbar.unfocused.color: #aea79f
|
||||
toolbar.iconbar.unfocused.colorTo: #aea79f
|
||||
toolbar.iconbar.unfocused.textColor: #444444
|
||||
toolbar.iconbar.unfocused.justify: center
|
||||
|
||||
############################################################## WINDOW #########
|
||||
|
||||
window.roundCorners: TopRight TopLeft
|
||||
window.bevelWidth: 4
|
||||
window.shade: false
|
||||
window.borderWidth: 1
|
||||
window.borderColor: #333333
|
||||
|
||||
window.justify: Center
|
||||
window.title.height: 21
|
||||
|
||||
window.title.focus: flat gradient rectangle
|
||||
window.title.focus.color: #000000
|
||||
window.title.focus.colorTo: #333333
|
||||
window.title.unfocus: flat gradient rectangle
|
||||
window.title.unfocus.color: #111111
|
||||
window.title.unfocus.colorTo: #444444
|
||||
|
||||
window.label.focus: parentrelative
|
||||
window.label.focus.color: #
|
||||
window.label.focus.colorTo: #
|
||||
window.label.focus.textColor: #FFFFFF
|
||||
window.label.unfocus: parentrelative
|
||||
window.label.unfocus.color: #
|
||||
window.label.unfocus.colorTo: #
|
||||
window.label.unfocus.textColor: #aea79f
|
||||
|
||||
window.button.focus: parentrelative
|
||||
window.button.focus.color: #
|
||||
window.button.focus.colorTo: #
|
||||
window.button.focus.picColor: #FFFFFF
|
||||
window.button.unfocus: parentrelative
|
||||
window.button.unfocus.Color: #
|
||||
window.button.unfocus.ColorTo: #
|
||||
window.button.unfocus.picColor: #888888
|
||||
window.button.pressed: parentrelative
|
||||
window.button.pressed.color: #
|
||||
window.button.pressed.colorTo: #
|
||||
window.button.pressed.picColor: #000000
|
||||
|
||||
window.handle.focus: flat
|
||||
window.handle.focus.color: #1f1f1f
|
||||
window.handle.focus.colorTo: #1f1f1f
|
||||
window.handle.unfocus: lat
|
||||
window.handle.unfocus.color: #1f1f1f
|
||||
window.handle.unfocus.colorTo: #1f1f1f
|
||||
window.handleWidth: 2
|
||||
|
||||
window.grip.focus: flat
|
||||
window.grip.focus.color: #525252
|
||||
window.grip.focus.colorTo: #525252
|
||||
window.grip.unfocus: flat
|
||||
window.grip.unfocus.color: #1f1f1f
|
||||
window.grip.unfocus.colorTo: #1f1f1f
|
||||
|
||||
###############################################################################
|
||||
# EOF
|
||||
@@ -0,0 +1,7 @@
|
||||
session.menuFile: ~/.fluxbox/menu
|
||||
session.keyFile: ~/.fluxbox/keys
|
||||
session.styleFile: /usr/share/fluxbox/styles/aerokube
|
||||
session.configVersion: 13
|
||||
session.screen0.strftimeFormat: %d %b, %a %02k:%M:%S
|
||||
session.screen0.toolbar.visible: false
|
||||
session.screen0.toolbar.tools:
|
||||
@@ -0,0 +1,3 @@
|
||||
module xseld
|
||||
|
||||
go 1.17
|
||||
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
cmd := exec.Command("xsel", "-b")
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
cmd.Args = append(cmd.Args, "-o")
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
go io.Copy(w, stdout)
|
||||
case http.MethodPost:
|
||||
cmd.Args = append(cmd.Args, "-i")
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
defer stdin.Close()
|
||||
io.Copy(stdin, r.Body)
|
||||
}()
|
||||
default:
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
log.Fatal(http.ListenAndServe(":9090", nil))
|
||||
}
|
||||
Reference in New Issue
Block a user