2 paster -- paste service
3 Copyright (C) 2021-2022 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
37 //go:embed asciicast.tmpl
38 ASCIICastHTMLTmplRaw string
39 ASCIICastHTMLTmpl = template.Must(template.New("asciicast").Parse(
44 func fatal(s string) {
49 func asciicastHTML(playerPath, cast string) error {
51 err := ASCIICastHTMLTmpl.Execute(&buf, struct {
55 PlayerPath: playerPath,
62 fd, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_EXCL, os.FileMode(0666))
66 if _, err = fd.Write(buf.Bytes()); err != nil {
74 maxSize := flag.Uint64("max-size", 1<<20, "Maximal upload size")
75 asciicastPath := flag.String("asciicast-path", "", "Generate HTMLs for .cast asciicasts, specify \"asciinema-player-v2.6.1\"")
77 fmt.Fprintf(os.Stderr, "Usage: paster [options] URL [...]\n")
81 if len(flag.Args()) == 0 {
86 r := bufio.NewReader(os.Stdin)
87 b, err := r.ReadByte()
92 fatal("bad bencode: no dictionary start")
94 buf := make([]byte, 21)
98 if _, err = io.ReadFull(r, buf[:3]); err != nil {
101 switch s := string(buf[:3]); s {
103 if _, err = io.ReadFull(r, buf[:2]); err != nil {
107 fatal(`bad bencode: invalid "e" format`)
109 extLen, err := strconv.Atoi(string(buf[:1]))
113 if _, err = io.ReadFull(r, buf[:extLen]); err != nil {
116 ext = "." + string(buf[:extLen])
119 n, err := r.Read(buf)
123 i := bytes.IndexByte(buf[:n], ':')
125 fatal(`bad bencode: invalid "v" length`)
127 size, err = strconv.ParseUint(string(buf[:i]), 10, 64)
139 fatal("bad bencode: invalid key")
141 rnd := make([]byte, 12)
142 if _, err = io.ReadFull(rand.Reader, rnd); err != nil {
145 fn = "." + base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(rnd) +
147 fd, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_EXCL, os.FileMode(0666))
152 bfd := bufio.NewWriter(fd)
153 mr := io.MultiReader(bytes.NewReader(buf), r)
154 mw := io.MultiWriter(bfd, h)
155 if _, err = io.CopyN(mw, mr, int64(size-1)); err != nil {
158 if _, err = mr.Read(buf[:1]); err != nil {
161 if _, err = mw.Write(buf[:1]); err != nil {
164 if (ext == ".txt" || ext == ".url") && buf[0] != '\n' {
165 if err = bfd.WriteByte('\n'); err != nil {
169 if _, err = mr.Read(buf[:1]); err != nil {
174 fatal("bad bencode: no dictionary end")
176 if err = bfd.Flush(); err != nil {
179 if err = fd.Close(); err != nil {
182 if err = os.Rename(fn, fn[1:]); err != nil {
185 for _, u := range flag.Args() {
186 fmt.Println(u + fn[1:])
188 fmt.Println("SHA512/2:", hex.EncodeToString(h.Sum(nil)[:512/2/8]))
189 if ext == ".cast" && *asciicastPath != "" {
190 if err = asciicastHTML(*asciicastPath, fn[1:]); err != nil {
193 for _, u := range flag.Args() {
194 fmt.Println(u + fn[1:] + ".html")
200 os.Getenv("TCPREMOTEIP"),
201 os.Getenv("TCPREMOTEPORT"),