Compare commits

...

10 Commits

Author SHA1 Message Date
80497fb2a8 build: add on-commit github action
Some checks are pending
build abyss / build (amd64, linux) (push) Waiting to run
build abyss / build (arm64, linux) (push) Waiting to run
build abyss / build (ppc64le, linux) (push) Waiting to run
build abyss / build (riscv64, linux) (push) Waiting to run
2024-09-03 22:26:00 -03:00
da544e8176 docs: change running instructions
program now reads from .env, so, we can change the way of running and
simplify it
2024-09-03 22:04:31 -03:00
7e512671a8 ops: update docker files 2024-09-03 21:54:21 -03:00
04fc379479 feat: easier setup and more transparent customization 2024-09-03 21:53:26 -03:00
Lucas Barbieri
2431f5e655 docs: fix documentation on running the webserver 2024-08-25 23:21:17 -03:00
Lucas Barbieri
acd9b90042 feat: remove /upload and just use / 2024-08-25 23:17:20 -03:00
Lucas Barbieri
84565a5a1a refactor: split into multiple files 2024-08-25 23:17:20 -03:00
Lucas Barbieri
0962cf19bf chore: update gitignore to dont track binary 2024-08-25 23:17:20 -03:00
jabuxas
43ce66b444
fix: update release.yml 2024-08-20 10:51:28 -03:00
jabuxas
b578f6bfcc
feat: update workflow file 2024-08-20 10:47:51 -03:00
12 changed files with 265 additions and 104 deletions

37
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,37 @@
name: build abyss
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux]
goarch: [amd64, arm64, riscv64, ppc64le]
steps:
- name: checkout code
uses: actions/checkout@v4
- name: set up go
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: build for ${{ matrix.goarch }}
run: |
export CGO_ENABLED=0
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -a -ldflags '-extldflags "-static"' -o abyss-${{ matrix.goarch }}
- name: upload binaries
uses: actions/upload-artifact@v4
with:
name: abyss-${{ matrix.goarch }}
path: abyss-${{ matrix.goarch }}

View File

@ -1,28 +0,0 @@
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Go
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.23'
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...

89
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,89 @@
# .github/workflows/release.yaml
on: release
name: Build Release
jobs:
release-linux-386:
name: release linux/386
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: "386"
GOOS: linux
EXTRA_FILES: "README.md LICENSE"
release-linux-amd64:
name: release linux/amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: amd64
GOOS: linux
EXTRA_FILES: "README.md LICENSE"
release-linux-arm:
name: release linux/386
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: "arm"
GOOS: linux
EXTRA_FILES: "README.md LICENSE"
release-linux-arm64:
name: release linux/amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: arm64
GOOS: linux
EXTRA_FILES: "README.md LICENSE"
release-darwin-amd64:
name: release darwin/amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: amd64
GOOS: darwin
EXTRA_FILES: "README.md LICENSE"
release-windows-386:
name: release windows/386
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: "386"
GOOS: windows
EXTRA_FILES: "README.md LICENSE"
release-windows-amd64:
name: release windows/amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: compile and release
uses: ngs/go-release.action@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: amd64
GOOS: windows
EXTRA_FILES: "README.md LICENSE"

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
files/
.key
abyss
.env

View File

@ -2,7 +2,7 @@ FROM golang:1.23
WORKDIR /app
# COPY go.mod go.sum ./
COPY go.mod go.sum ./
COPY go.mod ./
RUN go mod download

View File

@ -1,45 +1,61 @@
# abyss
abyss is a basic single user http server made for uploading files (logs, images) and then sharing them to the internet
note: this is a project made for learning purposes, you should use other more mature projects if running in production
note: this is a project made for learning purposes, you should use other more mature projects if running in production. probably.
## table of contents
- [running abyss](#running)
- [installing with docker](#docker)
- [installing manually](#manual)
- [uploading files](#uploading)
- [docs](#docs)
- [todo list](#todo)
## running:
- change URL environment variable to your end url. example: `URL=paste.abyss.dev` if you your files will be accessed through `paste.abyss.dev/name-of-file`
- add your password (key) to `.key` in the root directory of the project - it will be used for authentication for uploads.
- add AUTH_USERNAME and AUTH_PASSWORD environment variables for access to `/tree/`
- run `./generate_config.sh` to setup the necessary environment variables
### docker
- to run with docker, you can use docker compose:
```bash
docker compose up -d # might be docker-compose depending on distro
```
- dont change inside port of 8080 unless you know what you're doing
- dont change inside port of 8999 unless you know what you're doing
- when updating, run with `--build` instead:
```bash
docker compose up --build -d
```
### manual
- to run it, either build with `go build -o abyss` or run it directly with:
- to run it manually, build it with `go build -o abyss` and run:
```bash
URL="your-domain" AUTH_USERNAME=admin AUTH_PASSWORD=admin go run ./main.go
./abyss
```
## uploading
- then, simply upload your files with curl:
```bash
curl -F "file=@/path/to/file" -H "X-Auth: "$(cat /path/to/.key) http://localhost:8080/upload
curl -F "file=@/path/to/file" -H "X-Auth: "$(cat /path/to/.key) http://localhost:8999/
```
## docs
- `ABYSS_URL`: this is used for the correct formatting of the response of `curl`.
- `AUTH_USERNAME | AUTH_PASSWORD`: this is used to access `http://localhost:8999/tree`, which shows all uploaded files
- `UPLOAD_KEY`: this is key checked when uploading files. if the key doesn't match with server's one, then it refuses uploading.
## todo:
- [x] add upload of logs funcionality (like 0x0.st)
- [x] add docker easy setup
- ~~add db for tracking of file names~~ (dont need that)

55
abyss.go Normal file
View File

@ -0,0 +1,55 @@
package main
import (
"log"
"net/http"
"os"
"time"
"github.com/joho/godotenv"
)
const (
filesDir = "./files"
port = ":8999"
)
func main() {
app := new(Application)
godotenv.Load()
app.auth.username = os.Getenv("AUTH_USERNAME")
app.auth.password = os.Getenv("AUTH_PASSWORD")
app.url = os.Getenv("ABYSS_URL")
app.key = os.Getenv("UPLOAD_KEY")
if app.auth.username == "" {
log.Fatal("basic auth username must be provided")
}
if app.auth.password == "" {
log.Fatal("basic auth password must be provided")
}
mux := http.NewServeMux()
mux.HandleFunc("/", app.fileHandler)
mux.HandleFunc(
"/tree/",
app.basicAuth(app.treeHandler),
)
srv := &http.Server{
Addr: port,
Handler: mux,
IdleTimeout: time.Minute,
ReadTimeout: 10 * time.Second,
WriteTimeout: 60 * time.Second,
}
log.Printf("starting server on %s", srv.Addr)
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}

View File

@ -1,13 +1,10 @@
services:
paste:
environment:
URL: "localhost:58080"
AUTH_USERNAME: "admin"
AUTH_PASSWORD: "admin"
build: .
ports:
- "58080:8080"
- "58080:8999"
volumes:
- ./files:/app/files
- ./.key:/app/.key
restart: unless-stopped
env_file:
- .env

31
generate_config.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/sh
echo "Press enter to use the default value '[value]' or use a custom value"
read -p "Server domain name - this is the end url of where abyss will be hosted []: " -e ABYSS_URL
read -p "Upload key - this is the key you will need to have to be able to make uploads to the server []: " -e UPLOAD_KEY
read -p "Auth username - this is the username to access /tree (show all uploaded files) [admin]: " -e AUTH_USERNAME
if [ -z $AUTH_USERNAME ]; then
AUTH_USERNAME="admin"
fi
read -p "Auth password - this is the password to access /tree (show all uploaded files) [admin]: " -e AUTH_PASSWORD
if [ -z $AUTH_PASSWORD ]; then
AUTH_PASSWORD="admin"
fi
cat << EOF > .env
# This is the full name of the final domain for the server. Example: paste.abyss.dev
ABYSS_URL=$ABYSS_URL
# This is the username of the user for accessing /tree
AUTH_USERNAME=$AUTH_USERNAME
# This is the password of the user for accessing /tree
AUTH_PASSWORD=$AUTH_PASSWORD
# This is the key needed to make uploads. Include it as X-Auth in curl.
# Tip: Save it somewhere and use it in curl with \$(cat /path/to/key)
UPLOAD_KEY=$UPLOAD_KEY
EOF

2
go.mod
View File

@ -1,3 +1,5 @@
module github.com/jabuxas/abyss
go 1.22.6
require github.com/joho/godotenv v1.5.1

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=

View File

@ -5,69 +5,27 @@ import (
"crypto/subtle"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"time"
)
const (
filesDir = "./files"
port = ":8080"
)
type application struct {
type Application struct {
auth struct {
username string
password string
}
url string
key string
}
func main() {
app := new(application)
app.auth.username = os.Getenv("AUTH_USERNAME")
app.auth.password = os.Getenv("AUTH_PASSWORD")
app.url = os.Getenv("URL")
if app.auth.username == "" {
log.Fatal("basic auth username must be provided")
func (app *Application) fileHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
app.uploadHandler(w, r)
return
}
if app.auth.password == "" {
log.Fatal("basic auth password must be provided")
}
mux := http.NewServeMux()
mux.HandleFunc("/", app.fileHandler)
mux.HandleFunc(
"/tree/",
app.basicAuth(app.treeHandler),
)
mux.HandleFunc("/upload", app.uploadHandler)
srv := &http.Server{
Addr: port,
Handler: mux,
IdleTimeout: time.Minute,
ReadTimeout: 10 * time.Second,
WriteTimeout: 60 * time.Second,
}
log.Printf("starting server on %s", srv.Addr)
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
func (app *application) treeHandler(w http.ResponseWriter, r *http.Request) {
http.StripPrefix("/tree/", http.FileServer(http.Dir(filesDir))).ServeHTTP(w, r)
}
func (app *application) fileHandler(w http.ResponseWriter, r *http.Request) {
name := filepath.Clean(r.URL.Path)
path := filepath.Join(filesDir, name)
@ -83,12 +41,17 @@ func (app *application) fileHandler(w http.ResponseWriter, r *http.Request) {
}
}
func (app *application) uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
func (app *Application) treeHandler(w http.ResponseWriter, r *http.Request) {
http.StripPrefix("/tree/", http.FileServer(http.Dir(filesDir))).ServeHTTP(w, r)
}
func (app *Application) uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.Error(w, "Method not allowed", http.StatusUnauthorized)
return
}
if !checkAuth(w, r) {
if !app.checkAuth(r) {
http.Error(w, "You're not authorized.", http.StatusBadRequest)
return
}
@ -129,15 +92,11 @@ func (app *application) uploadHandler(w http.ResponseWriter, r *http.Request) {
}
}
func checkAuth(w http.ResponseWriter, r *http.Request) bool {
authKey, err := os.ReadFile(".key")
if err != nil {
http.Error(w, "Couldn't find your .key", http.StatusNotFound)
}
return r.Header.Get("X-Auth")+"\n" == string(authKey)
func (app *Application) checkAuth(r *http.Request) bool {
return r.Header.Get("X-Auth") == string(app.key)
}
func (app *application) basicAuth(next http.HandlerFunc) http.HandlerFunc {
func (app *Application) basicAuth(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if ok {