Dashboard.coffee 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. class Dashboard extends Class
  2. constructor: ->
  3. @menu_newversion = new Menu()
  4. @menu_port = new Menu()
  5. @menu_tor = new Menu()
  6. @menu_trackers = new Menu()
  7. @menu_multiuser = new Menu()
  8. @menu_donate = new Menu()
  9. @menu_warnings = new Menu()
  10. @port_checking = false
  11. @has_web_gl = null
  12. isTorAlways: ->
  13. return Page.server_info.fileserver_ip == "127.0.0.1"
  14. hasWebGl: ->
  15. if @has_web_gl == null
  16. canvas = document.createElement('canvas')
  17. ctx = canvas.getContext("webgl")
  18. @has_web_gl = if ctx then true else false
  19. @log "Webgl:", @has_web_gl
  20. return @has_web_gl
  21. getTorTitle: ->
  22. tor_title = Page.server_info.tor_status.replace(/\((.*)\)/, "").trim()
  23. if tor_title == "Disabled" then tor_title = _("Disabled")
  24. else if tor_title == "Error" then tor_title = _("Error")
  25. return tor_title
  26. tagTrackersTitle: ->
  27. if Page.server_info.offline
  28. return h("span.status.status-warning", "n/a")
  29. num_ok = 0
  30. num_total = 0
  31. status_db = {announcing: [], error: [], announced: []}
  32. if Page.announcer_stats
  33. stats = Page.announcer_stats
  34. else
  35. stats = Page.announcer_info
  36. for key, val of stats
  37. if val.status == "announced"
  38. num_ok += 1
  39. num_total += 1
  40. title = "#{num_ok}/#{num_total}"
  41. if num_total == 0
  42. return h("span.status", "Waiting...")
  43. else if num_ok > num_total / 2
  44. return h("span.status.status-ok", title)
  45. else if num_ok > 0
  46. return h("span.status.status-warning", title)
  47. else
  48. return h("span.status.status-error", title)
  49. handleTorClick: =>
  50. @menu_tor.items = []
  51. @menu_tor.items.push ["Status: #{Page.server_info?.tor_status}", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#how-to-make-zeronet-work-with-tor-under-linux"]
  52. if @getTorTitle() != "OK"
  53. @menu_tor.items.push ["How to make Tor connection work?", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#how-to-make-zeronet-work-with-tor-under-linux"]
  54. @menu_tor.items.push ["How to use ZeroNet in Tor Browser?", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#how-to-use-zeronet-in-tor-browser"]
  55. @menu_tor.items.push ["---"]
  56. if @isTorAlways()
  57. @menu_tor.items.push ["Disable always Tor mode", @handleDisableAlwaysTorClick]
  58. else
  59. @menu_tor.items.push ["Enable Tor for every connection (slower)", @handleEnableAlwaysTorClick]
  60. @menu_tor.toggle()
  61. return false
  62. handleEnableAlwaysTorClick: =>
  63. Page.cmd "configSet", ["tor", "always"], (res) =>
  64. Page.cmd "wrapperNotification", ["done", "Tor always mode enabled, please restart your ZeroNet to make it work.<br>For your privacy switch to Tor browser and start a new profile by renaming the data directory."]
  65. Page.cmd "wrapperConfirm", ["Restart ZeroNet client?", "Restart now"], (res) =>
  66. if res
  67. Page.cmd("serverShutdown", {restart: true})
  68. handleDisableAlwaysTorClick: =>
  69. Page.cmd "configSet", ["tor", null], (res) =>
  70. Page.cmd "wrapperNotification", ["done", "Tor always mode disabled, please restart your ZeroNet."]
  71. handlePortClick: =>
  72. @menu_port.items = []
  73. if Page.server_info.offline
  74. @menu_port.items.push ["Offline mode, network communication disabled.", "/Config"]
  75. else if Page.server_info.ip_external
  76. @menu_port.items.push ["Nice! Your port #{Page.server_info.fileserver_port} is opened.", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#do-i-need-to-have-a-port-opened"]
  77. else if @isTorAlways()
  78. @menu_port.items.push ["Good, your port is always closed when using ZeroNet in Tor always mode.", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#do-i-need-to-have-a-port-opened"]
  79. else if @getTorTitle() == "OK"
  80. @menu_port.items.push ["Your port #{Page.server_info.fileserver_port} is closed, but your Tor gateway is running well.", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#do-i-need-to-have-a-port-opened"]
  81. else
  82. @menu_port.items.push ["Your port #{Page.server_info.fileserver_port} is closed. You are still fine, but for faster experience try open it.", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#do-i-need-to-have-a-port-opened"]
  83. if Page.server_info.port_opened
  84. @menu_port.items.push ["---"]
  85. port_opened = Page.server_info.port_opened
  86. format = {
  87. true: h("span.status.status-ok", "Opened"),
  88. false: h("span.status.status-warning","Closed"),
  89. null: h("span.status.status-disabled","Unsupported")
  90. undefined: h("span.status.status-disabled","Checking...")
  91. }
  92. @menu_port.items.push [["IPv4: ", format[port_opened.ipv4], ", IPv6: ", format[port_opened.ipv6]], null]
  93. @menu_port.items.push ["---"]
  94. @menu_port.items.push ["Re-check opened port", @handlePortRecheckClick]
  95. @menu_port.toggle()
  96. return false
  97. handlePortRecheckClick: =>
  98. @port_checking = true
  99. Page.cmd "serverPortcheck", [], (res) =>
  100. @port_checking = false
  101. Page.reloadServerInfo()
  102. handleMultiuserClick: =>
  103. @menu_multiuser.items = []
  104. @menu_multiuser.items.push ["Show your masterseed", ( -> Page.cmd "userShowMasterSeed" )]
  105. if Page.server_info.multiuser_admin
  106. @menu_multiuser.items.push ["Select user", ( -> Page.cmd "userSelectForm" )]
  107. @menu_multiuser.items.push ["Logout", ( -> Page.cmd "userLogout" )]
  108. @menu_multiuser.toggle()
  109. return false
  110. handleDonateClick: =>
  111. @menu_donate.items = []
  112. @menu_donate.items.push ["Help to keep this project alive", Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "help_zeronet/donate/"]
  113. @menu_donate.toggle()
  114. return false
  115. handleLogoutClick: =>
  116. Page.cmd "uiLogout"
  117. handleNewversionClick: =>
  118. @menu_newversion.items = []
  119. @menu_newversion.items.push ["Update ZeroNet", ( ->
  120. Page.updateZeronet()
  121. )]
  122. @menu_newversion.items.push ["Details of the update", Text.getSiteUrl("Blog.ZeroNetwork.bit") ]
  123. @menu_newversion.toggle()
  124. return false
  125. handleTrackersClick: =>
  126. if Page.announcer_stats
  127. stats = Page.announcer_stats
  128. Page.reloadAnnouncerStats()
  129. else
  130. stats = Page.announcer_info
  131. @menu_trackers.items = []
  132. for tracker_url, stat of stats
  133. tracker_name = tracker_url.replace(/(.*:\/\/.*?)[\/#].*/, "$1").replace(/:[0-9]+$/, "")
  134. success_percent = parseInt((stat.num_success/stat.num_request)*100)
  135. if isNaN(success_percent)
  136. success_percent = "?"
  137. status = stat.status.capitalize()
  138. if status == "Announced" and stat.time_request and stat.time_status
  139. request_taken = stat.time_status - stat.time_request
  140. status = "#{request_taken.toFixed(2)}s"
  141. title_text = "Requests: #{stat.num_request}"
  142. if stat.last_error
  143. title_text += ", Last error: #{stat.last_error} (#{Time.since(stat.time_last_error)})"
  144. title = [tracker_name, h("span.tracker-status", {title: title_text}, "#{status} (#{success_percent}% success)")]
  145. @menu_trackers.items.push [title, null]
  146. @menu_trackers.toggle()
  147. return false
  148. handleWarningsClick: =>
  149. warnings = @getWarnings()
  150. @menu_warnings.items = []
  151. for warning in warnings
  152. @menu_warnings.items.push [h("b.status-error", warning.title), warning.href]
  153. if warning.descr
  154. @menu_warnings.items.push [warning.descr, warning.href]
  155. @menu_warnings.items.push ["---"]
  156. @menu_warnings.items.push ["Restart ZeroNet client", => Page.cmd("serverShutdown", {restart: true})]
  157. @menu_warnings.toggle()
  158. return false
  159. getWarnings: (add_server_errors=true) =>
  160. warnings = []
  161. # IE not supported
  162. if navigator.userAgent.match /(\b(MS)?IE\s+|Trident\/7.0)/
  163. warnings.push({
  164. title: "Unsupported browser",
  165. href: "http://browsehappy.com/",
  166. descr: "Internet Explorer is not fully supported browser by ZeroNet, please consider switching to Chrome or Firefox"
  167. })
  168. # No tor browser detected
  169. if (@isTorAlways() and (not navigator.userAgent.match(/(Firefox)/) or navigator.maxTouchPoints? or navigator.serviceWorker?))
  170. warnings.push({
  171. title: "Your browser is not safe",
  172. href: Text.getSiteUrl("1DocsYf2tZVVMEMJFHiDsppmFicZCWkVv1") + "faq/#how-to-use-zeronet-in-tor-browser",
  173. descr: "To protect your anonymity you should use ZeroNet in the Tor browser."
  174. })
  175. # Slow pure-python verify lib
  176. if Page.server_info.lib_verify_best == "btctools"
  177. warnings.push({
  178. title: "Slow verification library",
  179. href: "#"
  180. descr: "To significantly reduce CPU usage install libsecp256k1 or OpenSSL"
  181. })
  182. if Math.abs(Page.server_info.timecorrection) > 30
  183. warnings.push({
  184. title: ["Time out of sync: ", (0 - Page.server_info.timecorrection.toFixed(2)), "s"]
  185. href: "https://time.is",
  186. descr: "Looks like your system time is out of sync. Other users may not see your posted content and other problems could happen."
  187. })
  188. if add_server_errors
  189. if Page.server_errors.length > 2
  190. warnings = warnings.concat(Page.server_errors[-2..].reverse())
  191. warnings.push({
  192. title: "#{Page.server_errors.length - 2} more errors...",
  193. href: "#ZeroNet:Console:Error"
  194. })
  195. else
  196. warnings = warnings.concat(Page.server_errors)
  197. return warnings
  198. render: =>
  199. if Page.server_info
  200. tor_title = @getTorTitle()
  201. num_warnings = @getWarnings(false) + Page.server_errors.length
  202. h("div#Dashboard",
  203. # Warnings
  204. if num_warnings > 0
  205. h("a.warnings.dashboard-item", {href: "#Warnings", onmousedown: @handleWarningsClick, onclick: Page.returnFalse}, "Warnings: #{num_warnings}")
  206. @menu_warnings.render(".menu-warnings")
  207. # Update
  208. if parseFloat(Page.server_info.version.replace(/\./g, "0")) < parseFloat(Page.latest_version.replace(/\./g, "0"))
  209. h("a.newversion.dashboard-item", {href: "#Update", onmousedown: @handleNewversionClick, onclick: Page.returnFalse}, "New ZeroNet version: #{Page.latest_version}")
  210. else if Page.server_info.rev < Page.latest_rev
  211. h("a.newversion.dashboard-item", {href: "#Update", onmousedown: @handleNewversionClick, onclick: Page.returnFalse}, "New important update: rev#{Page.latest_rev}")
  212. @menu_newversion.render(".menu-newversion")
  213. # Donate
  214. h("a.port.dashboard-item.donate", {"href": "#Donate", onmousedown: @handleDonateClick, onclick: Page.returnFalse}, [h("div.icon-heart")]),
  215. @menu_donate.render(".menu-donate")
  216. # Multiuser
  217. if Page.server_info.multiuser
  218. h("a.port.dashboard-item.multiuser", {href: "#Multiuser", onmousedown: @handleMultiuserClick, onclick: Page.returnFalse}, [
  219. h("span", "User: "),
  220. h("span.status",
  221. {style: "color: #{Text.toColor(Page.server_info.master_address)}"},
  222. Page.server_info.master_address[0..4]+".."+Page.server_info.master_address[-4..]
  223. )
  224. ])
  225. if Page.server_info.multiuser
  226. @menu_multiuser.render(".menu-multiuser")
  227. if "UiPassword" in Page.server_info.plugins
  228. h("a.port.dashboard-item.logout", {href: "#Logout", onmousedown: @handleLogoutClick, onclick: Page.returnFalse}, [
  229. h("span", "Logout"),
  230. ])
  231. # Port open status
  232. @menu_port.render(".menu-port.menu-left"),
  233. h("a.dashboard-item.port", {href: "#Port", classes: {bounce: @port_checking}, onmousedown: @handlePortClick, onclick: Page.returnFalse}, [
  234. h("span", "Port: "),
  235. if Page.server_info.offline
  236. h("span.status.status-warning", "Offline mode")
  237. else if @port_checking
  238. h("span.status", "Checking")
  239. else if Page.server_info.ip_external == null
  240. h("span.status", "Checking")
  241. else if Page.server_info.ip_external == true
  242. h("span.status.status-ok", "Opened")
  243. else if @isTorAlways
  244. h("span.status.status-ok", "Closed")
  245. else if tor_title == "OK"
  246. h("span.status.status-warning", "Closed")
  247. else
  248. h("span.status.status-bad", "Closed")
  249. ]),
  250. # Tor status
  251. h("a.dashboard-item.tor", {href: "#Tor", onmousedown: @handleTorClick, onclick: Page.returnFalse}, [
  252. h("span", "Tor: "),
  253. if tor_title == "OK"
  254. if @isTorAlways()
  255. h("span.status.status-ok", "Always")
  256. else
  257. h("span.status.status-ok", "Available")
  258. else
  259. h("span.status.status-warning", tor_title)
  260. ]),
  261. @menu_tor.render(".menu-tor")
  262. # Announcer status
  263. if Page.announcer_info or Page.announcer_stats
  264. h("a.dashboard-item.trackers", {href: "#Trackers", onmousedown: @handleTrackersClick, onclick: Page.returnFalse}, [
  265. h("span", "Trackers: "),
  266. @tagTrackersTitle()
  267. ])
  268. @menu_trackers.render(".menu-trackers")
  269. )
  270. else
  271. h("div#Dashboard")
  272. window.Dashboard = Dashboard