thevoidforge 21.0.7 → 21.0.9
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/dist/wizard/api/auth.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { addRoute } from '../router.js';
|
|
6
6
|
import { parseJsonBody } from '../lib/body-parser.js';
|
|
7
|
-
import { hasUsers, createUser, login, logout, validateSession, parseSessionCookie, buildSessionCookie, clearSessionCookie, isRemoteMode, checkRateLimit, getClientIp, getUserRole, isValidUsername, } from '../lib/tower-auth.js';
|
|
7
|
+
import { hasUsers, createUser, login, logout, validateSession, parseSessionCookie, buildSessionCookie, clearSessionCookie, isRemoteMode, isLanMode, checkRateLimit, getClientIp, getUserRole, isValidUsername, } from '../lib/tower-auth.js';
|
|
8
8
|
import { audit } from '../lib/audit-log.js';
|
|
9
9
|
import { sendJson } from '../lib/http-helpers.js';
|
|
10
10
|
// POST /api/auth/setup — Create initial admin user (only when no users exist)
|
|
@@ -114,8 +114,8 @@ addRoute('POST', '/api/auth/logout', async (req, res) => {
|
|
|
114
114
|
});
|
|
115
115
|
// GET /api/auth/session — Check if current session is valid
|
|
116
116
|
addRoute('GET', '/api/auth/session', async (req, res) => {
|
|
117
|
-
if (!isRemoteMode()) {
|
|
118
|
-
sendJson(res, 200, { success: true, data: { authenticated: true, username: 'local', role: 'admin', remoteMode: false } });
|
|
117
|
+
if (!isRemoteMode() && !isLanMode()) {
|
|
118
|
+
sendJson(res, 200, { success: true, data: { authenticated: true, username: 'local', role: 'admin', remoteMode: false, lanMode: false } });
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
const token = parseSessionCookie(req.headers.cookie);
|
|
@@ -129,5 +129,5 @@ addRoute('GET', '/api/auth/session', async (req, res) => {
|
|
|
129
129
|
sendJson(res, 200, { success: true, data: { authenticated: false, needsSetup: false } });
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
|
-
sendJson(res, 200, { success: true, data: { authenticated: true, username: session.username, role: session.role, remoteMode:
|
|
132
|
+
sendJson(res, 200, { success: true, data: { authenticated: true, username: session.username, role: session.role, remoteMode: isRemoteMode(), lanMode: isLanMode() } });
|
|
133
133
|
});
|
package/dist/wizard/server.js
CHANGED
|
@@ -159,11 +159,10 @@ async function handleRequest(req, res) {
|
|
|
159
159
|
sendJson(res, 403, { success: false, error: 'Missing X-VoidForge-Request header' });
|
|
160
160
|
return;
|
|
161
161
|
}
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
if (isRemoteMode()) {
|
|
162
|
+
// Auth middleware — in remote and LAN modes, require valid session for non-exempt paths.
|
|
163
|
+
// LAN mode has full access (same as remote) but simpler auth (password only, no TOTP).
|
|
164
|
+
// Local mode (127.0.0.1) has no auth — it's your own machine.
|
|
165
|
+
if (isRemoteMode() || isLanMode()) {
|
|
167
166
|
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
168
167
|
if (!isAuthExempt(url.pathname)) {
|
|
169
168
|
const token = parseSessionCookie(req.headers.cookie);
|
package/dist/wizard/ui/app.js
CHANGED
|
@@ -669,6 +669,50 @@
|
|
|
669
669
|
}
|
|
670
670
|
});
|
|
671
671
|
|
|
672
|
+
// PRD file upload + drag-and-drop
|
|
673
|
+
const dropzone = $('#prd-dropzone');
|
|
674
|
+
const fileInput = $('#prd-file-input');
|
|
675
|
+
const prdTextarea = $('#prd-paste');
|
|
676
|
+
|
|
677
|
+
if (dropzone && fileInput) {
|
|
678
|
+
function handlePrdFile(file) {
|
|
679
|
+
const reader = new FileReader();
|
|
680
|
+
reader.onload = function (e) {
|
|
681
|
+
prdTextarea.value = e.target.result;
|
|
682
|
+
showStatus(prdStatus, 'success', 'Loaded: ' + file.name + ' (' + file.size + ' bytes)');
|
|
683
|
+
dropzone.style.borderColor = 'var(--accent, #5b5bf7)';
|
|
684
|
+
setTimeout(function () { dropzone.style.borderColor = ''; }, 2000);
|
|
685
|
+
};
|
|
686
|
+
reader.onerror = function () {
|
|
687
|
+
showStatus(prdStatus, 'error', 'Failed to read file');
|
|
688
|
+
};
|
|
689
|
+
reader.readAsText(file);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
dropzone.addEventListener('click', function () { fileInput.click(); });
|
|
693
|
+
dropzone.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') fileInput.click(); });
|
|
694
|
+
|
|
695
|
+
fileInput.addEventListener('change', function () {
|
|
696
|
+
if (fileInput.files && fileInput.files[0]) handlePrdFile(fileInput.files[0]);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
dropzone.addEventListener('dragover', function (e) {
|
|
700
|
+
e.preventDefault();
|
|
701
|
+
dropzone.style.borderColor = 'var(--accent, #5b5bf7)';
|
|
702
|
+
dropzone.style.background = 'rgba(91, 91, 247, 0.05)';
|
|
703
|
+
});
|
|
704
|
+
dropzone.addEventListener('dragleave', function () {
|
|
705
|
+
dropzone.style.borderColor = '';
|
|
706
|
+
dropzone.style.background = '';
|
|
707
|
+
});
|
|
708
|
+
dropzone.addEventListener('drop', function (e) {
|
|
709
|
+
e.preventDefault();
|
|
710
|
+
dropzone.style.borderColor = '';
|
|
711
|
+
dropzone.style.background = '';
|
|
712
|
+
if (e.dataTransfer.files && e.dataTransfer.files[0]) handlePrdFile(e.dataTransfer.files[0]);
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
|
|
672
716
|
let cachedPrompt = null;
|
|
673
717
|
$('#copy-prd-prompt').addEventListener('click', async () => {
|
|
674
718
|
const promptCopyStatus = $('#prompt-copy-status');
|
|
@@ -177,11 +177,19 @@
|
|
|
177
177
|
|
|
178
178
|
<div class="tab-panel" id="tab-paste" role="tabpanel" aria-labelledby="tab-btn-paste">
|
|
179
179
|
<div class="card">
|
|
180
|
-
<p>Already have a PRD
|
|
180
|
+
<p>Already have a PRD? Drop the file here, upload it, or paste below.</p>
|
|
181
|
+
|
|
182
|
+
<div class="field">
|
|
183
|
+
<div id="prd-dropzone" style="border: 2px dashed var(--border, #333); border-radius: 8px; padding: 2rem; text-align: center; cursor: pointer; transition: border-color 0.2s, background 0.2s; margin-bottom: 12px;" role="button" tabindex="0" aria-label="Drop a PRD file here or click to upload">
|
|
184
|
+
<p style="margin: 0 0 8px 0; font-size: 1.1em;">Drop your PRD file here</p>
|
|
185
|
+
<p style="margin: 0; opacity: 0.6; font-size: 0.9em;">or click to browse (.md, .txt, .yaml)</p>
|
|
186
|
+
<input type="file" id="prd-file-input" accept=".md,.txt,.yaml,.yml,.markdown" style="display: none;">
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
181
189
|
|
|
182
190
|
<div class="field">
|
|
183
191
|
<label>PRD Generator Prompt</label>
|
|
184
|
-
<p class="field-hint" style="margin-bottom: 8px;">
|
|
192
|
+
<p class="field-hint" style="margin-bottom: 8px;">Or copy this prompt into ChatGPT, Gemini, or any AI — then paste the output below.</p>
|
|
185
193
|
<button class="btn btn-secondary" id="copy-prd-prompt" type="button">Copy Generator Prompt to Clipboard</button>
|
|
186
194
|
<div class="status-row" id="prompt-copy-status" role="status" aria-live="polite"></div>
|
|
187
195
|
</div>
|
package/dist/wizard/ui/lobby.js
CHANGED
|
@@ -710,14 +710,14 @@
|
|
|
710
710
|
const res = await fetch('/api/auth/session');
|
|
711
711
|
const body = await res.json();
|
|
712
712
|
const data = body.data || {};
|
|
713
|
-
if (data.remoteMode && data.authenticated) {
|
|
713
|
+
if ((data.remoteMode || data.lanMode) && data.authenticated) {
|
|
714
714
|
currentUser = { username: data.username || '', role: data.role || 'viewer' };
|
|
715
715
|
const roleLabel = { admin: 'Admin', deployer: 'Deployer', viewer: 'Viewer' }[data.role] || '';
|
|
716
716
|
authUser.textContent = data.username + (roleLabel ? ' (' + roleLabel + ')' : '');
|
|
717
717
|
authUser.style.display = '';
|
|
718
718
|
btnLogout.style.display = '';
|
|
719
719
|
}
|
|
720
|
-
if (data.remoteMode && !data.authenticated) {
|
|
720
|
+
if ((data.remoteMode || data.lanMode) && !data.authenticated) {
|
|
721
721
|
window.location.href = '/login.html';
|
|
722
722
|
}
|
|
723
723
|
} catch { /* local mode — no auth needed */ }
|