synfull 0.1.2 → 0.1.4

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="theme-color" content="#0b1220" />
7
7
  <title>Synfull</title>
8
- <script type="module" crossorigin src="/assets/index-ERXSRoTY.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-hx4yW_Xg.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-B40UafPr.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synfull",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Local-first cross-platform host monitoring dashboard",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -66,16 +66,62 @@ function saveBindHost(host) {
66
66
  fs.mkdirSync(HOME, { recursive: true })
67
67
  fs.writeFileSync(CLI_CONFIG, `${JSON.stringify({ bindHost: host }, null, 2)}\n`, { mode: 0o600 })
68
68
  }
69
- async function configureBindHost() {
69
+ async function configureBindHost(rl) {
70
70
  if (!process.stdin.isTTY || !process.stdout.isTTY) return
71
+ const answer = await rl.question('Allow other devices on your LAN to access Synfull by binding to 0.0.0.0? (y/N): ')
72
+ const host = /^y(es)?$/i.test(answer.trim()) ? '0.0.0.0' : '127.0.0.1'
73
+ saveBindHost(host)
74
+ console.log(host === '0.0.0.0'
75
+ ? 'LAN access enabled. Change the initial admin password from this machine before signing in from another device; use a trusted LAN and configure your firewall.'
76
+ : 'Synfull will only accept connections from this machine.')
77
+ }
78
+ async function configureDockerAccess(rl, options = {}) {
79
+ const platform = options.platform || process.platform
80
+ const interactive = options.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY)
81
+ const username = options.username || process.env.SUDO_USER || os.userInfo().username
82
+ const isRoot = options.isRoot ?? Boolean(process.getuid && process.getuid() === 0)
83
+ const spawnCommand = options.spawnSync || spawnSync
84
+ const runCommand = options.run || run
85
+ if (platform !== 'linux' || !interactive) return false
86
+ if (isRoot) {
87
+ console.log('Run `synfull setup` as your normal account (not sudo); setup will request sudo only if Docker group access is approved.')
88
+ return false
89
+ }
90
+ const dockerGroup = spawnCommand('getent', ['group', 'docker'], { encoding: 'utf8', windowsHide: true })
91
+ if (dockerGroup.status !== 0) {
92
+ console.log('No Linux docker group was found. Install/configure Docker Engine first; Synfull did not change account permissions.')
93
+ return false
94
+ }
95
+ console.log('Docker group membership grants root-equivalent control of this computer (including control over containers and host files).')
96
+ const answer = await rl.question(`Allow Synfull to use Docker by adding ${username} to the docker group? (y/N): `)
97
+ if (!/^y(es)?$/i.test(answer.trim())) {
98
+ console.log('Docker group access was not changed. The Docker integration will remain unavailable unless your account already has socket access.')
99
+ return false
100
+ }
101
+ const groups = spawnCommand('id', ['-nG', username], { encoding: 'utf8', windowsHide: true })
102
+ const alreadyMember = groups.status === 0 && groups.stdout.trim().split(/\s+/).includes('docker')
103
+ if (!alreadyMember) {
104
+ const command = process.getuid && process.getuid() === 0 ? 'usermod' : 'sudo'
105
+ const args = command === 'sudo' ? ['usermod', '-aG', 'docker', username] : ['-aG', 'docker', username]
106
+ runCommand(command, args)
107
+ console.log(`Added ${username} to the docker group.`)
108
+ } else {
109
+ console.log(`${username} is already in the docker group.`)
110
+ }
111
+ const serviceInstalled = spawnCommand('systemctl', ['cat', 'synfull-npm.service'], { stdio: 'ignore', windowsHide: true }).status === 0
112
+ if (!serviceInstalled) console.log('No Synfull systemd service is installed. Log out/in (or start a fresh session with Docker group membership) before running Synfull so it receives the new group permissions.')
113
+ return serviceInstalled
114
+ }
115
+ function restartSynfullService(runCommand = run) {
116
+ runCommand('sudo', ['systemctl', 'restart', 'synfull-npm.service'])
117
+ console.log('Restarted the Synfull system service so it picks up Docker group access.')
118
+ }
119
+ async function configureSetup() {
120
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return false
71
121
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
72
122
  try {
73
- const answer = await rl.question('Allow other devices on your LAN to access Synfull by binding to 0.0.0.0? (y/N): ')
74
- const host = /^y(es)?$/i.test(answer.trim()) ? '0.0.0.0' : '127.0.0.1'
75
- saveBindHost(host)
76
- console.log(host === '0.0.0.0'
77
- ? 'LAN access enabled. Change the initial admin password from this machine before signing in from another device; use a trusted LAN and configure your firewall.'
78
- : 'Synfull will only accept connections from this machine.')
123
+ await configureBindHost(rl)
124
+ return await configureDockerAccess(rl)
79
125
  } finally {
80
126
  rl.close()
81
127
  }
@@ -237,7 +283,12 @@ async function main() {
237
283
  if (command === '--version' || command === '-v') { console.log(VERSION); return }
238
284
  if (command === '--help' || command === '-h') { help(); return }
239
285
  if (!['win32', 'linux'].includes(process.platform)) throw new Error('Synfull npm CLI currently supports Windows and Linux.')
240
- if (command === 'setup') { await configureBindHost(); ensureRuntime(); console.log(`Runtime ready. Data directory: ${STATE_DIR}`) }
286
+ if (command === 'setup') {
287
+ const restartServiceForDocker = await configureSetup()
288
+ ensureRuntime()
289
+ if (restartServiceForDocker) restartSynfullService()
290
+ console.log(`Runtime ready. Data directory: ${STATE_DIR}`)
291
+ }
241
292
  else if (command === 'start') startServer(false)
242
293
  else if (command === 'run') startServer(true)
243
294
  else if (command === 'stop') stopServer()
@@ -253,4 +304,4 @@ async function main() {
253
304
  else help()
254
305
  }
255
306
  if (require.main === module) main().catch(error => { console.error(`Synfull: ${error.message}`); process.exitCode = 1 })
256
- module.exports = { ensureRuntime, serverEnvironment, configuredBindHost, selectedBindHost, saveBindHost, APP_DIR, STATE_DIR, ROOT }
307
+ module.exports = { ensureRuntime, serverEnvironment, configuredBindHost, selectedBindHost, saveBindHost, configureDockerAccess, restartSynfullService, APP_DIR, STATE_DIR, ROOT }