Allow config-specific flags

pull/285/head
Kelvin Schoofs 4 years ago
parent cdf0f997e1
commit 9de1d03422

@ -342,17 +342,8 @@ vscode.workspace.onDidChangeConfiguration(async (e) => {
});
loadConfigs();
export type FlagValue = string | boolean | null;
export type FlagCombo = [value: FlagValue, origin: string];
export const DEFAULT_FLAGS: string[] = ['-DF-GE'];
let cachedFlags: Record<string, FlagCombo> = {};
function calculateFlags(): Record<string, FlagCombo> {
const flags: Record<string, FlagCombo> = {};
const config = vscode.workspace.getConfiguration('sshfs').inspect<string[]>('flags');
if (!config) throw new Error(`Could not inspect "sshfs.flags" config field`);
function parseList(list: string[] | undefined, origin: string) {
if (list === undefined) return;
function parseFlagList(list: string[] | undefined, origin: string): Record<string, FlagCombo> {
if (list === undefined) return {};
if (!Array.isArray(list)) throw new Error(`Expected string array for flags, but got: ${list}`);
const scope: Record<string, FlagCombo> = {};
for (const flag of list) {
@ -373,19 +364,27 @@ function calculateFlags(): Record<string, FlagCombo> {
if (name in scope) continue;
scope[name] = [value, origin];
}
// Override if necessary (since workspace settings come after global settings)
// Per "location", we still ignore duplicate flag names
Object.assign(flags, scope);
}
parseList(DEFAULT_FLAGS, 'Built-in Default');
parseList(config.defaultValue, 'Default Settings');
return scope;
}
export type FlagValue = string | boolean | null;
export type FlagCombo = [value: FlagValue, origin: string];
export const DEFAULT_FLAGS: string[] = ['-DF-GE'];
let cachedFlags: Record<string, FlagCombo> = {};
function calculateFlags(): Record<string, FlagCombo> {
const flags: Record<string, FlagCombo> = {};
const config = vscode.workspace.getConfiguration('sshfs').inspect<string[]>('flags');
if (!config) throw new Error(`Could not inspect "sshfs.flags" config field`);
const applyList = (list: string[] | undefined, origin: string) => Object.assign(flags, parseFlagList(list, origin));
applyList(DEFAULT_FLAGS, 'Built-in Default');
applyList(config.defaultValue, 'Default Settings');
// Electron v11 crashes for DiffieHellman GroupExchange, although it's fixed in 11.3.0
if ((process.versions as { electron?: string }).electron?.match(/^11\.(0|1|2)\./)) {
parseList(['+DF-GE'], 'Fix for issue #239')
applyList(['+DF-GE'], 'Fix for issue #239')
}
parseList(config.globalValue, 'Global Settings');
parseList(config.workspaceValue, 'Workspace Settings');
parseList(config.workspaceFolderValue, 'WorkspaceFolder Settings');
applyList(config.globalValue, 'Global Settings');
applyList(config.workspaceValue, 'Workspace Settings');
applyList(config.workspaceFolderValue, 'WorkspaceFolder Settings');
Logging.info(`Calculated config flags: ${JSON.stringify(flags)}`);
return cachedFlags = flags;
}
@ -395,8 +394,17 @@ vscode.workspace.onDidChangeConfiguration(event => {
});
calculateFlags();
/** Returns a cached version. Gets updated by ConfigurationChangeEvent events */
export function getFlags(): Record<string, FlagCombo> { return cachedFlags; }
/**
* Returns (a copy of the) global flags. Gets updated by ConfigurationChangeEvent events.
* In case `flags` is given, flags specified in this array will override global ones in the returned result.
* @param flags An optional array of flags to check before the global ones
*/
export function getFlags(flags?: string[]): Record<string, FlagCombo> {
return {
...cachedFlags,
...parseFlagList(flags, 'Override'),
};
}
/**
* Checks the `sshfs.flags` config (overridable by e.g. workspace settings).
@ -411,9 +419,10 @@ export function getFlags(): Record<string, FlagCombo> { return cachedFlags; }
* For `undefined`, an actual `undefined` is returned. For all other cases, a FlagCombo
* is returned, e.g. "NAME" returns `[null, "someOrigin"]` and `"+F"` returns `[true, "someOrigin"]`
* @param target The name of the flag to look for
* @param flags An optional array of flags to check before the global ones
*/
export function getFlag(target: string): FlagCombo | undefined {
return calculateFlags()[target.toLowerCase()];
export function getFlag(target: string, flags?: string[]): FlagCombo | undefined {
return getFlags(flags)[target.toLowerCase()];
}
/**
@ -428,10 +437,11 @@ export function getFlag(target: string): FlagCombo | undefined {
* - All other strings result in an error
* @param target The name of the flag to look for
* @param defaultValue The value to return when no flag with the given name is present
* @param flags An optional array of flags to check before the global ones
* @returns The matching FlagCombo or `[missingValue, 'missing']` instead
*/
export function getFlagBoolean(target: string, missingValue: boolean): FlagCombo {
const combo = getFlag(target);
export function getFlagBoolean(target: string, missingValue: boolean, flags?: string[]): FlagCombo {
const combo = getFlag(target, flags);
if (!combo) return [missingValue, 'missing'];
const [value, reason] = combo;
if (value == null) return [true, reason];

@ -253,13 +253,13 @@ export async function createSSH(config: FileSystemConfig, sock?: NodeJS.Readable
});
try {
const finalConfig: ConnectConfig = { ...config, sock, ...DEFAULT_CONFIG };
if (config.debug || getFlag('DEBUG_SSH2') !== undefined) {
if (config.debug || getFlag('DEBUG_SSH2', config.flags) !== undefined) {
const scope = Logging.scope(`ssh2(${config.name})`);
finalConfig.debug = (msg: string) => scope.debug(msg);
}
// Unless the flag 'DF-GE' is specified, disable DiffieHellman groupex algorithms (issue #239)
// Note: If the config already specifies a custom `algorithms.key`, ignore it (trust the user?)
const [flagV, flagR] = getFlagBoolean('DF-GE', false);
const [flagV, flagR] = getFlagBoolean('DF-GE', false, config.flags);
if (flagV) {
logging.info(`Flag "DF-GE" enabled due to '${flagR}', disabling DiffieHellman kex groupex algorithms`);
let kex: string[] = require('ssh2-streams/lib/constants').ALGORITHMS.KEX;

@ -104,6 +104,8 @@ export interface FileSystemConfig extends ConnectConfig {
newFileMode?: number | string;
/** Whether this config was created from an instant connection string. Enables fuzzy matching for e.g. PuTTY, config-by-host, ... */
instantConnection?: boolean;
/** List of special flags to enable/disable certain fixes/features. Flags are usually used for issues or beta testing. Flags can disappear/change anytime! */
flags?: string[];
/** Internal property saying where this config comes from. Undefined if this config is merged or something */
_location?: ConfigLocation;
/** Internal property keeping track of where this config comes from (including merges) */

Loading…
Cancel
Save