mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
Allow importing unknown settings, add export key selection, improve json keys
This commit is contained in:
parent
bed5c72a6b
commit
d19efe7103
3 changed files with 43 additions and 16 deletions
|
@ -85,7 +85,7 @@ func handleExportSingleSetting(ar *api.Request) (data []byte, err error) {
|
||||||
if len(q) > 0 {
|
if len(q) > 0 {
|
||||||
request = &ExportRequest{
|
request = &ExportRequest{
|
||||||
From: q.Get("from"),
|
From: q.Get("from"),
|
||||||
Key: q.Get("key"),
|
Keys: q["key"], // Get []string by direct map access.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
request = &ExportRequest{}
|
request = &ExportRequest{}
|
||||||
|
@ -95,12 +95,12 @@ func handleExportSingleSetting(ar *api.Request) (data []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check parameters.
|
// Check parameters.
|
||||||
if request.From == "" || request.Key == "" {
|
if request.From == "" || len(request.Keys) != 1 {
|
||||||
return nil, errors.New("missing parameters")
|
return nil, errors.New("missing or malformed parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export.
|
// Export.
|
||||||
export, err := ExportSingleSetting(request.Key, request.From)
|
export, err := ExportSingleSetting(request.Keys[0], request.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ type SettingsImportRequest struct {
|
||||||
// any settings would be replaced or deleted.
|
// any settings would be replaced or deleted.
|
||||||
Reset bool `json:"reset"`
|
Reset bool `json:"reset"`
|
||||||
|
|
||||||
|
AllowUnknown bool `json:"allowUnknown"`
|
||||||
|
|
||||||
Export *SettingsExport `json:"export"`
|
Export *SettingsExport `json:"export"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +44,10 @@ func registerSettingsAPI() error {
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Field: "from",
|
Field: "from",
|
||||||
Description: "Specify where to export from.",
|
Description: "Specify where to export from.",
|
||||||
|
}, {
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Field: "key",
|
||||||
|
Description: "Optionally select a single setting to export. Repeat to export selection.",
|
||||||
}},
|
}},
|
||||||
BelongsTo: module,
|
BelongsTo: module,
|
||||||
DataFunc: handleExportSettings,
|
DataFunc: handleExportSettings,
|
||||||
|
@ -67,6 +73,10 @@ func registerSettingsAPI() error {
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Field: "reset",
|
Field: "reset",
|
||||||
Description: "Replace all existing settings.",
|
Description: "Replace all existing settings.",
|
||||||
|
}, {
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Field: "allowUnknown",
|
||||||
|
Description: "Allow importing of unknown values.",
|
||||||
}},
|
}},
|
||||||
BelongsTo: module,
|
BelongsTo: module,
|
||||||
StructFunc: handleImportSettings,
|
StructFunc: handleImportSettings,
|
||||||
|
@ -85,6 +95,7 @@ func handleExportSettings(ar *api.Request) (data []byte, err error) {
|
||||||
if len(q) > 0 {
|
if len(q) > 0 {
|
||||||
request = &ExportRequest{
|
request = &ExportRequest{
|
||||||
From: q.Get("from"),
|
From: q.Get("from"),
|
||||||
|
Keys: q["key"], // Get []string by direct map access.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
request = &ExportRequest{}
|
request = &ExportRequest{}
|
||||||
|
@ -99,7 +110,7 @@ func handleExportSettings(ar *api.Request) (data []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export.
|
// Export.
|
||||||
export, err := ExportSettings(request.From)
|
export, err := ExportSettings(request.From, request.Keys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -120,7 +131,8 @@ func handleImportSettings(ar *api.Request) (any, error) {
|
||||||
RawExport: string(ar.InputData),
|
RawExport: string(ar.InputData),
|
||||||
RawMime: ar.Header.Get("Content-Type"),
|
RawMime: ar.Header.Get("Content-Type"),
|
||||||
},
|
},
|
||||||
Reset: q.Has("reset"),
|
Reset: q.Has("reset"),
|
||||||
|
AllowUnknown: q.Has("allowUnknown"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
request = &SettingsImportRequest{}
|
request = &SettingsImportRequest{}
|
||||||
|
@ -151,7 +163,7 @@ func handleImportSettings(ar *api.Request) (any, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportSettings exports the global settings.
|
// ExportSettings exports the global settings.
|
||||||
func ExportSettings(from string) (*SettingsExport, error) {
|
func ExportSettings(from string, keys []string) (*SettingsExport, error) {
|
||||||
var settings map[string]any
|
var settings map[string]any
|
||||||
if from == ExportTargetGlobal {
|
if from == ExportTargetGlobal {
|
||||||
// Collect all changed global settings.
|
// Collect all changed global settings.
|
||||||
|
@ -175,6 +187,17 @@ func ExportSettings(from string) (*SettingsExport, error) {
|
||||||
settings = config.Flatten(p.Config)
|
settings = config.Flatten(p.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only extract some setting keys, if wanted.
|
||||||
|
if len(keys) > 0 {
|
||||||
|
selection := make(map[string]any, len(keys))
|
||||||
|
for _, key := range keys {
|
||||||
|
if v, ok := settings[key]; ok {
|
||||||
|
selection[key] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings = selection
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there any changed settings.
|
// Check if there any changed settings.
|
||||||
if len(settings) == 0 {
|
if len(settings) == 0 {
|
||||||
return nil, ErrUnchanged
|
return nil, ErrUnchanged
|
||||||
|
@ -237,7 +260,10 @@ func ImportSettings(r *SettingsImportRequest) (*ImportResult, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if checked < len(settings) {
|
if checked < len(settings) {
|
||||||
return nil, fmt.Errorf("%w: the export contains unknown settings", ErrInvalidImportRequest)
|
result.ContainsUnknown = true
|
||||||
|
if !r.AllowUnknown {
|
||||||
|
return nil, fmt.Errorf("%w: the export contains unknown settings", ErrInvalidImportRequest)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import global settings.
|
// Import global settings.
|
||||||
|
|
17
sync/util.go
17
sync/util.go
|
@ -35,8 +35,8 @@ var (
|
||||||
|
|
||||||
// ExportRequest is a request for an export.
|
// ExportRequest is a request for an export.
|
||||||
type ExportRequest struct {
|
type ExportRequest struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
Key string `json:"key"`
|
Keys []string `json:"keys"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportRequest is a request to import an export.
|
// ImportRequest is a request to import an export.
|
||||||
|
@ -44,16 +44,17 @@ type ImportRequest struct {
|
||||||
// Where the export should be import to.
|
// Where the export should be import to.
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
// Only validate, but do not actually change anything.
|
// Only validate, but do not actually change anything.
|
||||||
ValidateOnly bool `json:"validate_only"`
|
ValidateOnly bool `json:"validateOnly"`
|
||||||
|
|
||||||
RawExport string `json:"raw_export"`
|
RawExport string `json:"rawExport"`
|
||||||
RawMime string `json:"raw_mime"`
|
RawMime string `json:"rawMime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportResult is returned by successful import operations.
|
// ImportResult is returned by successful import operations.
|
||||||
type ImportResult struct {
|
type ImportResult struct {
|
||||||
RestartRequired bool `json:"restart_required"`
|
RestartRequired bool `json:"restartRequired"`
|
||||||
ReplacesExisting bool `json:"replaces_existing"`
|
ReplacesExisting bool `json:"replacesExisting"`
|
||||||
|
ContainsUnknown bool `json:"containsUnknown"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errors.
|
// Errors.
|
||||||
|
@ -113,7 +114,7 @@ func serializeExport(export any, ar *api.Request) ([]byte, error) {
|
||||||
case dsd.JSON:
|
case dsd.JSON:
|
||||||
data, err = filesig.AddJSONChecksum(data)
|
data, err = filesig.AddJSONChecksum(data)
|
||||||
case dsd.YAML:
|
case dsd.YAML:
|
||||||
data, err = filesig.AddYAMLChecksum(data, filesig.TextPlacementTop)
|
data, err = filesig.AddYAMLChecksum(data, filesig.TextPlacementBottom)
|
||||||
default:
|
default:
|
||||||
return nil, dsd.ErrIncompatibleFormat
|
return nil, dsd.ErrIncompatibleFormat
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue