apiblaze 0.1.0 → 0.1.1

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +39 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -52,3 +52,4 @@ On Ctrl+C the tunnel is cleanly deregistered.
52
52
  ## License
53
53
 
54
54
  MIT
55
+ # npm-apiblaze
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ var ApiError = class extends Error {
39
39
  // src/commands/login.ts
40
40
  var import_chalk = __toESM(require("chalk"));
41
41
  var import_ora = __toESM(require("ora"));
42
+ var crypto = __toESM(require("crypto"));
42
43
 
43
44
  // src/lib/auth.ts
44
45
  var fs = __toESM(require("fs"));
@@ -76,17 +77,28 @@ function getApiblazeDir() {
76
77
  // src/commands/login.ts
77
78
  var AUTH_BASE = "https://auth.apiblaze.com";
78
79
  var CLIENT_ID = "emdE4-Pt9LGOAXL5MA1zEQ";
80
+ var SCOPE = "openid email profile offline_access";
81
+ function generateCodeVerifier() {
82
+ return crypto.randomBytes(32).toString("base64url");
83
+ }
84
+ function generateCodeChallenge(verifier) {
85
+ return crypto.createHash("sha256").update(verifier).digest("base64url");
86
+ }
79
87
  function openBrowser(url) {
80
88
  const { exec } = require("child_process");
81
- const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "${url}"` : `xdg-open "${url}"`;
82
- exec(cmd, () => {
83
- });
89
+ const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
90
+ exec(cmd);
84
91
  }
85
- async function requestDeviceCode() {
86
- const res = await fetch(`${AUTH_BASE}/oauth/device/code`, {
92
+ async function requestDeviceCode(codeChallenge) {
93
+ const res = await fetch(`${AUTH_BASE}/device_authorization`, {
87
94
  method: "POST",
88
95
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
89
- body: new URLSearchParams({ client_id: CLIENT_ID, scope: "offline_access" })
96
+ body: new URLSearchParams({
97
+ client_id: CLIENT_ID,
98
+ scope: SCOPE,
99
+ code_challenge: codeChallenge,
100
+ code_challenge_method: "S256"
101
+ })
90
102
  });
91
103
  if (!res.ok) {
92
104
  const body = await res.text();
@@ -94,17 +106,19 @@ async function requestDeviceCode() {
94
106
  }
95
107
  return res.json();
96
108
  }
97
- async function pollForToken(deviceCode, intervalSecs) {
109
+ async function pollForToken(deviceCode, codeVerifier, intervalSecs) {
110
+ const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
98
111
  let pollInterval = intervalSecs * 1e3;
99
112
  while (true) {
100
113
  await new Promise((r) => setTimeout(r, pollInterval));
101
- const res = await fetch(`${AUTH_BASE}/oauth/token`, {
114
+ const res = await fetch(`${AUTH_BASE}/token`, {
102
115
  method: "POST",
103
116
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
104
117
  body: new URLSearchParams({
105
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
118
+ grant_type: DEVICE_GRANT,
106
119
  device_code: deviceCode,
107
- client_id: CLIENT_ID
120
+ client_id: CLIENT_ID,
121
+ code_verifier: codeVerifier
108
122
  })
109
123
  });
110
124
  const body = await res.json();
@@ -126,17 +140,24 @@ async function pollForToken(deviceCode, intervalSecs) {
126
140
  }
127
141
  async function runLogin() {
128
142
  console.log(import_chalk.default.bold("\nLogging in to APIblaze...\n"));
129
- const deviceAuth = await requestDeviceCode();
130
- console.log(`${import_chalk.default.cyan("\u2192")} Open this URL in your browser:`);
131
- console.log(` ${import_chalk.default.bold.underline(deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri)}
143
+ const codeVerifier = generateCodeVerifier();
144
+ const codeChallenge = generateCodeChallenge(codeVerifier);
145
+ const deviceAuth = await requestDeviceCode(codeChallenge);
146
+ const verifyUrl = deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri;
147
+ console.log(`${import_chalk.default.cyan("\u2192")} Open this URL in your browser to confirm login:`);
148
+ console.log(` ${import_chalk.default.bold.underline(verifyUrl)}
132
149
  `);
133
- if (!deviceAuth.verification_uri_complete) {
134
- console.log(`${import_chalk.default.cyan("\u2192")} Enter code: ${import_chalk.default.bold(deviceAuth.user_code)}
150
+ console.log(`${import_chalk.default.cyan("\u2192")} Your code: ${import_chalk.default.bold(deviceAuth.user_code)}
135
151
  `);
152
+ openBrowser(verifyUrl);
153
+ const spinner = (0, import_ora.default)("Waiting for authorization in browser...").start();
154
+ let token;
155
+ try {
156
+ token = await pollForToken(deviceAuth.device_code, codeVerifier, deviceAuth.interval);
157
+ } catch (err) {
158
+ spinner.fail("Login failed.");
159
+ throw err;
136
160
  }
137
- openBrowser(deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri);
138
- const spinner = (0, import_ora.default)("Waiting for authorization...").start();
139
- const token = await pollForToken(deviceAuth.device_code, deviceAuth.interval);
140
161
  saveCredentials({
141
162
  accessToken: token.access_token,
142
163
  refreshToken: token.refresh_token,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Dev tunnel CLI for APIblaze — route localhost projects through Cloudflare tunnels",
5
5
  "keywords": [
6
6
  "apiblaze",