@tencentcloudadp/cli 0.1.1 → 0.1.2

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/cli.js CHANGED
@@ -1688,6 +1688,7 @@ function createLocalCredentialForm() {
1688
1688
  }
1689
1689
  async function openForm(input) {
1690
1690
  const token = randomBytes(32).toString("base64url");
1691
+ const csrf = randomBytes(32).toString("base64url");
1691
1692
  const expectedPath = `/login/${token}`;
1692
1693
  let host = "";
1693
1694
  let state = "open";
@@ -1699,7 +1700,7 @@ async function openForm(input) {
1699
1700
  const server = createServer((req, res) => {
1700
1701
  void handle(req, res).catch(() => {
1701
1702
  if (!res.headersSent) {
1702
- send(res, 500, page({ error: "Internal error" }));
1703
+ send(res, 500, page({ error: "Internal error", csrf }));
1703
1704
  }
1704
1705
  });
1705
1706
  });
@@ -1718,19 +1719,15 @@ async function openForm(input) {
1718
1719
  return;
1719
1720
  }
1720
1721
  if (req.method === "GET") {
1721
- send(res, 200, page({ site: input.defaultSite }));
1722
+ send(res, 200, page({ site: input.defaultSite, csrf }));
1722
1723
  return;
1723
1724
  }
1724
1725
  if (req.method !== "POST") {
1725
1726
  send(res, 405, "Method not allowed", "text/plain");
1726
1727
  return;
1727
1728
  }
1728
- if (!isSameOrigin(req, host)) {
1729
- send(res, 403, "Cross-origin request rejected", "text/plain");
1730
- return;
1731
- }
1732
1729
  if (state === "verifying") {
1733
- send(res, 409, page({ error: "A submission is already being verified. Wait a moment and reload." }));
1730
+ send(res, 409, page({ error: "A submission is already being verified. Wait a moment and reload.", csrf }));
1734
1731
  return;
1735
1732
  }
1736
1733
  const body = await readBody(req);
@@ -1738,9 +1735,17 @@ async function openForm(input) {
1738
1735
  send(res, 413, "Request body too large", "text/plain");
1739
1736
  return;
1740
1737
  }
1741
- const parsed = parseSubmission(new URLSearchParams(body));
1738
+ const params = new URLSearchParams(body);
1739
+ if (!isSameOrigin(req, host) && !sameSecret(params.get("csrf") ?? "", csrf)) {
1740
+ send(res, 403, page({
1741
+ error: "\u6D4F\u89C8\u5668\u628A\u8FD9\u6B21\u63D0\u4EA4\u5F53\u6210\u4E86\u8DE8\u7AD9\u8BF7\u6C42\u3002\u8BF7\u5728\u672C\u9875\u91CD\u65B0\u586B\u5199\u5E76\u70B9\u300C\u9A8C\u8BC1\u5E76\u4FDD\u5B58\u300D\u3002",
1742
+ csrf
1743
+ }));
1744
+ return;
1745
+ }
1746
+ const parsed = parseSubmission(params);
1742
1747
  if ("error" in parsed) {
1743
- send(res, 400, page({ error: parsed.error, site: parsed.site, secretId: parsed.secretId }));
1748
+ send(res, 400, page({ error: parsed.error, site: parsed.site, secretId: parsed.secretId, csrf }));
1744
1749
  return;
1745
1750
  }
1746
1751
  state = "verifying";
@@ -1749,7 +1754,7 @@ async function openForm(input) {
1749
1754
  } catch (error) {
1750
1755
  state = "open";
1751
1756
  const message = error instanceof Error ? error.message : "Verification failed";
1752
- send(res, 400, page({ error: message, site: parsed.credential.site, secretId: parsed.credential.secretId }));
1757
+ send(res, 400, page({ error: message, site: parsed.credential.site, secretId: parsed.credential.secretId, csrf }));
1753
1758
  return;
1754
1759
  }
1755
1760
  state = "done";
@@ -1850,6 +1855,11 @@ body{font:14px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;max-wi
1850
1855
  label{display:block;margin:14px 0 4px;font-weight:600}input,select{width:100%;padding:8px;box-sizing:border-box;border:1px solid #c9cdd4;border-radius:6px;font:inherit}
1851
1856
  button{margin-top:20px;padding:9px 18px;border:0;border-radius:6px;background:#0052d9;color:#fff;font:inherit;cursor:pointer}
1852
1857
  .err{background:#fff1f0;border:1px solid #ffccc7;padding:8px 12px;border-radius:6px}.hint{color:#646a73;font-size:13px}
1858
+ .site-hint,.endpoint-field{display:none}
1859
+ form:has(#site option[value="cloud"]:checked) .hint-cloud,
1860
+ form:has(#site option[value="independent"]:checked) .hint-independent,
1861
+ form:has(#site option[value="custom"]:checked) .hint-custom,
1862
+ form:has(#site option[value="custom"]:checked) .endpoint-field{display:block}
1853
1863
  </style></head><body>${body}</body></html>`;
1854
1864
  }
1855
1865
  function form(input) {
@@ -1859,15 +1869,20 @@ function form(input) {
1859
1869
  <p class="hint">\u51ED\u636E\u53EA\u4FDD\u5B58\u5728\u672C\u673A\uFF08~/.adp/profiles\uFF0C\u6743\u9650 0600\uFF09\uFF0C\u4E0D\u4F1A\u53D1\u9001\u5230\u5BF9\u8BDD\u3002\u8BF7\u4E0D\u8981\u628A\u5BC6\u94A5\u7C98\u8D34\u5230\u804A\u5929\u91CC\u3002</p>
1860
1870
  ${input.error ? `<p class="err">${escapeHtml(input.error)}</p>` : ""}
1861
1871
  <form method="post" autocomplete="off">
1872
+ <input type="hidden" name="csrf" value="${escapeHtml(input.csrf ?? "")}">
1862
1873
  <label for="site">\u7AD9\u70B9</label>
1863
1874
  <select id="site" name="site">${option("cloud", "\u516C\u6709\u4E91\uFF08adp.tencentcloudapi.com\uFF09")}${option("independent", "\u72EC\u7ACB\u7AD9\uFF08capi.adp.tencent.com\uFF09")}${option("custom", "\u81EA\u5B9A\u4E49\u5730\u5740")}</select>
1864
- <label for="endpoint">\u81EA\u5B9A\u4E49\u5730\u5740\uFF08\u4EC5\u81EA\u5B9A\u4E49\u7AD9\u70B9\uFF09</label>
1875
+ <div class="endpoint-field">
1876
+ <label for="endpoint">\u81EA\u5B9A\u4E49\u5730\u5740</label>
1865
1877
  <input id="endpoint" name="endpoint" placeholder="capi.internal.example.com">
1878
+ </div>
1866
1879
  <label for="secretId">SecretId</label>
1867
- <input id="secretId" name="secretId" required value="${escapeHtml(input.secretId ?? "")}" placeholder="\u516C\u6709\u4E91 CAM \u5BC6\u94A5\u4EE5 AKID \u5F00\u5934">
1880
+ <input id="secretId" name="secretId" required value="${escapeHtml(input.secretId ?? "")}">
1868
1881
  <label for="secretKey">SecretKey</label>
1869
1882
  <input id="secretKey" name="secretKey" type="password" required>
1870
- <p class="hint">\u516C\u6709\u4E91\u5BC6\u94A5\u5728 <a href="https://console.cloud.tencent.com/cam/capi" target="_blank" rel="noreferrer">CAM \u63A7\u5236\u53F0</a> \u521B\u5EFA\u3002</p>
1883
+ <p class="hint site-hint hint-cloud">\u516C\u6709\u4E91\u5BC6\u94A5\u5728 <a href="https://console.cloud.tencent.com/cam/capi" target="_blank" rel="noreferrer">CAM \u63A7\u5236\u53F0</a> \u521B\u5EFA\uFF0CSecretId \u4EE5 AKID \u5F00\u5934\u3002</p>
1884
+ <p class="hint site-hint hint-independent">\u72EC\u7ACB\u7AD9\u5BC6\u94A5\u5728 <a href="https://adp.tencent.com/adp#/key-manage" target="_blank" rel="noreferrer">\u4F01\u4E1A\u7BA1\u7406 \u2192 \u5BC6\u94A5\u7BA1\u7406 \u2192 \u65B0\u5EFAAPI\u5BC6\u94A5</a>\uFF0C\u4E0D\u8981\u6C42 AKID \u524D\u7F00\u3002</p>
1885
+ <p class="hint site-hint hint-custom">\u4F7F\u7528\u76EE\u6807\u73AF\u5883\u7B7E\u53D1\u7684 SecretId / SecretKey\u3002</p>
1871
1886
  <button type="submit">\u9A8C\u8BC1\u5E76\u4FDD\u5B58</button>
1872
1887
  </form>`;
1873
1888
  }