mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-05 04:56:02 +01:00
Add option to disallow WebHook to private addresses (#2397)
This commit is contained in:
@@ -42,6 +42,7 @@ libraryDependencies ++= Seq(
|
||||
"io.github.gitbucket" % "markedj" % "1.0.16",
|
||||
"org.apache.commons" % "commons-compress" % "1.19",
|
||||
"org.apache.commons" % "commons-email" % "1.5",
|
||||
"commons-net" % "commons-net" % "3.6",
|
||||
"org.apache.httpcomponents" % "httpclient" % "4.5.10",
|
||||
"org.apache.sshd" % "apache-sshd" % "2.1.0" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
||||
"org.apache.tika" % "tika-core" % "1.23",
|
||||
|
||||
@@ -526,7 +526,8 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
WebHookPushPayload.createDummyPayload(ownerAccount)
|
||||
}
|
||||
|
||||
val (webHook, json, reqFuture, resFuture) = callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload).head
|
||||
val (webHook, json, reqFuture, resFuture) =
|
||||
callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload, context.settings).head
|
||||
|
||||
val toErrorMap: PartialFunction[Throwable, Map[String, String]] = {
|
||||
case e: java.net.UnknownHostException => Map("error" -> ("Unknown host " + e.getMessage))
|
||||
|
||||
@@ -324,13 +324,14 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
pullreq.branch,
|
||||
loginAccount,
|
||||
s"Merge branch '${alias}' into ${pullreq.requestBranch}",
|
||||
Some(pullreq)
|
||||
Some(pullreq),
|
||||
context.settings
|
||||
) match {
|
||||
case None => // conflict
|
||||
flash.update("error", s"Can't automatic merging branch '${alias}' into ${pullreq.requestBranch}.")
|
||||
case Some(oldId) =>
|
||||
// update pull request
|
||||
updatePullRequests(owner, name, pullreq.requestBranch, loginAccount, "synchronize")
|
||||
updatePullRequests(owner, name, pullreq.requestBranch, loginAccount, "synchronize", context.settings)
|
||||
flash.update("info", s"Merge branch '${alias}' into ${pullreq.requestBranch}")
|
||||
}
|
||||
}
|
||||
@@ -357,7 +358,15 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val owner = repository.owner
|
||||
val name = repository.name
|
||||
|
||||
mergePullRequest(repository, issueId, context.loginAccount.get, form.message, form.strategy, form.isDraft) match {
|
||||
mergePullRequest(
|
||||
repository,
|
||||
issueId,
|
||||
context.loginAccount.get,
|
||||
form.message,
|
||||
form.strategy,
|
||||
form.isDraft,
|
||||
context.settings
|
||||
) match {
|
||||
case Right(objectId) => redirect(s"/${owner}/${name}/pull/${issueId}")
|
||||
case Left(message) => Some(BadRequest(message))
|
||||
}
|
||||
@@ -558,7 +567,8 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
commitIdFrom = form.commitIdFrom,
|
||||
commitIdTo = form.commitIdTo,
|
||||
isDraft = form.isDraft,
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
|
||||
// insert labels
|
||||
|
||||
@@ -294,7 +294,8 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
)
|
||||
}
|
||||
|
||||
val (webHook, json, reqFuture, resFuture) = callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload).head
|
||||
val (webHook, json, reqFuture, resFuture) =
|
||||
callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload, context.settings).head
|
||||
|
||||
val toErrorMap: PartialFunction[Throwable, Map[String, String]] = {
|
||||
case e: java.net.UnknownHostException => Map("error" -> ("Unknown host " + e.getMessage))
|
||||
|
||||
@@ -354,7 +354,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
path = form.path,
|
||||
files = files.toIndexedSeq,
|
||||
message = form.message.getOrElse("Add files via upload"),
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
) {
|
||||
case (git, headTip, builder, inserter) =>
|
||||
JGitUtil.processTree(git, headTip) { (path, tree) =>
|
||||
@@ -441,7 +442,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
charset = form.charset,
|
||||
message = form.message.getOrElse(s"Create ${form.newFileName}"),
|
||||
commit = form.commit,
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
|
||||
redirect(
|
||||
@@ -465,7 +467,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
form.message.getOrElse(s"Rename ${form.oldFileName.get} to ${form.newFileName}")
|
||||
},
|
||||
commit = form.commit,
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
|
||||
redirect(
|
||||
@@ -485,7 +488,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
charset = "",
|
||||
message = form.message.getOrElse(s"Delete ${form.fileName}"),
|
||||
commit = form.commit,
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
|
||||
redirect(
|
||||
|
||||
@@ -90,17 +90,11 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
)(OIDC.apply)
|
||||
),
|
||||
"skinName" -> trim(label("AdminLTE skin name", text(required))),
|
||||
"showMailAddress" -> trim(label("Show mail address", boolean())) //,
|
||||
// "pluginNetworkInstall" -> trim(label("Network plugin installation", boolean())),
|
||||
// "proxy" -> optionalIfNotChecked(
|
||||
// "useProxy",
|
||||
// mapping(
|
||||
// "host" -> trim(label("Proxy host", text(required))),
|
||||
// "port" -> trim(label("Proxy port", number())),
|
||||
// "user" -> trim(label("Keystore", optional(text()))),
|
||||
// "password" -> trim(label("Keystore", optional(text())))
|
||||
// )(Proxy.apply)
|
||||
// )
|
||||
"showMailAddress" -> trim(label("Show mail address", boolean())),
|
||||
"webhook" -> mapping(
|
||||
"blockPrivateAddress" -> trim(label("Block private address", boolean())),
|
||||
"whitelist" -> trim(label("Whitelist", multiLineText()))
|
||||
)(WebHook.apply)
|
||||
)(SystemSettings.apply).verifying { settings =>
|
||||
Vector(
|
||||
if (settings.ssh.enabled && settings.baseUrl.isEmpty) {
|
||||
@@ -524,6 +518,17 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
()
|
||||
})
|
||||
|
||||
private def multiLineText(constraints: Constraint*): SingleValueType[Seq[String]] =
|
||||
new SingleValueType[Seq[String]](constraints: _*) {
|
||||
def convert(value: String, messages: Messages): Seq[String] = {
|
||||
if (value == null) {
|
||||
Nil
|
||||
} else {
|
||||
value.split("\n").toIndexedSeq.map(_.trim)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def members: Constraint = new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
||||
if (value.split(",").exists {
|
||||
|
||||
@@ -191,7 +191,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
form.pageName,
|
||||
commitId
|
||||
)
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum, context.settings) {
|
||||
getAccountByUserName(repository.owner).map { repositoryUser =>
|
||||
WebHookGollumPayload("edited", form.pageName, commitId, repository, repositoryUser, loginAccount)
|
||||
}
|
||||
@@ -229,7 +229,7 @@ trait WikiControllerBase extends ControllerBase {
|
||||
commitId =>
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
recordCreateWikiPageActivity(repository.owner, repository.name, loginAccount.userName, form.pageName)
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum, context.settings) {
|
||||
getAccountByUserName(repository.owner).map { repositoryUser =>
|
||||
WebHookGollumPayload("created", form.pageName, commitId, repository, repositoryUser, loginAccount)
|
||||
}
|
||||
|
||||
@@ -115,7 +115,8 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
commitIdFrom = commitIdFrom.getName,
|
||||
commitIdTo = commitIdTo.getName,
|
||||
isDraft = false,
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
getApiPullRequest(repository, issueId).map(JsonFormat(_))
|
||||
case _ =>
|
||||
@@ -143,7 +144,8 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
commitIdFrom = commitIdFrom.getName,
|
||||
commitIdTo = commitIdTo.getName,
|
||||
isDraft = false,
|
||||
loginAccount = context.loginAccount.get
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
getApiPullRequest(repository, createPullReqAlt.issue).map(JsonFormat(_))
|
||||
case _ =>
|
||||
|
||||
@@ -127,17 +127,14 @@ trait ApiRepositoryContentsControllerBase extends ControllerBase {
|
||||
branch,
|
||||
path,
|
||||
Some(paths.last),
|
||||
if (data.sha.isDefined) {
|
||||
Some(paths.last)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
data.sha.map(_ => paths.last),
|
||||
StringUtil.base64Decode(data.content),
|
||||
data.message,
|
||||
commit,
|
||||
context.loginAccount.get,
|
||||
data.committer.map(_.name).getOrElse(context.loginAccount.get.fullName),
|
||||
data.committer.map(_.email).getOrElse(context.loginAccount.get.mailAddress)
|
||||
data.committer.map(_.email).getOrElse(context.loginAccount.get.mailAddress),
|
||||
context.settings
|
||||
)
|
||||
ApiContents("file", paths.last, path, objectId.name, None, None)(RepositoryName(repository))
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ trait CommitsService {
|
||||
repository,
|
||||
issue,
|
||||
pullRequest,
|
||||
loginAccount
|
||||
loginAccount,
|
||||
context.settings
|
||||
)
|
||||
}
|
||||
case None =>
|
||||
|
||||
@@ -80,16 +80,17 @@ trait HandleCommentService {
|
||||
|
||||
// call web hooks
|
||||
action match {
|
||||
case None => commentId foreach (callIssueCommentWebHook(repository, issue, _, loginAccount))
|
||||
case None =>
|
||||
commentId foreach (callIssueCommentWebHook(repository, issue, _, loginAccount, context.settings))
|
||||
case Some(act) =>
|
||||
val webHookAction = act match {
|
||||
case "close" => "closed"
|
||||
case "reopen" => "reopened"
|
||||
}
|
||||
if (issue.isPullRequest)
|
||||
callPullRequestWebHook(webHookAction, repository, issue.issueId, loginAccount)
|
||||
callPullRequestWebHook(webHookAction, repository, issue.issueId, loginAccount, context.settings)
|
||||
else
|
||||
callIssuesWebHook(webHookAction, repository, issue, loginAccount)
|
||||
callIssuesWebHook(webHookAction, repository, issue, loginAccount, context.settings)
|
||||
}
|
||||
|
||||
// call hooks
|
||||
|
||||
@@ -57,7 +57,7 @@ trait IssueCreationService {
|
||||
createReferComment(owner, name, issue, title + " " + body.getOrElse(""), loginAccount)
|
||||
|
||||
// call web hooks
|
||||
callIssuesWebHook("opened", repository, issue, loginAccount)
|
||||
callIssuesWebHook("opened", repository, issue, loginAccount, context.settings)
|
||||
|
||||
// call hooks
|
||||
PluginRegistry().getIssueHooks.foreach(_.created(issue, repository))
|
||||
|
||||
@@ -8,6 +8,7 @@ import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.{JGitUtil, LockUtil}
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
import org.eclipse.jgit.merge.{MergeStrategy, Merger, RecursiveMerger}
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.transport.RefSpec
|
||||
@@ -167,7 +168,8 @@ trait MergeService {
|
||||
remoteBranch: String,
|
||||
loginAccount: Account,
|
||||
message: String,
|
||||
pullreq: Option[PullRequest]
|
||||
pullreq: Option[PullRequest],
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): Option[ObjectId] = {
|
||||
val localUserName = localRepository.owner
|
||||
val localRepositoryName = localRepository.name
|
||||
@@ -212,7 +214,7 @@ trait MergeService {
|
||||
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, localUserName, localRepositoryName)
|
||||
.foreach { issueId =>
|
||||
getIssue(localRepository.owner, localRepository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", localRepository, issue, loginAccount)
|
||||
callIssuesWebHook("closed", localRepository, issue, loginAccount, settings)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(
|
||||
_.closedByCommitComment(issue, localRepository, commit.fullMessage, loginAccount)
|
||||
@@ -223,7 +225,7 @@ trait MergeService {
|
||||
}
|
||||
|
||||
pullreq.foreach { pullreq =>
|
||||
callWebHookOf(localRepository.owner, localRepository.name, WebHook.Push) {
|
||||
callWebHookOf(localRepository.owner, localRepository.name, WebHook.Push, settings) {
|
||||
for {
|
||||
ownerAccount <- getAccountByUserName(localRepository.owner)
|
||||
} yield {
|
||||
@@ -251,7 +253,8 @@ trait MergeService {
|
||||
loginAccount: Account,
|
||||
message: String,
|
||||
strategy: String,
|
||||
isDraft: Boolean
|
||||
isDraft: Boolean,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context, context: Context): Either[String, ObjectId] = {
|
||||
if (!isDraft) {
|
||||
if (repository.repository.options.mergeOptions.split(",").contains(strategy)) {
|
||||
@@ -333,7 +336,7 @@ trait MergeService {
|
||||
repository.name
|
||||
).foreach { issueId =>
|
||||
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount, context.settings)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(_.closedByCommitComment(issue, repository, commit.fullMessage, loginAccount))
|
||||
}
|
||||
@@ -347,7 +350,7 @@ trait MergeService {
|
||||
repository.name
|
||||
).foreach { issueId =>
|
||||
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount, context.settings)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(_.closedByCommitComment(issue, repository, issueContent, loginAccount))
|
||||
}
|
||||
@@ -355,16 +358,23 @@ trait MergeService {
|
||||
closeIssuesFromMessage(message, loginAccount.userName, repository.owner, repository.name)
|
||||
.foreach { issueId =>
|
||||
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount, context.settings)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(_.closedByCommitComment(issue, repository, issueContent, loginAccount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callPullRequestWebHook("closed", repository, issueId, context.loginAccount.get)
|
||||
callPullRequestWebHook("closed", repository, issueId, context.loginAccount.get, context.settings)
|
||||
|
||||
updatePullRequests(repository.owner, repository.name, pullreq.branch, loginAccount, "closed")
|
||||
updatePullRequests(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.branch,
|
||||
loginAccount,
|
||||
"closed",
|
||||
settings
|
||||
)
|
||||
|
||||
// call hooks
|
||||
PluginRegistry().getPullRequestHooks.foreach { h =>
|
||||
|
||||
@@ -8,6 +8,7 @@ import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.api.JsonFormat
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.JGitUtil
|
||||
@@ -106,7 +107,8 @@ trait PullRequestService {
|
||||
commitIdFrom: String,
|
||||
commitIdTo: String,
|
||||
isDraft: Boolean,
|
||||
loginAccount: Account
|
||||
loginAccount: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, context: Context): Unit = {
|
||||
getIssue(originRepository.owner, originRepository.name, issueId.toString).foreach { baseIssue =>
|
||||
PullRequests insert PullRequest(
|
||||
@@ -142,7 +144,7 @@ trait PullRequestService {
|
||||
)
|
||||
|
||||
// call web hook
|
||||
callPullRequestWebHook("opened", originRepository, issueId, loginAccount)
|
||||
callPullRequestWebHook("opened", originRepository, issueId, loginAccount, settings)
|
||||
|
||||
getIssue(originRepository.owner, originRepository.name, issueId.toString) foreach { issue =>
|
||||
// extract references and create refer comment
|
||||
@@ -226,7 +228,14 @@ trait PullRequestService {
|
||||
/**
|
||||
* Fetch pull request contents into refs/pull/${issueId}/head and update pull request table.
|
||||
*/
|
||||
def updatePullRequests(owner: String, repository: String, branch: String, loginAccount: Account, action: String)(
|
||||
def updatePullRequests(
|
||||
owner: String,
|
||||
repository: String,
|
||||
branch: String,
|
||||
loginAccount: Account,
|
||||
action: String,
|
||||
settings: SystemSettings
|
||||
)(
|
||||
implicit s: Session,
|
||||
c: JsonFormat.Context
|
||||
): Unit = {
|
||||
@@ -275,7 +284,8 @@ trait PullRequestService {
|
||||
action,
|
||||
getRepository(owner, repository).get,
|
||||
pullreq.requestBranch,
|
||||
loginAccount
|
||||
loginAccount,
|
||||
settings
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import gitbucket.core.model.{Account, WebHook}
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
import gitbucket.core.service.WebHookService.WebHookPushPayload
|
||||
import gitbucket.core.util.Directory.getRepositoryDir
|
||||
import gitbucket.core.util.JGitUtil.CommitInfo
|
||||
@@ -12,6 +13,7 @@ import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
|
||||
import org.eclipse.jgit.lib._
|
||||
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||
|
||||
import scala.util.Using
|
||||
|
||||
trait RepositoryCommitFileService {
|
||||
@@ -24,12 +26,13 @@ trait RepositoryCommitFileService {
|
||||
branch: String,
|
||||
path: String,
|
||||
message: String,
|
||||
loginAccount: Account
|
||||
loginAccount: Account,
|
||||
settings: SystemSettings
|
||||
)(
|
||||
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
|
||||
)(implicit s: Session, c: JsonFormat.Context) = {
|
||||
// prepend path to the filename
|
||||
_commitFile(repository, branch, message, loginAccount, loginAccount.fullName, loginAccount.mailAddress)(f)
|
||||
_commitFile(repository, branch, message, loginAccount, loginAccount.fullName, loginAccount.mailAddress, settings)(f)
|
||||
}
|
||||
|
||||
def commitFile(
|
||||
@@ -42,7 +45,8 @@ trait RepositoryCommitFileService {
|
||||
charset: String,
|
||||
message: String,
|
||||
commit: String,
|
||||
loginAccount: Account
|
||||
loginAccount: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): ObjectId = {
|
||||
commitFile(
|
||||
repository,
|
||||
@@ -55,7 +59,8 @@ trait RepositoryCommitFileService {
|
||||
commit,
|
||||
loginAccount,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress
|
||||
loginAccount.mailAddress,
|
||||
settings
|
||||
)
|
||||
}
|
||||
|
||||
@@ -70,7 +75,8 @@ trait RepositoryCommitFileService {
|
||||
commit: String,
|
||||
loginAccount: Account,
|
||||
fullName: String,
|
||||
mailAddress: String
|
||||
mailAddress: String,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): ObjectId = {
|
||||
|
||||
val newPath = newFileName.map { newFileName =>
|
||||
@@ -80,7 +86,7 @@ trait RepositoryCommitFileService {
|
||||
if (path.length == 0) oldFileName else s"${path}/${oldFileName}"
|
||||
}
|
||||
|
||||
_commitFile(repository, branch, message, loginAccount, fullName, mailAddress) {
|
||||
_commitFile(repository, branch, message, loginAccount, fullName, mailAddress, settings) {
|
||||
case (git, headTip, builder, inserter) =>
|
||||
if (headTip.getName == commit) {
|
||||
val permission = JGitUtil
|
||||
@@ -111,7 +117,8 @@ trait RepositoryCommitFileService {
|
||||
message: String,
|
||||
loginAccount: Account,
|
||||
committerName: String,
|
||||
committerMailAddress: String
|
||||
committerMailAddress: String,
|
||||
settings: SystemSettings
|
||||
)(
|
||||
f: (Git, ObjectId, DirCacheBuilder, ObjectInserter) => Unit
|
||||
)(implicit s: Session, c: JsonFormat.Context): ObjectId = {
|
||||
@@ -165,7 +172,7 @@ trait RepositoryCommitFileService {
|
||||
refUpdate.update()
|
||||
|
||||
// update pull request
|
||||
updatePullRequests(repository.owner, repository.name, branch, loginAccount, "synchronize")
|
||||
updatePullRequests(repository.owner, repository.name, branch, loginAccount, "synchronize", settings)
|
||||
|
||||
// record activity
|
||||
val commitInfo = new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||
@@ -178,7 +185,7 @@ trait RepositoryCommitFileService {
|
||||
if (branch == repository.repository.defaultBranch) {
|
||||
closeIssuesFromMessage(message, committerName, repository.owner, repository.name).foreach { issueId =>
|
||||
getIssue(repository.owner, repository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount)
|
||||
callIssuesWebHook("closed", repository, issue, loginAccount, settings)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(_.closedByCommitComment(issue, repository, message, loginAccount))
|
||||
}
|
||||
@@ -191,7 +198,7 @@ trait RepositoryCommitFileService {
|
||||
}
|
||||
|
||||
val commit = new JGitUtil.CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Push) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Push, settings) {
|
||||
getAccountByUserName(repository.owner).map { ownerAccount =>
|
||||
WebHookPushPayload(
|
||||
git,
|
||||
|
||||
@@ -70,6 +70,8 @@ trait SystemSettingsService {
|
||||
}
|
||||
props.setProperty(SkinName, settings.skinName.toString)
|
||||
props.setProperty(ShowMailAddress, settings.showMailAddress.toString)
|
||||
props.setProperty(WebHookBlockPrivateAddress, settings.webHook.blockPrivateAddress.toString)
|
||||
props.setProperty(WebHookWhitelist, settings.webHook.whitelist.mkString("\n"))
|
||||
|
||||
Using.resource(new java.io.FileOutputStream(GitBucketConf)) { out =>
|
||||
props.store(out, null)
|
||||
@@ -146,7 +148,8 @@ trait SystemSettingsService {
|
||||
None
|
||||
},
|
||||
getValue(props, SkinName, "skin-blue"),
|
||||
getValue(props, ShowMailAddress, false)
|
||||
getValue(props, ShowMailAddress, false),
|
||||
WebHook(getValue(props, WebHookBlockPrivateAddress, false), getSeqValue(props, WebHookWhitelist, ""))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -175,7 +178,8 @@ object SystemSettingsService {
|
||||
oidcAuthentication: Boolean,
|
||||
oidc: Option[OIDC],
|
||||
skinName: String,
|
||||
showMailAddress: Boolean
|
||||
showMailAddress: Boolean,
|
||||
webHook: WebHook
|
||||
) {
|
||||
|
||||
def baseUrl(request: HttpServletRequest): String =
|
||||
@@ -252,7 +256,7 @@ object SystemSettingsService {
|
||||
|
||||
case class SshAddress(host: String, port: Int, genericUser: String)
|
||||
|
||||
case class Lfs(serverUrl: Option[String])
|
||||
case class WebHook(blockPrivateAddress: Boolean, whitelist: Seq[String])
|
||||
|
||||
val DefaultSshPort = 29418
|
||||
val DefaultSmtpPort = 25
|
||||
@@ -303,6 +307,8 @@ object SystemSettingsService {
|
||||
private val PluginProxyPort = "plugin.proxy.port"
|
||||
private val PluginProxyUser = "plugin.proxy.user"
|
||||
private val PluginProxyPassword = "plugin.proxy.password"
|
||||
private val WebHookBlockPrivateAddress = "webhook.block_private_address"
|
||||
private val WebHookWhitelist = "webhook.whitelist"
|
||||
|
||||
private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = {
|
||||
getConfigValue(key).getOrElse {
|
||||
@@ -316,6 +322,16 @@ object SystemSettingsService {
|
||||
}
|
||||
}
|
||||
|
||||
private def getSeqValue[A: ClassTag](props: java.util.Properties, key: String, default: A): Seq[A] = {
|
||||
getValue[String](props, key, "").split("\n").toIndexedSeq.map { value =>
|
||||
if (value == null || value.isEmpty) {
|
||||
default
|
||||
} else {
|
||||
convertType(value).asInstanceOf[A]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def getOptionValue[A: ClassTag](props: java.util.Properties, key: String, default: Option[A]): Option[A] = {
|
||||
getConfigValue(key).orElse {
|
||||
defining(props.getProperty(key)) { value =>
|
||||
|
||||
@@ -3,24 +3,26 @@ package gitbucket.core.service
|
||||
import fr.brouillard.oss.security.xhub.XHub
|
||||
import fr.brouillard.oss.security.xhub.XHub.{XHubConverter, XHubDigest}
|
||||
import gitbucket.core.api._
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.{
|
||||
Account,
|
||||
AccountWebHook,
|
||||
AccountWebHookEvent,
|
||||
CommitComment,
|
||||
Issue,
|
||||
IssueComment,
|
||||
Label,
|
||||
PullRequest,
|
||||
WebHook,
|
||||
RepositoryWebHook,
|
||||
RepositoryWebHookEvent,
|
||||
AccountWebHook,
|
||||
AccountWebHookEvent
|
||||
WebHook
|
||||
}
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import org.apache.http.client.utils.URLEncodedUtils
|
||||
import gitbucket.core.util.JGitUtil.CommitInfo
|
||||
import gitbucket.core.util.{RepositoryName, StringUtil}
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.{HttpClientUtil, RepositoryName, StringUtil}
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import org.apache.http.NameValuePair
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity
|
||||
@@ -34,6 +36,7 @@ import scala.util.{Failure, Success}
|
||||
import org.apache.http.HttpRequest
|
||||
import org.apache.http.HttpResponse
|
||||
import gitbucket.core.model.WebHookContentType
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
import org.apache.http.client.entity.EntityBuilder
|
||||
import org.apache.http.entity.ContentType
|
||||
|
||||
@@ -201,20 +204,28 @@ trait WebHookService {
|
||||
def deleteAccountWebHook(owner: String, url: String)(implicit s: Session): Unit =
|
||||
AccountWebHooks.filter(_.byPrimaryKey(owner, url)).delete
|
||||
|
||||
def callWebHookOf(owner: String, repository: String, event: WebHook.Event)(
|
||||
def callWebHookOf(owner: String, repository: String, event: WebHook.Event, settings: SystemSettings)(
|
||||
makePayload: => Option[WebHookPayload]
|
||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||
val webHooks = getWebHooksByEvent(owner, repository, event)
|
||||
if (webHooks.nonEmpty) {
|
||||
makePayload.map(callWebHook(event, webHooks, _))
|
||||
makePayload.map(callWebHook(event, webHooks, _, settings))
|
||||
}
|
||||
val accountWebHooks = getAccountWebHooksByEvent(owner, event)
|
||||
if (accountWebHooks.nonEmpty) {
|
||||
makePayload.map(callWebHook(event, accountWebHooks, _))
|
||||
makePayload.map(callWebHook(event, accountWebHooks, _, settings))
|
||||
}
|
||||
}
|
||||
|
||||
def callWebHook(event: WebHook.Event, webHooks: List[WebHook], payload: WebHookPayload)(
|
||||
private def validateTargetAddress(settings: SystemSettings, url: String): Boolean = {
|
||||
val host = new java.net.URL(url).getHost
|
||||
|
||||
!settings.webHook.blockPrivateAddress ||
|
||||
!HttpClientUtil.isPrivateAddress(host) ||
|
||||
settings.webHook.whitelist.exists(range => HttpClientUtil.inIpRange(range, host))
|
||||
}
|
||||
|
||||
def callWebHook(event: WebHook.Event, webHooks: List[WebHook], payload: WebHookPayload, settings: SystemSettings)(
|
||||
implicit c: JsonFormat.Context
|
||||
): List[(WebHook, String, Future[HttpRequest], Future[HttpResponse])] = {
|
||||
import org.apache.http.impl.client.HttpClientBuilder
|
||||
@@ -234,6 +245,9 @@ trait WebHookService {
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!validateTargetAddress(settings, webHook.url)) {
|
||||
throw new IllegalArgumentException(s"Illegal address: ${webHook.url}")
|
||||
}
|
||||
val httpClient = HttpClientBuilder.create.useSystemProperties.addInterceptorLast(itcp).build
|
||||
logger.debug(s"start web hook invocation for ${webHook.url}")
|
||||
val httpPost = new HttpPost(webHook.url)
|
||||
@@ -302,7 +316,6 @@ trait WebHookService {
|
||||
} else {
|
||||
Nil
|
||||
}
|
||||
// logger.debug("end callWebHook")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,9 +328,10 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
action: String,
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
issue: Issue,
|
||||
sender: Account
|
||||
sender: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, context: JsonFormat.Context): Unit = {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Issues) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Issues, settings) {
|
||||
val users =
|
||||
getAccountsByUserNames(Set(repository.owner, issue.openedUserName) ++ issue.assignedUserName, Set(sender))
|
||||
for {
|
||||
@@ -346,10 +360,11 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
action: String,
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
issueId: Int,
|
||||
sender: Account
|
||||
sender: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||
import WebHookService._
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.PullRequest) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.PullRequest, settings) {
|
||||
for {
|
||||
(issue, pullRequest) <- getPullRequest(repository.owner, repository.name, issueId)
|
||||
users = getAccountsByUserNames(
|
||||
@@ -408,7 +423,8 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
action: String,
|
||||
requestRepository: RepositoryService.RepositoryInfo,
|
||||
requestBranch: String,
|
||||
sender: Account
|
||||
sender: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||
import WebHookService._
|
||||
for {
|
||||
@@ -439,7 +455,7 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
mergedComment = getMergedComment(baseRepo.owner, baseRepo.name, issue.issueId)
|
||||
)
|
||||
|
||||
callWebHook(WebHook.PullRequest, webHooks, payload)
|
||||
callWebHook(WebHook.PullRequest, webHooks, payload, settings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,10 +469,11 @@ trait WebHookPullRequestReviewCommentService extends WebHookService {
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
issue: Issue,
|
||||
pullRequest: PullRequest,
|
||||
sender: Account
|
||||
sender: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||
import WebHookService._
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.PullRequestReviewComment) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.PullRequestReviewComment, settings) {
|
||||
val users =
|
||||
getAccountsByUserNames(Set(repository.owner, pullRequest.requestUserName, issue.openedUserName), Set(sender))
|
||||
for {
|
||||
@@ -498,9 +515,10 @@ trait WebHookIssueCommentService extends WebHookPullRequestService {
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
issue: Issue,
|
||||
issueCommentId: Int,
|
||||
sender: Account
|
||||
sender: Account,
|
||||
settings: SystemSettings
|
||||
)(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.IssueComment) {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.IssueComment, settings) {
|
||||
for {
|
||||
issueComment <- getComment(repository.owner, repository.name, issueCommentId.toString())
|
||||
users = getAccountsByUserNames(
|
||||
|
||||
@@ -239,7 +239,8 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
with MilestonesService
|
||||
with WebHookPullRequestService
|
||||
with WebHookPullRequestReviewCommentService
|
||||
with CommitsService {
|
||||
with CommitsService
|
||||
with SystemSettingsService {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
||||
private var existIds: Seq[String] = Nil
|
||||
@@ -269,6 +270,8 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
}
|
||||
|
||||
def onPostReceive(receivePack: ReceivePack, commands: java.util.Collection[ReceiveCommand]): Unit = {
|
||||
val settings = loadSystemSettings()
|
||||
|
||||
Database() withTransaction { implicit session =>
|
||||
try {
|
||||
Using.resource(Git.open(Directory.getRepositoryDir(owner, repository))) { git =>
|
||||
@@ -317,7 +320,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||
closeIssuesFromMessage(commit.fullMessage, pusher, owner, repository).foreach { issueId =>
|
||||
getIssue(owner, repository, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", repositoryInfo, issue, pusherAccount)
|
||||
callIssuesWebHook("closed", repositoryInfo, issue, pusherAccount, settings)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(_.closedByCommitComment(issue, repositoryInfo, commit.fullMessage, pusherAccount))
|
||||
}
|
||||
@@ -337,7 +340,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
}.isDefined) {
|
||||
markMergeAndClosePullRequest(pusher, owner, repository, pull)
|
||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||
callPullRequestWebHook("closed", repositoryInfo, pull.issueId, pusherAccount)
|
||||
callPullRequestWebHook("closed", repositoryInfo, pull.issueId, pusherAccount, settings)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,14 +368,14 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
case ReceiveCommand.Type.CREATE | ReceiveCommand.Type.UPDATE |
|
||||
ReceiveCommand.Type.UPDATE_NONFASTFORWARD =>
|
||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||
updatePullRequests(owner, repository, branchName, pusherAccount, "synchronize")
|
||||
updatePullRequests(owner, repository, branchName, pusherAccount, "synchronize", settings)
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
// call web hook
|
||||
callWebHookOf(owner, repository, WebHook.Push) {
|
||||
callWebHookOf(owner, repository, WebHook.Push, settings) {
|
||||
for {
|
||||
pusherAccount <- getAccountByUserName(pusher)
|
||||
ownerAccount <- getAccountByUserName(owner)
|
||||
@@ -390,7 +393,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
}
|
||||
}
|
||||
if (command.getType == ReceiveCommand.Type.CREATE) {
|
||||
callWebHookOf(owner, repository, WebHook.Create) {
|
||||
callWebHookOf(owner, repository, WebHook.Create, settings) {
|
||||
for {
|
||||
pusherAccount <- getAccountByUserName(pusher)
|
||||
ownerAccount <- getAccountByUserName(owner)
|
||||
@@ -428,11 +431,14 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
extends PostReceiveHook
|
||||
with WebHookService
|
||||
with AccountService
|
||||
with RepositoryService {
|
||||
with RepositoryService
|
||||
with SystemSettingsService {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[WikiCommitHook])
|
||||
|
||||
override def onPostReceive(receivePack: ReceivePack, commands: util.Collection[ReceiveCommand]): Unit = {
|
||||
val settings = loadSystemSettings()
|
||||
|
||||
Database() withTransaction { implicit session =>
|
||||
try {
|
||||
commands.asScala.headOption.foreach { command =>
|
||||
@@ -468,7 +474,7 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
(commits.head._1, fileName, commits.last._3)
|
||||
}
|
||||
|
||||
callWebHookOf(owner, repository, WebHook.Gollum) {
|
||||
callWebHookOf(owner, repository, WebHook.Gollum, settings) {
|
||||
for {
|
||||
pusherAccount <- getAccountByUserName(pusher)
|
||||
repositoryUser <- getAccountByUserName(owner)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import java.net.{InetAddress, URL}
|
||||
|
||||
import gitbucket.core.service.SystemSettingsService
|
||||
import org.apache.commons.net.util.SubnetUtils
|
||||
import org.apache.http.HttpHost
|
||||
import org.apache.http.auth.{AuthScope, UsernamePasswordCredentials}
|
||||
import org.apache.http.impl.client.{BasicCredentialsProvider, CloseableHttpClient, HttpClientBuilder}
|
||||
@@ -32,4 +35,19 @@ object HttpClientUtil {
|
||||
}
|
||||
}
|
||||
|
||||
def isPrivateAddress(address: String): Boolean = {
|
||||
val ipAddress = InetAddress.getByName(address)
|
||||
ipAddress.isSiteLocalAddress || ipAddress.isLinkLocalAddress || ipAddress.isLoopbackAddress
|
||||
}
|
||||
|
||||
def inIpRange(ipRange: String, ipAddress: String): Boolean = {
|
||||
if (ipRange.contains('/')) {
|
||||
val utils = new SubnetUtils(ipRange)
|
||||
utils.setInclusiveHostCount(true)
|
||||
utils.getInfo.isInRange(ipAddress)
|
||||
} else {
|
||||
ipRange == ipAddress
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -283,6 +283,23 @@
|
||||
Send notifications
|
||||
</label>
|
||||
</fieldset>
|
||||
<!--====================================================================-->
|
||||
<!-- Web hook -->
|
||||
<!--====================================================================-->
|
||||
<hr>
|
||||
<label class="strong">Web hook</label>
|
||||
<fieldset>
|
||||
<label class="checkbox" for="blockPrivateAddress">
|
||||
<input type="checkbox" id="blockPrivateAddress" name="webhook.blockPrivateAddress"@if(context.settings.webHook.blockPrivateAddress){ checked}/>
|
||||
Block sending to private addresses
|
||||
</label>
|
||||
</fieldset>
|
||||
<div class="webhook">
|
||||
<label><span class="strong">IP whitelist</span></label>
|
||||
<fieldset>
|
||||
<textarea name="webhook.whitelist" class="form-control" style="height: 100px;">@context.settings.webHook.whitelist.mkString("\n")</textarea>
|
||||
</fieldset>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
$('#skinName').change(function(evt) {
|
||||
@@ -344,5 +361,9 @@ $(function(){
|
||||
$('#notification').prop('checked', false);
|
||||
}
|
||||
}).change();
|
||||
|
||||
$('#blockPrivateAddress').change(function(){
|
||||
$('.webhook textarea').prop('disabled', !$(this).prop('checked'));
|
||||
}).change();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -51,7 +51,11 @@ trait ServiceSpecBase extends MockitoSugar {
|
||||
oidcAuthentication = false,
|
||||
oidc = None,
|
||||
skinName = "skin-blue",
|
||||
showMailAddress = false
|
||||
showMailAddress = false,
|
||||
webHook = SystemSettingsService.WebHook(
|
||||
blockPrivateAddress = false,
|
||||
whitelist = Nil
|
||||
)
|
||||
)
|
||||
|
||||
def withTestDB[A](action: (Session) => A): A = {
|
||||
@@ -137,7 +141,8 @@ trait ServiceSpecBase extends MockitoSugar {
|
||||
commitIdFrom = baesBranch,
|
||||
commitIdTo = requestBranch,
|
||||
isDraft = false,
|
||||
loginAccount = loginAccount.get
|
||||
loginAccount = loginAccount.get,
|
||||
settings = createSystemSettings()
|
||||
)
|
||||
dummyService.getPullRequest(baseUserName, baseRepositoryName, issueId).get
|
||||
}
|
||||
|
||||
14
src/test/scala/gitbucket/core/util/HttpClientUtilSpec.scala
Normal file
14
src/test/scala/gitbucket/core/util/HttpClientUtilSpec.scala
Normal file
@@ -0,0 +1,14 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
class HttpClientUtilSpec extends FunSuite {
|
||||
|
||||
test("isPrivateAddress") {
|
||||
assert(HttpClientUtil.isPrivateAddress("localhost") == true)
|
||||
assert(HttpClientUtil.isPrivateAddress("192.168.10.2") == true)
|
||||
assert(HttpClientUtil.isPrivateAddress("169.254.169.254") == true)
|
||||
assert(HttpClientUtil.isPrivateAddress("www.google.com") == false)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,12 +2,12 @@ package gitbucket.core.view
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import javax.servlet.http.{HttpServletRequest, HttpSession}
|
||||
|
||||
import javax.servlet.http.{HttpServletRequest, HttpSession}
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.RequestCache
|
||||
import gitbucket.core.service.SystemSettingsService.{Ssh, SystemSettings}
|
||||
import gitbucket.core.service.SystemSettingsService.{Ssh, SystemSettings, WebHook}
|
||||
import org.mockito.Mockito._
|
||||
import org.scalatest.FunSpec
|
||||
import org.scalatestplus.mockito.MockitoSugar
|
||||
@@ -137,7 +137,11 @@ class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
|
||||
oidcAuthentication = false,
|
||||
oidc = None,
|
||||
skinName = "skin-blue",
|
||||
showMailAddress = false
|
||||
showMailAddress = false,
|
||||
webHook = WebHook(
|
||||
blockPrivateAddress = false,
|
||||
whitelist = Nil
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user