freeschema 1.0.3 → 1.0.5
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/bin/freeschema.js
CHANGED
|
@@ -114,6 +114,44 @@ function generateJwt() {
|
|
|
114
114
|
return crypto.randomBytes(32).toString('hex');
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
// Mosquitto 2.0 $7$ PBKDF2-HMAC-SHA512 password entry
|
|
118
|
+
function generateMosquittoPassword(username, password) {
|
|
119
|
+
const iterations = 101;
|
|
120
|
+
const salt = crypto.randomBytes(12);
|
|
121
|
+
const hash = crypto.pbkdf2Sync(password, salt, iterations, 64, 'sha512');
|
|
122
|
+
return `${username}:$7$${iterations}$${salt.toString('base64')}$${hash.toString('base64')}\n`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function ensureMosquittoConfig(cwd) {
|
|
126
|
+
const dir = (sub) => path.join(cwd, 'mosquitto', sub);
|
|
127
|
+
['config', 'data', 'log'].forEach(d => {
|
|
128
|
+
if (!fs.existsSync(dir(d))) fs.mkdirSync(dir(d), { recursive: true });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const confDest = path.join(dir('config'), 'mosquitto.conf');
|
|
132
|
+
if (!fs.existsSync(confDest)) {
|
|
133
|
+
const confSrc = path.join(TEMPLATES_DIR, 'mosquitto', 'config', 'mosquitto.conf');
|
|
134
|
+
if (fs.existsSync(confSrc)) fs.copyFileSync(confSrc, confDest);
|
|
135
|
+
else fs.writeFileSync(confDest, [
|
|
136
|
+
'listener 1883', 'allow_anonymous false',
|
|
137
|
+
'password_file /mosquitto/config/password.txt', '',
|
|
138
|
+
'listener 9001', 'protocol websockets', 'allow_anonymous false', '',
|
|
139
|
+
'persistence true', 'persistence_location /mosquitto/data/',
|
|
140
|
+
'log_dest file /mosquitto/log/mosquitto.log', '',
|
|
141
|
+
].join('\n'));
|
|
142
|
+
console.log(' Created mosquitto/config/mosquitto.conf');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const pwDest = path.join(dir('config'), 'password.txt');
|
|
146
|
+
if (!fs.existsSync(pwDest)) {
|
|
147
|
+
const env = readEnv();
|
|
148
|
+
const mqttUser = env.MQTT_USERNAME || 'freeschema';
|
|
149
|
+
const mqttPass = env.MQTT_PASSWORD || 'freeschema';
|
|
150
|
+
fs.writeFileSync(pwDest, generateMosquittoPassword(mqttUser, mqttPass));
|
|
151
|
+
console.log(' Created mosquitto/config/password.txt');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
117
155
|
function fmtBytes(b) {
|
|
118
156
|
if (b >= 1073741824) return (b / 1073741824).toFixed(1) + ' GB';
|
|
119
157
|
if (b >= 1048576) return (b / 1048576).toFixed(1) + ' MB';
|
|
@@ -161,6 +199,37 @@ function makeProgressBar(label) {
|
|
|
161
199
|
};
|
|
162
200
|
}
|
|
163
201
|
|
|
202
|
+
// Patches known issues in the local docker-compose.yml so existing installs
|
|
203
|
+
// are automatically healed on start/update without requiring a re-init.
|
|
204
|
+
const COMPOSE_PATCHES = [
|
|
205
|
+
{
|
|
206
|
+
find: /- \.\/mosquitto\/config:\/mosquitto\/config:ro/g,
|
|
207
|
+
replace: '- ./mosquitto/config:/mosquitto/config',
|
|
208
|
+
label: 'mosquitto config mount (removed :ro)',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
find: /(image: eclipse-mosquitto:[^\n]+\n)(?! user:)/,
|
|
212
|
+
replace: '$1 user: "1883:1883"\n',
|
|
213
|
+
label: 'mosquitto user (1883:1883 to skip chown on Windows)',
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
function patchComposeFile() {
|
|
218
|
+
const composePath = path.join(process.cwd(), 'docker-compose.yml');
|
|
219
|
+
if (!fs.existsSync(composePath)) return;
|
|
220
|
+
let content = fs.readFileSync(composePath, 'utf8');
|
|
221
|
+
let patched = false;
|
|
222
|
+
for (const { find, replace, label } of COMPOSE_PATCHES) {
|
|
223
|
+
if (find.test(content)) {
|
|
224
|
+
content = content.replace(find, replace);
|
|
225
|
+
patched = true;
|
|
226
|
+
console.log(` Patched docker-compose.yml: ${label}`);
|
|
227
|
+
}
|
|
228
|
+
find.lastIndex = 0;
|
|
229
|
+
}
|
|
230
|
+
if (patched) fs.writeFileSync(composePath, content);
|
|
231
|
+
}
|
|
232
|
+
|
|
164
233
|
function runCompose(composeArgs, opts = {}) {
|
|
165
234
|
const cwd = process.cwd();
|
|
166
235
|
if (!fs.existsSync(path.join(cwd, 'docker-compose.yml'))) {
|
|
@@ -309,6 +378,10 @@ async function cmdInit() {
|
|
|
309
378
|
const mqttPass = await prompt(' MQTT password', readEnvVar(envPath, 'MQTT_PASSWORD') || 'freeschema');
|
|
310
379
|
setEnvVar(envPath, 'MQTT_USERNAME', mqttUser);
|
|
311
380
|
setEnvVar(envPath, 'MQTT_PASSWORD', mqttPass);
|
|
381
|
+
// Write password.txt with correct hash for the chosen credentials
|
|
382
|
+
const pwDir = path.join(target, 'mosquitto', 'config');
|
|
383
|
+
if (!fs.existsSync(pwDir)) fs.mkdirSync(pwDir, { recursive: true });
|
|
384
|
+
fs.writeFileSync(path.join(pwDir, 'password.txt'), generateMosquittoPassword(mqttUser, mqttPass));
|
|
312
385
|
console.log(' MQTT configured (local) ✓');
|
|
313
386
|
} else {
|
|
314
387
|
console.log('\n External MQTT broker:');
|
|
@@ -433,6 +506,7 @@ function waitForMySQL(container, user, pass, maxAttempts = 30) {
|
|
|
433
506
|
}
|
|
434
507
|
|
|
435
508
|
function cmdStart() {
|
|
509
|
+
patchComposeFile();
|
|
436
510
|
const cwd = process.cwd();
|
|
437
511
|
const missing = ['.env', '.env.frontend'].filter(f => !fs.existsSync(path.join(cwd, f)));
|
|
438
512
|
if (missing.length) {
|
|
@@ -444,7 +518,10 @@ function cmdStart() {
|
|
|
444
518
|
const profiles = [];
|
|
445
519
|
const flags = args.slice(1);
|
|
446
520
|
if (flags.includes('--local-db') || flags.includes('--db')) profiles.push('--profile', 'local-db');
|
|
447
|
-
if (flags.includes('--local-mqtt') || flags.includes('--mqtt'))
|
|
521
|
+
if (flags.includes('--local-mqtt') || flags.includes('--mqtt')) {
|
|
522
|
+
profiles.push('--profile', 'local-mqtt');
|
|
523
|
+
ensureMosquittoConfig(cwd);
|
|
524
|
+
}
|
|
448
525
|
|
|
449
526
|
const seedIdx = args.indexOf('--seed');
|
|
450
527
|
const seedFile = seedIdx !== -1 ? args[seedIdx + 1] : null;
|
|
@@ -501,6 +578,7 @@ function cmdPull() {
|
|
|
501
578
|
|
|
502
579
|
function cmdUpdate() {
|
|
503
580
|
console.log('Updating FreeSchema…\n');
|
|
581
|
+
patchComposeFile();
|
|
504
582
|
|
|
505
583
|
// 1. Update the CLI itself via npm
|
|
506
584
|
console.log('Step 1/2 — Updating freeschema CLI…');
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
listener 1883
|
|
2
|
-
allow_anonymous false
|
|
3
|
-
password_file /mosquitto/config/password.txt
|
|
4
|
-
|
|
5
|
-
listener 9001
|
|
6
|
-
protocol websockets
|
|
7
|
-
allow_anonymous false
|
|
8
|
-
|
|
9
|
-
persistence true
|
|
10
|
-
persistence_location /mosquitto/data/
|
|
11
|
-
log_dest file /mosquitto/log/mosquitto.log
|
|
1
|
+
listener 1883
|
|
2
|
+
allow_anonymous false
|
|
3
|
+
password_file /mosquitto/config/password.txt
|
|
4
|
+
|
|
5
|
+
listener 9001
|
|
6
|
+
protocol websockets
|
|
7
|
+
allow_anonymous false
|
|
8
|
+
|
|
9
|
+
persistence true
|
|
10
|
+
persistence_location /mosquitto/data/
|
|
11
|
+
log_dest file /mosquitto/log/mosquitto.log
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
freeschema:$7$101$orXdSDv8OTk6tUnW$XhsqgkbuoDKh0PqtwNBfXZxyPVSKkv7zgHrjAKL5uBnl79kX0AXrSn8o4TWbeVYFVEE4q+r2IiadBPAKORw4kQ==
|