Simple telnet server for write.as http://nerds.write.as
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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