Simple telnet server for write.as http://nerds.write.as
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

228 Zeilen
4.8 KiB

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "bytes"
  6. "io/ioutil"
  7. "crypto/rand"
  8. "io"
  9. "os"
  10. "os/exec"
  11. "strings"
  12. "flag"
  13. "unicode/utf8"
  14. )
  15. var (
  16. banner []byte
  17. outDir string
  18. staticDir string
  19. debugging bool
  20. rsyncHost string
  21. )
  22. const (
  23. colBlue = "\033[0;34m"
  24. colGreen = "\033[0;32m"
  25. colBGreen = "\033[1;32m"
  26. colCyan = "\033[0;36m"
  27. colBRed = "\033[1;31m"
  28. colBold = "\033[1;37m"
  29. noCol = "\033[0m"
  30. nameLen = 12
  31. hr = "————————————————————————————————————————————————————————————————————————————————"
  32. )
  33. func main() {
  34. // Get any arguments
  35. outDirPtr := flag.String("o", "/var/write", "Directory where text files will be stored.")
  36. staticDirPtr := flag.String("s", ".", "Directory where required static files exist.")
  37. rsyncHostPtr := flag.String("h", "", "Hostname of the server to rsync saved files to.")
  38. portPtr := flag.Int("p", 2323, "Port to listen on.")
  39. debugPtr := flag.Bool("debug", false, "Enables garrulous debug logging.")
  40. flag.Parse()
  41. outDir = *outDirPtr
  42. staticDir = *staticDirPtr
  43. rsyncHost = *rsyncHostPtr
  44. debugging = *debugPtr
  45. fmt.Print("\nCONFIG:\n")
  46. fmt.Printf("Output directory : %s\n", outDir)
  47. fmt.Printf("Static directory : %s\n", staticDir)
  48. fmt.Printf("rsync host : %s\n", rsyncHost)
  49. fmt.Printf("Debugging enabled : %t\n\n", debugging)
  50. fmt.Print("Initializing...")
  51. var err error
  52. banner, err = ioutil.ReadFile(staticDir + "/banner.txt")
  53. if err != nil {
  54. fmt.Println(err)
  55. }
  56. fmt.Println("DONE")
  57. ln, err := net.Listen("tcp", fmt.Sprintf(":%d", *portPtr))
  58. if err != nil {
  59. panic(err)
  60. }
  61. fmt.Printf("Listening on localhost:%d\n", *portPtr)
  62. for {
  63. conn, err := ln.Accept()
  64. if err != nil {
  65. fmt.Println(err)
  66. continue
  67. }
  68. go handleConnection(conn)
  69. }
  70. }
  71. func output(c net.Conn, m string) bool {
  72. _, err := c.Write([]byte(m))
  73. if err != nil {
  74. c.Close()
  75. return false
  76. }
  77. return true
  78. }
  79. func outputBytes(c net.Conn, m []byte) bool {
  80. _, err := c.Write(m)
  81. if err != nil {
  82. c.Close()
  83. return false
  84. }
  85. return true
  86. }
  87. func handleConnection(c net.Conn) {
  88. outputBytes(c, banner)
  89. output(c, fmt.Sprintf("\n%sWelcome to write.as!%s\n", colBGreen, noCol))
  90. output(c, fmt.Sprintf("If this is freaking you out, you can get notified of the %sbrowser-based%s launch\ninstead at https://write.as.\n\n", colBold, noCol))
  91. waitForEnter(c)
  92. c.Close()
  93. fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
  94. }
  95. func waitForEnter(c net.Conn) {
  96. b := make([]byte, 4)
  97. output(c, fmt.Sprintf("%sPress Enter to continue...%s\n", colBRed, noCol))
  98. for {
  99. n, err := c.Read(b)
  100. if debugging {
  101. fmt.Print(b[0:n])
  102. fmt.Printf("\n%d: %s\n", n, b[0:n])
  103. }
  104. if bytes.IndexRune(b[0:n], '\n') > -1 {
  105. break
  106. }
  107. if err != nil || n == 0 {
  108. c.Close()
  109. break
  110. }
  111. }
  112. output(c, fmt.Sprintf("Enter anything you like.\nPress %sCtrl-D%s to publish and quit.\n%s\n", colBold, noCol, hr))
  113. readInput(c)
  114. }
  115. func checkExit(b []byte, n int) bool {
  116. return n > 0 && bytes.IndexRune(b[0:n], '\n') == -1
  117. }
  118. func readInput(c net.Conn) {
  119. defer c.Close()
  120. b := make([]byte, 4096)
  121. var post bytes.Buffer
  122. for {
  123. n, err := c.Read(b)
  124. post.Write(b[0:n])
  125. if debugging {
  126. fmt.Print(b[0:n])
  127. fmt.Printf("\n%d: %s\n", n, b[0:n])
  128. }
  129. if checkExit(b, n) {
  130. file, err := savePost(post.Bytes())
  131. if err != nil {
  132. fmt.Printf("There was an error saving: %s\n", err)
  133. output(c, "Something went terribly wrong, sorry. Try again later?\n\n")
  134. break
  135. }
  136. output(c, fmt.Sprintf("\n%s\nPosted to %shttp://nerds.write.as/%s%s", hr, colBlue, file, noCol))
  137. if rsyncHost != "" {
  138. output(c, "\nPosting to secure site...")
  139. exec.Command("rsync", "-ptgou", outDir + "/" + file, rsyncHost + ":").Run()
  140. output(c, fmt.Sprintf("\nPosted! View at %shttps://write.as/%s%s", colBlue, file, noCol))
  141. }
  142. output(c, "\nSee you later.\n\n")
  143. break
  144. }
  145. if err != nil || n == 0 {
  146. break
  147. }
  148. }
  149. }
  150. func savePost(post []byte) (string, error) {
  151. filename := generateFileName()
  152. f, err := os.Create(outDir + "/" + filename)
  153. defer f.Close()
  154. if err != nil {
  155. fmt.Println(err)
  156. }
  157. var decodedPost bytes.Buffer
  158. // Decode UTF-8
  159. for len(post) > 0 {
  160. r, size := utf8.DecodeRune(post)
  161. decodedPost.WriteRune(r)
  162. post = post[size:]
  163. }
  164. _, err = io.WriteString(f, stripCtlAndExtFromUTF8(string(decodedPost.Bytes())))
  165. return filename, err
  166. }
  167. func generateFileName() string {
  168. c := nameLen
  169. var dictionary string = "0123456789abcdefghijklmnopqrstuvwxyz"
  170. var bytes = make([]byte, c)
  171. rand.Read(bytes)
  172. for k, v := range bytes {
  173. bytes[k] = dictionary[v%byte(len(dictionary))]
  174. }
  175. return string(bytes)
  176. }
  177. func stripCtlAndExtFromUTF8(str string) string {
  178. return strings.Map(func(r rune) rune {
  179. if r == 10 || r == 13 || (r >= 32 && r < 65533) {
  180. return r
  181. }
  182. return -1
  183. }, str)
  184. }