Browse Source

Initial commit

master
Teran McKinney 2 years ago
commit
043123a2c0
  1. 1
      .gitignore
  2. 24
      LICENSE.md
  3. 17
      README.md
  4. 15
      demo.html
  5. 87
      rantbin.go
  6. 13
      rantbin.service
  7. 74
      test.sh

1
.gitignore

@ -0,0 +1 @@
rantbin

24
LICENSE.md

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>

17
README.md

@ -0,0 +1,17 @@
# rantbin minimalist website feedback
## Usage
* Run: `go run rantbin :2222`
* Write: `curl --data-urlencode data@rantbin.go localhost:2222/feedback`
* Read: Look for files as SHA256SUMs of the data in the current directory.
Limits feedback to 4096 or sometimes less. Doesn't need Javascript.
See [demo.html](demo.html) for example HTML usage.
Also see [rantbin.service](rantbin.service) for a Systemd service file.
## License
[Public domain / Unlicense](/LICENSE.md)

15
demo.html

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<title>rantbin demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
</head>
<body>
<h1>rantbin demo</h1>
<form action="http://localhost:2222/feedback" method="post" autocomplete="off" target="_blank">
<input type="text" name="data" placeholder="Your rant here...">
<br/>
<input type="submit" value="Submit">
</form>
</body>
</html>

87
rantbin.go

@ -0,0 +1,87 @@
// rantbin...
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
// 8197 works out to be the same thing as 4096 y's. 4096 regular letters will be larger, but roughly gives us 4KiB max file size or less.
const MAX_POST = 8197
// Max length of de-URL encoded feedback.
const MAX_LENGTH = 4096
// Max number of feedback files.
const MAX_FILES = 128
func main() {
var err error
http.HandleFunc("/feedback", func(w http.ResponseWriter, r *http.Request) {
// https://stackoverflow.com/questions/28282370/is-it-advisable-to-further-limit-the-size-of-forms-when-using-golang
r.Body = http.MaxBytesReader(w, r.Body, MAX_POST)
err = r.ParseForm()
if err != nil {
log.Print("Post too long.")
http.Error(w, "Your post request was probably too long.", 400)
return
}
data := []byte(r.FormValue("data"))
length := len(data)
if length == 0 {
log.Print("No form data.")
http.Error(w, "No form data found.", 400)
return
} else if length > MAX_LENGTH {
log.Printf("This is strange, data is %d bytes long but we allowed the POST?", length)
http.Error(w, "Your message was too long.", 400)
return
}
// Make sure we don't fill up disk with too many feedbacks.
var feedbacks []os.FileInfo
feedbacks, err = ioutil.ReadDir(".")
if err != nil {
log.Print("EXCEPTION")
log.Print(err)
http.Error(w, "Issue totalling up feedbacks. Please contact the administrator.", 500)
return
}
number_of_feedbacks := len(feedbacks)
if number_of_feedbacks >= MAX_FILES {
log.Print("EXCEPTION")
log.Printf("%d feedbacks detected, max is %d", number_of_feedbacks, MAX_FILES)
http.Error(w, "Too many feedbacks. Please contact the administrator.", 500)
return
}
hash := sha256.Sum256(data)
path := hex.EncodeToString(hash[:])
_, err = os.Stat(path)
if err == nil {
log.Printf("%s already exists.", path)
http.Error(w, "That identical data already exists.", 400)
return
}
err = ioutil.WriteFile(path, []byte(data), 0644)
if err != nil {
log.Print("EXCEPTION")
log.Print(err)
http.Error(w, "Unable to write to disk. Please contact the administrator.", 500)
return
}
log.Printf("write: %s\n", path)
fmt.Fprint(w, "Feedback received.")
return
})
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "Usage: rantbin <port> (like :2222)")
os.Exit(1)
}
log.Fatal(http.ListenAndServe(os.Args[1], nil))
}

13
rantbin.service

@ -0,0 +1,13 @@
[Unit]
Description=rantbin minimalist website feedback
[Service]
DynamicUser=yes
ExecStart=/usr/local/bin/rantbin :2222
RuntimeDirectory=rantbin
WorkingDirectory=/run/rantbin
ProtectSystem=strict
NoNewPrivileges=yes
UMask=0077
Restart=on-failure
[Install]
WantedBy=multi-user.target

74
test.sh

@ -0,0 +1,74 @@
#!/usr/bin/env bash
# No real need to use stderr here since it's just tests.
set -eE
shellcheck "$0"
# Before we build...
go fmt
go doc
go test
go build
strip -s rantbin
mkdir test_dir
cd test_dir
../rantbin :2222 &
PID=$!
# So, there's a bug in shellcheck where disabling SC2103 doesn't work.
# shellcheck disable=SC2103
# cd ..
cd "$(echo .. | grep .)"
cleanup() {
echo "Cleaning up."
rm -r test_dir
kill "$PID"
}
fail() {
echo "$1"
cleanup
exit 1
}
trap fail $(seq 1 64)
# Be sure we are running.
sleep 2
# Functional tests.
echo test | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback || fail "Should be able to write.."
[ -f "test_dir/f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" ] || fail "Output file not created."
echo -n | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback && fail "Should error on empty input."
# This is.. approximate because it's URL encoded.
yes | head -c 4096 | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback || fail "Should allow a 4096 byte post."
yes | head -c 4097 | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback && fail "Should fail on anything greater than 4096 bytes."
[ "$(wc -l test_dir/309a1668b23adc98b0ec1b67d55bdca1e89e9d81c0930d5baf9b85df85d76ee0)" != "4096" ] || fail "4096 byte file wrong length or checksum???"
yes | head -c 4096 | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback && fail "Shouldn't be able to write the same message twice."
ls -1 test_dir
# Start over for final max files test.
rm test_dir/*
for i in $(seq 1 128); do
yes | head -c "$i" | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback || fail "Should be able to add file number $i"
done
echo test | curl -s --show-error --fail --data-urlencode data@- "http://localhost:2222"/feedback && fail "Should not be able to make more than 128 feedbacks."
cleanup
echo Success.
Loading…
Cancel
Save