Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions components/terminal/xterm-terminal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,17 @@ export function XtermTerminal({
return null;
}

// Remove credentials from URL — they are sent in the WebSocket init message instead
url.searchParams.delete('authorization');

// Add session ID as arg parameter for ttyd-auth.sh
// URL format: ?authorization=base64(user:pass)&arg=SESSION_ID
url.searchParams.append('arg', terminalSessionId.current);

const wsProtocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
const wsPath = url.pathname.replace(/\/$/, '') + '/ws';
const wsFullUrl = `${wsProtocol}//${url.host}${wsPath}${url.search}`;

console.log('[XtermTerminal] Connecting to:', wsFullUrl.replace(authorization, '***'));
console.log('[XtermTerminal] Connecting to:', wsFullUrl);
return { wsFullUrl, authorization };
} catch (error) {
console.error('[XtermTerminal] Failed to parse URL:', error);
Expand Down
8 changes: 6 additions & 2 deletions lib/actions/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ export async function runCommand(
const { ttyd } = await getSandboxTtydContext(sandboxId, session.user.id)
const { baseUrl, accessToken, authorization } = ttyd

const output = await execCommand(baseUrl, accessToken, command, timeoutMs, authorization)
const result = await execCommand(baseUrl, accessToken, command, timeoutMs, authorization)

return { success: true, output }
if (result.exitCode !== 0) {
return { success: false, error: `Command failed with exit code ${result.exitCode}`, output: result.output }
}

return { success: true, output: result.output }
} catch (error) {
console.error('Failed to execute command in sandbox:', error)
const errorMessage = error instanceof TtydExecError ? error.message : 'Unknown error'
Expand Down
14 changes: 5 additions & 9 deletions lib/util/ttyd-exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ function stripAnsiCodes(str: string): string {
function buildWsUrl(
ttydUrl: string,
accessToken: string,
sessionId?: string,
authorization?: string
sessionId?: string
): string {
const url = new URL(ttydUrl)
const wsProtocol = url.protocol === 'https:' ? 'wss:' : 'ws:'
Expand All @@ -180,10 +179,7 @@ function buildWsUrl(
if (sessionId) {
params.append('arg', sessionId)
}
if (authorization) {
params.append('authorization', authorization)
}

// authorization is sent securely in the WebSocket init message — not added to URL
return `${wsProtocol}//${url.host}${wsPath}?${params.toString()}`
}

Expand Down Expand Up @@ -256,7 +252,7 @@ export async function executeTtydCommand(options: TtydExecOptions): Promise<Ttyd
const endMarkerPattern = new RegExp(`${END_MARKER_PREFIX}${markerId}:(\\d+)___`)

// Build WebSocket URL
const wsUrl = buildWsUrl(ttydUrl, accessToken, sessionId, authorization)
const wsUrl = buildWsUrl(ttydUrl, accessToken, sessionId)

// Text encoder/decoder
const textEncoder = new TextEncoder()
Expand Down Expand Up @@ -566,7 +562,7 @@ export async function execCommand(
command: string,
timeoutMs?: number,
authorization?: string
): Promise<string> {
): Promise<{ output: string; exitCode: number }> {
const result = await executeTtydCommand({
ttydUrl,
accessToken,
Expand All @@ -579,7 +575,7 @@ export async function execCommand(
throw new TtydExecError('Command timed out', TtydExecErrorCode.TIMEOUT)
}

return result.output
return { output: result.output, exitCode: result.exitCode }
}

/**
Expand Down
1 change: 1 addition & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
turbopack: false as any,
reactStrictMode: true,
output: 'standalone',
compress: true,
Expand Down
Loading