From ebb166ddcba75a88538aecb5e41534cbe5649637 Mon Sep 17 00:00:00 2001 From: Kevin Gilpin Date: Thu, 30 Nov 2023 14:57:16 -0500 Subject: [PATCH 1/4] feat: AppMap: Enter License Key Command to enter email address and license key directly. --- package.json | 12 ++-- .../appmapServerAuthenticationProvider.ts | 46 ++++++++++-- src/extension.ts | 4 +- src/uri/appmapServerAuthenticationHandler.ts | 24 ++++--- yarn.lock | 71 ++++++++++++++----- 5 files changed, 116 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index b9fc9379..0a8ffca8 100644 --- a/package.json +++ b/package.json @@ -193,6 +193,10 @@ "command": "appmap.logout", "title": "AppMap: Logout" }, + { + "command": "appmap.enterLicenseKey", + "title": "AppMap: Enter License Key" + }, { "command": "appmap.updateAppMapTestConfig", "title": "AppMap: Add AppMap Test Configuration" @@ -464,7 +468,7 @@ "mocha-suppress-logs": "^0.3.1", "mockery": "^2.1.0", "node-libs-browser": "^2.2.1", - "openapi-types": "^11.0.1", + "openapi-types": "^12.1.3", "prettier": "^2.8.4", "prettier-eslint": "^12.0.0", "project-root-directory": "^1.0.3", @@ -485,12 +489,12 @@ }, "dependencies": { "@appland/appmap": "^3.80.2", - "@appland/client": "^1.7.0", + "@appland/client": "^1.9.0", "@appland/components": "^3.13.2", "@appland/diagrams": "^1.7.0", - "@appland/models": "^2.6.3", + "@appland/models": "^2.9.0", "@appland/scanner": "^1.83.0", - "@appland/sequence-diagram": "^1.8.0", + "@appland/sequence-diagram": "^1.11.0", "@yarnpkg/parsers": "^3.0.0-rc.45", "bent": "^7.3.12", "bootstrap": "^4.5.3", diff --git a/src/authentication/appmapServerAuthenticationProvider.ts b/src/authentication/appmapServerAuthenticationProvider.ts index 0bb8b5b0..9a93b364 100644 --- a/src/authentication/appmapServerAuthenticationProvider.ts +++ b/src/authentication/appmapServerAuthenticationProvider.ts @@ -9,6 +9,8 @@ import { DEBUG_EXCEPTION, Telemetry } from '../telemetry'; import ErrorCode from '../telemetry/definitions/errorCodes'; import { AUTHN_PROVIDER_NAME } from './index'; import { debuglog } from 'node:util'; +import { LicenseKey } from '@appland/client'; +import { base64UrlDecode } from '@appland/models'; const debug = debuglog('appmap-vscode:AppMapServerAuthenticationProvider'); @@ -20,6 +22,31 @@ enum AuthFailure { SignInAttempt = 'SignInAttempt', } +function enterLicenseKeyCommand(authProvider: AppMapServerAuthenticationProvider): { + dispose(): any; +} { + const command = vscode.commands.registerCommand('appmap.enterLicenseKey', async () => { + const licenseKey = await vscode.window.showInputBox({ + title: `Enter your AppMap license key`, + ignoreFocusOut: true, + }); + if (!licenseKey) return; + + if (!(await LicenseKey.check(licenseKey))) { + vscode.window.showErrorMessage('Invalid license key'); + return; + } + + const decoded = base64UrlDecode(licenseKey); + const tokens = decoded.split(':'); + const email = tokens.slice(0, tokens.length - 1).join(':'); + + const session = AppMapServerAuthenticationHandler.buildSession(email, licenseKey); + authProvider.setSession(session); + }); + return command; +} + export default class AppMapServerAuthenticationProvider implements vscode.AuthenticationProvider { private _onDidChangeSessions = new vscode.EventEmitter(); @@ -40,6 +67,7 @@ export default class AppMapServerAuthenticationProvider implements vscode.Authen { supportsMultipleAccounts: false } ); context.subscriptions.push(registration); + context.subscriptions.push(enterLicenseKeyCommand(provider)); return provider; } @@ -67,19 +95,23 @@ export default class AppMapServerAuthenticationProvider implements vscode.Authen return this.session ? [this.session] : []; } - async createSession(): Promise { - this.session = await this.performSignIn(); - debug('createSession(); session %savailable', this.session ? '' : 'not '); - - if (!this.session) throw new Error('AppMap authentication was not completed'); - + setSession(session: vscode.AuthenticationSession): void { + this.session = session; this.context.secrets .store(APPMAP_SERVER_SESSION_KEY, JSON.stringify(this.session)) .then(undefined, (err) => console.warn('error storing session key: %s', err)); this._onDidChangeSessions.fire({ added: [this.session], removed: [], changed: [] }); + } + + async createSession(): Promise { + const session = await this.performSignIn(); + debug('createSession(); session %savailable', session ? '' : 'not '); + + if (!session) throw new Error('AppMap authentication was not completed'); - return this.session; + this.setSession(session); + return session; } async removeSession(): Promise { diff --git a/src/extension.ts b/src/extension.ts index 24bda976..5677d931 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -170,8 +170,8 @@ export async function activate(context: vscode.ExtensionContext): Promise { - if (e.added) vscode.window.showInformationMessage('Logged in to AppMap'); - if (e.removed) vscode.window.showInformationMessage('Logged out of AppMap'); + if (e.added?.length) vscode.window.showInformationMessage('Logged in to AppMap'); + if (e.removed?.length) vscode.window.showInformationMessage('Logged out of AppMap'); AppMapServerConfiguration.updateAppMapClientConfiguration(); }); vscode.commands.registerCommand('appmap.login', async () => { diff --git a/src/uri/appmapServerAuthenticationHandler.ts b/src/uri/appmapServerAuthenticationHandler.ts index 7a92c090..a9c7ebe5 100644 --- a/src/uri/appmapServerAuthenticationHandler.ts +++ b/src/uri/appmapServerAuthenticationHandler.ts @@ -23,24 +23,30 @@ export default class AppMapServerAuthenticationHandler implements RequestHandler return; } - const apiKeyParam = queryParams.get('api_key'); - if (!apiKeyParam) { + const licenseKeyParam = queryParams.get('api_key'); + if (!licenseKeyParam) { this._onError.fire(new Error('missing parameter "api_key"')); return; } - const buffer = Buffer.from(apiKeyParam, 'base64'); + const buffer = Buffer.from(licenseKeyParam, 'base64'); const [email] = buffer.toString('utf-8').split(':'); - this._onCreateSession.fire({ - id: email, - account: { id: email, label: email }, - scopes: ['default'], - accessToken: apiKeyParam, - }); + this._onCreateSession.fire( + AppMapServerAuthenticationHandler.buildSession(email, licenseKeyParam) + ); } dispose(): void { // do nothing, we have nothing to dispose } + + static buildSession(email: string, licenseKey: string): vscode.AuthenticationSession { + return { + id: email, + account: { id: email, label: email }, + scopes: ['default'], + accessToken: licenseKey, + }; + } } diff --git a/yarn.lock b/yarn.lock index b0809be5..26c7e84a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -107,7 +107,7 @@ __metadata: languageName: node linkType: hard -"@appland/client@npm:^1.5.0, @appland/client@npm:^1.7.0, @appland/client@npm:^1.8.0": +"@appland/client@npm:^1.5.0, @appland/client@npm:^1.8.0": version: 1.8.0 resolution: "@appland/client@npm:1.8.0" dependencies: @@ -119,6 +119,18 @@ __metadata: languageName: node linkType: hard +"@appland/client@npm:^1.9.0": + version: 1.9.0 + resolution: "@appland/client@npm:1.9.0" + dependencies: + "@appland/models": 2.9.0 + "@types/form-data": ^2.5.0 + form-data: ^4.0.0 + js-yaml: ^4.1.0 + checksum: 86402259f2fb4a2c4f83776b8dd1db643af2f102583bd3d616f86c2868328562f67bf47047eaa38f5c8671ca48890531c59ed30c97322ef04a4b3d4604123f60 + languageName: node + linkType: hard + "@appland/components@npm:^2": version: 2.61.0 resolution: "@appland/components@npm:2.61.0" @@ -184,6 +196,16 @@ __metadata: languageName: node linkType: hard +"@appland/models@npm:2.9.0, @appland/models@npm:^2.9.0": + version: 2.9.0 + resolution: "@appland/models@npm:2.9.0" + dependencies: + "@appland/sql-parser": ^1.5.0 + crypto-js: ^4.0.0 + checksum: d5faf24f8f4b26481494b3fc942ac6bba4c78d2211581b5eab9e21c60c2ef083bbdc43b7acd43dc9ff864e6b6b735914648885d5e00fee0c727836d3ef3cca06 + languageName: node + linkType: hard + "@appland/models@npm:^2.7.0": version: 2.7.0 resolution: "@appland/models@npm:2.7.0" @@ -204,6 +226,16 @@ __metadata: languageName: node linkType: hard +"@appland/openapi@npm:^1.7.0": + version: 1.7.0 + resolution: "@appland/openapi@npm:1.7.0" + dependencies: + "@appland/models": ^2.6.3 + js-yaml: ^4.1.0 + checksum: 50a1283c7108d8772c9497d5b77c5bbbfba2b22c6d465d7e878f6e5b47ee31d86018858c86612001573edbcfab038bd0cf21a2313ad0962417a1db12ee0cbb35 + languageName: node + linkType: hard + "@appland/scanner@npm:^1.83.0": version: 1.83.0 resolution: "@appland/scanner@npm:1.83.0" @@ -241,29 +273,30 @@ __metadata: languageName: node linkType: hard -"@appland/sequence-diagram@npm:^1.6.1, @appland/sequence-diagram@npm:^1.7.0": - version: 1.7.0 - resolution: "@appland/sequence-diagram@npm:1.7.0" +"@appland/sequence-diagram@npm:^1.11.0": + version: 1.11.0 + resolution: "@appland/sequence-diagram@npm:1.11.0" dependencies: - "@appland/models": ^2.6.3 - "@appland/openapi": ^1.4.3 + "@appland/models": ^2.7.0 + "@appland/openapi": ^1.7.0 "@datastructures-js/priority-queue": ^6.1.3 crypto-js: ^4.1.1 diff: ^5.1.0 - checksum: 033d425f1a29de1dd531ae67968e7b495f6d7f2f477f63ef6631de9e278bdb41393394def03624d23b9d247184d5f746489a1c7dbeee379d3848acfeeb4ec0ba + lru-cache: 6.0.0 + checksum: 1bcc27f311e0024ecb4bb816b9886c4954ba87ba66f913050587844ab1aca048e2b13313e8d277ed4af99f900c93b40b76c4cdcdd40e4fe3b67d75603c0ba5b3 languageName: node linkType: hard -"@appland/sequence-diagram@npm:^1.8.0": - version: 1.8.0 - resolution: "@appland/sequence-diagram@npm:1.8.0" +"@appland/sequence-diagram@npm:^1.6.1, @appland/sequence-diagram@npm:^1.7.0": + version: 1.7.0 + resolution: "@appland/sequence-diagram@npm:1.7.0" dependencies: "@appland/models": ^2.6.3 "@appland/openapi": ^1.4.3 "@datastructures-js/priority-queue": ^6.1.3 crypto-js: ^4.1.1 diff: ^5.1.0 - checksum: 143e78ec50f26d0dd4ddb7b57b8fdb89043209949290a2262766c39a1489129adb55de352874f975c7d332e6e32a294da4367ca134a210bd799231f23262463a + checksum: 033d425f1a29de1dd531ae67968e7b495f6d7f2f477f63ef6631de9e278bdb41393394def03624d23b9d247184d5f746489a1c7dbeee379d3848acfeeb4ec0ba languageName: node linkType: hard @@ -2773,12 +2806,12 @@ __metadata: resolution: "appmap@workspace:." dependencies: "@appland/appmap": ^3.80.2 - "@appland/client": ^1.7.0 + "@appland/client": ^1.9.0 "@appland/components": ^3.13.2 "@appland/diagrams": ^1.7.0 - "@appland/models": ^2.6.3 + "@appland/models": ^2.9.0 "@appland/scanner": ^1.83.0 - "@appland/sequence-diagram": ^1.8.0 + "@appland/sequence-diagram": ^1.11.0 "@playwright/test": ^1.22.2 "@semantic-release/changelog": ^5.0.1 "@semantic-release/exec": ^5.0.0 @@ -2829,7 +2862,7 @@ __metadata: mocha-suppress-logs: ^0.3.1 mockery: ^2.1.0 node-libs-browser: ^2.2.1 - openapi-types: ^11.0.1 + openapi-types: ^12.1.3 popper.js: ^1.16.1 prettier: ^2.8.4 prettier-eslint: ^12.0.0 @@ -9872,10 +9905,10 @@ __metadata: languageName: node linkType: hard -"openapi-types@npm:^11.0.1": - version: 11.0.1 - resolution: "openapi-types@npm:11.0.1" - checksum: 182c5b28199a0d030bf5f64b9c23f65dc800cdc845ae09c40aa5e03b862634a02526d5092af53bf853514af778ee2f36dead741e0521e01f944cf7f50927e14e +"openapi-types@npm:^12.1.3": + version: 12.1.3 + resolution: "openapi-types@npm:12.1.3" + checksum: 7fa5547f87a58d2aa0eba6e91d396f42d7d31bc3ae140e61b5d60b47d2fd068b48776f42407d5a8da7280cf31195aa128c2fc285e8bb871d1105edee5647a0bb languageName: node linkType: hard From 122ab62ea936eac6812730c9ed24c061a4b99756 Mon Sep 17 00:00:00 2001 From: Kevin Gilpin Date: Thu, 30 Nov 2023 15:27:01 -0500 Subject: [PATCH 2/4] refactor: Remove deprecated imports --- src/services/findingLocation.ts | 2 +- src/services/findingsIndex.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/findingLocation.ts b/src/services/findingLocation.ts index 4a3d48b5..520afcff 100644 --- a/src/services/findingLocation.ts +++ b/src/services/findingLocation.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { Finding } from '@appland/scanner/built/cli'; +import { Finding } from '@appland/scanner'; export type FindingLocation = { finding: Finding; diff --git a/src/services/findingsIndex.ts b/src/services/findingsIndex.ts index ff8ffb2f..5578cb8b 100644 --- a/src/services/findingsIndex.ts +++ b/src/services/findingsIndex.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { Finding } from '@appland/scanner/built/cli'; +import { Finding } from '@appland/scanner'; import { ResolvedFinding } from './resolvedFinding'; import { debuglog, promisify } from 'util'; import { readFile } from 'fs'; From 257a78efd9a0d6cf73dad1b843169fb62785021a Mon Sep 17 00:00:00 2001 From: Kevin Gilpin Date: Thu, 30 Nov 2023 15:28:10 -0500 Subject: [PATCH 3/4] chore: Code format --- src/configuration/extensionSettings.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/configuration/extensionSettings.ts b/src/configuration/extensionSettings.ts index 8a165541..88939f51 100644 --- a/src/configuration/extensionSettings.ts +++ b/src/configuration/extensionSettings.ts @@ -2,9 +2,7 @@ import * as vscode from 'vscode'; export default class ExtensionSettings { public static get appMapServerURL(): vscode.Uri { - const configUrl: string = vscode.workspace - .getConfiguration('appMap') - .get('applandUrl') as string; + const configUrl = vscode.workspace.getConfiguration('appMap').get('applandUrl') as string; return vscode.Uri.parse(configUrl); } From cb583ec34380d78bfc0a0ab6e045d389ed8535b4 Mon Sep 17 00:00:00 2001 From: Kevin Gilpin Date: Thu, 30 Nov 2023 15:28:25 -0500 Subject: [PATCH 4/4] feat: Update default AppMap server URL --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a8ffca8..c7c7d580 100644 --- a/package.json +++ b/package.json @@ -215,7 +215,7 @@ "properties": { "appMap.applandUrl": { "type": "string", - "default": "https://app.land", + "default": "https://getappmap.com", "description": "URL of an AppLand cloud instance for AppMap storage" }, "appMap.viewConfiguration": {