pinokiod 1.3.90 → 1.3.92

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.
@@ -1,18 +1,37 @@
1
1
  const { yellow, green, blue } = require('kleur');
2
2
  const QRCode = require('qrcode');
3
+ const path = require('path')
4
+ const Util = require('../../util')
3
5
  class C {
4
6
  async tunnel (req, ondata, kernel) {
5
7
  /*
6
8
  {
7
9
  "method": "cloundflare.tunnel",
8
10
  "params": {
9
- "uri": "{{local.url}}"
11
+ "uri": "{{local.url}}",
12
+ "passcode": (optional)
10
13
  }
11
14
  }
12
15
 
13
16
  => cloudflared tunnel --url http://localhost:8080
14
17
  */
15
- const message = `cloudflared tunnel --url ${req.params.uri}`
18
+
19
+
20
+ let pipe_uri
21
+ if (req.params.passcode) {
22
+ // 1. start a pipe server => needed for authentication
23
+ const api_path = Util.api_path(req.parent.path, kernel)
24
+ const pinokio_path = path.resolve(api_path, "pinokio.js")
25
+ const config = (await kernel.loader.load(pinokio_path)).resolved
26
+ pipe_uri = await kernel.pipe.start(req.params.uri, req.parent.path, req.params.passcode, config)
27
+ } else {
28
+ // 2. if no passcode required, no need for a pipe server just use the original
29
+ pipe_uri = req.params.uri
30
+ }
31
+
32
+
33
+ // 2. run cloudflare tunnel on the proxy
34
+ const message = `cloudflared tunnel --url ${pipe_uri}`
16
35
  let params = {
17
36
  id: message,
18
37
  message
@@ -65,15 +84,24 @@ class C {
65
84
  if (!kernel.memory.local[req.parent.path].$share.cloudflare) {
66
85
  kernel.memory.local[req.parent.path].$share.cloudflare = {}
67
86
  }
68
- kernel.memory.local[req.parent.path].$share.cloudflare[req.params.uri] = cloudflare_url
87
+ kernel.memory.local[req.parent.path].$share.cloudflare[pipe_uri] = cloudflare_url
69
88
 
70
89
  return { uri: cloudflare_url }
71
90
  }
72
91
  async stop (req, ondata, kernel) {
92
+ // stop the cloudflare shell
73
93
  const message = `cloudflared tunnel --url ${req.params.uri}`
74
94
  await kernel.shell.kill({
75
95
  id: message
76
96
  })
97
+
98
+ // stop pipe server
99
+ await kernel.pipe.stop(req.params.uri, req.parent.path)
100
+
101
+ // delete the local variable
102
+ delete kernel.memory.local[req.parent.path].$share.cloudflare[req.params.uri]
103
+
77
104
  }
105
+
78
106
  }
79
107
  module.exports = C
@@ -128,6 +128,10 @@ class Api {
128
128
  // stop all proxies
129
129
  this.stopProxy({ script: requestPath })
130
130
 
131
+ // stop all cloudflare tunnels
132
+
133
+ await this.kernel.stopCloudflare({ path: requestPath })
134
+
131
135
  // if there are any pending waiters, delete them
132
136
 
133
137
  if (this.waiter[requestPath]) {
@@ -538,7 +542,7 @@ class Api {
538
542
  // get fully resolved env
539
543
  let env = await Environment.get2(request.path, this.kernel)
540
544
  // set template
541
- this.kernel.template.update(env)
545
+ this.kernel.template.update({ env })
542
546
 
543
547
  // render until `{{ }}` pattern does not exist
544
548
  // 1. render once
@@ -74,6 +74,9 @@ class Local {
74
74
  if (val === "true" || val === "1") {
75
75
  const c = new Cloudflare()
76
76
  req.params.uri = req.params[KEY]
77
+ if ("PINOKIO_SHARE_PASSCODE" in current_env) {
78
+ req.params.passcode = current_env.PINOKIO_SHARE_PASSCODE
79
+ }
77
80
  await c.tunnel(req, ondata, kernel)
78
81
  }
79
82
  }
@@ -102,6 +102,48 @@ const ENVS = [{
102
102
  "#",
103
103
  "##########################################################################",
104
104
  ],
105
+ }, {
106
+ type: ["system", "app"],
107
+ key: "PINOKIO_SHARE_CLOUDFLARE",
108
+ val: "false",
109
+ comment: [
110
+ "##########################################################################",
111
+ "#",
112
+ "# PINOKIO_SHARE_CLOUDFLARE",
113
+ "# Set this variable to share the app publicly via cloudflare tunnel.",
114
+ "#",
115
+ "##########################################################################",
116
+ ]
117
+ }, {
118
+ type: ["app"],
119
+ key: "PINOKIO_SHARE_PASSCODE",
120
+ val: "",
121
+ comment: [
122
+ "##########################################################################",
123
+ "#",
124
+ "# PINOKIO_SHARE_PASSCODE",
125
+ "#",
126
+ "# By default, your publicly shared app will be 100% open to anyone",
127
+ "# with the link via Cloudflare.",
128
+ "#",
129
+ "# You can add authorization by protecting it with a passcode.",
130
+ "# Set this value, and any access to the app will require a pass code input",
131
+ "#",
132
+ "##########################################################################",
133
+ ],
134
+ }, {
135
+ type: ["system", "app"],
136
+ key: "PINOKIO_SCRIPT_DEFAULT",
137
+ val: "true",
138
+ comment: [
139
+ "##########################################################################",
140
+ "#",
141
+ "# PINOKIO_SCRIPT_DEFAULT",
142
+ "# If this variable is false, 'default': true menu items in pinokio.js",
143
+ "# will NOT automatically run",
144
+ "#",
145
+ "##########################################################################",
146
+ ]
105
147
  }, {
106
148
  type: ["system"],
107
149
  key: "PINOKIO_DRIVE",
@@ -194,31 +236,6 @@ const ENVS = [{
194
236
  "#",
195
237
  "##########################################################################",
196
238
  ],
197
- }, {
198
- type: ["system", "app"],
199
- key: "PINOKIO_SHARE_CLOUDFLARE",
200
- val: "false",
201
- comment: [
202
- "##########################################################################",
203
- "#",
204
- "# PINOKIO_SHARE_CLOUDFLARE",
205
- "# Set this variable to share the app publicly via cloudflare tunnel.",
206
- "#",
207
- "##########################################################################",
208
- ]
209
- }, {
210
- type: ["system", "app"],
211
- key: "PINOKIO_SCRIPT_DEFAULT",
212
- val: "true",
213
- comment: [
214
- "##########################################################################",
215
- "#",
216
- "# PINOKIO_SCRIPT_DEFAULT",
217
- "# If this variable is false, 'default': true menu items in pinokio.js",
218
- "# will NOT automatically run",
219
- "#",
220
- "##########################################################################",
221
- ]
222
239
  }];
223
240
  //const ENV = (homedir) => {
224
241
  // const lines = ENVS.map((e) => {
package/kernel/index.js CHANGED
@@ -22,6 +22,8 @@ const Environment = require("./environment")
22
22
  const Util = require('./util')
23
23
  const Config = require("./pinokio.json")
24
24
  const Info = require('./info')
25
+ const Pipe = require("../pipe")
26
+ const Cloudflare = require('./api/cloudflare')
25
27
  const VARS = {
26
28
  pip: {
27
29
  install: {
@@ -45,11 +47,33 @@ class Kernel {
45
47
  this.exposed = {}
46
48
  this.envs = {}
47
49
  this.info = new Info(this)
50
+ this.pipe = new Pipe(this)
51
+ this.cloudflare = new Cloudflare()
48
52
  }
49
53
  /*
50
54
  kernel.env() => return the system environment
51
55
  kernel.env("api/stablediffusion") => returns the full environment object
52
56
  */
57
+ async stopCloudflare(option) {
58
+ if (option.uri) {
59
+ } else if (option.path) {
60
+ let scriptPath = option.path
61
+ if (this.memory.local[scriptPath] && this.memory.local[scriptPath].$share) {
62
+ let cf = this.memory.local[scriptPath].$share.cloudflare
63
+ let uris = Object.keys(cf)
64
+ for(let uri of uris) {
65
+ await this.cloudflare.stop({
66
+ parent: {
67
+ path: scriptPath
68
+ },
69
+ params: { uri }
70
+ }, (e) => {
71
+ process.stdout.write(e.raw)
72
+ }, this)
73
+ }
74
+ }
75
+ }
76
+ }
53
77
  async env(...args) {
54
78
  let folderpath
55
79
  if (args) {
@@ -114,7 +138,10 @@ class Kernel {
114
138
  * let available_port = await kernel.port()
115
139
  *
116
140
  **********************************************/
117
- return portfinder.getPortPromise()
141
+ return portfinder.getPortPromise({
142
+ port: 42000
143
+ })
144
+ //return portfinder.getPortPromise()
118
145
  }
119
146
  path(...args) {
120
147
  return path.resolve(this.homedir, ...args)
package/kernel/sysinfo.js CHANGED
@@ -122,8 +122,7 @@ class Sysinfo {
122
122
  }
123
123
 
124
124
 
125
- this.info.env = process.env
126
- //this.info.shell_env = vars
125
+ // this.info.env = process.env
127
126
  this.info.shell_env = lines
128
127
  }
129
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "1.3.90",
3
+ "version": "1.3.92",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,6 +12,7 @@
12
12
  "7zip-min-win-asar-support": "^1.4.4",
13
13
  "async-retry": "^1.3.3",
14
14
  "axios": "^1.4.0",
15
+ "bcrypt": "^5.1.1",
15
16
  "clear-module": "^4.1.2",
16
17
  "compressing": "^1.10.0",
17
18
  "cookie-parser": "^1.4.6",
@@ -33,9 +34,10 @@
33
34
  "glob-gitignore": "^1.0.14",
34
35
  "handlebars": "^4.7.7",
35
36
  "http-proxy": "^1.18.1",
37
+ "http-proxy-middleware": "^3.0.0",
36
38
  "http-terminator": "^3.2.0",
37
39
  "isomorphic-git": "^1.23.0",
38
- "jimini": "^0.0.5",
40
+ "jimini": "^0.0.6",
39
41
  "jsdom": "^24.0.0",
40
42
  "jsonpath-plus": "^7.2.0",
41
43
  "key-store": "^1.2.0",
package/pipe/index.js ADDED
@@ -0,0 +1,102 @@
1
+ const { createProxyMiddleware } = require('http-proxy-middleware');
2
+
3
+ const path = require('path')
4
+ const { createHttpTerminator } = require('http-terminator')
5
+ const express = require('express')
6
+ const session = require('express-session');
7
+ const bcrypt = require('bcrypt');
8
+ const cors = require('cors');
9
+ class Pipe {
10
+ constructor(kernel) {
11
+ this.kernel = kernel
12
+ this.terminators = {}
13
+ this.procs = {}
14
+ }
15
+ authenticate (req, res, next) {
16
+ if (req.session.authenticated) {
17
+ next();
18
+ } else {
19
+ console.log("not authenticated. redirect /pionkio/login")
20
+ res.redirect('/pinokio/login');
21
+ }
22
+ }
23
+ // a pipe server for creating publicly shareable endpoints
24
+ async start(url, scriptPath, passcode, config) {
25
+
26
+ if (!config) config = {}
27
+ if (config.icon) {
28
+ }
29
+
30
+
31
+ let port = await this.kernel.port()
32
+ let app = express();
33
+ app.use(cors({ origin: '*' }));
34
+ app.use(express.urlencoded({ extended: true }));
35
+ app.set('view engine', 'ejs');
36
+ app.set("views", path.resolve(__dirname, "views"))
37
+ // app.use(express.static(path.resolve(__dirname, 'public')));
38
+ app.use(session({
39
+ secret: 'oikonip',
40
+ resave: false,
41
+ saveUninitialized: true
42
+ }));
43
+ app.get('/pinokio/login', (req, res) => {
44
+ res.render("login", { error: null, ...config })
45
+ });
46
+
47
+ app.post('/pinokio/login', async (req, res) => {
48
+
49
+ const { password } = req.body;
50
+
51
+ //if (await bcrypt.compare(password, hashedPassword)) {
52
+ if (password === passcode) {
53
+ req.session.authenticated = true;
54
+ res.redirect('/');
55
+ } else {
56
+ res.status(401).render("login", { error: "Invalid passcode", ...config })
57
+ }
58
+ });
59
+
60
+ app.get('/pinokio/logout', (req, res) => {
61
+ req.session.authenticated = false;
62
+ res.redirect('/login');
63
+ });
64
+
65
+
66
+ const proxy = createProxyMiddleware({
67
+ pathFilter: '/',
68
+ target: url,
69
+ ws: true
70
+ })
71
+
72
+ app.use('/', this.authenticate, proxy)
73
+
74
+
75
+ await new Promise((resolve, reject) => {
76
+ console.log("starting pipe server at port", port)
77
+ let server = app.listen(port, () => {
78
+ console.log(`Pipe server listening on port ${port}`)
79
+ resolve()
80
+ });
81
+ let terminator = createHttpTerminator({ server });
82
+ this.terminators[url] = terminator
83
+ })
84
+ let pipe_uri = `http://localhost:${port}`
85
+
86
+ // original url => pipe url
87
+ if (!this.procs[scriptPath]) {
88
+ this.procs[scriptPath] = {}
89
+ }
90
+ this.procs[scriptPath][url] = pipe_uri
91
+ return pipe_uri
92
+ }
93
+ async stop(url, scriptPath) {
94
+ console.log("stop pipe", { scriptPath, url, terminator: this.terminators[url] })
95
+ if (this.terminators[url]) {
96
+ await this.terminators[url].terminate()
97
+ delete this.terminators[url]
98
+ delete this.procs[scriptPath][url]
99
+ }
100
+ }
101
+ }
102
+ module.exports = Pipe
@@ -0,0 +1,78 @@
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
+ <style>
7
+ body {
8
+ display: flex;
9
+ justify-content: center;
10
+ align-items: center;
11
+ height: 100%;
12
+ font-family: sans-serif;
13
+ font-size: 14px;
14
+ background: rgb(27, 28, 29);
15
+ color: white;
16
+ }
17
+ main {
18
+ max-width: 500px;
19
+ width: 100%;
20
+ text-align: center;
21
+ text-transform: lowercase;
22
+ }
23
+ main img {
24
+ width: 80px;
25
+ margin-bottom: 20px;
26
+ }
27
+ main form {
28
+ display: flex;
29
+ }
30
+ main input {
31
+ flex-grow: 1;
32
+ padding: 10px;
33
+ box-sizing: border-box;
34
+ border: none;
35
+ /*
36
+ background: rgba(0,0,0,0.06);
37
+ */
38
+ font-size: 14px;
39
+ border-radius: 0;
40
+
41
+ }
42
+ main button {
43
+ color: white;
44
+ background: royalblue;
45
+ padding: 10px;
46
+ box-sizing: border-box;
47
+ border: none;
48
+ }
49
+ .error {
50
+ border-left: 3px solid red;
51
+ color: red;
52
+ text-align: left;
53
+ padding: 5px 10px;
54
+ box-sizing: border-box;
55
+ font-size: 14px;
56
+ }
57
+ h1 {
58
+ letter-spacing: -1px;
59
+ margin-bottom: 20px;
60
+ }
61
+ </style>
62
+ </head>
63
+ <body>
64
+ <main>
65
+ <!--
66
+ <img src="/pinokio-black.png"/>
67
+ -->
68
+ <h1>PINOKIO</h1>
69
+ <form method="POST" action="/pinokio/login">
70
+ <input placeholder="enter passcode" type="password" name="password" required>
71
+ <button type="submit">Login</button>
72
+ </form>
73
+ <% if (error) { %>
74
+ <div class='error'><%=error%></div>
75
+ <% } %>
76
+ <main>
77
+ </body>
78
+ </html>
package/server/index.js CHANGED
@@ -172,6 +172,28 @@ class Server {
172
172
  }
173
173
  })
174
174
  }
175
+ async init_env(env_dir_path) {
176
+ let current = this.kernel.path(env_dir_path, "ENVIRONMENT")
177
+ // if environment.json doesn't exist,
178
+ let exists = await this.exists(current)
179
+ if (exists) {
180
+ // if ENVIRONMENT already exists, don't do anything
181
+ } else {
182
+ // if ENVIRONMENT doesn't exist, need to create one
183
+ // 1. if _ENVIRONMENT exists, create ENVIRONMENT by appending _ENVIRONMENT to ENVIRONMENT
184
+ // 2. if _ENVIRONMENT doesn't exist, just write ENVIRONMENT
185
+ // if _ENVIRONMENT exists,
186
+ let _environment = this.kernel.path(env_dir_path, "_ENVIRONMENT")
187
+ let _exists = await this.exists(_environment)
188
+ let content = await Environment.ENV("app")
189
+ if (_exists) {
190
+ let _environmentStr = await fs.promises.readFile(_environment, "utf8")
191
+ await fs.promises.writeFile(current, _environmentStr + "\n\n\n" + content)
192
+ } else {
193
+ await fs.promises.writeFile(current, content)
194
+ }
195
+ }
196
+ }
175
197
  async chrome(req, res, type) {
176
198
  let name = req.params.name
177
199
  let app_path = this.kernel.path("api", name, "pinokio.js")
@@ -230,26 +252,7 @@ class Server {
230
252
  }
231
253
  }
232
254
 
233
- let current = this.kernel.path("api", name, "ENVIRONMENT")
234
- // if environment.json doesn't exist,
235
- let exists = await this.exists(current)
236
- if (exists) {
237
- // if ENVIRONMENT already exists, don't do anything
238
- } else {
239
- // if ENVIRONMENT doesn't exist, need to create one
240
- // 1. if _ENVIRONMENT exists, create ENVIRONMENT by appending _ENVIRONMENT to ENVIRONMENT
241
- // 2. if _ENVIRONMENT doesn't exist, just write ENVIRONMENT
242
- // if _ENVIRONMENT exists,
243
- let _environment = this.kernel.path("api", name, "_ENVIRONMENT")
244
- let _exists = await this.exists(_environment)
245
- let content = await Environment.ENV("app")
246
- if (_exists) {
247
- let _environmentStr = await fs.promises.readFile(_environment, "utf8")
248
- await fs.promises.writeFile(current, content + "\n\n" + _environmentStr)
249
- } else {
250
- await fs.promises.writeFile(current, content)
251
- }
252
- }
255
+ await this.init_env("api/" + name)
253
256
 
254
257
  let mode = "run"
255
258
  if (req.query && req.query.mode) {
@@ -1872,9 +1875,15 @@ class Server {
1872
1875
  // stop proxies
1873
1876
  for(let scriptPath in this.kernel.api.proxies) {
1874
1877
  try {
1878
+ // Turn off local sharing
1875
1879
  await this.kernel.api.stopProxy({
1876
1880
  script: scriptPath
1877
1881
  })
1882
+
1883
+ // Turn off cloudflare sharing
1884
+ await this.kernel.stopCloudflare({
1885
+ path: scriptPath
1886
+ })
1878
1887
  } catch (e) {
1879
1888
  }
1880
1889
  }
@@ -2165,18 +2174,56 @@ class Server {
2165
2174
  }
2166
2175
  })
2167
2176
  this.app.post("/env", async (req, res) => {
2168
- console.log("req.body", req.body)
2169
- let fullpath = path.resolve(this.kernel.homedir, req.body.filepath)
2177
+ let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
2170
2178
  let updated = req.body.vals
2171
2179
  await Util.update_env(fullpath, updated)
2172
2180
  res.json({})
2173
2181
  })
2182
+ this.app.get("/env", async (req, res) => {
2183
+ let env_path = path.resolve(this.kernel.homedir)
2184
+ await this.init_env(env_path)
2185
+
2186
+ let filepath = path.resolve(this.kernel.homedir, "ENVIRONMENT")
2187
+ let editorpath = "/edit/ENVIRONMENT"
2188
+
2189
+ const items = await Util.parse_env_detail(filepath)
2190
+
2191
+
2192
+ res.render("env_editor", {
2193
+ config: null,
2194
+ name: null,
2195
+ init: null,
2196
+ editorpath,
2197
+ items,
2198
+ theme: this.theme,
2199
+ filepath,
2200
+ agent: this.agent,
2201
+ })
2202
+ })
2174
2203
  this.app.get("/env/*", async (req, res) => {
2204
+
2205
+ let env_path = req.params[0]
2206
+ await this.init_env(env_path)
2207
+
2175
2208
  let pathComponents = req.params[0].split("/")
2176
- let filepath = path.resolve(this.kernel.homedir, req.params[0])
2177
- let editorpath = "/edit/" + req.params[0]
2209
+ let filepath = path.resolve(this.kernel.homedir, req.params[0], "ENVIRONMENT")
2210
+ let editorpath = "/edit/" + req.params[0] + "/ENVIRONMENT"
2178
2211
  const items = await Util.parse_env_detail(filepath)
2212
+ let p = path.resolve(this.kernel.homedir, env_path, "pinokio.js")
2213
+ let config = (await this.kernel.loader.load(p)).resolved
2214
+ if (config.icon) {
2215
+ config.icon = `/${env_path}/${config.icon}?raw=true`
2216
+ }
2217
+
2218
+ let name
2219
+ if (env_path.startsWith("api")) {
2220
+ name = env_path.split("/")[1]
2221
+ }
2222
+
2179
2223
  res.render("env_editor", {
2224
+ config,
2225
+ name,
2226
+ init: req.query ? req.query.init : null,
2180
2227
  editorpath,
2181
2228
  items,
2182
2229
  theme: this.theme,
@@ -2184,12 +2231,45 @@ class Server {
2184
2231
  agent: this.agent,
2185
2232
  })
2186
2233
  })
2234
+ this.app.get("/pre/api/:name", async (req, res) => {
2235
+ let p = path.resolve(this.kernel.homedir, req.params.name, "pinokio.js")
2236
+ let config = (await this.kernel.loader.load(p)).resolved
2237
+ if (config && config.pre) {
2238
+ config.pre.forEach((item) => {
2239
+ item.icon = `/api/${req.params.name}/${item.icon}?raw=true`
2240
+ })
2241
+ res.render("pre", {
2242
+ name: req.params.name,
2243
+ theme: this.theme,
2244
+ agent: this.agent,
2245
+ name: req.params.name,
2246
+ items: config.pre
2247
+ })
2248
+ } else {
2249
+ res.redirect("/env/" + req.params.name + "?init=true")
2250
+ }
2251
+ })
2252
+ this.app.get("/initialize/:name", async (req, res) => {
2253
+ let p = path.resolve(this.kernel.homedir, "api", req.params.name, "pinokio.js")
2254
+ let config = (await this.kernel.loader.load(p)).resolved
2255
+ if (config) {
2256
+ // if pinokio.js exists
2257
+ if (config.pre && Array.isArray(config.pre)) {
2258
+ // if pre exists, redirect to /pre/:name
2259
+ res.redirect(`/pre/api/${req.params.name}`)
2260
+ } else {
2261
+ // if pre doesn't exist, redirect to /env/:name
2262
+ res.redirect(`/env/api/${req.params.name}?init=true`)
2263
+ }
2264
+ } else {
2265
+ // if pinokio.js doesn't exist, send to /browser/:name
2266
+ res.redirect(`/pinokio/browser/${req.params.name}`)
2267
+ }
2268
+ })
2187
2269
  this.app.get("/share/:name", async (req, res) => {
2188
2270
  let filepath = path.resolve(this.kernel.homedir, "api", req.params.name, "ENVIRONMENT")
2189
2271
  //let filepath = path.resolve(this.kernel.homedir, req.params[0])
2190
- console.log("filepath", filepath)
2191
2272
  const config = await Util.parse_env(filepath)
2192
- console.log("config", config)
2193
2273
  const keys = [
2194
2274
  "PINOKIO_SHARE_CLOUDFLARE",
2195
2275
  "PINOKIO_SHARE_LOCAL",
@@ -2206,10 +2286,8 @@ class Server {
2206
2286
  })
2207
2287
  let cloudflare_links = []
2208
2288
  let local_links = []
2209
- console.log({ app_path, scripts })
2210
2289
  for(let script in this.kernel.memory.local) {
2211
2290
  let mem = this.kernel.memory.local[script]
2212
- console.log({ script, mem })
2213
2291
  if (mem.$share) {
2214
2292
  if (mem.$share.cloudflare) {
2215
2293
  for(let key in mem.$share.cloudflare) {
@@ -2802,47 +2880,6 @@ class Server {
2802
2880
  });
2803
2881
  })
2804
2882
 
2805
-
2806
-
2807
- // this.expose_app = express();
2808
- // this.expose_app.use(cors({
2809
- // origin: '*'
2810
- // }));
2811
- // this.expose_app.use('/', proxy(async (req) => {
2812
- // console.log("req.url", req.url)
2813
- // let tokens = req.url.split("/")
2814
- // console.log({ tokens })
2815
- // if (tokens.length >=2 ) {
2816
- // let app = tokens[1]
2817
- // console.log({ app })
2818
- // console.log("resolved = ", this.kernel.exposed[app])
2819
- // return this.kernel.exposed[app]
2820
- // }
2821
- // }, {
2822
- //// proxyReqPathResolver: (req) => {
2823
- //// console.log("proxyReqPathResolver", req.url)
2824
- //// let chunks = req.url.split("/")
2825
- //// let transformed
2826
- //// if (chunks.length > 3) {
2827
- //// transformed = "/" + chunks.slice(3).join("/")
2828
- //// } else {
2829
- //// transformed = "/"
2830
- //// }
2831
- //// console.log({ chunks, transformed })
2832
- //// return transformed
2833
- //// }
2834
- // }))
2835
- // this.expose_port = await portfinder.getPortPromise({ port: this.port })
2836
- // console.log("EXPOSE_PORT", this.expose_port)
2837
- // await new Promise((resolve, reject) => {
2838
- // this.expose_server = this.expose_app.listen(this.expose_port, () => {
2839
- // console.log(`Server listening on port ${this.expose_port}`)
2840
- // resolve()
2841
- // });
2842
- // this.exposeTerminator = createHttpTerminator({
2843
- // server: this.expose_server
2844
- // });
2845
- // })
2846
2883
  }
2847
2884
  }
2848
2885
  module.exports = Server
@@ -104,8 +104,8 @@ const install = async (name, url, term, socket, options) => {
104
104
  })
105
105
  } else {
106
106
  // ask the backend to create install.json and start.json if gradio
107
- //location.href = `/?selected=${name}`
108
- location.href = `/pinokio/browser/${name}`
107
+ //location.href = `/pinokio/browser/${name}`
108
+ location.href = `/initialize/${name}`
109
109
 
110
110
  }
111
111
  }
@@ -561,7 +561,7 @@ body.dark .loader-container {
561
561
  <a target="/share/<%=name%>" href="/share/<%=name%>", class="btn header-item frame-link" data-index="1" data-mode="refresh">
562
562
  <div class='tab'><i class="fa-solid fa-wifi"></i> Share</div>
563
563
  </a>
564
- <a target="/env/api/<%=name%>/ENVIRONMENT" href="/env/api/<%=name%>/ENVIRONMENT", class="btn header-item frame-link" data-index="1" data-mode="refresh">
564
+ <a target="/env/api/<%=name%>" href="/env/api/<%=name%>", class="btn header-item frame-link" data-index="1" data-mode="refresh">
565
565
  <div class='tab'><i class="fa-solid fa-gear"></i> Configure</div>
566
566
  </a>
567
567
  </div>
@@ -73,13 +73,25 @@ td.key {
73
73
  .button:hover {
74
74
 
75
75
  }
76
- #editor {
77
- box-sizing: border-box;
78
- max-width: 800px;
79
- padding: 20px;
80
- }
76
+ <% if (init) { %>
77
+ main {
78
+ width: 100%;
79
+ box-sizing: border-box;
80
+ max-width: 600px;
81
+ padding: 20px;
82
+ margin: 0 auto;
83
+ }
84
+ <% } else { %>
85
+ #editor {
86
+ width: 100%;
87
+ box-sizing: border-box;
88
+ max-width: 600px;
89
+ padding: 20px;
90
+ margin: 0 auto;
91
+ }
92
+ <% } %>
93
+
81
94
  header .runner {
82
- padding: 10px 0 0;
83
95
  }
84
96
  .disabled {
85
97
  opacity: 0.7;
@@ -119,6 +131,59 @@ body.dark .comment {
119
131
  #save {
120
132
  background: royalblue;
121
133
  }
134
+ a#customize {
135
+ text-decoration: underline;
136
+ cursor: pointer;
137
+ }
138
+ .e {
139
+ padding: 10px 0;
140
+ }
141
+ #editor {
142
+ padding: 20px 0;
143
+ }
144
+ .center {
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ }
149
+ body {
150
+ display: block;
151
+ }
152
+ .card {
153
+ display: flex;
154
+ padding: 10px 0;
155
+ box-sizing: border-box;
156
+ }
157
+ .card img {
158
+ width: 100px;
159
+ border-radius: 10px;
160
+ }
161
+ .card .description {
162
+ opacity: 0.8;
163
+ }
164
+ .card .title {
165
+ font-weight: bold;
166
+ font-size: 30px;
167
+ letter-spacing: -1px;
168
+ }
169
+ .card .col {
170
+ padding-left: 10px;
171
+ }
172
+ h1 {
173
+ font-size: 50px;
174
+ font-family: georgia;
175
+ font-style: italic;
176
+ }
177
+ footer {
178
+ background: none;
179
+ padding: 0;
180
+ text-align: right;
181
+ display: block;
182
+ margin-bottom: 20px;
183
+ }
184
+ footer .btn {
185
+ margin-left: 10px;
186
+ }
122
187
  </style>
123
188
  <script>
124
189
  document.addEventListener("DOMContentLoaded", async () => {
@@ -145,40 +210,70 @@ document.addEventListener("DOMContentLoaded", async () => {
145
210
  return res.json()
146
211
  })
147
212
  console.log("res" ,res)
148
- n.Noty({
149
- text: `Updated!`
150
- })
213
+ <% if (init && name) { %>
214
+ location.href = "/pinokio/browser/<%=name%>"
215
+ <% } else { %>
216
+ n.Noty({
217
+ text: `Updated!`
218
+ })
219
+ <% } %>
151
220
  })
221
+ <% if (init) { %>
222
+ document.querySelector("#customize").addEventListener("click", (e) => {
223
+ e.preventDefault()
224
+ e.stopPropagation()
225
+ document.querySelector("#editor").classList.toggle("hidden")
226
+ })
227
+ <% } %>
152
228
  })
153
229
  </script>
154
230
  </head>
155
- <body class='columns <%=theme%>'>
156
- <header class='navheader grabbable'>
157
- <h1>
158
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
159
- <%=filepath%>
160
- </h1>
161
- <div class='runner'>
162
- <div id='save' class='btn'>
163
- <span class='save'><i class="fa-solid fa-check"></i> Save</span>
164
- </div>
165
- <a class='btn' href="<%=editorpath%>"><i class="fa-solid fa-pen-to-square"></i> Edit file</a>
166
- <button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> Open in File Explorer</button>
167
- </div>
168
- </header>
169
- <main>
170
- <div id='editor'>
171
- <% items.forEach((item) => { %>
172
- <% if (item.type === "comment") { %>
173
- <div class='comment'><%=item.val.replaceAll(/^[ #]+/g, "")%></div>
174
- <% } else { %>
175
- <div class='env-item'>
176
- <label for="<%=item.key%>"><%=item.key%></label>
177
- <input id="<%=item.key%>" type="text" value="<%=item.val%>">
231
+ <body class='<%=theme%> <%=init ? 'center' : ''%>'>
232
+ <main>
233
+ <% if (init) { %>
234
+ <div>
235
+ <h1>Install</h1>
236
+ <% if (config) { %>
237
+ <div class='card'>
238
+ <% if (config.icon) { %>
239
+ <img src="<%=config.icon%>">
240
+ <% } %>
241
+ <div class='col'>
242
+ <div class='title'><%=config.title%></div>
243
+ <div class='description'><%=config.description%></div>
178
244
  </div>
179
- <% } %>
180
- <% }) %>
245
+ </div>
246
+ <% } %>
247
+ <footer>
248
+ <button id='customize' class='btn'><i class="fa-solid fa-gear"></i> Customize</button>
249
+ <div id='save' class='btn'>
250
+ <span class='save'><i class="fa-solid fa-check"></i> Install</span>
251
+ </div>
252
+ </footer>
181
253
  </div>
182
- </main>
254
+ <% } else { %>
255
+ <header class='navheader grabbable'>
256
+ <div class='runner'>
257
+ <div id='save' class='btn'>
258
+ <span class='save'><i class="fa-solid fa-check"></i> Save</span>
259
+ </div>
260
+ <a class='btn' href="<%=editorpath%>"><i class="fa-solid fa-pen-to-square"></i> Edit file</a>
261
+ <button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> Open in File Explorer</button>
262
+ </div>
263
+ </header>
264
+ <% } %>
265
+ <div id='editor' class='<%=init ? "hidden" : ''%>'>
266
+ <% items.forEach((item) => { %>
267
+ <% if (item.type === "comment") { %>
268
+ <div class='comment'><%=item.val.replaceAll(/^[ #]+/g, "")%></div>
269
+ <% } else { %>
270
+ <div class='env-item'>
271
+ <label for="<%=item.key%>"><%=item.key%></label>
272
+ <input id="<%=item.key%>" type="text" value="<%=item.val%>">
273
+ </div>
274
+ <% } %>
275
+ <% }) %>
276
+ </div>
277
+ </main>
183
278
  </body>
184
279
  </html>
@@ -0,0 +1,109 @@
1
+ <html class='columns'>
2
+ <head>
3
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
4
+ <script src="/hotkeys.min.js"></script>
5
+ <script src="/ace/ace.js"></script>
6
+ <script src="/noty.js"></script>
7
+ <script src="/notyq.js"></script>
8
+ <script src="/xterm.js"></script>
9
+ <script src="/xterm-addon-fit.js"></script>
10
+ <script src="/xterm-addon-web-links.js"></script>
11
+ <script src="/xterm-theme.js"></script>
12
+ <script src="/xterm-addon-search.js"></script>
13
+ <script src="/xterm-addon-search-bar.js"></script>
14
+ <script src="/sweetalert2.js"></script>
15
+ <script src="/Socket.js"></script>
16
+ <script src="/common.js"></script>
17
+ <script src="/he.js"></script>
18
+ <script src="/opener.js"></script>
19
+ <script src="/nav.js"></script>
20
+ <script src="/autoexpand.js"></script>
21
+ <script src="/modalinput.js"></script>
22
+ <script src="/simplemodal.js"></script>
23
+ <script src="/waitmodal.js"></script>
24
+ <script src="/notifyinput.js"></script>
25
+ <script src="/report.js"></script>
26
+ <link href="/xterm.min.css" rel="stylesheet" />
27
+ <link href="/css/fontawesome.min.css" rel="stylesheet">
28
+ <link href="/css/solid.min.css" rel="stylesheet">
29
+ <link href="/css/regular.min.css" rel="stylesheet">
30
+ <link href="/css/brands.min.css" rel="stylesheet">
31
+ <link href="/style.css" rel="stylesheet"/>
32
+ <link href="/noty.css" rel="stylesheet"/>
33
+ <% if (agent === "electron") { %>
34
+ <link href="/electron.css" rel="stylesheet"/>
35
+ <% } %>
36
+ <style>
37
+ main {
38
+ max-width: 500px;
39
+ margin: 50px auto;
40
+ width: 100%;
41
+ }
42
+ h1 {
43
+ letter-spacing: -1px;
44
+ }
45
+ .item {
46
+ border-radius: 5px;
47
+ padding: 10px;
48
+ box-sizing: border-box;
49
+ display: flex;
50
+ align-items: flex-start;
51
+ /*
52
+ border: 1px solid rgba(0,0,0,0.07);
53
+ */
54
+ background: rgba(0,0,0,0.04);
55
+ margin: 10px 0;
56
+
57
+ }
58
+ .item .btn {
59
+ width: 50px;
60
+ text-align: center;
61
+ }
62
+ .item img {
63
+ width: 100px;
64
+ }
65
+ .item .col {
66
+ flex-grow: 1;
67
+ padding: 10px;
68
+ box-sizing: border-box;
69
+ }
70
+ footer {
71
+ background: none;
72
+ }
73
+ footer a.btn {
74
+ text-align: center;
75
+ display: block;
76
+ width: 100%;
77
+ }
78
+ .e {
79
+ padding: 5px 0;
80
+ }
81
+ </style>
82
+ </head>
83
+ <body class='columns <%=theme%>'>
84
+ <header class='navheader grabbable'>
85
+ </header>
86
+ <main>
87
+ <h1>Requirements</h1>
88
+ <div class='e'>
89
+ <div>To run <%=name%>, you need to have the following programs installed.</div>
90
+ <div>Get the apps if you haven't already, and press "Done".</div>
91
+ </div>
92
+ <div class='items'>
93
+ <% items.forEach((item) => { %>
94
+ <div class='item'>
95
+ <img src="<%=item.icon%>">
96
+ <div class='col'>
97
+ <div class='title'><%=item.title%></div>
98
+ <div class='description'><%=item.description%></div>
99
+ </div>
100
+ <a target="_blank" features="browser" href='<%=item.href%>' class='btn'>Get</a>
101
+ </div>
102
+ <% }) %>
103
+ </div>
104
+ <footer>
105
+ <a class='btn' href="/env/api/<%=name%>?init=true">Done</a>
106
+ </footer>
107
+ </main>
108
+ </body>
109
+ </html>
@@ -302,7 +302,7 @@ hr {
302
302
  <br>
303
303
  <div>Edit the system ENVIRONMENT file to customize pinokio system wide settings, such as where files are stored, terminal behavior, etc.</div>
304
304
  <br>
305
- <a class='btn' href="/env/ENVIRONMENT"><i class="fa-regular fa-pen-to-square"></i> Edit ENVIRONMENT</a>
305
+ <a class='btn' href="/env"><i class="fa-regular fa-pen-to-square"></i> Edit ENVIRONMENT</a>
306
306
  </div>
307
307
  <hr/>
308
308
  <div class='troubleshoot'>
@@ -164,7 +164,7 @@ document.addEventListener("DOMContentLoaded", async () => {
164
164
  "Content-Type": "application/json"
165
165
  },
166
166
  body: JSON.stringify({
167
- filepath: "api/" + location.pathname.slice(7) + "/ENVIRONMENT",
167
+ filepath: "api/" + location.pathname.slice(7),
168
168
  vals
169
169
  })
170
170
  }).then((res) => {
@@ -194,6 +194,7 @@ document.addEventListener("DOMContentLoaded", async () => {
194
194
  <li>This will let you share your local Pinokio app to the public internet, which anyone with a URL can access.</li>
195
195
  <li>Powered by <a href="https://www.cloudflare.com/products/tunnel/" target="_blank" features="browser">Cloudflare Tunnel</a></li>
196
196
  <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>
197
198
  </ul>
198
199
  <% cloudflare_links.forEach((link) => { %>
199
200
  <div class='shared'>