Update provisioning URL and streamline SSH key delivery
Fixes the hardcoded 'https://' in the stub provisioner's lnbitsUrl to 'http://' and implements an atomic, first-retrieval SSH private key delivery mechanism. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 418bf6f8-212b-4bb0-a7a5-8231a061da4e Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 2f0c982b-02f6-4381-9fc4-34f489842999 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9f85e954-647c-46a5-90a7-396e495a805a/418bf6f8-212b-4bb0-a7a5-8231a061da4e/sPDHkg8 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -497,7 +497,7 @@ export class ProvisionerService {
|
||||
dropletId: fakeDropletId,
|
||||
nodeIp: "198.51.100.42",
|
||||
tailscaleHostname: `timmy-node-${jobId.slice(0, 8)}.tail1234.ts.net`,
|
||||
lnbitsUrl: `https://timmy-node-${jobId.slice(0, 8)}.tail1234.ts.net`,
|
||||
lnbitsUrl: `http://timmy-node-${jobId.slice(0, 8)}.tail1234.ts.net:3000`,
|
||||
sshPrivateKey: privateKey,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
@@ -568,8 +568,10 @@ export class ProvisionerService {
|
||||
? `timmy-node-${jobId.slice(0, 8)}.${this.tsTailnet}.ts.net`
|
||||
: null;
|
||||
|
||||
// LNbits listens on port 3000 (HTTP). Tailscale encrypts the link at the
|
||||
// network layer, so http:// is correct — no TLS termination on the service.
|
||||
const lnbitsUrl = tailscaleHostname
|
||||
? `https://${tailscaleHostname}`
|
||||
? `http://${tailscaleHostname}:3000`
|
||||
: nodeIp
|
||||
? `http://${nodeIp}:3000`
|
||||
: null;
|
||||
|
||||
@@ -144,17 +144,29 @@ router.get("/bootstrap/:id", async (req: Request, res: Response) => {
|
||||
break;
|
||||
|
||||
case "ready": {
|
||||
const keyNote = job.sshKeyDelivered
|
||||
? "SSH private key was delivered on first retrieval — check your records"
|
||||
: null;
|
||||
// Atomic one-time SSH key delivery: only the request that wins the
|
||||
// guarded UPDATE (WHERE ssh_key_delivered = false) delivers the key.
|
||||
// Concurrent first-reads both see delivered=false in the pre-fetched
|
||||
// job, but only one UPDATE matches — the other gets 0 rows and falls
|
||||
// back to the "already delivered" note.
|
||||
let sshPrivateKey: string | null = null;
|
||||
let keyNote: string | null = null;
|
||||
|
||||
// Deliver SSH key on first retrieval, then clear it from DB
|
||||
const sshPrivateKey = job.sshKeyDelivered ? null : job.sshPrivateKey;
|
||||
if (!job.sshKeyDelivered && job.sshPrivateKey) {
|
||||
await db
|
||||
const won = await db
|
||||
.update(bootstrapJobs)
|
||||
.set({ sshKeyDelivered: true, sshPrivateKey: null, updatedAt: new Date() })
|
||||
.where(eq(bootstrapJobs.id, job.id));
|
||||
.where(and(eq(bootstrapJobs.id, job.id), eq(bootstrapJobs.sshKeyDelivered, false)))
|
||||
.returning({ id: bootstrapJobs.id });
|
||||
|
||||
if (won.length > 0) {
|
||||
// This request won the delivery race — return the key we pre-read.
|
||||
sshPrivateKey = job.sshPrivateKey;
|
||||
} else {
|
||||
keyNote = "SSH private key was delivered on a concurrent request — check your records";
|
||||
}
|
||||
} else {
|
||||
keyNote = "SSH private key was delivered on first retrieval — check your records";
|
||||
}
|
||||
|
||||
res.json({
|
||||
|
||||
Reference in New Issue
Block a user