freeschema 1.0.4 → 1.0.6

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';
@@ -174,6 +212,11 @@ const COMPOSE_PATCHES = [
174
212
  replace: '$1 user: "1883:1883"\n',
175
213
  label: 'mosquitto user (1883:1883 to skip chown on Windows)',
176
214
  },
215
+ {
216
+ find: /(--default-authentication-plugin=mysql_native_password)(?!\s*\n\s*--log-bin-trust)/,
217
+ replace: '$1\n --log-bin-trust-function-creators=1',
218
+ label: 'MySQL log_bin_trust_function_creators (allows stored functions/triggers)',
219
+ },
177
220
  ];
178
221
 
179
222
  function patchComposeFile() {
@@ -340,6 +383,10 @@ async function cmdInit() {
340
383
  const mqttPass = await prompt(' MQTT password', readEnvVar(envPath, 'MQTT_PASSWORD') || 'freeschema');
341
384
  setEnvVar(envPath, 'MQTT_USERNAME', mqttUser);
342
385
  setEnvVar(envPath, 'MQTT_PASSWORD', mqttPass);
386
+ // Write password.txt with correct hash for the chosen credentials
387
+ const pwDir = path.join(target, 'mosquitto', 'config');
388
+ if (!fs.existsSync(pwDir)) fs.mkdirSync(pwDir, { recursive: true });
389
+ fs.writeFileSync(path.join(pwDir, 'password.txt'), generateMosquittoPassword(mqttUser, mqttPass));
343
390
  console.log(' MQTT configured (local) ✓');
344
391
  } else {
345
392
  console.log('\n External MQTT broker:');
@@ -476,7 +523,10 @@ function cmdStart() {
476
523
  const profiles = [];
477
524
  const flags = args.slice(1);
478
525
  if (flags.includes('--local-db') || flags.includes('--db')) profiles.push('--profile', 'local-db');
479
- if (flags.includes('--local-mqtt') || flags.includes('--mqtt')) profiles.push('--profile', 'local-mqtt');
526
+ if (flags.includes('--local-mqtt') || flags.includes('--mqtt')) {
527
+ profiles.push('--profile', 'local-mqtt');
528
+ ensureMosquittoConfig(cwd);
529
+ }
480
530
 
481
531
  const seedIdx = args.indexOf('--seed');
482
532
  const seedFile = seedIdx !== -1 ? args[seedIdx + 1] : null;
@@ -492,13 +542,14 @@ function cmdStart() {
492
542
  const env = readEnv();
493
543
  const dbUser = env.DB_USER || env.MYSQL_USER || 'freeschema';
494
544
  const dbPass = env.DB_PASSWORD || env.MYSQL_PASSWORD || 'Freeschema@123';
545
+ const rootPass = env.MYSQL_ROOT_PASSWORD || ('Admin@' + dbPass);
495
546
  const dbName = env.DB_DATABASE || 'freeschema_db';
496
547
  const container = getMysqlContainer();
497
548
  if (!waitForMySQL(container, dbUser, dbPass)) die('MySQL did not become ready — check logs with `freeschema logs mysql-server`.');
498
549
  console.log(` Seeding ${dbName} from ${seedFile}…`);
499
550
  const result = spawnSync(
500
551
  'docker',
501
- ['exec', '-i', container, 'mysql', `-u${dbUser}`, `-p${dbPass}`, dbName],
552
+ ['exec', '-i', container, 'mysql', '-uroot', `-p${rootPass}`, dbName],
502
553
  { input: fs.readFileSync(seedFile), stdio: ['pipe', 'inherit', 'inherit'] }
503
554
  );
504
555
  if (result.error || result.status !== 0) die('Seed failed — check container logs.');
@@ -635,15 +686,15 @@ function cmdDbRestore() {
635
686
  if (!fs.existsSync(sqlFile)) die(`File not found: ${sqlFile}`);
636
687
 
637
688
  const env = readEnv();
638
- const dbUser = env.DB_USER || env.MYSQL_USER || 'freeschema';
639
689
  const dbPass = env.DB_PASSWORD || env.MYSQL_PASSWORD || 'Freeschema@123';
690
+ const rootPass = env.MYSQL_ROOT_PASSWORD || ('Admin@' + dbPass);
640
691
  const dbName = env.DB_DATABASE || 'freeschema_db';
641
692
  const container = getMysqlContainer();
642
693
 
643
694
  console.log(`Restoring ${sqlFile} → ${dbName}…`);
644
695
  const result = spawnSync(
645
696
  'docker',
646
- ['exec', '-i', container, 'mysql', `-u${dbUser}`, `-p${dbPass}`, dbName],
697
+ ['exec', '-i', container, 'mysql', '-uroot', `-p${rootPass}`, dbName],
647
698
  { input: fs.readFileSync(sqlFile), stdio: ['pipe', 'inherit', 'inherit'] }
648
699
  );
649
700
  if (result.error || result.status !== 0) die('Restore failed — check container logs.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freeschema",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "FreeSchema — self-hosted deployment CLI",
5
5
  "keywords": [
6
6
  "freeschema",
@@ -39,6 +39,7 @@ services:
39
39
  user: "999:999"
40
40
  command: >
41
41
  --default-authentication-plugin=mysql_native_password
42
+ --log-bin-trust-function-creators=1
42
43
  healthcheck:
43
44
  test: ["CMD-SHELL", "mysqladmin ping -h localhost -u${MYSQL_USER:-freeschema} -p${MYSQL_PASSWORD:-Freeschema@123} --silent"]
44
45
  interval: 10s