]> Sergey Matveev's repositories - paster.git/commitdiff
Texinfo documentation, website and asciicasts
authorSergey Matveev <stargrave@stargrave.org>
Fri, 11 Feb 2022 13:24:09 +0000 (16:24 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 11 Feb 2022 18:50:37 +0000 (21:50 +0300)
15 files changed:
INSTALL
PROTOCOL [deleted file]
README
asciicast.tmpl [new file with mode: 0644]
contrib/clean.sh [new file with mode: 0755]
doc/.gitignore [new file with mode: 0644]
doc/asciicast.texi [new file with mode: 0644]
doc/examples.texi [new file with mode: 0644]
doc/features.texi [new file with mode: 0644]
doc/index.texi [new file with mode: 0644]
doc/install.texi [new file with mode: 0644]
doc/protocol.texi [new file with mode: 0644]
doc/style.css [new file with mode: 0644]
doc/www.do [new file with mode: 0644]
main.go

diff --git a/INSTALL b/INSTALL
index 28a9b0b0688036154d7e82836091032573c790bb..17039284251e86bf5f674148c2a0923684f18ed2 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,57 +1 @@
-Install paster itself:
-
-    $ go get go.stargrave.org/paster
-
-Add "paster" user and "pastes" directory, also accessible by HTTP service:
-
-    # pw useradd paster -s /usr/sbin/nologin -w no -d /path/to/pastes
-    # mkdir /path/to/pastes
-    # echo "<html><body>Paste service</body></html>" > /path/to/pastes/index.html
-    # chown -R paster:lighttpd pastes
-    # chmod 2750 pastes
-    # chmod 640 /path/to/pastes/index.html
-
-Create daemontools+ucspi-tcp service:
-
-    # mkdir -p /var/service/.paster/log/main
-    # cat > /var/service/.paster/run <<EOF
-    #!/bin/sh -e
-    cd /path/to/pastes
-    umask 027
-    exec setuidgid paster tcpserver -DHR -l 0 ::0 2020 \
-        timeout 1m $GOPATH/bin/paster http://paster.example.com/ 2>&1
-    EOF
-    # cat > /var/service/.paster/log/run <<EOF
-    #!/bin/sh -e
-    exec setuidgid paster multilog t ./main
-    EOF
-    # chmod +x /var/service/.paster/run /var/service/.paster/log/run
-    # chown paster /var/service/.paster/log/main
-    # mv /var/service/.paster /var/service/paster
-
-Optionally prepare X.509 certificate for TLS enabled service:
-
-    # umask 077
-    # certtool --generate-privkey --bits 256 --ecc --outfile \
-        paster.example.com.key.pem
-    # tmpl=`mktemp`
-    # cat > $tmpl <<EOF
-    dn = "cn=paster.example.com"
-    expiration_days = 365
-    signing_key
-    dns_name = "paster.example.com"
-    EOF
-    # certtool --generate-self-signed \
-        --load-privkey paster.example.com.key.pem \
-        --template $tmpl --outfile paster.example.com.pem
-    # rm $tmpl
-    # chown paster:paster paster.example.com*.pem
-    # chmod 600 paster.example.com.key.pem
-
-and choose from plenty of UCSPI-friendly TLS wrappers:
-http://www.fehcom.de/ipnet/ucspi-ssl.html, https://github.com/younix/ucspi
-or likely go.cypherpunks.ru/ucspi/cmd/tlss:
-
-    exec setuidgid paster tcpserver -DHR -l 0 ::0 2021 tlss \
-        -key paster.example.com.key.pem -cert paster.example.com.pem \
-        timeout 1m $GOPATH/bin/paster http://paster.example.com/ 2>&1
+Look for doc/install.texi.
diff --git a/PROTOCOL b/PROTOCOL
deleted file mode 100644 (file)
index 96ee59c..0000000
--- a/PROTOCOL
+++ /dev/null
@@ -1,8 +0,0 @@
-Protocol is very simple: bencoded dictionary is sent over TCP.
-
-* "v" key contains the data you want to paste
-* optional "e" key, holding the desired filename extension, without the
-  leading dot, up to 9 characters long
-
-"hello world" => d1:v11:hello worlde
-"http://example.com/" and "url" extension => d1:e3:url1:v18:http://example.come
diff --git a/README b/README
index d5264162b44ed4442dac84c6b92bb9e9c09a680a..e6a5978c37e656efccef0b6b598d8dbcf1f676dc 100644 (file)
--- a/README
+++ b/README
@@ -1,45 +1,2 @@
 go.stargrave.org/paster -- paste service daemon
-
-Are you tired of too complicated solutions even for the simple task like
-paste storage? I too. That is why that paster daemon is here.
-
-* It uses file system for storing the pastes
-* Pastes are shared through the external program (HTTP, FTP, Gopher, ...)
-* Paste files have an extension (.txt by default), that can be overriden
-  for the given paste. So your HTTP service can answer with varying
-  Content-Types. You can share images for example, not only plaintext
-* No excessive HTTP protocol: just send bencode-ed dictionary with the
-  data over the TCP
-* Newline is appended for .txt/.url pastes, if it is missing
-* SHA512/2 checksum is sent back to you, for integrity checking
-* Intended to be run as a UCSPI-TCP service
-  (https://cr.yp.to/ucspi-tcp.html) under daemontools-like supervisor
-  (http://cr.yp.to/daemontools.html)
-* You can clear an old ones with simple: find pastes -ctime XXX -delete
-
-With contrib/paster you can send the paste very easily:
-
-    $ paster
-    something I want to send
-    whatever whenever
-    ^D
-    http://paster.example.com/4KEOLWCZY5CBVWDNT5TA.txt
-    28d95ef0e8d6a4f4222d0e7eb2a23777aa99efb0794e535a0f4a55490705438f
-
-    $ paster webp < some-image.webp
-    http://paster.example.com/KO5O7SJTUGBORVGOZBSA.webp
-    7f53424fe50f1d70fa32763cde31335dc82fd63c975e8ab95f0bb4a6cd94fb1c
-
-    $ paster some-other-image.webp
-    http://paster.example.com/O6D2O3N5HPH63ZFIYF4A.webp
-    https://paster.example.com/O6D2O3N5HPH63ZFIYF4A.webp
-    ftp://paster.example.com/pub/pastes/O6D2O3N5HPH63ZFIYF4A.webp
-    2ffe10846ec637d29ab9145b98c3699653c01910bb6d9e00e41f7fe02c5882a8
-
-    $ grep whatever ... | paster
-    $ import png:- | paster png
-    $ import -define webp:lossless=true webp:- | paster webp
-    $ echo http://example.com | paster url
-    $ paster < /proc/cpuinfo
-
 paster is free software: see the file COPYING for copying conditions.
diff --git a/asciicast.tmpl b/asciicast.tmpl
new file mode 100644 (file)
index 0000000..2238033
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>asciicast</title>
+    <link rel="stylesheet" type="text/css" href="{{.PlayerPath}}.css" />
+  </head>
+  <body>
+  <asciinema-player src="{{.Cast}}"></asciinema-player>
+  <script src="{{.PlayerPath}}.js"></script>
+  <noscript>
+    No JavaScript support.
+    Download <a href="{{.Cast}}">asciicast</a> and play it with
+    <a href="https://pypi.org/project/asciinema/">asciinema</a>.
+  </noscript>
+  </body>
+</html>
diff --git a/contrib/clean.sh b/contrib/clean.sh
new file mode 100755 (executable)
index 0000000..a9148a9
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+find . -type f -mtime +1 \
+    -and -not -name index.html \
+    -and -not -name "asciinema-player-*" \
+    -delete
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644 (file)
index 0000000..2129d45
--- /dev/null
@@ -0,0 +1 @@
+/paster.html
diff --git a/doc/asciicast.texi b/doc/asciicast.texi
new file mode 100644 (file)
index 0000000..2dc6be2
--- /dev/null
@@ -0,0 +1,22 @@
+@node Asciicast
+@unnumbered Asciicast
+
+You can optionally automatically generate HTML pages for your
+@file{.cast}s, if you copy
+@url{https://github.com/asciinema/asciinema-player/releases, asciinema-player}
+bundle to your HTTP server and specify its base name for
+@option{-asciicast-path}:
+
+@example
+$ v=v2.6.1
+$ u=https://github.com/asciinema/asciinema-player/releases/download/$v/
+$ for ext in css js ; do
+    wget -O /path/to/www/asciinema-player-$v.$ext $u/asciinema-player.$ext
+done
+
+use $GOPATH/bin/paster -asciicast-path asciinema-player-v2.6.1
+@end example
+
+After that, additional @file{.cast.html} file will be generated during
+upload each time, with the links to the @file{.cast} and the player. You
+will also get those HTML URLs in the output.
diff --git a/doc/examples.texi b/doc/examples.texi
new file mode 100644 (file)
index 0000000..1de5e34
--- /dev/null
@@ -0,0 +1,55 @@
+@node Examples
+@unnumbered Examples
+
+With @command{contrib/paster} you can send the paste very easily:
+
+@itemize
+
+@item
+@example
+$ paster
+something I want to send
+whatever whenever
+^D
+http://paster.example.com/4KEOLWCZY5CBVWDNT5TA.txt
+SHA512/2: 28d95ef0e8d6a4f4222d0e7eb2a23777aa99efb0794e535a0f4a55490705438f
+@end example
+
+@item With overriden file extension
+@example
+$ paster webp < some-image.webp
+http://paster.example.com/KO5O7SJTUGBORVGOZBSA.webp
+SHA512/2: 7f53424fe50f1d70fa32763cde31335dc82fd63c975e8ab95f0bb4a6cd94fb1c
+@end example
+
+@item With file extension taken from the specified path. Daemon is run
+    with multiple URLs specified.
+
+@example
+$ paster some-other-image.webp
+http://paster.example.com/O6D2O3N5HPH63ZFIYF4A.webp
+https://paster.example.com/O6D2O3N5HPH63ZFIYF4A.webp
+ftp://paster.example.com/pub/pastes/O6D2O3N5HPH63ZFIYF4A.webp
+SHA512/2: 2ffe10846ec637d29ab9145b98c3699653c01910bb6d9e00e41f7fe02c5882a8
+@end example
+
+@item
+@example
+$ grep whatever ... | paster
+$ import png:- | paster png
+$ import -define webp:lossless=true webp:- | paster webp
+$ echo http://example.com | paster url
+$ paster < /proc/cpuinfo
+@end example
+
+@item Pasting the @url{https://asciinema.org/, asciicast} requires
+@file{.cast} extension. @file{.cast.html} URLs will appear.
+
+@example
+$ paster path/to/ascii.cast
+http://paster.example.com/ST4LOKGUISMACAAFC4CA.cast
+SHA512/2: 171e39f35b58b39f0bc2f3def59955d6573756374584d5443afa16d31032fdf3
+http://paster.example.com/ST4LOKGUISMACAAFC4CA.cast.html
+@end example
+
+@end itemize
diff --git a/doc/features.texi b/doc/features.texi
new file mode 100644 (file)
index 0000000..56bcfa6
--- /dev/null
@@ -0,0 +1,31 @@
+@node Features
+@unnumbered Features
+
+@itemize
+
+@item It uses file system for storing the pastes
+
+@item Pastes are shared through the external program (HTTP, FTP, Gopher, ...)
+
+@item Paste files have an extension (@file{.txt} by default), that can
+    be overriden for the given paste. So your HTTP service can answer
+    with varying @code{Content-Types}. You can share images for example,
+    not only plaintext
+
+@item No excessive HTTP protocol: just send
+    @url{https://en.wikipedia.org/wiki/Bencode, bencode}-ed dictionary
+    with the data over the TCP
+
+@item Newline is appended for @file{.txt}/@file{.url} pastes, if it is missing
+
+@item SHA512/2 checksum is sent back to you, for integrity checking
+
+@item Intended to be run as a @url{https://cr.yp.to/ucspi-tcp.html, UCSPI-TCP}
+    service @url{http://cr.yp.to/daemontools.html, daemontools}-like supervisor
+
+@item Can automatically generate HTML files with the links for automatic
+    @url{https://asciinema.org/, asciicasts} playback.
+
+@item You can clear an old ones with simple:
+    @code{find pastes -ctime XXX -delete}
+@end itemize
diff --git a/doc/index.texi b/doc/index.texi
new file mode 100644 (file)
index 0000000..03d3e0f
--- /dev/null
@@ -0,0 +1,30 @@
+\input texinfo
+@documentencoding UTF-8
+@settitle paster
+
+@copying
+Copyright @copyright{} 2021-2022 @email{stargrave@@stargrave.org, Sergey Matveev}
+@end copying
+
+@node Top
+@top paster
+
+Are you tired of too complicated solutions even for the simple task like
+paste storage? I too. That is why that @strong{paster daemon} is here.
+
+paster is
+@url{https://www.gnu.org/philosophy/pragmatic.html, copylefted}
+@url{https://www.gnu.org/philosophy/free-sw.html, free software}
+licenced under @url{https://www.gnu.org/licenses/gpl-3.0.html, GNU GPLv3}.
+
+Please send questions, bug reports and patches to @url{paster@@stargrave.org}.
+
+@insertcopying
+
+@include features.texi
+@include examples.texi
+@include install.texi
+@include asciicast.texi
+@include protocol.texi
+
+@bye
diff --git a/doc/install.texi b/doc/install.texi
new file mode 100644 (file)
index 0000000..8083cb3
--- /dev/null
@@ -0,0 +1,104 @@
+@node Install
+@unnumbered Install
+
+@itemize
+
+@item
+Install paster itself:
+
+@example
+$ go get go.stargrave.org/paster
+@end example
+
+If you have got problems with your trust anchors, unwilling to
+authenticate @code{go.stargrave.org}'s TLS connection, then clone the
+repository from @url{git://git.stargrave.org/paster.git} and build it
+as ordinary Go package with @code{go build}.
+
+@item
+Add @code{paster} user and @code{pastes} directory, also accessible by
+HTTP service (@url{http://www.godlighty.stargrave.org/, @code{godlighty}}
+user in current example):
+
+@example
+# pw useradd paster -s /usr/sbin/nologin -w no -d /path/to/pastes
+# mkdir /path/to/pastes
+# cat > /path/to/pastes/index.html <<EOF
+<!DOCTYPE html>
+<html>
+  <head><title>paster</title></head>
+  <body>Paste service.</body>
+</html>
+EOF
+# chown -R paster:godlighty pastes
+# chmod 2750 pastes
+# chmod 640 /path/to/pastes/index.html
+@end example
+
+@item
+Create @url{http://cr.yp.to/daemontools.html, daemontools} +
+@url{https://cr.yp.to/ucspi-tcp.html, UCSPI-TCP} service:
+
+@example
+# mkdir -p /var/service/.paster/log/main
+
+# cat > /var/service/.paster/run <<EOF
+#!/bin/sh -e
+cd /path/to/pastes
+umask 027
+exec setuidgid paster tcpserver -DHR -l 0 ::0 2020 \
+    timeout 1m $GOPATH/bin/paster http://paster.example.com/ 2>&1
+EOF
+
+# cat > /var/service/.paster/log/run <<EOF
+#!/bin/sh -e
+exec setuidgid paster multilog t ./main
+EOF
+
+# chmod +x /var/service/.paster/run /var/service/.paster/log/run
+# chown paster /var/service/.paster/log/main
+# mv /var/service/.paster /var/service/paster
+@end example
+
+@item
+Optionally prepare X.509 certificate for TLS enabled service:
+
+@example
+# umask 077
+# certtool --generate-privkey --bits 256 --ecc --outfile \
+    paster.example.com.key.pem
+
+# tmpl=`mktemp`
+# cat > $tmpl <<EOF
+dn = "cn=paster.example.com"
+expiration_days = 365
+signing_key
+dns_name = "paster.example.com"
+EOF
+
+# certtool --generate-self-signed \
+    --load-privkey paster.example.com.key.pem \
+    --template $tmpl --outfile paster.example.com.pem
+# rm $tmpl
+
+# chown paster:paster paster.example.com*.pem
+# chmod 600 paster.example.com.key.pem
+@end example
+
+and choose from plenty of UCSPI-friendly TLS wrappers:
+@url{http://www.fehcom.de/ipnet/ucspi-ssl.html},
+@url{https://github.com/younix/ucspi}
+or likely the @code{go.cypherpunks.ru/ucspi/cmd/tlss}:
+
+@example
+exec setuidgid paster tcpserver -DHR -l 0 ::0 2021 tlss \
+    -key paster.example.com.key.pem -cert paster.example.com.pem \
+    timeout 1m $GOPATH/bin/paster http://paster.example.com/ 2>&1
+@end example
+
+@item
+Be sure that your HTTP/whatever server uses proper @code{Content-Type}
+based on filename's extension (@code{text/plain} for @file{.txt},
+@code{image/jxl} for @file{.jxl} and so on).
+
+@end itemize
diff --git a/doc/protocol.texi b/doc/protocol.texi
new file mode 100644 (file)
index 0000000..12e0a4f
--- /dev/null
@@ -0,0 +1,16 @@
+@node Protocol
+@unnumbered Protocol
+
+Protocol is very simple: @url{https://en.wikipedia.org/wiki/Bencode,
+bencode}d dictionary is sent over TCP.
+
+@itemize
+@item @code{v} key contains the data you want to paste
+@item optional @code{e} key, holding the desired filename extension,
+    without the leading dot, up to 9 characters long
+@end itemize
+
+@example
+"hello world" => d1:v11:hello worlde
+"http://example.com/" and "url" extension => d1:e3:url1:v18:http://example.come
+@end example
diff --git a/doc/style.css b/doc/style.css
new file mode 100644 (file)
index 0000000..44fa2e0
--- /dev/null
@@ -0,0 +1,5 @@
+body { background-color: #AEBECE }
+h1, h2, h3, h4 { text-align: center }
+h1, h2, h3, h4, strong { color: #900090 }
+pre { background-color: #CCCCCC }
+table, th, td { border: 1px solid black ; border-collapse: collapse }
diff --git a/doc/www.do b/doc/www.do
new file mode 100644 (file)
index 0000000..ea98526
--- /dev/null
@@ -0,0 +1,15 @@
+redo-ifchange *.texi
+html=paster.html
+rm -f $html/*.html
+${MAKEINFO:=makeinfo} --html \
+    --css-include style.css \
+    --set-customization-variable SECTION_NAME_IN_TITLE=1 \
+    --set-customization-variable TREE_TRANSFORMATIONS=complete_tree_nodes_menus \
+    --set-customization-variable FORMAT_MENU=menu \
+    --set-customization-variable SHOW_TITLE=0 \
+    --set-customization-variable DATE_IN_HEADER=1 \
+    --set-customization-variable CLOSE_QUOTE_SYMBOL=\" \
+    --set-customization-variable OPEN_QUOTE_SYMBOL=\" \
+    -o $html index.texi
+find $html -type d -exec chmod 755 {} +
+find $html -type f -exec chmod 644 {} +
diff --git a/main.go b/main.go
index 139b5366d31f9caf6c75b001de1f671ab365877b..89bcc6eabdb6010ae235c37b162fb06aae213f65 100644 (file)
--- a/main.go
+++ b/main.go
@@ -22,22 +22,57 @@ import (
        "bytes"
        "crypto/rand"
        "crypto/sha512"
+       _ "embed"
        "encoding/base32"
        "encoding/hex"
        "flag"
        "fmt"
+       "html/template"
        "io"
        "os"
        "strconv"
 )
 
+var (
+       //go:embed asciicast.tmpl
+       ASCIICastHTMLTmplRaw string
+       ASCIICastHTMLTmpl    = template.Must(template.New("asciicast").Parse(
+               ASCIICastHTMLTmplRaw,
+       ))
+)
+
 func fatal(s string) {
        fmt.Println(s)
        os.Exit(1)
 }
 
+func asciicastHTML(playerPath, cast string) error {
+       var buf bytes.Buffer
+       err := ASCIICastHTMLTmpl.Execute(&buf, struct {
+               PlayerPath string
+               Cast       string
+       }{
+               PlayerPath: playerPath,
+               Cast:       cast,
+       })
+       if err != nil {
+               return err
+       }
+       fn := cast + ".html"
+       fd, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, os.FileMode(0666))
+       if err != nil {
+               return err
+       }
+       if _, err = fd.Write(buf.Bytes()); err != nil {
+               os.Remove(fn)
+               return err
+       }
+       return fd.Close()
+}
+
 func main() {
        maxSize := flag.Uint64("max-size", 1<<20, "Maximal upload size")
+       asciicastPath := flag.String("asciicast-path", "", "Generate HTMLs for .cast asciicasts, specify \"asciinema-player-v2.6.1\"")
        flag.Usage = func() {
                fmt.Fprintf(os.Stderr, "Usage: paster [options] URL [...]\n")
                flag.PrintDefaults()
@@ -150,7 +185,15 @@ AnotherKey:
        for _, u := range flag.Args() {
                fmt.Println(u + fn[1:])
        }
-       fmt.Println(hex.EncodeToString(h.Sum(nil)[:512/2/8]))
+       fmt.Println("SHA512/2:", hex.EncodeToString(h.Sum(nil)[:512/2/8]))
+       if ext == ".cast" && *asciicastPath != "" {
+               if err = asciicastHTML(*asciicastPath, fn[1:]); err != nil {
+                       goto Failed
+               }
+               for _, u := range flag.Args() {
+                       fmt.Println(u + fn[1:] + ".html")
+               }
+       }
        fmt.Fprintf(
                os.Stderr,
                "[%s]:%s %s %d\n",