Compare commits

...

10 commits

Author SHA1 Message Date
Felix Niederwanger 0e93e017f3
Merge pull request #45 from grisu48/post
Fix upload not working issue
2022-08-09 16:21:26 +02:00
Felix Niederwanger 9218427a0b
Fix upload not working issue
Fix the issue that the web upload was not working. The issue was coming
from overwriting the multibody reader with r.Body.
2022-08-09 11:22:03 +02:00
Felix Niederwanger fb036c40cc
Merge pull request #43 from grisu48/doc
Improve the deployment documentation
2022-07-01 09:00:25 +02:00
Felix Niederwanger 87820e04cb
Improve the deployment documentation
Include code steps on how to setup pasta and improve the wording.
2022-07-01 08:58:37 +02:00
Felix Niederwanger 3a9c402698
Merge pull request #42 from grisu48/ghcr
Build container in github
2022-07-01 08:47:55 +02:00
Felix Niederwanger ad5bdcfd11
Build container in github
Add a CI for building the container in GitHub and improve the
documentation about using pasta as a container application.
2022-07-01 08:46:13 +02:00
Felix Niederwanger 08c762fa47
Merge pull request #40 from grisu48/fix
Fix the content handling of the input form
2022-07-01 08:29:29 +02:00
Felix Niederwanger 5025670328
Fix the content handling of the input form
Fix the content handling when data is passed via the input form. The
previous handling prevented e.g. curl links by consuming the request
body. Now the request body is only consumed in case of the POST form.

Add also a test to check the `curl` handling of the pasta server.
2022-06-30 16:34:06 +02:00
Felix Niederwanger 0d66b1569b
Merge pull request #37 from grisu48/textbox
Add textarea to index page
2022-04-30 18:04:37 +02:00
Felix Niederwanger 2ee99daf04
Add textarea to index page
Adds a text area to the index page so people can just dump stuff there
without uploading a file.

Bump go version to 1.16 as required by io.NopCloser.
2022-04-30 18:02:44 +02:00
8 changed files with 186 additions and 110 deletions

44
.github/workflows/ghcr.yml vendored Normal file
View file

@ -0,0 +1,44 @@
---
# See https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages
name: Create and publish container
'on':
release:
types: [published]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
github-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View file

@ -15,7 +15,7 @@ jobs:
- name: Setup go
uses: actions/setup-go@v2
with:
go-version: '1.14'
go-version: '1.16'
- name: Install requirements
run: make requirements
- name: Compile binaries

View file

@ -7,10 +7,7 @@ ADD . /app
RUN cd /app && make requirements && make pastad-static
FROM scratch
#RUN mkdir /app
#RUN mkdir /data
WORKDIR /data
COPY --from=build-env /app/pastad /app/pastad
COPY --from=build-env /app/mime.types /app/mime.types
COPY --from=build-env /app/pastad /app/mime.types /app/
ENTRYPOINT ["/app/pastad", "-m", "/app/mime.types", "-c", "/data/pastad.toml"]
VOLUME ["/data"]

View file

@ -22,9 +22,8 @@ test: pastad pasta
# TODO: This syntax is horrible :-)
bash -c 'cd test && ./test.sh'
docker: Dockerfile pasta pastad
container-docker: Dockerfile pasta pastad
docker build . -t feldspaten.org/pasta
deploy: Dockerfile pasta pastad
docker build . -t grisu48/pasta
docker push grisu48/pasta
container-podman: Dockerfile pasta pastad
podman build . -t feldspaten.org/pasta

View file

