Skip to content

Commit dfd9874

Browse files
committed
wip: bundled wip to verify against CI
1 parent f4b48c4 commit dfd9874

17 files changed

Lines changed: 1507 additions & 272 deletions

.env.example

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@ E2E_ABLY_ABLY_ACCESS_TOKEN=your_control_api_access_token
1010
# Set this to skip E2E tests even when API key is present (for CI or local dev when you don't want to run E2E tests)
1111
# SKIP_E2E_TESTS=true
1212

13-
# CI bypass secret for rate limit bypass in parallel tests
14-
# This should match the CI_BYPASS_SECRET on the terminal server
15-
CI_BYPASS_SECRET=your_ci_bypass_secret
13+
# Terminal server signing secret
14+
# MUST match the live server's SIGNING_SECRET configuration at wss://web-cli.ably.com
15+
# Used to:
16+
# 1. Sign credentials for HMAC authentication (signedConfig + signature)
17+
# 2. Bypass rate limiting in tests (bypassRateLimit flag in signed config)
18+
# Contact platform team for the actual secret
19+
TERMINAL_SERVER_SIGNING_SECRET=your_signing_secret
20+
21+
# Legacy: CI_BYPASS_SECRET (still supported as fallback)
22+
# CI_BYPASS_SECRET=your_ci_bypass_secret
1623

1724
# Terminal server URL for local testing (defaults to production)
1825
# TERMINAL_SERVER_URL=ws://localhost:8080

examples/web-cli/api/sign.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { VercelRequest, VercelResponse } from "@vercel/node";
2+
import { signCredentials, getSigningSecret } from "../server/sign-handler.js";
3+
4+
/**
5+
* Vercel Serverless Function: Sign credentials for terminal authentication
6+
*
7+
* This endpoint signs API keys with HMAC-SHA256 to create signed configs
8+
* that can be validated by the terminal server.
9+
*
10+
* Environment Variables Required:
11+
* - SIGNING_SECRET or TERMINAL_SERVER_SIGNING_SECRET
12+
*
13+
* Request Body:
14+
* - apiKey: string (required) - Ably API key in format "appId.keyId:secret"
15+
* - bypassRateLimit: boolean (optional) - Set to true for CI/testing
16+
*
17+
* Response:
18+
* - signedConfig: string - JSON-encoded config that was signed
19+
* - signature: string - HMAC-SHA256 hex signature
20+
*/
21+
export default async function handler(
22+
req: VercelRequest,
23+
res: VercelResponse,
24+
) {
25+
// Only accept POST requests
26+
if (req.method !== "POST") {
27+
return res.status(405).json({ error: "Method not allowed" });
28+
}
29+
30+
// Get signing secret from environment
31+
const secret = getSigningSecret();
32+
33+
if (!secret) {
34+
console.error("[/api/sign] Signing secret not configured");
35+
return res.status(500).json({ error: "Signing secret not configured" });
36+
}
37+
38+
const { apiKey, bypassRateLimit } = req.body;
39+
40+
if (!apiKey) {
41+
return res.status(400).json({ error: "apiKey is required" });
42+
}
43+
44+
// Use shared signing logic
45+
const result = signCredentials({ apiKey, bypassRateLimit }, secret);
46+
47+
res.status(200).json(result);
48+
}

examples/web-cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@tailwindcss/vite": "^4.1.5",
2424
"@types/react": "^18.3.20",
2525
"@types/react-dom": "^18.3.5",
26+
"@vercel/node": "^5.5.17",
2627
"@vitejs/plugin-react": "^4.3.4",
2728
"autoprefixer": "^10.4.21",
2829
"eslint": "^9.21.0",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import crypto from "crypto";
2+
3+
/**
4+
* Shared signing logic for credential authentication
5+
* Used by: Vercel function, Vite middleware, and preview server
6+
*/
7+
8+
export interface SignRequest {
9+
apiKey: string;
10+
bypassRateLimit?: boolean;
11+
}
12+
13+
export interface SignResponse {
14+
signedConfig: string;
15+
signature: string;
16+
}
17+
18+
/**
19+
* Sign credentials using HMAC-SHA256
20+
* @param request - Request containing apiKey and optional flags
21+
* @param secret - Signing secret from environment
22+
* @returns Signed config and signature
23+
*/
24+
export function signCredentials(
25+
request: SignRequest,
26+
secret: string,
27+
): SignResponse {
28+
const { apiKey, bypassRateLimit } = request;
29+
30+
// Build config object (matches terminal server expectations)
31+
const config = {
32+
apiKey,
33+
timestamp: Date.now(),
34+
bypassRateLimit: bypassRateLimit || false,
35+
};
36+
37+
// Serialize to JSON - this exact string is what gets signed
38+
const configString = JSON.stringify(config);
39+
40+
// Generate HMAC-SHA256 signature
41+
const hmac = crypto.createHmac("sha256", secret);
42+
hmac.update(configString);
43+
const signature = hmac.digest("hex");
44+
45+
return {
46+
signedConfig: configString,
47+
signature,
48+
};
49+
}
50+
51+
/**
52+
* Get signing secret from environment variables
53+
* Checks multiple variable names for compatibility
54+
*/
55+
export function getSigningSecret(): string | null {
56+
return (
57+
process.env.SIGNING_SECRET ||
58+
process.env.TERMINAL_SERVER_SIGNING_SECRET ||
59+
process.env.CI_BYPASS_SECRET ||
60+
null
61+
);
62+
}

0 commit comments

Comments
 (0)