pinokiod 3.16.4 → 3.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/kernel/bin/index.js +0 -3
- package/kernel/bin/py.js +0 -1
- package/kernel/peer.js +1 -0
- package/kernel/procs.js +5 -0
- package/package.json +1 -1
- package/server/index.js +0 -1
- package/server/public/https.png +0 -0
- package/server/public/peernet.png +0 -0
- package/server/public/peers.png +0 -0
- package/server/public/style.css +14 -0
- package/server/views/network.ejs +128 -108
- package/server/views/old_network.ejs +874 -0
package/kernel/bin/index.js
CHANGED
|
@@ -957,7 +957,6 @@ class Bin {
|
|
|
957
957
|
let dependencies
|
|
958
958
|
if (r.name === "conda") {
|
|
959
959
|
dependencies = config.bin.conda_requirements
|
|
960
|
-
console.log("check dependencies", dependencies)
|
|
961
960
|
requirements[i].dependencies = dependencies
|
|
962
961
|
}
|
|
963
962
|
let installed = await this.check_installed(r, dependencies)
|
|
@@ -980,8 +979,6 @@ class Bin {
|
|
|
980
979
|
this.install_required = install_required
|
|
981
980
|
this.requirements_pending = requirements_pending
|
|
982
981
|
|
|
983
|
-
console.log("check_bin finished 2")
|
|
984
|
-
|
|
985
982
|
requirements = requirements.filter((r) => {
|
|
986
983
|
return r.relevant
|
|
987
984
|
})
|
package/kernel/bin/py.js
CHANGED
package/kernel/peer.js
CHANGED
package/kernel/procs.js
CHANGED
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -3416,7 +3416,6 @@ class Server {
|
|
|
3416
3416
|
bin: this.kernel.bin.preset("network"),
|
|
3417
3417
|
})
|
|
3418
3418
|
|
|
3419
|
-
console.log({ requirements_pending, install_required })
|
|
3420
3419
|
if (!requirements_pending && install_required) {
|
|
3421
3420
|
console.log("redirect to /setup/network")
|
|
3422
3421
|
res.redirect("/setup/network?callback=/network")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/server/public/style.css
CHANGED
|
@@ -267,6 +267,20 @@ footer .toggle-expand {
|
|
|
267
267
|
footer pre {
|
|
268
268
|
background: none !important;
|
|
269
269
|
}
|
|
270
|
+
.swal2-popup.full-popup img {
|
|
271
|
+
width: 100%;
|
|
272
|
+
}
|
|
273
|
+
.swal2-popup.full-popup {
|
|
274
|
+
max-width: 800px;
|
|
275
|
+
width: 100%;
|
|
276
|
+
}
|
|
277
|
+
.full-modal {
|
|
278
|
+
font-size: 14px;
|
|
279
|
+
text-align: left;
|
|
280
|
+
}
|
|
281
|
+
.swal2-title.full-title {
|
|
282
|
+
text-align: left;
|
|
283
|
+
}
|
|
270
284
|
.swal2-popup.min-popup a {
|
|
271
285
|
outline: none;
|
|
272
286
|
}
|
package/server/views/network.ejs
CHANGED
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
text-decoration: none;
|
|
28
28
|
color: black;
|
|
29
29
|
}
|
|
30
|
+
ol {
|
|
31
|
+
padding-inline-start: 15px;
|
|
32
|
+
}
|
|
33
|
+
a.explain {
|
|
34
|
+
color: royalblue;
|
|
35
|
+
text-decoration: underline;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
30
38
|
.status {
|
|
31
39
|
padding: 10px;
|
|
32
40
|
margin: 10px;
|
|
@@ -245,7 +253,7 @@ td:first-child, th:first-child {
|
|
|
245
253
|
vertical-align: top;
|
|
246
254
|
border-bottom: 1px solid rgba(0,0,0,0.05);
|
|
247
255
|
text-align: left;
|
|
248
|
-
padding: 20px
|
|
256
|
+
padding: 20px 5px;
|
|
249
257
|
font-weight: normal;
|
|
250
258
|
font-size: 12px;
|
|
251
259
|
margin-bottom: 10px;
|
|
@@ -256,7 +264,7 @@ td:first-child, th:first-child {
|
|
|
256
264
|
.container-row td {
|
|
257
265
|
vertical-align: top;
|
|
258
266
|
font-size: 14px;
|
|
259
|
-
padding: 5px
|
|
267
|
+
padding: 5px;
|
|
260
268
|
word-wrap: break-word;
|
|
261
269
|
}
|
|
262
270
|
|
|
@@ -379,6 +387,9 @@ input:checked + .slider:before {
|
|
|
379
387
|
flex-grow: 1;
|
|
380
388
|
padding: 10px;
|
|
381
389
|
}
|
|
390
|
+
table h3 {
|
|
391
|
+
margin: 0;
|
|
392
|
+
}
|
|
382
393
|
|
|
383
394
|
|
|
384
395
|
@media only screen and (max-width: 480px) {
|
|
@@ -423,7 +434,11 @@ input:checked + .slider:before {
|
|
|
423
434
|
<div class='config'>
|
|
424
435
|
<div class='config-header'>
|
|
425
436
|
<div class='header-label'><i class='fa-solid fa-wifi'></i> Network</div>
|
|
426
|
-
<div class='desc'>Instant HTTPS for every app on your local network.</div>
|
|
437
|
+
<div class='desc'>Instant HTTPS and Peer network for every app on your local network.</div>
|
|
438
|
+
<ol>
|
|
439
|
+
<li><strong>Instant HTTPS</strong> <a class='explain' data-type='https'>Learn more</a></li>
|
|
440
|
+
<li><strong>Local Peer-to-Peer Network</strong> <a class='explain' data-type='peer'>Learn more</a></li>
|
|
441
|
+
</ol>
|
|
427
442
|
</div>
|
|
428
443
|
<div class='config-body'>
|
|
429
444
|
<div class='config-row'>
|
|
@@ -465,121 +480,73 @@ input:checked + .slider:before {
|
|
|
465
480
|
</div>
|
|
466
481
|
<% } else { %>
|
|
467
482
|
<div class='header-label-sub'>
|
|
468
|
-
<h1><i class="fa-solid fa-wifi"></i> <%=name
|
|
483
|
+
<h1><i class="fa-solid fa-wifi"></i> <%=name%> (peer)</h1>
|
|
469
484
|
<div class='s'><i class="fa-brands fa-<%=brands[platform]%>"></i> <%=platform%> <%=host%></div>
|
|
470
485
|
</div>
|
|
471
486
|
<% } %>
|
|
472
487
|
<table>
|
|
473
|
-
|
|
474
|
-
<
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
<
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
<a class='ln' target="_blank" href="http://<%=item.external_ip%>">http://<%=item.external_ip%></a>
|
|
490
|
-
</div>
|
|
491
|
-
<% } %>
|
|
492
|
-
</td>
|
|
493
|
-
<td>
|
|
494
|
-
<% item.internal_router.forEach((domain) => { %>
|
|
488
|
+
<% if (current_host === host) { %>
|
|
489
|
+
<tr>
|
|
490
|
+
<th><h2>App</h2><div>All servers on this machine</div></th>
|
|
491
|
+
<th><h2>Local</h2><div>endpoints accessible from this machine</div></th>
|
|
492
|
+
<th><h2>Network</h2><div>endpoints accessible from any machine on the local network</div></th>
|
|
493
|
+
<th><h2>Peer</h2><div>endpoints accessible from any pinokio peer on the local network <a class='explain' data-type='peer'>How to start a peer</a></div></th>
|
|
494
|
+
</tr>
|
|
495
|
+
<% processes.forEach((item) => { %>
|
|
496
|
+
<tr>
|
|
497
|
+
<td class='title'><%=item.name%></td>
|
|
498
|
+
<td>
|
|
499
|
+
<% item.internal_router.forEach((domain) => { %>
|
|
500
|
+
<div>
|
|
501
|
+
<a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
|
|
502
|
+
</div>
|
|
503
|
+
<% }) %>
|
|
495
504
|
<div>
|
|
496
|
-
<a class='ln' target="_blank" href="
|
|
505
|
+
<a class='ln' target="_blank" href="http://localhost:<%=item.port%>">http://localhost:<%=item.port%></a>
|
|
497
506
|
</div>
|
|
498
|
-
|
|
499
|
-
<
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
507
|
+
</td>
|
|
508
|
+
<td>
|
|
509
|
+
<% if (item.external_ip) { %>
|
|
510
|
+
<div>
|
|
511
|
+
<a class='ln' target="_blank" href="http://<%=item.external_ip%>">http://<%=item.external_ip%></a>
|
|
512
|
+
</div>
|
|
513
|
+
<% } %>
|
|
514
|
+
</td>
|
|
515
|
+
<td>
|
|
516
|
+
<% item.external_router.forEach((domain) => { %>
|
|
517
|
+
<div>
|
|
518
|
+
<a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
|
|
519
|
+
</div>
|
|
520
|
+
<% }) %>
|
|
521
|
+
</td>
|
|
522
|
+
</tr>
|
|
523
|
+
<% }) %>
|
|
524
|
+
<% } else { %>
|
|
525
|
+
<tr>
|
|
526
|
+
<th><h2>App</h2><div>All servers on this machine</div></th>
|
|
527
|
+
<th><h2>Endpoints</h2><div>accessible through peer network</div></th>
|
|
503
528
|
</tr>
|
|
504
|
-
|
|
529
|
+
<% processes.forEach((item) => { %>
|
|
530
|
+
<tr>
|
|
531
|
+
<td class='title'><%=item.name%></td>
|
|
532
|
+
<td>
|
|
533
|
+
<% if (item.external_ip) { %>
|
|
534
|
+
<div>
|
|
535
|
+
<a class='ln' target="_blank" href="http://<%=item.external_ip%>">http://<%=item.external_ip%></a>
|
|
536
|
+
</div>
|
|
537
|
+
<% } %>
|
|
538
|
+
<% item.external_router.forEach((domain) => { %>
|
|
539
|
+
<div>
|
|
540
|
+
<a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
|
|
541
|
+
</div>
|
|
542
|
+
<% }) %>
|
|
543
|
+
</td>
|
|
544
|
+
</tr>
|
|
545
|
+
<% }) %>
|
|
546
|
+
<% } %>
|
|
505
547
|
</table>
|
|
506
548
|
</div>
|
|
507
549
|
<% }) %>
|
|
508
|
-
<div class='container-row hidden'>
|
|
509
|
-
<div class='header-label-sub'><i class="fa-solid fa-microchip"></i> System Programs</div>
|
|
510
|
-
<div class='line align-top'>
|
|
511
|
-
<h3>
|
|
512
|
-
<img class='icon' src="<%=icon%>">
|
|
513
|
-
<div class='col'>
|
|
514
|
-
<div class='title'>Pinokio</div>
|
|
515
|
-
<% if (proxy) { %>
|
|
516
|
-
<div class='description'><a href="<%=proxy.proxy%>" target="_blank"><%=proxy.proxy%></a> → <a href="<%=localhost%>" target="_blank"><%=localhost%></a></div>
|
|
517
|
-
<a class='wifi-qr badge' data-qr="<%=qr%>" data-url="<%=proxy.proxy%>"><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
|
|
518
|
-
<% } else { %>
|
|
519
|
-
<div class='description'>Share Pinokio <a href="<%=localhost%>" target="_blank"><%=localhost%></a> with other devices on the same network</div>
|
|
520
|
-
<% } %>
|
|
521
|
-
<div class='btn-container'>
|
|
522
|
-
<% if (proxy) { %>
|
|
523
|
-
<div id='wifi-stop' data-proxy="<%=proxy.proxy%>" class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></div>
|
|
524
|
-
<% } else { %>
|
|
525
|
-
<div id='wifi' class='btn'><div><i class="fa-solid fa-play"></i> Start</div></div>
|
|
526
|
-
<div id='wifi-starting' class='btn disabled hidden'><div><i class="fa-solid fa-circle-notch fa-spin"></i> Starting</div></div>
|
|
527
|
-
<% } %>
|
|
528
|
-
</div>
|
|
529
|
-
</div>
|
|
530
|
-
</h3>
|
|
531
|
-
</div>
|
|
532
|
-
<% items.forEach((item) => { %>
|
|
533
|
-
<div class='line align-top'>
|
|
534
|
-
<h3>
|
|
535
|
-
<img class='icon' src="<%=item.icon%>">
|
|
536
|
-
<div class='col'>
|
|
537
|
-
<div class='title'><%=item.name%></div>
|
|
538
|
-
<% if (item.proxy) { %>
|
|
539
|
-
<div class='description'><a href="<%=item.proxy%>" target="_blank"><%=item.proxy%></a> → <a href="<%=item.target%>" target="_blank"><%=item.target%></a></div>
|
|
540
|
-
<a class='wifi-qr badge' data-qr="<%=item.qr%>" data-url="<%=item.proxy%>"><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
|
|
541
|
-
<% } else { %>
|
|
542
|
-
<div class='description'>Share <%=item.target%> with other devices on the same network</div>
|
|
543
|
-
<% } %>
|
|
544
|
-
<div class='btn-container'>
|
|
545
|
-
<% if (item.running) { %>
|
|
546
|
-
<div data-port="<%=item.port%>" data-name="<%=item.name%>" data-target="<%=item.target%>" class='stop btn'><i class="fa-solid fa-stop"></i> Stop</div>
|
|
547
|
-
<% } else { %>
|
|
548
|
-
<div data-port="<%=item.port%>" data-name="<%=item.name%>" data-target="<%=item.target%>" class='start btn'><i class="fa-solid fa-play"></i> Start at port <%=item.port%></div>
|
|
549
|
-
<% } %>
|
|
550
|
-
</div>
|
|
551
|
-
</div>
|
|
552
|
-
</h3>
|
|
553
|
-
</div>
|
|
554
|
-
<% }) %>
|
|
555
|
-
</div>
|
|
556
|
-
<!--
|
|
557
|
-
<div class='container-row'>
|
|
558
|
-
<div class='header-label-sub'><i class="fa-solid fa-dice-d6"></i> Pinokio</div>
|
|
559
|
-
<% apps.forEach((item) => { %>
|
|
560
|
-
<a class='line align-top' href="<%=item.link%>">
|
|
561
|
-
<h3>
|
|
562
|
-
<% if (item.icon) { %>
|
|
563
|
-
<img class='icon' src="<%=item.icon%>">
|
|
564
|
-
<% } else { %>
|
|
565
|
-
<% if (theme === 'dark') { %>
|
|
566
|
-
<img class='icon' src="/pinokio-white.png">
|
|
567
|
-
<% } else { %>
|
|
568
|
-
<img class='icon' src="/pinokio-black.png">
|
|
569
|
-
<% } %>
|
|
570
|
-
<% } %>
|
|
571
|
-
<div class='col'>
|
|
572
|
-
<div class='title'><%=item.name%></div>
|
|
573
|
-
<div class='description'><%=item.description%></div>
|
|
574
|
-
</div>
|
|
575
|
-
<div class='spinner'>
|
|
576
|
-
<i class="fa-solid fa-chevron-right"></i>
|
|
577
|
-
</div>
|
|
578
|
-
</h3>
|
|
579
|
-
</a>
|
|
580
|
-
<% }) %>
|
|
581
|
-
</div>
|
|
582
|
-
-->
|
|
583
550
|
</div>
|
|
584
551
|
<% } %>
|
|
585
552
|
</main>
|
|
@@ -663,6 +630,59 @@ document.querySelector("#active").addEventListener("change", (e)=> {
|
|
|
663
630
|
document.querySelector("main").addEventListener("click", async (e) => {
|
|
664
631
|
let target
|
|
665
632
|
|
|
633
|
+
if (e.target.classList.contains("explain")) {
|
|
634
|
+
target = e.target
|
|
635
|
+
} else {
|
|
636
|
+
target = e.target.closest(".explain")
|
|
637
|
+
}
|
|
638
|
+
if (target) {
|
|
639
|
+
e.preventDefault()
|
|
640
|
+
e.stopPropagation()
|
|
641
|
+
let type = target.getAttribute("data-type")
|
|
642
|
+
if (type === "https") {
|
|
643
|
+
await Swal.fire({
|
|
644
|
+
title: "Instant HTTPS",
|
|
645
|
+
customClass: {
|
|
646
|
+
popup: "full-popup",
|
|
647
|
+
title: "full-title"
|
|
648
|
+
},
|
|
649
|
+
showConfirmButton: false,
|
|
650
|
+
html: `<div class='full-modal'>
|
|
651
|
+
<ol>
|
|
652
|
+
<li><strong>Instant:</strong> Pinokio automatically turns ALL your local applications into HTTPS.</li>
|
|
653
|
+
<li><strong>System-wide:</strong> Instant HTTPS automagically works for ALL your local apps and APIs system-wide (not just those installed on pinokio)</li>
|
|
654
|
+
<li><strong>Not just for Pinokio:</strong> This means, even the apis and apps that have nothing to do with Pinokio (such as Ollama, LMStudio, or really anything) become HTTPS-ified.</li>
|
|
655
|
+
<li><strong>Whole New Application Architecture:</strong> Exposing localhost apps over HTTPS unlocks powerful new possibilities. It enables a completely new application architecture where public websites can securely leverage your local APIs as backend services.</li>
|
|
656
|
+
</ol>
|
|
657
|
+
<img src="/https.png"/>
|
|
658
|
+
<br>
|
|
659
|
+
</div>`
|
|
660
|
+
})
|
|
661
|
+
} else if (type === "peer") {
|
|
662
|
+
await Swal.fire({
|
|
663
|
+
title: "Peer to Peer HTTPS Local Network",
|
|
664
|
+
customClass: {
|
|
665
|
+
popup: "full-popup",
|
|
666
|
+
title: "full-title"
|
|
667
|
+
},
|
|
668
|
+
showConfirmButton: false,
|
|
669
|
+
html: `<div class='full-modal'>
|
|
670
|
+
<div>Peers can access each other over HTTPS. It's like a whole internet, but among your local machines.</div>
|
|
671
|
+
<br>
|
|
672
|
+
<img src="/peernet.png"/>
|
|
673
|
+
<br>
|
|
674
|
+
<div>To start a peer, install Pinokio on any other machine on the same network.</div>
|
|
675
|
+
<br>
|
|
676
|
+
<div>Peers automatically discover each other and display accessible apps and endpoints from other machines:</div>
|
|
677
|
+
<br>
|
|
678
|
+
<img src="/peers.png"/>
|
|
679
|
+
<br>
|
|
680
|
+
</div>`
|
|
681
|
+
})
|
|
682
|
+
}
|
|
683
|
+
return
|
|
684
|
+
}
|
|
685
|
+
|
|
666
686
|
if (e.target.classList.contains("save")) {
|
|
667
687
|
target = e.target
|
|
668
688
|
} else {
|
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Pinokio</title>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
|
6
|
+
<link href="/xterm.min.css" rel="stylesheet" />
|
|
7
|
+
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
|
8
|
+
<link href="/css/solid.min.css" rel="stylesheet">
|
|
9
|
+
<link href="/css/regular.min.css" rel="stylesheet">
|
|
10
|
+
<link href="/css/brands.min.css" rel="stylesheet">
|
|
11
|
+
<link href="/markdown.css" rel="stylesheet"/>
|
|
12
|
+
<link href="/noty.css" rel="stylesheet"/>
|
|
13
|
+
<link href="/style.css" rel="stylesheet"/>
|
|
14
|
+
<script src="/sweetalert2.js"></script>
|
|
15
|
+
<script src="/commander.js"></script>
|
|
16
|
+
<% if (agent === "electron") { %>
|
|
17
|
+
<link href="/electron.css" rel="stylesheet"/>
|
|
18
|
+
<% } %>
|
|
19
|
+
<style>
|
|
20
|
+
.line2 {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
background: rgba(0,0,100,0.04);
|
|
25
|
+
}
|
|
26
|
+
.line2 a {
|
|
27
|
+
text-decoration: none;
|
|
28
|
+
color: black;
|
|
29
|
+
}
|
|
30
|
+
.status {
|
|
31
|
+
padding: 10px;
|
|
32
|
+
margin: 10px;
|
|
33
|
+
border-radius: 10px;
|
|
34
|
+
}
|
|
35
|
+
.status.offline {
|
|
36
|
+
background: silver;
|
|
37
|
+
}
|
|
38
|
+
.status.online {
|
|
39
|
+
background: yellowgreen;
|
|
40
|
+
}
|
|
41
|
+
.switch {
|
|
42
|
+
padding: 10px;
|
|
43
|
+
margin: 10px 0;
|
|
44
|
+
}
|
|
45
|
+
.switch[data-online=true] {
|
|
46
|
+
color: yellowgreen;
|
|
47
|
+
}
|
|
48
|
+
.button {
|
|
49
|
+
padding: 10px;
|
|
50
|
+
}
|
|
51
|
+
.on, .off {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
}
|
|
55
|
+
header .runner {
|
|
56
|
+
padding: 10px 0 0;
|
|
57
|
+
}
|
|
58
|
+
.proc-table {
|
|
59
|
+
display: flex;
|
|
60
|
+
}
|
|
61
|
+
.proc-table .title {
|
|
62
|
+
flex-grow: 1;
|
|
63
|
+
}
|
|
64
|
+
.proxy {
|
|
65
|
+
padding: 0 10px;
|
|
66
|
+
text-align: right;
|
|
67
|
+
}
|
|
68
|
+
.proxy a {
|
|
69
|
+
text-decoration: none;
|
|
70
|
+
display: inline-block;
|
|
71
|
+
padding: 5px 10px;
|
|
72
|
+
border-radius: 2px;
|
|
73
|
+
background: black;
|
|
74
|
+
color: white;
|
|
75
|
+
}
|
|
76
|
+
.browser-options-btns {
|
|
77
|
+
display: flex;
|
|
78
|
+
padding-top: 5px;
|
|
79
|
+
}
|
|
80
|
+
.browser-options-row {
|
|
81
|
+
border-top: 1px solid rgba(0,0,0,0.1);
|
|
82
|
+
border-bottom: 1px solid rgba(0,0,0,0.1);
|
|
83
|
+
display: flex;
|
|
84
|
+
padding: 20px 0;
|
|
85
|
+
align-items: flex-start;
|
|
86
|
+
}
|
|
87
|
+
.browser-options-row h3 {
|
|
88
|
+
margin: 0;
|
|
89
|
+
font-size: 14px;
|
|
90
|
+
margin-bottom: 3px;
|
|
91
|
+
}
|
|
92
|
+
.line.align-top h3.table-grid {
|
|
93
|
+
display: grid;
|
|
94
|
+
grid-template-columns: repeat(3, 1fr);
|
|
95
|
+
}
|
|
96
|
+
.browser-options-row .btn.disabled {
|
|
97
|
+
opacity: 0.7;
|
|
98
|
+
}
|
|
99
|
+
.browser-options-row .btn {
|
|
100
|
+
font-weight: bold;
|
|
101
|
+
width: 100px;
|
|
102
|
+
text-align: center;
|
|
103
|
+
display: block;
|
|
104
|
+
margin-right: 10px;
|
|
105
|
+
flex-shrink: 0;
|
|
106
|
+
padding: 5px;
|
|
107
|
+
}
|
|
108
|
+
.badge {
|
|
109
|
+
font-size: 12px;
|
|
110
|
+
padding: 5px 10px;
|
|
111
|
+
background: rgba(0,0,100,0.1);
|
|
112
|
+
border-radius: 5px;
|
|
113
|
+
display: inline-block;
|
|
114
|
+
margin-top: 5px;
|
|
115
|
+
}
|
|
116
|
+
a.badge {
|
|
117
|
+
color: royalblue;
|
|
118
|
+
text-decoration: none;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
}
|
|
121
|
+
.badge a {
|
|
122
|
+
color: royalblue;
|
|
123
|
+
text-decoration: none;
|
|
124
|
+
}
|
|
125
|
+
body.dark .btn {
|
|
126
|
+
color: white;
|
|
127
|
+
border: 1px solid rgba(255,255,255,0.3);
|
|
128
|
+
}
|
|
129
|
+
body.dark .badge {
|
|
130
|
+
background: rgba(255,255,255,0.1);
|
|
131
|
+
}
|
|
132
|
+
body.dark .browser-options-row {
|
|
133
|
+
border-top: 1px solid rgba(255,255,255,0.05);
|
|
134
|
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
|
135
|
+
}
|
|
136
|
+
.description a {
|
|
137
|
+
color: royalblue;
|
|
138
|
+
text-decoration: none;
|
|
139
|
+
}
|
|
140
|
+
a.ln[href^=https] {
|
|
141
|
+
color: #56ad00;
|
|
142
|
+
}
|
|
143
|
+
a.ln:hover {
|
|
144
|
+
color: red !important;
|
|
145
|
+
}
|
|
146
|
+
.line.align-top h3 {
|
|
147
|
+
/*
|
|
148
|
+
align-items: flex-start;
|
|
149
|
+
*/
|
|
150
|
+
align-items: center;
|
|
151
|
+
}
|
|
152
|
+
.line a:hover {
|
|
153
|
+
color: red;
|
|
154
|
+
}
|
|
155
|
+
.line img {
|
|
156
|
+
width: 40px;
|
|
157
|
+
height: 40px;
|
|
158
|
+
}
|
|
159
|
+
.btn-container {
|
|
160
|
+
margin-top: 10px;
|
|
161
|
+
}
|
|
162
|
+
.header-label {
|
|
163
|
+
padding: 0;
|
|
164
|
+
font-size: 50px;
|
|
165
|
+
letter-spacing: -2px;
|
|
166
|
+
font-weight: lighter;
|
|
167
|
+
/*
|
|
168
|
+
text-align: center;
|
|
169
|
+
*/
|
|
170
|
+
text-transform: capitalize;
|
|
171
|
+
}
|
|
172
|
+
.header-label-sub h1 {
|
|
173
|
+
font-size: 25px;
|
|
174
|
+
letter-spacing: -1px;
|
|
175
|
+
font-weight: lighter;
|
|
176
|
+
}
|
|
177
|
+
.header-label-sub {
|
|
178
|
+
font-size: 16px;
|
|
179
|
+
padding: 10px 0;
|
|
180
|
+
border-bottom: 1px solid rgba(0,0,0,0.1);
|
|
181
|
+
}
|
|
182
|
+
.header-label-sub .s {
|
|
183
|
+
padding: 10px 0;
|
|
184
|
+
opacity: 0.7;
|
|
185
|
+
}
|
|
186
|
+
.header-container {
|
|
187
|
+
margin: 10px;
|
|
188
|
+
background: rgba(0, 0, 100, 0.04);
|
|
189
|
+
padding: 20px;
|
|
190
|
+
box-sizing: border-box;
|
|
191
|
+
}
|
|
192
|
+
.container {
|
|
193
|
+
display: grid;
|
|
194
|
+
grid-template-columns: repeat(<%=list.length%>, 1fr);
|
|
195
|
+
}
|
|
196
|
+
.dark .container-row {
|
|
197
|
+
background: rgba(255, 255, 255, 0.04);
|
|
198
|
+
}
|
|
199
|
+
.container-row {
|
|
200
|
+
background: rgba(0, 0, 100, 0.04);
|
|
201
|
+
padding: 15px 30px;
|
|
202
|
+
box-sizing: border-box;
|
|
203
|
+
}
|
|
204
|
+
.container-row.current .header-label-sub {
|
|
205
|
+
color: royalblue;
|
|
206
|
+
}
|
|
207
|
+
/*
|
|
208
|
+
.container-row.current .header-label-sub {
|
|
209
|
+
color: royalblue;
|
|
210
|
+
}
|
|
211
|
+
*/
|
|
212
|
+
.desc {
|
|
213
|
+
/*
|
|
214
|
+
text-align:center;
|
|
215
|
+
*/
|
|
216
|
+
padding: 10px 0;
|
|
217
|
+
}
|
|
218
|
+
#reset-label {
|
|
219
|
+
color: firebrick;
|
|
220
|
+
}
|
|
221
|
+
.link-label {
|
|
222
|
+
margin-right: 10px;
|
|
223
|
+
text-decoration: underline;
|
|
224
|
+
color: royalblue;
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
}
|
|
227
|
+
.container-row table {
|
|
228
|
+
width: 100%;
|
|
229
|
+
table-layout: fixed;
|
|
230
|
+
}
|
|
231
|
+
table a {
|
|
232
|
+
text-decoration: none;
|
|
233
|
+
color: royalblue;
|
|
234
|
+
}
|
|
235
|
+
td:first-child, th:first-child {
|
|
236
|
+
max-width: 100px;
|
|
237
|
+
}
|
|
238
|
+
.container-row th h2 {
|
|
239
|
+
font-weight: lighter;
|
|
240
|
+
font-size: 18px;
|
|
241
|
+
margin: 0;
|
|
242
|
+
text-transform: uppercase;
|
|
243
|
+
}
|
|
244
|
+
.container-row th {
|
|
245
|
+
vertical-align: top;
|
|
246
|
+
border-bottom: 1px solid rgba(0,0,0,0.05);
|
|
247
|
+
text-align: left;
|
|
248
|
+
padding: 20px 0;
|
|
249
|
+
font-weight: normal;
|
|
250
|
+
font-size: 12px;
|
|
251
|
+
margin-bottom: 10px;
|
|
252
|
+
}
|
|
253
|
+
.container-row td.title {
|
|
254
|
+
overflow-wrap: break-word;
|
|
255
|
+
}
|
|
256
|
+
.container-row td {
|
|
257
|
+
vertical-align: top;
|
|
258
|
+
font-size: 14px;
|
|
259
|
+
padding: 5px 2px;
|
|
260
|
+
word-wrap: break-word;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
body.dark .config {
|
|
264
|
+
color: white;
|
|
265
|
+
}
|
|
266
|
+
.config {
|
|
267
|
+
/*
|
|
268
|
+
background: rgba(0,0,0,0.9);
|
|
269
|
+
*/
|
|
270
|
+
color: black;
|
|
271
|
+
padding: 30px;
|
|
272
|
+
text-align: left;
|
|
273
|
+
}
|
|
274
|
+
.config-header {
|
|
275
|
+
}
|
|
276
|
+
.config-body {
|
|
277
|
+
display: flex;
|
|
278
|
+
align-items: flex-end;
|
|
279
|
+
}
|
|
280
|
+
.config .btn {
|
|
281
|
+
font-size: 16px;
|
|
282
|
+
font-weight: bold;
|
|
283
|
+
width: 100px;
|
|
284
|
+
background: royalblue;
|
|
285
|
+
flex-shrink: 0;
|
|
286
|
+
}
|
|
287
|
+
.config-row {
|
|
288
|
+
padding: 10px 20px 0 0;
|
|
289
|
+
}
|
|
290
|
+
.label {
|
|
291
|
+
padding-bottom: 5px;
|
|
292
|
+
font-weight: bold;
|
|
293
|
+
}
|
|
294
|
+
.config-row input[type=text] {
|
|
295
|
+
padding: 7px;
|
|
296
|
+
}
|
|
297
|
+
.btn.save {
|
|
298
|
+
padding: 8px;
|
|
299
|
+
}
|
|
300
|
+
.switcher {
|
|
301
|
+
position: relative;
|
|
302
|
+
display: inline-block;
|
|
303
|
+
width: 60px;
|
|
304
|
+
height: 34px;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.switcher input {
|
|
308
|
+
opacity: 0;
|
|
309
|
+
width: 0;
|
|
310
|
+
height: 0;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.slider {
|
|
314
|
+
position: absolute;
|
|
315
|
+
cursor: pointer;
|
|
316
|
+
top: 0;
|
|
317
|
+
left: 0;
|
|
318
|
+
right: 0;
|
|
319
|
+
bottom: 0;
|
|
320
|
+
background-color: #ccc;
|
|
321
|
+
-webkit-transition: .4s;
|
|
322
|
+
transition: .4s;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.slider:before {
|
|
326
|
+
position: absolute;
|
|
327
|
+
content: "";
|
|
328
|
+
height: 26px;
|
|
329
|
+
width: 26px;
|
|
330
|
+
left: 4px;
|
|
331
|
+
bottom: 4px;
|
|
332
|
+
background-color: white;
|
|
333
|
+
-webkit-transition: .4s;
|
|
334
|
+
transition: .4s;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
input:checked + .slider {
|
|
338
|
+
/*
|
|
339
|
+
background-color: #2196F3;
|
|
340
|
+
*/
|
|
341
|
+
background-color: royalblue;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
input:focus + .slider {
|
|
345
|
+
box-shadow: 0 0 1px #2196F3;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
input:checked + .slider:before {
|
|
349
|
+
-webkit-transform: translateX(26px);
|
|
350
|
+
-ms-transform: translateX(26px);
|
|
351
|
+
transform: translateX(26px);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/* Rounded sliders */
|
|
355
|
+
.slider.round {
|
|
356
|
+
border-radius: 34px;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.slider.round:before {
|
|
360
|
+
border-radius: 50%;
|
|
361
|
+
}
|
|
362
|
+
.loading {
|
|
363
|
+
text-align: center;
|
|
364
|
+
padding: 50px;
|
|
365
|
+
}
|
|
366
|
+
.advanced a.btn {
|
|
367
|
+
text-align: center;
|
|
368
|
+
}
|
|
369
|
+
.advanced {
|
|
370
|
+
margin: 20px 0;
|
|
371
|
+
}
|
|
372
|
+
.advanced h3 {
|
|
373
|
+
margin: 0 0 5px;
|
|
374
|
+
}
|
|
375
|
+
.advanced .row {
|
|
376
|
+
display: flex;
|
|
377
|
+
}
|
|
378
|
+
.advanced input[type=text] {
|
|
379
|
+
flex-grow: 1;
|
|
380
|
+
padding: 10px;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@media only screen and (max-width: 480px) {
|
|
385
|
+
.btn2 {
|
|
386
|
+
padding: 5px;
|
|
387
|
+
font-size: 11px;
|
|
388
|
+
}
|
|
389
|
+
.nav-btns {
|
|
390
|
+
flex-grow: 1;
|
|
391
|
+
justify-content: center;
|
|
392
|
+
padding: 0;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
</style>
|
|
396
|
+
<script src="/hotkeys.min.js"></script>
|
|
397
|
+
<script src="/sweetalert2.js"></script>
|
|
398
|
+
<script src="/common.js"></script>
|
|
399
|
+
<script src="/opener.js"></script>
|
|
400
|
+
</head>
|
|
401
|
+
<body class='<%=theme%>' data-agent="<%=agent%>">
|
|
402
|
+
<header class='navheader grabbable'>
|
|
403
|
+
<h1>
|
|
404
|
+
<a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
|
|
405
|
+
<button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
|
|
406
|
+
<button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
|
|
407
|
+
<button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
|
|
408
|
+
<a class='btn2 create-new' id='create-new-folder'><div><i class="fa-solid fa-folder-plus"></i></div><div>Create</div></a>
|
|
409
|
+
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
410
|
+
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
411
|
+
<div class='flexible'></div>
|
|
412
|
+
<div class='nav-btns'>
|
|
413
|
+
<a class='btn2' id='explore' href="/?mode=explore"><div><i class="fa-solid fa-magnifying-glass"></i></div><div>Discover</div></a>
|
|
414
|
+
<a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
|
|
415
|
+
<button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
|
|
416
|
+
<a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
|
|
417
|
+
<a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
|
|
418
|
+
<button id='new-window' title='open a new window' class='btn2' data-agent="<%=agent%>"><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
|
|
419
|
+
</div>
|
|
420
|
+
</h1>
|
|
421
|
+
</header>
|
|
422
|
+
<main>
|
|
423
|
+
<div class='config'>
|
|
424
|
+
<div class='config-header'>
|
|
425
|
+
<div class='header-label'><i class='fa-solid fa-wifi'></i> Network</div>
|
|
426
|
+
<div class='desc'>Instant HTTPS for every app on your local network.</div>
|
|
427
|
+
</div>
|
|
428
|
+
<div class='config-body'>
|
|
429
|
+
<div class='config-row'>
|
|
430
|
+
<div id='active-label' class='label'><%=peer_active ? "On" : "Off"%></div>
|
|
431
|
+
<label class="switcher">
|
|
432
|
+
<input id='active' type="checkbox" <%=peer_active ? 'checked' : ''%>>
|
|
433
|
+
<span class="slider"></span>
|
|
434
|
+
</label>
|
|
435
|
+
</div>
|
|
436
|
+
<div class='config-row' id='network_name'>
|
|
437
|
+
<div class='label'>Network Name</div>
|
|
438
|
+
<input id='name' type='text' value="<%=name%>">
|
|
439
|
+
</div>
|
|
440
|
+
<button class='btn save'>Save</button>
|
|
441
|
+
</div>
|
|
442
|
+
<div class='advanced'>
|
|
443
|
+
<div class='row'>
|
|
444
|
+
<div id='advanced-label' class='link-label label'>Advanced</div>
|
|
445
|
+
<div id='reset-label' class='link-label label'>Reset HTTPS Certificates</div>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
<div class='loading hidden'>
|
|
450
|
+
<i class="fa-solid fa-circle-notch fa-spin"></i> Stand by. Do not close this window..
|
|
451
|
+
</div>
|
|
452
|
+
<% if (requirements_pending) { %>
|
|
453
|
+
<div class='loading'>
|
|
454
|
+
<i class="fa-solid fa-circle-notch fa-spin"></i> Loading...
|
|
455
|
+
</div>
|
|
456
|
+
<% } else { %>
|
|
457
|
+
<div class='container'>
|
|
458
|
+
<% let brands = { win32: "windows", darwin: "apple", linux: "Linux" } %>
|
|
459
|
+
<% list.forEach(({ host, name, platform, processes }, index) => { %>
|
|
460
|
+
<div class='container-row <%=current_host === host ? 'current' : ''%>'>
|
|
461
|
+
<% if (current_host === host) { %>
|
|
462
|
+
<div class='header-label-sub'>
|
|
463
|
+
<h1><i class="fa-solid fa-podcast"></i> <%=name%> (this machine)</h1>
|
|
464
|
+
<div class='s'><i class="fa-brands fa-<%=brands[platform]%>"></i> <%=platform%> <%=host%></div>
|
|
465
|
+
</div>
|
|
466
|
+
<% } else { %>
|
|
467
|
+
<div class='header-label-sub'>
|
|
468
|
+
<h1><i class="fa-solid fa-wifi"></i> <%=name%></h1>
|
|
469
|
+
<div class='s'><i class="fa-brands fa-<%=brands[platform]%>"></i> <%=platform%> <%=host%></div>
|
|
470
|
+
</div>
|
|
471
|
+
<% } %>
|
|
472
|
+
<table>
|
|
473
|
+
<tr>
|
|
474
|
+
<th><h2>Server</h2><div>Running apps</div></th>
|
|
475
|
+
<th><h2>Shared</h2><div>Use on any machine on the network</div></th>
|
|
476
|
+
<th><h2>Local</h2><div>Use on <%=current_host%></div></th>
|
|
477
|
+
</tr>
|
|
478
|
+
<% processes.forEach((item) => { %>
|
|
479
|
+
<tr>
|
|
480
|
+
<td class='title'><%=item.name%></td>
|
|
481
|
+
<td>
|
|
482
|
+
<% item.external_router.forEach((domain) => { %>
|
|
483
|
+
<div>
|
|
484
|
+
<a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
|
|
485
|
+
</div>
|
|
486
|
+
<% }) %>
|
|
487
|
+
<% if (item.external_ip) { %>
|
|
488
|
+
<div>
|
|
489
|
+
<a class='ln' target="_blank" href="http://<%=item.external_ip%>">http://<%=item.external_ip%></a>
|
|
490
|
+
</div>
|
|
491
|
+
<% } %>
|
|
492
|
+
</td>
|
|
493
|
+
<td>
|
|
494
|
+
<% item.internal_router.forEach((domain) => { %>
|
|
495
|
+
<div>
|
|
496
|
+
<a class='ln' target="_blank" href="https://<%=domain%>">https://<%=domain%></a>
|
|
497
|
+
</div>
|
|
498
|
+
<% }) %>
|
|
499
|
+
<div>
|
|
500
|
+
<a class='ln' target="_blank" href="http://localhost:<%=item.port%>">http://localhost:<%=item.port%></a>
|
|
501
|
+
</div>
|
|
502
|
+
</td>
|
|
503
|
+
</tr>
|
|
504
|
+
<% }) %>
|
|
505
|
+
</table>
|
|
506
|
+
</div>
|
|
507
|
+
<% }) %>
|
|
508
|
+
<div class='container-row hidden'>
|
|
509
|
+
<div class='header-label-sub'><i class="fa-solid fa-microchip"></i> System Programs</div>
|
|
510
|
+
<div class='line align-top'>
|
|
511
|
+
<h3>
|
|
512
|
+
<img class='icon' src="<%=icon%>">
|
|
513
|
+
<div class='col'>
|
|
514
|
+
<div class='title'>Pinokio</div>
|
|
515
|
+
<% if (proxy) { %>
|
|
516
|
+
<div class='description'><a href="<%=proxy.proxy%>" target="_blank"><%=proxy.proxy%></a> → <a href="<%=localhost%>" target="_blank"><%=localhost%></a></div>
|
|
517
|
+
<a class='wifi-qr badge' data-qr="<%=qr%>" data-url="<%=proxy.proxy%>"><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
|
|
518
|
+
<% } else { %>
|
|
519
|
+
<div class='description'>Share Pinokio <a href="<%=localhost%>" target="_blank"><%=localhost%></a> with other devices on the same network</div>
|
|
520
|
+
<% } %>
|
|
521
|
+
<div class='btn-container'>
|
|
522
|
+
<% if (proxy) { %>
|
|
523
|
+
<div id='wifi-stop' data-proxy="<%=proxy.proxy%>" class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></div>
|
|
524
|
+
<% } else { %>
|
|
525
|
+
<div id='wifi' class='btn'><div><i class="fa-solid fa-play"></i> Start</div></div>
|
|
526
|
+
<div id='wifi-starting' class='btn disabled hidden'><div><i class="fa-solid fa-circle-notch fa-spin"></i> Starting</div></div>
|
|
527
|
+
<% } %>
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
</h3>
|
|
531
|
+
</div>
|
|
532
|
+
<% items.forEach((item) => { %>
|
|
533
|
+
<div class='line align-top'>
|
|
534
|
+
<h3>
|
|
535
|
+
<img class='icon' src="<%=item.icon%>">
|
|
536
|
+
<div class='col'>
|
|
537
|
+
<div class='title'><%=item.name%></div>
|
|
538
|
+
<% if (item.proxy) { %>
|
|
539
|
+
<div class='description'><a href="<%=item.proxy%>" target="_blank"><%=item.proxy%></a> → <a href="<%=item.target%>" target="_blank"><%=item.target%></a></div>
|
|
540
|
+
<a class='wifi-qr badge' data-qr="<%=item.qr%>" data-url="<%=item.proxy%>"><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
|
|
541
|
+
<% } else { %>
|
|
542
|
+
<div class='description'>Share <%=item.target%> with other devices on the same network</div>
|
|
543
|
+
<% } %>
|
|
544
|
+
<div class='btn-container'>
|
|
545
|
+
<% if (item.running) { %>
|
|
546
|
+
<div data-port="<%=item.port%>" data-name="<%=item.name%>" data-target="<%=item.target%>" class='stop btn'><i class="fa-solid fa-stop"></i> Stop</div>
|
|
547
|
+
<% } else { %>
|
|
548
|
+
<div data-port="<%=item.port%>" data-name="<%=item.name%>" data-target="<%=item.target%>" class='start btn'><i class="fa-solid fa-play"></i> Start at port <%=item.port%></div>
|
|
549
|
+
<% } %>
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
</h3>
|
|
553
|
+
</div>
|
|
554
|
+
<% }) %>
|
|
555
|
+
</div>
|
|
556
|
+
<!--
|
|
557
|
+
<div class='container-row'>
|
|
558
|
+
<div class='header-label-sub'><i class="fa-solid fa-dice-d6"></i> Pinokio</div>
|
|
559
|
+
<% apps.forEach((item) => { %>
|
|
560
|
+
<a class='line align-top' href="<%=item.link%>">
|
|
561
|
+
<h3>
|
|
562
|
+
<% if (item.icon) { %>
|
|
563
|
+
<img class='icon' src="<%=item.icon%>">
|
|
564
|
+
<% } else { %>
|
|
565
|
+
<% if (theme === 'dark') { %>
|
|
566
|
+
<img class='icon' src="/pinokio-white.png">
|
|
567
|
+
<% } else { %>
|
|
568
|
+
<img class='icon' src="/pinokio-black.png">
|
|
569
|
+
<% } %>
|
|
570
|
+
<% } %>
|
|
571
|
+
<div class='col'>
|
|
572
|
+
<div class='title'><%=item.name%></div>
|
|
573
|
+
<div class='description'><%=item.description%></div>
|
|
574
|
+
</div>
|
|
575
|
+
<div class='spinner'>
|
|
576
|
+
<i class="fa-solid fa-chevron-right"></i>
|
|
577
|
+
</div>
|
|
578
|
+
</h3>
|
|
579
|
+
</a>
|
|
580
|
+
<% }) %>
|
|
581
|
+
</div>
|
|
582
|
+
-->
|
|
583
|
+
</div>
|
|
584
|
+
<% } %>
|
|
585
|
+
</main>
|
|
586
|
+
<script>
|
|
587
|
+
document.querySelector("#reset-label").addEventListener("click", async (e) => {
|
|
588
|
+
e.preventDefault()
|
|
589
|
+
e.stopPropagation()
|
|
590
|
+
let ok = confirm("are you sure you want to re-generate http certificates?")
|
|
591
|
+
if (ok) {
|
|
592
|
+
let r = await fetch("/network/reset", {
|
|
593
|
+
method: "post",
|
|
594
|
+
headers: {
|
|
595
|
+
"Content-Type": "application/json"
|
|
596
|
+
}
|
|
597
|
+
}).then((res) => {
|
|
598
|
+
return res.json()
|
|
599
|
+
})
|
|
600
|
+
if (r.success) {
|
|
601
|
+
//alert("Successfully updated the pinokio home to " + val)
|
|
602
|
+
document.querySelector(".loading").classList.remove("hidden")
|
|
603
|
+
document.querySelector(".save").classList.add("hidden")
|
|
604
|
+
fetch("/restart", {
|
|
605
|
+
method: "post"
|
|
606
|
+
}, () => {
|
|
607
|
+
})
|
|
608
|
+
setInterval(async () => {
|
|
609
|
+
try {
|
|
610
|
+
let res = await fetch("/check_peer").then((res) => {
|
|
611
|
+
return res.json()
|
|
612
|
+
})
|
|
613
|
+
if (res.success) {
|
|
614
|
+
document.querySelector(".loading").classList.add("hidden")
|
|
615
|
+
location.href = location.href
|
|
616
|
+
}
|
|
617
|
+
} catch (e) {
|
|
618
|
+
console.log(e)
|
|
619
|
+
}
|
|
620
|
+
}, 1000)
|
|
621
|
+
} else if (r.error) {
|
|
622
|
+
alert(r.error)
|
|
623
|
+
location.href = location.href
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
})
|
|
628
|
+
document.querySelector("#advanced-label").addEventListener("click", (e) => {
|
|
629
|
+
e.preventDefault()
|
|
630
|
+
e.stopPropagation()
|
|
631
|
+
//document.querySelector("#advanced-input").classList.toggle("hidden")
|
|
632
|
+
Commander({
|
|
633
|
+
callback: "/network",
|
|
634
|
+
path: "~/network",
|
|
635
|
+
icon: "fa-solid fa-circle-down",
|
|
636
|
+
title: "Custom Router",
|
|
637
|
+
placeholder: "enter a custom router git url",
|
|
638
|
+
description: `<div>you can write your own custom routers to handle custom request handling for any port <a target="_blank" href="<%=docs%>">Learn more</a></div>`,
|
|
639
|
+
target: "_top",
|
|
640
|
+
message: (url) => {
|
|
641
|
+
let name = new URL(url).pathname.split("/").slice(-2).join("_")
|
|
642
|
+
return encodeURIComponent(`git clone ${url} ${name}`)
|
|
643
|
+
}
|
|
644
|
+
})
|
|
645
|
+
})
|
|
646
|
+
if (document.querySelector("#active").checked) {
|
|
647
|
+
console.log("checked")
|
|
648
|
+
document.querySelector("#network_name").classList.remove("hidden")
|
|
649
|
+
} else {
|
|
650
|
+
console.log("not checked")
|
|
651
|
+
document.querySelector("#network_name").classList.add("hidden")
|
|
652
|
+
}
|
|
653
|
+
document.querySelector("#active").addEventListener("change", (e)=> {
|
|
654
|
+
console.log(e.target.checked)
|
|
655
|
+
if (e.target.checked) {
|
|
656
|
+
document.querySelector("#network_name").classList.remove("hidden")
|
|
657
|
+
document.querySelector("#active-label").innerHTML = "On"
|
|
658
|
+
} else {
|
|
659
|
+
document.querySelector("#network_name").classList.add("hidden")
|
|
660
|
+
document.querySelector("#active-label").innerHTML = "Off"
|
|
661
|
+
}
|
|
662
|
+
})
|
|
663
|
+
document.querySelector("main").addEventListener("click", async (e) => {
|
|
664
|
+
let target
|
|
665
|
+
|
|
666
|
+
if (e.target.classList.contains("save")) {
|
|
667
|
+
target = e.target
|
|
668
|
+
} else {
|
|
669
|
+
target = e.target.closest(".save")
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (target) {
|
|
673
|
+
let active = document.querySelector("#active").checked ? "1": "0"
|
|
674
|
+
let body = {
|
|
675
|
+
PINOKIO_NETWORK_NAME: document.querySelector("#name").value,
|
|
676
|
+
PINOKIO_NETWORK_ACTIVE: active,
|
|
677
|
+
PINOKIO_HTTPS_ACTIVE: active,
|
|
678
|
+
}
|
|
679
|
+
/*
|
|
680
|
+
let body = {
|
|
681
|
+
PINOKIO_NETWORK_NAME: document.querySelector("#name").value,
|
|
682
|
+
PINOKIO_NETWORK_ACTIVE: (document.querySelector("#peer_active").checked ? "1": "0"),
|
|
683
|
+
PINOKIO_HTTPS_ACTIVE: (document.querySelector("#https_active").checked ? "1": "0")
|
|
684
|
+
}
|
|
685
|
+
*/
|
|
686
|
+
console.log(body)
|
|
687
|
+
let r = await fetch("/network", {
|
|
688
|
+
method: "post",
|
|
689
|
+
headers: { "Content-Type": "application/json" },
|
|
690
|
+
body: JSON.stringify(body)
|
|
691
|
+
}).then((res) => {
|
|
692
|
+
return res.json()
|
|
693
|
+
})
|
|
694
|
+
if (r.success) {
|
|
695
|
+
//alert("Successfully updated the pinokio home to " + val)
|
|
696
|
+
document.querySelector(".loading").classList.remove("hidden")
|
|
697
|
+
document.querySelector(".save").classList.add("hidden")
|
|
698
|
+
fetch("/restart", {
|
|
699
|
+
method: "post"
|
|
700
|
+
}, () => {
|
|
701
|
+
})
|
|
702
|
+
setInterval(async () => {
|
|
703
|
+
try {
|
|
704
|
+
let res = await fetch("/check_peer").then((res) => {
|
|
705
|
+
return res.json()
|
|
706
|
+
})
|
|
707
|
+
if (res.success) {
|
|
708
|
+
document.querySelector(".loading").classList.add("hidden")
|
|
709
|
+
location.href = location.href
|
|
710
|
+
}
|
|
711
|
+
} catch (e) {
|
|
712
|
+
console.log(e)
|
|
713
|
+
}
|
|
714
|
+
}, 1000)
|
|
715
|
+
} else if (r.error) {
|
|
716
|
+
alert(r.error)
|
|
717
|
+
location.href = location.href
|
|
718
|
+
}
|
|
719
|
+
return
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (e.target.classList.contains("stop")) {
|
|
723
|
+
target = e.target
|
|
724
|
+
} else {
|
|
725
|
+
target = e.target.closest(".stop")
|
|
726
|
+
}
|
|
727
|
+
if (target) {
|
|
728
|
+
// stop
|
|
729
|
+
let res = await fetch("/proxy", {
|
|
730
|
+
method: "post",
|
|
731
|
+
headers: {
|
|
732
|
+
"Content-Type": "application/json"
|
|
733
|
+
},
|
|
734
|
+
body: JSON.stringify({
|
|
735
|
+
action: "stop",
|
|
736
|
+
target: target.getAttribute("data-target"),
|
|
737
|
+
name: target.getAttribute("data-name")
|
|
738
|
+
})
|
|
739
|
+
}).then((res) => {
|
|
740
|
+
return res.json()
|
|
741
|
+
})
|
|
742
|
+
location.href = location.href
|
|
743
|
+
return
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (e.target.classList.contains("start")) {
|
|
747
|
+
target = e.target
|
|
748
|
+
} else {
|
|
749
|
+
target = e.target.closest(".start")
|
|
750
|
+
}
|
|
751
|
+
if (target) {
|
|
752
|
+
let res = await fetch("/proxy", {
|
|
753
|
+
method: "post",
|
|
754
|
+
headers: {
|
|
755
|
+
"Content-Type": "application/json"
|
|
756
|
+
},
|
|
757
|
+
body: JSON.stringify({
|
|
758
|
+
action: "start",
|
|
759
|
+
target: target.getAttribute("data-target"),
|
|
760
|
+
name: target.getAttribute("data-name"),
|
|
761
|
+
port: target.getAttribute("data-port")
|
|
762
|
+
})
|
|
763
|
+
}).then((res) => {
|
|
764
|
+
return res.json()
|
|
765
|
+
})
|
|
766
|
+
location.href = location.href
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (e.target.classList.contains("wifi-qr")) {
|
|
770
|
+
target = e.target
|
|
771
|
+
} else {
|
|
772
|
+
target = e.target.closest(".wifi-qr")
|
|
773
|
+
}
|
|
774
|
+
if (target) {
|
|
775
|
+
let url = target.getAttribute("data-url")
|
|
776
|
+
let qr = target.getAttribute("data-qr")
|
|
777
|
+
console.log({ url, qr })
|
|
778
|
+
await Swal.fire({
|
|
779
|
+
title: "Local Share",
|
|
780
|
+
customClass: {
|
|
781
|
+
popup: "min-popup",
|
|
782
|
+
title: "min-title"
|
|
783
|
+
},
|
|
784
|
+
showConfirmButton: false,
|
|
785
|
+
html: `<div class='min-modal'>
|
|
786
|
+
<div>Access Pinokio from</div>
|
|
787
|
+
<div>any local network device</div>
|
|
788
|
+
<div><img src="${qr}"></div>
|
|
789
|
+
<a href="${url}" target="_blank">${url}</a>
|
|
790
|
+
</div>`
|
|
791
|
+
})
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
})
|
|
796
|
+
if (document.querySelector("#back")) {
|
|
797
|
+
document.querySelector("#back").addEventListener("click", (e) => {
|
|
798
|
+
history.back()
|
|
799
|
+
})
|
|
800
|
+
}
|
|
801
|
+
if (document.querySelector("#forward")) {
|
|
802
|
+
document.querySelector("#forward").addEventListener("click", (e) => {
|
|
803
|
+
history.forward()
|
|
804
|
+
})
|
|
805
|
+
}
|
|
806
|
+
<% if (proxy) { %>
|
|
807
|
+
if (document.querySelector("#wifi-stop")) {
|
|
808
|
+
document.querySelector("#wifi-stop").addEventListener("click", async (e) => {
|
|
809
|
+
let res = await fetch("/unpublish", {
|
|
810
|
+
method: "post",
|
|
811
|
+
headers: {
|
|
812
|
+
"Content-Type": "application/json"
|
|
813
|
+
},
|
|
814
|
+
body: JSON.stringify({
|
|
815
|
+
type: "local"
|
|
816
|
+
})
|
|
817
|
+
}).then((res) => {
|
|
818
|
+
return res.json()
|
|
819
|
+
})
|
|
820
|
+
console.log(res)
|
|
821
|
+
location.href = location.href
|
|
822
|
+
})
|
|
823
|
+
}
|
|
824
|
+
<% } else { %>
|
|
825
|
+
if (document.querySelector("#wifi")) {
|
|
826
|
+
document.querySelector("#wifi").addEventListener("click", async (e) => {
|
|
827
|
+
document.querySelector("#wifi").classList.add("hidden")
|
|
828
|
+
document.querySelector("#wifi-starting").classList.remove("hidden")
|
|
829
|
+
let res = await fetch("/publish", {
|
|
830
|
+
method: "post",
|
|
831
|
+
headers: {
|
|
832
|
+
"Content-Type": "application/json"
|
|
833
|
+
},
|
|
834
|
+
body: JSON.stringify({
|
|
835
|
+
type: "local"
|
|
836
|
+
})
|
|
837
|
+
}).then((res) => {
|
|
838
|
+
return res.json()
|
|
839
|
+
})
|
|
840
|
+
console.log(res)
|
|
841
|
+
location.href = location.href
|
|
842
|
+
})
|
|
843
|
+
}
|
|
844
|
+
<% } %>
|
|
845
|
+
<% if (requirements_pending) { %>
|
|
846
|
+
setInterval(() => {
|
|
847
|
+
fetch("/requirements_check/network").then((res) => {
|
|
848
|
+
return res.json()
|
|
849
|
+
}).then((res) => {
|
|
850
|
+
console.log(res)
|
|
851
|
+
if (!res.requirements_pending) {
|
|
852
|
+
if (res.install_required) {
|
|
853
|
+
location.href = "/setup/network?callback=/network"
|
|
854
|
+
} else {
|
|
855
|
+
location.href = location.href
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
})
|
|
859
|
+
}, 2000)
|
|
860
|
+
<% } %>
|
|
861
|
+
<% if (peer_active) { %>
|
|
862
|
+
setInterval(() => {
|
|
863
|
+
fetch("/peer_check").then((res) => {
|
|
864
|
+
return res.json()
|
|
865
|
+
}).then((res) => {
|
|
866
|
+
if (res.updated) {
|
|
867
|
+
location.href = location.href
|
|
868
|
+
}
|
|
869
|
+
})
|
|
870
|
+
}, 2000)
|
|
871
|
+
<% } %>
|
|
872
|
+
</script>
|
|
873
|
+
</body>
|
|
874
|
+
</html>
|