freeschema 1.0.9 → 1.0.10
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 +88 -95
- package/package.json +1 -1
package/bin/freeschema.js
CHANGED
|
@@ -614,19 +614,6 @@ async function cmdStart() {
|
|
|
614
614
|
console.log(' CLIENT_SECRET is not configured.');
|
|
615
615
|
console.log(' Setting up admin credentials…');
|
|
616
616
|
console.log('─────────────────────────────────────────');
|
|
617
|
-
|
|
618
|
-
// Wait for MySQL to be ready before inserting credentials
|
|
619
|
-
try {
|
|
620
|
-
const container = getMysqlContainer();
|
|
621
|
-
const env = readEnv();
|
|
622
|
-
const dbUser = env.DB_USER || env.MYSQL_USER || 'freeschema';
|
|
623
|
-
const dbPass = env.DB_PASSWORD || env.MYSQL_PASSWORD || 'Freeschema@123';
|
|
624
|
-
waitForMySQL(container, dbUser, dbPass);
|
|
625
|
-
} catch (e) {
|
|
626
|
-
console.log(' (skipping credentials setup — MySQL not running)');
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
617
|
await cmdSetupCredentials();
|
|
631
618
|
}
|
|
632
619
|
}
|
|
@@ -772,116 +759,122 @@ function cmdDbRestore() {
|
|
|
772
759
|
|
|
773
760
|
// ── setup-credentials ─────────────────────────────────────────────────────────
|
|
774
761
|
|
|
775
|
-
function
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
762
|
+
function getWicoContainer() {
|
|
763
|
+
const out = runComposeOutput(['ps', '--format', 'json']);
|
|
764
|
+
if (!out) return null;
|
|
765
|
+
const containers = out.split('\n')
|
|
766
|
+
.map(l => { try { return JSON.parse(l); } catch { return null; } })
|
|
767
|
+
.filter(Boolean);
|
|
768
|
+
const wico = containers.find(c => c.Service === 'wico-server' || (c.Name || '').includes('wico-server'));
|
|
769
|
+
return wico ? (wico.Name || wico.ID) : null;
|
|
782
770
|
}
|
|
783
771
|
|
|
784
|
-
function
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
772
|
+
function waitForWicoServer(container, maxAttempts = 60) {
|
|
773
|
+
process.stdout.write(' Waiting for wico-server');
|
|
774
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
775
|
+
const r = spawnSync('docker', [
|
|
776
|
+
'exec', container, 'curl', '-sf', 'http://localhost:7000/health'
|
|
777
|
+
], { stdio: 'pipe' });
|
|
778
|
+
if (r.status === 0) { process.stdout.write(' ready\n'); return true; }
|
|
779
|
+
process.stdout.write('.');
|
|
780
|
+
sleep(3000);
|
|
781
|
+
}
|
|
782
|
+
process.stdout.write(' timed out\n');
|
|
783
|
+
return false;
|
|
795
784
|
}
|
|
796
785
|
|
|
797
786
|
async function cmdSetupCredentials() {
|
|
798
787
|
const envPath = path.join(process.cwd(), '.env');
|
|
799
788
|
if (!fs.existsSync(envPath)) die('.env not found. Run `freeschema init` first.');
|
|
800
789
|
|
|
801
|
-
|
|
802
|
-
const dbName = env.DB_DATABASE || env.MYSQL_DATABASE || 'freeschema_db';
|
|
790
|
+
console.log('\nSetting up CLIENT_ID and CLIENT_SECRET via API\n');
|
|
803
791
|
|
|
804
|
-
|
|
792
|
+
// Find wico-server container
|
|
793
|
+
const container = getWicoContainer();
|
|
794
|
+
if (!container) die('wico-server is not running.\nStart with `freeschema start`.');
|
|
805
795
|
|
|
806
|
-
//
|
|
807
|
-
|
|
808
|
-
|
|
796
|
+
// Wait for wico-server to be healthy
|
|
797
|
+
if (!waitForWicoServer(container)) {
|
|
798
|
+
die('wico-server did not become ready.\nCheck logs: freeschema logs wico-server');
|
|
799
|
+
}
|
|
809
800
|
|
|
810
|
-
//
|
|
811
|
-
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
console.log('done');
|
|
801
|
+
// Prompt for admin credentials
|
|
802
|
+
const email = await prompt('Admin email');
|
|
803
|
+
const password = await promptSecret('Admin password');
|
|
804
|
+
if (!email || !password) die('Email and password are required.');
|
|
815
805
|
|
|
816
|
-
// Step
|
|
817
|
-
process.stdout.write('[
|
|
818
|
-
const
|
|
806
|
+
// Step 1: Login
|
|
807
|
+
process.stdout.write('\n[1/3] Logging in… ');
|
|
808
|
+
const loginBody = JSON.stringify({ email, password, application: 'boomconsole' });
|
|
809
|
+
const loginResult = spawnSync('docker', [
|
|
810
|
+
'exec', container, 'curl', '-sf',
|
|
811
|
+
'-X', 'POST', 'http://localhost:7000/api/auth/login',
|
|
812
|
+
'-H', 'Content-Type: application/json',
|
|
813
|
+
'-d', loginBody
|
|
814
|
+
], { stdio: ['inherit', 'pipe', 'pipe'] });
|
|
819
815
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
SET @type_id = (
|
|
825
|
-
SELECT id FROM the_concepts
|
|
826
|
-
WHERE character_value = 'the_client_secret'
|
|
827
|
-
ORDER BY id ASC LIMIT 1
|
|
828
|
-
);
|
|
829
|
-
|
|
830
|
-
-- Insert the secret hash as a new concept
|
|
831
|
-
INSERT INTO the_concepts (
|
|
832
|
-
user_id, category_id, category_user_id, type_id, type_user_id,
|
|
833
|
-
character_value, security_id, security_user_id, access_id, access_user_id,
|
|
834
|
-
session_information_id, session_information_user_id
|
|
835
|
-
) VALUES (
|
|
836
|
-
999, @type_id, 999, @type_id, 999,
|
|
837
|
-
'${hashedSecret}', 4, 999, 4, 999, 999, 999
|
|
838
|
-
);
|
|
839
|
-
|
|
840
|
-
SET @secret_concept_id = LAST_INSERT_ID();
|
|
841
|
-
|
|
842
|
-
-- Look up the connection type for 'the_entity_s_client_secret'
|
|
843
|
-
SET @conn_type_id = (
|
|
844
|
-
SELECT id FROM the_concepts
|
|
845
|
-
WHERE character_value = 'the_entity_s_client_secret'
|
|
846
|
-
ORDER BY id ASC LIMIT 1
|
|
847
|
-
);
|
|
848
|
-
|
|
849
|
-
-- Link entity → secret concept
|
|
850
|
-
INSERT INTO the_connections (
|
|
851
|
-
user_id, of_the_concepts_id, of_the_concepts_user_id,
|
|
852
|
-
type_id, type_user_id, order_id, order_user_id,
|
|
853
|
-
to_the_concepts_id, to_the_concepts_user_id,
|
|
854
|
-
security_id, security_user_id, access_id, access_user_id,
|
|
855
|
-
session_information_id, session_information_user_id
|
|
856
|
-
) VALUES (
|
|
857
|
-
999, @entity_id, 999,
|
|
858
|
-
@conn_type_id, 999, 999, 999,
|
|
859
|
-
@secret_concept_id, 999,
|
|
860
|
-
4, 999, 4, 999, 999, 999
|
|
861
|
-
);
|
|
862
|
-
`;
|
|
816
|
+
if (loginResult.status !== 0) {
|
|
817
|
+
const errText = (loginResult.stderr || '').toString().trim() || 'curl returned non-zero';
|
|
818
|
+
die(`Login request failed: ${errText}`);
|
|
819
|
+
}
|
|
863
820
|
|
|
821
|
+
let loginRes;
|
|
864
822
|
try {
|
|
865
|
-
|
|
866
|
-
} catch
|
|
867
|
-
die(
|
|
823
|
+
loginRes = JSON.parse((loginResult.stdout || '').toString().trim());
|
|
824
|
+
} catch {
|
|
825
|
+
die('Invalid JSON in login response — is wico-server healthy?');
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Response shape: { status: 200, data: { token, userConcept, ... } }
|
|
829
|
+
const token = loginRes?.data?.token;
|
|
830
|
+
const entityId = loginRes?.data?.userConcept;
|
|
831
|
+
if (!token) {
|
|
832
|
+
die(`Login failed: ${JSON.stringify(loginRes)}`);
|
|
833
|
+
}
|
|
834
|
+
console.log(`done (entity ${entityId})`);
|
|
835
|
+
|
|
836
|
+
// Step 2: Generate client-secret
|
|
837
|
+
process.stdout.write('[2/3] Generating client-secret… ');
|
|
838
|
+
const secretResult = spawnSync('docker', [
|
|
839
|
+
'exec', container, 'curl', '-sf',
|
|
840
|
+
'-X', 'POST', 'http://localhost:7000/api/client-secret',
|
|
841
|
+
'-H', `Authorization: Bearer ${token}`,
|
|
842
|
+
'-H', 'Content-Type: application/json'
|
|
843
|
+
], { stdio: ['inherit', 'pipe', 'pipe'] });
|
|
844
|
+
|
|
845
|
+
if (secretResult.status !== 0) {
|
|
846
|
+
const errText = (secretResult.stderr || '').toString().trim() || 'curl returned non-zero';
|
|
847
|
+
die(`/api/client-secret request failed: ${errText}`);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
let secretRes;
|
|
851
|
+
try {
|
|
852
|
+
secretRes = JSON.parse((secretResult.stdout || '').toString().trim());
|
|
853
|
+
} catch {
|
|
854
|
+
die('Invalid JSON in client-secret response');
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Response shape: { success: true, message: "<plainSecretString>" }
|
|
858
|
+
const secret = secretRes?.message;
|
|
859
|
+
if (!secret || typeof secret !== 'string' || !secretRes?.success) {
|
|
860
|
+
die(`Unexpected client-secret response: ${JSON.stringify(secretRes)}`);
|
|
868
861
|
}
|
|
869
862
|
console.log('done');
|
|
870
863
|
|
|
871
|
-
// Step 3:
|
|
864
|
+
// Step 3: Update .env
|
|
872
865
|
process.stdout.write('[3/3] Updating .env… ');
|
|
873
866
|
setEnvVar(envPath, 'CLIENT_ID', String(entityId));
|
|
874
|
-
setEnvVar(envPath, 'CLIENT_SECRET',
|
|
867
|
+
setEnvVar(envPath, 'CLIENT_SECRET', secret);
|
|
875
868
|
console.log('done');
|
|
876
869
|
|
|
877
870
|
console.log(`
|
|
878
871
|
─────────────────────────────────────────
|
|
879
872
|
Credentials saved to .env:
|
|
880
873
|
CLIENT_ID = ${entityId}
|
|
881
|
-
CLIENT_SECRET =
|
|
874
|
+
CLIENT_SECRET = (saved — restart to apply)
|
|
882
875
|
─────────────────────────────────────────
|
|
883
876
|
|
|
884
|
-
Restart
|
|
877
|
+
Restart node-server and node-cache-server to pick up the new secret:
|
|
885
878
|
freeschema restart node-server
|
|
886
879
|
`);
|
|
887
880
|
}
|