estatehelm 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1454,25 +1454,21 @@ function prompt(question) {
1454
1454
  });
1455
1455
  });
1456
1456
  }
1457
- var ALLOWED_CALLBACK_PORTS = [11033, 11034, 11035];
1458
1457
  async function findAvailablePort() {
1459
- for (const port of ALLOWED_CALLBACK_PORTS) {
1460
- const available = await isPortAvailable(port);
1461
- if (available) {
1462
- return port;
1463
- }
1464
- }
1465
- throw new Error(
1466
- `No available ports for CLI callback. Ports ${ALLOWED_CALLBACK_PORTS.join(", ")} are all in use.`
1467
- );
1468
- }
1469
- function isPortAvailable(port) {
1470
- return new Promise((resolve) => {
1458
+ return new Promise((resolve, reject) => {
1471
1459
  const server = http.createServer();
1472
- server.listen(port, "127.0.0.1", () => {
1473
- server.close(() => resolve(true));
1460
+ server.listen(0, "127.0.0.1", () => {
1461
+ const address = server.address();
1462
+ const port = typeof address === "object" && address ? address.port : 0;
1463
+ server.close(() => {
1464
+ if (port > 0) {
1465
+ resolve(port);
1466
+ } else {
1467
+ reject(new Error("Failed to find available port"));
1468
+ }
1469
+ });
1474
1470
  });
1475
- server.on("error", () => resolve(false));
1471
+ server.on("error", reject);
1476
1472
  });
1477
1473
  }
1478
1474
  function createApiClient(token) {
@@ -1544,85 +1540,11 @@ async function decryptDeviceCredentials(encryptedPayload) {
1544
1540
  );
1545
1541
  return new Uint8Array(plaintext);
1546
1542
  }
1547
- function generatePKCE() {
1548
- const verifierBytes = crypto.getRandomValues(new Uint8Array(32));
1549
- const verifier = base64Encode(verifierBytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1550
- const encoder = new TextEncoder();
1551
- const data = encoder.encode(verifier);
1552
- const hashBuffer = crypto.subtle.digestSync ? crypto.subtle.digestSync("SHA-256", data) : null;
1553
- const cryptoNode = require("crypto");
1554
- const hash = cryptoNode.createHash("sha256").update(verifier).digest();
1555
- const challenge = hash.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1556
- return { verifier, challenge };
1557
- }
1558
- var GOOGLE_CLIENT_ID = "51644152299-ikanidsebtsn6sukgk0sg1hq5h95k2h6.apps.googleusercontent.com";
1559
- async function createNativeLoginFlow() {
1560
- const response = await fetch(`${KRATOS_URL}/self-service/login/api`, {
1561
- method: "GET",
1562
- headers: { Accept: "application/json" }
1563
- });
1564
- if (!response.ok) {
1565
- const error = await response.text();
1566
- throw new Error(`Failed to create login flow: ${response.status} - ${error}`);
1567
- }
1568
- const flow = await response.json();
1569
- return flow.id;
1570
- }
1571
- async function submitIdTokenToKratos(flowId, idToken, provider = "google") {
1572
- const response = await fetch(`${KRATOS_URL}/self-service/login?flow=${flowId}`, {
1573
- method: "POST",
1574
- headers: {
1575
- "Content-Type": "application/json",
1576
- Accept: "application/json"
1577
- },
1578
- body: JSON.stringify({
1579
- method: "oidc",
1580
- provider,
1581
- id_token: idToken
1582
- })
1583
- });
1584
- if (!response.ok) {
1585
- const error = await response.json().catch(() => ({}));
1586
- throw new Error(
1587
- error.error?.message || error.ui?.messages?.[0]?.text || `Kratos login failed: ${response.status}`
1588
- );
1589
- }
1590
- const result = await response.json();
1591
- if (!result.session_token) {
1592
- throw new Error("No session_token in Kratos response");
1593
- }
1594
- return result.session_token;
1595
- }
1596
- async function exchangeCodeForTokens(code, codeVerifier, redirectUri) {
1597
- const response = await fetch("https://oauth2.googleapis.com/token", {
1598
- method: "POST",
1599
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
1600
- body: new URLSearchParams({
1601
- client_id: GOOGLE_CLIENT_ID,
1602
- code,
1603
- code_verifier: codeVerifier,
1604
- grant_type: "authorization_code",
1605
- redirect_uri: redirectUri
1606
- })
1607
- });
1608
- if (!response.ok) {
1609
- const error = await response.json().catch(() => ({}));
1610
- throw new Error(error.error_description || error.error || "Token exchange failed");
1611
- }
1612
- const tokens = await response.json();
1613
- if (!tokens.id_token) {
1614
- throw new Error("No id_token in Google response");
1615
- }
1616
- return {
1617
- idToken: tokens.id_token,
1618
- accessToken: tokens.access_token
1619
- };
1620
- }
1621
- function waitForOAuthCallback(port) {
1543
+ function waitForCallback(port) {
1622
1544
  return new Promise((resolve, reject) => {
1623
1545
  const server = http.createServer((req, res) => {
1624
1546
  const url = new URL(req.url || "/", `http://127.0.0.1:${port}`);
1625
- const code = url.searchParams.get("code");
1547
+ const sessionToken = url.searchParams.get("session_token");
1626
1548
  const error = url.searchParams.get("error");
1627
1549
  if (error) {
1628
1550
  res.writeHead(400, { "Content-Type": "text/html" });
@@ -1638,7 +1560,7 @@ function waitForOAuthCallback(port) {
1638
1560
  reject(new Error(url.searchParams.get("error_description") || error));
1639
1561
  return;
1640
1562
  }
1641
- if (code) {
1563
+ if (sessionToken) {
1642
1564
  res.writeHead(200, { "Content-Type": "text/html" });
1643
1565
  res.end(`
1644
1566
  <!DOCTYPE html>
@@ -1649,7 +1571,7 @@ function waitForOAuthCallback(port) {
1649
1571
  </html>
1650
1572
  `);
1651
1573
  server.close();
1652
- resolve(code);
1574
+ resolve(sessionToken);
1653
1575
  return;
1654
1576
  }
1655
1577
  res.writeHead(404);
@@ -1666,35 +1588,22 @@ function waitForOAuthCallback(port) {
1666
1588
  async function login() {
1667
1589
  console.log("\nEstateHelm Login");
1668
1590
  console.log("================\n");
1669
- console.log("Creating login flow...");
1670
- const flowId = await createNativeLoginFlow();
1591
+ console.log("Starting authentication server...");
1671
1592
  const port = await findAvailablePort();
1672
- const redirectUri = `http://127.0.0.1:${port}/callback`;
1673
- const { verifier, challenge } = generatePKCE();
1674
- const authUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
1675
- authUrl.searchParams.set("client_id", GOOGLE_CLIENT_ID);
1676
- authUrl.searchParams.set("redirect_uri", redirectUri);
1677
- authUrl.searchParams.set("response_type", "code");
1678
- authUrl.searchParams.set("scope", "openid email profile");
1679
- authUrl.searchParams.set("code_challenge", challenge);
1680
- authUrl.searchParams.set("code_challenge_method", "S256");
1681
- authUrl.searchParams.set("access_type", "offline");
1682
- console.log("\nOpening browser for Google authentication...");
1593
+ const callbackUrl = `http://127.0.0.1:${port}/callback`;
1594
+ const loginUrl = `${APP_URL}/cli-auth?callback=${encodeURIComponent(callbackUrl)}`;
1595
+ console.log("\nOpening browser for authentication...");
1683
1596
  console.log(`If the browser doesn't open, visit:
1684
- ${authUrl.toString()}
1597
+ ${loginUrl}
1685
1598
  `);
1686
- const codePromise = waitForOAuthCallback(port);
1687
- await (0, import_open.default)(authUrl.toString());
1599
+ const tokenPromise = waitForCallback(port);
1600
+ await (0, import_open.default)(loginUrl);
1688
1601
  console.log("Waiting for authentication...");
1689
- const code = await codePromise;
1690
- console.log("Exchanging authorization code...");
1691
- const { idToken } = await exchangeCodeForTokens(code, verifier, redirectUri);
1692
- console.log("Completing authentication...");
1693
- const sessionToken = await submitIdTokenToKratos(flowId, idToken, "google");
1602
+ const sessionToken = await tokenPromise;
1694
1603
  console.log("Authentication successful!");
1695
1604
  console.log(`Token: ${sanitizeToken(sessionToken)}`);
1696
1605
  await saveBearerToken(sessionToken);
1697
- await saveRefreshToken("");
1606
+ await saveRefreshToken("kratos-session-no-refresh");
1698
1607
  const client = createApiClient(sessionToken);
1699
1608
  console.log("\nFetching encryption keys...");
1700
1609
  const serverWrapSecret = await getServerWrapSecret(client);