Compare commits
4 commits
main
...
update_tun
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6ea07e9a65 | ||
![]() |
e8e26c8386 | ||
![]() |
c8cbb9a58c | ||
![]() |
4287f26af7 |
9 changed files with 119 additions and 158 deletions
12
README.md
12
README.md
|
@ -25,6 +25,18 @@ WebVM is powered by the CheerpX virtualization engine, and enables safe, sandbox
|
|||
- go back to the WebVM tab. You will see your IP address in the top right
|
||||
- start firing network requests!
|
||||
|
||||
# How to: login to Tailscale with an Auth key
|
||||
|
||||
- Add `#authKey=<your-key>` at the end of the URL
|
||||
- Done. You don't need to manually log in anymore
|
||||
|
||||
It is recommended to use an ephemeral key.
|
||||
|
||||
# How to: login to a self-hosted Tailscale network (Headscale)
|
||||
|
||||
- Add `#controlUrl=<your-control-url>` at the end of the URL
|
||||
- You can combine this option with `authKey` with a `&`: `#controlUrl=<url>&authKey=<key>`
|
||||
|
||||
# Bugs and Issues
|
||||
|
||||
Please use [Issues](https://github.com/leaningtech/webvm/issues) to report any bug.
|
||||
|
|
75
index.html
75
index.html
|
@ -31,81 +31,12 @@
|
|||
<link rel="stylesheet" id="us-fonts-css" href="https://fonts.googleapis.com/css?family=Montserrat%3A300%2C400%2C500%2C600%2C700&display=swap&ver=6.0.2" media="all">
|
||||
<link rel="stylesheet" href="./xterm/xterm.css" />
|
||||
<link rel="stylesheet" href="./scrollbar.css" />
|
||||
<script src="./xterm/xterm.js"></script>
|
||||
<script src="./xterm/xterm-addon-fit.js"></script>
|
||||
<script>
|
||||
window.networkInterface = { bind: null, connect: null, listen: null, ready: false };
|
||||
</script>
|
||||
<script src="./xterm/xterm.js"></script>
|
||||
<script src="./xterm/xterm-addon-fit.js"></script>
|
||||
<script defer type="module">
|
||||
import { State } from "/tun/tailscale_tun.js";
|
||||
import { autoConf } from "/tun/tailscale_tun_auto.js";
|
||||
|
||||
let resolveLogin = null;
|
||||
let loginPromise = new Promise((f,r) => {
|
||||
resolveLogin = f;
|
||||
});
|
||||
const loginElem = document.getElementById("loginLink");
|
||||
const statusElem = document.getElementById("networkStatus");
|
||||
const loginUrlCb = (url) => {
|
||||
loginElem.href = url;
|
||||
loginElem.target = "_blank";
|
||||
statusElem.innerHTML = "Tailscale Login";
|
||||
resolveLogin(url);
|
||||
};
|
||||
const stateUpdateCb = (state) => {
|
||||
switch(state)
|
||||
{
|
||||
case State.NeedsLogin:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.Running:
|
||||
{
|
||||
loginElem.href = "https://login.tailscale.com/admin/machines";
|
||||
break;
|
||||
}
|
||||
case State.Starting:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.Stopped:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.NoState:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
const netmapUpdateCb = (map) => {
|
||||
const ip = map.self.addresses[0];
|
||||
statusElem.innerHTML = "IP: "+ip;
|
||||
};
|
||||
const { listen, connect, bind, up } = await autoConf({
|
||||
loginUrlCb,
|
||||
stateUpdateCb,
|
||||
netmapUpdateCb,
|
||||
});
|
||||
window.networkInterface.bind = bind;
|
||||
window.networkInterface.connect = connect;
|
||||
window.networkInterface.listen = listen;
|
||||
window.networkInterface.ready = true;
|
||||
loginElem.style.cursor = "pointer";
|
||||
statusElem.style.color = "white";
|
||||
loginElem.onclick = () => {
|
||||
loginElem.onclick = null;
|
||||
statusElem.innerHTML = "Downloading network code...";
|
||||
const w = window.open("login.html", "_blank");
|
||||
async function waitLogin() {
|
||||
await up();
|
||||
statusElem.innerHTML = "Starting login...";
|
||||
const url = await loginPromise;
|
||||
w.location.href = url;
|
||||
}
|
||||
waitLogin();
|
||||
};
|
||||
</script>
|
||||
<script type="module" src="network.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="margin:0;height:100%;background:black;color:white;overflow:hidden; display:flex; flex-direction: column; justify-content: space-between; height: 100%;">
|
||||
|
|
86
network.js
Normal file
86
network.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
import { State } from "./tun/tailscale_tun.js";
|
||||
import { autoConf } from "./tun/tailscale_tun_auto.js";
|
||||
|
||||
let params = new URLSearchParams("?"+window.location.hash.substr(1));
|
||||
let authKey = params.get("authKey") || undefined;
|
||||
let controlUrl = params.get("controlUrl") || undefined;
|
||||
console.log(authKey, controlUrl);
|
||||
let loginElemUrl = controlUrl ? null : "https://login.tailscale.com/admin/machines";
|
||||
|
||||
let resolveLogin = null;
|
||||
let loginPromise = new Promise((f,r) => {
|
||||
resolveLogin = f;
|
||||
});
|
||||
const loginElem = document.getElementById("loginLink");
|
||||
const statusElem = document.getElementById("networkStatus");
|
||||
const loginUrlCb = (url) => {
|
||||
loginElem.href = url;
|
||||
loginElem.target = "_blank";
|
||||
statusElem.innerHTML = "Tailscale Login";
|
||||
resolveLogin(url);
|
||||
};
|
||||
const stateUpdateCb = (state) => {
|
||||
switch(state)
|
||||
{
|
||||
case State.NeedsLogin:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.Running:
|
||||
{
|
||||
if (loginElemUrl) {
|
||||
loginElem.href = loginElemUrl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State.Starting:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.Stopped:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.NoState:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
const netmapUpdateCb = (map) => {
|
||||
const ip = map.self.addresses[0];
|
||||
statusElem.innerHTML = "IP: "+ip;
|
||||
};
|
||||
const { listen, connect, bind, up } = await autoConf({
|
||||
loginUrlCb,
|
||||
stateUpdateCb,
|
||||
netmapUpdateCb,
|
||||
authKey,
|
||||
controlUrl,
|
||||
});
|
||||
window.networkInterface.bind = bind;
|
||||
window.networkInterface.connect = connect;
|
||||
window.networkInterface.listen = listen;
|
||||
window.networkInterface.ready = true;
|
||||
loginElem.style.cursor = "pointer";
|
||||
statusElem.style.color = "white";
|
||||
if (authKey) {
|
||||
if (loginElemUrl) {
|
||||
loginElem.href = loginElemUrl;
|
||||
loginElem.target = "_blank";
|
||||
}
|
||||
up();
|
||||
} else {
|
||||
loginElem.onclick = () => {
|
||||
loginElem.onclick = null;
|
||||
statusElem.innerHTML = "Downloading network code...";
|
||||
const w = window.open("login.html", "_blank");
|
||||
async function waitLogin() {
|
||||
await up();
|
||||
statusElem.innerHTML = "Starting login...";
|
||||
const url = await loginPromise;
|
||||
w.location.href = url;
|
||||
}
|
||||
waitLogin();
|
||||
};
|
||||
}
|
|
@ -30,81 +30,12 @@
|
|||
<link rel="stylesheet" id="us-fonts-css" href="https://fonts.googleapis.com/css?family=Montserrat%3A300%2C400%2C500%2C600%2C700&display=swap&ver=6.0.2" media="all">
|
||||
<link rel="stylesheet" href="./xterm/xterm.css" />
|
||||
<link rel="stylesheet" href="./scrollbar.css" />
|
||||
<script src="./xterm/xterm.js"></script>
|
||||
<script src="./xterm/xterm-addon-fit.js"></script>
|
||||
<script>
|
||||
window.networkInterface = { bind: null, connect: null, listen: null, ready: false };
|
||||
</script>
|
||||
<script src="./xterm/xterm.js"></script>
|
||||
<script src="./xterm/xterm-addon-fit.js"></script>
|
||||
<script defer type="module">
|
||||
import { State } from "/tun/tailscale_tun.js";
|
||||
import { autoConf } from "/tun/tailscale_tun_auto.js";
|
||||
|
||||
let resolveLogin = null;
|
||||
let loginPromise = new Promise((f,r) => {
|
||||
resolveLogin = f;
|
||||
});
|
||||
const loginElem = document.getElementById("loginLink");
|
||||
const statusElem = document.getElementById("networkStatus");
|
||||
const loginUrlCb = (url) => {
|
||||
loginElem.href = url;
|
||||
loginElem.target = "_blank";
|
||||
statusElem.innerHTML = "Tailscale Login";
|
||||
resolveLogin(url);
|
||||
};
|
||||
const stateUpdateCb = (state) => {
|
||||
switch(state)
|
||||
{
|
||||
case State.NeedsLogin:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.Running:
|
||||
{
|
||||
loginElem.href = "https://login.tailscale.com/admin/machines";
|
||||
break;
|
||||
}
|
||||
case State.Starting:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.Stopped:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case State.NoState:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
const netmapUpdateCb = (map) => {
|
||||
const ip = map.self.addresses[0];
|
||||
statusElem.innerHTML = "IP: "+ip;
|
||||
};
|
||||
const { listen, connect, bind, up } = await autoConf({
|
||||
loginUrlCb,
|
||||
stateUpdateCb,
|
||||
netmapUpdateCb,
|
||||
});
|
||||
window.networkInterface.bind = bind;
|
||||
window.networkInterface.connect = connect;
|
||||
window.networkInterface.listen = listen;
|
||||
window.networkInterface.ready = true;
|
||||
loginElem.style.cursor = "pointer";
|
||||
statusElem.style.color = "white";
|
||||
loginElem.onclick = () => {
|
||||
loginElem.onclick = null;
|
||||
statusElem.innerHTML = "Downloading network code...";
|
||||
const w = window.open("login.html", "_blank");
|
||||
async function waitLogin() {
|
||||
await up();
|
||||
statusElem.innerHTML = "Starting login...";
|
||||
const url = await loginPromise;
|
||||
w.location.href = url;
|
||||
}
|
||||
waitLogin();
|
||||
};
|
||||
</script>
|
||||
<script type="module" src="network.js"></script>
|
||||
</head>
|
||||
|
||||
<body style="margin:0;height:100%;background:black;color:white;overflow:hidden; display:flex; flex-direction: column; justify-content: space-between; height: 100%;">
|
||||
|
@ -319,7 +250,7 @@
|
|||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
|
||||
var cxFile = "https://cheerpxdemos.leaningtech.com/publicdeploy/20221125/cx.js";
|
||||
var cxFile = "https://cheerpxdemos.leaningtech.com/publicdeploy/CX_VERSION/cx.js";
|
||||
script.src = cxFile;
|
||||
script.addEventListener("load", runInit, false);
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
BIN
tun/ipstack.wasm
BIN
tun/ipstack.wasm
Binary file not shown.
BIN
tun/tailscale.wasm
Executable file → Normal file
BIN
tun/tailscale.wasm
Executable file → Normal file
Binary file not shown.
|
@ -51,7 +51,7 @@ export async function init() {
|
|||
IpStack.input(ev.data)
|
||||
};
|
||||
IpStack.output(function(p){
|
||||
ipn.tun.postMessage(p);
|
||||
ipn.tun.postMessage(p, [p.buffer]);
|
||||
});
|
||||
};
|
||||
setupIpStack();
|
||||
|
@ -65,10 +65,15 @@ export async function init() {
|
|||
if (localIp != newLocalIp)
|
||||
{
|
||||
localIp = newLocalIp;
|
||||
IpStack.up({localIp, ipMap: {
|
||||
try{
|
||||
IpStack.up({localIp, dnsIp, ipMap: {
|
||||
["127.0.0.53"]: dnsIp,
|
||||
[dnsIp]: "127.0.0.53",
|
||||
}});
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
debugger;
|
||||
}
|
||||
}
|
||||
},
|
||||
notifyBrowseToURL: (l) => listeners.onloginurl(l),
|
||||
|
@ -82,6 +87,7 @@ export async function init() {
|
|||
listen: IpStack.listen,
|
||||
bind: IpStack.bind,
|
||||
parseIP: IpStack.parseIP,
|
||||
resolve: IpStack.resolve,
|
||||
up: async (conf) => {
|
||||
if (ipn == null) {
|
||||
await lazyRunIpn();
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
import {State, init} from "./tailscale_tun.js";
|
||||
|
||||
export async function autoConf({loginUrlCb, stateUpdateCb, netmapUpdateCb}) {
|
||||
const { listen, connect, bind, parseIP, up, down, login, logout, listeners } = await init();
|
||||
|
||||
const getSettings = () => {
|
||||
settings.controlUrl = null;
|
||||
settings.exitNodeIp = null;
|
||||
settings.dnsIp = null;
|
||||
settings.wantsRunning = true;
|
||||
};
|
||||
export async function autoConf({loginUrlCb, stateUpdateCb, netmapUpdateCb, controlUrl, authKey}) {
|
||||
const { listen, connect, bind, parseIP, resolve, up, down, login, logout, listeners } = await init();
|
||||
|
||||
const settings = {
|
||||
controlUrl: undefined,
|
||||
controlUrl: controlUrl,
|
||||
authKey: authKey,
|
||||
exitNodeIp: undefined,
|
||||
dnsIp: undefined,
|
||||
wantsRunning: true,
|
||||
|
@ -75,6 +69,7 @@ export async function autoConf({loginUrlCb, stateUpdateCb, netmapUpdateCb}) {
|
|||
connect,
|
||||
listen,
|
||||
parseIP,
|
||||
resolve,
|
||||
up: async () => {
|
||||
await up(settings);
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue