mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Desktop: Fixes #7621: Certain plugins could create invalid settings, which could result in a crash
This commit is contained in:
parent
f7682d3da3
commit
dc5dc94ed5
@ -453,6 +453,12 @@ class ConfigScreenComponent extends React.Component<any, any> {
|
||||
inputStyle.marginBottom = subLabel.marginBottom;
|
||||
|
||||
const splitCmd = (cmdString: string) => {
|
||||
// Normally not necessary but certain plugins found a way to
|
||||
// set the set the value to "undefined", leading to a crash.
|
||||
// This is now fixed at the model level but to be sure we
|
||||
// check here too, to handle any already existing data.
|
||||
// https://github.com/laurent22/joplin/issues/7621
|
||||
if (!cmdString) cmdString = '';
|
||||
const path = pathUtils.extractExecutablePath(cmdString);
|
||||
const args = cmdString.substr(path.length + 1);
|
||||
return [pathUtils.unquotePath(path), args];
|
||||
|
@ -379,4 +379,19 @@ describe('models/Setting', function() {
|
||||
}
|
||||
});
|
||||
|
||||
test('values should not be undefined when they are set', async () => {
|
||||
Setting.setValue('locale', undefined);
|
||||
expect(Setting.value('locale')).toBe('');
|
||||
});
|
||||
|
||||
test('values should not be undefined when registering a setting', async () => {
|
||||
await Setting.registerSetting('myCustom', {
|
||||
public: true,
|
||||
value: undefined,
|
||||
type: Setting.TYPE_STRING,
|
||||
});
|
||||
|
||||
expect(Setting.value('myCustom')).toBe('');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -1740,31 +1740,45 @@ class Setting extends BaseModel {
|
||||
if (!key.match(/^[a-zA-Z0-9_\-.]+$/)) throw new Error(`Key must only contain characters /a-zA-Z0-9_-./ : ${key}`);
|
||||
}
|
||||
|
||||
private static validateType(type: SettingItemType) {
|
||||
if (!Number.isInteger(type)) throw new Error(`Setting type is not an integer: ${type}`);
|
||||
if (type < 0) throw new Error(`Invalid setting type: ${type}`);
|
||||
}
|
||||
|
||||
static async registerSetting(key: string, metadataItem: SettingItem) {
|
||||
if (metadataItem.isEnum && !metadataItem.options) throw new Error('The `options` property is required for enum types');
|
||||
try {
|
||||
if (metadataItem.isEnum && !metadataItem.options) throw new Error('The `options` property is required for enum types');
|
||||
|
||||
this.validateKey(key);
|
||||
this.validateKey(key);
|
||||
this.validateType(metadataItem.type);
|
||||
|
||||
this.customMetadata_[key] = metadataItem;
|
||||
this.customMetadata_[key] = {
|
||||
...metadataItem,
|
||||
value: this.formatValue(metadataItem.type, metadataItem.value),
|
||||
};
|
||||
|
||||
// Clear cache
|
||||
this.metadata_ = null;
|
||||
this.keys_ = null;
|
||||
// Clear cache
|
||||
this.metadata_ = null;
|
||||
this.keys_ = null;
|
||||
|
||||
// Reload the value from the database, if it was already present
|
||||
const valueRow = await this.loadOne(key);
|
||||
if (valueRow) {
|
||||
this.cache_.push({
|
||||
// Reload the value from the database, if it was already present
|
||||
const valueRow = await this.loadOne(key);
|
||||
if (valueRow) {
|
||||
this.cache_.push({
|
||||
key: key,
|
||||
value: this.formatValue(key, valueRow.value),
|
||||
});
|
||||
}
|
||||
|
||||
this.dispatch({
|
||||
type: 'SETTING_UPDATE_ONE',
|
||||
key: key,
|
||||
value: this.formatValue(key, valueRow.value),
|
||||
value: this.value(key),
|
||||
});
|
||||
} catch (error) {
|
||||
error.message = `Could not register setting "${key}": ${error.message}`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.dispatch({
|
||||
type: 'SETTING_UPDATE_ONE',
|
||||
key: key,
|
||||
value: this.value(key),
|
||||
});
|
||||
}
|
||||
|
||||
static async registerSection(name: string, source: SettingSectionSource, section: SettingSection) {
|
||||
@ -2119,12 +2133,12 @@ class Setting extends BaseModel {
|
||||
return md.filter ? md.filter(value) : value;
|
||||
}
|
||||
|
||||
static formatValue(key: string, value: any) {
|
||||
const md = this.settingMetadata(key);
|
||||
static formatValue(key: string | SettingItemType, value: any) {
|
||||
const type = typeof key === 'string' ? this.settingMetadata(key).type : key;
|
||||
|
||||
if (md.type === SettingItemType.Int) return !value ? 0 : Math.floor(Number(value));
|
||||
if (type === SettingItemType.Int) return !value ? 0 : Math.floor(Number(value));
|
||||
|
||||
if (md.type === SettingItemType.Bool) {
|
||||
if (type === SettingItemType.Bool) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.toLowerCase();
|
||||
if (value === 'true') return true;
|
||||
@ -2134,26 +2148,26 @@ class Setting extends BaseModel {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
if (md.type === SettingItemType.Array) {
|
||||
if (type === SettingItemType.Array) {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) return value;
|
||||
if (typeof value === 'string') return JSON.parse(value);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (md.type === SettingItemType.Object) {
|
||||
if (type === SettingItemType.Object) {
|
||||
if (!value) return {};
|
||||
if (typeof value === 'object') return value;
|
||||
if (typeof value === 'string') return JSON.parse(value);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (md.type === SettingItemType.String) {
|
||||
if (type === SettingItemType.String) {
|
||||
if (!value) return '';
|
||||
return `${value}`;
|
||||
}
|
||||
|
||||
throw new Error(`Unhandled value type: ${md.type}`);
|
||||
throw new Error(`Unhandled value type: ${type}`);
|
||||
}
|
||||
|
||||
static value(key: string) {
|
||||
|
Loading…
Reference in New Issue
Block a user