snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 21:19:12 +05:00
commit c60cc7ca75
8092 changed files with 394160 additions and 0 deletions

97
oryx/jsonx/patch.go Normal file
View File

@@ -0,0 +1,97 @@
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package jsonx
import (
"encoding/json"
"fmt"
"strconv"
"strings"
jsonpatch "github.com/evanphx/json-patch/v5"
"github.com/gobwas/glob"
"github.com/pkg/errors"
)
var opAllowList = map[string]struct{}{
"add": {},
"remove": {},
"replace": {},
}
func isUnsupported(op jsonpatch.Operation) bool {
_, ok := opAllowList[op.Kind()]
return !ok
}
func isElementAccess(path string) bool {
if path == "" {
return false
}
elements := strings.Split(path, "/")
lastElement := elements[len(elements)-1:][0]
if lastElement == "-" {
return true
}
if _, err := strconv.Atoi(lastElement); err == nil {
return true
}
return false
}
// ApplyJSONPatch applies a JSON patch to an object and returns the modified
// object. The original object is not modified. It returns an error if the patch
// is invalid or if the patch includes paths that are denied. denyPaths is a
// list of path globs (interpreted with [glob.Compile] that are not allowed to
// be patched.
func ApplyJSONPatch[T any](p json.RawMessage, object T, denyPaths ...string) (result T, err error) {
patch, err := jsonpatch.DecodePatch(p)
if err != nil {
return result, errors.WithStack(err)
}
denyPattern := fmt.Sprintf("{%s}", strings.ToLower(strings.Join(denyPaths, ",")))
matcher, err := glob.Compile(denyPattern, '/')
if err != nil {
return result, errors.WithStack(err)
}
for _, op := range patch {
// Some operations are buggy, see https://github.com/evanphx/json-patch/pull/158
if isUnsupported(op) {
return result, errors.Errorf("unsupported operation: %s", op.Kind())
}
path, err := op.Path()
if err != nil {
return result, errors.Errorf("error parsing patch operations: %v", err)
}
if matcher.Match(strings.ToLower(path)) {
return result, errors.Errorf("patch includes denied path: %s", path)
}
// JSON patch officially rejects replacing paths that don't exist, but we want to be more tolerant.
// Therefore, we will ensure that all paths that we want to replace exist in the original document.
if op.Kind() == "replace" && !isElementAccess(path) {
op["op"] = new(json.RawMessage(`"add"`))
}
}
original, err := json.Marshal(object)
if err != nil {
return result, errors.WithStack(err)
}
options := jsonpatch.NewApplyOptions()
options.EnsurePathExistsOnAdd = true
modified, err := patch.ApplyWithOptions(original, options)
if err != nil {
return result, errors.WithStack(err)
}
err = json.Unmarshal(modified, &result)
return result, errors.WithStack(err)
}