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.

175 lines
3.6 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. )
  13. var (
  14. banner []byte
  15. )
  16. const (
  17. colBlue = "\033[0;34m"
  18. colGreen = "\033[0;32m"
  19. colBGreen = "\033[1;32m"
  20. colCyan = "\033[0;36m"
  21. colBRed = "\033[1;31m"
  22. colBold = "\033[1;37m"
  23. noCol = "\033[0m"
  24. nameLen = 12
  25. outDir = "/var/write/"
  26. bannerDir = "./"
  27. hr = "————————————————————————————————————————————————————————————————————————————————"
  28. )
  29. func main() {
  30. ln, err := net.Listen("tcp", ":9727")
  31. if err != nil {
  32. panic(err)
  33. }
  34. fmt.Println("Listening on localhost:9727")
  35. fmt.Print("Initializing...")
  36. banner, err = ioutil.ReadFile(bannerDir + "/banner.txt")
  37. if err != nil {
  38. fmt.Println(err)
  39. }
  40. fmt.Println("DONE")
  41. for {
  42. conn, err := ln.Accept()
  43. if err != nil {
  44. fmt.Println(err)
  45. continue
  46. }
  47. go handleConnection(conn)
  48. }
  49. }
  50. func output(c net.Conn, m string) bool {
  51. _, err := c.Write([]byte(m))
  52. if err != nil {
  53. c.Close()
  54. return false
  55. }
  56. return true
  57. }
  58. func outputBytes(c net.Conn, m []byte) bool {
  59. _, err := c.Write(m)
  60. if err != nil {
  61. c.Close()
  62. return false
  63. }
  64. return true
  65. }
  66. func handleConnection(c net.Conn) {
  67. outputBytes(c, banner)
  68. output(c, fmt.Sprintf("\n%sWelcome to write.as!%s\n", colBGreen, noCol))
  69. 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))
  70. waitForEnter(c)
  71. c.Close()
  72. fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
  73. }
  74. func waitForEnter(c net.Conn) {
  75. b := make([]byte, 4)
  76. output(c, fmt.Sprintf("%sPress Enter to continue...%s\n", colBRed, noCol))
  77. for {
  78. n, err := c.Read(b)
  79. if bytes.IndexRune(b[0:n], '\n') > -1 {
  80. break
  81. }
  82. if err != nil || n == 0 {
  83. c.Close()
  84. break
  85. }
  86. }
  87. output(c, fmt.Sprintf("Enter anything you like.\nPress %sCtrl-D%s to publish and quit.\n%s\n", colBold, noCol, hr))
  88. readInput(c)
  89. }
  90. func checkExit(b []byte, n int) bool {
  91. return n > 0 && bytes.IndexRune(b[0:n], '\n') == -1
  92. }
  93. func readInput(c net.Conn) {
  94. defer c.Close()
  95. b := make([]byte, 4096)
  96. var post bytes.Buffer
  97. for {
  98. n, err := c.Read(b)
  99. post.Write(b[0:n])
  100. if checkExit(b, n) {
  101. file, err := savePost(post.Bytes())
  102. if err != nil {
  103. fmt.Printf("There was an error saving: %s\n", err)
  104. output(c, "Something went terribly wrong, sorry. Try again later?\n\n")
  105. break
  106. }
  107. output(c, fmt.Sprintf("\n%s\nPosted to %shttp://nerds.write.as/%s%s\nPosting to secure site...", hr, colBlue, file, noCol))
  108. exec.Command("rsync", "-ptgou", outDir + file, "www:").Run()
  109. output(c, fmt.Sprintf("\nPosted! View at %shttps://write.as/%s%s\nSee you later.\n\n", colBlue, file, noCol))
  110. break
  111. }
  112. if err != nil || n == 0 {
  113. break
  114. }
  115. }
  116. }
  117. func savePost(post []byte) (string, error) {
  118. filename := generateFileName()
  119. f, err := os.Create(outDir + filename)
  120. defer f.Close()
  121. if err != nil {
  122. fmt.Println(err)
  123. }
  124. _, err = io.WriteString(f, stripCtlAndExtFromUTF8(string(post)))
  125. return filename, err
  126. }
  127. func generateFileName() string {
  128. c := nameLen
  129. var dictionary string = "0123456789abcdefghijklmnopqrstuvwxyz"
  130. var bytes = make([]byte, c)
  131. rand.Read(bytes)
  132. for k, v := range bytes {
  133. bytes[k] = dictionary[v%byte(len(dictionary))]
  134. }
  135. return string(bytes)
  136. }
  137. func stripCtlAndExtFromUTF8(str string) string {
  138. return strings.Map(func(r rune) rune {
  139. if r == 10 || r == 13 || (r >= 32 && r < 255) {
  140. return r
  141. }
  142. return -1
  143. }, str)
  144. }