Simple telnet server for write.as http://nerds.write.as
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

188 linhas
4.1 KiB

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "bytes"
  6. "io/ioutil"
  7. "os"
  8. "flag"
  9. "database/sql"
  10. _ "github.com/go-sql-driver/mysql"
  11. "github.com/writeas/writeas-telnet/store"
  12. )
  13. var (
  14. banner []byte
  15. staticDir string
  16. debugging bool
  17. db *sql.DB
  18. )
  19. const (
  20. colBlue = "\033[0;34m"
  21. colGreen = "\033[0;32m"
  22. colBGreen = "\033[1;32m"
  23. colCyan = "\033[0;36m"
  24. colBRed = "\033[1;31m"
  25. colBold = "\033[1;37m"
  26. noCol = "\033[0m"
  27. hr = "————————————————————————————————————————————————————————————————————————————————"
  28. )
  29. func main() {
  30. // Get any arguments
  31. staticDirPtr := flag.String("s", "./static", "Directory where required static files exist.")
  32. portPtr := flag.Int("p", 2323, "Port to listen on.")
  33. debugPtr := flag.Bool("debug", false, "Enables garrulous debug logging.")
  34. flag.Parse()
  35. staticDir = *staticDirPtr
  36. debugging = *debugPtr
  37. fmt.Print("\nCONFIG:\n")
  38. fmt.Printf("Static directory : %s\n", staticDir)
  39. fmt.Printf("Debugging enabled : %t\n\n", debugging)
  40. fmt.Print("Initializing...")
  41. var err error
  42. banner, err = ioutil.ReadFile(staticDir + "/banner.txt")
  43. if err != nil {
  44. fmt.Println(err)
  45. }
  46. fmt.Println("DONE")
  47. // Connect to database
  48. dbUser := os.Getenv("WA_USER")
  49. dbPassword := os.Getenv("WA_PASSWORD")
  50. dbHost := os.Getenv("WA_HOST")
  51. if dbUser == "" || dbPassword == "" {
  52. fmt.Println("Database user or password not set.")
  53. return
  54. }
  55. fmt.Print("Connecting to database...")
  56. db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:3306)/writeas?charset=utf8mb4", dbUser, dbPassword, dbHost))
  57. if err != nil {
  58. fmt.Printf("\n%s\n", err)
  59. return
  60. }
  61. defer db.Close()
  62. fmt.Println("CONNECTED")
  63. ln, err := net.Listen("tcp", fmt.Sprintf(":%d", *portPtr))
  64. if err != nil {
  65. panic(err)
  66. }
  67. fmt.Printf("Listening on localhost:%d\n", *portPtr)
  68. for {
  69. conn, err := ln.Accept()
  70. if err != nil {
  71. fmt.Println(err)
  72. continue
  73. }
  74. go handleConnection(conn)
  75. }
  76. }
  77. func output(c net.Conn, m string) bool {
  78. _, err := c.Write([]byte(m))
  79. if err != nil {
  80. c.Close()
  81. return false
  82. }
  83. return true
  84. }
  85. func outputBytes(c net.Conn, m []byte) bool {
  86. _, err := c.Write(m)
  87. if err != nil {
  88. c.Close()
  89. return false
  90. }
  91. return true
  92. }
  93. func handleConnection(c net.Conn) {
  94. outputBytes(c, banner)
  95. output(c, fmt.Sprintf("\n%sWelcome to write.as!%s\n", colBGreen, noCol))
  96. 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))
  97. waitForEnter(c)
  98. c.Close()
  99. fmt.Printf("Connection from %v closed.\n", c.RemoteAddr())
  100. }
  101. func waitForEnter(c net.Conn) {
  102. b := make([]byte, 4)
  103. output(c, fmt.Sprintf("%sPress Enter to continue...%s\n", colBRed, noCol))
  104. for {
  105. n, err := c.Read(b)
  106. if debugging {
  107. fmt.Print(b[0:n])
  108. fmt.Printf("\n%d: %s\n", n, b[0:n])
  109. }
  110. if bytes.IndexRune(b[0:n], '\n') > -1 {
  111. break
  112. }
  113. if err != nil || n == 0 {
  114. c.Close()
  115. break
  116. }
  117. }
  118. output(c, fmt.Sprintf("Enter anything you like.\nPress %sCtrl-D%s to publish and quit.\n%s\n", colBold, noCol, hr))
  119. readInput(c)
  120. }
  121. func checkExit(b []byte, n int) bool {
  122. return n > 0 && bytes.IndexRune(b[0:n], '\n') == -1
  123. }
  124. func readInput(c net.Conn) {
  125. defer c.Close()
  126. b := make([]byte, 4096)
  127. var post bytes.Buffer
  128. for {
  129. n, err := c.Read(b)
  130. post.Write(b[0:n])
  131. if debugging {
  132. fmt.Print(b[0:n])
  133. fmt.Printf("\n%d: %s\n", n, b[0:n])
  134. }
  135. if checkExit(b, n) {
  136. friendlyId := store.GenerateFriendlyRandomString(store.FriendlyIdLen)
  137. editToken := store.Generate62RandomString(32)
  138. _, err := db.Exec("INSERT INTO posts (id, content, modify_token) VALUES (?, ?, ?)", friendlyId, post.Bytes(), editToken)
  139. if err != nil {
  140. fmt.Printf("There was an error saving: %s\n", err)
  141. output(c, "Something went terribly wrong, sorry. Try again later?\n\n")
  142. break
  143. }
  144. output(c, fmt.Sprintf("\n%s\nPosted! View at %shttps://write.as/%s%s", hr, colBlue, friendlyId, noCol))
  145. output(c, "\nSee you later.\n\n")
  146. break
  147. }
  148. if err != nil || n == 0 {
  149. break
  150. }
  151. }
  152. }