@ -4,21 +4,49 @@
Stupid simple pastebin service written in go.
Fastest way of deploying is via the [`deploy_pasta.sh`](deploy_pasta.sh) script.
## Run via podman/docker
## Run via docker
The easiest way of self-hosting a `pasta` server is via the provided container from `ghcr.io/grisu48/pasta:latest`. The container runs fine as rootless container. Setup your own `pasta` instance is as easy as:
The easiest way of self-hosting a `pasta` server is via the [docker image](https://hub.docker.com/r/grisu48/pasta/). All you need to do is
* Create your `data` directory (holds config + data)
* Create a [pastad.toml](pastad.toml.example) file therein
* Start the container, mount the `data` directory as `/data` and publish port `8199`
* Configure your reverse proxy (e.g. `nginx`) to forward requests to the `pasta` container
* Create your `data` directory
* Put the [pastad.toml](pastad.toml.example) file there
* Start the container, mount the `data` directory as `/data`
Assuming you want your data directory be e.g. `/srv/pasta`, prepare your server:
Assuming your data is in `/srv/pasta/` you can do
mkdir /srv/pasta
cp pastad.toml.example /srv/pastsa/pastad.toml
$EDITOR /srv/pastsa/pastad.toml # Modify the configuration to your needs
docker container run -d -v /srv/pasta:/data -p 127.0.0.1:8199:8199 grisu48/pasta
And then create and run your container with your preferred container engine:
Configure your reverse proxy (e.g. `nginx`) then accordingly. I don't recomment to publish `pastad` on port 80 without a reverse proxy.
docker container run -d --name pasta -v /srv/pasta:/data -p 127.0.0.1:8199:8199 ghcr.io/grisu48/pasta
podman container run -d --name pasta -v /srv/pasta:/data -p 127.0.0.1:8199:8199 ghcr.io/grisu48/pasta
`pasta` listens here on port 8199 and all you need to do is to configure your reverse proxy (e.g. `nginx`) accordingly:
```nginx
server {
listen 80;
listen [::]:80;
server_name my-awesome-pasta.server;
client_max_body_size 32M;
location / {
proxy_pass http://127.0.0.1:8199/;
}
}
```
Note that the good old [dockerhub image](https://hub.docker.com/r/grisu48/pasta/) is deprecated. It still gets updates but will be removed one fine day.
## Run on openSUSE
We build openSUSE package at [build.opensuse.org](https://build.opensuse.org/package/show/home%3Aph03nix%3Atools/pasta). To install follow the instructions from [software.opensuse.org](https://software.opensuse.org/download/package?package=pasta&project=home%3Aph03nix%3Atools) or the following snippet:
# Tumbleweed
zypper addrepo zypper addrepo https://download.opensuse.org/repositories/home:ph03nix:tools/openSUSE_Tumbleweed/home:ph03nix:tools.repo
zypper refresh && zypper install pasta
## Run on RancherOS
@ -35,14 +63,6 @@ $ sudo mkfs.ext4 /dev/sdb1
$ sudo ros install -d /dev/sda -c cloud-init.yaml
```
## Run on openSUSE
We build openSUSE package at [build.opensuse.org](https://build.opensuse.org/package/show/home%3Aph03nix%3Atools/pasta). To install follow the instructions from [software.opensuse.org](https://software.opensuse.org/download/package?package=pasta&project=home%3Aph03nix%3Atools) or the following snippet:
# Tumbleweed
zypper addrepo zypper addrepo https://download.opensuse.org/repositories/home:ph03nix:tools/openSUSE_Tumbleweed/home:ph03nix:tools.repo
zypper refresh && zypper install pasta
## Build and run from source
make pastad # Server
@ -50,7 +70,7 @@ We build openSUSE package at [build.opensuse.org](https://build.opensuse.org/pac
make # all
make static # static binaries
Then create a `pastad.toml` file using the provided example (`pastad.toml.example`) and run the server with
Create a `pastad.toml` file using the provided example (`pastad.toml.example`) and run the server with
./pastad
@ -93,9 +113,10 @@ Assuing the server runs on http://localhost:8199, you can use the `pasta` tool o
## pasta CLI
`pasta` is the CLI utility for easy handling. For instance, if you want to push the `README.md` file and create a pasta out of it:
`pasta` is the CLI utility for making the creation of a pasta as easy as possible.
For instance, if you want to push the `README.md` file and create a pasta out of it:
pasta README.md
pasta -r http://localhost:8199 REAME.md
pasta -r http://localhost:8199 REAME.md # Define a custom remote server
`pasta` reads the `~/.pasta.toml` file (see the [example file](pasta.toml.example))
`pasta` reads the config from `~/.pasta.toml` (see the [example file](pasta.toml.example))

View file

@ -284,7 +284,7 @@ ServerError:
fmt.Fprintf(w, "server error")
}
func receiveBody(reader io.Reader, pasta *Pasta) error {
func receive(reader io.Reader, pasta *Pasta) error {
buf := make([]byte, 4096)
file, err := os.OpenFile(pasta.Filename, os.O_RDWR|os.O_APPEND, 0640)
if err != nil {
@ -385,19 +385,31 @@ func ReceivePasta(r *http.Request) (Pasta, error) {
}
if isMultipart(r) {
// Close body, also if it's not set as reader
defer r.Body.Close()
reader, err = receiveMultibody(r, &pasta)
if err != nil {
pasta.Id = ""
return pasta, err
}
} else {
// Otherwise the message body is the upload content
reader = r.Body
// Check if the input is coming from the POST form
inputs := r.URL.Query()["input"]
if len(inputs) > 0 && inputs[0] == "form" {
// Copy reader, as r.FromValue consumes it's contents
defer r.Body.Close()
reader = r.Body
if content := r.FormValue("content"); content != "" {
reader = io.NopCloser(strings.NewReader(content))
} else {
pasta.Id = "" // Empty pasta
return pasta, nil
}
} else {
reader = r.Body
}
}
defer reader.Close()
if err := receiveBody(reader, &pasta); err != nil {
if err := receive(reader, &pasta); err != nil {
return pasta, err
}
if pasta.Size >= cf.MaxPastaSize {
@ -526,14 +538,15 @@ func handlerPost(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<!doctype html><html><head><title>pasta</title></head>\n")
fmt.Fprintf(w, "<body>\n")
fmt.Fprintf(w, "<h1>pasta</h1>\n")
fmt.Fprintf(w, "<p><a href=\"%s\">%s</a>", url, url)
if pasta.ExpireDate > 0 {
fmt.Fprintf(w, " (expires %s)", time.Unix(pasta.ExpireDate, 0).Format("2006-01-02-15:04:05"))
}
fmt.Fprintf(w, "</p>\n")
deleteLink := fmt.Sprintf("%s/delete?id=%s&token=%s", cf.BaseUrl, pasta.Id, pasta.Token)
fmt.Fprintf(w, "<p>Accidentally uploaded? <a href=\"%s\">Delete it</a> right away</p>\n", deleteLink)
fmt.Fprintf(w, "<p>Modification token: <code>%s</code></p>\n", pasta.Token)
fmt.Fprintf(w, "<p>Here is your pasta: <a href=\"%s\">%s</a>.<br/>", url, url)
fmt.Fprintf(w, "<a href=\"%s\">Delete</a> it in case you don't want it anymore.</p>\n", deleteLink)
fmt.Fprintf(w, "<pre>")
if pasta.ExpireDate > 0 {
fmt.Fprintf(w, "Expiration: %s\n", time.Unix(pasta.ExpireDate, 0).Format("2006-01-02-15:04:05"))
}
fmt.Fprintf(w, "Modification token: %s\n</pre>\n", pasta.Token)
fmt.Fprintf(w, "<p>That was fun! Let's <a href=\"%s\">upload another one</a>.</p>\n", cf.BaseUrl)
fmt.Fprintf(w, "</body></html>")
} else if retFormat == "json" {
// Dont use json package, the reply is simple enough to build it on-the-fly
@ -628,19 +641,69 @@ func handlerDelete(w http.ResponseWriter, r *http.Request) {
deletePasta(id, token, w)
}
func timeHumanReadable(timestamp int64) string {
if timestamp < 60 {
return fmt.Sprintf("%d s", timestamp)
}
minutes := timestamp / 60
seconds := timestamp - (minutes * 60)
if minutes < 60 {
return fmt.Sprintf("%d:%d min", minutes, seconds)
}
hours := minutes / 60
minutes -= hours * 60
if hours < 24 {
return fmt.Sprintf("%d s", hours)
}
days := hours / 24
hours -= days * 24
if days > 365 {
years := float32(days) / 365.0
return fmt.Sprintf("%.2f years", years)
} else if days > 28 {
weeks := days / 7
if weeks > 4 {
months := days / 30
return fmt.Sprintf("%d months", months)
}
return fmt.Sprintf("%d weeks", weeks)
} else {
return fmt.Sprintf("%d days", days)
}
}
func handlerIndex(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<!doctype html><html><head><title>pasta</title></head>\n")
fmt.Fprintf(w, "<body>\n")
fmt.Fprintf(w, "<h1>pasta</h1>\n")
fmt.Fprintf(w, "<p>Stupid simple pastebin service written in go. Visit the project repo on <a href=\"https://github.com/grisu48/pasta\" target=\"_BLANK\">Github</a>.</p>\n")
fmt.Fprintf(w, "<h3>Post a file</h3>\n")
fmt.Fprintf(w, "<p>Just shove your file via POST request to the main page :</p>")
fmt.Fprintf(w, "<pre>curl -X POST '%s' --data-binary @FILE</pre>\n", cf.BaseUrl)
fmt.Fprintf(w, "<p>Or use the following upload form</p>")
fmt.Fprintf(w, "<p>Stupid simple paste service written in <code>go</code><br/>\n")
fmt.Fprintf(w, "Checkout our fresh CLI utilities in <a href=\"https://github.com/grisu48/pasta/releases/\" target=\"_BLANK\">releases</a> because you are amazing!</p>\n")
fmt.Fprintf(w, "<h2>Post a new and fresh pasta</h2>\n")
fmt.Fprintf(w, "<p>Just POST your file at the server, e.g. ")
fmt.Fprintf(w, "<code>curl -X POST '%s' --data-binary @FILE</code></p>\n", cf.BaseUrl)
if cf.DefaultExpire > 0 {
fmt.Fprintf(w, "<p>pastas expire by default after %s - Enjoy them while they are fresh!</p>\n", timeHumanReadable(cf.DefaultExpire))
}
fmt.Fprintf(w, "<h3>File upload</h3>")
fmt.Fprintf(w, "<p>Upload your file and make a fresh pasta out of it:</p>")
fmt.Fprintf(w, "<form enctype=\"multipart/form-data\" method=\"post\" action=\"/?ret=html\">\n")
fmt.Fprintf(w, "<input type=\"file\" name=\"file\">\n")
fmt.Fprintf(w, "<input type=\"submit\" value=\"Upload\">\n")
fmt.Fprintf(w, "</form>\n")
fmt.Fprintf(w, "<h3>Text paste</h3>")
fmt.Fprintf(w, "<p>Just paste your contents in the textfield and hit the <tt>pasta</tt> button below</p>\n")
fmt.Fprintf(w, "<form method=\"post\" action=\"/?input=form&ret=html\">\n")
if cf.MaxPastaSize > 0 {
fmt.Fprintf(w, "<textarea name=\"content\" rows=\"10\" cols=\"80\" maxlength=\"%d\"></textarea><br/>\n", cf.MaxPastaSize)
} else {
fmt.Fprintf(w, "<textarea name=\"content\" rows=\"10\" cols=\"80\"></textarea><br/>\n")
}
fmt.Fprintf(w, "<input type=\"submit\" value=\"Pasta!\">\n")
fmt.Fprintf(w, "</form>\n")
fmt.Fprintf(w, "<p>project page: <a href=\"https://github.com/grisu48/pasta\" target=\"_BLANK\">github.com/grisu48/pasta</a></p>\n")
fmt.Fprintf(w, "</body></html>")
}

View file

@ -1,61 +0,0 @@
#!/bin/bash
#
# Suggested deploy script for pasta
#
CONTAINER_NAME="pasta" # Name of the container
CONTAINER_MEMORY="64" # Memory limitations for the container in MB
DATA="/srv/pasta" # Data directory for config file and pastas
PORT="8199" # Exposed port of the container
function usage() {
echo "$0 - Simple pasta deployment script"
echo "Usage: $0 [DATADIR] - deploy instance as docker container"
echo " $0 --rm - remove container"
echo ""
echo "OPTIONS"
echo " DATADIR - Directory where data will be stored"
}
if [[ $# -ge 1 ]]; then
DATA="$1"
if [[ $DATA == "-h" || $DATA == "--help" ]]; then
usage
exit 0
fi
fi
if [[ $CONTAINER_NAME != "" ]]; then
docker container stop "$CONTAINER_NAME"
docker container rm "$CONTAINER_NAME"
fi
# Special use case: Remove container
if [[ $DATA == "--rm" ]]; then
exit 0
fi
docker pull grisu48/pasta
# Prepare data directory
mkdir -p "$DATA"
if [[ ! -s "$DATA/pastad.toml" ]]; then
echo "Using default configuration file $DATA/pastad.toml"
cp "pastad.toml.example" "$DATA/pastad.toml"
else
echo "Found existing pastad.toml configuration"
fi
set -e
docker container create --name "$CONTAINER_NAME" -p "$PORT":8199 -v "$DATA" grisu48/pasta
docker update --restart unless-stopped "$CONTAINER_NAME"
if [[ "$CONTAINER_MEMORY" != "" ]]; then
# Update memory, use double the memory as swap
docker update --memory "${CONTAINER_MEMORY}M" --memory-swap "$(($CONTAINER_MEMORY * 2))M" "$CONTAINER_NAME"
fi
docker container start "$CONTAINER_NAME"

View file

@ -31,7 +31,7 @@ fi
## Setup pasta server
../pastad -c pastad.toml -m ../mime.types -B http://127.0.0.1:8200 -b 127.0.0.1:8200 &
sleep 2 # TODO: Don't do sleep here you lazy ... :-)
sleep 2
## Push a testfile
echo "Testfile 123" > testfile
@ -44,6 +44,19 @@ link=`../pasta -r http://127.0.0.1:8200 < testfile`
curl -o testfile2 $link
diff testfile testfile2
echo "Testfile 2 matches"
# Test also sending via curl
url=`curl -X POST http://127.0.0.1:8200 --data-binary @testfile | grep -Eo 'http://.*'`
echo "curl stored as $url"
curl -o testfile3 "$url"
diff testfile testfile3
echo "Testfile 3 matches"
# Test the POST form
echo -n "testpasta" > testfile4
url=`curl -X POST "http://127.0.0.1:8200?input=form&content=testpasta" | grep -Eo 'http://.*'`
curl -o testfile5 "$url"
diff testfile4 testfile5
# Test different format in link
curl -X POST http://127.0.0.1:8200?ret=json --data-binary @testfile
## Second pasta server with environment variables
echo "Testing environment variables ... "