synfull 0.1.2 → 0.1.3
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/README.md +2 -2
- package/package.json +1 -1
- package/scripts/synfull.cjs +60 -9
package/README.md
CHANGED
|
@@ -13,11 +13,11 @@ synfull start
|
|
|
13
13
|
synfull open
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
During interactive `synfull setup`, you can choose whether to bind to `0.0.0.0` for access from other devices on your LAN; localhost-only (`127.0.0.1`) remains the default, and non-interactive setup stays local-only. LAN binding exposes the login page and server to every reachable network interface: use a trusted LAN, configure the host firewall to allow only
|
|
16
|
+
During interactive `synfull setup`, you can choose whether to bind to `0.0.0.0` for access from other devices on your LAN; localhost-only (`127.0.0.1`) remains the default, and non-interactive setup stays local-only. On Linux, setup also offers to add your account to the `docker` group so the Docker integration can access the daemon. This is optional and grants root-equivalent control of the computer; decline if you do not fully trust the account with administrator-level Docker access. If Synfull's systemd service is installed, setup restarts it after group membership changes; otherwise, an interactive user session may need a logout/login before new group membership applies. LAN binding exposes the login page and server to every reachable network interface: use a trusted LAN, configure the host firewall to allow only intended devices/subnets, change the initial `admin` / `admin` password locally before signing in remotely, and do not expose Synfull directly to the public internet. npm installation alone does not register a background service or change system startup.
|
|
17
17
|
|
|
18
18
|
### Commands
|
|
19
19
|
|
|
20
|
-
- `synfull setup` asks whether to allow LAN access, then prepares the isolated Python runtime and dependencies.
|
|
20
|
+
- `synfull setup` asks whether to allow LAN access and, on Linux, whether to grant the current account Docker-group access; it then prepares the isolated Python runtime and dependencies. Both choices are optional and are used by later starts/service registration. Docker group membership is root-equivalent. If an installed Synfull systemd service is present, setup restarts it after adding group access; otherwise log out and back in for a shell session to receive the new group membership.
|
|
21
21
|
- `synfull start` runs in the background; `synfull run` keeps the server in the foreground.
|
|
22
22
|
- `synfull status`, `synfull stop`, and `synfull open` manage a manually started instance.
|
|
23
23
|
- `synfull install-service` explicitly enables automatic start and restart. On Windows this registers a per-user logon scheduled task. On Linux it creates and enables a system-wide systemd service and therefore requires `sudo`; the service runs as your invoking user, not root.
|
package/package.json
CHANGED
package/scripts/synfull.cjs
CHANGED
|
@@ -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
|
-
|
|
74
|
-
|
|
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') {
|
|
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 }
|