ds-01 1.0.14 → 1.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.
@@ -1,41 +1,26 @@
1
1
  import { Command } from "commander";
2
- import {
3
- intro,
4
- outro,
5
- spinner,
6
- note,
7
- cancel,
8
- } from "@clack/prompts";
2
+ import { intro, outro, spinner, note, cancel } from "@clack/prompts";
9
3
  import pc from "picocolors";
10
4
  import open from "open";
11
5
  import machineIdPkg from "node-machine-id";
12
-
13
6
  import { saveToken } from "../utils/config.js";
14
7
  import {
15
8
  createDeviceKey,
16
9
  getDevicePublicKey,
17
10
  } from "../utils/secureKeyStore.js";
18
11
 
19
- const API_BASE_URL =
20
- process.env.DS01_API_URL ||
21
- "https://ds-01.vercel.app";
12
+ const API_BASE_URL = process.env.DS01_API_URL || "https://ds-01.vercel.app";
22
13
 
23
14
  const { machineIdSync } = machineIdPkg;
24
15
 
25
16
  export const login = new Command()
26
17
  .name("login")
27
- .description(
28
- "Authenticate your terminal with DS01 via browser",
29
- )
18
+ .description("Authenticate your terminal with DS01 via browser")
30
19
  .action(async () => {
31
20
  console.log();
32
21
 
33
22
  intro(
34
- `${pc.bgWhite(
35
- pc.black(
36
- pc.bold(" DS01 "),
37
- ),
38
- )} ${pc.gray(
23
+ `${pc.bgWhite(pc.black(pc.bold(" DS01 ")))} ${pc.gray(
39
24
  "v1.0.0 — Terminal Authentication",
40
25
  )}`,
41
26
  );
@@ -43,300 +28,142 @@ export const login = new Command()
43
28
  const s = spinner();
44
29
 
45
30
  try {
46
- // ==================================================
47
- // 1. CREATE / LOAD SECURE DEVICE KEY
48
- // ==================================================
49
-
50
- s.start(
51
- "Preparing secure device identity...",
52
- );
31
+ s.start("Preparing secure device identity...");
53
32
 
54
33
  await createDeviceKey();
55
-
56
- const publicKey =
57
- await getDevicePublicKey();
58
-
59
- const hardwareId =
60
- machineIdSync();
61
-
34
+ const publicKey = await getDevicePublicKey();
35
+ const hardwareId = machineIdSync();
62
36
  const publicKeyType =
63
- process.platform === "win32"
64
- ? "windows-rsa"
65
- : "macos-ec";
66
-
67
- // ==================================================
68
- // 2. REQUEST DEVICE CODE
69
- // ==================================================
70
-
71
- s.start(
72
- "Requesting pairing code...",
73
- );
37
+ process.platform === "win32" ? "windows-rsa" : "macos-ec";
74
38
 
75
- const initResponse =
76
- await fetch(
77
- `${API_BASE_URL}/api/auth/device/code`,
78
- {
79
- method: "POST",
39
+ // Req to my server with machineId and certificate for now but eventually will send the publicKey
40
+ s.start("Requesting pairing code...");
80
41
 
81
- headers: {
82
- "Content-Type":
83
- "application/json",
84
- },
42
+ const initResponse = await fetch(`${API_BASE_URL}/api/auth/device/code`, {
43
+ method: "POST",
44
+ headers: {
45
+ "Content-Type": "application/json",
46
+ },
85
47
 
86
- body: JSON.stringify({
87
- machineId:
88
- hardwareId,
89
-
90
- publicKey,
91
-
92
- publicKeyType,
93
- }),
94
- },
95
- );
48
+ body: JSON.stringify({
49
+ machineId: hardwareId,
50
+ publicKey,
51
+ publicKeyType,
52
+ }),
53
+ });
96
54
 
97
55
  if (!initResponse.ok) {
98
- s.stop(
99
- pc.red(
100
- "Failed to reach DS01 authorization server.",
101
- ),
102
- );
103
-
104
- cancel(
105
- `Server responded with HTTP ${initResponse.status}`,
106
- );
107
-
56
+ s.stop(pc.red("Failed to reach DS01 authorization server."));
57
+ cancel(`Server responded with HTTP ${initResponse.status}`);
108
58
  process.exit(1);
109
59
  }
110
60
 
111
- const {
112
- deviceCode,
113
- userCode,
114
- verificationUrl,
115
- interval,
116
- } =
61
+ const { deviceCode, userCode, verificationUrl, interval } =
117
62
  await initResponse.json();
118
63
 
119
- if (
120
- !deviceCode ||
121
- !userCode ||
122
- !verificationUrl
123
- ) {
64
+ if (!deviceCode || !userCode || !verificationUrl) {
124
65
  throw new Error(
125
66
  "Authorization server returned an invalid device response.",
126
67
  );
127
68
  }
128
69
 
129
- s.stop(
130
- pc.green(
131
- "Secure device identity registered.",
132
- ),
133
- );
134
-
135
- // ==================================================
136
- // 3. SHOW BROWSER AUTHORIZATION
137
- // ==================================================
70
+ s.stop(pc.green("Secure device identity registered."));
138
71
 
72
+ // Opening users browser with verification URL
139
73
  note(
140
- `${pc.bold(
141
- "Pairing Code:",
142
- )} ${pc.cyan(
143
- pc.bold(
144
- ` ${userCode} `,
145
- ),
74
+ `${pc.bold("Pairing Code:")} ${pc.cyan(
75
+ pc.bold(` ${userCode} `),
146
76
  )}\n` +
147
- `${pc.bold(
148
- "Verification URL:",
149
- )} ${pc.underline(
150
- verificationUrl,
151
- )}`,
77
+ `${pc.bold("Verification URL:")} ${pc.underline(verificationUrl)}`,
152
78
  "Action Required",
153
79
  );
154
80
 
155
81
  try {
156
- await open(
157
- verificationUrl,
158
- );
82
+ await open(verificationUrl);
159
83
  } catch {
160
84
  // Browser launch failure is non-fatal.
161
85
  }
86
+
87
+ // we polling to one of my server endpoint to check wether the temporary req is approved or not ??
88
+ s.start("Waiting for web authorization...");
162
89
 
163
- // ==================================================
164
- // 4. POLL FOR AUTHORIZATION
165
- // ==================================================
166
-
167
- s.start(
168
- "Waiting for web authorization...",
169
- );
170
-
171
- const pollInterval =
172
- (interval || 5) * 1000;
173
-
174
- let token: string | null =
175
- null;
90
+ const pollInterval = (interval || 5) * 1000;
91
+ let token: string | null = null;
176
92
 
177
93
  while (true) {
178
- await new Promise(
179
- (resolve) =>
180
- setTimeout(
181
- resolve,
182
- pollInterval,
183
- ),
184
- );
185
-
186
- const tokenResponse =
187
- await fetch(
188
- `${API_BASE_URL}/api/auth/device/token`,
189
- {
190
- method: "POST",
94
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
191
95
 
192
- headers: {
193
- "Content-Type":
194
- "application/json",
195
- },
196
-
197
- body: JSON.stringify({
198
- deviceCode,
199
- machineId:
200
- hardwareId,
201
- }),
96
+ const tokenResponse = await fetch(
97
+ `${API_BASE_URL}/api/auth/device/token`,
98
+ {
99
+ method: "POST",
100
+ headers: {
101
+ "Content-Type": "application/json",
202
102
  },
203
- );
103
+ body: JSON.stringify({
104
+ deviceCode,
105
+ machineId: hardwareId,
106
+ }),
107
+ },
108
+ );
204
109
 
205
110
  let tokenData: any;
206
-
207
111
  try {
208
- tokenData =
209
- await tokenResponse.json();
112
+ tokenData = await tokenResponse.json();
210
113
  } catch {
211
- s.stop(
212
- pc.red(
213
- "Authorization server returned invalid JSON.",
214
- ),
215
- );
216
-
217
- cancel(
218
- "Unable to read authorization response.",
219
- );
220
-
114
+ s.stop(pc.red("Authorization server returned invalid JSON."));
115
+ cancel("Unable to read authorization response.");
221
116
  process.exit(1);
222
117
  }
223
118
 
224
- // ==================================================
225
- // AUTHORIZATION SUCCESS
226
- // ==================================================
227
-
119
+ // Auth success stop polling
228
120
  if (
229
121
  tokenResponse.ok &&
230
- typeof tokenData.accessToken ===
231
- "string" &&
122
+ typeof tokenData.accessToken === "string" &&
232
123
  tokenData.accessToken.length > 0
233
124
  ) {
234
- token =
235
- tokenData.accessToken;
236
-
125
+ token = tokenData.accessToken;
237
126
  break;
238
127
  }
239
128
 
240
- // ==================================================
241
- // STILL WAITING
242
- // ==================================================
243
-
244
- if (
245
- tokenData.error ===
246
- "authorization_pending"
247
- ) {
129
+ // Still waiting keep polling
130
+ if (tokenData.error === "authorization_pending") {
248
131
  continue;
249
132
  }
250
133
 
251
- // ==================================================
252
- // AUTHORIZATION FAILED
253
- // ==================================================
254
-
255
- s.stop(
256
- pc.red(
257
- "Authorization failed or expired.",
258
- ),
259
- );
260
-
261
- cancel(
262
- `Reason: ${
263
- tokenData.error ||
264
- "Unknown authorization error"
265
- }`,
266
- );
267
-
134
+ // Authorization Failed
135
+ s.stop(pc.red("Authorization failed or expired."));
136
+ cancel(`Reason: ${tokenData.error || "Unknown authorization error"}`);
268
137
  process.exit(1);
269
138
  }
270
139
 
271
- // ==================================================
272
- // 5. STOP POLLING SPINNER
273
- // ==================================================
274
-
275
- s.stop(
276
- pc.green(
277
- "Hardware signature linked & token verified!",
278
- ),
279
- );
280
-
281
- // ==================================================
282
- // 6. ENSURE TOKEN EXISTS
283
- // ==================================================
140
+ // outside the loop stop the spinner
141
+ s.stop(pc.green("Hardware signature linked & token verified!"));
284
142
 
143
+ // ENSURE TOKEN EXISTS
285
144
  if (!token) {
286
145
  throw new Error(
287
146
  "Authorization completed without receiving an access token.",
288
147
  );
289
148
  }
290
149
 
291
- // ==================================================
292
- // 7. SAVE TOKEN
293
- // ==================================================
294
-
295
- saveToken(
296
- token,
297
- hardwareId,
298
- );
299
-
300
- // ==================================================
301
- // 8. SUCCESS
302
- // ==================================================
303
-
150
+ saveToken(token, hardwareId);
304
151
  outro(
305
- `${pc.white(
306
- "✔",
307
- )} ${pc.bold(
308
- "Terminal synced successfully",
309
- )}\n` +
310
- pc.gray(
311
- "Secure device key and session token are ready.",
312
- ),
152
+ `${pc.white("✔")} ${pc.bold("Terminal synced successfully")}\n` +
153
+ pc.gray("Secure device key and session token are ready."),
313
154
  );
314
155
 
315
- // ==================================================
316
- // 9. HARD EXIT
317
- // ==================================================
318
- //
156
+ // Hard Exit
319
157
  // The login command is completely finished.
320
- //
158
+
321
159
  // This prevents any lingering CLI handles
322
160
  // (spinner timers, readline handles, etc.)
323
161
  // from keeping the Node process alive.
324
162
  //
325
163
  process.exit(0);
326
164
  } catch (error: any) {
327
- s.stop(
328
- pc.red(
329
- "An error occurred during login.",
330
- ),
331
- );
332
-
333
- cancel(
334
- pc.gray(
335
- error?.message ||
336
- "Unknown CLI Error",
337
- ),
338
- );
339
-
165
+ s.stop(pc.red("An error occurred during login."));
166
+ cancel(pc.gray(error?.message || "Unknown CLI Error"));
340
167
  process.exit(1);
341
168
  }
342
- });
169
+ });
@@ -41,9 +41,7 @@ export const logout = new Command()
41
41
 
42
42
  // NEW: Delete local credentials only after the server confirms
43
43
  // that the CLI session has been revoked.
44
- console.log("✅ Server confirmed CLI session was revoked.");
45
44
  deleteToken();
46
- console.log("✅ Local credentials deleted.");
47
45
  spinner.succeed(chalk.green("Successfully logged out."));
48
46
  console.log(
49
47
  chalk.gray(
@@ -11,13 +11,16 @@ const execFileAsync = promisify(execFile);
11
11
  const KEY_NAME = "DS01-CLI-Device-Key";
12
12
 
13
13
  const __filename = fileURLToPath(import.meta.url);
14
+ // import.meta.ur -- current module ka location URL form mein deta hai
15
+
14
16
  const __dirname = path.dirname(__filename);
17
+ //C:\Projects\DS01\cli\dist\utils
18
+
19
+ // __filename = where is THIS FILE?
20
+ // __dirname = which folder contains THIS FILE?
15
21
 
16
22
  function getMacHelperPath(): string {
17
- return path.resolve(
18
- __dirname,
19
- "../native/macos-key-helper.swift",
20
- );
23
+ return path.resolve(__dirname, "../native/macos-key-helper.swift");
21
24
  }
22
25
 
23
26
  function ensureSupportedOS(): void {
@@ -30,11 +33,7 @@ function ensureSupportedOS(): void {
30
33
  }
31
34
  }
32
35
 
33
- /**
34
- * ---------------------------------------------------------
35
- * WINDOWS
36
- * ---------------------------------------------------------
37
- */
36
+ // for windows
38
37
 
39
38
  async function createWindowsDeviceKey(): Promise<void> {
40
39
  const script = `
@@ -102,21 +101,10 @@ Write-Output "CREATED"
102
101
  const result = stdout.trim();
103
102
 
104
103
  if (result !== "CREATED" && result !== "EXISTS") {
105
- throw new Error(
106
- "Failed to create Windows DS01 device key.",
107
- );
104
+ throw new Error("Failed to create Windows DS01 device key.");
108
105
  }
109
106
  }
110
107
 
111
- /**
112
- * Find exactly one valid DS01 certificate.
113
- *
114
- * We intentionally do not use Select-Object -First 1.
115
- *
116
- * 0 certificates -> error
117
- * 1 certificate -> use it
118
- * 2+ certificates -> error
119
- */
120
108
  function getWindowsCertificateLookup(): string {
121
109
  return `
122
110
  $certificates = @(Get-ChildItem Cert:\\CurrentUser\\My |
@@ -138,6 +126,12 @@ $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]$certifi
138
126
  `;
139
127
  }
140
128
 
129
+ // cert - just a variable holding the certificate object
130
+ // X509Certificate2 is a Windows/.NET certificate object
131
+ // that gives the code a standard way to work with the certificate and its associated key information
132
+ // X509Certificate2 a class/type, rather than simply a "format"
133
+
134
+
141
135
  async function getWindowsPublicKey(): Promise<string> {
142
136
  const script = `
143
137
  $ErrorActionPreference = "Stop"
@@ -165,19 +159,14 @@ ${getWindowsCertificateLookup()}
165
159
  const certificate = stdout.trim();
166
160
 
167
161
  if (!certificate) {
168
- throw new Error(
169
- "Unable to read Windows DS01 public certificate.",
170
- );
162
+ throw new Error("Unable to read Windows DS01 public certificate.");
171
163
  }
172
164
 
173
165
  return certificate;
174
166
  }
175
167
 
176
- async function signWindowsDeviceKey(
177
- data: Uint8Array,
178
- ): Promise<Uint8Array> {
179
- const dataBase64 =
180
- Buffer.from(data).toString("base64");
168
+ async function signWindowsDeviceKey(data: Uint8Array): Promise<Uint8Array> {
169
+ const dataBase64 = Buffer.from(data).toString("base64");
181
170
 
182
171
  const script = `
183
172
  $ErrorActionPreference = "Stop"
@@ -226,17 +215,16 @@ finally {
226
215
  },
227
216
  );
228
217
 
218
+
219
+
220
+
229
221
  const signature = stdout.trim();
230
222
 
231
223
  if (!signature) {
232
- throw new Error(
233
- "Failed to sign data with Windows device key.",
234
- );
224
+ throw new Error("Failed to sign data with Windows device key.");
235
225
  }
236
226
 
237
- return new Uint8Array(
238
- Buffer.from(signature, "base64"),
239
- );
227
+ return new Uint8Array(Buffer.from(signature, "base64"));
240
228
  }
241
229
 
242
230
  async function deleteWindowsDeviceKey(): Promise<void> {
@@ -277,18 +265,10 @@ Write-Output "DELETED"
277
265
  );
278
266
  }
279
267
 
280
- /**
281
- * ---------------------------------------------------------
282
- * MACOS
283
- * ---------------------------------------------------------
284
- */
268
+ // for Mac
285
269
 
286
270
  async function runMacHelper(
287
- operation:
288
- | "create"
289
- | "public"
290
- | "sign"
291
- | "delete",
271
+ operation: "create" | "public" | "sign" | "delete",
292
272
  data?: Uint8Array,
293
273
  ): Promise<string> {
294
274
  const helper = getMacHelperPath();
@@ -296,76 +276,51 @@ async function runMacHelper(
296
276
  const args = [helper, operation];
297
277
 
298
278
  if (data) {
299
- args.push(
300
- Buffer.from(data).toString("base64"),
301
- );
279
+ args.push(Buffer.from(data).toString("base64"));
302
280
  }
303
281
 
304
- const { stdout } = await execFileAsync(
305
- "swift",
306
- args,
307
- {
308
- windowsHide: true,
309
- },
310
- );
282
+ const { stdout } = await execFileAsync("swift", args, {
283
+ windowsHide: true,
284
+ });
311
285
 
312
286
  return stdout.trim();
313
287
  }
314
288
 
315
289
  async function createMacDeviceKey(): Promise<void> {
316
- const result =
317
- await runMacHelper("create");
290
+ const result = await runMacHelper("create");
318
291
 
319
- if (
320
- result !== "CREATED" &&
321
- result !== "EXISTS"
322
- ) {
292
+ if (result !== "CREATED" && result !== "EXISTS") {
323
293
  throw new Error(
324
- result ||
325
- "Failed to create macOS Secure Enclave device key.",
294
+ result || "Failed to create macOS Secure Enclave device key.",
326
295
  );
327
296
  }
328
297
  }
329
298
 
330
299
  async function getMacPublicKey(): Promise<string> {
331
- const result =
332
- await runMacHelper("public");
300
+ const result = await runMacHelper("public");
333
301
 
334
302
  if (!result) {
335
- throw new Error(
336
- "Unable to read macOS DS01 public key.",
337
- );
303
+ throw new Error("Unable to read macOS DS01 public key.");
338
304
  }
339
305
 
340
306
  return result;
341
307
  }
342
308
 
343
- async function signMacDeviceKey(
344
- data: Uint8Array,
345
- ): Promise<Uint8Array> {
346
- const result =
347
- await runMacHelper("sign", data);
309
+ async function signMacDeviceKey(data: Uint8Array): Promise<Uint8Array> {
310
+ const result = await runMacHelper("sign", data);
348
311
 
349
312
  if (!result) {
350
- throw new Error(
351
- "Failed to sign data with macOS Secure Enclave key.",
352
- );
313
+ throw new Error("Failed to sign data with macOS Secure Enclave key.");
353
314
  }
354
315
 
355
- return new Uint8Array(
356
- Buffer.from(result, "base64"),
357
- );
316
+ return new Uint8Array(Buffer.from(result, "base64"));
358
317
  }
359
318
 
360
319
  async function deleteMacDeviceKey(): Promise<void> {
361
320
  await runMacHelper("delete");
362
321
  }
363
322
 
364
- /**
365
- * ---------------------------------------------------------
366
- * PUBLIC API
367
- * ---------------------------------------------------------
368
- */
323
+ // Public APIs which we use this for creating keys and certificate
369
324
 
370
325
  export async function createDeviceKey(): Promise<void> {
371
326
  ensureSupportedOS();
@@ -388,9 +343,7 @@ export async function getDevicePublicKey(): Promise<string> {
388
343
  return getMacPublicKey();
389
344
  }
390
345
 
391
- export async function signWithDeviceKey(
392
- data: Uint8Array,
393
- ): Promise<Uint8Array> {
346
+ export async function signWithDeviceKey(data: Uint8Array): Promise<Uint8Array> {
394
347
  ensureSupportedOS();
395
348
 
396
349
  if (os.platform() === "win32") {
@@ -409,4 +362,4 @@ export async function deleteDeviceKey(): Promise<void> {
409
362
  }
410
363
 
411
364
  await deleteMacDeviceKey();
412
- }
365
+ }
package/src/test-key.ts DELETED
@@ -1,20 +0,0 @@
1
- import {
2
- createDeviceKey,
3
- getDevicePublicKey,
4
- signWithDeviceKey,
5
- } from "./utils/secureKeyStore.js";
6
-
7
- await createDeviceKey();
8
-
9
- const publicKey = await getDevicePublicKey();
10
-
11
- console.log("Public key:", publicKey);
12
-
13
- const message = new TextEncoder().encode("hello DS01");
14
-
15
- const signature = await signWithDeviceKey(message);
16
-
17
- console.log(
18
- "Signature:",
19
- Buffer.from(signature).toString("base64"),
20
- );