mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-15 12:33:45 +09:00
Compare commits
18 Commits
v1.25.1
...
release/v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b01d6de82 | ||
|
|
d67cd622d0 | ||
|
|
15f3e9d5a5 | ||
|
|
01fa8b2b7e | ||
|
|
1d9ae7ac23 | ||
|
|
01873a99c1 | ||
|
|
ce70863793 | ||
|
|
327f2207dc | ||
|
|
db876d8f17 | ||
|
|
2b71bf283b | ||
|
|
1ca4fef611 | ||
|
|
70ee6b9029 | ||
|
|
e5b404ec53 | ||
|
|
5842cd23a6 | ||
|
|
289bd9694b | ||
|
|
154d7521a5 | ||
|
|
24189dcced | ||
|
|
f84bf259ad |
@@ -567,6 +567,11 @@ ENABLED = true
|
|||||||
;; Alternative location to specify OAuth2 authentication secret. You cannot specify both this and JWT_SECRET, and must pick one
|
;; Alternative location to specify OAuth2 authentication secret. You cannot specify both this and JWT_SECRET, and must pick one
|
||||||
;JWT_SECRET_URI = file:/etc/gitea/oauth2_jwt_secret
|
;JWT_SECRET_URI = file:/etc/gitea/oauth2_jwt_secret
|
||||||
;;
|
;;
|
||||||
|
;; The "issuer" claim identifies the principal that issued the JWT.
|
||||||
|
;; Gitea 1.25 makes it default to "ROOT_URL without the last slash" to follow the standard.
|
||||||
|
;; If you have old logins from before 1.25, you may want to set it to the old (non-standard) value "ROOT_URL with the last slash".
|
||||||
|
;JWT_CLAIM_ISSUER =
|
||||||
|
;;
|
||||||
;; Lifetime of an OAuth2 access token in seconds
|
;; Lifetime of an OAuth2 access token in seconds
|
||||||
;ACCESS_TOKEN_EXPIRATION_TIME = 3600
|
;ACCESS_TOKEN_EXPIRATION_TIME = 3600
|
||||||
;;
|
;;
|
||||||
|
|||||||
14
go.mod
14
go.mod
@@ -116,13 +116,13 @@ require (
|
|||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
github.com/yuin/goldmark-meta v1.1.0
|
github.com/yuin/goldmark-meta v1.1.0
|
||||||
gitlab.com/gitlab-org/api/client-go v0.142.4
|
gitlab.com/gitlab-org/api/client-go v0.142.4
|
||||||
golang.org/x/crypto v0.42.0
|
golang.org/x/crypto v0.44.0
|
||||||
golang.org/x/image v0.30.0
|
golang.org/x/image v0.30.0
|
||||||
golang.org/x/net v0.44.0
|
golang.org/x/net v0.46.0
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.30.0
|
||||||
golang.org/x/sync v0.17.0
|
golang.org/x/sync v0.18.0
|
||||||
golang.org/x/sys v0.37.0
|
golang.org/x/sys v0.38.0
|
||||||
golang.org/x/text v0.30.0
|
golang.org/x/text v0.31.0
|
||||||
google.golang.org/grpc v1.75.0
|
google.golang.org/grpc v1.75.0
|
||||||
google.golang.org/protobuf v1.36.8
|
google.golang.org/protobuf v1.36.8
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
@@ -279,9 +279,9 @@ require (
|
|||||||
go.uber.org/zap/exp v0.3.0 // indirect
|
go.uber.org/zap/exp v0.3.0 // indirect
|
||||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/mod v0.28.0 // indirect
|
golang.org/x/mod v0.29.0 // indirect
|
||||||
golang.org/x/time v0.12.0 // indirect
|
golang.org/x/time v0.12.0 // indirect
|
||||||
golang.org/x/tools v0.37.0 // indirect
|
golang.org/x/tools v0.38.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
|||||||
32
go.sum
32
go.sum
@@ -840,8 +840,8 @@ 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.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
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.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -878,8 +878,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.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.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.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -908,8 +908,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.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
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.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -932,8 +932,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -975,8 +975,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.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.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.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -987,8 +987,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.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
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.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -1002,8 +1002,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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.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.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
@@ -1039,8 +1039,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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
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.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -466,11 +466,13 @@ func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, c
|
|||||||
return currentWhitelist, nil
|
return currentWhitelist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prUserIDs, err := access_model.GetUserIDsWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
whitelist = make([]int64, 0, len(newWhitelist))
|
whitelist = make([]int64, 0, len(newWhitelist))
|
||||||
for _, userID := range newWhitelist {
|
for _, userID := range newWhitelist {
|
||||||
if reader, err := access_model.IsRepoReader(ctx, repo, userID); err != nil {
|
if !prUserIDs.Contains(userID) {
|
||||||
return nil, err
|
|
||||||
} else if !reader {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
whitelist = append(whitelist, userID)
|
whitelist = append(whitelist, userID)
|
||||||
|
|||||||
@@ -53,24 +53,45 @@ func RemoveTeamRepo(ctx context.Context, teamID, repoID int64) error {
|
|||||||
// GetTeamsWithAccessToAnyRepoUnit returns all teams in an organization that have given access level to the repository special unit.
|
// GetTeamsWithAccessToAnyRepoUnit returns all teams in an organization that have given access level to the repository special unit.
|
||||||
// This function is only used for finding some teams that can be used as branch protection allowlist or reviewers, it isn't really used for access control.
|
// This function is only used for finding some teams that can be used as branch protection allowlist or reviewers, it isn't really used for access control.
|
||||||
// FIXME: TEAM-UNIT-PERMISSION this logic is not complete, search the fixme keyword to see more details
|
// FIXME: TEAM-UNIT-PERMISSION this logic is not complete, search the fixme keyword to see more details
|
||||||
func GetTeamsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) ([]*Team, error) {
|
func GetTeamsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (teams []*Team, err error) {
|
||||||
teams := make([]*Team, 0, 5)
|
teamIDs, err := getTeamIDsWithAccessToAnyRepoUnit(ctx, orgID, repoID, mode, unitType, unitTypesMore...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(teamIDs) == 0 {
|
||||||
|
return teams, nil
|
||||||
|
}
|
||||||
|
err = db.GetEngine(ctx).Where(builder.In("id", teamIDs)).OrderBy("team.name").Find(&teams)
|
||||||
|
return teams, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTeamIDsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (teamIDs []int64, err error) {
|
||||||
sub := builder.Select("team_id").From("team_unit").
|
sub := builder.Select("team_id").From("team_unit").
|
||||||
Where(builder.Expr("team_unit.team_id = team.id")).
|
Where(builder.Expr("team_unit.team_id = team.id")).
|
||||||
And(builder.In("team_unit.type", append([]unit.Type{unitType}, unitTypesMore...))).
|
And(builder.In("team_unit.type", append([]unit.Type{unitType}, unitTypesMore...))).
|
||||||
And(builder.Expr("team_unit.access_mode >= ?", mode))
|
And(builder.Expr("team_unit.access_mode >= ?", mode))
|
||||||
|
|
||||||
err := db.GetEngine(ctx).
|
err = db.GetEngine(ctx).
|
||||||
|
Select("team.id").
|
||||||
|
Table("team").
|
||||||
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
||||||
And("team_repo.org_id = ?", orgID).
|
And("team_repo.org_id = ? AND team_repo.repo_id = ?", orgID, repoID).
|
||||||
And("team_repo.repo_id = ?", repoID).
|
|
||||||
And(builder.Or(
|
And(builder.Or(
|
||||||
builder.Expr("team.authorize >= ?", mode),
|
builder.Expr("team.authorize >= ?", mode),
|
||||||
builder.In("team.id", sub),
|
builder.In("team.id", sub),
|
||||||
)).
|
)).
|
||||||
OrderBy("name").
|
Find(&teamIDs)
|
||||||
Find(&teams)
|
return teamIDs, err
|
||||||
|
}
|
||||||
return teams, err
|
|
||||||
|
func GetTeamUserIDsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (userIDs []int64, err error) {
|
||||||
|
teamIDs, err := getTeamIDsWithAccessToAnyRepoUnit(ctx, orgID, repoID, mode, unitType, unitTypesMore...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(teamIDs) == 0 {
|
||||||
|
return userIDs, nil
|
||||||
|
}
|
||||||
|
err = db.GetEngine(ctx).Table("team_user").Select("uid").Where(builder.In("team_id", teamIDs)).Find(&userIDs)
|
||||||
|
return userIDs, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@@ -458,54 +459,44 @@ func HasAnyUnitAccess(ctx context.Context, userID int64, repo *repo_model.Reposi
|
|||||||
return perm.HasAnyUnitAccess(), nil
|
return perm.HasAnyUnitAccess(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUsersWithAccessMode returns users that have at least given access mode to the repository.
|
func GetUsersWithUnitAccess(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode, unitType unit.Type) (users []*user_model.User, err error) {
|
||||||
func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode) (_ []*user_model.User, err error) {
|
userIDs, err := GetUserIDsWithUnitAccess(ctx, repo, mode, unitType)
|
||||||
if err = repo.LoadOwner(ctx); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(userIDs) == 0 {
|
||||||
e := db.GetEngine(ctx)
|
return users, nil
|
||||||
accesses := make([]*Access, 0, 10)
|
}
|
||||||
if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil {
|
if err = db.GetEngine(ctx).In("id", userIDs.Values()).OrderBy("`name`").Find(&users); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave a seat for owner itself to append later, but if owner is an organization
|
|
||||||
// and just waste 1 unit is cheaper than re-allocate memory once.
|
|
||||||
users := make([]*user_model.User, 0, len(accesses)+1)
|
|
||||||
if len(accesses) > 0 {
|
|
||||||
userIDs := make([]int64, len(accesses))
|
|
||||||
for i := 0; i < len(accesses); i++ {
|
|
||||||
userIDs[i] = accesses[i].UserID
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = e.In("id", userIDs).Find(&users); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !repo.Owner.IsOrganization() {
|
|
||||||
users = append(users, repo.Owner)
|
|
||||||
}
|
|
||||||
|
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoReaders returns all users that have explicit read access or higher to the repository.
|
func GetUserIDsWithUnitAccess(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode, unitType unit.Type) (container.Set[int64], error) {
|
||||||
func GetRepoReaders(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) {
|
userIDs := container.Set[int64]{}
|
||||||
return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeRead)
|
e := db.GetEngine(ctx)
|
||||||
}
|
accesses := make([]*Access, 0, 10)
|
||||||
|
if err := e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil {
|
||||||
// GetRepoWriters returns all users that have write access to the repository.
|
return nil, err
|
||||||
func GetRepoWriters(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) {
|
|
||||||
return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeWrite)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsRepoReader returns true if user has explicit read access or higher to the repository.
|
|
||||||
func IsRepoReader(ctx context.Context, repo *repo_model.Repository, userID int64) (bool, error) {
|
|
||||||
if repo.OwnerID == userID {
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
return db.GetEngine(ctx).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{})
|
for _, a := range accesses {
|
||||||
|
userIDs.Add(a.UserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo.LoadOwner(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !repo.Owner.IsOrganization() {
|
||||||
|
userIDs.Add(repo.Owner.ID)
|
||||||
|
} else {
|
||||||
|
teamUserIDs, err := organization.GetTeamUserIDsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, mode, unitType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userIDs.AddMultiple(teamUserIDs...)
|
||||||
|
}
|
||||||
|
return userIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRepoUnitUser check whether user could visit the unit of this repository
|
// CheckRepoUnitUser check whether user could visit the unit of this repository
|
||||||
|
|||||||
@@ -169,9 +169,9 @@ func TestGetUserRepoPermission(t *testing.T) {
|
|||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||||
team := &organization.Team{OrgID: org.ID, LowerName: "test_team"}
|
team := &organization.Team{OrgID: org.ID, LowerName: "test_team"}
|
||||||
require.NoError(t, db.Insert(ctx, team))
|
require.NoError(t, db.Insert(ctx, team))
|
||||||
|
require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID}))
|
||||||
|
|
||||||
t.Run("DoerInTeamWithNoRepo", func(t *testing.T) {
|
t.Run("DoerInTeamWithNoRepo", func(t *testing.T) {
|
||||||
require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID}))
|
|
||||||
perm, err := GetUserRepoPermission(ctx, repo32, user)
|
perm, err := GetUserRepoPermission(ctx, repo32, user)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode)
|
assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode)
|
||||||
@@ -219,6 +219,15 @@ func TestGetUserRepoPermission(t *testing.T) {
|
|||||||
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
|
assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode)
|
||||||
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
|
assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode])
|
||||||
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues])
|
assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues])
|
||||||
|
|
||||||
|
users, err := GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeRead, unit.TypeIssues)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, users, 1)
|
||||||
|
assert.Equal(t, user.ID, users[0].ID)
|
||||||
|
|
||||||
|
users, err = GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeWrite, unit.TypeIssues)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, users)
|
||||||
})
|
})
|
||||||
|
|
||||||
require.NoError(t, db.Insert(ctx, repo_model.Collaboration{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
|
require.NoError(t, db.Insert(ctx, repo_model.Collaboration{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite}))
|
||||||
@@ -229,5 +238,10 @@ func TestGetUserRepoPermission(t *testing.T) {
|
|||||||
assert.Equal(t, perm_model.AccessModeWrite, perm.AccessMode)
|
assert.Equal(t, perm_model.AccessModeWrite, perm.AccessMode)
|
||||||
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
|
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode])
|
||||||
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeIssues])
|
assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeIssues])
|
||||||
|
|
||||||
|
users, err := GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeWrite, unit.TypeIssues)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, users, 1)
|
||||||
|
assert.Equal(t, user.ID, users[0].ID)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package actions
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -13,6 +12,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/glob"
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
|
|
||||||
"github.com/nektos/act/pkg/jobparser"
|
"github.com/nektos/act/pkg/jobparser"
|
||||||
@@ -77,7 +77,7 @@ func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
content, err := io.ReadAll(f)
|
content, err := util.ReadWithLimit(f, 1024*1024)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -19,12 +19,17 @@ type TreeEntry struct {
|
|||||||
gogitTreeEntry *object.TreeEntry
|
gogitTreeEntry *object.TreeEntry
|
||||||
ptree *Tree
|
ptree *Tree
|
||||||
|
|
||||||
|
fullName string
|
||||||
|
|
||||||
size int64
|
size int64
|
||||||
sized bool
|
sized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the entry
|
// Name returns the name of the entry
|
||||||
func (te *TreeEntry) Name() string {
|
func (te *TreeEntry) Name() string {
|
||||||
|
if te.fullName != "" {
|
||||||
|
return te.fullName
|
||||||
|
}
|
||||||
return te.gogitTreeEntry.Name
|
return te.gogitTreeEntry.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
|
|||||||
seen := map[plumbing.Hash]bool{}
|
seen := map[plumbing.Hash]bool{}
|
||||||
walker := object.NewTreeWalker(t.gogitTree, true, seen)
|
walker := object.NewTreeWalker(t.gogitTree, true, seen)
|
||||||
for {
|
for {
|
||||||
_, entry, err := walker.Next()
|
fullName, entry, err := walker.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -84,6 +84,7 @@ func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
|
|||||||
ID: ParseGogitHash(entry.Hash),
|
ID: ParseGogitHash(entry.Hash),
|
||||||
gogitTreeEntry: &entry,
|
gogitTreeEntry: &entry,
|
||||||
ptree: t,
|
ptree: t,
|
||||||
|
fullName: fullName,
|
||||||
}
|
}
|
||||||
entries = append(entries, convertedEntry)
|
entries = append(entries, convertedEntry)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package template
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -76,7 +75,7 @@ func unmarshalFromEntry(entry *git.TreeEntry, filename string) (*api.IssueTempla
|
|||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
content, err := io.ReadAll(r)
|
content, err := util.ReadWithLimit(r, 1024*1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read all: %w", err)
|
return nil, fmt.Errorf("read all: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) {
|
|||||||
if p.Metadata.Readme != "" {
|
if p.Metadata.Readme != "" {
|
||||||
f, err := archive.Open(p.Metadata.Readme)
|
f, err := archive.Open(p.Metadata.Readme)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
buf, _ := io.ReadAll(f)
|
buf, _ := util.ReadWithLimit(f, 1024*1024)
|
||||||
m.Readme = string(buf)
|
m.Readme = string(buf)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func ParsePackage(r io.Reader) (*Package, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if strings.EqualFold(hd.Name, "readme.md") {
|
} else if strings.EqualFold(hd.Name, "readme.md") {
|
||||||
data, err := io.ReadAll(tr)
|
data, err := util.ReadWithLimit(tr, 1024*1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ var OAuth2 = struct {
|
|||||||
InvalidateRefreshTokens bool
|
InvalidateRefreshTokens bool
|
||||||
JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"`
|
JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"`
|
||||||
JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"`
|
JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"`
|
||||||
|
JWTClaimIssuer string `ini:"JWT_CLAIM_ISSUER"`
|
||||||
MaxTokenLength int
|
MaxTokenLength int
|
||||||
DefaultApplications []string
|
DefaultApplications []string
|
||||||
}{
|
}{
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ func (a *AzureBlobStorage) Delete(path string) error {
|
|||||||
func (a *AzureBlobStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
|
func (a *AzureBlobStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) {
|
||||||
blobClient := a.getBlobClient(path)
|
blobClient := a.getBlobClient(path)
|
||||||
|
|
||||||
|
// TODO: OBJECT-STORAGE-CONTENT-TYPE: "browser inline rendering images/PDF" needs proper Content-Type header from storage
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
u, err := blobClient.GetSASURL(sas.BlobPermissions{
|
u, err := blobClient.GetSASURL(sas.BlobPermissions{
|
||||||
Read: true,
|
Read: true,
|
||||||
|
|||||||
@@ -279,20 +279,44 @@ func (m *MinioStorage) Delete(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
|
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
|
||||||
func (m *MinioStorage) URL(path, name, method string, serveDirectReqParams url.Values) (*url.URL, error) {
|
func (m *MinioStorage) URL(storePath, name, method string, serveDirectReqParams url.Values) (*url.URL, error) {
|
||||||
// copy serveDirectReqParams
|
// copy serveDirectReqParams
|
||||||
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
|
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
|
|
||||||
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")
|
// Here we might not know the real filename, and it's quite inefficient to detect the mine type by pre-fetching the object head.
|
||||||
|
// So we just do a quick detection by extension name, at least if works for the "View Raw File" for an LFS file on the Web UI.
|
||||||
|
// Detect content type by extension name, only support the well-known safe types for inline rendering.
|
||||||
|
// TODO: OBJECT-STORAGE-CONTENT-TYPE: need a complete solution and refactor for Azure in the future
|
||||||
|
ext := path.Ext(name)
|
||||||
|
inlineExtMimeTypes := map[string]string{
|
||||||
|
".png": "image/png",
|
||||||
|
".jpg": "image/jpeg",
|
||||||
|
".jpeg": "image/jpeg",
|
||||||
|
".gif": "image/gif",
|
||||||
|
".webp": "image/webp",
|
||||||
|
".avif": "image/avif",
|
||||||
|
// ATTENTION! Don't support unsafe types like HTML/SVG due to security concerns: they can contain JS code, and maybe they need proper Content-Security-Policy
|
||||||
|
// HINT: PDF-RENDER-SANDBOX: PDF won't render in sandboxed context, it seems fine to render it inline
|
||||||
|
".pdf": "application/pdf",
|
||||||
|
|
||||||
|
// TODO: refactor with "modules/public/mime_types.go", for example: "DetectWellKnownSafeInlineMimeType"
|
||||||
|
}
|
||||||
|
if mimeType, ok := inlineExtMimeTypes[ext]; ok {
|
||||||
|
reqParams.Set("response-content-type", mimeType)
|
||||||
|
reqParams.Set("response-content-disposition", "inline")
|
||||||
|
} else {
|
||||||
|
reqParams.Set("response-content-disposition", fmt.Sprintf(`attachment; filename="%s"`, quoteEscaper.Replace(name)))
|
||||||
|
}
|
||||||
|
|
||||||
expires := 5 * time.Minute
|
expires := 5 * time.Minute
|
||||||
if method == http.MethodHead {
|
if method == http.MethodHead {
|
||||||
u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
|
u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(storePath), expires, reqParams)
|
||||||
return u, convertMinioErr(err)
|
return u, convertMinioErr(err)
|
||||||
}
|
}
|
||||||
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams)
|
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(storePath), expires, reqParams)
|
||||||
return u, convertMinioErr(err)
|
return u, convertMinioErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func ReadAtMost(r io.Reader, buf []byte) (n int, err error) {
|
|||||||
// ReadWithLimit reads at most "limit" bytes from r into buf.
|
// ReadWithLimit reads at most "limit" bytes from r into buf.
|
||||||
// If EOF or ErrUnexpectedEOF occurs while reading, err will be nil.
|
// If EOF or ErrUnexpectedEOF occurs while reading, err will be nil.
|
||||||
func ReadWithLimit(r io.Reader, n int) (buf []byte, err error) {
|
func ReadWithLimit(r io.Reader, n int) (buf []byte, err error) {
|
||||||
return readWithLimit(r, 1024, n)
|
return readWithLimit(r, 4*1024, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readWithLimit(r io.Reader, batch, limit int) ([]byte, error) {
|
func readWithLimit(r io.Reader, batch, limit int) ([]byte, error) {
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ func EnumeratePackages(ctx *context.Context) {
|
|||||||
Timestamp: fileMetadata.Timestamp,
|
Timestamp: fileMetadata.Timestamp,
|
||||||
Build: fileMetadata.Build,
|
Build: fileMetadata.Build,
|
||||||
BuildNumber: fileMetadata.BuildNumber,
|
BuildNumber: fileMetadata.BuildNumber,
|
||||||
Dependencies: fileMetadata.Dependencies,
|
Dependencies: util.SliceNilAsEmpty(fileMetadata.Dependencies),
|
||||||
License: versionMetadata.License,
|
License: versionMetadata.License,
|
||||||
LicenseFamily: versionMetadata.LicenseFamily,
|
LicenseFamily: versionMetadata.LicenseFamily,
|
||||||
HashMD5: pfd.Blob.HashMD5,
|
HashMD5: pfd.Blob.HashMD5,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
@@ -260,6 +259,13 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "docker buildx imagetools create" multi-arch operations:
|
||||||
|
// {"type":"oci","is_tagged":false,"platform":"unknown/unknown"}
|
||||||
|
// {"type":"oci","is_tagged":false,"platform":"linux/amd64","layer_creation":["ADD file:9233f6f2237d79659a9521f7e390df217cec49f1a8aa3a12147bbca1956acdb9 in /","CMD [\"/bin/sh\"]"]}
|
||||||
|
// {"type":"oci","is_tagged":false,"platform":"unknown/unknown"}
|
||||||
|
// {"type":"oci","is_tagged":false,"platform":"linux/arm64","layer_creation":["ADD file:df53811312284306901fdaaff0a357a4bf40d631e662fe9ce6d342442e494b6c in /","CMD [\"/bin/sh\"]"]}
|
||||||
|
// {"type":"oci","is_tagged":true,"manifests":[{"platform":"linux/amd64","digest":"sha256:72bb73e706c0dec424d00a1febb21deaf1175a70ead009ad8b159729cfcf5769","size":2819478},{"platform":"linux/arm64","digest":"sha256:9e1426dd084a3221663b85ca1ee99d140c50b153917a5c5604c1f9b78229fd24","size":2716499},{"platform":"unknown/unknown","digest":"sha256:b93f03d0ae11b988243e1b2cd8d29accf5b9670547b7bd8c7d96abecc7283e6e","size":1798},{"platform":"unknown/unknown","digest":"sha256:f034b182ba66366c63a5d195c6dfcd3333c027409c0ac98e55ade36aaa3b2963","size":1798}]}
|
||||||
|
|
||||||
_pv := &packages_model.PackageVersion{
|
_pv := &packages_model.PackageVersion{
|
||||||
PackageID: p.ID,
|
PackageID: p.ID,
|
||||||
CreatorID: mci.Creator.ID,
|
CreatorID: mci.Creator.ID,
|
||||||
@@ -273,27 +279,18 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
|||||||
log.Error("Error inserting package: %v", err)
|
log.Error("Error inserting package: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if container_module.IsMediaTypeImageIndex(mci.MediaType) {
|
|
||||||
if pv.CreatedUnix.AsTime().Before(time.Now().Add(-24 * time.Hour)) {
|
|
||||||
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// keep download count on overwriting
|
// keep download count on overwriting
|
||||||
_pv.DownloadCount = pv.DownloadCount
|
_pv.DownloadCount = pv.DownloadCount
|
||||||
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
pv, err = packages_model.GetOrInsertVersion(ctx, _pv)
|
||||||
|
if err != nil {
|
||||||
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||||
log.Error("Error inserting package: %v", err)
|
log.Error("Error inserting package: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
err = packages_model.UpdateVersion(ctx, &packages_model.PackageVersion{ID: pv.ID, MetadataJSON: _pv.MetadataJSON})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := packages_service.CheckCountQuotaExceeded(ctx, mci.Creator, mci.Owner); err != nil {
|
if err := packages_service.CheckCountQuotaExceeded(ctx, mci.Creator, mci.Owner); err != nil {
|
||||||
|
|||||||
@@ -897,7 +897,7 @@ func EditBranchProtection(ctx *context.APIContext) {
|
|||||||
} else {
|
} else {
|
||||||
whitelistUsers = protectBranch.WhitelistUserIDs
|
whitelistUsers = protectBranch.WhitelistUserIDs
|
||||||
}
|
}
|
||||||
if form.ForcePushAllowlistDeployKeys != nil {
|
if form.ForcePushAllowlistUsernames != nil {
|
||||||
forcePushAllowlistUsers, err = user_model.GetUserIDsByNames(ctx, form.ForcePushAllowlistUsernames, false)
|
forcePushAllowlistUsers, err = user_model.GetUserIDsByNames(ctx, form.ForcePushAllowlistUsernames, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
if user_model.IsErrUserNotExist(err) {
|
||||||
|
|||||||
@@ -369,11 +369,11 @@ func ReqChangeRepoFileOptionsAndCheck(ctx *context.APIContext) {
|
|||||||
},
|
},
|
||||||
Signoff: commonOpts.Signoff,
|
Signoff: commonOpts.Signoff,
|
||||||
}
|
}
|
||||||
if commonOpts.Dates.Author.IsZero() {
|
if changeFileOpts.Dates.Author.IsZero() {
|
||||||
commonOpts.Dates.Author = time.Now()
|
changeFileOpts.Dates.Author = time.Now()
|
||||||
}
|
}
|
||||||
if commonOpts.Dates.Committer.IsZero() {
|
if changeFileOpts.Dates.Committer.IsZero() {
|
||||||
commonOpts.Dates.Committer = time.Now()
|
changeFileOpts.Dates.Committer = time.Now()
|
||||||
}
|
}
|
||||||
ctx.Data["__APIChangeRepoFilesOptions"] = changeFileOpts
|
ctx.Data["__APIChangeRepoFilesOptions"] = changeFileOpts
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,6 +436,7 @@ func ViewProject(ctx *context.Context) {
|
|||||||
ctx.Data["Project"] = project
|
ctx.Data["Project"] = project
|
||||||
ctx.Data["IssuesMap"] = issuesMap
|
ctx.Data["IssuesMap"] = issuesMap
|
||||||
ctx.Data["Columns"] = columns
|
ctx.Data["Columns"] = columns
|
||||||
|
ctx.Data["Title"] = fmt.Sprintf("%s - %s", project.Title, ctx.ContextUser.DisplayName())
|
||||||
|
|
||||||
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
|
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
|
||||||
ctx.ServerError("RenderUserOrgHeader", err)
|
ctx.ServerError("RenderUserOrgHeader", err)
|
||||||
|
|||||||
@@ -1208,7 +1208,11 @@ func MergePullRequest(ctx *context.Context) {
|
|||||||
func deleteBranchAfterMergeAndFlashMessage(ctx *context.Context, prID int64) {
|
func deleteBranchAfterMergeAndFlashMessage(ctx *context.Context, prID int64) {
|
||||||
var fullBranchName string
|
var fullBranchName string
|
||||||
err := repo_service.DeleteBranchAfterMerge(ctx, ctx.Doer, prID, &fullBranchName)
|
err := repo_service.DeleteBranchAfterMerge(ctx, ctx.Doer, prID, &fullBranchName)
|
||||||
if errTr := util.ErrorAsTranslatable(err); errTr != nil {
|
if errors.Is(err, util.ErrPermissionDenied) || errors.Is(err, util.ErrNotExist) {
|
||||||
|
// no need to show error to end users if no permission or branch not exist
|
||||||
|
log.Debug("DeleteBranchAfterMerge (ignore unnecessary error): %v", err)
|
||||||
|
return
|
||||||
|
} else if errTr := util.ErrorAsTranslatable(err); errTr != nil {
|
||||||
ctx.Flash.Error(errTr.Translate(ctx.Locale))
|
ctx.Flash.Error(errTr.Translate(ctx.Locale))
|
||||||
return
|
return
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
|
|||||||
@@ -73,10 +73,9 @@ func SettingsProtectedBranch(c *context.Context) {
|
|||||||
|
|
||||||
c.Data["PageIsSettingsBranches"] = true
|
c.Data["PageIsSettingsBranches"] = true
|
||||||
c.Data["Title"] = c.Locale.TrString("repo.settings.protected_branch") + " - " + rule.RuleName
|
c.Data["Title"] = c.Locale.TrString("repo.settings.protected_branch") + " - " + rule.RuleName
|
||||||
|
users, err := access_model.GetUsersWithUnitAccess(c, c.Repo.Repository, perm.AccessModeRead, unit.TypePullRequests)
|
||||||
users, err := access_model.GetRepoReaders(c, c.Repo.Repository)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ServerError("Repo.Repository.GetReaders", err)
|
c.ServerError("GetUsersWithUnitAccess", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Data["Users"] = users
|
c.Data["Users"] = users
|
||||||
|
|||||||
@@ -149,9 +149,9 @@ func setTagsContext(ctx *context.Context) error {
|
|||||||
}
|
}
|
||||||
ctx.Data["ProtectedTags"] = protectedTags
|
ctx.Data["ProtectedTags"] = protectedTags
|
||||||
|
|
||||||
users, err := access_model.GetRepoReaders(ctx, ctx.Repo.Repository)
|
users, err := access_model.GetUsersWithUnitAccess(ctx, ctx.Repo.Repository, perm.AccessModeRead, unit.TypePullRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("Repo.Repository.GetReaders", err)
|
ctx.ServerError("GetUsersWithUnitAccess", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.Data["Users"] = users
|
ctx.Data["Users"] = users
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) (buf []b
|
|||||||
|
|
||||||
meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid)
|
meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid)
|
||||||
if err != nil { // fallback to a plain file
|
if err != nil { // fallback to a plain file
|
||||||
|
fi.lfsMeta = &pointer
|
||||||
log.Warn("Unable to access LFS pointer %s in repo %d: %v", pointer.Oid, repoID, err)
|
log.Warn("Unable to access LFS pointer %s in repo %d: %v", pointer.Oid, repoID, err)
|
||||||
return buf, dataRc, fi, nil
|
return buf, dataRc, fi, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,8 +92,6 @@ func handleFileViewRenderMarkup(ctx *context.Context, filename string, sniffedTy
|
|||||||
ctx.ServerError("Render", err)
|
ctx.ServerError("Render", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// to prevent iframe from loading third-party url
|
|
||||||
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'")
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,14 +239,17 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
|
|||||||
// * IsRenderableXxx: some files are rendered by backend "markup" engine, some are rendered by frontend (pdf, 3d)
|
// * IsRenderableXxx: some files are rendered by backend "markup" engine, some are rendered by frontend (pdf, 3d)
|
||||||
// * DefaultViewMode: when there is no "display" query parameter, which view mode should be used by default, source or rendered
|
// * DefaultViewMode: when there is no "display" query parameter, which view mode should be used by default, source or rendered
|
||||||
|
|
||||||
utf8Reader := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
|
contentReader := io.MultiReader(bytes.NewReader(buf), dataRc)
|
||||||
|
if fInfo.st.IsRepresentableAsText() {
|
||||||
|
contentReader = charset.ToUTF8WithFallbackReader(contentReader, charset.ConvertOpts{})
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case fInfo.blobOrLfsSize >= setting.UI.MaxDisplayFileSize:
|
case fInfo.blobOrLfsSize >= setting.UI.MaxDisplayFileSize:
|
||||||
ctx.Data["IsFileTooLarge"] = true
|
ctx.Data["IsFileTooLarge"] = true
|
||||||
case handleFileViewRenderMarkup(ctx, entry.Name(), fInfo.st, buf, utf8Reader):
|
case handleFileViewRenderMarkup(ctx, entry.Name(), fInfo.st, buf, contentReader):
|
||||||
// it also sets ctx.Data["FileContent"] and more
|
// it also sets ctx.Data["FileContent"] and more
|
||||||
ctx.Data["IsMarkup"] = true
|
ctx.Data["IsMarkup"] = true
|
||||||
case handleFileViewRenderSource(ctx, entry.Name(), attrs, fInfo, utf8Reader):
|
case handleFileViewRenderSource(ctx, entry.Name(), attrs, fInfo, contentReader):
|
||||||
// it also sets ctx.Data["FileContent"] and more
|
// it also sets ctx.Data["FileContent"] and more
|
||||||
ctx.Data["IsDisplayingSource"] = true
|
ctx.Data["IsDisplayingSource"] = true
|
||||||
case handleFileViewRenderImage(ctx, fInfo, buf):
|
case handleFileViewRenderImage(ctx, fInfo, buf):
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
content, err := io.ReadAll(reader)
|
content, err := util.ReadWithLimit(reader, 5*1024*1024) // 5MB should be enough for a wiki page
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ReadAll", err)
|
ctx.ServerError("ReadAll", err)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -105,9 +105,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if source.AttributeAvatar != "" {
|
if source.AttributeAvatar != "" {
|
||||||
if err := user_service.UploadAvatar(ctx, user, sr.Avatar); err != nil {
|
_ = user_service.UploadAvatar(ctx, user, sr.Avatar)
|
||||||
return user, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ func getWhitelistEntities[T *user_model.User | *organization.Team](entities []T,
|
|||||||
|
|
||||||
// ToBranchProtection convert a ProtectedBranch to api.BranchProtection
|
// ToBranchProtection convert a ProtectedBranch to api.BranchProtection
|
||||||
func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo *repo_model.Repository) *api.BranchProtection {
|
func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo *repo_model.Repository) *api.BranchProtection {
|
||||||
readers, err := access_model.GetRepoReaders(ctx, repo)
|
readers, err := access_model.GetUsersWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetRepoReaders: %v", err)
|
log.Error("GetRepoReaders: %v", err)
|
||||||
}
|
}
|
||||||
@@ -720,7 +720,7 @@ func ToAnnotatedTagObject(repo *repo_model.Repository, commit *git.Commit) *api.
|
|||||||
|
|
||||||
// ToTagProtection convert a git.ProtectedTag to an api.TagProtection
|
// ToTagProtection convert a git.ProtectedTag to an api.TagProtection
|
||||||
func ToTagProtection(ctx context.Context, pt *git_model.ProtectedTag, repo *repo_model.Repository) *api.TagProtection {
|
func ToTagProtection(ctx context.Context, pt *git_model.ProtectedTag, repo *repo_model.Repository) *api.TagProtection {
|
||||||
readers, err := access_model.GetRepoReaders(ctx, repo)
|
readers, err := access_model.GetUsersWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetRepoReaders: %v", err)
|
log.Error("GetRepoReaders: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package issue
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -15,6 +14,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/issue/template"
|
"code.gitea.io/gitea/modules/issue/template"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -65,7 +65,7 @@ func GetTemplateConfig(gitRepo *git.Repository, path string, commit *git.Commit)
|
|||||||
|
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
configContent, err := io.ReadAll(reader)
|
configContent, err := util.ReadWithLimit(reader, 1024*1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GetDefaultTemplateConfig(), err
|
return GetDefaultTemplateConfig(), err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,8 +112,12 @@ func NewJwtRegisteredClaimsFromUser(clientID string, grantUserID int64, exp *jwt
|
|||||||
// to retrieve the configuration information. This MUST also be identical to the "iss" Claim value in ID Tokens issued from this Issuer.
|
// to retrieve the configuration information. This MUST also be identical to the "iss" Claim value in ID Tokens issued from this Issuer.
|
||||||
// * https://accounts.google.com/.well-known/openid-configuration
|
// * https://accounts.google.com/.well-known/openid-configuration
|
||||||
// * https://github.com/login/oauth/.well-known/openid-configuration
|
// * https://github.com/login/oauth/.well-known/openid-configuration
|
||||||
|
issuer := setting.OAuth2.JWTClaimIssuer
|
||||||
|
if issuer == "" {
|
||||||
|
issuer = strings.TrimSuffix(setting.AppURL, "/")
|
||||||
|
}
|
||||||
return jwt.RegisteredClaims{
|
return jwt.RegisteredClaims{
|
||||||
Issuer: strings.TrimSuffix(setting.AppURL, "/"),
|
Issuer: issuer,
|
||||||
Audience: []string{clientID},
|
Audience: []string{clientID},
|
||||||
Subject: strconv.FormatInt(grantUserID, 10),
|
Subject: strconv.FormatInt(grantUserID, 10),
|
||||||
ExpiresAt: exp,
|
ExpiresAt: exp,
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -138,31 +140,37 @@ func (gt *giteaTemplateFileMatcher) Match(s string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func readGiteaTemplateFile(tmpDir string) (*giteaTemplateFileMatcher, error) {
|
func readLocalTmpRepoFileContent(localPath string, limit int) ([]byte, error) {
|
||||||
localPath := filepath.Join(tmpDir, ".gitea", "template")
|
ok, err := util.IsRegularFile(localPath)
|
||||||
if _, err := os.Stat(localPath); os.IsNotExist(err) {
|
if err != nil {
|
||||||
return nil, nil
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else if !ok {
|
||||||
|
return nil, fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := os.ReadFile(localPath)
|
f, err := os.Open(localPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return util.ReadWithLimit(f, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readGiteaTemplateFile(tmpDir string) (*giteaTemplateFileMatcher, error) {
|
||||||
|
localPath := filepath.Join(tmpDir, ".gitea", "template")
|
||||||
|
content, err := readLocalTmpRepoFileContent(localPath, 1024*1024)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return newGiteaTemplateFileMatcher(localPath, content), nil
|
return newGiteaTemplateFileMatcher(localPath, content), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, templateRepo, generateRepo *repo_model.Repository) error {
|
func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, templateRepo, generateRepo *repo_model.Repository) error {
|
||||||
tmpFullPath := filepath.Join(tmpDir, tmpDirSubPath)
|
tmpFullPath := filepath.Join(tmpDir, tmpDirSubPath)
|
||||||
if ok, err := util.IsRegularFile(tmpFullPath); !ok {
|
content, err := readLocalTmpRepoFileContent(tmpFullPath, 1024*1024)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
content, err := os.ReadFile(tmpFullPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return util.Iif(errors.Is(err, fs.ErrNotExist), nil, err)
|
||||||
}
|
}
|
||||||
if err := util.Remove(tmpFullPath); err != nil {
|
if err := util.Remove(tmpFullPath); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -172,7 +180,7 @@ func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, t
|
|||||||
substSubPath := filepath.Clean(filePathSanitize(generateExpansion(ctx, tmpDirSubPath, templateRepo, generateRepo)))
|
substSubPath := filepath.Clean(filePathSanitize(generateExpansion(ctx, tmpDirSubPath, templateRepo, generateRepo)))
|
||||||
newLocalPath := filepath.Join(tmpDir, substSubPath)
|
newLocalPath := filepath.Join(tmpDir, substSubPath)
|
||||||
regular, err := util.IsRegularFile(newLocalPath)
|
regular, err := util.IsRegularFile(newLocalPath)
|
||||||
if canWrite := regular || os.IsNotExist(err); !canWrite {
|
if canWrite := regular || errors.Is(err, fs.ErrNotExist); !canWrite {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(filepath.Dir(newLocalPath), 0o755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(newLocalPath), 0o755); err != nil {
|
||||||
@@ -242,15 +250,15 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
|
|||||||
|
|
||||||
// Variable expansion
|
// Variable expansion
|
||||||
fileMatcher, err := readGiteaTemplateFile(tmpDir)
|
fileMatcher, err := readGiteaTemplateFile(tmpDir)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return fmt.Errorf("readGiteaTemplateFile: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fileMatcher != nil {
|
|
||||||
err = processGiteaTemplateFile(ctx, tmpDir, templateRepo, generateRepo, fileMatcher)
|
err = processGiteaTemplateFile(ctx, tmpDir, templateRepo, generateRepo, fileMatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("processGiteaTemplateFile: %w", err)
|
||||||
}
|
}
|
||||||
|
} else if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
log.Debug("skip processing repo template files: no available .gitea/template")
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("readGiteaTemplateFile: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = git.InitRepository(ctx, tmpDir, false, templateRepo.ObjectFormatName); err != nil {
|
if err = git.InitRepository(ctx, tmpDir, false, templateRepo.ObjectFormatName); err != nil {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -175,6 +176,31 @@ func TestProcessGiteaTemplateFile(t *testing.T) {
|
|||||||
// subst from a link, skip, and the target is unchanged
|
// subst from a link, skip, and the target is unchanged
|
||||||
assertSymLink("subst-${TEMPLATE_NAME}-from-link", tmpDir+"/sub/link-target")
|
assertSymLink("subst-${TEMPLATE_NAME}-from-link", tmpDir+"/sub/link-target")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
templateFilePath := tmpDir + "/.gitea/template"
|
||||||
|
|
||||||
|
_ = os.Remove(templateFilePath)
|
||||||
|
_, err := os.Lstat(templateFilePath)
|
||||||
|
require.ErrorIs(t, err, fs.ErrNotExist)
|
||||||
|
_, err = readGiteaTemplateFile(tmpDir) // no template file
|
||||||
|
require.ErrorIs(t, err, fs.ErrNotExist)
|
||||||
|
|
||||||
|
_ = os.WriteFile(templateFilePath+".target", []byte("test-data-target"), 0o644)
|
||||||
|
_ = os.Symlink(templateFilePath+".target", templateFilePath)
|
||||||
|
content, _ := os.ReadFile(templateFilePath)
|
||||||
|
require.Equal(t, "test-data-target", string(content))
|
||||||
|
_, err = readGiteaTemplateFile(tmpDir) // symlinked template file
|
||||||
|
require.ErrorIs(t, err, fs.ErrNotExist)
|
||||||
|
|
||||||
|
_ = os.Remove(templateFilePath)
|
||||||
|
_ = os.WriteFile(templateFilePath, []byte("test-data-regular"), 0o644)
|
||||||
|
content, _ = os.ReadFile(templateFilePath)
|
||||||
|
require.Equal(t, "test-data-regular", string(content))
|
||||||
|
fm, err := readGiteaTemplateFile(tmpDir) // regular template file
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, fm.globs, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransformers(t *testing.T) {
|
func TestTransformers(t *testing.T) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/queue"
|
"code.gitea.io/gitea/modules/queue"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -264,7 +265,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
|
|||||||
t.ResponseInfo.Headers[k] = strings.Join(vals, ",")
|
t.ResponseInfo.Headers[k] = strings.Join(vals, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := io.ReadAll(resp.Body)
|
p, err := util.ReadWithLimit(resp.Body, 1024*1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.ResponseInfo.Body = fmt.Sprintf("read body: %s", err)
|
t.ResponseInfo.Body = fmt.Sprintf("read body: %s", err)
|
||||||
return fmt.Errorf("unable to deliver webhook task[%d] in %s as unable to read response body: %w", t.ID, w.URL, err)
|
return fmt.Errorf("unable to deliver webhook task[%d] in %s as unable to read response body: %w", t.ID, w.URL, err)
|
||||||
|
|||||||
@@ -78,18 +78,6 @@
|
|||||||
{{ctx.Locale.Tr "repo.release.downloads"}}
|
{{ctx.Locale.Tr "repo.release.downloads"}}
|
||||||
</summary>
|
</summary>
|
||||||
<ul class="ui divided list attachment-list">
|
<ul class="ui divided list attachment-list">
|
||||||
{{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}}
|
|
||||||
<li class="item">
|
|
||||||
<a class="archive-link" download href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow">
|
|
||||||
<strong class="flex-text-inline">{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="item">
|
|
||||||
<a class="archive-link" download href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow">
|
|
||||||
<strong class="flex-text-inline">{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
{{range $att := $release.Attachments}}
|
{{range $att := $release.Attachments}}
|
||||||
<li class="item">
|
<li class="item">
|
||||||
<a target="_blank" class="tw-flex-1 gt-ellipsis" rel="nofollow" download href="{{$att.DownloadURL}}">
|
<a target="_blank" class="tw-flex-1 gt-ellipsis" rel="nofollow" download href="{{$att.DownloadURL}}">
|
||||||
@@ -105,6 +93,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}}
|
||||||
|
<li class="item">
|
||||||
|
<a class="archive-link" download href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.zip" rel="nofollow">
|
||||||
|
<strong class="flex-text-inline">{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP)</strong>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="item">
|
||||||
|
<a class="archive-link" download href="{{$.RepoLink}}/archive/{{$release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow">
|
||||||
|
<strong class="flex-text-inline">{{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ)</strong>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{{if .HeatmapData}}
|
{{if .HeatmapData}}
|
||||||
|
<div class="activity-heatmap-container">
|
||||||
<div id="user-heatmap" class="is-loading"
|
<div id="user-heatmap" class="is-loading"
|
||||||
data-heatmap-data="{{JsonUtils.EncodeToString .HeatmapData}}"
|
data-heatmap-data="{{JsonUtils.EncodeToString .HeatmapData}}"
|
||||||
data-locale-total-contributions="{{ctx.Locale.Tr "heatmap.number_of_contributions_in_the_last_12_months" (ctx.Locale.PrettyNumber .HeatmapTotalContributions)}}"
|
data-locale-total-contributions="{{ctx.Locale.Tr "heatmap.number_of_contributions_in_the_last_12_months" (ctx.Locale.PrettyNumber .HeatmapTotalContributions)}}"
|
||||||
@@ -6,5 +7,6 @@
|
|||||||
data-locale-more="{{ctx.Locale.Tr "heatmap.more"}}"
|
data-locale-more="{{ctx.Locale.Tr "heatmap.more"}}"
|
||||||
data-locale-less="{{ctx.Locale.Tr "heatmap.less"}}"
|
data-locale-less="{{ctx.Locale.Tr "heatmap.less"}}"
|
||||||
></div>
|
></div>
|
||||||
<div class="divider"></div>
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
ref: refs/heads/master
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[core]
|
|
||||||
repositoryformatversion = 0
|
|
||||||
filemode = true
|
|
||||||
bare = true
|
|
||||||
ignorecase = true
|
|
||||||
precomposeunicode = true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
The repository will be used to test third-party renderer in TestExternalMarkupRenderer
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
data=$(cat)
|
|
||||||
exitcodes=""
|
|
||||||
hookname=$(basename $0)
|
|
||||||
GIT_DIR=${GIT_DIR:-$(dirname $0)}
|
|
||||||
|
|
||||||
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
|
||||||
test -x "${hook}" && test -f "${hook}" || continue
|
|
||||||
echo "${data}" | "${hook}"
|
|
||||||
exitcodes="${exitcodes} $?"
|
|
||||||
done
|
|
||||||
|
|
||||||
for i in ${exitcodes}; do
|
|
||||||
[ ${i} -eq 0 ] || exit ${i}
|
|
||||||
done
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
data=$(cat)
|
|
||||||
exitcodes=""
|
|
||||||
hookname=$(basename $0)
|
|
||||||
GIT_DIR=${GIT_DIR:-$(dirname $0)}
|
|
||||||
|
|
||||||
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
|
||||||
test -x "${hook}" && test -f "${hook}" || continue
|
|
||||||
echo "${data}" | "${hook}"
|
|
||||||
exitcodes="${exitcodes} $?"
|
|
||||||
done
|
|
||||||
|
|
||||||
for i in ${exitcodes}; do
|
|
||||||
[ ${i} -eq 0 ] || exit ${i}
|
|
||||||
done
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
exitcodes=""
|
|
||||||
hookname=$(basename $0)
|
|
||||||
GIT_DIR=${GIT_DIR:-$(dirname $0)}
|
|
||||||
|
|
||||||
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
|
||||||
test -x "${hook}" && test -f "${hook}" || continue
|
|
||||||
"${hook}" $1 $2 $3
|
|
||||||
exitcodes="${exitcodes} $?"
|
|
||||||
done
|
|
||||||
|
|
||||||
for i in ${exitcodes}; do
|
|
||||||
[ ${i} -eq 0 ] || exit ${i}
|
|
||||||
done
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
|||||||
# pack-refs with: peeled fully-peeled sorted
|
|
||||||
c961cc4d1ba6b7ee1ba228a9a02b00b7746d8033 refs/heads/master
|
|
||||||
@@ -237,6 +237,8 @@ func TestPackageConda(t *testing.T) {
|
|||||||
assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5)
|
assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5)
|
||||||
assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256)
|
assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256)
|
||||||
assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size)
|
assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size)
|
||||||
|
assert.NotNil(t, packageInfo.Dependencies)
|
||||||
|
assert.Empty(t, packageInfo.Dependencies)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run(".conda", func(t *testing.T) {
|
t.Run(".conda", func(t *testing.T) {
|
||||||
@@ -268,6 +270,8 @@ func TestPackageConda(t *testing.T) {
|
|||||||
assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5)
|
assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5)
|
||||||
assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256)
|
assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256)
|
||||||
assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size)
|
assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size)
|
||||||
|
assert.NotNil(t, packageInfo.Dependencies)
|
||||||
|
assert.Empty(t, packageInfo.Dependencies)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
|
|
||||||
oci "github.com/opencontainers/image-spec/specs-go/v1"
|
oci "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPackageContainer(t *testing.T) {
|
func TestPackageContainer(t *testing.T) {
|
||||||
@@ -70,13 +71,12 @@ func TestPackageContainer(t *testing.T) {
|
|||||||
|
|
||||||
manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6"
|
manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6"
|
||||||
manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
||||||
manifestContentType := container_module.ContentTypeDockerDistributionManifestV2
|
|
||||||
|
|
||||||
untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d"
|
untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d"
|
||||||
untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
|
||||||
|
|
||||||
indexManifestDigest := "sha256:bab112d6efb9e7f221995caaaa880352feb5bd8b1faf52fae8d12c113aa123ec"
|
indexManifestDigest := "sha256:2c6b5afb967d5de02795ee1d177c3746d005df4b4c2b829385b0d186b3414b6b"
|
||||||
indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}`
|
indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","is_tagged":true,"manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}`
|
||||||
|
|
||||||
anonymousToken := ""
|
anonymousToken := ""
|
||||||
userToken := ""
|
userToken := ""
|
||||||
@@ -467,7 +467,7 @@ func TestPackageContainer(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, pv.DownloadCount)
|
assert.EqualValues(t, 1, pv.DownloadCount)
|
||||||
|
|
||||||
// Overwrite existing tag should keep the download count
|
t.Run("OverwriteTagKeepDownloadCount", func(t *testing.T) {
|
||||||
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)).
|
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)).
|
||||||
AddTokenAuth(userToken).
|
AddTokenAuth(userToken).
|
||||||
SetHeader("Content-Type", oci.MediaTypeImageManifest)
|
SetHeader("Content-Type", oci.MediaTypeImageManifest)
|
||||||
@@ -477,6 +477,7 @@ func TestPackageContainer(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, pv.DownloadCount)
|
assert.EqualValues(t, 1, pv.DownloadCount)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("HeadManifest", func(t *testing.T) {
|
t.Run("HeadManifest", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
@@ -505,7 +506,7 @@ func TestPackageContainer(t *testing.T) {
|
|||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length"))
|
assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length"))
|
||||||
assert.Equal(t, manifestContentType, resp.Header().Get("Content-Type"))
|
assert.Equal(t, oci.MediaTypeImageManifest, resp.Header().Get("Content-Type")) // the manifest is overwritten by above OverwriteTagKeepDownloadCount
|
||||||
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
|
||||||
assert.Equal(t, manifestContent, resp.Body.String())
|
assert.Equal(t, manifestContent, resp.Body.String())
|
||||||
})
|
})
|
||||||
@@ -599,6 +600,17 @@ func TestPackageContainer(t *testing.T) {
|
|||||||
assert.True(t, pd.Files[0].File.IsLead)
|
assert.True(t, pd.Files[0].File.IsLead)
|
||||||
assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType))
|
assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType))
|
||||||
assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest))
|
assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest))
|
||||||
|
|
||||||
|
lastPackageVersionID := pv.ID
|
||||||
|
t.Run("UploadAgain", func(t *testing.T) {
|
||||||
|
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, multiTag), strings.NewReader(indexManifestContent)).
|
||||||
|
AddTokenAuth(userToken).
|
||||||
|
SetHeader("Content-Type", oci.MediaTypeImageIndex)
|
||||||
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
|
pv, err := packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, multiTag)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotEqual(t, lastPackageVersionID, pv.ID)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("HeadBlob", func(t *testing.T) {
|
t.Run("HeadBlob", func(t *testing.T) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/markup/external"
|
"code.gitea.io/gitea/modules/markup/external"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@@ -25,29 +26,45 @@ import (
|
|||||||
func TestExternalMarkupRenderer(t *testing.T) {
|
func TestExternalMarkupRenderer(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
if !setting.Database.Type.IsSQLite3() {
|
if !setting.Database.Type.IsSQLite3() {
|
||||||
t.Skip()
|
t.Skip("only SQLite3 test config supports external markup renderer")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const binaryContentPrefix = "any prefix text."
|
||||||
|
const binaryContent = binaryContentPrefix + "\xfe\xfe\xfe\x00\xff\xff"
|
||||||
|
detectedEncoding, _ := charset.DetectEncoding([]byte(binaryContent))
|
||||||
|
assert.NotEqual(t, binaryContent, strings.ToValidUTF8(binaryContent, "?"))
|
||||||
|
assert.Equal(t, "ISO-8859-2", detectedEncoding) // even if the binary content can be detected as text encoding, it shouldn't affect the raw rendering
|
||||||
|
|
||||||
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
_, err := createFile(user2, repo1, "file.no-sanitizer", "master", `any content`)
|
_, err := createFileInBranch(user2, repo1, createFileInBranchOptions{}, map[string]string{
|
||||||
|
"test.html": `<div><any attr="val"><script></script></div>`,
|
||||||
|
"html.no-sanitizer": `<script>foo("raw")</script>`,
|
||||||
|
"bin.no-sanitizer": binaryContent,
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("RenderNoSanitizer", func(t *testing.T) {
|
t.Run("RenderNoSanitizer", func(t *testing.T) {
|
||||||
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/file.no-sanitizer")
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/html.no-sanitizer")
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
doc := NewHTMLParser(t, resp.Body)
|
div := NewHTMLParser(t, resp.Body).Find("div.file-view")
|
||||||
div := doc.Find("div.file-view")
|
|
||||||
data, err := div.Html()
|
data, err := div.Html()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, `<script>window.alert("hi")</script>`, strings.TrimSpace(data))
|
assert.Equal(t, `<script>foo("raw")</script>`, strings.TrimSpace(data))
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/user2/repo1/src/branch/master/bin.no-sanitizer")
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
div = NewHTMLParser(t, resp.Body).Find("div.file-view")
|
||||||
|
data, err = div.Html()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, strings.ReplaceAll(binaryContent, "\x00", ""), strings.TrimSpace(data)) // HTML template engine removes the null bytes
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("RenderContentDirectly", func(t *testing.T) {
|
t.Run("RenderContentDirectly", func(t *testing.T) {
|
||||||
req := NewRequest(t, "GET", "/user30/renderer/src/branch/master/README.html")
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/test.html")
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
assert.Equal(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
|
assert.Equal(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
|
||||||
|
|
||||||
@@ -55,18 +72,21 @@ func TestExternalMarkupRenderer(t *testing.T) {
|
|||||||
div := doc.Find("div.file-view")
|
div := doc.Find("div.file-view")
|
||||||
data, err := div.Html()
|
data, err := div.Html()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "<div>\n\ttest external renderer\n</div>", strings.TrimSpace(data))
|
// the content is fully sanitized
|
||||||
|
assert.Equal(t, `<div><script></script></div>`, strings.TrimSpace(data))
|
||||||
})
|
})
|
||||||
|
|
||||||
// above tested "no-sanitizer" mode, then we test iframe mode below
|
// above tested in-page rendering (no iframe), then we test iframe mode below
|
||||||
r := markup.GetRendererByFileName("any-file.html").(*external.Renderer)
|
r := markup.GetRendererByFileName("any-file.html").(*external.Renderer)
|
||||||
defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)()
|
defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)()
|
||||||
|
assert.True(t, r.NeedPostProcess())
|
||||||
r = markup.GetRendererByFileName("any-file.no-sanitizer").(*external.Renderer)
|
r = markup.GetRendererByFileName("any-file.no-sanitizer").(*external.Renderer)
|
||||||
defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)()
|
defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)()
|
||||||
|
assert.False(t, r.NeedPostProcess())
|
||||||
|
|
||||||
t.Run("RenderContentInIFrame", func(t *testing.T) {
|
t.Run("RenderContentInIFrame", func(t *testing.T) {
|
||||||
t.Run("DefaultSandbox", func(t *testing.T) {
|
t.Run("DefaultSandbox", func(t *testing.T) {
|
||||||
req := NewRequest(t, "GET", "/user30/renderer/src/branch/master/README.html")
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/test.html")
|
||||||
|
|
||||||
t.Run("ParentPage", func(t *testing.T) {
|
t.Run("ParentPage", func(t *testing.T) {
|
||||||
respParent := MakeRequest(t, req, http.StatusOK)
|
respParent := MakeRequest(t, req, http.StatusOK)
|
||||||
@@ -77,31 +97,42 @@ func TestExternalMarkupRenderer(t *testing.T) {
|
|||||||
|
|
||||||
// default sandbox on parent page
|
// default sandbox on parent page
|
||||||
assert.Equal(t, "allow-scripts allow-popups", iframe.AttrOr("sandbox", ""))
|
assert.Equal(t, "allow-scripts allow-popups", iframe.AttrOr("sandbox", ""))
|
||||||
assert.Equal(t, "/user30/renderer/render/branch/master/README.html", iframe.AttrOr("data-src", ""))
|
assert.Equal(t, "/user2/repo1/render/branch/master/test.html", iframe.AttrOr("data-src", ""))
|
||||||
})
|
})
|
||||||
t.Run("SubPage", func(t *testing.T) {
|
t.Run("SubPage", func(t *testing.T) {
|
||||||
req = NewRequest(t, "GET", "/user30/renderer/render/branch/master/README.html")
|
req = NewRequest(t, "GET", "/user2/repo1/render/branch/master/test.html")
|
||||||
respSub := MakeRequest(t, req, http.StatusOK)
|
respSub := MakeRequest(t, req, http.StatusOK)
|
||||||
assert.Equal(t, "text/html; charset=utf-8", respSub.Header().Get("Content-Type"))
|
assert.Equal(t, "text/html; charset=utf-8", respSub.Header().Get("Content-Type"))
|
||||||
|
|
||||||
// default sandbox in sub page response
|
// default sandbox in sub page response
|
||||||
assert.Equal(t, "frame-src 'self'; sandbox allow-scripts allow-popups", respSub.Header().Get("Content-Security-Policy"))
|
assert.Equal(t, "frame-src 'self'; sandbox allow-scripts allow-popups", respSub.Header().Get("Content-Security-Policy"))
|
||||||
assert.Equal(t, "<script src=\"/assets/js/external-render-iframe.js\"></script><link rel=\"stylesheet\" href=\"/assets/css/external-render-iframe.css\"><div>\n\ttest external renderer\n</div>\n", respSub.Body.String())
|
// FIXME: actually here is a bug (legacy design problem), the "PostProcess" will escape "<script>" tag, but it indeed is the sanitizer's job
|
||||||
|
assert.Equal(t, `<script src="/assets/js/external-render-iframe.js"></script><link rel="stylesheet" href="/assets/css/external-render-iframe.css"><div><any attr="val"><script></script></any></div>`, respSub.Body.String())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("NoSanitizerNoSandbox", func(t *testing.T) {
|
t.Run("NoSanitizerNoSandbox", func(t *testing.T) {
|
||||||
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/file.no-sanitizer")
|
t.Run("BinaryContent", func(t *testing.T) {
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/bin.no-sanitizer")
|
||||||
respParent := MakeRequest(t, req, http.StatusOK)
|
respParent := MakeRequest(t, req, http.StatusOK)
|
||||||
iframe := NewHTMLParser(t, respParent.Body).Find("iframe.external-render-iframe")
|
iframe := NewHTMLParser(t, respParent.Body).Find("iframe.external-render-iframe")
|
||||||
assert.Equal(t, "/user2/repo1/render/branch/master/file.no-sanitizer", iframe.AttrOr("data-src", ""))
|
assert.Equal(t, "/user2/repo1/render/branch/master/bin.no-sanitizer", iframe.AttrOr("data-src", ""))
|
||||||
|
|
||||||
req = NewRequest(t, "GET", "/user2/repo1/render/branch/master/file.no-sanitizer")
|
req = NewRequest(t, "GET", "/user2/repo1/render/branch/master/bin.no-sanitizer")
|
||||||
respSub := MakeRequest(t, req, http.StatusOK)
|
respSub := MakeRequest(t, req, http.StatusOK)
|
||||||
|
assert.Equal(t, binaryContent, respSub.Body.String()) // raw content should keep the raw bytes (including invalid UTF-8 bytes), and no "external-render-iframe" helpers
|
||||||
|
|
||||||
// no sandbox (disabled by RENDER_CONTENT_SANDBOX)
|
// no sandbox (disabled by RENDER_CONTENT_SANDBOX)
|
||||||
assert.Empty(t, iframe.AttrOr("sandbox", ""))
|
assert.Empty(t, iframe.AttrOr("sandbox", ""))
|
||||||
assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy"))
|
assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("HTMLContentWithExternalRenderIframeHelper", func(t *testing.T) {
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/render/branch/master/html.no-sanitizer")
|
||||||
|
respSub := MakeRequest(t, req, http.StatusOK)
|
||||||
|
assert.Equal(t, `<script src="/assets/js/external-render-iframe.js"></script><link rel="stylesheet" href="/assets/css/external-render-iframe.css"><script>foo("raw")</script>`, respSub.Body.String())
|
||||||
|
assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy"))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -919,9 +919,10 @@ func TestOAuth_GrantScopesClaimAllGroups(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testOAuth2WellKnown(t *testing.T) {
|
func testOAuth2WellKnown(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.AppURL, "https://try.gitea.io/")()
|
||||||
urlOpenidConfiguration := "/.well-known/openid-configuration"
|
urlOpenidConfiguration := "/.well-known/openid-configuration"
|
||||||
|
|
||||||
defer test.MockVariableValue(&setting.AppURL, "https://try.gitea.io/")()
|
t.Run("WellKnown", func(t *testing.T) {
|
||||||
req := NewRequest(t, "GET", urlOpenidConfiguration)
|
req := NewRequest(t, "GET", urlOpenidConfiguration)
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
var respMap map[string]any
|
var respMap map[string]any
|
||||||
@@ -933,6 +934,17 @@ func testOAuth2WellKnown(t *testing.T) {
|
|||||||
assert.Equal(t, "https://try.gitea.io/login/oauth/userinfo", respMap["userinfo_endpoint"])
|
assert.Equal(t, "https://try.gitea.io/login/oauth/userinfo", respMap["userinfo_endpoint"])
|
||||||
assert.Equal(t, "https://try.gitea.io/login/oauth/introspect", respMap["introspection_endpoint"])
|
assert.Equal(t, "https://try.gitea.io/login/oauth/introspect", respMap["introspection_endpoint"])
|
||||||
assert.Equal(t, []any{"RS256"}, respMap["id_token_signing_alg_values_supported"])
|
assert.Equal(t, []any{"RS256"}, respMap["id_token_signing_alg_values_supported"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("WellKnownWithIssuer", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.OAuth2.JWTClaimIssuer, "https://try.gitea.io/")()
|
||||||
|
req := NewRequest(t, "GET", urlOpenidConfiguration)
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
var respMap map[string]any
|
||||||
|
DecodeJSON(t, resp, &respMap)
|
||||||
|
assert.Equal(t, "https://try.gitea.io/", respMap["issuer"]) // has trailing by JWTClaimIssuer
|
||||||
|
assert.Equal(t, "https://try.gitea.io/login/oauth/authorize", respMap["authorization_endpoint"])
|
||||||
|
})
|
||||||
|
|
||||||
defer test.MockVariableValue(&setting.OAuth2.Enabled, false)()
|
defer test.MockVariableValue(&setting.OAuth2.Enabled, false)()
|
||||||
MakeRequest(t, NewRequest(t, "GET", urlOpenidConfiguration), http.StatusNotFound)
|
MakeRequest(t, NewRequest(t, "GET", urlOpenidConfiguration), http.StatusNotFound)
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ RENDER_CONTENT_MODE = sanitized
|
|||||||
[markup.no-sanitizer]
|
[markup.no-sanitizer]
|
||||||
ENABLED = true
|
ENABLED = true
|
||||||
FILE_EXTENSIONS = .no-sanitizer
|
FILE_EXTENSIONS = .no-sanitizer
|
||||||
RENDER_COMMAND = echo '<script>window.alert("hi")</script>'
|
RENDER_COMMAND = go run build/test-echo.go
|
||||||
; This test case is reused, at first it is used to test "no-sanitizer" (sandbox doesn't take effect here)
|
; This test case is reused, at first it is used to test "no-sanitizer" (sandbox doesn't take effect here)
|
||||||
; Then it will be updated and used to test "iframe + sandbox-disabled"
|
; Then it will be updated and used to test "iframe + sandbox-disabled"
|
||||||
RENDER_CONTENT_MODE = no-sanitizer
|
RENDER_CONTENT_MODE = no-sanitizer
|
||||||
|
|||||||
@@ -626,7 +626,6 @@ img.ui.avatar,
|
|||||||
font-family: var(--fonts-monospace);
|
font-family: var(--fonts-monospace);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
padding: 3px 5px;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,44 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* before the Vue component is mounted, show a loading indicator with dummy size */
|
.activity-heatmap-container {
|
||||||
/* the ratio is guesswork, see https://github.com/razorness/vue3-calendar-heatmap/issues/26 */
|
container-type: inline-size;
|
||||||
#user-heatmap.is-loading {
|
|
||||||
aspect-ratio: 5.415; /* the size is about 790 x 145 */
|
|
||||||
}
|
}
|
||||||
.user.profile #user-heatmap.is-loading {
|
|
||||||
aspect-ratio: 5.645; /* the size is about 953 x 169 */
|
@container (width > 0) {
|
||||||
|
#user-heatmap {
|
||||||
|
/* Set element to fixed height so that it does not resize after load. The calculation is complex
|
||||||
|
because the element does not scale with a fixed aspect ratio. */
|
||||||
|
height: calc((100cqw / 5) - (100cqw / 25) + 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fallback height adjustment above for browsers that don't support container queries */
|
||||||
|
@supports not (container-type: inline-size) {
|
||||||
|
/* Before the Vue component is mounted, show a loading indicator with dummy size */
|
||||||
|
/* The ratio is guesswork for legacy browsers, new browsers use the "@container" approach above */
|
||||||
|
#user-heatmap.is-loading {
|
||||||
|
aspect-ratio: 5.4823972051; /* the size is about 816 x 148.84 */
|
||||||
|
}
|
||||||
|
.user.profile #user-heatmap.is-loading {
|
||||||
|
aspect-ratio: 5.6290608387; /* the size is about 953 x 169.3 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#user-heatmap text {
|
#user-heatmap text {
|
||||||
fill: currentcolor !important;
|
fill: currentcolor !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* root legend */
|
||||||
|
#user-heatmap .vch__container > .vch__legend {
|
||||||
|
display: flex;
|
||||||
|
font-size: 11px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
/* for the "Less" and "More" legend */
|
/* for the "Less" and "More" legend */
|
||||||
#user-heatmap .vch__legend .vch__legend {
|
#user-heatmap .vch__legend .vch__legend {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 11px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: right;
|
justify-content: right;
|
||||||
}
|
}
|
||||||
@@ -34,25 +55,3 @@
|
|||||||
#user-heatmap .vch__day__square:hover {
|
#user-heatmap .vch__day__square:hover {
|
||||||
outline: 1.5px solid var(--color-text);
|
outline: 1.5px solid var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move the "? contributions in the last ? months" text from top to bottom */
|
|
||||||
#user-heatmap .total-contributions {
|
|
||||||
font-size: 11px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
#user-heatmap .total-contributions {
|
|
||||||
left: 21px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
#user-heatmap .total-contributions {
|
|
||||||
font-size: 10px;
|
|
||||||
left: 17px;
|
|
||||||
bottom: -4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -387,6 +387,7 @@ td .commit-summary {
|
|||||||
|
|
||||||
.repository.view.issue .pull-desc code {
|
.repository.view.issue .pull-desc code {
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.repository.view.issue .pull-desc a[data-clipboard-text] {
|
.repository.view.issue .pull-desc a[data-clipboard-text] {
|
||||||
|
|||||||
@@ -53,9 +53,6 @@ function handleDayClick(e: Event & {date: Date}) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="total-contributions">
|
|
||||||
{{ locale.textTotalContributions }}
|
|
||||||
</div>
|
|
||||||
<calendar-heatmap
|
<calendar-heatmap
|
||||||
:locale="locale.heatMapLocale"
|
:locale="locale.heatMapLocale"
|
||||||
:no-data-text="locale.noDataText"
|
:no-data-text="locale.noDataText"
|
||||||
@@ -65,5 +62,7 @@ function handleDayClick(e: Event & {date: Date}) {
|
|||||||
:range-color="colorRange"
|
:range-color="colorRange"
|
||||||
@day-click="handleDayClick($event)"
|
@day-click="handleDayClick($event)"
|
||||||
:tippy-props="{theme: 'tooltip'}"
|
:tippy-props="{theme: 'tooltip'}"
|
||||||
/>
|
>
|
||||||
|
<template #vch__legend-left>{{ locale.textTotalContributions }}</template>
|
||||||
|
</calendar-heatmap>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import './globals.ts';
|
|
||||||
import '../fomantic/build/fomantic.js';
|
import '../fomantic/build/fomantic.js';
|
||||||
import '../../node_modules/easymde/dist/easymde.min.css'; // TODO: lazy load in "switchToEasyMDE"
|
import '../../node_modules/easymde/dist/easymde.min.css'; // TODO: lazy load in "switchToEasyMDE"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
// bootstrap module must be the first one to be imported, it handles webpack lazy-loading and global errors
|
// bootstrap module must be the first one to be imported, it handles webpack lazy-loading and global errors
|
||||||
import './bootstrap.ts';
|
import './bootstrap.ts';
|
||||||
|
|
||||||
|
// many users expect to use jQuery in their custom scripts (https://docs.gitea.com/administration/customizing-gitea#example-plantuml)
|
||||||
|
// so load globals (including jQuery) as early as possible
|
||||||
|
import './globals.ts';
|
||||||
|
|
||||||
import './webcomponents/index.ts';
|
import './webcomponents/index.ts';
|
||||||
import {onDomReady} from './utils/dom.ts';
|
import {onDomReady} from './utils/dom.ts';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user