@aion0/forge 0.10.82 → 0.10.84
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/RELEASE_NOTES.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
# Forge v0.10.
|
|
1
|
+
# Forge v0.10.84
|
|
2
2
|
|
|
3
3
|
Released: 2026-06-15
|
|
4
4
|
|
|
5
|
-
## Changes since v0.10.
|
|
5
|
+
## Changes since v0.10.83
|
|
6
6
|
|
|
7
|
+
### Other
|
|
8
|
+
- fix(auth): logout redirects to current origin, not localhost:8403
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
|
|
11
|
+
**Full Changelog**: https://github.com/aiwatching/forge/compare/v0.10.83...v0.10.84
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import { loadSettings, loadSettingsMasked, saveSettings, type Settings } from '@/lib/settings';
|
|
3
4
|
import { restartTelegramBot } from '@/lib/init';
|
|
4
5
|
import { SECRET_FIELDS } from '@/lib/crypto';
|
|
5
6
|
import { verifyAdmin } from '@/lib/password';
|
|
6
7
|
|
|
8
|
+
// Container deployments manage the admin password out-of-band (control plane /
|
|
9
|
+
// `make change-password`), which also re-pairs the browser-extension bridge
|
|
10
|
+
// token. Same detection signal as app/api/onboarding/route.ts.
|
|
11
|
+
function inContainer(): boolean {
|
|
12
|
+
if (process.env.FORGE_CONTAINER === '1') return true;
|
|
13
|
+
try { return existsSync('/.dockerenv'); } catch { return false; }
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
export async function GET() {
|
|
8
|
-
return NextResponse.json(loadSettingsMasked());
|
|
17
|
+
return NextResponse.json({ ...loadSettingsMasked(), _inContainer: inContainer() });
|
|
9
18
|
}
|
|
10
19
|
|
|
11
20
|
export async function PUT(req: Request) {
|
|
@@ -34,6 +43,21 @@ export async function PUT(req: Request) {
|
|
|
34
43
|
&& !existingSettings.telegramTunnelPassword
|
|
35
44
|
&& !!newValue;
|
|
36
45
|
|
|
46
|
+
// In container mode the admin password is managed out-of-band (the
|
|
47
|
+
// platform rotation also re-pairs the browser extension's bridge token).
|
|
48
|
+
// Changing it here would desync that token and break the agent's browser,
|
|
49
|
+
// with no UI re-pair path. Block rotations — but still allow the very first
|
|
50
|
+
// set (isFirstAdminSet), which happens before any extension pairing.
|
|
51
|
+
if (field === 'telegramTunnelPassword' && !isFirstAdminSet && inContainer()) {
|
|
52
|
+
return NextResponse.json({
|
|
53
|
+
ok: false,
|
|
54
|
+
error:
|
|
55
|
+
'Password is managed by the platform in container mode. Change it from ' +
|
|
56
|
+
'the admin console / self-service portal (it also re-pairs the browser ' +
|
|
57
|
+
'extension), or on the host run: make change-password U=<user>.',
|
|
58
|
+
}, { status: 403 });
|
|
59
|
+
}
|
|
60
|
+
|
|
37
61
|
if (!isFirstAdminSet && !verifyAdmin(adminPassword)) {
|
|
38
62
|
return NextResponse.json({ ok: false, error: 'Wrong password' }, { status: 403 });
|
|
39
63
|
}
|
package/components/Dashboard.tsx
CHANGED
|
@@ -916,7 +916,14 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
916
916
|
<span className="w-3 text-center">?</span><span>Help</span>
|
|
917
917
|
</button>
|
|
918
918
|
<button
|
|
919
|
-
onClick={() =>
|
|
919
|
+
onClick={async () => {
|
|
920
|
+
// Redirect client-side so logout stays on the CURRENT origin
|
|
921
|
+
// (tunnel host / LAN IP / custom port). next-auth's own
|
|
922
|
+
// callbackUrl uses the server baseUrl, which is localhost:8403
|
|
923
|
+
// when cloudflared rewrites the Host header.
|
|
924
|
+
await signOut({ redirect: false });
|
|
925
|
+
window.location.href = '/login';
|
|
926
|
+
}}
|
|
920
927
|
className="w-full text-left text-[11px] px-3 py-1.5 text-[var(--text-secondary)] hover:text-[var(--red)] hover:bg-[var(--bg-tertiary)] flex items-center gap-2"
|
|
921
928
|
>
|
|
922
929
|
<span className="w-3 text-center">⏻</span><span>Logout</span>
|
|
@@ -367,6 +367,9 @@ export default function SettingsModal({ onClose }: { onClose: () => void }) {
|
|
|
367
367
|
maxConcurrentPipelines: 5,
|
|
368
368
|
});
|
|
369
369
|
const [secretStatus, setSecretStatus] = useState<Record<string, boolean>>({});
|
|
370
|
+
// Container deployments manage the admin password out-of-band (it also
|
|
371
|
+
// re-pairs the browser extension); UI change is disabled when set.
|
|
372
|
+
const [inContainer, setInContainer] = useState(false);
|
|
370
373
|
const [newRoot, setNewRoot] = useState('');
|
|
371
374
|
const [newDocRoot, setNewDocRoot] = useState('');
|
|
372
375
|
const [pickerFor, setPickerFor] = useState<null | 'project' | 'doc'>(null);
|
|
@@ -390,7 +393,9 @@ export default function SettingsModal({ onClose }: { onClose: () => void }) {
|
|
|
390
393
|
const fetchSettings = useCallback(() => {
|
|
391
394
|
fetch('/api/settings').then(r => r.json()).then((data: Settings) => {
|
|
392
395
|
const status = data._secretStatus || {};
|
|
396
|
+
setInContainer(!!(data as any)._inContainer);
|
|
393
397
|
delete data._secretStatus;
|
|
398
|
+
delete (data as any)._inContainer;
|
|
394
399
|
setSettings(data);
|
|
395
400
|
origSettingsRef.current = JSON.stringify(data);
|
|
396
401
|
setSecretStatus(status);
|
|
@@ -983,14 +988,30 @@ export default function SettingsModal({ onClose }: { onClose: () => void }) {
|
|
|
983
988
|
<p className="text-[10px] text-[var(--text-secondary)]">
|
|
984
989
|
Used for local login, tunnel start, secret changes, and Telegram commands. Remote login requires admin password + session code (generated on tunnel start).
|
|
985
990
|
</p>
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
991
|
+
{inContainer && secretStatus.telegramTunnelPassword ? (
|
|
992
|
+
<>
|
|
993
|
+
<div className="flex items-center justify-between gap-2 px-2 py-1.5 bg-[var(--bg-tertiary)] border border-[var(--border)] rounded">
|
|
994
|
+
<span className="text-xs font-mono text-[var(--text-secondary)]">••••••••</span>
|
|
995
|
+
<span className="text-[9px] text-[var(--text-secondary)] italic">Managed by platform</span>
|
|
996
|
+
</div>
|
|
997
|
+
<p className="text-[9px] text-[var(--text-secondary)]">
|
|
998
|
+
Password is managed by the platform. Change it from the admin console
|
|
999
|
+
or your self-service portal — it also re-pairs the browser extension.
|
|
1000
|
+
(Host CLI: <code className="text-[var(--accent)]">make change-password U=<user></code>.)
|
|
1001
|
+
</p>
|
|
1002
|
+
</>
|
|
1003
|
+
) : (
|
|
1004
|
+
<>
|
|
1005
|
+
<SecretField
|
|
1006
|
+
label="Admin Password"
|
|
1007
|
+
isSet={!!secretStatus.telegramTunnelPassword}
|
|
1008
|
+
onEdit={() => setEditingSecret({ field: 'telegramTunnelPassword', label: 'Admin Password' })}
|
|
1009
|
+
/>
|
|
1010
|
+
<p className="text-[9px] text-[var(--text-secondary)]">
|
|
1011
|
+
Forgot? Run: <code className="text-[var(--accent)]">forge --reset-password</code>
|
|
1012
|
+
</p>
|
|
1013
|
+
</>
|
|
1014
|
+
)}
|
|
994
1015
|
</div>
|
|
995
1016
|
|
|
996
1017
|
{/* API Key */}
|
package/package.json
CHANGED