-
Notifications
You must be signed in to change notification settings - Fork 42
Trust prompting #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trust prompting #193
Changes from 7 commits
9e3f7c8
b1136b5
58bedc7
8761b45
c59a7cf
3b815d2
2273800
be528ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import { window } from 'vscode'; | ||
| import { traceInfo } from '../common/logging'; | ||
| import { getCallingExtension } from '../common/utils/frameUtils'; | ||
| import { getConfiguration } from '../common/workspace.apis'; | ||
| import { SettingsPackageTrust, promptForInstallPermissions, promptForAlwaysAsk } from './utils'; | ||
|
|
||
| export enum InstallPermissionEnum { | ||
| AlwaysAllow = 'alwaysAllow', | ||
| AlwaysAsk = 'alwaysAsk', | ||
| InstallNoConfigure = 'installNoConfigure', | ||
| Cancel = 'cancel', | ||
| } | ||
|
|
||
| export enum SimpleResponseEnum { | ||
| YesInstall = 'yesInstall', | ||
| NoInstall = 'noInstall', | ||
| Cancel = 'cancel', | ||
| } | ||
| export async function packageManagementFlow(packages: string[]): Promise<void> { | ||
| // what does it mean to return, will we tell the calling extension about it? | ||
| //check to see if pkg was already installed? | ||
| const callingExtension = getCallingExtension(); | ||
| traceInfo(`Python API: Installing packages for extension: '${callingExtension}'`); | ||
| const config = getConfiguration('python-envs'); | ||
| let extPkgTrustConfig: SettingsPackageTrust | undefined = | ||
| config.get<SettingsPackageTrust>('allowAutoPackageManagement'); | ||
| let callingExtensionTrustLevel; | ||
| let isConfigured = true; | ||
| if (extPkgTrustConfig === undefined) { | ||
| // TODO:s THIS DOESN'T WORK | ||
| // no package trust config, default to alwaysAsk | ||
| callingExtensionTrustLevel = InstallPermissionEnum.AlwaysAsk; | ||
| isConfigured = false; | ||
| } else { | ||
| // check for package trust settings | ||
| callingExtensionTrustLevel = extPkgTrustConfig[callingExtension]; | ||
| if (callingExtensionTrustLevel === undefined) { | ||
| // no specific package trust settings, checking wildcard in config | ||
| callingExtensionTrustLevel = extPkgTrustConfig['*']; | ||
| if (callingExtensionTrustLevel === undefined) { | ||
| // no wildcard in config, default to alwaysAsk | ||
| callingExtensionTrustLevel = InstallPermissionEnum.AlwaysAsk; | ||
| isConfigured = false; | ||
| } | ||
| } | ||
| } | ||
| traceInfo(`package trust settings for '${callingExtension}' is ${callingExtensionTrustLevel}`); | ||
|
|
||
| if (!isConfigured) { | ||
| // calling extension has no config, user has no wildcard setup | ||
| // prompt user to "alwaysAsk" or "alwaysAllow" | ||
| const selectedOption = await promptForInstallPermissions(callingExtension, packages.join(', ')); | ||
| if (selectedOption === InstallPermissionEnum.Cancel) { | ||
| // user cancelled the prompt, exit | ||
| window.showErrorMessage(`Installation of ${packages.join(', ')} was canceled by the user.`); | ||
| return Promise.reject('User cancelled the package installation.'); | ||
| } | ||
| if (selectedOption !== InstallPermissionEnum.InstallNoConfigure) { | ||
| // meaning the user selected "alwaysAsk" or "alwaysAllow", update the config | ||
| const newExtTrustConfig = { ...extPkgTrustConfig, [callingExtension]: selectedOption }; | ||
| config.update('allowAutoPackageManagement', newExtTrustConfig, true); | ||
| } | ||
| } else { | ||
| // user has already configured package trust settings for this extension | ||
| if (callingExtensionTrustLevel === InstallPermissionEnum.AlwaysAsk) { | ||
| traceInfo('Installation is pending user confirmation due to permission settings.'); | ||
| // prompt user to allow or deny package installation | ||
| const simpleResponse = await promptForAlwaysAsk(callingExtension, packages.join(', ')); | ||
| if (simpleResponse === SimpleResponseEnum.NoInstall || simpleResponse === SimpleResponseEnum.Cancel) { | ||
| // user cancelled the prompt, exit | ||
| window.showErrorMessage(`Installation of ${packages.join(', ')} was canceled by the user.`); | ||
| return Promise.reject('User cancelled the package installation.'); | ||
| } | ||
| } | ||
| // if callingExtensionTrustLevel is 'alwaysAllow' just continue to install | ||
| } | ||
| // actually install the packages | ||
| return Promise.resolve(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import { window } from 'vscode'; | ||
| import { InstallPermissionEnum, SimpleResponseEnum } from './packageManagement'; | ||
|
|
||
| export type SettingsPackageTrust = { | ||
| [key: string]: InstallPermissionEnum.AlwaysAllow | InstallPermissionEnum.AlwaysAsk; | ||
| }; | ||
|
|
||
| export const ALWAYS_ALLOW = 'Always allow installs'; | ||
| export const ALWAYS_ASK = 'Always ask before installing'; | ||
| export const INSTALL_NO_CONFIGURE = 'Install without configuring permissions'; | ||
|
|
||
| export const YES_INSTALL = 'Yes, Install'; | ||
| export const NO_INSTALL = 'Do Not Install'; | ||
|
|
||
| export function promptForInstallPermissions(extensionName: string, packages: string): Thenable<InstallPermissionEnum> { | ||
| return new Promise((resolve) => { | ||
| window | ||
| .showInformationMessage( | ||
| 'Would you like to set permissions for future package installs from the ' + extensionName + ' extension?', | ||
| { | ||
| detail: `package/s: "${packages}"`, | ||
| modal: true, | ||
| }, | ||
| ALWAYS_ASK, | ||
| ALWAYS_ALLOW, | ||
| INSTALL_NO_CONFIGURE, | ||
| ) | ||
| .then((selectedOption) => { | ||
| switch (selectedOption) { | ||
| case ALWAYS_ALLOW: | ||
| resolve(InstallPermissionEnum.AlwaysAllow); | ||
| break; | ||
| case ALWAYS_ASK: | ||
| resolve(InstallPermissionEnum.AlwaysAsk); | ||
| break; | ||
| case INSTALL_NO_CONFIGURE: | ||
| resolve(InstallPermissionEnum.InstallNoConfigure); | ||
| break; | ||
| default: | ||
| resolve(InstallPermissionEnum.Cancel); | ||
| break; | ||
| } | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| export function promptForAlwaysAsk(extensionName: string, packages: string): Thenable<string | undefined> { | ||
| return new Promise((resolve) => { | ||
| window | ||
| .showInformationMessage( | ||
| 'Do you want to install the following package/s from the ' + extensionName + ' extension?', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will we be referencing the package names in this message as well?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but if there are multiple then we may want to say something like
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added it in the detail:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see! I missed that part in the initial review |
||
| { | ||
| detail: `package/s: "${packages}"`, | ||
| modal: true, | ||
| }, | ||
| YES_INSTALL, | ||
| NO_INSTALL, | ||
| ) | ||
| .then((selectedOption) => { | ||
| switch (selectedOption) { | ||
| case YES_INSTALL: | ||
| resolve(SimpleResponseEnum.YesInstall); | ||
| break; | ||
| case NO_INSTALL: | ||
| resolve(SimpleResponseEnum.NoInstall); | ||
| break; | ||
| default: | ||
| resolve(SimpleResponseEnum.Cancel); | ||
| break; | ||
| } | ||
| }); | ||
| }); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.