@illuminis/comprism 0.1.4 → 0.1.5

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.
@@ -234,14 +234,40 @@ async function runLogin(args) {
234
234
  process.exitCode = 1;
235
235
  return;
236
236
  }
237
- out(ui.banner('Sign in'));
237
+ // Under the session's own mark when the session is about to open, so the
238
+ // name is not drawn twice in a row.
239
+ out(args.includes('--into-session') ? ` ${ui.c.bold('Sign in')}` : ui.banner('Sign in'));
238
240
  out();
239
241
  // Flags still work, for a script or a second machine. A person gets asked.
240
242
  const flag = (name) => {
241
243
  const i = args.indexOf(name);
242
244
  return i >= 0 ? args[i + 1] : undefined;
243
245
  };
244
- const username = flag('--username') || flag('--email') || await (0, prompt_1.ask)(' email: ');
246
+ // THE LAST PERSON, OFFERED. Signing in again is Enter: the email and the
247
+ // workspace they used last time, exactly as they were, so a local workspace
248
+ // stays local instead of being looked up again and sent to production.
249
+ const { readLast, saveLast, forgetLast, savedPassword, savePassword, forgetPassword, keychainAvailable } = await Promise.resolve().then(() => __importStar(require('../lib/lastlogin')));
250
+ if (args.includes('--forget')) {
251
+ forgetLast();
252
+ out(ui.ok('The last sign in and any saved password on this Mac are forgotten.'));
253
+ out();
254
+ return;
255
+ }
256
+ const last = flag('--username') || flag('--email') || flag('--workspace') ? null : readLast();
257
+ if (last) {
258
+ out(` ${ui.c.dim('last time')} ${ui.c.bold(last.email)} ${ui.c.dim('at')} ${ui.c.bold(last.workspace)}`);
259
+ out(` ${ui.c.dim('press Enter to sign in as them, or type another email')}`);
260
+ }
261
+ const typedEmail = flag('--username') || flag('--email') || await (0, prompt_1.askOrCancel)(' email: ');
262
+ // Ctrl+C is "never mind", not "yes, the last person".
263
+ if (typedEmail === null) {
264
+ out();
265
+ out(ui.c.dim(' sign in canceled'));
266
+ out();
267
+ return;
268
+ }
269
+ const username = typedEmail || last?.email || '';
270
+ const again = Boolean(last && username === last.email);
245
271
  if (!username) {
246
272
  out(ui.fail('An email address is needed.'));
247
273
  out();
@@ -249,11 +275,12 @@ async function runLogin(args) {
249
275
  return;
250
276
  }
251
277
  // Where this person's workspace is. Asked of the product, not of them.
252
- let typedWorkspace = flag('--workspace');
278
+ let typedWorkspace = flag('--workspace') || (again ? last?.workspace : undefined);
253
279
  // Captured BEFORE the email lookup can fill it in. A workspace the product
254
280
  // worked out is not a workspace the person typed, and only the second may be
255
- // a local address. See the fence in `writeConnection`.
256
- const typedByHand = Boolean(typedWorkspace);
281
+ // a local address. See the fence in `writeConnection`. The last sign in
282
+ // counts as typed only if it was typed then.
283
+ const typedByHand = Boolean(flag('--workspace')) || Boolean(again && last?.typed);
257
284
  if (!typedWorkspace) {
258
285
  const live = new ui.LiveIndicator();
259
286
  live.start('finding your workspace');
@@ -292,7 +319,11 @@ async function runLogin(args) {
292
319
  process.exitCode = 1;
293
320
  return;
294
321
  }
295
- const password = byCompany ? '' : await (0, prompt_1.askHidden)(' password: ');
322
+ // The keychain first, when the person chose to keep it there last time.
323
+ const kept = byCompany ? null : savedPassword(username, typedWorkspace);
324
+ if (kept)
325
+ out(` ${ui.c.dim('password: from your Mac keychain')}`);
326
+ const password = byCompany ? '' : kept || await (0, prompt_1.askHidden)(' password: ');
296
327
  if (!byCompany && !password) {
297
328
  out(ui.fail('A password is needed.'));
298
329
  out();
@@ -357,6 +388,10 @@ async function runLogin(args) {
357
388
  }
358
389
  }
359
390
  if (!reply.sign_in?.token) {
391
+ // A kept password that no longer works is removed, so the next sign in
392
+ // asks for the new one instead of failing the same way again.
393
+ if (kept)
394
+ forgetPassword(username, typedWorkspace);
360
395
  out();
361
396
  out(ui.fail(reply.message || 'That username and password were not accepted.'));
362
397
  out(` ${ui.c.dim('check the workspace name too: a right password in the wrong workspace looks the same')}`);
@@ -420,14 +455,33 @@ async function runLogin(args) {
420
455
  // So a new terminal presents the key just issued, not the last one or none.
421
456
  for (const profile of (await Promise.resolve().then(() => __importStar(require('./install')))).finishSetup())
422
457
  out(` Finishing setup: added one line to ${profile}`);
458
+ // Remembered for next time: who, and where, exactly as used now.
459
+ saveLast({ email: username, workspace: typedWorkspace, typed: typedByHand });
460
+ if (!byCompany && !kept && password && keychainAvailable()) {
461
+ const keep = (await (0, prompt_1.ask)(' keep your password in your Mac keychain, so next time is just Enter? (y/n) '))
462
+ .trim().toLowerCase();
463
+ if (keep === 'y' || keep === 'yes') {
464
+ out(savePassword(username, typedWorkspace, password)
465
+ ? ` ${ui.c.dim('kept in your keychain; remove it with')} ${ui.c.bold('comprism login --forget')}`
466
+ : ` ${ui.c.dim('the keychain would not take it; you will be asked next time')}`);
467
+ }
468
+ }
423
469
  out();
424
- out(ui.ok(`Signed in as ${ui.c.bold(username)} at ${ui.c.bold(signedIn?.workspace_url || url)}.`));
470
+ // Where this machine will actually talk to: the address typed, when one was.
471
+ const where = (typedByHand && url) || signedIn?.workspace_url || url;
472
+ const onLaptop = /localhost|127\.0\.0\.1/.test(where);
473
+ out(ui.ok(`Signed in as ${ui.c.bold(username)} ${onLaptop
474
+ ? `on this laptop (${ui.c.bold(where.replace(/^https?:\/\//, ''))})`
475
+ : `at ${ui.c.bold(where)}`}.`));
425
476
  if (workspaceKey) {
426
477
  out(` ${ui.c.dim('This machine is enrolled and can be revoked from Administration.')}`);
427
478
  // Straight into the welcome screen, so the first thing after signing in is
428
479
  // where they are rather than another instruction.
429
- const { showWelcome } = await Promise.resolve().then(() => __importStar(require('./welcome')));
430
- await showWelcome();
480
+ // Unless the session is about to open, which draws it itself.
481
+ if (!args.includes('--into-session')) {
482
+ const { showWelcome } = await Promise.resolve().then(() => __importStar(require('./welcome')));
483
+ await showWelcome();
484
+ }
431
485
  }
432
486
  else {
433
487
  process.exitCode = 1;
@@ -4,5 +4,9 @@ export interface Opening {
4
4
  latest?: boolean;
5
5
  resume?: string;
6
6
  pick?: boolean;
7
+ /** Set once signing in has been offered, so it is never offered twice. */
8
+ noSignIn?: boolean;
9
+ /** The mark is already on screen (signing in drew it). */
10
+ noMark?: boolean;
7
11
  }
8
12
  export declare function runRepl(how?: Opening): Promise<void>;