Merge pull request #3618 from Neko-Box-Coder/LockConfig

Removing the ability for plugins to modify settings.json and bindings.json. Adding an option to reject plugins to bind keys.
This commit is contained in:
Jöran Karl
2025-11-18 21:28:19 +01:00
committed by GitHub
6 changed files with 55 additions and 21 deletions

View File

@@ -73,7 +73,7 @@ func luaImportMicroConfig() *lua.LTable {
ulua.L.SetField(pkg, "OptionComplete", luar.New(ulua.L, action.OptionComplete))
ulua.L.SetField(pkg, "OptionValueComplete", luar.New(ulua.L, action.OptionValueComplete))
ulua.L.SetField(pkg, "NoComplete", luar.New(ulua.L, nil))
ulua.L.SetField(pkg, "TryBindKey", luar.New(ulua.L, action.TryBindKey))
ulua.L.SetField(pkg, "TryBindKey", luar.New(ulua.L, action.TryBindKeyPlug))
ulua.L.SetField(pkg, "Reload", luar.New(ulua.L, action.ReloadConfig))
ulua.L.SetField(pkg, "AddRuntimeFileFromMemory", luar.New(ulua.L, config.PluginAddRuntimeFileFromMemory))
ulua.L.SetField(pkg, "AddRuntimeFilesFromDirectory", luar.New(ulua.L, config.PluginAddRuntimeFilesFromDirectory))
@@ -88,8 +88,8 @@ func luaImportMicroConfig() *lua.LTable {
ulua.L.SetField(pkg, "RegisterCommonOption", luar.New(ulua.L, config.RegisterCommonOptionPlug))
ulua.L.SetField(pkg, "RegisterGlobalOption", luar.New(ulua.L, config.RegisterGlobalOptionPlug))
ulua.L.SetField(pkg, "GetGlobalOption", luar.New(ulua.L, config.GetGlobalOption))
ulua.L.SetField(pkg, "SetGlobalOption", luar.New(ulua.L, action.SetGlobalOption))
ulua.L.SetField(pkg, "SetGlobalOptionNative", luar.New(ulua.L, action.SetGlobalOptionNative))
ulua.L.SetField(pkg, "SetGlobalOption", luar.New(ulua.L, action.SetGlobalOptionPlug))
ulua.L.SetField(pkg, "SetGlobalOptionNative", luar.New(ulua.L, action.SetGlobalOptionNativePlug))
ulua.L.SetField(pkg, "ConfigDir", luar.New(ulua.L, config.ConfigDir))
return pkg

View File

@@ -261,9 +261,18 @@ func eventsEqual(e1 Event, e2 Event) bool {
return e1 == e2
}
// TryBindKeyPlug tries to bind a key for the plugin without writing to bindings.json.
// This operation can be rejected by lockbindings to prevent unexpected actions by the user.
func TryBindKeyPlug(k, v string, overwrite bool) (bool, error) {
if l, ok := config.GlobalSettings["lockbindings"]; ok && l.(bool) {
return false, errors.New("bindings is locked by the user")
}
return TryBindKey(k, v, overwrite, false)
}
// TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
// Returns true if the keybinding already existed and a possible error
func TryBindKey(k, v string, overwrite bool) (bool, error) {
// Returns true if the keybinding already existed or is binded successfully and a possible error
func TryBindKey(k, v string, overwrite bool, writeToFile bool) (bool, error) {
var e error
var parsed map[string]any
@@ -310,7 +319,12 @@ func TryBindKey(k, v string, overwrite bool) (bool, error) {
txt, _ := json.MarshalIndent(parsed, "", " ")
txt = append(txt, '\n')
if writeToFile {
return true, writeFile(filename, txt)
} else {
return true, nil
}
}
return false, e
}

View File

@@ -630,7 +630,7 @@ func doSetGlobalOptionNative(option string, nativeValue any) error {
return nil
}
func SetGlobalOptionNative(option string, nativeValue any) error {
func SetGlobalOptionNative(option string, nativeValue any, writeToFile bool) error {
if err := config.OptionIsValid(option, nativeValue); err != nil {
return err
}
@@ -653,6 +653,10 @@ func SetGlobalOptionNative(option string, nativeValue any) error {
delete(b.LocalSettings, option)
}
if !writeToFile {
return nil
}
err := config.WriteSettings(filepath.Join(config.ConfigDir, "settings.json"))
if err != nil {
if errors.Is(err, util.ErrOverwrite) {
@@ -665,7 +669,7 @@ func SetGlobalOptionNative(option string, nativeValue any) error {
return nil
}
func SetGlobalOption(option, value string) error {
func SetGlobalOption(option, value string, writeToFile bool) error {
if _, ok := config.GlobalSettings[option]; !ok {
return config.ErrInvalidOption
}
@@ -675,7 +679,15 @@ func SetGlobalOption(option, value string) error {
return err
}
return SetGlobalOptionNative(option, nativeValue)
return SetGlobalOptionNative(option, nativeValue, writeToFile)
}
func SetGlobalOptionNativePlug(option string, nativeValue any) error {
return SetGlobalOptionNative(option, nativeValue, false)
}
func SetGlobalOptionPlug(option, value string) error {
return SetGlobalOption(option, value, false)
}
// ResetCmd resets a setting to its default value
@@ -689,7 +701,7 @@ func (h *BufPane) ResetCmd(args []string) {
defaults := config.DefaultAllSettings()
if _, ok := defaults[option]; ok {
SetGlobalOptionNative(option, defaults[option])
SetGlobalOptionNative(option, defaults[option], true)
return
}
InfoBar.Error(config.ErrInvalidOption)
@@ -705,7 +717,7 @@ func (h *BufPane) SetCmd(args []string) {
option := args[0]
value := args[1]
err := SetGlobalOption(option, value)
err := SetGlobalOption(option, value, true)
if err == config.ErrInvalidOption {
err := h.Buf.SetOption(option, value)
if err != nil {
@@ -761,7 +773,7 @@ func (h *BufPane) toggleOption(option string, local bool) error {
return err
}
} else {
if err := SetGlobalOptionNative(option, newVal); err != nil {
if err := SetGlobalOptionNative(option, newVal, true); err != nil {
return err
}
}
@@ -844,7 +856,7 @@ func (h *BufPane) BindCmd(args []string) {
return
}
_, err := TryBindKey(parseKeyArg(args[0]), args[1], true)
_, err := TryBindKey(parseKeyArg(args[0]), args[1], true, true)
if err != nil {
if errors.Is(err, util.ErrOverwrite) {
screen.TermMessage(err)

View File

@@ -119,6 +119,7 @@ var DefaultGlobalOnlySettings = map[string]any{
"helpsplit": "hsplit",
"infobar": true,
"keymenu": false,
"lockbindings": false,
"mouse": true,
"multiopen": "tab",
"parsecursor": false,

View File

@@ -227,6 +227,12 @@ Here are the available options:
default value: `false`
* `lockbindings`: prevent plugins and lua scripts from binding any keys.
Any custom actions must be binded manually either via commands like `bind`
or by modifying the `bindings.json` file.
default value: `false`
* `matchbrace`: show matching braces for '()', '{}', '[]' when the cursor
is on a brace character or (if `matchbraceleft` is enabled) next to it.

View File

@@ -174,11 +174,12 @@ The packages and their contents are listed below (in Go type signatures):
values afterwards
- `NoComplete`: no autocompletion suggestions
- `TryBindKey(k, v string, overwrite bool) (bool, error)`: bind the key
`k` to the string `v` in the `bindings.json` file. If `overwrite` is
true, this will overwrite any existing binding to key `k`. Returns true
if the binding was made, and a possible error (for example writing to
`bindings.json` can cause an error).
- `TryBindKey(k, v string, overwrite bool) (bool, error)`:
bind the key `k` to the string `v`. If `overwrite` is true, this will
overwrite any existing binding to key `k`.
Returns true if the binding was made, and a possible error.
This operation can be rejected by `lockbindings` to prevent undesired
actions by the user.
- `Reload()`: reload configuration files.
@@ -224,9 +225,9 @@ The packages and their contents are listed below (in Go type signatures):
given plugin in the `GlobalSettings` map.
- `SetGlobalOption(option, value string) error`: sets an option to a
given value. Same as using the `> set` command. This will try to convert
the value into the proper type for the option. Can return an error if the
option name is not valid, or the value can not be converted.
given value. This will try to convert the value into the proper
type for the option. Can return an error if the option name is not
valid, or the value can not be converted.
- `SetGlobalOptionNative(option string, value any) error`: sets
an option to a given value, where the type of value is the actual