Skip to content

Commit

Permalink
Merge branch 'auth-token-ui'
Browse files Browse the repository at this point in the history
  • Loading branch information
jonlamb-gh committed Nov 30, 2023
2 parents 46d4801 + dbde427 commit dccc063
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 28 deletions.
36 changes: 12 additions & 24 deletions vscode/src/cliConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
* Access to configuration and state from the Modality CLI's view of the world.
*/

import * as path from "path";
import * as os from "os";
import * as fs from "fs";
import * as vscode from "vscode";
import * as util from "util";
import * as child_process from "child_process";
Expand Down Expand Up @@ -78,15 +75,22 @@ export async function activeSegments(): Promise<api.WorkspaceSegmentMetadata[]>
}

/** Read the modality CLI's auth token. */
export function userAuthToken(): string | null {
const authTokenPath = path.join(cliConfigDir(), ".user_auth_token");
if (fs.statSync(authTokenPath)) {
return fs.readFileSync(authTokenPath, "utf8");
} else {
export async function userAuthToken(): Promise<string | null> {
const modality = toolPath("modality");
try {
const res = await execFile(modality, ["user", "auth-token", "--format", "json"], { encoding: "utf8" });
return JSON.parse(res.stdout).auth_token;
} catch (error) {
return null;
}
}

/** Set the modality CLI's auth token. */
export async function setUserAuthToken(authToken: string) {
const modality = toolPath("modality");
await execFile(modality, ["user", "auth-token", "--format", "json", "--use", authToken], { encoding: "utf8" });
}

/**
* Get the backend URL being used by the modality cli. Remove any trailing slash or api version.
*/
Expand Down Expand Up @@ -139,19 +143,3 @@ export async function allowInsecureHttps(): Promise<boolean | null> {
}
return res_json.insecure;
}

/**
* Get the user-specific modality_cli config dir, for the platform
*/
function cliConfigDir(): string {
let appConfigDir: string;
if (os.platform() === "win32") {
// TODO is this right for what we do on windows?
appConfigDir = process.env.APPDATA;
} else if (os.platform() === "darwin") {
appConfigDir = path.join(os.homedir(), "Library", "Application Support");
} else {
appConfigDir = path.join(os.homedir(), ".config");
}
return path.join(appConfigDir, "modality_cli");
}
6 changes: 3 additions & 3 deletions vscode/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import * as fs from "fs";
* The auth token that should be used to access the modality API, both directly
* and via the CLI.
*/
export function userAuthToken(): string | null {
export async function userAuthToken(): Promise<string | null> {
const auxonConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("auxon");
const vscodeAuthToken = auxonConfig.get<null | string>("authToken");
if (vscodeAuthToken) {
return vscodeAuthToken.trim();
}

const cliAuthToken = cliConfig.userAuthToken();
const cliAuthToken = await cliConfig.userAuthToken();
if (cliAuthToken) {
return cliAuthToken.trim();
}
Expand Down Expand Up @@ -85,7 +85,7 @@ export async function allowInsecureHttps(): Promise<boolean> {
*/
export async function toolEnv(): Promise<Record<string, string>> {
const env: Record<string, string> = {
MODALITY_AUTH_TOKEN: userAuthToken(),
MODALITY_AUTH_TOKEN: await userAuthToken(),
// TODO implement this in the CLI
MODALITY_ALLOW_INSECURE_TLS: (await allowInsecureHttps()).toString(),
MODALITY_URL: (await modalityUrlV1()).toString(),
Expand Down
19 changes: 18 additions & 1 deletion vscode/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as vscode from "vscode";
import { LanguageClient } from "vscode-languageclient/node";

import * as cliConfig from "./cliConfig";
import * as user from "./user";
import * as api from "./modalityApi";
import * as workspaces from "./workspaces";
import * as segments from "./segments";
Expand All @@ -21,11 +23,26 @@ let lspClient: LanguageClient;

export async function activate(context: vscode.ExtensionContext) {
log = vscode.window.createOutputChannel("Auxon SpeQTr");

// If this is a fresh install, prompt for new first user creation
await user.handleNewUserCreation();

lspClient = await lsp.activateLspClient(context);

const apiUrl = await config.modalityUrl();
const token = config.userAuthToken();
const allowInsecure = await config.allowInsecureHttps();
let token = await config.userAuthToken();

// We can't do anything without an auth token
while (!token) {
const userSuppliedAuthToken = await user.promptForValidAuthToken();
if (userSuppliedAuthToken) {
// Already validated in the input box
cliConfig.setUserAuthToken(userSuppliedAuthToken);
token = userSuppliedAuthToken;
}
}

const apiClient = new api.Client(apiUrl.toString(), token, allowInsecure);

terminalLinkProvider.register(context);
Expand Down
74 changes: 74 additions & 0 deletions vscode/src/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as util from "util";
import * as vscode from "vscode";
import * as child_process from "child_process";
import { toolPath } from "./config";

const execFile = util.promisify(child_process.execFile);

/**
* Create a new default user if no users exist (fresh modality install).
*/
export async function handleNewUserCreation() {
const numUsers = await numberOfModalityUsers();
if (numUsers == 0) {
const title = "Looks like this is a fresh install. Would you like to create a default user?";
const placeHolder = "user name";
const newUser = await vscode.window.showInputBox({ title, placeHolder });
if (newUser) {
await createAndUseNewUser(newUser);
}
}
}

/**
* Prompt for an auth token, returning it if the user provided a valid one.
*/
export async function promptForValidAuthToken(): Promise<string | null> {
const title = "An auth token is required to use the Auxon extension. Enter the auth token to use.";
const placeHolder = "auth token";
const validateInput = async (text) => {
if (await validateUserAuthToken(text)) {
return null;
} else {
return "Not a valid auth token";
}
};
const userSuppliedAuthToken = await vscode.window.showInputBox({ title, placeHolder, validateInput });
if (userSuppliedAuthToken) {
return userSuppliedAuthToken;
} else {
return null;
}
}

/**
* Get the number of users from 'modality user list'.
*/
async function numberOfModalityUsers(): Promise<number> {
const modality = toolPath("modality");
const res = await execFile(modality, ["user", "list", "--format", "json"], { encoding: "utf8" });
return JSON.parse(res.stdout).users.length as number;
}

/**
* Create and use a new user.
*/
async function createAndUseNewUser(userName: string) {
const modality = toolPath("modality");
await execFile(modality, ["user", "create", "--use", "--format", "json", userName], { encoding: "utf8" });
}

/**
* Check if the auth token is valid.
*/
async function validateUserAuthToken(authToken: string): Promise<boolean> {
const modality = toolPath("modality");
try {
const res = await execFile(modality, ["user", "inspect-auth-token", "--format", "json", authToken], {
encoding: "utf8",
});
return "user_name" in JSON.parse(res.stdout);
} catch (e) {
return false;
}
}

0 comments on commit dccc063

Please sign in to comment.