tailscale_tun_ui.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. const State = {
  2. NoState: 0,
  3. InUseOtherUser: 1,
  4. NeedsLogin: 2,
  5. NeedsMachineAuth: 3,
  6. Stopped: 4,
  7. Starting: 5,
  8. Running: 6,
  9. };
  10. export const createUi = (parent, {upCb,downCb,loginCb,logoutCb}) => {
  11. const html = `
  12. <div id="networkModalOverlay" style="width:100%;height:100vh;position:absolute;display:none ;align-items:center;justify-content:center;background:rgba(0,0,0,0.7);color:black;z-index:100">
  13. <div id="networkModal" style="max-width:650px;width:100%;background:white;height:400px;display:flex;flex-direction:row;padding:10px;justify-content:space-around">
  14. <div class="networkModalLeft">
  15. <h2>Network Configuration</h2>
  16. <form id="networkModalForm">
  17. <label for="controlUrl">Control URL: </label>
  18. <input type="text" id="controlUrl" name="controlUrl"><br><br>
  19. <label for="exitNode">Exit Node: </label>
  20. <input type="text" id="exitNode" name="exitNode"><br><br>
  21. <label for="dns">DNS Server: </label>
  22. <input type="text" id="dns" name="dns"><br><br>
  23. <button type="submit">Save</button>
  24. </form>
  25. <h2>Network Status</h2>
  26. <div id="networkModalState">Disconnected</div>
  27. <div id="networkModalAction"></div>
  28. </div>
  29. <div class="networkModalRight">
  30. <h2>Peers</h2>
  31. <div id="networkModalPeers"></div>
  32. </div>
  33. </div>
  34. </div>
  35. `;
  36. const templ = document.createElement("template");
  37. templ.innerHTML = html;
  38. parent.prepend(templ.content);
  39. const overlay = parent.querySelector("#networkModalOverlay");
  40. const form = parent.querySelector("#networkModalForm");
  41. const stateDiv = parent.querySelector("#networkModalState");
  42. const actionDiv = parent.querySelector("#networkModalAction");
  43. const peersDiv = parent.querySelector("#networkModalPeers");
  44. const getSettings = () => {
  45. const str = window.localStorage["networkSettings"] || "{}";
  46. const v = JSON.parse(str);
  47. return v;
  48. };
  49. const setSetting = (settings) => {
  50. for (const k of Object.keys(settings))
  51. {
  52. if (settings[k] === "")
  53. settings[k] = undefined;
  54. }
  55. window.localStorage["networkSettings"] = JSON.stringify(settings);
  56. }
  57. const populate = () => {
  58. const settings = getSettings();
  59. form.querySelector("#controlUrl").value = settings.controlUrl || "";
  60. form.querySelector("#exitNode").value = settings.exitNodeIp || "";
  61. form.querySelector("#dns").value = settings.dnsIp || "";
  62. };
  63. populate();
  64. const showModal = () => {
  65. overlay.style.display = "flex";
  66. };
  67. const hideModal = () => {
  68. overlay.style.display = "none";
  69. };
  70. overlay.onclick = (e) => {
  71. if (e.target === e.currentTarget)
  72. hideModal();
  73. };
  74. form.onsubmit = (e) => {
  75. e.preventDefault();
  76. const settings = {
  77. controlUrl: form.elements["controlUrl"].value,
  78. exitNodeIp: form.elements["exitNode"].value,
  79. dnsIp: form.elements["dns"].value,
  80. };
  81. setSetting(settings);
  82. };
  83. const updateState = (state) => {
  84. switch(state)
  85. {
  86. case State.NeedsLogin:
  87. {
  88. loginCb();
  89. break;
  90. }
  91. case State.Running:
  92. {
  93. const settings = getSettings();
  94. settings.wantsRunning = true;
  95. setSetting(settings);
  96. stateDiv.innerHTML = "Running";
  97. const action = document.createElement("button");
  98. action.textContent = "Stop";
  99. action.onclick = () => {
  100. downCb();
  101. action.disabled = true;
  102. }
  103. actionDiv.innerHTML = "";
  104. actionDiv.appendChild(action);
  105. break;
  106. }
  107. case State.Starting:
  108. {
  109. stateDiv.innerHTML = "Starting";
  110. actionDiv.innerHTML = "";
  111. break;
  112. }
  113. case State.Stopped:
  114. {
  115. const settings = getSettings();
  116. settings.wantsRunning = false;
  117. setSetting(settings);
  118. stateDiv.innerHTML = "Stopped";
  119. const actionLogout = document.createElement("button");
  120. const actionStart = document.createElement("button");
  121. actionStart.textContent = "Start";
  122. actionStart.onclick = () => {
  123. const settings = getSettings();
  124. upCb(settings);
  125. actionStart.disabled = true;
  126. actionLogout.disabled = true;
  127. }
  128. actionLogout.textContent = "Logout";
  129. actionLogout.onclick = () => {
  130. logoutCb();
  131. actionStart.disabled = true;
  132. actionLogout.disabled = true;
  133. }
  134. actionDiv.innerHTML = "";
  135. actionDiv.appendChild(actionStart);
  136. actionDiv.appendChild(actionLogout);
  137. break;
  138. }
  139. case State.NoState:
  140. {
  141. stateDiv.innerHTML = "Not Started";
  142. const action = document.createElement("button");
  143. action.textContent = "Start";
  144. action.onclick = () => {
  145. const settings = getSettings();
  146. upCb(settings);
  147. action.disabled = true;
  148. }
  149. actionDiv.innerHTML = "";
  150. actionDiv.appendChild(action);
  151. setTimeout(()=> {
  152. const settings = getSettings();
  153. if (settings.wantsRunning)
  154. {
  155. upCb(settings);
  156. action.disabled = true;
  157. return;
  158. }
  159. },0);
  160. break;
  161. }
  162. default:
  163. {
  164. console.log(state);
  165. stateDiv.innerHTML = "Loading";
  166. actionDiv.innerHTML = "";
  167. break;
  168. }
  169. }
  170. };
  171. const setLoginUrl = (login) => {
  172. console.log("login url:",login);
  173. stateDiv.innerHTML = "Need Login";
  174. const action = document.createElement("button");
  175. action.textContent = "Login";
  176. action.onclick = () => {
  177. window.open(login, "_blank");
  178. }
  179. actionDiv.innerHTML = "";
  180. actionDiv.appendChild(action);
  181. };
  182. const updatePeers = (map) => {
  183. const myIP = map.self.addresses[0];
  184. let peers = `self -> ${myIP}<br/>`;
  185. for (let p of map.peers) {
  186. peers = `${peers}${p.name.split(".")[0]} -> ${p.addresses[0]}<br/>`;
  187. }
  188. peersDiv.innerHTML = peers;
  189. };
  190. return {
  191. showModal,
  192. updateState,
  193. updatePeers,
  194. setLoginUrl,
  195. getSettings,
  196. }
  197. }