diff --git a/go.mod b/go.mod index ce8c319821..0684b16c3d 100644 --- a/go.mod +++ b/go.mod @@ -110,13 +110,13 @@ require ( github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc gitlab.com/gitlab-org/api/client-go v1.46.0 go.yaml.in/yaml/v4 v4.0.0-rc.3 - golang.org/x/crypto v0.49.0 - golang.org/x/image v0.38.0 - golang.org/x/net v0.52.0 + golang.org/x/crypto v0.52.0 + golang.org/x/image v0.40.0 + golang.org/x/net v0.55.0 golang.org/x/oauth2 v0.36.0 golang.org/x/sync v0.20.0 - golang.org/x/sys v0.42.0 - golang.org/x/text v0.35.0 + golang.org/x/sys v0.45.0 + golang.org/x/text v0.37.0 google.golang.org/grpc v1.79.3 google.golang.org/protobuf v1.36.11 gopkg.in/ini.v1 v1.67.1 diff --git a/go.sum b/go.sum index 04dfc9a8da..0aa0e592b7 100644 --- a/go.sum +++ b/go.sum @@ -277,8 +277,6 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ= github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/getkin/kin-openapi v0.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4= -github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 h1:mtDjlmloH7ytdblogrMz1/8Hqua1y8B4ID+bh3rvod0= github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= @@ -302,12 +300,12 @@ github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5Hql github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0= -github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY= +github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= +github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM= -github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= +github.com/go-git/go-git/v5 v5.19.0 h1:+WkVUQZSy/F1Gb13udrMKjIM2PrzsNfDKFSfo5tkMtc= +github.com/go-git/go-git/v5 v5.19.0/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= @@ -600,8 +598,8 @@ github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= -github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= -github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= +github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU= +github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -787,12 +785,12 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= -golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= -golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE= -golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/image v0.40.0 h1:Tw4GyDXMo+daZN1znreBRC3VayR1aLFUyUEOLUdW1a8= +golang.org/x/image v0.40.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -802,8 +800,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -821,8 +819,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -870,8 +868,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -882,8 +880,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -894,8 +892,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -908,8 +906,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= -golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/models/activities/action.go b/models/activities/action.go index 4ffdca842a..97388402d4 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -436,6 +436,12 @@ type GetFeedsOptions struct { DontCount bool // do counting in GetFeeds } +func (opts *GetFeedsOptions) ApplyPublicOnly(publicOnly bool) { + if publicOnly { + opts.IncludePrivate = false + } +} + // ActivityReadable return whether doer can read activities of user func ActivityReadable(user, doer *user_model.User) bool { return !user.KeepActivityPrivate || diff --git a/models/admin/task.go b/models/admin/task.go index 5d2b9bbff6..7056a8359e 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -137,6 +137,11 @@ func (task *Task) MigrateConfig() (*migration.MigrateOptions, error) { log.Error("Unable to decrypt AuthToken, maybe SECRET_KEY is wrong: %v", err) } } + if opts.AWSSecretAccessKeyEncrypted != "" { + if opts.AWSSecretAccessKey, err = secret.DecryptSecret(setting.SecretKey, opts.AWSSecretAccessKeyEncrypted); err != nil { + log.Error("Unable to decrypt AWSSecretAccessKey, maybe SECRET_KEY is wrong: %v", err) + } + } return &opts, nil } @@ -201,6 +206,8 @@ func FinishMigrateTask(ctx context.Context, task *Task) error { conf.AuthPasswordEncrypted = "" conf.AuthTokenEncrypted = "" conf.CloneAddrEncrypted = "" + conf.AWSSecretAccessKey = "" + conf.AWSSecretAccessKeyEncrypted = "" confBytes, err := json.Marshal(conf) if err != nil { return err diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index 893060a165..6af4a9f686 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -5,9 +5,8 @@ package auth import ( "context" - "crypto/sha256" + "crypto/subtle" "encoding/base32" - "encoding/base64" "errors" "fmt" "net" @@ -24,6 +23,7 @@ import ( uuid "github.com/google/uuid" "golang.org/x/crypto/bcrypt" + "golang.org/x/oauth2" "xorm.io/builder" "xorm.io/xorm" ) @@ -31,7 +31,10 @@ import ( // Authorization codes should expire within 10 minutes per https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2 const oauth2AuthorizationCodeValidity = 10 * time.Minute -var ErrOAuth2AuthorizationCodeInvalidated = errors.New("oauth2 authorization code already invalidated") +var ( + ErrOAuth2AuthorizationCodeInvalidated = errors.New("oauth2 authorization code already invalidated") + ErrOAuth2GrantStaleCounter = errors.New("oauth2 grant state changed during token refresh") +) // OAuth2Application represents an OAuth2 client (RFC 6749) type OAuth2Application struct { @@ -151,30 +154,40 @@ func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool { // https://www.rfc-editor.org/rfc/rfc6819#section-5.2.3.3 // https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-12#section-3.1 - contains := func(s string) bool { - s = strings.TrimSuffix(strings.ToLower(s), "/") - for _, u := range app.RedirectURIs { - if strings.TrimSuffix(strings.ToLower(u), "/") == s { + redirectCandidates := []string{redirectURI} + if !app.ConfidentialClient { + loopbackRedirect, ok := normalizePublicClientRedirectURI(redirectURI) + if ok { + redirectCandidates = append(redirectCandidates, loopbackRedirect) + } + } + + for _, candidate := range redirectCandidates { + normalizedCandidate := normalizeRedirectURIForComparison(candidate) + for _, registeredURI := range app.RedirectURIs { + if normalizeRedirectURIForComparison(registeredURI) == normalizedCandidate { return true } } - return false } - if !app.ConfidentialClient { - uri, err := url.Parse(redirectURI) - // ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3 - if err == nil && uri.Scheme == "http" && uri.Port() != "" { - ip := net.ParseIP(uri.Hostname()) - if ip != nil && ip.IsLoopback() { - // strip port - uri.Host = uri.Hostname() - if contains(uri.String()) { - return true - } - } - } + + return false +} + +func normalizeRedirectURIForComparison(redirectURI string) string { + return strings.TrimSuffix(util.ToLowerASCII(redirectURI), "/") +} + +func normalizePublicClientRedirectURI(redirectURI string) (string, bool) { + parsedURI, err := url.Parse(redirectURI) + if err != nil || parsedURI.Scheme != "http" || parsedURI.Port() == "" { + return "", false } - return contains(redirectURI) + if ip := net.ParseIP(parsedURI.Hostname()); ip == nil || !ip.IsLoopback() { + return "", false + } + parsedURI.Host = parsedURI.Hostname() + return parsedURI.String(), true } // Base32 characters, but lowercased. @@ -424,22 +437,34 @@ func (code *OAuth2AuthorizationCode) Invalidate(ctx context.Context) error { return nil } +func (code *OAuth2AuthorizationCode) requiresCodeVerifier() bool { + return code.CodeChallengeMethod != "" || code.CodeChallenge != "" +} + +func deriveCodeChallenge(method, verifier string) (string, bool) { + switch method { + case "S256": + return oauth2.S256ChallengeFromVerifier(verifier), true + case "plain": + return verifier, true + default: + return "", false + } +} + // ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation. func (code *OAuth2AuthorizationCode) ValidateCodeChallenge(verifier string) bool { - switch code.CodeChallengeMethod { - case "S256": - // base64url(SHA256(verifier)) see https://tools.ietf.org/html/rfc7636#section-4.6 - h := sha256.Sum256([]byte(verifier)) - hashedVerifier := base64.RawURLEncoding.EncodeToString(h[:]) - return hashedVerifier == code.CodeChallenge - case "plain": - return verifier == code.CodeChallenge - case "": + if !code.requiresCodeVerifier() { return true - default: - // unsupported method -> return false + } + if verifier == "" || code.CodeChallengeMethod == "" { return false } + expectedChallenge, ok := deriveCodeChallenge(code.CodeChallengeMethod, verifier) + if !ok { + return false + } + return subtle.ConstantTimeCompare([]byte(expectedChallenge), []byte(code.CodeChallenge)) == 1 } // GetOAuth2AuthorizationByCode returns an authorization by its code @@ -504,15 +529,18 @@ func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redi // IncreaseCounter increases the counter and updates the grant func (grant *OAuth2Grant) IncreaseCounter(ctx context.Context) error { - _, err := db.GetEngine(ctx).ID(grant.ID).Incr("counter").Update(new(OAuth2Grant)) + affected, err := db.GetEngine(ctx). + Where("id = ?", grant.ID). + And("counter = ?", grant.Counter). + Incr("counter"). + Update(new(OAuth2Grant)) if err != nil { return err } - updatedGrant, err := GetOAuth2GrantByID(ctx, grant.ID) - if err != nil { - return err + if affected == 0 { + return ErrOAuth2GrantStaleCounter } - grant.Counter = updatedGrant.Counter + grant.Counter++ return nil } diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go index d72e1cb1d5..465dfb14f2 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/oauth2" ) func TestOAuth2AuthorizationCode(t *testing.T) { @@ -116,6 +117,47 @@ func TestOAuth2Application_ContainsRedirect_Slash(t *testing.T) { assert.False(t, app.ContainsRedirectURI("http://127.0.0.1/other")) } +func TestOAuth2Application_ContainsRedirectURI_ASCIIOnlyNormalization(t *testing.T) { + testCases := []struct { + name string + registered []string + redirectURI string + allowed bool + }{ + { + name: "exact-match", + registered: []string{"https://signin.example.test/callback"}, + redirectURI: "https://signin.example.test/callback", + allowed: true, + }, + { + name: "ascii-case-insensitive", + registered: []string{"https://signin.example.test/callback"}, + redirectURI: "https://signIN.example.test/callback", + allowed: true, + }, + { + name: "non-ascii-not-folded", + registered: []string{"https://signin.example.test/callback"}, + redirectURI: "https://signİn.example.test/callback", + allowed: false, + }, + { + name: "loopback-strips-port", + registered: []string{"http://127.0.0.1/callback"}, + redirectURI: "http://127.0.0.1:12345/callback", + allowed: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + app := &auth_model.OAuth2Application{RedirectURIs: tc.registered} + assert.Equal(t, tc.allowed, app.ContainsRedirectURI(tc.redirectURI)) + }) + } +} + func TestOAuth2Application_ValidateClientSecret(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1}) @@ -193,6 +235,16 @@ func TestOAuth2Grant_IncreaseCounter(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 2}) } +func TestOAuth2Grant_IncreaseCounterRejectsStaleCounter(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 1}) + stale := *grant + + assert.NoError(t, grant.IncreaseCounter(t.Context())) + err := stale.IncreaseCounter(t.Context()) + assert.ErrorIs(t, err, auth_model.ErrOAuth2GrantStaleCounter) +} + func TestOAuth2Grant_ScopeContains(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Scope: "openid profile"}) @@ -237,35 +289,38 @@ func TestRevokeOAuth2Grant(t *testing.T) { //////////////////// Authorization Code func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) { - // test plain - code := &auth_model.OAuth2AuthorizationCode{ - CodeChallengeMethod: "plain", - CodeChallenge: "test123", - } - assert.True(t, code.ValidateCodeChallenge("test123")) - assert.False(t, code.ValidateCodeChallenge("ierwgjoergjio")) + s256Verifier := "s256-verifier" + s256Challenge := oauth2.S256ChallengeFromVerifier(s256Verifier) + missingVerifierChallenge := oauth2.S256ChallengeFromVerifier("verifier-not-supplied") - // test S256 - code = &auth_model.OAuth2AuthorizationCode{ - CodeChallengeMethod: "S256", - CodeChallenge: "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", + testCases := []struct { + name string + method string + challenge string + verifier string + valid bool + }{ + {"plain-success", "plain", "plain-secret", "plain-secret", true}, + {"plain-failure", "plain", "plain-secret", "ierwgjoergjio", false}, + {"s256-success", "S256", s256Challenge, s256Verifier, true}, + {"s256-failure", "S256", s256Challenge, "wiogjerogorewngoenrgoiuenorg", false}, + {"unsupported-method", "monkey", "foiwgjioriogeiogjerger", "foiwgjioriogeiogjerger", false}, + {"no-pkce-configured", "", "", "", true}, + {"s256-missing-verifier", "S256", missingVerifierChallenge, "", false}, + {"plain-missing-verifier", "plain", "plain-secret", "", false}, + {"missing-method-with-challenge", "", "foierjiogerogerg", "", false}, + {"missing-method-rejects-even-matching-verifier", "", "foierjiogerogerg", "foierjiogerogerg", false}, } - assert.True(t, code.ValidateCodeChallenge("N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt")) - assert.False(t, code.ValidateCodeChallenge("wiogjerogorewngoenrgoiuenorg")) - // test unknown - code = &auth_model.OAuth2AuthorizationCode{ - CodeChallengeMethod: "monkey", - CodeChallenge: "foiwgjioriogeiogjerger", + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + code := &auth_model.OAuth2AuthorizationCode{ + CodeChallengeMethod: tc.method, + CodeChallenge: tc.challenge, + } + assert.Equal(t, tc.valid, code.ValidateCodeChallenge(tc.verifier)) + }) } - assert.False(t, code.ValidateCodeChallenge("foiwgjioriogeiogjerger")) - - // test no code challenge - code = &auth_model.OAuth2AuthorizationCode{ - CodeChallengeMethod: "", - CodeChallenge: "foierjiogerogerg", - } - assert.True(t, code.ValidateCodeChallenge("")) } func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) { diff --git a/models/organization/org_list.go b/models/organization/org_list.go index f37961b5f6..136417d932 100644 --- a/models/organization/org_list.go +++ b/models/organization/org_list.go @@ -54,6 +54,12 @@ type FindOrgOptions struct { IncludeVisibility structs.VisibleType } +func (opts *FindOrgOptions) ApplyPublicOnly(publicOnly bool) { + if publicOnly { + opts.IncludeVisibility = structs.VisibleTypePublic + } +} + func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { cond := builder.Eq{"uid": userID} if !includePrivate { diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index e927174a55..25dee1bf0e 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -212,6 +212,13 @@ type SearchRepoOptions struct { OnlyShowRelevant bool } +func (opts *SearchRepoOptions) ApplyPublicOnly(publicOnly bool) { + if publicOnly { + opts.Private = false + opts.AllLimited = false + } +} + // UserOwnedRepoCond returns user ownered repositories func UserOwnedRepoCond(userID int64) builder.Cond { return builder.Eq{ diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 28ae83a095..e4b0a1b067 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -24,6 +24,12 @@ type StarredReposOptions struct { IncludePrivate bool } +func (opts *StarredReposOptions) ApplyPublicOnly(publicOnly bool) { + if publicOnly { + opts.IncludePrivate = false + } +} + func (opts *StarredReposOptions) ToConds() builder.Cond { var cond builder.Cond = builder.Eq{ "star.uid": opts.StarrerID, @@ -62,6 +68,12 @@ type WatchedReposOptions struct { IncludePrivate bool } +func (opts *WatchedReposOptions) ApplyPublicOnly(publicOnly bool) { + if publicOnly { + opts.IncludePrivate = false + } +} + func (opts *WatchedReposOptions) ToConds() builder.Cond { var cond builder.Cond = builder.Eq{ "watch.user_id": opts.WatcherID, diff --git a/models/user/search.go b/models/user/search.go index 36d1d3913b..55feef6af2 100644 --- a/models/user/search.go +++ b/models/user/search.go @@ -59,6 +59,12 @@ type SearchUserOptions struct { IncludeReserved bool } +func (opts *SearchUserOptions) ApplyPublicOnly(publicOnly bool) { + if publicOnly { + opts.Visible = []structs.VisibleType{structs.VisibleTypePublic} + } +} + func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Session { var cond builder.Cond cond = builder.In("type", opts.Types) diff --git a/models/user/user.go b/models/user/user.go index da03aff3a8..14ad5f7a92 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -307,6 +307,13 @@ func (u *User) DashboardLink() string { return setting.AppSubURL + "/" } +func (u *User) SettingsLink() string { + if u.IsOrganization() { + return u.OrganisationLink() + "/settings" + } + return setting.AppSubURL + "/user/settings" +} + // HomeLink returns the user or organization home page link. func (u *User) HomeLink() string { return setting.AppSubURL + "/" + url.PathEscape(u.Name) diff --git a/modules/actions/artifacts.go b/modules/actions/artifacts.go index 4884eb42e8..fcf24dbf5f 100644 --- a/modules/actions/artifacts.go +++ b/modules/actions/artifacts.go @@ -4,6 +4,10 @@ package actions import ( + "crypto/hmac" + "crypto/sha256" + "encoding/binary" + "io" "net/http" "strings" @@ -15,6 +19,22 @@ import ( "code.gitea.io/gitea/services/context" ) +type tagType string + +// BuildSignature builds a hmac signature for the input values. +// "tag" is an internal pre-defined static string to distinguish the signatures for different purpose. +func BuildSignature(tag tagType, vals ...string) []byte { + m := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret()) + _, _ = io.WriteString(m, string(tag)) + var buf8 [8]byte + for _, v := range vals { + binary.LittleEndian.PutUint64(buf8[:], uint64(len(v))) + _, _ = m.Write(buf8[:]) + _, _ = io.WriteString(m, v) + } + return m.Sum(nil) +} + // IsArtifactV4 detects whether the artifact is likely from v4. // V4 backend stores the files as a single combined zip file per artifact, and ensures ContentEncoding contains a slash // (otherwise this uses application/zip instead of the custom mime type), which is not the case for the old backend. diff --git a/modules/actions/artifacts_test.go b/modules/actions/artifacts_test.go new file mode 100644 index 0000000000..4c03843653 --- /dev/null +++ b/modules/actions/artifacts_test.go @@ -0,0 +1,36 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuildSignature(t *testing.T) { + a := BuildSignature("v0", "x") + b := BuildSignature("v0", "x") + assert.Equal(t, a, b) + + a = BuildSignature("v0", "x", "yz") + b = BuildSignature("v0", "xy", "z") + assert.NotEqual(t, a, b) + + a = BuildSignature("v1", "x") + b = BuildSignature("v2", "x") + assert.NotEqual(t, a, b) + + a = BuildSignature("v0", "x") + b = BuildSignature("v0x") + assert.NotEqual(t, a, b) + + a = BuildSignature("v0", "", "x") + b = BuildSignature("v0", "x", "") + assert.NotEqual(t, a, b) + + a = BuildSignature("v0") + b = BuildSignature("v0") + assert.Equal(t, a, b) +} diff --git a/modules/migration/options.go b/modules/migration/options.go index 163aa0cfaa..0f73c55ac4 100644 --- a/modules/migration/options.go +++ b/modules/migration/options.go @@ -40,5 +40,7 @@ type MigrateOptions struct { MirrorInterval string `json:"mirror_interval"` AWSAccessKeyID string - AWSSecretAccessKey string + AWSSecretAccessKey string `json:",omitempty"` + + AWSSecretAccessKeyEncrypted string `json:"aws_secret_access_key_encrypted,omitempty"` } diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 878b9e24d7..1f3194a5f3 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -3626,7 +3626,13 @@ "packages.terraform.delete.latest": "The latest version of a Terraform state cannot be deleted.", "packages.vagrant.install": "To add a Vagrant box, run the following command:", "packages.settings.link": "Link this package to a repository", - "packages.settings.link.description": "If you link a package with a repository, the package will appear in the repository's package list. Only repositories under the same owner can be linked. Leaving the field empty will remove the link.", + "packages.settings.link.description": "If you link a package with a repository, the package will appear in the repository's package list.", + "packages.settings.link.notice1": "Only repositories under the same owner can be linked.", + "packages.settings.link.notice2": "Linking a repository does not change the package visibility.", + "packages.settings.link.notice3": "Leaving the field empty will remove the link.", + "packages.settings.visibility": "Package visibility", + "packages.settings.visibility.inherit": "Package visibility is inherited from the owner and cannot be changed independently here. To change it, update the visibility settings of the user or organization that owns this package.", + "packages.settings.visibility.button": "Change owner visibility", "packages.settings.link.select": "Select Repository", "packages.settings.link.button": "Update Repository Link", "packages.settings.link.success": "Repository link was successfully updated.", diff --git a/package.json b/package.json index 791b1e5f59..270e21c4fb 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "jquery": "4.0.0", "js-yaml": "4.1.1", "katex": "0.16.44", - "mermaid": "11.14.0", + "mermaid": "11.15.0", "online-3d-viewer": "0.18.0", "pdfobject": "2.3.1", "perfect-debounce": "2.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3690d0e56f..02831364ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,11 +84,11 @@ importers: specifier: 1.2.3 version: 1.2.3 '@mcaptcha/vanilla-glue': - specifier: 0.1.0-alpha-3 - version: 0.1.0-alpha-3 + specifier: 0.1.0-rc2 + version: 0.1.0-rc2 '@mermaid-js/layout-elk': specifier: 0.2.1 - version: 0.2.1(mermaid@11.14.0) + version: 0.2.1(mermaid@11.15.0) '@primer/octicons': specifier: 19.23.1 version: 19.23.1 @@ -171,8 +171,8 @@ importers: specifier: 0.16.44 version: 0.16.44 mermaid: - specifier: 11.14.0 - version: 11.14.0 + specifier: 11.15.0 + version: 11.15.0 online-3d-viewer: specifier: 0.18.0 version: 0.18.0 @@ -284,7 +284,7 @@ importers: version: 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2) '@vitest/eslint-plugin': specifier: 1.6.14 - version: 1.6.14(@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1))) + version: 1.6.14(@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(jsdom@20.0.3)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1))) eslint: specifier: 10.1.0 version: 10.1.0(jiti@2.6.1) @@ -377,7 +377,7 @@ importers: version: 17.13.1 vitest: specifier: 4.1.2 - version: 4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)) + version: 4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(jsdom@20.0.3)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)) vue-tsc: specifier: 3.2.6 version: 3.2.6(typescript@6.0.2) @@ -425,21 +425,9 @@ packages: '@cacheable/utils@2.4.1': resolution: {integrity: sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==} - '@chevrotain/cst-dts-gen@11.1.2': - resolution: {integrity: sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==} - - '@chevrotain/gast@11.1.2': - resolution: {integrity: sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==} - - '@chevrotain/regexp-to-ast@11.1.2': - resolution: {integrity: sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==} - '@chevrotain/types@11.1.2': resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} - '@chevrotain/utils@11.1.2': - resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==} - '@citation-js/core@0.7.21': resolution: {integrity: sha512-Vobv2/Yfnn6C6BVO/pvj7madQ7Mfzl83/jAWwixbemGF6ZThhGMz8++FD9hWHyHXDMYuLGa6fK68c2VsolZmTA==} engines: {node: '>=16.0.0'} @@ -889,6 +877,22 @@ packages: '@iconify/utils@3.1.0': resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -968,19 +972,19 @@ packages: '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} - '@mcaptcha/core-glue@0.1.0-alpha-5': - resolution: {integrity: sha512-16qWm5O5X0Y9LXULULaAks8Vf9FNlUUBcR5KDt49aWhFhG5++JzxNmCwQM9EJSHNU7y0U+FdyAWcGmjfKlkRLA==} + '@mcaptcha/core-glue@0.1.0-rc1': + resolution: {integrity: sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg==} - '@mcaptcha/vanilla-glue@0.1.0-alpha-3': - resolution: {integrity: sha512-GT6TJBgmViGXcXiT5VOr+h/6iOnThSlZuCoOWncubyTZU9R3cgU5vWPkF7G6Ob6ee2CBe3yqBxxk24CFVGTVXw==} + '@mcaptcha/vanilla-glue@0.1.0-rc2': + resolution: {integrity: sha512-LDjn9lrKioJ3zwaQOfql7PXsnxCAHg7b1rPw7G0OxpvVE7xLB/a40SHfIIiocce2VS9TPI4MbcKm5pcuy8fU5g==} '@mermaid-js/layout-elk@0.2.1': resolution: {integrity: sha512-MX9jwhMyd5zDcFsYcl3duDUkKhjVRUCGEQrdCeNV5hCIR6+3FuDDbRbFmvVbAu15K1+juzsYGG+K8MDvCY1Amg==} peerDependencies: mermaid: ^11.0.2 - '@mermaid-js/parser@1.1.0': - resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} + '@mermaid-js/parser@1.1.1': + resolution: {integrity: sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==} '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1248,10 +1252,19 @@ packages: '@simonwep/pickr@1.9.0': resolution: {integrity: sha512-oEYvv15PyfZzjoAzvXYt3UyNGwzsrpFxLaZKzkOSd0WYBVwLd19iJerePDONxC1iF6+DpcswPdLIM2KzCJuYFg==} + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + '@sindresorhus/merge-streams@4.0.0': resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@solid-primitives/refs@1.1.3': resolution: {integrity: sha512-aam02fjNKpBteewF/UliPSQCVJsIIGOLEWQOh+ll6R/QePzBOOBMcC4G+5jTaO75JuUS1d/14Q1YXT3X0Ow6iA==} peerDependencies: @@ -1285,6 +1298,10 @@ packages: '@swc/helpers@0.2.14': resolution: {integrity: sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA==} + '@tootallnate/once@2.0.1': + resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==} + engines: {node: '>= 10'} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -1408,12 +1425,24 @@ packages: '@types/hammerjs@2.0.46': resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jquery@4.0.0': resolution: {integrity: sha512-Z+to+A2VkaHq1DfI2oSwsoCdhCHMpTSgjWzNcbNlRGYzksDBpPUgEcAL+RQjOBJRaLoEAOHXxqDGBVP+BblBwg==} '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + '@types/jsdom@20.0.1': + resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1438,6 +1467,9 @@ packages: '@types/sortablejs@1.15.9': resolution: {integrity: sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/swagger-ui-dist@3.30.6': resolution: {integrity: sha512-FVxN7wjLYRtJsZBscOcOcf8oR++m38vbUFjT33Mr9HBuasX9bRDrJsp7iwixcOtKSHEEa2B7o2+4wEiXqC+Ebw==} @@ -1450,6 +1482,9 @@ packages: '@types/toastify-js@1.12.4': resolution: {integrity: sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==} + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -1462,6 +1497,12 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@typescript-eslint/eslint-plugin@8.58.0': resolution: {integrity: sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1720,16 +1761,31 @@ packages: '@vue/shared@3.5.31': resolution: {integrity: sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==} + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + + acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} @@ -1751,6 +1807,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi_up@6.0.6: resolution: {integrity: sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==} @@ -1785,6 +1845,9 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + axe-core@4.11.2: resolution: {integrity: sha512-byD6KPdvo72y/wj2T/4zGEvvlis+PsZsn/yPS3pEO+sFpcrqRpX/TJCxvVaEsNeMrfQbCr7w163YqoD9IYwHXw==} engines: {node: '>=4'} @@ -1849,6 +1912,10 @@ packages: cacheable@2.3.4: resolution: {integrity: sha512-djgxybDbw9fL/ZWMI3+CE8ZilNxcwFkVtDc1gJ+IlOSSWkSMPQabhV/XCHTQ6pwwN6aivXPZ43omTooZiX06Ew==} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1864,6 +1931,10 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} @@ -1892,14 +1963,6 @@ packages: peerDependencies: chart.js: '>=3.2.0' - chevrotain-allstar@0.3.1: - resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} - peerDependencies: - chevrotain: ^11.0.0 - - chevrotain@11.1.2: - resolution: {integrity: sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -1907,6 +1970,10 @@ packages: chroma-js@3.2.0: resolution: {integrity: sha512-os/OippSlX1RlWWr+QDPcGUZs0uoqr32urfxESG9U93lhUfbnlyckte84Q8P1UQY/qth983AS1JONKmLS4T0nw==} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + ci-info@4.4.0: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} @@ -1940,6 +2007,10 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2035,6 +2106,16 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssom@0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + + cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + + cssstyle@2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2197,6 +2278,10 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-urls@3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} @@ -2217,6 +2302,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} @@ -2234,6 +2322,10 @@ packages: delaunator@5.1.0: resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2264,6 +2356,11 @@ packages: domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead + domhandler@5.0.3: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} @@ -2277,6 +2374,10 @@ packages: dropzone@6.0.0-beta.2: resolution: {integrity: sha512-k44yLuFFhRk53M8zP71FaaNzJYIzr99SKmpbO/oZKNslDjNXQsBTdfLs+iONd0U0L94zzlFzRnFdqbLcs7h9fQ==} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + easymde@2.20.0: resolution: {integrity: sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ==} @@ -2296,6 +2397,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -2307,9 +2412,28 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-toolkit@1.46.1: + resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} + esbuild@0.27.4: resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} engines: {node: '>=18'} @@ -2323,10 +2447,19 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-prettier@10.1.8: resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true @@ -2559,6 +2692,11 @@ packages: resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -2662,6 +2800,10 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2672,6 +2814,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} @@ -2679,6 +2824,14 @@ packages: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} @@ -2717,6 +2870,13 @@ packages: globjoin@0.1.4: resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hachure-fill@0.5.2: resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} @@ -2728,10 +2888,22 @@ packages: resolution: {integrity: sha512-Tz23LR9T9jOGVZm2x1EPdXqwA37G/owYMxRwU0E4miurAtFsPMQ1d2Jc2okUaSjZqAFz2oEn3FLXC5a0a+siyA==} engines: {node: '>=20.0.0'} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-flag@5.0.1: resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} engines: {node: '>=12'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hashery@1.5.1: resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} engines: {node: '>=20'} @@ -2742,6 +2914,10 @@ packages: hookified@2.1.1: resolution: {integrity: sha512-AHb76R16GB5EsPBE2J7Ko5kiEyXwviB9P5SMrAKcuAu4vJPZttViAbj9+tZeaQE5zjDme+1vcHP78Yj/WoAveA==} + html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + html-tags@5.1.0: resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==} engines: {node: '>=20.10'} @@ -2752,6 +2928,14 @@ packages: htmx.org@2.0.8: resolution: {integrity: sha512-fm297iru0iWsNJlBrjvtN7V9zjaxd+69Oqjh4F/Vq9Wwi2kFisLcrLCiv5oBX0KLfOX/zG8AUo9ROMU5XUB44Q==} + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -2861,6 +3045,27 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jest-environment-jsdom@29.7.0: + resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jiti@1.21.7: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true @@ -2889,6 +3094,15 @@ packages: resolution: {integrity: sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==} engines: {node: '>=20.0.0'} + jsdom@20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -2952,10 +3166,6 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - langium@4.2.1: - resolution: {integrity: sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==} - engines: {node: '>=20.10.0', npm: '>=10.2.3'} - language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -3118,6 +3328,10 @@ packages: resolution: {integrity: sha512-imiILyUW/Y6YvxbobfReC4PpzjPfpMTUiiH9gN5sloQ3dJAhfJRE40l2q8pMT8+V4xRHiIZ5vaZtJw4D03qduQ==} engines: {vscode: ^1.55.0} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mathml-tag-names@4.0.0: resolution: {integrity: sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==} @@ -3138,8 +3352,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - mermaid@11.14.0: - resolution: {integrity: sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==} + mermaid@11.15.0: + resolution: {integrity: sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==} micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -3220,6 +3434,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -3294,6 +3516,9 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nwsapi@2.2.23: + resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -3334,6 +3559,9 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -3482,6 +3710,13 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -3494,9 +3729,15 @@ packages: resolution: {integrity: sha512-n7mar4T0xQ+39dE2vGTAlbxUEpndwPANH0kDef1/MYsB8Bba9wshkybIRx74qgcvKQPEWErf9AqAdYjhzY2Ilg==} engines: {node: '>=20'} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -3528,6 +3769,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3572,6 +3816,10 @@ packages: resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scslre@0.3.0: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} @@ -3610,6 +3858,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + slash@5.1.0: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} @@ -3638,6 +3890,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + spectral-cli-bundle@1.0.7: resolution: {integrity: sha512-vIUC0nwv9tYxWV1xHdR3CTVDOEEtLKaDCcQpARZgO0Db7VmSpSWJ4xrnVPNSmO59hBtGwW2CVzHf0OimJBaKAA==} engines: {node: '>=20'} @@ -3647,6 +3903,10 @@ packages: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -3732,6 +3992,10 @@ packages: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + supports-hyperlinks@4.4.0: resolution: {integrity: sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==} engines: {node: '>=20'} @@ -3757,6 +4021,9 @@ packages: swagger-ui-dist@5.32.1: resolution: {integrity: sha512-6HQoo7+j8PA2QqP5kgAb9dl1uxUjvR0SAoL/WUp1sTEvm0F6D5npgU2OGCLwl++bIInqGlEUQ2mpuZRZYtyCzQ==} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + sync-fetch@0.4.5: resolution: {integrity: sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==} engines: {node: '>=14'} @@ -3813,9 +4080,17 @@ packages: toastify-js@1.12.0: resolution: {integrity: sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + tributejs@5.1.3: resolution: {integrity: sha512-B5CXihaVzXw+1UHhNFyAwUTMDk1EfoLP5Tj1VhD9yybZ1I8DZJEv8tZ1l0RJo0t0tk9ZhR8eG5tEsaCvRigmdQ==} @@ -3842,6 +4117,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + typescript-eslint@8.58.0: resolution: {integrity: sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3878,6 +4157,10 @@ packages: resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} engines: {node: '>=20'} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -3895,6 +4178,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3988,23 +4274,6 @@ packages: jsdom: optional: true - vscode-jsonrpc@8.2.0: - resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} - engines: {node: '>=14.0.0'} - - vscode-languageserver-protocol@3.17.5: - resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} - - vscode-languageserver-textdocument@1.0.12: - resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} - - vscode-languageserver-types@3.17.5: - resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} - - vscode-languageserver@9.0.1: - resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} - hasBin: true - vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -4040,13 +4309,30 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} + whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -4094,6 +4380,9 @@ packages: xml-reader@2.4.3: resolution: {integrity: sha512-xWldrIxjeAMAu6+HSf9t50ot1uL5M+BtOidRCWHXIeewvSeIpscWCsp4Zxjk8kHHhdqFBrfK8U0EJeCcnyQ/gA==} + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -4142,23 +4431,8 @@ snapshots: hashery: 1.5.1 keyv: 5.6.0 - '@chevrotain/cst-dts-gen@11.1.2': - dependencies: - '@chevrotain/gast': 11.1.2 - '@chevrotain/types': 11.1.2 - lodash-es: 4.17.23 - - '@chevrotain/gast@11.1.2': - dependencies: - '@chevrotain/types': 11.1.2 - lodash-es: 4.17.23 - - '@chevrotain/regexp-to-ast@11.1.2': {} - '@chevrotain/types@11.1.2': {} - '@chevrotain/utils@11.1.2': {} - '@citation-js/core@0.7.21': dependencies: '@citation-js/date': 0.5.1 @@ -4690,6 +4964,35 @@ snapshots: '@iconify/types': 2.0.0 mlly: 1.8.2 + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + jest-mock: 29.7.0 + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 25.5.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.5.0 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4809,21 +5112,27 @@ snapshots: '@marijn/find-cluster-break@1.0.2': {} - '@mcaptcha/core-glue@0.1.0-alpha-5': {} + '@mcaptcha/core-glue@0.1.0-rc1': {} - '@mcaptcha/vanilla-glue@0.1.0-alpha-3': + '@mcaptcha/vanilla-glue@0.1.0-rc2': dependencies: - '@mcaptcha/core-glue': 0.1.0-alpha-5 + '@mcaptcha/core-glue': 0.1.0-rc1 + jest-environment-jsdom: 29.7.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate - '@mermaid-js/layout-elk@0.2.1(mermaid@11.14.0)': + '@mermaid-js/layout-elk@0.2.1(mermaid@11.15.0)': dependencies: d3: 7.9.0 elkjs: 0.9.3 - mermaid: 11.14.0 + mermaid: 11.15.0 - '@mermaid-js/parser@1.1.0': + '@mermaid-js/parser@1.1.1': dependencies: - langium: 4.2.1 + '@chevrotain/types': 11.1.2 '@napi-rs/wasm-runtime@0.2.12': dependencies: @@ -5027,8 +5336,18 @@ snapshots: core-js: 3.32.2 nanopop: 2.3.0 + '@sinclair/typebox@0.27.10': {} + '@sindresorhus/merge-streams@4.0.0': {} + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + '@solid-primitives/refs@1.1.3(solid-js@1.9.12)': dependencies: '@solid-primitives/utils': 6.4.0(solid-js@1.9.12) @@ -5067,6 +5386,8 @@ snapshots: '@swc/helpers@0.2.14': {} + '@tootallnate/once@2.0.1': {} + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -5216,10 +5537,26 @@ snapshots: '@types/hammerjs@2.0.46': {} + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/jquery@4.0.0': {} '@types/js-yaml@4.0.9': {} + '@types/jsdom@20.0.1': + dependencies: + '@types/node': 25.5.0 + '@types/tough-cookie': 4.0.5 + parse5: 7.3.0 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -5238,6 +5575,8 @@ snapshots: '@types/sortablejs@1.15.9': {} + '@types/stack-utils@2.0.3': {} + '@types/swagger-ui-dist@3.30.6': {} '@types/tern@0.23.9': @@ -5248,6 +5587,8 @@ snapshots: '@types/toastify-js@1.12.4': {} + '@types/tough-cookie@4.0.5': {} + '@types/trusted-types@2.0.7': optional: true @@ -5259,6 +5600,12 @@ snapshots: dependencies: '@types/node': 25.5.0 + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + '@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -5499,7 +5846,7 @@ snapshots: vite: 8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1) vue: 3.5.31(typescript@6.0.2) - '@vitest/eslint-plugin@1.6.14(@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)))': + '@vitest/eslint-plugin@1.6.14(@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(jsdom@20.0.3)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)))': dependencies: '@typescript-eslint/scope-manager': 8.58.0 '@typescript-eslint/utils': 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2) @@ -5507,7 +5854,7 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2) typescript: 6.0.2 - vitest: 4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)) + vitest: 4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(jsdom@20.0.3)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -5628,12 +5975,29 @@ snapshots: '@vue/shared@3.5.31': {} + abab@2.0.6: {} + + acorn-globals@7.0.1: + dependencies: + acorn: 8.16.0 + acorn-walk: 8.3.5 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 + acorn-walk@8.3.5: + dependencies: + acorn: 8.16.0 + acorn@8.16.0: {} + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -5658,6 +6022,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi_up@6.0.6: {} any-promise@1.3.0: {} @@ -5685,6 +6051,8 @@ snapshots: astral-regex@2.0.0: {} + asynckit@0.4.0: {} + axe-core@4.11.2: {} axobject-query@4.1.0: {} @@ -5741,6 +6109,11 @@ snapshots: keyv: 5.6.0 qified: 0.9.1 + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + callsites@3.1.0: {} camelcase-css@2.0.1: {} @@ -5749,6 +6122,11 @@ snapshots: chai@6.2.2: {} + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + change-case@5.4.4: {} character-entities-legacy@3.0.0: {} @@ -5772,20 +6150,6 @@ snapshots: chart.js: 4.5.1 hammerjs: 2.0.8 - chevrotain-allstar@0.3.1(chevrotain@11.1.2): - dependencies: - chevrotain: 11.1.2 - lodash-es: 4.17.23 - - chevrotain@11.1.2: - dependencies: - '@chevrotain/cst-dts-gen': 11.1.2 - '@chevrotain/gast': 11.1.2 - '@chevrotain/regexp-to-ast': 11.1.2 - '@chevrotain/types': 11.1.2 - '@chevrotain/utils': 11.1.2 - lodash-es: 4.17.23 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -5800,6 +6164,8 @@ snapshots: chroma-js@3.2.0: {} + ci-info@3.9.0: {} + ci-info@4.4.0: {} citeproc@2.4.63: {} @@ -5829,6 +6195,10 @@ snapshots: colord@2.9.3: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@11.1.0: {} commander@14.0.3: {} @@ -5910,6 +6280,14 @@ snapshots: dependencies: css-tree: 2.2.1 + cssom@0.3.8: {} + + cssom@0.5.0: {} + + cssstyle@2.3.0: + dependencies: + cssom: 0.3.8 + csstype@3.2.3: {} cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): @@ -6098,6 +6476,12 @@ snapshots: damerau-levenshtein@1.0.8: {} + data-urls@3.0.2: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + dayjs@1.11.20: {} debug@3.2.7: @@ -6108,6 +6492,8 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -6125,6 +6511,8 @@ snapshots: dependencies: robust-predicates: 3.0.3 + delayed-stream@1.0.0: {} + dequal@2.0.3: {} detect-libc@2.1.2: {} @@ -6151,6 +6539,10 @@ snapshots: domelementtype@2.3.0: {} + domexception@4.0.0: + dependencies: + webidl-conversions: 7.0.0 + domhandler@5.0.3: dependencies: domelementtype: 2.3.0 @@ -6170,6 +6562,12 @@ snapshots: '@swc/helpers': 0.2.14 just-extend: 5.1.1 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + easymde@2.20.0: dependencies: '@types/codemirror': 5.60.17 @@ -6188,6 +6586,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + entities@7.0.1: {} env-paths@2.2.1: {} @@ -6196,8 +6596,25 @@ snapshots: dependencies: is-arrayish: 0.2.1 + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@2.0.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: '@nolyfill/hasown@1.0.44' + + es-toolkit@1.46.1: {} + esbuild@0.27.4: optionalDependencies: '@esbuild/aix-ppc64': 0.27.4 @@ -6231,8 +6648,18 @@ snapshots: escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)): dependencies: eslint: 10.1.0(jiti@2.6.1) @@ -6566,6 +6993,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 5.0.1 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -6658,16 +7087,44 @@ snapshots: flatted@3.4.2: {} + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: '@nolyfill/hasown@1.0.44' + mime-types: 2.1.35 + fsevents@2.3.2: optional: true fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + functional-red-black-tree@1.0.1: {} get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: '@nolyfill/hasown@1.0.44' + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 @@ -6707,6 +7164,10 @@ snapshots: globjoin@0.1.4: {} + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + hachure-fill@0.5.2: {} hammerjs@2.0.8: {} @@ -6723,8 +7184,16 @@ snapshots: - bufferutil - utf-8-validate + has-flag@4.0.0: {} + has-flag@5.0.1: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hashery@1.5.1: dependencies: hookified: 1.15.1 @@ -6733,6 +7202,10 @@ snapshots: hookified@2.1.1: {} + html-encoding-sniffer@3.0.0: + dependencies: + whatwg-encoding: 2.0.0 + html-tags@5.1.0: {} htmlparser2@8.0.2: @@ -6744,6 +7217,21 @@ snapshots: htmx.org@2.0.8: {} + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.1 + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + iconv-lite@0.6.3: dependencies: safer-buffer: '@nolyfill/safer-buffer@1.0.44' @@ -6824,6 +7312,48 @@ snapshots: isexe@2.0.0: {} + jest-environment-jsdom@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/jsdom': 20.0.1 + '@types/node': 25.5.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + jsdom: 20.0.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.29.0 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + jest-util: 29.7.0 + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.2 + jiti@1.21.7: {} jiti@2.6.1: {} @@ -6842,6 +7372,39 @@ snapshots: jsdoc-type-pratt-parser@7.2.0: {} + jsdom@20.0.3: + dependencies: + abab: 2.0.6 + acorn: 8.16.0 + acorn-globals: 7.0.1 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.6.0 + domexception: 4.0.0 + escodegen: 2.1.0 + form-data: 4.0.5 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.23 + parse5: 7.3.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.20.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -6893,14 +7456,6 @@ snapshots: kind-of@6.0.3: {} - langium@4.2.1: - dependencies: - chevrotain: 11.1.2 - chevrotain-allstar: 0.3.1(chevrotain@11.1.2) - vscode-languageserver: 9.0.1 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.1.0 - language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -7053,6 +7608,8 @@ snapshots: fast-deep-equal: 3.1.3 svgson: 5.3.1 + math-intrinsics@1.1.0: {} + mathml-tag-names@4.0.0: {} mdn-data@2.0.28: {} @@ -7065,11 +7622,11 @@ snapshots: merge2@1.4.1: {} - mermaid@11.14.0: + mermaid@11.15.0: dependencies: '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.0 - '@mermaid-js/parser': 1.1.0 + '@mermaid-js/parser': 1.1.1 '@types/d3': 7.4.3 '@upsetjs/venn.js': 2.0.0 cytoscape: 3.33.1 @@ -7080,9 +7637,9 @@ snapshots: dagre-d3-es: 7.0.14 dayjs: 1.11.20 dompurify: 3.3.3 + es-toolkit: 1.46.1 katex: 0.16.44 khroma: 2.1.0 - lodash-es: 4.17.23 marked: 16.4.2 roughjs: 4.6.6 stylis: 4.3.6 @@ -7266,6 +7823,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@10.2.5: dependencies: brace-expansion: 5.0.5 @@ -7321,6 +7884,8 @@ snapshots: dependencies: boolbase: 1.0.0 + nwsapi@2.2.23: {} + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -7373,6 +7938,10 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5@7.3.0: + dependencies: + entities: 6.0.1 + path-browserify@1.0.1: {} path-data-parser@0.1.0: {} @@ -7487,6 +8056,16 @@ snapshots: prettier@3.8.1: {} + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + punycode.js@2.3.1: {} punycode@2.3.1: {} @@ -7495,8 +8074,12 @@ snapshots: dependencies: hookified: 2.1.1 + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} + react-is@18.3.1: {} + read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -7524,6 +8107,8 @@ snapshots: require-from-string@2.0.2: {} + requires-port@1.0.0: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -7586,6 +8171,10 @@ snapshots: sax@1.6.0: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scslre@0.3.0: dependencies: '@eslint-community/regexpp': 4.12.2 @@ -7612,6 +8201,8 @@ snapshots: signal-exit@4.1.0: {} + slash@3.0.0: {} + slash@5.1.0: {} slice-ansi@4.0.0: @@ -7638,12 +8229,19 @@ snapshots: source-map-js@1.2.1: {} + source-map@0.6.1: + optional: true + spectral-cli-bundle@1.0.7: optionalDependencies: fsevents: 2.3.3 stable-hash-x@0.2.0: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + stackback@0.0.2: {} std-env@4.0.0: {} @@ -7756,6 +8354,10 @@ snapshots: supports-color@10.2.2: {} + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + supports-hyperlinks@4.4.0: dependencies: has-flag: 5.0.1 @@ -7786,6 +8388,8 @@ snapshots: dependencies: '@scarf/scarf': 1.4.0 + symbol-tree@3.2.4: {} + sync-fetch@0.4.5: dependencies: buffer: 5.7.1 @@ -7866,8 +8470,19 @@ snapshots: toastify-js@1.12.0: {} + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + tr46@0.0.3: {} + tr46@3.0.0: + dependencies: + punycode: 2.3.1 + tributejs@5.1.3: {} ts-api-utils@2.5.0(typescript@5.9.3): @@ -7896,6 +8511,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-detect@4.0.8: {} + typescript-eslint@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) @@ -7934,6 +8551,8 @@ snapshots: unicorn-magic@0.4.0: {} + universalify@0.2.0: {} + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -7970,6 +8589,11 @@ snapshots: dependencies: punycode: 2.3.1 + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + util-deprecate@1.0.2: {} uuid@11.1.0: {} @@ -7996,7 +8620,7 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - vitest@4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)): + vitest@4.1.2(@types/node@25.5.0)(happy-dom@20.8.9)(jsdom@20.0.3)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)): dependencies: '@vitest/expect': 4.1.2 '@vitest/mocker': 4.1.2(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)) @@ -8021,24 +8645,10 @@ snapshots: optionalDependencies: '@types/node': 25.5.0 happy-dom: 20.8.9 + jsdom: 20.0.3 transitivePeerDependencies: - msw - vscode-jsonrpc@8.2.0: {} - - vscode-languageserver-protocol@3.17.5: - dependencies: - vscode-jsonrpc: 8.2.0 - vscode-languageserver-types: 3.17.5 - - vscode-languageserver-textdocument@1.0.12: {} - - vscode-languageserver-types@3.17.5: {} - - vscode-languageserver@9.0.1: - dependencies: - vscode-languageserver-protocol: 3.17.5 - vscode-uri@3.1.0: {} vue-bar-graph@2.2.0(typescript@6.0.2): @@ -8082,10 +8692,25 @@ snapshots: w3c-keyname@2.2.8: {} + w3c-xmlserializer@4.0.0: + dependencies: + xml-name-validator: 4.0.0 + webidl-conversions@3.0.1: {} + webidl-conversions@7.0.0: {} + + whatwg-encoding@2.0.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-mimetype@3.0.0: {} + whatwg-url@11.0.0: + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -8123,4 +8748,6 @@ snapshots: eventemitter3: 2.0.3 xml-lexer: 0.2.2 + xmlchars@2.2.0: {} + yocto-queue@0.1.0: {} diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go index 8bd3fb7e2b..83982c4a7f 100644 --- a/routers/api/actions/artifactsv4.go +++ b/routers/api/actions/artifactsv4.go @@ -162,13 +162,7 @@ func ArtifactsV4Routes(prefix string) *web.Router { } func (r *artifactV4Routes) buildSignature(endpoint, expires, artifactName string, taskID, artifactID int64) []byte { - mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret()) - mac.Write([]byte(endpoint)) - mac.Write([]byte(expires)) - mac.Write([]byte(artifactName)) - _, _ = fmt.Fprint(mac, taskID) - _, _ = fmt.Fprint(mac, artifactID) - return mac.Sum(nil) + return actions.BuildSignature("v4", endpoint, expires, artifactName, strconv.FormatInt(taskID, 10), strconv.FormatInt(artifactID, 10)) } func (r *artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endpoint, artifactName string, taskID, artifactID int64) string { diff --git a/routers/api/packages/composer/api.go b/routers/api/packages/composer/api.go index a3ea2c2f9a..0d95ab3ed9 100644 --- a/routers/api/packages/composer/api.go +++ b/routers/api/packages/composer/api.go @@ -9,7 +9,10 @@ import ( "time" packages_model "code.gitea.io/gitea/models/packages" + access_model "code.gitea.io/gitea/models/perm/access" + "code.gitea.io/gitea/modules/log" composer_module "code.gitea.io/gitea/modules/packages/composer" + "code.gitea.io/gitea/services/context" ) // ServiceIndexResponse contains registry endpoints @@ -91,7 +94,7 @@ type Source struct { Reference string `json:"reference"` } -func createPackageMetadataResponse(registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse { +func createPackageMetadataResponse(ctx *context.Context, registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse { versions := make([]*PackageVersionMetadata, 0, len(pds)) for _, pd := range pds { @@ -116,10 +119,15 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac }, } if pd.Repository != nil { - pkg.Source = Source{ - URL: pd.Repository.HTMLURL(), - Type: "git", - Reference: pd.Version.Version, + permission, err := access_model.GetDoerRepoPermission(ctx, pd.Repository, ctx.Doer) + if err != nil { + log.Error("GetDoerRepoPermission[%d]: %v", pd.Repository.ID, err) + } else if permission.HasAnyUnitAccessOrPublicAccess() { + pkg.Source = Source{ + URL: pd.Repository.HTMLURL(), + Type: "git", + Reference: pd.Version.Version, + } } } diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 8eb66ca244..b18cdc242c 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -146,6 +146,7 @@ func PackageMetadata(ctx *context.Context) { } resp := createPackageMetadataResponse( + ctx, setting.AppURL+"api/packages/"+ctx.Package.Owner.Name+"/composer", pds, ) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index f7e436cc63..1a6390b904 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -212,6 +212,11 @@ func repoAssignment() func(ctx *context.APIContext) { ctx.APIErrorNotFound() return } + + if !ctx.TokenCanAccessRepo(repo) { + ctx.APIErrorNotFound() + return + } } } @@ -249,51 +254,66 @@ func checkTokenPublicOnly() func(ctx *context.APIContext) { return } - // public Only permission check - switch { - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository): - if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { - ctx.APIError(http.StatusForbidden, "token scope is limited to public repos") - return - } - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryIssue): - if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { - ctx.APIError(http.StatusForbidden, "token scope is limited to public issues") - return - } - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization): - if ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic { - ctx.APIError(http.StatusForbidden, "token scope is limited to public orgs") - return - } - if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() && ctx.ContextUser.Visibility != api.VisibleTypePublic { - ctx.APIError(http.StatusForbidden, "token scope is limited to public orgs") - return - } - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryUser): - if ctx.ContextUser != nil && ctx.ContextUser.IsTokenAccessAllowed() && ctx.ContextUser.Visibility != api.VisibleTypePublic { - ctx.APIError(http.StatusForbidden, "token scope is limited to public users") - return - } - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryActivityPub): - if ctx.ContextUser != nil && ctx.ContextUser.IsTokenAccessAllowed() && ctx.ContextUser.Visibility != api.VisibleTypePublic { - ctx.APIError(http.StatusForbidden, "token scope is limited to public activitypub") - return - } - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryNotification): - if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { - ctx.APIError(http.StatusForbidden, "token scope is limited to public notifications") - return - } - case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryPackage): - if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() { - ctx.APIError(http.StatusForbidden, "token scope is limited to public packages") - return + for _, category := range requiredScopeCategories { + switch category { + case auth_model.AccessTokenScopeCategoryRepository: + if !ctx.TokenCanAccessRepo(ctx.Repo.Repository) { + ctx.APIError(http.StatusForbidden, "token scope is limited to public repos") + return + } + case auth_model.AccessTokenScopeCategoryIssue: + if !ctx.TokenCanAccessRepo(ctx.Repo.Repository) { + ctx.APIError(http.StatusForbidden, "token scope is limited to public issues") + return + } + case auth_model.AccessTokenScopeCategoryOrganization: + orgPrivate := ctx.Org.Organization != nil && !ctx.Org.Organization.Visibility.IsPublic() + userOrgPrivate := ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() && !ctx.ContextUser.Visibility.IsPublic() + if orgPrivate || userOrgPrivate { + ctx.APIError(http.StatusForbidden, "token scope is limited to public orgs") + return + } + case auth_model.AccessTokenScopeCategoryUser: + if ctx.ContextUser != nil && ctx.ContextUser.IsTokenAccessAllowed() && !ctx.ContextUser.Visibility.IsPublic() { + ctx.APIError(http.StatusForbidden, "token scope is limited to public users") + return + } + case auth_model.AccessTokenScopeCategoryActivityPub: + if ctx.ContextUser != nil && ctx.ContextUser.IsTokenAccessAllowed() && !ctx.ContextUser.Visibility.IsPublic() { + ctx.APIError(http.StatusForbidden, "token scope is limited to public activitypub") + return + } + case auth_model.AccessTokenScopeCategoryNotification: + if !ctx.TokenCanAccessRepo(ctx.Repo.Repository) { + ctx.APIError(http.StatusForbidden, "token scope is limited to public notifications") + return + } + case auth_model.AccessTokenScopeCategoryPackage: + if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() { + ctx.APIError(http.StatusForbidden, "token scope is limited to public packages") + return + } } } } } +func rejectPublicOnly() func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + if !ctx.PublicOnly { + return + } + + ctx.APIError(http.StatusForbidden, "this endpoint is not available for public-only tokens") + } +} + +func contextAuthenticatedUser() func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + ctx.ContextUser = ctx.Doer + } +} + // if a token is being used for auth, we check that it contains the required scope // if a token is not being used, reqToken will enforce other sign in methods func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeCategory) func(ctx *context.APIContext) { @@ -957,6 +977,8 @@ func Routes() *web.Router { }) // Notifications (requires 'notifications' scope) + // The notifications API is not available for public-only tokens because a user's notifications mix + // public and private repository events in the same mailbox. m.Group("/notifications", func() { m.Combo(""). Get(reqToken(), notify.ListNotifications). @@ -965,7 +987,7 @@ func Routes() *web.Router { m.Combo("/threads/{id}"). Get(reqToken(), notify.GetThread). Patch(reqToken(), notify.ReadThread) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification)) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification), rejectPublicOnly()) // Users (requires user scope) m.Group("/users", func() { @@ -1013,8 +1035,9 @@ func Routes() *web.Router { m.Group("/settings", func() { m.Get("", user.GetUserSettings) m.Patch("", bind(api.UserSettingsOptions{}), user.UpdateUserSettings) - }, reqToken()) - m.Combo("/emails"). + }, rejectPublicOnly()) + // Email addresses are always private account data. + m.Combo("/emails", rejectPublicOnly()). Get(user.ListEmails). Post(bind(api.CreateEmailOption{}), user.AddEmail). Delete(bind(api.DeleteEmailOption{}), user.DeleteEmail) @@ -1046,7 +1069,7 @@ func Routes() *web.Router { m.Get("/runs", reqToken(), user.ListWorkflowRuns) m.Get("/jobs", reqToken(), user.ListWorkflowJobs) - }) + }, rejectPublicOnly()) m.Get("/followers", user.ListMyFollowers) m.Group("/following", func() { @@ -1064,7 +1087,7 @@ func Routes() *web.Router { Post(bind(api.CreateKeyOption{}), user.CreatePublicKey) m.Combo("/{id}").Get(user.GetPublicKey). Delete(user.DeletePublicKey) - }) + }, rejectPublicOnly()) // (admin:application scope) m.Group("/applications", func() { @@ -1075,7 +1098,7 @@ func Routes() *web.Router { Delete(user.DeleteOauth2Application). Patch(bind(api.CreateOAuth2ApplicationOptions{}), user.UpdateOauth2Application). Get(user.GetOauth2Application) - }) + }, rejectPublicOnly()) // (admin:gpg_key scope) m.Group("/gpg_keys", func() { @@ -1083,13 +1106,13 @@ func Routes() *web.Router { Post(bind(api.CreateGPGKeyOption{}), user.CreateGPGKey) m.Combo("/{id}").Get(user.GetGPGKey). Delete(user.DeleteGPGKey) - }) - m.Get("/gpg_key_token", user.GetVerificationToken) - m.Post("/gpg_key_verify", bind(api.VerifyGPGKeyOption{}), user.VerifyUserGPGKey) + }, rejectPublicOnly()) + m.Get("/gpg_key_token", rejectPublicOnly(), user.GetVerificationToken) + m.Post("/gpg_key_verify", rejectPublicOnly(), bind(api.VerifyGPGKeyOption{}), user.VerifyUserGPGKey) // (repo scope) m.Combo("/repos", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(user.ListMyRepos). - Post(bind(api.CreateRepoOption{}), repo.Create) + Post(rejectPublicOnly(), bind(api.CreateRepoOption{}), repo.Create) // (repo scope) m.Group("/starred", func() { @@ -1100,22 +1123,22 @@ func Routes() *web.Router { m.Delete("", user.Unstar) }, repoAssignment(), checkTokenPublicOnly()) }, reqStarsEnabled(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)) - m.Get("/times", repo.ListMyTrackedTimes) - m.Get("/stopwatches", repo.GetStopwatches) + m.Get("/times", rejectPublicOnly(), repo.ListMyTrackedTimes) + m.Get("/stopwatches", rejectPublicOnly(), repo.GetStopwatches) m.Get("/subscriptions", user.GetMyWatchedRepos) - m.Get("/teams", org.ListUserTeams) + m.Get("/teams", rejectPublicOnly(), org.ListUserTeams) m.Group("/hooks", func() { m.Combo("").Get(user.ListHooks). Post(bind(api.CreateHookOption{}), user.CreateHook) m.Combo("/{id}").Get(user.GetHook). Patch(bind(api.EditHookOption{}), user.EditHook). Delete(user.DeleteHook) - }, reqWebhooksEnabled()) + }, reqWebhooksEnabled(), rejectPublicOnly()) m.Group("/avatar", func() { m.Post("", bind(api.UpdateUserAvatarOption{}), user.UpdateAvatar) m.Delete("", user.DeleteAvatar) - }) + }, rejectPublicOnly()) m.Group("/blocks", func() { m.Get("", user.ListBlocks) @@ -1124,8 +1147,8 @@ func Routes() *web.Router { m.Put("", user.BlockUser) m.Delete("", user.UnblockUser) }, context.UserAssignmentAPI(), checkTokenPublicOnly()) - }) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken()) + }, rejectPublicOnly()) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken(), contextAuthenticatedUser(), checkTokenPublicOnly()) // Repositories (requires repo scope, org scope) m.Post("/org/{org}/repos", @@ -1431,10 +1454,10 @@ func Routes() *web.Router { }, reqAdmin()) }, reqAnyRepoReader()) // MokoGitea badge engine - m.Get("/badge/{type}.svg", repo.GetRepoBadge) - m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates) - m.Get("/issue_config", context.ReferencesGitRepo(), repo.GetIssueConfig) - m.Get("/issue_config/validate", context.ReferencesGitRepo(), repo.ValidateIssueConfig) + m.Get("/badge/{type}.svg", repo.GetRepoBadge) + m.Get("/issue_templates", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.GetIssueTemplates) + m.Get("/issue_config", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.GetIssueConfig) + m.Get("/issue_config/validate", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.ValidateIssueConfig) m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages) m.Get("/licenses", reqRepoReader(unit.TypeCode), repo.GetLicenses) m.Get("/activities/feeds", repo.ListRepoActivityFeeds) @@ -1648,7 +1671,7 @@ func Routes() *web.Router { }, reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly()) // Organizations - m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs) + m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), checkTokenPublicOnly(), org.ListMyOrgs) m.Group("/users/{username}/orgs", func() { m.Get("", reqToken(), org.ListUserOrgs) m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions) diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 2df871a0aa..d34462540d 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -40,6 +40,7 @@ func listUserOrgs(ctx *context.APIContext, u *user_model.User) { UserID: u.ID, IncludeVisibility: organization.DoerViewOtherVisibility(ctx.Doer, u), } + opts.ApplyPublicOnly(ctx.PublicOnly) orgs, maxResults, err := db.FindAndCount[organization.Organization](ctx, opts) if err != nil { ctx.APIErrorInternal(err) @@ -199,7 +200,7 @@ func GetAll(ctx *context.APIContext) { // "$ref": "#/responses/OrganizationList" vMode := []api.VisibleType{api.VisibleTypePublic} - if ctx.IsSigned && !ctx.PublicOnly { + if ctx.IsSigned { vMode = append(vMode, api.VisibleTypeLimited) if ctx.Doer.IsAdmin { vMode = append(vMode, api.VisibleTypePrivate) @@ -208,13 +209,16 @@ func GetAll(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - publicOrgs, maxResults, err := user_model.SearchUsers(ctx, user_model.SearchUserOptions{ + searchOpts := user_model.SearchUserOptions{ Actor: ctx.Doer, ListOptions: listOptions, Types: []user_model.UserType{user_model.UserTypeOrganization}, OrderBy: db.SearchOrderByAlphabetically, Visible: vMode, - }) + } + searchOpts.ApplyPublicOnly(ctx.PublicOnly) + + publicOrgs, maxResults, err := user_model.SearchUsers(ctx, searchOpts) if err != nil { ctx.APIErrorInternal(err) return @@ -494,6 +498,7 @@ func ListOrgActivityFeeds(ctx *context.APIContext) { Date: ctx.FormString("date"), ListOptions: listOptions, } + opts.ApplyPublicOnly(ctx.PublicOnly) feeds, count, err := feed_service.GetFeeds(ctx, opts) if err != nil { diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 93637c2cb3..9faee18ed8 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -6,7 +6,6 @@ package repo import ( go_context "context" "crypto/hmac" - "crypto/sha256" "encoding/base64" "errors" "fmt" @@ -1939,11 +1938,7 @@ func DeleteArtifact(ctx *context.APIContext) { } func buildSignature(endp string, expires, artifactID int64) []byte { - mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret()) - mac.Write([]byte(endp)) - fmt.Fprint(mac, expires) - fmt.Fprint(mac, artifactID) - return mac.Sum(nil) + return actions.BuildSignature("api", endp, strconv.FormatInt(expires, 10), strconv.FormatInt(artifactID, 10)) } func buildDownloadRawEndpoint(repo *repo_model.Repository, artifactID int64) string { diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 39ca7fb77e..64692e0c22 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -47,9 +47,10 @@ func buildSearchIssuesRepoIDs(ctx *context.APIContext) (repoIDs []int64, allPubl Actor: ctx.Doer, } if ctx.IsSigned { - opts.Private = !ctx.PublicOnly + opts.Private = true opts.AllLimited = true } + opts.ApplyPublicOnly(ctx.PublicOnly) if ctx.FormString("owner") != "" { owner, err := user_model.GetUserByName(ctx, ctx.FormString("owner")) if err != nil { diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 641a6f447d..16bc7e5815 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -134,9 +134,6 @@ func Search(ctx *context.APIContext) { // "$ref": "#/responses/validationError" private := ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")) - if ctx.PublicOnly { - private = false - } opts := repo_model.SearchRepoOptions{ ListOptions: utils.GetListOptions(ctx), @@ -152,6 +149,7 @@ func Search(ctx *context.APIContext) { StarredByID: ctx.FormInt64("starredBy"), IncludeDescription: ctx.FormBool("includeDesc"), } + opts.ApplyPublicOnly(ctx.PublicOnly) if ctx.FormString("template") != "" { opts.Template = optional.Some(ctx.FormBool("template")) @@ -573,6 +571,10 @@ func GetByID(ctx *context.APIContext) { } return } + if !ctx.TokenCanAccessRepo(repo) { + ctx.APIErrorNotFound() + return + } permission, err := access_model.GetDoerRepoPermission(ctx, repo, ctx.Doer) if err != nil { @@ -1321,6 +1323,7 @@ func ListRepoActivityFeeds(ctx *context.APIContext) { Date: ctx.FormString("date"), ListOptions: listOptions, } + opts.ApplyPublicOnly(ctx.PublicOnly) feeds, count, err := feed_service.GetFeeds(ctx, opts) if err != nil { diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index a664888dbf..0e0b6b431b 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -19,12 +19,15 @@ import ( func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { opts := utils.GetListOptions(ctx) - repos, count, err := repo_model.GetUserRepositories(ctx, repo_model.SearchRepoOptions{ + searchOpts := repo_model.SearchRepoOptions{ Actor: u, Private: private, ListOptions: opts, OrderBy: "id ASC", - }) + } + searchOpts.ApplyPublicOnly(ctx.PublicOnly) + + repos, count, err := repo_model.GetUserRepositories(ctx, searchOpts) if err != nil { ctx.APIErrorInternal(err) return @@ -79,8 +82,7 @@ func ListUserRepos(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - private := ctx.IsSigned - listUserRepos(ctx, ctx.ContextUser, private) + listUserRepos(ctx, ctx.ContextUser, ctx.IsSigned) } // ListMyRepos - list the repositories you own or have access to. @@ -110,6 +112,7 @@ func ListMyRepos(ctx *context.APIContext) { Private: ctx.IsSigned, IncludeDescription: true, } + opts.ApplyPublicOnly(ctx.PublicOnly) repos, count, err := repo_model.SearchRepository(ctx, opts) if err != nil { diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index 50a54b2683..fb2a324eed 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -20,11 +20,14 @@ import ( // getStarredRepos returns the repos that the user with the specified userID has // starred func getStarredRepos(ctx *context.APIContext, user *user_model.User, private bool) ([]*api.Repository, error) { - starredRepos, err := repo_model.GetStarredRepos(ctx, &repo_model.StarredReposOptions{ + opts := &repo_model.StarredReposOptions{ ListOptions: utils.GetListOptions(ctx), StarrerID: user.ID, IncludePrivate: private, - }) + } + opts.ApplyPublicOnly(ctx.PublicOnly) + + starredRepos, err := repo_model.GetStarredRepos(ctx, opts) if err != nil { return nil, err } diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 005770c571..539e6d7f6a 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -9,7 +9,6 @@ import ( activities_model "code.gitea.io/gitea/models/activities" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" @@ -69,19 +68,16 @@ func Search(ctx *context.APIContext) { maxResults = 1 users = []*user_model.User{user_model.NewActionsUser()} default: - var visible []structs.VisibleType - if ctx.PublicOnly { - visible = []structs.VisibleType{structs.VisibleTypePublic} - } - users, maxResults, err = user_model.SearchUsers(ctx, user_model.SearchUserOptions{ + opts := user_model.SearchUserOptions{ Actor: ctx.Doer, Keyword: ctx.FormTrim("q"), UID: uid, Types: []user_model.UserType{user_model.UserTypeIndividual}, SearchByEmail: true, - Visible: visible, ListOptions: listOptions, - }) + } + opts.ApplyPublicOnly(ctx.PublicOnly) + users, maxResults, err = user_model.SearchUsers(ctx, opts) if err != nil { ctx.JSON(http.StatusInternalServerError, map[string]any{ "ok": false, @@ -214,6 +210,7 @@ func ListUserActivityFeeds(ctx *context.APIContext) { Date: ctx.FormString("date"), ListOptions: listOptions, } + opts.ApplyPublicOnly(ctx.PublicOnly) feeds, count, err := feed_service.GetFeeds(ctx, opts) if err != nil { diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index 9c11d5ca35..1773193f06 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -18,11 +18,14 @@ import ( // getWatchedRepos returns the repos that the user with the specified userID is watching func getWatchedRepos(ctx *context.APIContext, user *user_model.User, private bool) ([]*api.Repository, int64, error) { - watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, &repo_model.WatchedReposOptions{ + opts := &repo_model.WatchedReposOptions{ ListOptions: utils.GetListOptions(ctx), WatcherID: user.ID, IncludePrivate: private, - }) + } + opts.ApplyPublicOnly(ctx.PublicOnly) + + watchedRepos, total, err := repo_model.GetWatchedRepos(ctx, opts) if err != nil { return nil, 0, err } diff --git a/routers/web/auth/oauth2_provider.go b/routers/web/auth/oauth2_provider.go index 05931d8f59..b4f36d543c 100644 --- a/routers/web/auth/oauth2_provider.go +++ b/routers/web/auth/oauth2_provider.go @@ -561,6 +561,13 @@ func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, server }) return } + if grant.ApplicationID != app.ID { + handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{ + ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidGrant, + ErrorDescription: "refresh token belongs to a different client", + }) + return + } // check if token got already used if setting.OAuth2.InvalidateRefreshTokens && (grant.Counter != token.Counter || token.Counter == 0) { @@ -630,6 +637,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s }) return } + if authorizationCode.RedirectURI != "" && form.RedirectURI != authorizationCode.RedirectURI { + handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{ + ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidGrant, + ErrorDescription: "redirect_uri differs from the original authorization request", + }) + return + } // check if granted for this application if authorizationCode.Grant.ApplicationID != app.ID { handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{ diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index bb2002521c..247f6d530b 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -6,6 +6,7 @@ package repo import ( "net/http" + auth_model "code.gitea.io/gitea/models/auth" issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" @@ -21,6 +22,17 @@ import ( repo_service "code.gitea.io/gitea/services/repository" ) +func attachmentReadScope(unitType unit.Type) (auth_model.AccessTokenScope, bool) { + switch unitType { + case unit.TypeIssues, unit.TypePullRequests: + return auth_model.AccessTokenScopeReadIssue, true + case unit.TypeReleases: + return auth_model.AccessTokenScopeReadRepository, true + default: + return "", false + } +} + // UploadIssueAttachment response for Issue/PR attachments func UploadIssueAttachment(ctx *context.Context) { uploadAttachment(ctx, ctx.Repo.Repository.ID, attachment.UploadAttachmentForIssue) @@ -150,9 +162,12 @@ func ServeAttachment(ctx *context.Context, uuid string) { return } } else { // If we have the linked type, we need to check access - var perm access_model.Permission - if ctx.Repo.Repository == nil { - repo, err := repo_model.GetRepositoryByID(ctx, repoID) + var ( + perm access_model.Permission + repo = ctx.Repo.Repository + ) + if repo == nil { + repo, err = repo_model.GetRepositoryByID(ctx, repoID) if err != nil { ctx.ServerError("GetRepositoryByID", err) return @@ -170,6 +185,13 @@ func ServeAttachment(ctx *context.Context, uuid string) { ctx.HTTPError(http.StatusNotFound) return } + + if requiredScope, ok := attachmentReadScope(unitType); ok { + context.CheckTokenScopes(ctx, repo, requiredScope) + if ctx.Written() { + return + } + } } if err := attach.IncreaseDownloadCount(ctx); err != nil { diff --git a/routers/web/repo/download.go b/routers/web/repo/download.go index 25166ea1d3..7c74987d0d 100644 --- a/routers/web/repo/download.go +++ b/routers/web/repo/download.go @@ -7,6 +7,7 @@ package repo import ( "time" + auth_model "code.gitea.io/gitea/models/auth" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/httpcache" @@ -18,6 +19,11 @@ import ( "code.gitea.io/gitea/services/context" ) +func checkDownloadTokenScope(ctx *context.Context) bool { + context.CheckRepoScopedToken(ctx, ctx.Repo.Repository, auth_model.Read) + return !ctx.Written() +} + // ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Time) error { if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) { @@ -88,6 +94,10 @@ func getBlobForEntry(ctx *context.Context) (*git.Blob, *time.Time) { // SingleDownload download a file by repos path func SingleDownload(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + blob, lastModified := getBlobForEntry(ctx) if blob == nil { return @@ -100,6 +110,10 @@ func SingleDownload(ctx *context.Context) { // SingleDownloadOrLFS download a file by repos path redirecting to LFS if necessary func SingleDownloadOrLFS(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + blob, lastModified := getBlobForEntry(ctx) if blob == nil { return @@ -112,6 +126,10 @@ func SingleDownloadOrLFS(ctx *context.Context) { // DownloadByID download a file by sha1 ID func DownloadByID(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + blob, err := ctx.Repo.GitRepo.GetBlob(ctx.PathParam("sha")) if err != nil { if git.IsErrNotExist(err) { @@ -128,6 +146,10 @@ func DownloadByID(ctx *context.Context) { // DownloadByIDOrLFS download a file by sha1 ID taking account of LFS func DownloadByIDOrLFS(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + blob, err := ctx.Repo.GitRepo.GetBlob(ctx.PathParam("sha")) if err != nil { if git.IsErrNotExist(err) { diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index 928c78a61f..fbfdcf2d51 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -180,8 +180,8 @@ func httpBase(ctx *context.Context, optGitService ...string) *serviceHandler { } if repoExist { - // Because of special ref "refs/for" (agit) , need delay write permission check - if git.DefaultFeatures().SupportProcReceive { + // Only the main code repo accepts refs/for pushes, so wiki pushes must keep write checks. + if git.DefaultFeatures().SupportProcReceive && !isWiki { accessMode = perm.AccessModeRead } diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 538074250b..8ad611be34 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -364,6 +364,10 @@ func RedirectDownload(ctx *context.Context) { // Download an archive of a repository func Download(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"), ctx.FormStrings("path")) if err != nil { if errors.Is(err, util.ErrInvalidArgument) { @@ -389,6 +393,10 @@ func Download(ctx *context.Context) { // a request that's already in-progress, but the archiver service will just // kind of drop it on the floor if this is the case. func InitiateDownload(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + paths := ctx.FormStrings("path") if setting.Repository.StreamArchives || len(paths) > 0 { ctx.JSON(http.StatusOK, map[string]any{ diff --git a/services/context/api.go b/services/context/api.go index 3f9f3e1cdd..5b3a35a7fa 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/cache" @@ -47,6 +48,12 @@ type APIContext struct { PublicOnly bool // Whether the request is for a public endpoint } +// TokenCanAccessRepo reports whether the current API token is allowed to access the repository. +// A public-only token cannot reach a private repo; any other token is unrestricted by this check. +func (ctx *APIContext) TokenCanAccessRepo(repo *repo_model.Repository) bool { + return repo == nil || !ctx.PublicOnly || !repo.IsPrivate +} + func init() { web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider { return req.Context().Value(apiContextKey).(*APIContext) diff --git a/services/context/permission.go b/services/context/permission.go index 1f40e26153..ffdca9d662 100644 --- a/services/context/permission.go +++ b/services/context/permission.go @@ -12,10 +12,43 @@ import ( "code.gitea.io/gitea/models/unit" ) +// CheckTokenScopes checks whether the authenticated API token contains any of the given scopes. +func CheckTokenScopes(ctx *Context, repo *repo_model.Repository, scopes ...auth_model.AccessTokenScope) { + if ctx.Data["IsApiToken"] != true { + return + } + + scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if !ok { + return + } + + publicOnly, err := scope.PublicOnly() + if err != nil { + ctx.ServerError("PublicOnly", err) + return + } + + if publicOnly && repo != nil && repo.IsPrivate { + ctx.HTTPError(http.StatusForbidden) + return + } + + scopeMatched, err := scope.HasAnyScope(scopes...) + if err != nil { + ctx.ServerError("HasAnyScope", err) + return + } + + if !scopeMatched { + ctx.HTTPError(http.StatusForbidden) + } +} + // RequireRepoAdmin returns a middleware for requiring repository admin permission func RequireRepoAdmin() func(ctx *Context) { return func(ctx *Context) { - if !ctx.IsSigned || !ctx.Repo.Permission.IsAdmin() { + if !ctx.IsSigned || !ctx.Repo.IsAdmin() { ctx.NotFound(nil) return } @@ -35,7 +68,7 @@ func CanWriteToBranch() func(ctx *Context) { // RequireUnitWriter returns a middleware for requiring repository write to one of the unit permission func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) { return func(ctx *Context) { - if slices.ContainsFunc(unitTypes, ctx.Repo.Permission.CanWrite) { + if slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) { return } ctx.NotFound(nil) @@ -46,7 +79,7 @@ func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) { func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) { return func(ctx *Context) { for _, unitType := range unitTypes { - if ctx.Repo.Permission.CanRead(unitType) { + if ctx.Repo.CanRead(unitType) { return } if unitType == unit.TypeCode && canWriteAsMaintainer(ctx) { @@ -57,39 +90,7 @@ func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) { } } -// CheckRepoScopedToken check whether personal access token has repo scope +// CheckRepoScopedToken checks whether the authenticated API token has repo scope. func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) { - if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true { - return - } - - scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if ok { // it's a personal access token but not oauth2 token - var scopeMatched bool - - requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository) - - // check if scope only applies to public resources - publicOnly, err := scope.PublicOnly() - if err != nil { - ctx.ServerError("HasScope", err) - return - } - - if publicOnly && repo.IsPrivate { - ctx.HTTPError(http.StatusForbidden) - return - } - - scopeMatched, err = scope.HasScope(requiredScopes...) - if err != nil { - ctx.ServerError("HasScope", err) - return - } - - if !scopeMatched { - ctx.HTTPError(http.StatusForbidden) - return - } - } + CheckTokenScopes(ctx, repo, auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository)...) } diff --git a/services/lfs/server.go b/services/lfs/server.go index 0d4243a47e..26eb4878c6 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" "github.com/golang-jwt/jwt/v5" @@ -605,6 +606,18 @@ func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repo log.Error("Unable to GetUserById[%d]: Error: %v", claims.UserID, err) return nil, err } + if !u.IsActive || u.ProhibitLogin { + return nil, util.NewPermissionDeniedErrorf("not allowed to access any repository") + } + + perm, err := access_model.GetDoerRepoPermission(ctx, target, u) + if err != nil { + log.Error("Unable to GetDoerRepoPermission for user[%d] repo[%d]: %v", claims.UserID, target.ID, err) + return nil, err + } + if !perm.CanAccess(mode, unit.TypeCode) { + return nil, util.NewPermissionDeniedErrorf("no permission to access the repository") + } return u, nil } diff --git a/services/lfs/server_test.go b/services/lfs/server_test.go index e66e48cee8..d8e5a9252a 100644 --- a/services/lfs/server_test.go +++ b/services/lfs/server_test.go @@ -7,9 +7,11 @@ import ( "strings" "testing" + "code.gitea.io/gitea/models/db" perm_model "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" @@ -22,11 +24,15 @@ func TestMain(m *testing.M) { func TestAuthenticate(t *testing.T) { require.NoError(t, unittest.PrepareTestDatabase()) + ctx, _ := contexttest.MockContext(t, "/") + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - token2, _ := GetLFSAuthTokenWithBearer(AuthTokenOptions{Op: "download", UserID: 2, RepoID: 1}) - _, token2, _ = strings.Cut(token2, " ") - ctx, _ := contexttest.MockContext(t, "/") + getUserToken := func(op string, userID int64, repo *repo_model.Repository) string { + s, _ := GetLFSAuthTokenWithBearer(AuthTokenOptions{Op: op, UserID: userID, RepoID: repo.ID}) + _, token, _ := strings.Cut(s, " ") + return token + } t.Run("handleLFSToken", func(t *testing.T) { u, err := handleLFSToken(ctx, "", repo1, perm_model.AccessModeRead) @@ -37,15 +43,62 @@ func TestAuthenticate(t *testing.T) { require.Error(t, err) assert.Nil(t, u) - u, err = handleLFSToken(ctx, token2, repo1, perm_model.AccessModeRead) + u, err = handleLFSToken(ctx, getUserToken("download", 2, repo1), repo1, perm_model.AccessModeRead) require.NoError(t, err) assert.EqualValues(t, 2, u.ID) }) t.Run("authenticate", func(t *testing.T) { const prefixBearer = "Bearer " + token := getUserToken("download", 2, repo1) assert.False(t, authenticate(ctx, repo1, "", true, false)) assert.False(t, authenticate(ctx, repo1, prefixBearer+"invalid", true, false)) - assert.True(t, authenticate(ctx, repo1, prefixBearer+token2, true, false)) + assert.True(t, authenticate(ctx, repo1, prefixBearer+token, true, false)) + }) + + handleLFSTokenTestPerm := func(op string, userID int64, repo *repo_model.Repository, accessMode perm_model.AccessMode) error { + token := getUserToken(op, userID, repo) + u, err := handleLFSToken(ctx, token, repo, accessMode) + if err == nil { + assert.Equal(t, userID, u.ID) + } + return err + } + + t.Run("handleLFSToken blocks prohibited users", func(t *testing.T) { + user37 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 37}) + + // prohibited user + assert.True(t, user37.ProhibitLogin) + err := handleLFSTokenTestPerm("download", 37, repo1, perm_model.AccessModeRead) + assert.ErrorContains(t, err, "not allowed to access any repository") + + // normal user + _, _ = db.GetEngine(t.Context()).ID(37).Cols("prohibit_login").Update(&user_model.User{ProhibitLogin: false}) + err = handleLFSTokenTestPerm("download", 37, repo1, perm_model.AccessModeRead) + assert.NoError(t, err) + + // inactive user + _, _ = db.GetEngine(t.Context()).ID(37).Cols("is_active").Update(&user_model.User{IsActive: false}) + err = handleLFSTokenTestPerm("download", 37, repo1, perm_model.AccessModeRead) + assert.ErrorContains(t, err, "not allowed to access any repository") + }) + + t.Run("handleLFSToken blocks users without repo access", func(t *testing.T) { + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + err := handleLFSTokenTestPerm("download", 10, repo2, perm_model.AccessModeRead) + assert.ErrorContains(t, err, "no permission to access the repository") + }) + + t.Run("handleLFSToken requires write access for uploads", func(t *testing.T) { + err := handleLFSTokenTestPerm("download", 10, repo1, perm_model.AccessModeRead) + assert.NoError(t, err) + err = handleLFSTokenTestPerm("upload", 10, repo1, perm_model.AccessModeWrite) + assert.ErrorContains(t, err, "no permission to access the repository") + }) + + t.Run("handleLFSToken allows writes for authorized users", func(t *testing.T) { + err := handleLFSTokenTestPerm("upload", 2, repo1, perm_model.AccessModeWrite) + assert.NoError(t, err) }) } diff --git a/services/task/task.go b/services/task/task.go index 86cf6a041f..25eccd1077 100644 --- a/services/task/task.go +++ b/services/task/task.go @@ -85,6 +85,11 @@ func CreateMigrateTask(ctx context.Context, doer, u *user_model.User, opts base. return nil, err } opts.AuthToken = "" + opts.AWSSecretAccessKeyEncrypted, err = secret.EncryptSecret(setting.SecretKey, opts.AWSSecretAccessKey) + if err != nil { + return nil, err + } + opts.AWSSecretAccessKey = "" bs, err := json.Marshal(&opts) if err != nil { return nil, err diff --git a/templates/package/settings.tmpl b/templates/package/settings.tmpl index d4241e6541..0192376652 100644 --- a/templates/package/settings.tmpl +++ b/templates/package/settings.tmpl @@ -10,12 +10,28 @@ {{template "user/overview/header" .}} {{end}} {{template "base/alert" .}} -
{{.PackageDescriptor.Package.Name}} / {{ctx.Locale.Tr "repo.settings"}}
++ {{.PackageDescriptor.Package.Name}} + + {{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}} + + / {{ctx.Locale.Tr "repo.settings"}} +
+{{ctx.Locale.Tr "packages.settings.visibility.inherit"}}
+ {{ctx.Locale.Tr "packages.settings.visibility.button"}} +{{ctx.Locale.Tr "packages.settings.link.description"}}
+- {{ctx.Locale.Tr "packages.settings.link.notice1"}}
+- {{ctx.Locale.Tr "packages.settings.link.notice2"}}
+- {{ctx.Locale.Tr "packages.settings.link.notice3"}}