pinokiod 1.3.96 → 1.3.97

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/shell.js CHANGED
@@ -736,7 +736,8 @@ class Shell {
736
736
  # index: ${this.index}
737
737
  # cmd: ${this.cmd}
738
738
  # timestamp: ${time}
739
- # ${infoYAML.replaceAll("\n", "\n# ")}
739
+
740
+ ${infoYAML}
740
741
 
741
742
  `
742
743
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "1.3.96",
3
+ "version": "1.3.97",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/pipe/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const { createProxyMiddleware } = require('http-proxy-middleware');
2
+ const { yellow, green, blue } = require('kleur');
2
3
 
3
4
  const path = require('path')
4
5
  const { createHttpTerminator } = require('http-terminator')
@@ -16,17 +17,12 @@ class Pipe {
16
17
  if (req.session.authenticated) {
17
18
  next();
18
19
  } else {
19
- console.log("not authenticated. redirect /pionkio/login")
20
20
  res.redirect('/pinokio/login');
21
21
  }
22
22
  }
23
23
  // a pipe server for creating publicly shareable endpoints
24
24
  async start(url, scriptPath, passcode, config) {
25
-
26
- if (!config) config = {}
27
- if (config.icon) {
28
- }
29
-
25
+ console.log("pipe.start", { url, scriptPath, passcode, config })
30
26
 
31
27
  let port = await this.kernel.port()
32
28
  let app = express();
@@ -49,7 +45,34 @@ class Pipe {
49
45
  const { password } = req.body;
50
46
 
51
47
  //if (await bcrypt.compare(password, hashedPassword)) {
52
- if (password === passcode) {
48
+
49
+ // multiple passcode options supported (comma separated)
50
+ let passcode_options = passcode.split(",")
51
+ if (passcode_options.includes(password)) {
52
+ const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
53
+ const agent = req.headers['user-agent']
54
+ let event = {
55
+ time: `${new Date().toLocaleString()}`,
56
+ ip,
57
+ agent
58
+ }
59
+ let log = `\r\n[${event.time}] Login from ${event.ip} | ${event.agent}\r\n`
60
+ console.log(log)
61
+ // this.kernel.api.ondata({
62
+ // id: scriptPath,
63
+ // type: "notify",
64
+ // data: {
65
+ // html: `<div><h6>${event.time}</h6><div>IP: ${event.ip}</div>`
66
+ // }
67
+ // })
68
+ this.kernel.api.ondata({
69
+ type: "stream",
70
+ kernel: true,
71
+ id: scriptPath,
72
+ data: {
73
+ raw: yellow(log)
74
+ }
75
+ })
53
76
  req.session.authenticated = true;
54
77
  res.redirect('/');
55
78
  } else {
@@ -67,7 +67,7 @@ h1 {
67
67
  -->
68
68
  <h1>PINOKIO</h1>
69
69
  <form method="POST" action="/pinokio/login">
70
- <input placeholder="enter passcode" type="password" name="password" required>
70
+ <input autofocus placeholder="enter passcode" type="password" name="password" required>
71
71
  <button type="submit">Login</button>
72
72
  </form>
73
73
  <% if (error) { %>
@@ -104,21 +104,6 @@ document.addEventListener("DOMContentLoaded", async () => {
104
104
  <% if (error) { %>
105
105
  document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
106
106
  <% } %>
107
- <% if (!install_required) { %>
108
- /*
109
- document.querySelector("footer").addEventListener("click", (e) => {
110
- if (e.target.classList.contains("toggle-expand") || e.target.closest(".toggle-expand")) {
111
- let el = document.querySelector("footer .toggle-expand i")
112
- if (el.classList.contains("fa-circle-chevron-up")) {
113
- el.className = "fa-solid fa-circle-chevron-down"
114
- } else if (el.classList.contains("fa-circle-chevron-down")) {
115
- el.className = "fa-solid fa-circle-chevron-up"
116
- }
117
- document.querySelector("footer").classList.toggle("expanded")
118
- }
119
- })
120
- */
121
- <% } %>
122
107
  <% if (requirements_pending) { %>
123
108
  await new Promise((resolve, reject) => {
124
109
  let interval = setInterval(() => {
@@ -641,34 +626,29 @@ document.addEventListener("DOMContentLoaded", async () => {
641
626
  }
642
627
  });
643
628
 
644
- document.querySelector(".stop").addEventListener("click", async (e) => {
645
- await rpc.stop()
646
- // socket.run({
647
- // id: location.pathname,
648
- // method: "kernel.api.stop"
649
- // }, (stream) => {
650
- // console.log("#", stream)
651
- // })
652
- document.querySelector(".run .play").classList.remove("hidden")
653
- document.querySelector(".run .starting").classList.add("hidden")
654
- document.querySelector(".run .stop").classList.add("hidden")
655
- })
656
- document.querySelector(".play").addEventListener("click", async (e) => {
657
- document.querySelector(".run .play").classList.add("hidden")
658
- document.querySelector(".run .starting").classList.remove("hidden")
659
- await rpc.run()
660
- })
629
+ if (document.querySelector(".stop")) {
630
+ document.querySelector(".stop").addEventListener("click", async (e) => {
631
+ await rpc.stop()
632
+ // socket.run({
633
+ // id: location.pathname,
634
+ // method: "kernel.api.stop"
635
+ // }, (stream) => {
636
+ // console.log("#", stream)
637
+ // })
638
+ document.querySelector(".run .play").classList.remove("hidden")
639
+ document.querySelector(".run .starting").classList.add("hidden")
640
+ document.querySelector(".run .stop").classList.add("hidden")
641
+ })
642
+ }
643
+ if (document.querySelector(".play")) {
644
+ document.querySelector(".play").addEventListener("click", async (e) => {
645
+ document.querySelector(".run .play").classList.add("hidden")
646
+ document.querySelector(".run .starting").classList.remove("hidden")
647
+ await rpc.run()
648
+ })
649
+ }
661
650
  <% } %>
662
651
 
663
- /*
664
- document.querySelector("#save").addEventListener("click", async (e) => {
665
- console.log("SAVE")
666
- await rpc.save()
667
- n.Noty({
668
- text: `saved`,
669
- })
670
- })
671
- */
672
652
  <% if (stop) { %>
673
653
  await rpc.stop()
674
654
  document.querySelector(".run .play").classList.remove("hidden")
@@ -685,74 +665,18 @@ document.addEventListener("DOMContentLoaded", async () => {
685
665
  <% } %>
686
666
  <% } %>
687
667
  <% } %>
688
- /*
689
- document.querySelector("#explore").addEventListener("click", async (e) => {
690
- e.preventDefault()
691
- e.stopPropagation()
692
- location.href = "/?mode=explore"
693
- })
694
- Reporter()
695
- */
696
668
 
697
-
698
-
699
- // document.querySelector(".memory").addEventListener("click", async (e) => {
700
- // let target = e.target.classList.contains("tunnel") ? e.target : e.target.closest(".tunnel")
701
- // let target2 = e.target.classList.contains("tunnel-stop") ? e.target : e.target.closest(".tunnel-stop")
702
- // if (target) {
703
- // e.preventDefault()
704
- // e.stopPropagation()
705
- // let url = target.getAttribute("data-url")
706
- // const token = prompt("Enter an Ngrok auth token to expose your machine to the public Internet https://ngrok.com/")
707
- // if (token && token.length > 0) {
708
- // let response = await fetch("/pinokio/tunnel", {
709
- // method: "POST",
710
- // headers: {
711
- // "Content-Type": "application/json"
712
- // },
713
- // body: JSON.stringify({ url, action: "start", token })
714
- // }).then((res) => {
715
- // return res.json()
716
- // })
717
- // await reloadMemory()
718
- // }
719
- // } else if (target2) {
720
- // console.log("target2", target2)
721
- // e.preventDefault()
722
- // e.stopPropagation()
723
- // let url = target2.getAttribute("data-url")
724
- // let response = await fetch("/pinokio/tunnel", {
725
- // method: "POST",
726
- // headers: {
727
- // "Content-Type": "application/json"
728
- // },
729
- // body: JSON.stringify({ url, action: "stop" })
730
- // }).then((res) => {
731
- // return res.json()
732
- // })
733
- // await reloadMemory()
734
- // }
735
- // })
736
- /*
737
- document.querySelector("#source").addEventListener("click", (e) => {
738
- refreshParent({
739
- id: "<%=filepath%>",
740
- action: {
741
- "type": "newtab",
742
- "url": e.target.getAttribute("data-editor-url")
669
+ if (document.querySelector("#lv")) {
670
+ document.querySelector("#lv").addEventListener("click", (e) => {
671
+ let m = e.target.closest(".memory")
672
+ m.classList.toggle("collapsed")
673
+ if (m.classList.contains("collapsed")) {
674
+ m.querySelector("i").className = "fa-solid fa-sort-down"
675
+ } else {
676
+ m.querySelector("i").className = "fa-solid fa-sort-up"
743
677
  }
744
678
  })
745
- })
746
- */
747
- document.querySelector("#lv").addEventListener("click", (e) => {
748
- let m = e.target.closest(".memory")
749
- m.classList.toggle("collapsed")
750
- if (m.classList.contains("collapsed")) {
751
- m.querySelector("i").className = "fa-solid fa-sort-down"
752
- } else {
753
- m.querySelector("i").className = "fa-solid fa-sort-up"
754
- }
755
- })
679
+ }
756
680
  })
757
681
  const reloadMemory = async () => {
758
682
  let url = "/pinokio/memory?filepath=<%=encodedFilePath%>"
@@ -137,7 +137,6 @@ hr {
137
137
  height: 1px;
138
138
  }
139
139
  .shared {
140
- margin-left: 30px;
141
140
  }
142
141
  .shared a {
143
142
  display: block;
@@ -145,19 +144,90 @@ hr {
145
144
  }
146
145
  .shared img {
147
146
  width: 200px;
147
+ border: 1px solid rgba(0,0,0,0.1);
148
+ }
149
+ .shared h2 {
150
+ margin: 0;
151
+ letter-spacing: -1px;
152
+ }
153
+ .passcode ol {
154
+ padding-inline-start: 15px;
155
+ margin: 5px 0 10px;
156
+ }
157
+ body.dark .passcode {
158
+ border: 1px solid rgba(255,255,255,0.1);
159
+ }
160
+ .passcode {
161
+ margin-left: 30px;
162
+ padding: 20px !important;
163
+ box-sizing: border-box;
164
+ border: 1px solid rgba(0,0,0,0.1);
165
+ margin-top: 20px;
166
+ margin-bottom: 20px;
167
+ }
168
+ .passcode h2 {
169
+ margin: 0;
170
+ font-size: 20px;
171
+ letter-spacing: -1px;
172
+ }
173
+ .passcode div {
174
+ padding: 0 0 10px;
175
+ }
176
+ .passcode .row {
177
+ display: flex;
178
+ padding: 0;
179
+ }
180
+ body.dark .passcode .row input {
181
+ background: white;
182
+ }
183
+ .passcode .row input {
184
+ border-radius: 0;
185
+ flex-grow: 1;
186
+ padding: 10px;
187
+ box-sizing: border-box;
188
+ border: none;
189
+ background: rgba(0,0,100,0.1);
190
+ }
191
+ body.dark .passcode button {
192
+ background: royalblue;
193
+ }
194
+ .passcode button {
195
+ border-radius: 0;
196
+ }
197
+ body.dark .cloudflare-running {
198
+ border: 1px solid rgba(255,255,255,0.1);
199
+ }
200
+ .cloudflare-running {
201
+ margin-left: 30px;
202
+ padding: 20px !important;
203
+ box-sizing: border-box;
204
+ border: 1px solid rgba(0,0,0,0.1);
148
205
  }
149
206
 
150
207
  </style>
151
208
  <script>
152
209
  document.addEventListener("DOMContentLoaded", async () => {
153
210
  const n = new N()
211
+ document.querySelector("#reveal").addEventListener("click", async (e) => {
212
+ let el = document.querySelector("#passcode")
213
+ if (el.type === "password") {
214
+ el.type = "text"
215
+ } else {
216
+ el.type = "password"
217
+ }
218
+ })
154
219
  document.querySelector("#save").addEventListener("click", async (e) => {
155
220
  // save
156
221
  const vals = {}
157
222
  const els = document.querySelectorAll(".env-item input[type=checkbox]")
158
223
  for(let el of els) {
159
- vals[el.id] = el.checked
224
+ let id = el.getAttribute("data-id")
225
+ vals[id] = el.checked
160
226
  }
227
+
228
+ const passcode_el = document.querySelector("#passcode")
229
+ vals.PINOKIO_SHARE_PASSCODE = passcode_el.value
230
+
161
231
  let res = await fetch("/env", {
162
232
  method: "POST",
163
233
  headers: {
@@ -165,7 +235,7 @@ document.addEventListener("DOMContentLoaded", async () => {
165
235
  },
166
236
  body: JSON.stringify({
167
237
  filepath: "api/" + location.pathname.slice(7),
168
- vals
238
+ vals,
169
239
  })
170
240
  }).then((res) => {
171
241
  return res.json()
@@ -185,23 +255,41 @@ document.addEventListener("DOMContentLoaded", async () => {
185
255
  <hr>
186
256
  <div class='env-item'>
187
257
  <% if (config.PINOKIO_SHARE_CLOUDFLARE.toString() === "true") { %>
188
- <input type="checkbox" id="PINOKIO_SHARE_CLOUDFLARE" name="cloudflare" checked />
258
+ <input type="checkbox" data-id="PINOKIO_SHARE_CLOUDFLARE" name="cloudflare" checked />
189
259
  <% } else { %>
190
- <input type="checkbox" id="PINOKIO_SHARE_CLOUDFLARE" name="cloudflare" />
260
+ <input type="checkbox" data-id="PINOKIO_SHARE_CLOUDFLARE" name="cloudflare" />
191
261
  <% } %>
192
262
  <label for="cloudflare"><i class="fa-brands fa-cloudflare"></i> Run a Public Node</label>
193
263
  <ul>
194
264
  <li>This will let you share your local Pinokio app to the public internet, which anyone with a URL can access.</li>
195
265
  <li>Powered by <a href="https://www.cloudflare.com/products/tunnel/" target="_blank" features="browser">Cloudflare Tunnel</a></li>
196
266
  <li>You can manually configure this in through the Configure menu (set PINOKIO_SHARE_CLOUDFLARE to true)</li>
197
- <li>You can add <strong>authentication</strong> by adding a passcode (set PINOKIO_SHARE_PASSCODE in the <strong>Configure</strong> tab)</li>
198
267
  </ul>
199
- <% cloudflare_links.forEach((link) => { %>
200
- <div class='shared'>
201
- <a href="<%=link.url%>" target="_blank" features="browser"><%=link.url%></a>
202
- <img src="<%=link.qr%>">
268
+ <div class='passcode'>
269
+ <h2>Passcode (optional)</h2>
270
+ <ol>
271
+ <li><strong>No passcode:</strong> Anyone with the URL can use the app</li>
272
+ <li><strong>Passcode:</strong> Users will need to authenticate with the passcode before using the app.</li>
273
+ <li>To allow multiple passcodes, separate the passode by commas (Example: ab12zd3,D3ad3a,df3d9Fa).</li>
274
+ </ol>
275
+ <div class='row'>
276
+ <input id='passcode' type='password' value="<%=config.PINOKIO_SHARE_PASSCODE || ''%>"/>
277
+ <button class='btn' id='reveal'><i class="fa-solid fa-eye"></i></button>
203
278
  </div>
204
- <% }) %>
279
+ </div>
280
+ <% if (cloudflare_links.length > 0) { %>
281
+ <div class='cloudflare-running'>
282
+ <div class='shared'>
283
+ <h2><i class="fa-solid fa-circle-notch fa-spin"></i> Running</h2>
284
+ </div>
285
+ <% cloudflare_links.forEach((link) => { %>
286
+ <div class='shared'>
287
+ <a href="<%=link.url%>" target="_blank" features="browser"><%=link.url%></a>
288
+ <img src="<%=link.qr%>">
289
+ </div>
290
+ <% }) %>
291
+ </div>
292
+ <% } %>
205
293
  </div>
206
294
  <div class='env-item'>
207
295
  <% if (config.PINOKIO_SHARE_LOCAL.toString() === "true") { %>