mirror of
https://github.com/withastro/astro.git
synced 2024-12-16 21:46:22 -05:00
update login flow to support Brave (#10258)
This commit is contained in:
parent
e86b81a671
commit
c2e7b9847e
4 changed files with 58 additions and 30 deletions
|
@ -53,6 +53,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@libsql/client": "^0.4.3",
|
||||
"async-listen": "^3.0.1",
|
||||
"deep-diff": "^1.0.2",
|
||||
"drizzle-orm": "^0.28.6",
|
||||
"kleur": "^4.1.5",
|
||||
|
|
|
@ -1,49 +1,65 @@
|
|||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { createServer } from 'node:http';
|
||||
import type { AstroConfig } from 'astro';
|
||||
import { listen } from 'async-listen';
|
||||
import { cyan } from 'kleur/colors';
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { createServer as _createServer } from 'node:http';
|
||||
import open from 'open';
|
||||
import ora from 'ora';
|
||||
import type { Arguments } from 'yargs-parser';
|
||||
import { SESSION_LOGIN_FILE } from '../../../tokens.js';
|
||||
import { getAstroStudioUrl } from '../../../utils.js';
|
||||
|
||||
function serveAndResolveSession(): Promise<string> {
|
||||
// NOTE(fks): How the Astro CLI login process works:
|
||||
// 1. The Astro CLI creates a temporary server to listen for the session token
|
||||
// 2. The user is directed to studio.astro.build/ to login
|
||||
// 3. The user is redirected back to the temporary server with their session token
|
||||
// 4. The temporary server receives and saves the session token, logging the user in
|
||||
// 5. The user is redirected one last time to a success/failure page
|
||||
async function createServer(): Promise<{ url: string; promise: Promise<string> }> {
|
||||
let resolve: (value: string | PromiseLike<string>) => void,
|
||||
reject: (value?: string | PromiseLike<string>) => void;
|
||||
reject: (reason?: Error) => void;
|
||||
|
||||
const server = _createServer((req, res) => {
|
||||
// Handle the request
|
||||
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
||||
const sessionParam = url.searchParams.get('session');
|
||||
// Handle the response & resolve the promise
|
||||
res.statusCode = 302;
|
||||
if (!sessionParam) {
|
||||
res.setHeader('location', getAstroStudioUrl() + '/auth/cli/error');
|
||||
reject(new Error('Failed to log in'));
|
||||
} else {
|
||||
res.setHeader('location', getAstroStudioUrl() + '/auth/cli/success');
|
||||
resolve(sessionParam);
|
||||
}
|
||||
res.end();
|
||||
});
|
||||
|
||||
const { port } = await listen(server, 0, '127.0.0.1');
|
||||
const serverUrl = `http://localhost:${port}`;
|
||||
const sessionPromise = new Promise<string>((_resolve, _reject) => {
|
||||
resolve = _resolve;
|
||||
reject = _reject;
|
||||
});
|
||||
|
||||
const server = createServer((req, res) => {
|
||||
res.writeHead(200);
|
||||
res.end();
|
||||
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
||||
const session = url.searchParams.get('session');
|
||||
if (!session) {
|
||||
reject();
|
||||
} else {
|
||||
resolve(session);
|
||||
}
|
||||
}).listen(5710, 'localhost');
|
||||
|
||||
return sessionPromise.finally(() => {
|
||||
}).finally(() => {
|
||||
server.closeAllConnections();
|
||||
server.close();
|
||||
});
|
||||
|
||||
return { url: serverUrl, promise: sessionPromise };
|
||||
}
|
||||
|
||||
export async function cmd({ flags }: { config: AstroConfig; flags: Arguments }) {
|
||||
let session = flags.session;
|
||||
const loginUrl = getAstroStudioUrl() + '/auth/cli';
|
||||
|
||||
if (!session) {
|
||||
console.log(`Opening ${cyan(loginUrl)} in your browser...`);
|
||||
const { url, promise } = await createServer();
|
||||
const loginUrl = getAstroStudioUrl() + '/auth/cli/login?returnTo=' + encodeURIComponent(url);
|
||||
console.log(`Opening the following URL in your browser...`);
|
||||
console.log(cyan(loginUrl));
|
||||
console.log(`If something goes wrong, copy-and-paste the URL into your browser.`);
|
||||
open(loginUrl);
|
||||
const spinner = ora('Waiting for confirmation...');
|
||||
session = await serveAndResolveSession();
|
||||
session = await promise;
|
||||
spinner.succeed('Successfully logged in!');
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,17 @@ export async function cli({ flags, config }: { flags: Arguments; config: AstroCo
|
|||
// are also handled by this package, so first check if this is a db command.
|
||||
const command = args[2] === 'db' ? args[3] : args[2];
|
||||
|
||||
switch (command) {
|
||||
case 'login': {
|
||||
const { cmd } = await import('./commands/login/index.js');
|
||||
return await cmd({ config, flags });
|
||||
}
|
||||
case 'logout': {
|
||||
const { cmd } = await import('./commands/logout/index.js');
|
||||
return await cmd({ config, flags });
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.db?.studio) {
|
||||
console.log(STUDIO_CONFIG_MISSING_CLI_ERROR);
|
||||
process.exit(1);
|
||||
|
@ -31,14 +42,6 @@ export async function cli({ flags, config }: { flags: Arguments; config: AstroCo
|
|||
const { cmd } = await import('./commands/verify/index.js');
|
||||
return await cmd({ config, flags });
|
||||
}
|
||||
case 'login': {
|
||||
const { cmd } = await import('./commands/login/index.js');
|
||||
return await cmd({ config, flags });
|
||||
}
|
||||
case 'logout': {
|
||||
const { cmd } = await import('./commands/logout/index.js');
|
||||
return await cmd({ config, flags });
|
||||
}
|
||||
case 'link': {
|
||||
const { cmd } = await import('./commands/link/index.js');
|
||||
return await cmd({ config, flags });
|
||||
|
|
|
@ -3805,6 +3805,9 @@ importers:
|
|||
'@libsql/client':
|
||||
specifier: ^0.4.3
|
||||
version: 0.4.3
|
||||
async-listen:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1
|
||||
deep-diff:
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2
|
||||
|
@ -8806,6 +8809,11 @@ packages:
|
|||
ultrahtml: 0.1.3
|
||||
dev: false
|
||||
|
||||
/async-listen@3.0.1:
|
||||
resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
|
||||
/async-sema@3.1.1:
|
||||
resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==}
|
||||
dev: false
|
||||
|
|
Loading…
Reference in a new issue