0
Fork 0
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:
Fred K. Schott 2024-02-28 21:26:19 -08:00 committed by GitHub
parent e86b81a671
commit c2e7b9847e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 30 deletions

View file

@ -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",

View file

@ -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!');
}

View file

@ -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 });

View file

@ -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