convex
Version:
Client for the Convex Cloud
224 lines (223 loc) • 7.86 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var login_exports = {};
__export(login_exports, {
checkAuthorization: () => checkAuthorization,
performLogin: () => performLogin
});
module.exports = __toCommonJS(login_exports);
var import_openid_client = require("openid-client");
var import_utils = require("./utils.js");
var import_open = __toESM(require("open"));
var import_chalk = __toESM(require("chalk"));
var import_config = require("./config.js");
var import__ = require("../../index.js");
var import_axios = __toESM(require("axios"));
var import_openid_client2 = require("openid-client");
var import_inquirer = __toESM(require("inquirer"));
var import_os = require("os");
var import_child_process = require("child_process");
const SCOPE = "openid email profile";
import_openid_client.custom.setHttpOptionsDefaults({
timeout: 1e4
});
async function writeGlobalConfig(ctx, config) {
const dirName = (0, import_utils.rootDirectory)();
ctx.fs.mkdir(dirName, { allowExisting: true });
const path = (0, import_utils.globalConfigPath)();
try {
ctx.fs.writeUtf8File(path, JSON.stringify(config));
} catch (err) {
console.log(
import_chalk.default.red(`Failed to write auth config to ${path} with error: ${err}`)
);
return await ctx.fatalError(1, "fs", err);
}
console.log(
import_chalk.default.green(`Successfully wrote your auth credentials to ${path}!`)
);
}
async function checkAuthorization(ctx) {
const header = await (0, import_utils.getAuthHeader)(ctx);
if (!header) {
return false;
}
try {
const resp = await import_axios.default.head(`${import_config.provisionHost}/api/${import__.version}/authorize`, {
headers: { Authorization: header },
validateStatus: (_) => true
});
return resp.status == 200;
} catch (e) {
console.log(import_chalk.default.gray(`Unexpected error when authorizing: ${e}`));
return false;
}
}
async function performDeviceAuthorization(ctx, auth0Client, shouldOpen) {
const handle = await auth0Client.deviceAuthorization({
scope: SCOPE,
audience: "https://console.convex.dev/api/"
});
const { verification_uri_complete, user_code, expires_in } = handle;
console.log(
`Visit ${verification_uri_complete} to finish logging in. You should see the following code which expires in ${expires_in % 60 === 0 ? `${expires_in / 60} minutes` : `${expires_in} seconds`}: ${user_code}`
);
if (shouldOpen) {
shouldOpen = (await import_inquirer.default.prompt([
{
name: "openBrowser",
message: `Open in browser?`,
type: "confirm",
default: true
}
])).openBrowser;
}
if (shouldOpen) {
console.log(
`Opening ${verification_uri_complete} in your browser to log in...`
);
try {
await (0, import_open.default)(verification_uri_complete);
} catch (err) {
console.log(import_chalk.default.red(`Unable to open browser.`));
console.log(
`Manually open ${verification_uri_complete} in your browser to log in.`
);
}
} else {
console.log(`Open ${verification_uri_complete} in your browser to log in.`);
}
try {
const tokens = await handle.poll();
if (typeof tokens.access_token == "string") {
return tokens.access_token;
} else {
throw Error("Access token is missing");
}
} catch (err) {
switch (err.error) {
case "access_denied":
console.error("Access denied.");
return await ctx.fatalError(1, err);
case "expired_token":
console.error("Device flow expired.");
return await ctx.fatalError(1, err);
default:
if (err instanceof import_openid_client.errors.OPError) {
console.error(
`Error = ${err.error}; error_description = ${err.error_description}`
);
} else {
console.error(`Login failed with error: ${err}`);
}
return await ctx.fatalError(1, err);
}
}
}
async function performPasswordAuthentication(ctx, issuer, clientId, username, password) {
const options = {
method: "POST",
url: new URL("/oauth/token", issuer).href,
headers: { "content-type": "application/x-www-form-urlencoded" },
data: new URLSearchParams({
grant_type: "password",
username,
password,
scope: SCOPE,
client_id: clientId,
audience: "https://console.convex.dev/api/"
})
};
try {
const response = await import_axios.default.request(options);
if (typeof response.data.access_token == "string") {
return response.data.access_token;
} else {
throw Error("Access token is missing");
}
} catch (err) {
console.log(`Password flow failed: ${err}`);
if (err.response) {
console.log(`${JSON.stringify(err.response.data)}`);
}
return await ctx.fatalError(1, err);
}
}
async function performLogin(ctx, overrideAuthUrl, overrideAuthClient, overrideAuthUsername, overrideAuthPassword, open2 = true, deviceNameOverride) {
let deviceName = deviceNameOverride ?? "";
if (!deviceName && process.platform == "darwin") {
try {
deviceName = (0, import_child_process.execSync)("scutil --get ComputerName").toString().trim();
} catch {
}
}
if (!deviceName) {
deviceName = (0, import_os.hostname)();
}
if (process.stdin.isTTY && !deviceNameOverride) {
const answers = await import_inquirer.default.prompt([
{
type: "input",
name: "deviceName",
message: "Enter a name for the device being authorized:",
default: deviceName
}
]);
deviceName = answers.deviceName;
}
const issuer = overrideAuthUrl ?? "https://auth.convex.dev";
const auth0 = await import_openid_client2.Issuer.discover(issuer);
const clientId = overrideAuthClient ?? "HFtA247jp9iNs08NTLIB7JsNPMmRIyfi";
const auth0Client = new auth0.Client({
client_id: clientId,
token_endpoint_auth_method: "none",
id_token_signed_response_alg: "RS256"
});
let accessToken;
if (overrideAuthUsername && overrideAuthPassword) {
accessToken = await performPasswordAuthentication(
ctx,
issuer,
clientId,
overrideAuthUsername,
overrideAuthPassword
);
} else {
accessToken = await performDeviceAuthorization(ctx, auth0Client, open2);
}
const authorizeArgs = {
authnToken: accessToken,
deviceName
};
const data = await (0, import_utils.bigBrainAPI)(ctx, "POST", "authorize", authorizeArgs);
const globalConfig = { accessToken: data.accessToken };
try {
await writeGlobalConfig(ctx, globalConfig);
} catch (err) {
return await ctx.fatalError(1, "fs", err);
}
console.log(import_chalk.default.green("Successfully logged in and authorized device"));
}
//# sourceMappingURL=login.js.map