turtle5204

secure chat test

Apr 21st, 2018
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.43 KB | None | 0 0
  1. -- Beware, horrible code lurks below, waiting to strike a carefree programmer.
  2.  
  3. -- Some functions
  4.  
  5. local function download_file(url, target)
  6. local ht = http.get(url)
  7. local data = ht.readAll()
  8. ht.close()
  9. local file = fs.open(target, "w")
  10. file.write(data)
  11. file.close()
  12. end
  13.  
  14. local function read_file(target)
  15. local file = fs.open(target, "r")
  16. local data = file.readAll()
  17. file.close()
  18. return data
  19. end
  20.  
  21. -- API Loading
  22. local function getAPI(name, url)
  23. local apiloc = "/" .. name
  24. if (not fs.exists(apiloc)) then
  25. local newapiloc = shell and shell.resolveProgram(name) or nil
  26. if type(newapiloc) ~= "string" then
  27. download_file(url, "/" .. name)
  28. else
  29. apiloc = newapiloc
  30. end
  31. end
  32. os.loadAPI(apiloc)
  33. if not _G[name] then
  34. error(name .. " failed to load!", 0)
  35. return
  36. end
  37. end
  38.  
  39. getAPI("ringnet", "https://pastebin.com/raw/bnDHMbNx")
  40. ringnet.openChannel(555)
  41.  
  42. ------------------------------------------------------------------------------------------------------
  43. ------------------------------------------------------------------------------------------------------
  44. ------------------------------------------------------------------------------------------------------
  45. ------------------------------------------------------------------------------------------------------
  46. ------------------------------------------------------------------------------------------------------
  47. ------------------------------------------------------------------------------------------------------
  48. ------------------------------------------------------------------------------------------------------
  49. ------------------------------------------------------------------------------------------------------
  50.  
  51. local tArgs = {...}
  52.  
  53. local function printUsage()
  54. print("Usages:")
  55. print("chat host <hostname>")
  56. print("chat join <hostname> <nickname>")
  57. end
  58.  
  59. local sOpenedModem = nil
  60. local function openModem()
  61. for n, sModem in ipairs(peripheral.getNames()) do
  62. if peripheral.getType(sModem) == "modem" then
  63. if not peripheral.call(sModem, "isOpen", 555) then
  64. peripheral.call(sModem, "open", 555)
  65. sOpenedModem = sModem
  66. end
  67. return true
  68. end
  69. end
  70. print("No modems found.")
  71. return false
  72. end
  73.  
  74. local function closeModem()
  75. if sOpenedModem ~= nil then
  76. peripheral.call(sOpenedModem, "close", 555)
  77. sOpenedModem = nil
  78. end
  79. end
  80.  
  81. -- Colours
  82. local highlightColour, textColour
  83. if term.isColour() then
  84. textColour = colours.white
  85. highlightColour = colours.yellow
  86. else
  87. textColour = colours.white
  88. highlightColour = colours.white
  89. end
  90.  
  91. local sCommand = tArgs[1]
  92. if sCommand == "host" then
  93. -- "chat host"
  94. -- Get hostname
  95. local sHostname = tArgs[2]
  96. if sHostname == nil then
  97. printUsage()
  98. return
  99. end
  100.  
  101. print("Our HID: " .. ringnet.get_handshakeID())
  102.  
  103. -- Host server
  104. if not openModem() then
  105. return
  106. end
  107. rednet.host("chat", sHostname)
  108. print("0 users connected.")
  109.  
  110. local tUsers = {}
  111. local nUsers = 0
  112. local function send(sText, nUserID)
  113. if nUserID then
  114. local tUser = tUsers[nUserID]
  115. if tUser then
  116. ringnet.sendData(
  117. tUser.nID,
  118. {
  119. sType = "text",
  120. nUserID = nUserID,
  121. sText = sText
  122. }
  123. )
  124. end
  125. else
  126. for nUserID, tUser in pairs(tUsers) do
  127. ringnet.sendData(
  128. tUser.nID,
  129. {
  130. sType = "text",
  131. nUserID = nUserID,
  132. sText = sText
  133. }
  134. )
  135. end
  136. end
  137. end
  138.  
  139. -- Setup ping pong
  140. local tPingPongTimer = {}
  141. local function ping(nUserID)
  142. local tUser = tUsers[nUserID]
  143. ringnet.sendData(
  144. tUser.nID,
  145. {
  146. sType = "ping to client",
  147. nUserID = nUserID
  148. }
  149. )
  150.  
  151. local timer = os.startTimer(15)
  152. tUser.bPingPonged = false
  153. tPingPongTimer[timer] = nUserID
  154. end
  155.  
  156. local function printUsers()
  157. local x, y = term.getCursorPos()
  158. term.setCursorPos(1, y - 1)
  159. term.clearLine()
  160. if nUsers == 1 then
  161. print(nUsers .. " user connected.")
  162. else
  163. print(nUsers .. " users connected.")
  164. end
  165. end
  166.  
  167. -- Handle messages
  168. local ok, error =
  169. pcall(
  170. function()
  171. parallel.waitForAny(
  172. ringnet.connectionHandler,
  173. function()
  174. while true do
  175. local sEvent, timer = os.pullEvent("timer")
  176. local nUserID = tPingPongTimer[timer]
  177. if nUserID and tUsers[nUserID] then
  178. local tUser = tUsers[nUserID]
  179. if tUser then
  180. if not tUser.bPingPonged then
  181. send("* " .. tUser.sUsername .. " has timed out")
  182. tUsers[nUserID] = nil
  183. nUsers = nUsers - 1
  184. printUsers()
  185. else
  186. ping(nUserID)
  187. end
  188. end
  189. end
  190. end
  191. end,
  192. function()
  193. while true do
  194. local tCommands
  195. tCommands = {
  196. ["me"] = function(tUser, sContent)
  197. if string.len(sContent) > 0 then
  198. send("* " .. tUser.sUsername .. " " .. sContent)
  199. else
  200. send("* Usage: /me [words]", tUser.nUserID)
  201. end
  202. end,
  203. ["nick"] = function(tUser, sContent)
  204. if string.len(sContent) > 0 then
  205. local sOldName = tUser.sUsername
  206. tUser.sUsername = sContent
  207. send("* " .. sOldName .. " is now known as " .. tUser.sUsername)
  208. else
  209. send("* Usage: /nick [nickname]", tUser.nUserID)
  210. end
  211. end,
  212. ["users"] = function(tUser, sContent)
  213. send("* Connected Users:", tUser.nUserID)
  214. local sUsers = "*"
  215. for nUserID, tUser in pairs(tUsers) do
  216. sUsers = sUsers .. " " .. tUser.sUsername
  217. end
  218. send(sUsers, tUser.nUserID)
  219. end,
  220. ["help"] = function(tUser, sContent)
  221. send("* Available commands:", tUser.nUserID)
  222. local sCommands = "*"
  223. for sCommand, fnCommand in pairs(tCommands) do
  224. sCommands = sCommands .. " /" .. sCommand
  225. end
  226. send(sCommands .. " /logout", tUser.nUserID)
  227. end
  228. }
  229.  
  230. local nSenderID, tMessage, dist = os.pullEvent("secure_receive")
  231. if (type(tMessage) == "string") then
  232. tMessage = textutils.unserialize(tMessage)
  233. end
  234. if type(tMessage) == "table" then
  235. if tMessage.sType == "login" then
  236. -- Login from new client
  237. local nUserID = tMessage.nUserID
  238. local sUsername = tMessage.sUsername
  239. if nUserID and sUsername then
  240. tUsers[nUserID] = {
  241. nID = nSenderID,
  242. nUserID = nUserID,
  243. sUsername = sUsername
  244. }
  245. nUsers = nUsers + 1
  246. printUsers()
  247. send("* " .. sUsername .. " has joined the chat")
  248. ping(nUserID)
  249. end
  250. else
  251. -- Something else from existing client
  252. local nUserID = tMessage.nUserID
  253. local tUser = tUsers[nUserID]
  254. if tUser and tUser.nID == nSenderID then
  255. if tMessage.sType == "logout" then
  256. send("* " .. tUser.sUsername .. " has left the chat")
  257. tUsers[nUserID] = nil
  258. nUsers = nUsers - 1
  259. printUsers()
  260. elseif tMessage.sType == "chat" then
  261. local sMessage = tMessage.sText
  262. if sMessage then
  263. local sCommand = string.match(sMessage, "^/([a-z]+)")
  264. if sCommand then
  265. local fnCommand = tCommands[sCommand]
  266. if fnCommand then
  267. local sContent = string.sub(sMessage, string.len(sCommand) + 3)
  268. fnCommand(tUser, sContent)
  269. else
  270. send("* Unrecognised command: /" .. sCommand, tUser.nUserID)
  271. end
  272. else
  273. send("<" .. tUser.sUsername .. "> " .. tMessage.sText)
  274. end
  275. end
  276. elseif tMessage.sType == "ping to server" then
  277. ringnet.sendData(
  278. tUser.nID,
  279. textutils.serialize(
  280. {
  281. sType = "pong to client",
  282. nUserID = nUserID
  283. }
  284. )
  285. )
  286. elseif tMessage.sType == "pong to server" then
  287. tUser.bPingPonged = true
  288. end
  289. end
  290. end
  291. end
  292. end
  293. end
  294. )
  295. end
  296. )
  297. if not ok then
  298. printError(error)
  299. end
  300.  
  301. -- Unhost server
  302. for nUserID, tUser in pairs(tUsers) do
  303. ringnet.sendData(
  304. tUser.nID,
  305. {
  306. sType = "kick",
  307. nUserID = nUserID
  308. }
  309. )
  310. end
  311. rednet.unhost("chat")
  312. closeModem()
  313. elseif sCommand == "join" then
  314. -- "chat join"
  315. -- Get hostname and username
  316. local sHostname = tArgs[2]
  317. local sUsername = tArgs[3]
  318. if sHostname == nil or sUsername == nil then
  319. printUsage()
  320. return
  321. end
  322.  
  323. -- Connect
  324. if not openModem() then
  325. return
  326. end
  327. parallel.waitForAll(
  328. ringnet.connectionHandler,
  329. function()
  330. ringnet.openTunnel(sHostname, 555)
  331. local ev, nHostID = os.pullEvent("tunnel_finish")
  332.  
  333. -- Login
  334. local nUserID = math.random(1, 2147483647)
  335. ringnet.sendData(
  336. nHostID,
  337. {
  338. sType = "login",
  339. nUserID = nUserID,
  340. sUsername = sUsername
  341. }
  342. )
  343.  
  344. -- Setup ping pong
  345. local bPingPonged = true
  346. local pingPongTimer = os.startTimer(0)
  347.  
  348. local function ping()
  349. ringnet.sendData(
  350. nHostID,
  351. {
  352. sType = "ping to server",
  353. nUserID = nUserID
  354. }
  355. )
  356. bPingPonged = false
  357. pingPongTimer = os.startTimer(15)
  358. end
  359.  
  360. -- Handle messages
  361. local w, h = term.getSize()
  362. local parentTerm = term.current()
  363. local titleWindow = window.create(parentTerm, 1, 1, w, 1, true)
  364. local historyWindow = window.create(parentTerm, 1, 2, w, h - 2, true)
  365. local promptWindow = window.create(parentTerm, 1, h, w, 1, true)
  366. historyWindow.setCursorPos(1, h - 2)
  367.  
  368. term.clear()
  369. term.setTextColour(textColour)
  370. term.redirect(promptWindow)
  371. promptWindow.restoreCursor()
  372.  
  373. local function drawTitle()
  374. local x, y = titleWindow.getCursorPos()
  375. local w, h = titleWindow.getSize()
  376. local sTitle = sUsername .. " on " .. sHostname
  377. titleWindow.setTextColour(highlightColour)
  378. titleWindow.setCursorPos(math.floor(w / 2 - string.len(sTitle) / 2), 1)
  379. titleWindow.clearLine()
  380. titleWindow.write(sTitle)
  381. promptWindow.restoreCursor()
  382. end
  383.  
  384. local function printMessage(sMessage)
  385. term.redirect(historyWindow)
  386. print()
  387. if string.match(sMessage, "^%*") then
  388. -- Information
  389. term.setTextColour(highlightColour)
  390. write(sMessage)
  391. term.setTextColour(textColour)
  392. else
  393. -- Chat
  394. local sUsernameBit = string.match(sMessage, "^<[^>]*>")
  395. if sUsernameBit then
  396. term.setTextColour(highlightColour)
  397. write(sUsernameBit)
  398. term.setTextColour(textColour)
  399. write(string.sub(sMessage, string.len(sUsernameBit) + 1))
  400. else
  401. write(sMessage)
  402. end
  403. end
  404. term.redirect(promptWindow)
  405. promptWindow.restoreCursor()
  406. end
  407.  
  408. drawTitle()
  409.  
  410. local ok, error =
  411. pcall(
  412. function()
  413. parallel.waitForAny(
  414. function()
  415. while true do
  416. local sEvent, timer = os.pullEvent()
  417. if sEvent == "timer" then
  418. if timer == pingPongTimer then
  419. if not bPingPonged then
  420. printMessage("Server timeout.")
  421. return
  422. else
  423. ping()
  424. end
  425. end
  426. elseif sEvent == "term_resize" then
  427. local w, h = parentTerm.getSize()
  428. titleWindow.reposition(1, 1, w, 1)
  429. historyWindow.reposition(1, 2, w, h - 2)
  430. promptWindow.reposition(1, h, w, 1)
  431. end
  432. end
  433. end,
  434. function()
  435. while true do
  436. local nSenderID, tMessage, dist = os.pullEvent("secure_receive")
  437. if (type(tMessage) == "string") then
  438. tMessage = textutils.unserialize(tMessage)
  439. end
  440. if nSenderID == nHostID and type(tMessage) == "table" and tMessage.nUserID == nUserID then
  441. if tMessage.sType == "text" then
  442. local sText = tMessage.sText
  443. if sText then
  444. printMessage(sText)
  445. end
  446. elseif tMessage.sType == "ping to client" then
  447. ringnet.sendData(
  448. nSenderID,
  449. textutils.serialize(
  450. {
  451. sType = "pong to server",
  452. nUserID = nUserID
  453. }
  454. )
  455. )
  456. elseif tMessage.sType == "pong to client" then
  457. bPingPonged = true
  458. elseif tMessage.sType == "kick" then
  459. return
  460. end
  461. end
  462. end
  463. end,
  464. function()
  465. local tSendHistory = {}
  466. while true do
  467. promptWindow.setCursorPos(1, 1)
  468. promptWindow.clearLine()
  469. promptWindow.setTextColor(highlightColour)
  470. promptWindow.write(": ")
  471. promptWindow.setTextColor(textColour)
  472.  
  473. local sChat = read(nil, tSendHistory)
  474. if string.match(sChat, "^/logout") then
  475. break
  476. else
  477. ringnet.sendData(
  478. nHostID,
  479. textutils.serialize(
  480. {
  481. sType = "chat",
  482. nUserID = nUserID,
  483. sText = sChat
  484. }
  485. )
  486. )
  487. table.insert(tSendHistory, sChat)
  488. end
  489. end
  490. end
  491. )
  492. end
  493. )
  494.  
  495. -- Close the windows
  496. term.redirect(parentTerm)
  497.  
  498. -- Print error notice
  499. local w, h = term.getSize()
  500. term.setCursorPos(1, h)
  501. term.clearLine()
  502. term.setCursorBlink(false)
  503. if not ok then
  504. printError(error)
  505. end
  506.  
  507. -- Logout
  508. ringnet.sendData(
  509. nHostID,
  510. {
  511. sType = "logout",
  512. nUserID = nUserID
  513. }
  514. )
  515. closeModem()
  516.  
  517. -- Print disconnection notice
  518. print("Disconnected.")
  519. end
  520. )
  521. else
  522. -- "chat somethingelse"
  523. printUsage()
  524. end
Advertisement
Add Comment
Please, Sign In to add comment