fix: approximated not verifying domain, change request type for /agents
route
This commit is contained in:
@@ -10,6 +10,10 @@ const envSchema = z.object({
|
||||
CLOUDFLARE_IMAGE_BUCKET_DOMAIN: z.string().optional(),
|
||||
APPROXIMATED_API_KEY: z.string().optional(),
|
||||
APPROXIMATED_TARGET_ADDRESS: z.string().optional(),
|
||||
/** Public IP customers point their A record to (Approximated edge IP). */
|
||||
APPROXIMATED_DNS_TARGET_IP: z.string().optional(),
|
||||
/** Optional CNAME target customers can point to instead of A record. */
|
||||
APPROXIMATED_DNS_TARGET_CNAME: z.string().optional(),
|
||||
// S3-compatible storage (MinIO, AWS S3, or other S3-compatible backends)
|
||||
OBJECT_STORAGE_ENDPOINT: z.string().optional(),
|
||||
OBJECT_STORAGE_REGION: z.string().optional(),
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { Context, Next } from 'hono';
|
||||
import { AGENT_CONTENT_TYPE } from '@cio/utils/constants';
|
||||
|
||||
/**
|
||||
* Render fronts services with Cloudflare's OWASP Managed Rules, which scan
|
||||
* `application/json` bodies and 403 anything that looks like SQL injection.
|
||||
* AI chat content trips this constantly (`SELECT … WHERE …`, `OR 1=1` etc.).
|
||||
* The dashboard sends `/agent/*` writes as `application/x-cio-agent`; this
|
||||
* middleware swaps the header back to `application/json` so Hono's zValidator
|
||||
* (which gates parsing on a `/application\/.+?\+?json/` regex) parses the body.
|
||||
*/
|
||||
export const agentContentTypeRewrite = async (c: Context, next: Next) => {
|
||||
const ct = c.req.header('content-type')?.toLowerCase() ?? '';
|
||||
if (!ct.startsWith(AGENT_CONTENT_TYPE)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const headers = new Headers(c.req.raw.headers);
|
||||
headers.set('content-type', 'application/json');
|
||||
c.req.raw = new Request(c.req.raw, { headers });
|
||||
|
||||
return next();
|
||||
};
|
||||
@@ -3,6 +3,7 @@ import { authMiddleware } from '@api/middlewares/auth';
|
||||
import { orgMemberMiddleware } from '@api/middlewares/org-member';
|
||||
import { orgAdminMiddleware } from '@api/middlewares/org-admin';
|
||||
import { authOrApiKeyMiddleware } from '@api/middlewares/auth-or-api-key';
|
||||
import { agentContentTypeRewrite } from '@api/middlewares/agent-content-type';
|
||||
import { handleError, AppError } from '@api/utils/errors';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { streamText, stepCountIs, convertToModelMessages } from 'ai';
|
||||
@@ -691,4 +692,7 @@ const agentCoreRouter = new Hono()
|
||||
}
|
||||
});
|
||||
|
||||
export const agentRouter = new Hono().route('/', agentCoreRouter).route('/history', agentHistoryRouter);
|
||||
export const agentRouter = new Hono()
|
||||
.use('*', agentContentTypeRewrite)
|
||||
.route('/', agentCoreRouter)
|
||||
.route('/history', agentHistoryRouter);
|
||||
|
||||
@@ -57,6 +57,14 @@ function ensureApproximatedConfig() {
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
if (!env.APPROXIMATED_DNS_TARGET_IP && !env.APPROXIMATED_DNS_TARGET_CNAME) {
|
||||
throw new AppError(
|
||||
'Set APPROXIMATED_DNS_TARGET_IP and/or APPROXIMATED_DNS_TARGET_CNAME so customers know where to point their DNS.',
|
||||
ErrorCodes.INTERNAL_ERROR,
|
||||
500
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function approximatedRequest<T>(path: string, init: RequestInit = {}): Promise<T | null> {
|
||||
@@ -92,20 +100,31 @@ async function approximatedRequest<T>(path: string, init: RequestInit = {}): Pro
|
||||
);
|
||||
}
|
||||
|
||||
if (payload && typeof payload === 'object' && 'data' in payload) {
|
||||
return (payload as { data: T }).data;
|
||||
}
|
||||
|
||||
return payload as T;
|
||||
}
|
||||
|
||||
function buildDnsRecords(hostname: string, vhost?: ApproximatedVhost | null): DomainDnsRecord[] {
|
||||
if (!vhost?.dns_pointed_at) return [];
|
||||
const targetIp = env.APPROXIMATED_DNS_TARGET_IP;
|
||||
const targetCname = env.APPROXIMATED_DNS_TARGET_CNAME;
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'A',
|
||||
name: hostname,
|
||||
value: vhost.dns_pointed_at,
|
||||
status: vhost.is_resolving ? 'active' : 'pending'
|
||||
}
|
||||
];
|
||||
const records: DomainDnsRecord[] = [];
|
||||
const isResolvingToTarget = Boolean(
|
||||
vhost?.is_resolving && (vhost?.dns_pointed_at === targetIp || vhost?.dns_pointed_at === targetCname)
|
||||
);
|
||||
const status: 'pending' | 'active' = isResolvingToTarget ? 'active' : 'pending';
|
||||
|
||||
if (targetIp) {
|
||||
records.push({ type: 'A', name: hostname, value: targetIp, status });
|
||||
}
|
||||
if (targetCname) {
|
||||
records.push({ type: 'CNAME', name: hostname, value: targetCname, status });
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
function mapDomainStatus(vhost?: ApproximatedVhost | null): DomainSetupStatus {
|
||||
@@ -113,7 +132,7 @@ function mapDomainStatus(vhost?: ApproximatedVhost | null): DomainSetupStatus {
|
||||
return 'reconnect_required';
|
||||
}
|
||||
|
||||
if (vhost.has_ssl && vhost.is_resolving && vhost.apx_hit) {
|
||||
if (vhost.has_ssl && vhost.is_resolving) {
|
||||
return 'verified';
|
||||
}
|
||||
|
||||
@@ -145,6 +164,7 @@ function getStatusMessage(status: DomainSetupStatus) {
|
||||
|
||||
function toDomainSetupResult(hostname: string, vhost?: ApproximatedVhost | null): DomainSetupResult {
|
||||
const status = mapDomainStatus(vhost);
|
||||
console.log('status', status);
|
||||
|
||||
return {
|
||||
hostname,
|
||||
@@ -201,6 +221,8 @@ async function createVhost(hostname: string): Promise<ApproximatedVhost> {
|
||||
if (!created) {
|
||||
throw new AppError('Approximated did not return a vhost', ErrorCodes.INTERNAL_ERROR, 500);
|
||||
}
|
||||
|
||||
console.log('created', created);
|
||||
return created;
|
||||
}
|
||||
|
||||
@@ -212,6 +234,7 @@ export async function connectDomain(hostname: string): Promise<DomainSetupResult
|
||||
|
||||
export async function refreshDomain(hostname: string): Promise<DomainSetupResult> {
|
||||
const vhost = await getVhost(hostname);
|
||||
console.log('existing', vhost);
|
||||
return toDomainSetupResult(hostname, vhost);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user