summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.classpath44
-rw-r--r--.github/SECURITY.md5
-rw-r--r--.github/workflows/ci-build.yml8
-rw-r--r--.github/workflows/nightly-build.yml32
-rw-r--r--build.moxie28
-rw-r--r--gitblit.iml125
-rw-r--r--releases.moxie74
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstance.java212
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstanceId.java265
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstanceReport.java43
-rw-r--r--src/main/java/com/gitblit/instance/GitblitInstanceStat.java127
-rw-r--r--src/main/java/com/gitblit/models/ServerStatus.java8
-rw-r--r--src/main/java/com/gitblit/servlet/GitblitContext.java9
-rw-r--r--src/main/java/com/gitblit/tickets/TicketNotifier.java3
-rw-r--r--src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java6
-rw-r--r--src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java5
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties4
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BasePage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditUserPage.java38
-rwxr-xr-xsrc/site/templates/ghreleasenotes.awk2
-rw-r--r--src/test/config/test-gitblit.properties1
-rw-r--r--src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java158
-rw-r--r--src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java184
-rw-r--r--src/test/java/com/gitblit/instance/GitblitInstanceTest.java64
-rw-r--r--src/test/java/com/gitblit/tests/GitBlitSuite.java8
-rw-r--r--src/test/java/com/gitblit/tests/GitblitUnitTest.java5
-rw-r--r--src/test/java/com/gitblit/tests/SshDaemonTest.java65
-rw-r--r--src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java7
36 files changed, 1376 insertions, 173 deletions
diff --git a/.classpath b/.classpath
index 0181995b..ed27f4e0 100644
--- a/.classpath
+++ b/.classpath
@@ -24,15 +24,15 @@
<classpathentry kind="lib" path="ext/javax.mail-1.5.6.jar" sourcepath="ext/src/javax.mail-1.5.6.jar" />
<classpathentry kind="lib" path="ext/activation-1.1.jar" sourcepath="ext/src/activation-1.1.jar" />
<classpathentry kind="lib" path="ext/javax.servlet-api-3.1.0.jar" sourcepath="ext/src/javax.servlet-api-3.1.0.jar" />
- <classpathentry kind="lib" path="ext/jetty-servlet-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-servlet-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-security-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-security-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-server-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-server-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-continuation-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-continuation-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-http-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-http-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-io-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-io-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-util-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-util-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-webapp-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-webapp-9.4.49.v20220914.jar" />
- <classpathentry kind="lib" path="ext/jetty-xml-9.4.49.v20220914.jar" sourcepath="ext/src/jetty-xml-9.4.49.v20220914.jar" />
+ <classpathentry kind="lib" path="ext/jetty-servlet-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-servlet-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-security-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-security-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-server-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-server-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-continuation-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-continuation-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-http-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-http-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-io-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-io-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-util-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-util-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-webapp-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-webapp-9.4.57.v20241219.jar" />
+ <classpathentry kind="lib" path="ext/jetty-xml-9.4.57.v20241219.jar" sourcepath="ext/src/jetty-xml-9.4.57.v20241219.jar" />
<classpathentry kind="lib" path="ext/wicket-1.4.22.jar" sourcepath="ext/src/wicket-1.4.22.jar" />
<classpathentry kind="lib" path="ext/wicket-auth-roles-1.4.22.jar" sourcepath="ext/src/wicket-auth-roles-1.4.22.jar" />
<classpathentry kind="lib" path="ext/wicket-extensions-1.4.22.jar" sourcepath="ext/src/wicket-extensions-1.4.22.jar" />
@@ -66,22 +66,23 @@
<classpathentry kind="lib" path="ext/commons-logging-1.2.jar" sourcepath="ext/src/commons-logging-1.2.jar" />
<classpathentry kind="lib" path="ext/commons-codec-1.9.jar" sourcepath="ext/src/commons-codec-1.9.jar" />
<classpathentry kind="lib" path="ext/org.eclipse.jgit.http.server-4.11.9.201909030838-r.jar" sourcepath="ext/src/org.eclipse.jgit.http.server-4.11.9.201909030838-r.jar" />
- <classpathentry kind="lib" path="ext/bcprov-jdk15on-1.69.jar" sourcepath="ext/src/bcprov-jdk15on-1.69.jar" />
- <classpathentry kind="lib" path="ext/bcmail-jdk15on-1.69.jar" sourcepath="ext/src/bcmail-jdk15on-1.69.jar" />
- <classpathentry kind="lib" path="ext/bcutil-jdk15on-1.69.jar" sourcepath="ext/src/bcutil-jdk15on-1.69.jar" />
- <classpathentry kind="lib" path="ext/bcpkix-jdk15on-1.69.jar" sourcepath="ext/src/bcpkix-jdk15on-1.69.jar" />
+ <classpathentry kind="lib" path="ext/bcprov-jdk18on-1.81.jar" sourcepath="ext/src/bcprov-jdk18on-1.81.jar" />
+ <classpathentry kind="lib" path="ext/bcmail-jdk18on-1.81.jar" sourcepath="ext/src/bcmail-jdk18on-1.81.jar" />
+ <classpathentry kind="lib" path="ext/bcpkix-jdk18on-1.81.jar" sourcepath="ext/src/bcpkix-jdk18on-1.81.jar" />
+ <classpathentry kind="lib" path="ext/bcutil-jdk18on-1.81.jar" sourcepath="ext/src/bcutil-jdk18on-1.81.jar" />
<classpathentry kind="lib" path="ext/eddsa-0.2.0.jar" sourcepath="ext/src/eddsa-0.2.0.jar" />
<classpathentry kind="lib" path="ext/sshd-core-1.7.0.jar" sourcepath="ext/src/sshd-core-1.7.0.jar" />
- <classpathentry kind="lib" path="ext/mina-core-2.0.25.jar" sourcepath="ext/src/mina-core-2.0.25.jar" />
+ <classpathentry kind="lib" path="ext/mina-core-2.0.27.jar" sourcepath="ext/src/mina-core-2.0.27.jar" />
<classpathentry kind="lib" path="ext/rome-0.9.jar" sourcepath="ext/src/rome-0.9.jar" />
<classpathentry kind="lib" path="ext/jdom-1.0.jar" sourcepath="ext/src/jdom-1.0.jar" />
<classpathentry kind="lib" path="ext/gson-2.10.jar" sourcepath="ext/src/gson-2.10.jar" />
- <classpathentry kind="lib" path="ext/groovy-all-2.4.4.jar" sourcepath="ext/src/groovy-all-2.4.4.jar" />
+ <classpathentry kind="lib" path="ext/groovy-all-2.4.21.jar" sourcepath="ext/src/groovy-all-2.4.21.jar" />
<classpathentry kind="lib" path="ext/unboundid-ldapsdk-2.3.8.jar" sourcepath="ext/src/unboundid-ldapsdk-2.3.8.jar" />
- <classpathentry kind="lib" path="ext/ivy-2.2.0.jar" sourcepath="ext/src/ivy-2.2.0.jar" />
+ <classpathentry kind="lib" path="ext/ivy-2.5.3.jar" sourcepath="ext/src/ivy-2.5.3.jar" />
<classpathentry kind="lib" path="ext/jcalendar-1.3.2.jar" />
- <classpathentry kind="lib" path="ext/commons-compress-1.24.0.jar" sourcepath="ext/src/commons-compress-1.24.0.jar" />
- <classpathentry kind="lib" path="ext/commons-io-2.11.0.jar" sourcepath="ext/src/commons-io-2.11.0.jar" />
+ <classpathentry kind="lib" path="ext/commons-compress-1.27.1.jar" sourcepath="ext/src/commons-compress-1.27.1.jar" />
+ <classpathentry kind="lib" path="ext/commons-io-2.19.0.jar" sourcepath="ext/src/commons-io-2.19.0.jar" />
+ <classpathentry kind="lib" path="ext/commons-lang3-3.16.0.jar" sourcepath="ext/src/commons-lang3-3.16.0.jar" />
<classpathentry kind="lib" path="ext/force-partner-api-24.0.0.jar" sourcepath="ext/src/force-partner-api-24.0.0.jar" />
<classpathentry kind="lib" path="ext/force-wsc-24.0.0.jar" sourcepath="ext/src/force-wsc-24.0.0.jar" />
<classpathentry kind="lib" path="ext/js-1.7R2.jar" sourcepath="ext/src/js-1.7R2.jar" />
@@ -97,7 +98,7 @@
<classpathentry kind="lib" path="ext/tika-core-1.28.5.jar" sourcepath="ext/src/tika-core-1.28.5.jar" />
<classpathentry kind="lib" path="ext/jsoup-1.16.2.jar" sourcepath="ext/src/jsoup-1.16.2.jar" />
<classpathentry kind="lib" path="ext/javax.activation-1.2.0.jar" sourcepath="ext/src/javax.activation-1.2.0.jar" />
- <classpathentry kind="lib" path="ext/junit-4.12.jar" sourcepath="ext/src/junit-4.12.jar" />
+ <classpathentry kind="lib" path="ext/junit-4.13.1.jar" sourcepath="ext/src/junit-4.13.1.jar" />
<classpathentry kind="lib" path="ext/hamcrest-core-1.3.jar" sourcepath="ext/src/hamcrest-core-1.3.jar" />
<classpathentry kind="lib" path="ext/selenium-java-2.28.0.jar" sourcepath="ext/src/selenium-java-2.28.0.jar" />
<classpathentry kind="lib" path="ext/selenium-support-2.28.0.jar" sourcepath="ext/src/selenium-support-2.28.0.jar" />
@@ -113,10 +114,5 @@
<classpathentry kind="lib" path="ext/byte-buddy-agent-1.9.10.jar" sourcepath="ext/src/byte-buddy-agent-1.9.10.jar" />
<classpathentry kind="lib" path="ext/objenesis-2.6.jar" sourcepath="ext/src/objenesis-2.6.jar" />
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" />
- <classpathentry kind="src" path="src/main/dagger">
- <attributes>
- <attribute name="optional" value="true"/>
- </attributes>
- </classpathentry>
<classpathentry kind="output" path="bin/classes" />
</classpath>
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
index 483daf0e..861c96f3 100644
--- a/.github/SECURITY.md
+++ b/.github/SECURITY.md
@@ -5,7 +5,10 @@
The Gitblit team takes security bugs seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
-To report a security issue, please send an email to the following email address and include the word "SECURITY" in the subject line.
+
+To report a security vulnerability, you can use the Github mechanism to [privately report a vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability). On Gitblit's repository page, choose the `Security` tab (under the repository name). Click the `Report a vulnerability` button on the right.
+
+Alternatively, you can also report any security issue via e-mail. Send an email to the following email address and include the word "SECURITY" in the subject line.
```
gitblitorg@gmail.com
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 138359d3..93fd1983 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -20,12 +20,12 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: true
- name: Setup Java ${{ matrix.java-version }}
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java-version }}
distribution: 'temurin'
@@ -54,12 +54,12 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: true
- name: Setup Java ${{ matrix.java-version }}
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java-version }}
distribution: 'temurin'
diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml
index ad2723f6..d8b01956 100644
--- a/.github/workflows/nightly-build.yml
+++ b/.github/workflows/nightly-build.yml
@@ -30,7 +30,7 @@ jobs:
steps:
- name: Cache marker for latest commit
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: cache-sha
with:
key: sha-${{ github.sha }}
@@ -54,7 +54,7 @@ jobs:
# Build Gitblit GO so that it can be packed into a docker image.
-# The built tarball is saved as an artefact, it can be downloaded
+# The built tarball is saved as an artifact, it can be downloaded
# by interested parties.
# We could even do better and check if paths of source files changed,
# but that is not that easy, so we build on any commit.
@@ -68,12 +68,12 @@ jobs:
steps:
- name: Checkout Gitblit
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: true
- name: Setup Java 8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: 'temurin'
@@ -88,7 +88,7 @@ jobs:
- name: Save built Gitblit package
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: gitblit-nightly
path: build/target/gitblit-*-SNAPSHOT.tar.gz
@@ -132,14 +132,14 @@ jobs:
steps:
- name: Checkout gitblit-docker
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
repository: ${{ env.GH_ORG }}/gitblit-docker
ref: master
fetch-depth: 2
- name: Download Gitblit nightly build
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
id: get-gb
with:
name: gitblit-nightly
@@ -162,13 +162,13 @@ jobs:
echo "BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%S)" >> "${GITHUB_ENV}"
- name: Login to Docker Hub
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_GB_USER }}
password: ${{ secrets.DOCKERHUB_GB_TOKEN }}
- name: Build snapshot docker image
- uses: docker/build-push-action@v3
+ uses: docker/build-push-action@v6
with:
file: generate/Dockerfile
context: .
@@ -181,15 +181,15 @@ jobs:
org.opencontainers.image.created=${{ env.BUILD_DATE }}
- name: Install Goss for testing the docker image
- uses: e1himself/goss-installation-action@v1.0.4
+ uses: e1himself/goss-installation-action@v1.2.1
with:
- version: 'v0.3.16'
+ version: 'v0.4.9'
- name: Test docker container - normal mode
env:
GOSS_WAIT_OPTS: "-r 15s -s 5s > /dev/null"
run: |
- dgoss run -p 8080:8080 -p 8443:8443 gitblit/gitblit:nightly
+ dgoss run -e GITBLIT_GOSS_TEST=true -p 8080:8080 -p 8443:8443 gitblit/gitblit:nightly
- name: Test docker container - bind mount
env:
@@ -201,7 +201,7 @@ jobs:
echo "include = gitblit-docker.properties" >> gitblit-data/etc/gitblit.properties
sed -e '/mode: / d' -e '/group: / d' goss.yaml > gitblit-data/goss.yaml
cp goss_wait.yaml gitblit-data/
- GOSS_FILES_PATH=gitblit-data dgoss run -p 8080:8080 -p 8443:8443 -v "$PWD/gitblit-data":/var/opt/gitblit gitblit/gitblit:nightly
+ GOSS_FILES_PATH=gitblit-data dgoss run -e GITBLIT_GOSS_TEST=true -p 8080:8080 -p 8443:8443 -v "$PWD/gitblit-data":/var/opt/gitblit gitblit/gitblit:nightly
[ -d gitblit-data/srv/git ] || exit 1
[ -f gitblit-data/etc/defaults.properties ] || exit 1
grep --quiet "This should not be overwritten" gitblit-data/etc/gitblit.properties || exit 1
@@ -211,17 +211,17 @@ jobs:
env:
GOSS_WAIT_OPTS: "-r 15s -s 5s > /dev/null"
run: |
- dgoss run -p 8080:8080 -p 8443:8443 --tmpfs /var/opt/gitblit/temp gitblit/gitblit:nightly
+ dgoss run -e GITBLIT_GOSS_TEST=true -p 8080:8080 -p 8443:8443 --tmpfs /var/opt/gitblit/temp gitblit/gitblit:nightly
# Delete the artifact unless this is the official Gitblit repo
- - uses: geekyeggo/delete-artifact@v2
+ - uses: geekyeggo/delete-artifact@v5
if: ${{ github.repository != 'gitblit-org/gitblit' }}
with:
name: gitblit-nightly
failOnError: false
- name: Push docker image to registry
- uses: docker/build-push-action@v3
+ uses: docker/build-push-action@v6
with:
file: generate/Dockerfile
context: .
diff --git a/build.moxie b/build.moxie
index 057c1c9d..bd1c9288 100644
--- a/build.moxie
+++ b/build.moxie
@@ -10,12 +10,12 @@ name: Gitblit
description: pure Java Git solution
groupId: com.gitblit
artifactId: gitblit
-version: 1.10.0-SNAPSHOT
+version: 1.10.1-SNAPSHOT
inceptionYear: 2011
# Current stable release
-releaseVersion: 1.9.3
-releaseDate: 2022-04-09
+releaseVersion: 1.10.0
+releaseDate: 2025-06-14
# Project urls
url: 'http://gitblit.com'
@@ -105,17 +105,17 @@ repositories: central, eclipse-snapshots, eclipse, gitblit
# Convenience properties for dependencies
properties: {
- jetty.version : 9.4.49.v20220914
+ jetty.version : 9.4.57.v20241219
slf4j.version : 1.7.36
wicket.version : 1.4.22
lucene.version : 5.5.2
jgit.version : 4.11.9.201909030838-r
- groovy.version : 2.4.4
- bouncycastle.version : 1.69
+ groovy.version : 2.4.21
+ bouncycastle.version : 1.81
selenium.version : 2.28.0
wikitext.version : 1.4
sshd.version: 1.7.0
- mina.version: 2.0.25
+ mina.version: 2.0.27
guice.version : 5.1.0
# Gitblit maintains a fork of guice-servlet
guice-servlet.version : 5.1.0-gb2
@@ -168,9 +168,9 @@ dependencies:
- compile 'org.fusesource.wikitext:confluence-core:${wikitext.version}' :war
- compile 'org.eclipse.jgit:org.eclipse.jgit:${jgit.version}' :war :fedclient :manager !junit
- compile 'org.eclipse.jgit:org.eclipse.jgit.http.server:${jgit.version}' :war :manager !junit
-- compile 'org.bouncycastle:bcprov-jdk15on:${bouncycastle.version}' :war
-- compile 'org.bouncycastle:bcmail-jdk15on:${bouncycastle.version}' :war
-- compile 'org.bouncycastle:bcpkix-jdk15on:${bouncycastle.version}' :war
+- compile 'org.bouncycastle:bcprov-jdk18on:${bouncycastle.version}' :war
+- compile 'org.bouncycastle:bcmail-jdk18on:${bouncycastle.version}' :war
+- compile 'org.bouncycastle:bcpkix-jdk18on:${bouncycastle.version}' :war
- compile 'net.i2p.crypto:eddsa:0.2.0' :war !org.easymock
- compile 'org.apache.sshd:sshd-core:${sshd.version}' :war !org.easymock
- compile 'org.apache.mina:mina-core:${mina.version}' :war !org.easymock
@@ -178,10 +178,10 @@ dependencies:
- compile 'com.google.code.gson:gson:2.10' :war :fedclient :manager :api
- compile 'org.codehaus.groovy:groovy-all:${groovy.version}' :war
- compile 'com.unboundid:unboundid-ldapsdk:2.3.8' :war
-- compile 'org.apache.ivy:ivy:2.2.0' :war
+- compile 'org.apache.ivy:ivy:2.5.3' :war
- compile 'com.toedter:jcalendar:1.3.2' :authority
-- compile 'org.apache.commons:commons-compress:1.24.0' :war
-- compile 'commons-io:commons-io:2.11.0' :war
+- compile 'org.apache.commons:commons-compress:1.27.1' :war
+- compile 'commons-io:commons-io:2.19.0' :war
- compile 'com.force.api:force-partner-api:24.0.0' :war
- compile 'org.freemarker:freemarker:2.3.22' :war
- compile 'com.github.dblock.waffle:waffle-jna:1.7.3' :war
@@ -193,7 +193,7 @@ dependencies:
- compile 'org.apache.tika:tika-core:1.28.5' :war
- compile 'org.jsoup:jsoup:1.16.2' :war
- compile 'com.sun.activation:javax.activation:1.2.0' :war :manager :fedclient
-- test 'junit:junit:4.12'
+- test 'junit:junit:4.13.1'
# Dependencies for Selenium web page testing
- test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar
- test 'org.seleniumhq.selenium:selenium-support:${selenium.version}' @jar
diff --git a/gitblit.iml b/gitblit.iml
index 0761644b..52dc93df 100644
--- a/gitblit.iml
+++ b/gitblit.iml
@@ -211,101 +211,101 @@
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-servlet-9.4.49.v20220914.jar">
+ <library name="jetty-servlet-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-servlet-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-servlet-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-servlet-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-servlet-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-security-9.4.49.v20220914.jar">
+ <library name="jetty-security-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-security-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-security-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-security-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-security-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-server-9.4.49.v20220914.jar">
+ <library name="jetty-server-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-server-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-server-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-server-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-server-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-continuation-9.4.49.v20220914.jar">
+ <library name="jetty-continuation-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-continuation-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-continuation-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-continuation-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-continuation-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-http-9.4.49.v20220914.jar">
+ <library name="jetty-http-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-http-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-http-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-http-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-http-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-io-9.4.49.v20220914.jar">
+ <library name="jetty-io-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-io-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-io-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-io-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-io-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-util-9.4.49.v20220914.jar">
+ <library name="jetty-util-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-util-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-util-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-util-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-util-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-webapp-9.4.49.v20220914.jar">
+ <library name="jetty-webapp-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-webapp-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-webapp-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-webapp-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-webapp-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="jetty-xml-9.4.49.v20220914.jar">
+ <library name="jetty-xml-9.4.57.v20241219.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/jetty-xml-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/jetty-xml-9.4.57.v20241219.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/jetty-xml-9.4.49.v20220914.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/jetty-xml-9.4.57.v20241219.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -671,46 +671,46 @@
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="bcprov-jdk15on-1.69.jar">
+ <library name="bcprov-jdk18on-1.81.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/bcprov-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/bcprov-jdk18on-1.81.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/bcprov-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/bcprov-jdk18on-1.81.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="bcmail-jdk15on-1.69.jar">
+ <library name="bcmail-jdk18on-1.81.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/bcmail-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/bcmail-jdk18on-1.81.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/bcmail-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/bcmail-jdk18on-1.81.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="bcutil-jdk15on-1.69.jar">
+ <library name="bcpkix-jdk18on-1.81.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/bcutil-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/bcpkix-jdk18on-1.81.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/bcutil-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/bcpkix-jdk18on-1.81.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="bcpkix-jdk15on-1.69.jar">
+ <library name="bcutil-jdk18on-1.81.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/bcpkix-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/bcutil-jdk18on-1.81.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/bcpkix-jdk15on-1.69.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/bcutil-jdk18on-1.81.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -737,13 +737,13 @@
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="mina-core-2.0.25.jar">
+ <library name="mina-core-2.0.27.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/mina-core-2.0.25.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/mina-core-2.0.27.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/mina-core-2.0.25.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/mina-core-2.0.27.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -781,13 +781,13 @@
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="groovy-all-2.4.4.jar">
+ <library name="groovy-all-2.4.21.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/groovy-all-2.4.4.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/groovy-all-2.4.21.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/groovy-all-2.4.4.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/groovy-all-2.4.21.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -803,13 +803,13 @@
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="ivy-2.2.0.jar">
+ <library name="ivy-2.5.3.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/ivy-2.2.0.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/ivy-2.5.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/ivy-2.2.0.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/ivy-2.5.3.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -823,24 +823,35 @@
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="commons-compress-1.24.0.jar">
+ <library name="commons-compress-1.27.1.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/commons-compress-1.24.0.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/commons-compress-1.27.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/commons-compress-1.24.0.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/commons-compress-1.27.1.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
- <library name="commons-io-2.11.0.jar">
+ <library name="commons-io-2.19.0.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/commons-io-2.11.0.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/commons-io-2.19.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/commons-io-2.11.0.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/commons-io-2.19.0.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library name="commons-lang3-3.16.0.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/commons-lang3-3.16.0.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/commons-lang3-3.16.0.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -1010,13 +1021,13 @@
</library>
</orderEntry>
<orderEntry type="module-library" scope="TEST">
- <library name="junit-4.12.jar">
+ <library name="junit-4.13.1.jar">
<CLASSES>
- <root url="jar://$MODULE_DIR$/ext/junit-4.12.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/junit-4.13.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/ext/src/junit-4.12.jar!/" />
+ <root url="jar://$MODULE_DIR$/ext/src/junit-4.13.1.jar!/" />
</SOURCES>
</library>
</orderEntry>
diff --git a/releases.moxie b/releases.moxie
index 303ee7ea..b0faa763 100644
--- a/releases.moxie
+++ b/releases.moxie
@@ -1,16 +1,36 @@
#
# ${project.version} release
#
-r34: {
+r35: {
title: ${project.name} ${project.version} released
id: ${project.version}
date: ${project.buildDate}
+ note: ~
+ html: ~
+ text: ~
+ security: ~
+ fixes: ~
+ changes: ~
+ additions: ~
+ dependencyChanges: ~
+ contributors: ~
+}
+
+#
+# 1.10.0 release
+#
+r34: {
+ title: Gitblit 1.10.0 released
+ id: 1.10.0
+ date: 2025-06-14
note: ''
- From 1.10.0 on Gitblit requires Java 8 as minimum Java version.
+ This release fixes a vulnerability allowing an attacker to circumvent authentication on the SSH transport. Users are urged to update to this version.
+
+ Should you have disabled the Flash-based copy-to-clipboard function because it wasn't working anymore (`web.allowFlashCopyToClipboard = false`), you may want to rethink this and enable it again. The configuration property has the same name, but the mechanism was exchanged. Flash is gone, and a modern JavaScript solution is now used to copy text directly to the clipboard (via clipboard.js).
- Should you have disabled the Flash-based copy-to-clipboard function because it wasn't working anymore (web.allowFlashCopyToClipboard = false), you may want to rethink this and enable it again. The configuration property has the same name, but the mechanism was exchanged. Flash is gone, and a modern JavaScript solution is now used to copy text directly to the clipboard (via clipboard.js).
+ The setting `server.requireClientCertificates` now has three values: `required`, `optional` and `none`. While `required` is synonymous to the old `true` value, and `optional` is synonymous to the old `false` value, the new `none` value results in the server never asking the client to present any client certificate at all. The old values `true` and `false` can still be used and keep their meaning.
- The setting 'server.requireClientCertificates' now has three values: required, optional and none. While 'required' is synonymous to the old 'true' value, and 'optional' is synonymous to the old 'false' value, the new 'none' value results in the server never asking the client to present any client certificate at all. The old values 'true' and 'false' can still be used and keep their meaning.
+ From 1.10.0 on Gitblit requires Java 8 as minimal Java version.
''
html: ~
@@ -18,9 +38,10 @@ r34: {
Highlights:
* Support for ECDSA and Ed25519 SSH keys
- * Move to Java 8
+ * Fix vulnerability that allowed SSH authentication to be circumvented
* Explicitly disable requesting optional client TLS certificates
* Copy-to-clipboard button is back and working
+ * Minimal required Java version is Java 8
While old DSA SSH host keys can still be used, a new Gitblit installation will no longer
generate a DSA host key. The default set of host keys is now RSA, ECDSA and Ed25519.
@@ -30,6 +51,8 @@ r34: {
''
security:
- Fix path traversal vulnerability which allowed access to "/resources//../WEB-INF/". (CVE-2022-31268) This was fixed by updating Jetty. (issue-1409)
+ - Fix exploit circumventing SSH authentication. Many thanks to András Veres-Szentkirályi (silentsignal.eu) for the report. (CVE-2024-28080)
+ - Fix vulnerability exposing user password hashes to administrators when an administrator edits a user's properties. Many thanks to Gerhard Klostermeier (syss.de) for the report.
fixes:
- Fix crash in Gitblit Authority when users were deleted from Gitblit but still had entries (certificates) in the Authority. (issue-1359, pr-1435)
- Fix tab-to-space conversion to work like tabs. (pr-1065 by @QuentinC)
@@ -40,31 +63,46 @@ r34: {
- Fix errors in Bugtraq preventing display of commit completely.
- Fix misaligned images in primary repository URL display. (issue-1437)
- Fix incorrect text being copied by copy button on tickets page
+ - Fix broken language files.
+ - Fix problems with single quotes in message texts. (pr-1455 by @losiki)
changes:
- Minimum Java required increased to Java 8. (pr-1218 by @paladox)
- - Add feedback on invalid keys to SSH key form. (issue-984, pr-1239 by @martinspielmann)
- - Replace old Flash-based Clippy copy-paste buttons to copy repository URLs and other text to the clipboard with a modern JavaScript-based approach via clipboard.js. (issue-1241, issue-965, pr-1438 by @flaix)
+ - Added feedback on invalid keys to SSH key form. (issue-984, pr-1239 by @martinspielmann)
+ - Replaced old Flash-based Clippy copy-paste buttons to copy repository URLs and other text to the clipboard with a modern JavaScript-based approach via clipboard.js. (issue-1241, issue-965, pr-1438 by @flaix)
+ - Updated various dependencies that had known CVEs.
+ - Updated Git clients list on empty repository page.
+ - Improved Chinese translation of "fork".
+ - Switched logging library from Log4j1 to reload4j.
+ - Updating the BouncyCastle version required to switch from bc*-jdk15on to bc*-jdk18on
additions:
- Option to explicitly disable optional client TLS certificates. (issue-1137, pr-1138 by @oddeirik)
- Support for ECDSA and Ed25519 (EdDSA) user keys. (pr-1427, pr-1272)
- New ECDSA and EdDSA host key types. (issue-1354, pr-1429 by @flaix)
- French version of empty repository page. (by @piradix)
- - Add support for Jenkins access token. Use setting 'groovy.jenkinsToken'. (issue-1423, pr-1425 by @TDesjardins)
+ - Add support for Jenkins access token. Use setting `groovy.jenkinsToken`. (issue-1423, pr-1425 by @TDesjardins)
dependencyChanges:
- update to JavaMail 1.5.6 (pr-1217 by @paladox)
- update to Google Guice 5.1.0
- - update to Google Guava 31.1-jre
+ - update to Google Guava 32.1.3-jre
- update to Google Gson 2.10
- - update to Apache commons-io 2.11.0
+ - update to Apache commons-io 2.19
- update to Apache commons-codec 1.9
- - update to Apache commons-compress 1.22
+ - update to Apache commons-compress 1.27.1
+ - update to Apache Tika 1.28.5
- update to libpam4j 1.11
- update to MINA SSHD 1.7.0
- - update to BouncyCastle 1.69
- - update to Jetty 9.4.49.v20220914 (pr-1213 by @paladox, plus more)
+ - update to MINA Core 2.0.27
+ - update to BouncyCastle 1.81
+ - update to Jetty 9.4.57.v20241219 (pr-1213 by @paladox, plus more)
- update to JGit 4.11.9.201909030838-r (pr-1252 by @jvanhercke, plus more)
- update to Bugtraq v0.4
+ - update to JSoup 1.16.2
+ - update to Groovy 2.4.21
+ - update to Ivy 2.5.3
+ - update to slf4j 1.7.36
+ - replace log4j1 with reload4j
- added clipboard.js, replacing Clippy
+ - update to JUnit 4.13.1
settings:
- { name: 'server.requireClientCertificates', defaultValue: 'optional' }
contributors:
@@ -79,6 +117,10 @@ r34: {
- @xxcdd
- @piradix
- Tino Desjardins
+ - @xxl-cc
+ - Egor Shchegolkov
+ - András Veres-Szentkirályi
+ - Gerhard Klostermeier
}
#
@@ -2161,6 +2203,6 @@ r1: {
- James Moger
}
-snapshot: &r34
-release: &r33
-releases: &r[1..33]
+snapshot: &r35
+release: &r34
+releases: &r[1..34]
diff --git a/src/main/java/com/gitblit/instance/GitblitInstance.java b/src/main/java/com/gitblit/instance/GitblitInstance.java
new file mode 100644
index 00000000..ca1fda38
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstance.java
@@ -0,0 +1,212 @@
+package com.gitblit.instance;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.gitblit.utils.JsonUtils.sendJsonString;
+
+public class GitblitInstance
+{
+ private final static String STATS_URL = "https://instats.gitblit.dev/hiitsme/";
+ private final static Logger LOG = LoggerFactory.getLogger(GitblitInstance.class);
+
+ private IRuntimeManager runtimeManager;
+
+ private String instanceId;
+
+ private GitblitInstanceReport report;
+
+ private ScheduledExecutorService executor;
+
+
+ /**
+ * Initialize the Gitblit instance reporting system.
+ *
+ * This will gather the static and dynamic statistics about the running
+ * instance, so that they can be reported.
+ *
+ * @param runtimeManager
+ * The runtime manager is used to determine the type of instance
+ * as well as for some other settings and data.
+ */
+ public void init(IRuntimeManager runtimeManager) {
+ this.runtimeManager = runtimeManager;
+
+ // Initialize ID
+ GitblitInstanceId instanceId = new GitblitInstanceId(runtimeManager.getBaseFolder());
+ this.instanceId = instanceId.getId().toString();
+ LOG.info(this.instanceId);
+
+ GitblitInstanceStat instanceStat;
+
+ if (runtimeManager.getSettings().hasSettings("container.dockerfileVersion")) {
+ instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.DOCKER);
+ }
+ else if (runtimeManager.getStatus().isGO){
+ instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.GO);
+ }
+ else {
+ instanceStat = new GitblitInstanceStat(GitblitInstanceStat.GitblitInstanceType.WAR);
+ }
+
+ instanceStat.init(runtimeManager.getStatus());
+
+ this.report = new GitblitInstanceReport(this.instanceId, instanceStat);
+ }
+
+
+ public void start()
+ {
+ if (shouldRunReports()) {
+ startReports();
+ }
+ }
+
+ public void stop()
+ {
+ if (this.executor != null && !this.executor.isShutdown() && !this.executor.isTerminated()) {
+ this.executor.shutdownNow();
+ System.out.println("Gitblit instance reporting task stopped.");
+ }
+ }
+
+
+
+ /**
+ * Determine if the reporting task should run.
+ *
+ * We do not want to report anything, i.e. the reporting task to run,
+ * if we are running unit tests or integration tests.
+ * Instance reports should only be sent for production instances or released versions.
+ * Therefore we also check if the Gitblit version is a SNAPSHOT version,
+ * or if the docker image is not a release version, when running from a docker image.
+ * A docker image running under GOSS should also not report anything.
+ */
+ boolean shouldRunReports()
+ {
+ // We can only run reports when we have been initialized
+ if (this.report == null || this.runtimeManager == null) {
+ return false;
+ }
+
+ // Check if we are running in a test environment
+ IStoredSettings settings = this.runtimeManager.getSettings();
+ if (! settings.getString("gitblit.testReportingUrl", "").isEmpty()) {
+ // Force reporting to run overriding any test settings
+ LOG.debug("Enabled reporting to test server URL: {}", settings.getString("gitblit.testReportingUrl", ""));
+ return true;
+ }
+ if (settings.getBoolean("gitblit.testRun", false)) {
+ return false;
+ }
+
+ // Check if we are running a SNAPSHOT version
+ if (this.runtimeManager.getStatus().version.endsWith("SNAPSHOT")) {
+ return false;
+ }
+
+ if (this.report.instanceStat.instanceType == GitblitInstanceStat.GitblitInstanceType.DOCKER) {
+ // Check if we are running a docker image that is not a release version
+ if (! settings.getString("container.imageType", "").equals("release")) {
+ return false;
+ }
+
+ // Check if we are running a docker image under GOSS
+ if (System.getenv("GITBLIT_GOSS_TEST") != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Start the reporting task.
+ *
+ * This will start a thread that runs once a day and sends the instance
+ * report to the popularity report server.
+ */
+ private void startReports()
+ {
+ this.executor = Executors.newSingleThreadScheduledExecutor();
+
+ String statsUrl = STATS_URL;
+ int delay = 24;
+ int period = 24 * 60; // 24 hours in minutes
+ TimeUnit unit = TimeUnit.MINUTES;
+ long retryInterval = 60 * 60 * 1000; // 1 hour in milliseconds
+ final long retryTimeout = 20 * 60 * 60 * 1000; // 20 hours in milliseconds
+
+ // If we are running in a test environment, we will send the reports more frequently
+ String testUrl = this.runtimeManager.getSettings().getString("gitblit.testReportingUrl", "");
+ if (! testUrl.isEmpty()) {
+ statsUrl = testUrl;
+ delay = 10;
+ period = 24;
+ unit = TimeUnit.SECONDS;
+ retryInterval = 10 * 1000; // 10 seconds in milliseconds
+ }
+
+ final String baseUrl = statsUrl;
+ final long retryIntervalFinal = retryInterval;
+ this.executor.scheduleAtFixedRate(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ sendMyStats(baseUrl + instanceId, retryIntervalFinal, retryTimeout);
+ }
+ }, delay, period, unit);
+ }
+
+ /**
+ * Send the instance report to the popularity report server.
+ *
+ * This will send a JSON object to the server with the instance report.
+ *
+ * @param reportUrl
+ * The URL to send the report to.
+ * @param retryInterval
+ * The interval in milliseconds to wait before retrying to send the report if it failed.
+ * @param retryTimeout
+ * The timeout in milliseconds to give up sending the report if it fails repeatedly.
+ */
+ private void sendMyStats(String reportUrl, long retryInterval, long retryTimeout)
+ {
+ // Create a HTTP POST request payload
+ String report = JsonUtils.toJsonString(this.report.fromNow());
+
+ int status = 0;
+ long timeToGiveup = System.currentTimeMillis() + retryTimeout;
+ while (status != 200 && System.currentTimeMillis() < timeToGiveup) {
+ try {
+ status = sendJsonString(reportUrl, report, "gitblitta", "countmein".toCharArray());
+ if (status != 200) {
+ LOG.debug("Error sending stats to " + reportUrl + ": " + status);
+ }
+ }
+ catch (IOException e) {
+ LOG.debug("Exception sending stats to " + reportUrl + ": " + e.getMessage());
+ }
+
+ if (status != 200) {
+ try {
+ Thread.sleep(retryInterval);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return; // exit if interrupted
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/gitblit/instance/GitblitInstanceId.java b/src/main/java/com/gitblit/instance/GitblitInstanceId.java
new file mode 100644
index 00000000..652c200c
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstanceId.java
@@ -0,0 +1,265 @@
+package com.gitblit.instance;
+
+import com.gitblit.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * The instance id is a unique identifier for an installed Gitblit instance.
+ *
+ * This is used to track the number of Gitblit instances in the field.
+ * Its purpose is to gauge the popularity of Gitblit and to help
+ * prioritize feature requests.
+ *
+ * The instance id should be unique between different instances, even
+ * on the same machine. But it should stay the same between restarts of
+ * the same instance. It should also stay the same between upgrades of
+ * the same instance. Therefore, it must be stored in a file that is
+ * not overwritten during upgrades, once it has been created.
+ */
+public class GitblitInstanceId
+{
+ static final String STORAGE_FILE = "gbins";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final File idFileBase;
+
+ private UUID id;
+
+
+ /**
+ * Constructor.
+ */
+ public GitblitInstanceId()
+ {
+ this.idFileBase = null;
+ }
+
+ /**
+ * Constructor.
+ */
+ public GitblitInstanceId(File idFileBase)
+ {
+ this.idFileBase = idFileBase;
+ }
+
+
+ /**
+ * Get the instance id.
+ *
+ * @return the instance id.
+ */
+ public UUID getId() {
+ if (this.id == null) {
+ load();
+ }
+ return this.id;
+ }
+
+
+ /**
+ * Load the instance id from the file.
+ */
+ private void load()
+ {
+ if (this.idFileBase == null) {
+ // Not working with stored id.
+ log.debug("No id file base directory specified. Generated id is not persisted.");
+ generate();
+ return;
+ }
+
+ File idFile = new File(this.idFileBase, STORAGE_FILE);
+ if (idFile.exists()) {
+ // Read the file
+ String uuidString = readFromFile(idFile);
+
+ // Parse the UUID
+ try {
+ this.id = UUID.fromString(uuidString);
+ return;
+ }
+ catch (IllegalArgumentException e) {
+ log.debug("Unable to parse instance id. Will generate a new one: {}", e.getMessage(), e);
+ }
+ }
+
+ // Generate a new instance id and persist it to disk.
+ generate();
+ storeToFile(idFile);
+ }
+
+
+ private String readFromFile(File idfile)
+ {
+// log.debug("Loading instance id from file: {}", idfile.getAbsolutePath());
+
+ String string = FileUtils.readContent(idfile, null).trim();
+ String uuidString = string.replaceAll("\\s+","");
+ return uuidString.trim();
+ }
+
+ private void storeToFile(File idfile)
+ {
+ // Make sure that the directory exists
+ if (!idfile.getParentFile().exists()) {
+ if (!idfile.getParentFile().mkdirs()) {
+ log.debug("Unable to create directory for instance id file: {}", idfile.getParentFile().getAbsolutePath());
+ return;
+ }
+ }
+
+ // Write the UUID to the file
+ String uuidString = this.id.toString();
+ FileUtils.writeContent(idfile, uuidString);
+ }
+
+
+ /**
+ * Generate a new instance id and persist it to disk.
+ *
+ * UUID is variant, i.e. OSF DCE, version 8, a custom format.
+ * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ * date -rand-8rnd-8rnd- rand OUI
+ *
+ * The variant nibble has the variant (1) in the upper two bits as 0b10xx,
+ * and the lower two bits are used as a version, currently 0bxx00.
+ * Should the format of this UUID change, the version can be incremented
+ * to 0bxx01 or 0bxx10. Further increments would set the bits in the variant
+ * nibble to 0bxx11 and employ more bits from the next nibble for further
+ * differentiation.
+ */
+ private void generate()
+ {
+ // Start with a random UUID
+ UUID id = UUID.randomUUID();
+ long upper = id.getMostSignificantBits();
+ long lower = id.getLeastSignificantBits();
+
+
+ // Set the variant bits to 0b1000, variant 1, our version 0.
+ lower &= 0x0FFFFFFFFFFFFFFFL; // Clear the variant bits
+ lower |= 0x8000000000000000L; // Set the variant bits to 0b1000
+
+ // Set the version bits to 0b1000, version 8.
+ upper &= 0xFFFFFFFFFFFF0FFFL; // Clear the version bits
+ upper |= 0x0000000000008000L; // Set the version bits to 0b1000
+
+
+ // Set the first four bytes to represent the date.
+ long date = System.currentTimeMillis();
+ date &= 0xFFFFFFFFFFFF0000L; // Clear the last two bytes, those are only a few minutes.
+ date <<= 2 * 8; // We do not need the upper two bytes, that is too far into the future.
+
+ upper &= 0x00000000FFFFFFFFL; // Clear the date bits.
+ upper |= date; // Set the date in the upper 32 bits.
+
+
+ // Set the OUI in the lower three bytes.
+ Long oui = getNodeOUI();
+ if (oui != null) {
+ lower &= 0xFFFFFFFFFF000000L; // Clear the OUI bits.
+ lower |= (0x1000000L | oui); // Set the OUI in the lower three bytes. Mark as valid OUI in bit above them.
+ }
+ else {
+ // Mark this as an invalid OUI, i.e. random bits, by setting the bit above the OUI bits to zero.
+ lower &= 0xFFFFFFFFFEFFFFFFL; // Clear the valid OUI indicator bit.
+ }
+
+ this.id = new UUID(upper, lower);
+ }
+
+
+ /**
+ * Get the OUI of one NIC of this host.
+ *
+ * @return null if no OUI could be detected, otherwise the OUI in the lower three bytes of a Long.
+ */
+ private Long getNodeOUI()
+ {
+ byte[] node = null;
+ String logPrefix = "Unable to detect host. Use random value.";
+
+ try {
+ InetAddress ipa = InetAddress.getLocalHost();
+ NetworkInterface iface = NetworkInterface.getByInetAddress(ipa);
+ if (iface != null) {
+ node = iface.getHardwareAddress();
+ logPrefix = "From getLocalHost:";
+ }
+
+ if (node == null) {
+ List<byte[]> macs = new ArrayList<>();
+ List<byte[]> offmacs = new ArrayList<>();
+ Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ iface = interfaces.nextElement();
+ byte[] mac = iface.getHardwareAddress();
+ if (mac != null) {
+ if (iface.isLoopback()) {
+ continue;
+ }
+ if (iface.isVirtual() || iface.isPointToPoint()) {
+ continue;
+ }
+ if (iface.isUp()) {
+ macs.add(mac);
+ }
+ else {
+ offmacs.add(mac);
+ }
+ }
+ }
+
+ if (macs.size() == 1) {
+ node = macs.get(0);
+ logPrefix = "From up iface:";
+ }
+ else if (offmacs.size() == 1) {
+ node = offmacs.get(0);
+ logPrefix = "From down iface:";
+ }
+ }
+
+ if (node == null) {
+ Socket socket = new Socket("www.gitblit.dev", 80);
+ ipa = socket.getLocalAddress();
+ socket.close();
+ iface = NetworkInterface.getByInetAddress(ipa);
+ if (iface != null) {
+ node = iface.getHardwareAddress();
+ logPrefix = "From socket:";
+ }
+ }
+
+ if (node == null) {
+ log.debug(logPrefix);
+ return null;
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("{} {}", logPrefix, String.format("%02X:%02X:%02X", node[0], node[1], node[2]));
+ }
+
+ long l = (((long)node[0]) << 16) & 0xff0000;
+ l |= (((long)node[1]) << 8) & 0xff00;
+ l |= ((long)node[2]) & 0xff;
+ return l;
+ }
+ catch (IOException e) {
+ log.debug("Exception while getting OUI: {}", e.getMessage(), e);
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/instance/GitblitInstanceReport.java b/src/main/java/com/gitblit/instance/GitblitInstanceReport.java
new file mode 100644
index 00000000..7b8db370
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstanceReport.java
@@ -0,0 +1,43 @@
+package com.gitblit.instance;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+/**
+ * GitblitInstanceReport collects the static and dynamic statistics about a running
+ * Gitblit instance, pairs it with a report version and instance id.
+ * This can then be send to the popularity report server.
+ *
+ */
+class GitblitInstanceReport
+{
+ private final int reportVersion = 1;
+ @SerializedName("instance")
+ private final String instanceId;
+ private final String startTs;
+ private String lpingTs;
+
+ final GitblitInstanceStat instanceStat;
+
+ GitblitInstanceReport(String instanceId, GitblitInstanceStat instanceStat)
+ {
+ this.instanceId = instanceId;
+ this.instanceStat = instanceStat;
+
+ // Convert the timestamp taken from instanceStat to a string in the format "yyyy-MM-dd'T'HHmmssZ" so
+ // it can be used better in a file name. It is replicated here so that it can be directly used by the receiver.
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.startTs = dateFormat.format(instanceStat.startTs);
+ }
+
+ GitblitInstanceReport fromNow()
+ {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.lpingTs = dateFormat.format(System.currentTimeMillis());
+ return this;
+ }
+}
diff --git a/src/main/java/com/gitblit/instance/GitblitInstanceStat.java b/src/main/java/com/gitblit/instance/GitblitInstanceStat.java
new file mode 100644
index 00000000..15ae6fa7
--- /dev/null
+++ b/src/main/java/com/gitblit/instance/GitblitInstanceStat.java
@@ -0,0 +1,127 @@
+package com.gitblit.instance;
+
+import com.gitblit.models.ServerStatus;
+
+import java.util.Date;
+
+/**
+ * GitblitInstanceStat collects the static information about a Gitblit instance,
+ * such as its version, type, operating system and other static data.
+ *
+ */
+class GitblitInstanceStat
+{
+
+ enum GitblitInstanceType {
+ GO,
+ WAR,
+ EXPRESS,
+ DOCKER
+ }
+
+ final GitblitInstanceType instanceType;
+
+ String version;
+ Date startTs;
+ String os;
+ String osName;
+ String osVersion;
+ String osArch;
+ String javaVersion;
+ String javaVendor;
+ String javaRuntimeVersion;
+ String javaRuntimeName;
+ String javaVmVersion;
+ String javaVmName;
+ long maxMem;
+
+
+ GitblitInstanceStat()
+ {
+ this.instanceType = GitblitInstanceType.WAR;
+ initOS();
+ initJava();
+ }
+
+ GitblitInstanceStat(GitblitInstanceType instanceType)
+ {
+ this.instanceType = instanceType;
+ initOS();
+ initJava();
+ }
+
+
+ GitblitInstanceStat init(ServerStatus serverStatus)
+ {
+ this.version = serverStatus.version;
+ this.startTs = serverStatus.bootDate;
+
+ this.maxMem = serverStatus.heapMaximum;
+
+ return this;
+ }
+
+
+ void initOS()
+ {
+ String os = System.getProperty("os.name");
+ if (os == null) {
+ this.os = "Unknown";
+ } else {
+ String oslc = os.toLowerCase();
+ if (oslc.contains("windows")) {
+ this.os = "Windows";
+ } else if (oslc.contains("linux")) {
+ this.os = "Linux";
+ } else if (oslc.contains("mac") || oslc.contains("darwin")) {
+ this.os = "macOS";
+ } else if (oslc.contains("bsd")) {
+ this.os = "BSD";
+ } else if (oslc.contains("solaris") || oslc.contains("sun") ||
+ oslc.contains("aix") || oslc.contains("hpux") || oslc.contains("unix")) {
+ this.os = "Unix";
+ } else {
+ this.os = os;
+ }
+ }
+
+ this.osName = System.getProperty("os.name");
+ this.osVersion = System.getProperty("os.version");
+ this.osArch = System.getProperty("os.arch");
+ }
+
+ void initJava()
+ {
+ this.javaVersion = System.getProperty("java.version");
+ this.javaVendor = System.getProperty("java.vendor");
+ this.javaRuntimeVersion = System.getProperty("java.runtime.version", "");
+ this.javaRuntimeName = System.getProperty("java.runtime.name", "");
+ this.javaVmVersion = System.getProperty("java.vm.version", "");
+ this.javaVmName = System.getProperty("java.vm.name", "");
+ }
+
+
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("GitblitInstanceStat {")
+ .append("\n instanceType: ").append(instanceType)
+ .append(",\n version: ").append(version)
+ .append(",\n startTs: ").append(startTs)
+ .append(",\n os: ").append(os)
+ .append(",\n osName: ").append(osName)
+ .append(",\n osVersion: ").append(osVersion)
+ .append(",\n osArch: ").append(osArch)
+ .append(",\n javaVersion: ").append(javaVersion)
+ .append(",\n javaVendor: ").append(javaVendor)
+ .append(",\n javaRuntimeVersion: ").append(javaRuntimeVersion)
+ .append(",\n javaRuntimeName: ").append(javaRuntimeName)
+ .append(",\n javaVmVersion: ").append(javaVmVersion)
+ .append(",\n javaVmName: ").append(javaVmName)
+ .append(",\n maxMem: ").append(maxMem)
+ .append("\n}");
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/gitblit/models/ServerStatus.java b/src/main/java/com/gitblit/models/ServerStatus.java
index bb6396bc..db56f8f9 100644
--- a/src/main/java/com/gitblit/models/ServerStatus.java
+++ b/src/main/java/com/gitblit/models/ServerStatus.java
@@ -51,9 +51,9 @@ public class ServerStatus implements Serializable {
public String servletContainer;
- public ServerStatus() {
+ public ServerStatus(String version) {
this.bootDate = new Date();
- this.version = Constants.getVersion();
+ this.version = version;
this.releaseDate = Constants.getBuildDate();
this.heapMaximum = Runtime.getRuntime().maxMemory();
@@ -76,6 +76,10 @@ public class ServerStatus implements Serializable {
put("os.version");
}
+ public ServerStatus() {
+ this(Constants.getVersion());
+ }
+
private void put(String key) {
systemProperties.put(key, System.getProperty(key));
}
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index cd8615a8..b370867c 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -32,6 +32,7 @@ import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
+import com.gitblit.instance.GitblitInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -87,6 +88,8 @@ public class GitblitContext extends GuiceServletContextListener {
private final File goBaseFolder;
+ private final GitblitInstance instance = new GitblitInstance();
+
/**
* Construct a Gitblit WAR/Express context.
*/
@@ -224,6 +227,10 @@ public class GitblitContext extends GuiceServletContextListener {
logger.error(null, t);
}
}
+
+ instance.init(runtime);
+ // The instance is up and running. Make it count.
+ instance.start();
}
private String lookupBaseFolderFromJndi() {
@@ -303,6 +310,8 @@ public class GitblitContext extends GuiceServletContextListener {
}
}
+ this.instance.stop();
+
for (IManager manager : managers) {
logger.debug("stopping {}", manager.getClass().getSimpleName());
manager.stop();
diff --git a/src/main/java/com/gitblit/tickets/TicketNotifier.java b/src/main/java/com/gitblit/tickets/TicketNotifier.java
index f284e7be..a16b3753 100644
--- a/src/main/java/com/gitblit/tickets/TicketNotifier.java
+++ b/src/main/java/com/gitblit/tickets/TicketNotifier.java
@@ -17,6 +17,7 @@ package com.gitblit.tickets;
import java.io.IOException;
import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
@@ -640,7 +641,7 @@ public class TicketNotifier {
for (String line : lines) {
sb.append(line).append('\n');
}
- } catch (IOException e) {
+ } catch (UncheckedIOException e) {
} finally {
if (is != null) {
diff --git a/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
index b6d233cf..06444606 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
@@ -54,10 +54,7 @@ public class SshKrbAuthenticator extends GSSAuthenticator {
public boolean validateIdentity(ServerSession session, String identity) {
log.info("identify with kerberos {}", identity);
SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
- if (client.getUser() != null) {
- log.info("{} has already authenticated!", identity);
- return true;
- }
+
String username = identity.toLowerCase(Locale.US);
if (stripDomain) {
int p = username.indexOf('@');
@@ -67,6 +64,7 @@ public class SshKrbAuthenticator extends GSSAuthenticator {
}
UserModel user = authManager.authenticate(username);
if (user != null) {
+// TODO: Check if the user was set in the client and if it is the same as this user. Do not allow changing the user during the SSH auth process.
client.setUser(user);
return true;
}
diff --git a/src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java
index e9e2d7e1..fa56baa8 100644
--- a/src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java
+++ b/src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java
@@ -45,14 +45,11 @@ public class UsernamePasswordAuthenticator implements PasswordAuthenticator {
@Override
public boolean authenticate(String username, String password, ServerSession session) {
SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
- if (client.getUser() != null) {
- log.info("{} has already authenticated!", username);
- return true;
- }
username = username.toLowerCase(Locale.US);
UserModel user = authManager.authenticate(username, password.toCharArray(), null);
if (user != null) {
+// TODO: Check if the user was set in the client and if it is the same as this user. Do not allow changing the user during the SSH auth process.
client.setUser(user);
return true;
}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index 221878e1..40f84538 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = A team must specify at least one repository.
gb.teamCreated = New team ''{0}'' successfully created.
gb.pleaseSetUsername = Please enter a username!
gb.usernameUnavailable = Username ''{0}'' is unavailable.
-gb.combinedMd5Rename = Gitblit is configured for combined-md5 password hashing. You must enter a new password on account rename.
+gb.combinedMd5Rename = This user is configured for combined-md5 password hashing. You must enter a new password on account rename.
gb.userCreated = New user ''{0}'' successfully created.
gb.couldNotFindFederationRegistration = Could not find federation registration!
gb.failedToFindGravatarProfile = Failed to find Gravatar profile for {0}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties
index 6c08bd60..8990b823 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = Ein Team muss mindestens einem Repository zugewie
gb.teamCreated = Neues Team ''{0}'' erfolgreich angelegt.
gb.pleaseSetUsername = Bitte geben Sie einen Benutzernamen an!
gb.usernameUnavailable = Benutzername ''{0}'' ist nicht verf\u00fcgbar.
-gb.combinedMd5Rename = Gitblit ist f\u00fcr kombiniertes MD5-Passwort-Hashing konfiguriert. Sie m\u00fcssen beim Umbenennen des Kontos ein neues Passwort angeben.
+gb.combinedMd5Rename = Dieser Benutzer ist f\u00fcr kombiniertes MD5-Passwort-Hashing konfiguriert. Sie m\u00fcssen beim Umbenennen des Kontos ein neues Passwort angeben.
gb.userCreated = Neuer Benutzer ''{0}'' erfolgreich angelegt.
gb.couldNotFindFederationRegistration = Konnte Verbindungsregistrierung (Federation) nicht finden!
gb.failedToFindGravatarProfile = Das Gravatar Profil f\u00fcr {0} konnte nicht gefunden werden
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties
index 2865aa91..83690fc2 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = Debe especificar al menos un repositorio para el
gb.teamCreated = Nuevo Equipo ''{0}'' creado satisfactoriamente.
gb.pleaseSetUsername = \u00A1Por favor, introduce un usuario!
gb.usernameUnavailable = El usuario ''{0}'' no est\u00E1 disponible.
-gb.combinedMd5Rename = GitBlit est\u00E1 configurado para Hashes combinados md5. Debes introducir una nueva contrase\u00F1a para renombrar la cuenta.
+gb.combinedMd5Rename = El usuario est\u00E1 configurado para Hashes combinados md5. Debes introducir una nueva contrase\u00F1a para renombrar la cuenta.
gb.userCreated = Nuevo usuario ''{0}'' creado satisfactoriamente.
gb.couldNotFindFederationRegistration = \u00A1No se pudo encontrar el registro de federaci\u00F3n!
gb.failedToFindGravatarProfile = Fallo al buscar el perfil Gravatar de {0}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties
index f02748c0..2a5f2aa2 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = Une \u00e9quipe doit d\u00e9finir au moins un d\u
gb.teamCreated = La nouvelle \u00e9quipe ''{0}'' cr\u00e9\u00e9 avec succ\u00e8s.
gb.pleaseSetUsername = Entrez un identifiant SVP !
gb.usernameUnavailable = L'identifiant ''{0}'' est indisponible.
-gb.combinedMd5Rename = Gitblit est configur\u00e9 pour des mots de passe hash\u00e9s combined-md5. Vous devez entrer un nouveau mot de passe pour ce compte.
+gb.combinedMd5Rename = L'identifiant est configur\u00e9 pour des mots de passe hash\u00e9s combined-md5. Vous devez entrer un nouveau mot de passe pour ce compte.
gb.userCreated = Le nouveau utilisateur ''{0}'' est cr\u00e9\u00e9 avec succ\u00e8s.
gb.couldNotFindFederationRegistration = N'arrive pas \u00e0 joindre l'enregistrement de la f\u00e9d\u00e9ration !
gb.failedToFindGravatarProfile = N'arrive pas trouver un profil Gravatar pour {0}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties
index e0c406fe..9c08c377 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = Un gruppo deve specificare almeno un repository.
gb.teamCreated = Nuovo gruppo ''{0}'' creato con successo.
gb.pleaseSetUsername = Nome utente non specificato!
gb.usernameUnavailable = Il nome utente ''{0}'' non è disponibile.
-gb.combinedMd5Rename = Gitblit è configurato per effettuare un hashing delle password di tipo combinato-md5. E' quindi necessario specificare una nuova password quando si rinomina un utenza.
+gb.combinedMd5Rename = Il nome utente è configurato per effettuare un hashing delle password di tipo combinato-md5. E' quindi necessario specificare una nuova password quando si rinomina un utenza.
gb.userCreated = Nuovo utente ''{0}'' creato con successo.
gb.couldNotFindFederationRegistration = Impossibile trovare la registrazione di federazione!
gb.failedToFindGravatarProfile = Profilo Gravatar per {0} non reperito!
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties
index a869e96b..e05c1940 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = Een team moet minimaal één repositorie specific
gb.teamCreated = Nieuw team ''{0}'' successvol aangemaakt.
gb.pleaseSetUsername = Vul aub een gebruikersnaam in!
gb.usernameUnavailable = Gebruikersnaam ''{0}'' is niet beschikbaar.
-gb.combinedMd5Rename = Gitblit is geconfigureerd voor combined-md5 wachtwoord hashing. U moet een nieuw wachtwoord opgeven bij het hernoemen van een account.
+gb.combinedMd5Rename = Gebruikersnaam is geconfigureerd voor combined-md5 wachtwoord hashing. U moet een nieuw wachtwoord opgeven bij het hernoemen van een account.
gb.userCreated = Nieuwe gebruiker ''{0}'' succesvol aangemaakt.
gb.couldNotFindFederationRegistration = Kon de federatie registratie niet vinden!
gb.failedToFindGravatarProfile = Kon het Gravatar profiel voor {0} niet vinden
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties
index 96522ec6..1efc6363 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties
@@ -248,7 +248,7 @@ gb.teamMustSpecifyRepository = Et team m\u00e5 ha minst et repository.
gb.teamCreated = Team ''{0}'' opprettet.
gb.pleaseSetUsername = Vennlist angi et brukernavn!
gb.usernameUnavailable = Brukernavnet ''{0}'' er ikke tilgjengelig.
-gb.combinedMd5Rename = Gitblit er satt opp med combined-md5 passord hashing. Du m\u00e5 angi et nytt passord n\u00e5r du gir en konto et nytt navn.
+gb.combinedMd5Rename = Brukernavnet er satt opp med combined-md5 passord hashing. Du m\u00e5 angi et nytt passord n\u00e5r du gir en konto et nytt navn.
gb.userCreated = Ny bruker ''{0}'' opprettet.
gb.couldNotFindFederationRegistration = Kunne ikke finne federeringsoppf\u00F8ringen!
gb.failedToFindGravatarProfile = Fant ikke gravatar-profilen for {0}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties
index a4753e72..a2e107fd 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties
@@ -246,8 +246,8 @@ gb.teamNameUnavailable = Nazwa zespo\u0142u ''{0}'' jest niedost\u0119pna.
gb.teamMustSpecifyRepository = Zesp\u00F3\u0142 musi posiada\u0107 conajmniej jedno repozytorium.
gb.teamCreated = Zesp\u00F3\u0142 ''{0}'' zosta\u0142 utworzony.
gb.pleaseSetUsername = Wpisz nazw\u0119 u\u017Cytkownika!
-gb.usernameUnavailable = Nazwa u\u017Cytkownika''{0}'' jest niedost\u0119pna.
-gb.combinedMd5Rename = Gitblit jest skonfigurowany na po\u0142\u0105czone haszowanie hase\u0142 md5. Musisz wpisa\u0107 nowe has\u0142o przy zmianie nazwy konta.
+gb.usernameUnavailable = Nazwa u\u017Cytkownika ''{0}'' jest niedost\u0119pna.
+gb.combinedMd5Rename = Nazwa u\u017Cytkownika jest skonfigurowany na po\u0142\u0105czone haszowanie hase\u0142 md5. Musisz wpisa\u0107 nowe has\u0142o przy zmianie nazwy konta.
gb.userCreated = U\u017Cytkownik ''{0}'' zosta\u0142 utworzony.
gb.couldNotFindFederationRegistration = Nie mo\u017Cna znale\u017A\u0107 rejestracji federacji!
gb.failedToFindGravatarProfile = B\u0142\u0105d podczas dopasowania profilu Gravatar dla {0}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties
index 26b6838d..b8473d2c 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties
@@ -247,7 +247,7 @@ gb.teamMustSpecifyRepository = Uma equipe deve especificar pelo menos um reposit
gb.teamCreated = Nova equipe ''{0}'' criada com sucesso.
gb.pleaseSetUsername = Por favor entre com um username!
gb.usernameUnavailable = Username ''{0}'' est\u00e1 indispon\u00edvel.
-gb.combinedMd5Rename = Gitblit est\u00e1 configurado para usar um hash combinado-md5. Voc\u00ea deve inserir um novo password ao renamear a conta.
+gb.combinedMd5Rename = Username est\u00e1 configurado para usar um hash combinado-md5. Voc\u00ea deve inserir um novo password ao renamear a conta.
gb.userCreated = Novo usu\u00e1rio ''{0}'' criado com sucesso.
gb.couldNotFindFederationRegistration = N\u00e3o foi poss\u00edvel localizar o registro da federa\u00e7\u00e3o!
gb.failedToFindGravatarProfile = Falha ao localizar um perfil Gravatar para {0}
diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.java b/src/main/java/com/gitblit/wicket/pages/BasePage.java
index 0d99f5e5..72e6a283 100644
--- a/src/main/java/com/gitblit/wicket/pages/BasePage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BasePage.java
@@ -17,6 +17,7 @@ package com.gitblit.wicket.pages;
import java.io.IOException;
import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
@@ -495,7 +496,7 @@ public abstract class BasePage extends SessionPage {
for (String line : lines) {
sb.append(line).append('\n');
}
- } catch (IOException e) {
+ } catch (UncheckedIOException e) {
} finally {
if (is != null) {
diff --git a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
index c6014e8f..add83dce 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
@@ -93,8 +93,11 @@ public class EditUserPage extends RootSubPage {
super.setupPage(getString("gb.edit"), userModel.username);
}
- final Model<String> confirmPassword = new Model<String>(
- StringUtils.isEmpty(userModel.password) ? "" : userModel.password);
+ final Model<String> confirmPassword = new Model<String>("");
+
+ // Saving current password of user and clearing the one in the model so that it doesn't show up in the page.
+ final String oldPassword = userModel.password;
+ userModel.password = "";
CompoundPropertyModel<UserModel> model = new CompoundPropertyModel<UserModel>(userModel);
// build list of projects including all repositories wildcards
@@ -149,13 +152,15 @@ public class EditUserPage extends RootSubPage {
boolean rename = !StringUtils.isEmpty(oldName)
&& !oldName.equalsIgnoreCase(username);
if (app().authentication().supportsCredentialChanges(userModel)) {
- if (!userModel.password.equals(confirmPassword.getObject())) {
- error(getString("gb.passwordsDoNotMatch"));
- return;
- }
- String password = userModel.password;
- if (!PasswordHash.isHashedEntry(password)) {
- // This is a plain text password.
+
+ if (!StringUtils.isEmpty(userModel.password)) {
+ // The password was changed
+ String password = userModel.password;
+ if (!password.equals(confirmPassword.getObject())) {
+ error(getString("gb.passwordsDoNotMatch"));
+ return;
+ }
+
// Check length.
int minLength = app().settings().getInteger(Keys.realm.minPasswordLength, 5);
if (minLength < 4) {
@@ -170,16 +175,19 @@ public class EditUserPage extends RootSubPage {
// change the cookie
userModel.cookie = userModel.createCookie();
- // Optionally store the password MD5 digest.
+ // Optionally store the password hash digest.
String type = app().settings().getString(Keys.realm.passwordStorage, PasswordHash.getDefaultType().name());
PasswordHash pwdh = PasswordHash.instanceOf(type);
if (pwdh != null) { // Hash the password
userModel.password = pwdh.toHashedEntry(password, username);
}
- } else if (rename
- && password.toUpperCase().startsWith(PasswordHash.Type.CMD5.name())) {
- error(getString("gb.combinedMd5Rename"));
- return;
+ } else {
+ if (rename && oldPassword.toUpperCase().startsWith(PasswordHash.Type.CMD5.name())) {
+ error(getString("gb.combinedMd5Rename"));
+ return;
+ }
+ // Set back saved password so that it is kept in the DB.
+ userModel.password = oldPassword;
}
}
@@ -251,10 +259,12 @@ public class EditUserPage extends RootSubPage {
form.add(new TextField<String>("username").setEnabled(editCredentials));
NonTrimmedPasswordTextField passwordField = new NonTrimmedPasswordTextField("password");
passwordField.setResetPassword(false);
+ passwordField.setRequired(false);
form.add(passwordField.setEnabled(editCredentials));
NonTrimmedPasswordTextField confirmPasswordField = new NonTrimmedPasswordTextField("confirmPassword",
confirmPassword);
confirmPasswordField.setResetPassword(false);
+ confirmPasswordField.setRequired(false);
form.add(confirmPasswordField.setEnabled(editCredentials));
form.add(new TextField<String>("displayName").setEnabled(editDisplayName));
form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress));
diff --git a/src/site/templates/ghreleasenotes.awk b/src/site/templates/ghreleasenotes.awk
index f4479552..455334a1 100755
--- a/src/site/templates/ghreleasenotes.awk
+++ b/src/site/templates/ghreleasenotes.awk
@@ -6,7 +6,7 @@ BEGIN { on=0 ; skip=1 ; block=0 ; section=""}
/r[0-9]+: *{/ { on=1 ; next }
/^[[:blank:]]*}[[:blank:]]*$/ { if (on) {
- print "[Full release notes on gitblit.com](http://gitblit.com/releases.html#" relId ")"
+ print "[Full release notes on gitblit.com](http://www.gitblit.com/releases.html#" relId ")"
exit 0
}
}
diff --git a/src/test/config/test-gitblit.properties b/src/test/config/test-gitblit.properties
index ef6a6c51..1b988cf7 100644
--- a/src/test/config/test-gitblit.properties
+++ b/src/test/config/test-gitblit.properties
@@ -1,6 +1,7 @@
#
# Gitblit Unit Testing properties
#
+gitblit.testRun = true
git.allowAnonymousPushes = true
git.defaultAccessRestriction = NONE
git.repositoriesFolder = ${baseFolder}/git
diff --git a/src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java b/src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java
new file mode 100644
index 00000000..e1c03757
--- /dev/null
+++ b/src/test/java/com/gitblit/instance/GitblitInstanceIdTest.java
@@ -0,0 +1,158 @@
+package com.gitblit.instance;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+public class GitblitInstanceIdTest
+{
+ @Rule
+ public TemporaryFolder baseFolder = new TemporaryFolder();
+
+ /**
+ * Tests that the version nibble is set to 0x8.
+ */
+ @Test
+ public void testUuidVersion() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId();
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long upper = uuid.getMostSignificantBits();
+ assertEquals(0x0000000000008000L, (upper & 0x000000000000F000L));
+ }
+
+ /**
+ * Tests that the variant nibble is set to 0x8.
+ */
+ @Test
+ public void testUuidVariant() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId();
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long lower = uuid.getLeastSignificantBits();
+ assertEquals(0x8000000000000000L, (lower & 0xF000000000000000L));
+ }
+
+ /**
+ * Test that the first four bytes hold a timestamp in a newly generated id.
+ */
+ @Test
+ public void testDatePart() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId();
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long upper = uuid.getMostSignificantBits();
+ long ts = System.currentTimeMillis();
+ assertEquals("Date part of UUID does not equal current date/time.", ts >> 2*8, upper >> 4*8);
+ }
+
+
+
+ /**
+ * Test that a new id is generated and stored in a file, when none existed.
+ */
+ @Test
+ public void testStoreId() throws Exception
+ {
+ GitblitInstanceId id = new GitblitInstanceId(baseFolder.getRoot());
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long lower = uuid.getLeastSignificantBits();
+ assertEquals(0x8000000000000000L, (lower & 0xF000000000000000L));
+ long upper = uuid.getMostSignificantBits();
+ assertEquals(0x0000000000008000L, (upper & 0x000000000000F000L));
+
+ File idFile = new File(baseFolder.getRoot(), GitblitInstanceId.STORAGE_FILE);
+ assertTrue("Id file was not created", idFile.exists());
+
+ String string = Files.readAllLines(idFile.toPath()).get(0);
+ try {
+ UUID uuidFromFile = UUID.fromString(string);
+ assertEquals("Returned id and id read from file are not equal.", uuid, uuidFromFile);
+ } catch (IllegalArgumentException e) {
+ fail("UUID read from file is not valid: " + string);
+ }
+ }
+
+
+ /**
+ * Test that a new id is generated and stored in a file, when none existed.
+ */
+ @Test
+ public void testStoreIdNonexistingFolder() throws Exception
+ {
+ File baseSubFolder = new File(baseFolder.getRoot(), "nonexisting");
+
+ GitblitInstanceId id = new GitblitInstanceId(baseSubFolder);
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+ long lower = uuid.getLeastSignificantBits();
+ assertEquals(0x8000000000000000L, (lower & 0xF000000000000000L));
+ long upper = uuid.getMostSignificantBits();
+ assertEquals(0x0000000000008000L, (upper & 0x000000000000F000L));
+
+ File idFile = new File(baseSubFolder, GitblitInstanceId.STORAGE_FILE);
+ assertTrue("Id file was not created", idFile.exists());
+
+ String string = Files.readAllLines(idFile.toPath()).get(0);
+ try {
+ UUID uuidFromFile = UUID.fromString(string);
+ assertEquals("Returned id and id read from file are not equal.", uuid, uuidFromFile);
+ } catch (IllegalArgumentException e) {
+ fail("UUID read from file is not valid: " + string);
+ }
+ }
+
+
+ /**
+ * Test that an existing id is read from an existing id file.
+ */
+ @Test
+ public void testReadId() throws Exception
+ {
+ File idFile = new File(baseFolder.getRoot(), GitblitInstanceId.STORAGE_FILE);
+ String uuidString = "0196e409-c664-82f3-88f1-e963d16c7b8a";
+ Files.write(idFile.toPath(), uuidString.getBytes());
+
+ GitblitInstanceId id = new GitblitInstanceId(baseFolder.getRoot());
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+
+ UUID refUuid = UUID.fromString(uuidString);
+ assertEquals("Returned id is not equal to reference id", refUuid, uuid);
+ }
+
+
+ /**
+ * Test reading id from a file with whitespace
+ */
+ @Test
+ public void testReadIdWhitespace() throws Exception
+ {
+ File idFile = new File(baseFolder.getRoot(), GitblitInstanceId.STORAGE_FILE);
+ String uuidString = "0196e409-c664-82f3-88f1-e963d16c7b8a";
+ String fileString = "\n " + uuidString + " \n \n";
+ Files.write(idFile.toPath(), fileString.getBytes());
+
+ GitblitInstanceId id = new GitblitInstanceId(baseFolder.getRoot());
+ UUID uuid = id.getId();
+ assertNotNull(uuid);
+
+ UUID refUuid = UUID.fromString(uuidString);
+ assertEquals("Returned id is not equal to reference id", refUuid, uuid);
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java b/src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java
new file mode 100644
index 00000000..0b883a33
--- /dev/null
+++ b/src/test/java/com/gitblit/instance/GitblitInstanceStatTest.java
@@ -0,0 +1,184 @@
+package com.gitblit.instance;
+
+import com.gitblit.Constants;
+import com.gitblit.models.ServerStatus;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Date;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class GitblitInstanceStatTest
+{
+
+ protected GitblitInstanceStat instanceStat;
+ protected ServerStatus serverStatus;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ instanceStat = new GitblitInstanceStat();
+ serverStatus = new ServerStatus();
+ instanceStat.init(serverStatus);
+ }
+
+
+ @Test
+ public void testGetVersion()
+ {
+ String version = instanceStat.version;
+ assertNotNull(version);
+ assertFalse(version.isEmpty());
+ assertEquals(Constants.getVersion(), version);
+ }
+
+ @Test
+ public void testGetStartTs()
+ {
+ Date date = instanceStat.startTs;
+ assertNotNull(date);
+ assertEquals(serverStatus.bootDate, date);
+ }
+
+ @Test
+ public void testGetType()
+ {
+ String type = instanceStat.instanceType.name();
+ assertNotNull(type);
+ assertFalse(type.isEmpty());
+ assertEquals("WAR", type);
+ }
+
+ @Test
+ public void testGetOS()
+ {
+ String os = instanceStat.os;
+
+ String oslc = System.getProperty("os.name").toLowerCase();
+
+ if (oslc.contains("windows")) {
+ assertEquals("Windows", os);
+ }
+ else if (oslc.contains("linux")) {
+ assertEquals("Linux", os);
+ }
+ else if (oslc.contains("mac")) {
+ assertEquals("macOS", os);
+ }
+ }
+
+ @Test
+ public void testGetOSName()
+ {
+ String name = instanceStat.osName;
+ assertNotNull(name);
+ assertFalse(name.isEmpty());
+ assertEquals(System.getProperty("os.name"), name);
+ }
+
+ @Test
+ public void testGetOSVersion()
+ {
+ String version = instanceStat.osVersion;
+ assertNotNull(version);
+ assertFalse(version.isEmpty());
+ assertEquals(System.getProperty("os.version"), version);
+ }
+
+ @Test
+ public void testGetOSArch()
+ {
+ String arch = instanceStat.osArch;
+ assertNotNull(arch);
+ assertFalse(arch.isEmpty());
+ assertEquals(System.getProperty("os.arch"), arch);
+ }
+
+ @Test
+ public void testGetJavaVersion()
+ {
+ String version = instanceStat.javaVersion;
+ assertNotNull(version);
+ assertFalse(version.isEmpty());
+ assertEquals(System.getProperty("java.version"), version);
+ }
+
+ @Test
+ public void testGetJavaVendor()
+ {
+ String vendor = instanceStat.javaVendor;
+ assertNotNull(vendor);
+ assertFalse(vendor.isEmpty());
+ assertEquals(System.getProperty("java.vendor"), vendor);
+ }
+
+ @Test
+ public void testGetJavaRuntimeVersion()
+ {
+ String rt = instanceStat.javaRuntimeVersion;
+ assertNotNull(rt);
+ assertFalse(rt.isEmpty());
+ assertEquals(System.getProperty("java.runtime.version"), rt);
+ }
+
+ @Test
+ public void testGetJavaRuntimeName()
+ {
+ String rt = instanceStat.javaRuntimeName;
+ assertNotNull(rt);
+ assertFalse(rt.isEmpty());
+ assertEquals(System.getProperty("java.runtime.name"), rt);
+ }
+
+ @Test
+ public void testGetJavaVmVersion()
+ {
+ String vm = instanceStat.javaVmVersion;
+ assertNotNull(vm);
+ assertFalse(vm.isEmpty());
+ assertEquals(System.getProperty("java.vm.version"), vm);
+ }
+
+ @Test
+ public void testGetJavaVmName()
+ {
+ String vm = instanceStat.javaVmName;
+ assertNotNull(vm);
+ assertFalse(vm.isEmpty());
+ assertEquals(System.getProperty("java.vm.name"), vm);
+ }
+
+ @Test
+ public void testGetMaxMem()
+ {
+ long maxMem = instanceStat.maxMem;
+ assertTrue(maxMem > 0);
+ assertEquals(Runtime.getRuntime().maxMemory(), maxMem);
+ }
+
+ @Test
+ public void testToString()
+ {
+ String str = instanceStat.toString();
+ assertNotNull(str);
+ assertFalse(str.isEmpty());
+ assertTrue(str.contains("GitblitInstanceStat"));
+ assertTrue(str.contains("version"));
+ assertTrue(str.contains("instanceType"));
+ assertTrue(str.contains("os"));
+ assertTrue(str.contains("osName"));
+ assertTrue(str.contains("osVersion"));
+ assertTrue(str.contains("osArch"));
+ assertTrue(str.contains("javaVersion"));
+ assertTrue(str.contains("javaVendor"));
+ assertTrue(str.contains("javaRuntimeVersion"));
+ assertTrue(str.contains("javaRuntimeName"));
+ assertTrue(str.contains("javaVmVersion"));
+ assertTrue(str.contains("javaVmName"));
+
+ }
+}
diff --git a/src/test/java/com/gitblit/instance/GitblitInstanceTest.java b/src/test/java/com/gitblit/instance/GitblitInstanceTest.java
new file mode 100644
index 00000000..8ebc5d2a
--- /dev/null
+++ b/src/test/java/com/gitblit/instance/GitblitInstanceTest.java
@@ -0,0 +1,64 @@
+package com.gitblit.instance;
+
+import com.gitblit.manager.IRuntimeManager;
+
+import com.gitblit.models.ServerStatus;
+import com.gitblit.tests.mock.MockRuntimeManager;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+
+public class GitblitInstanceTest
+{
+ @Test
+ public void testShouldNotReportUnintialized()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ assertFalse(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldNotReportInTests()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ instance.init(new MockRuntimeManager());
+ assertFalse(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldNotReportInSnapshotVersion()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ IRuntimeManager runtimeManager = new MockRuntimeManager();
+ runtimeManager.getSettings().overrideSetting("gitblit.testRun", "false");
+ instance.init(runtimeManager);
+ assertFalse(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldReportIfForced()
+ {
+ GitblitInstance instance = new GitblitInstance();
+ IRuntimeManager runtimeManager = new MockRuntimeManager();
+ runtimeManager.getSettings().overrideSetting("gitblit.testRunReporting", "true");
+ instance.init(runtimeManager);
+ assertTrue(instance.shouldRunReports());
+ }
+
+ @Test
+ public void testShouldReportInReleaseVersion()
+ {
+ ServerStatus serverStatus = new ServerStatus("1.10.123");
+ MockRuntimeManager runtimeManager = new MockRuntimeManager();
+ runtimeManager.setStatus(serverStatus);
+ runtimeManager.getSettings().overrideSetting("gitblit.testRun", "false");
+
+ GitblitInstance instance = new GitblitInstance();
+ instance.init(runtimeManager);
+ assertTrue(instance.shouldRunReports());
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java
index fbae039c..e0328112 100644
--- a/src/test/java/com/gitblit/tests/GitBlitSuite.java
+++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -26,6 +26,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import com.gitblit.instance.GitblitInstanceIdTest;
+import com.gitblit.instance.GitblitInstanceStatTest;
+import com.gitblit.instance.GitblitInstanceTest;
import com.gitblit.utils.TimeUtilsTest;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
@@ -74,7 +77,8 @@ import com.gitblit.utils.JGitUtils;
ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class,
- GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class, TicketReferenceTest.class })
+ GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class, TicketReferenceTest.class,
+ GitblitInstanceIdTest.class, GitblitInstanceStatTest.class, GitblitInstanceTest.class })
public class GitBlitSuite {
public static final File BASEFOLDER = new File("data");
@@ -216,7 +220,7 @@ public class GitBlitSuite {
}
cloneOrFetch("helloworld.git", HELLOWORLD_REPO_SOURCE.getAbsolutePath());
cloneOrFetch("ticgit.git", TICGIT_REPO_SOURCE.getAbsolutePath());
- cloneOrFetch("test/jgit.git", "https://github.com/eclipse/jgit.git");
+ cloneOrFetch("test/jgit.git", "https://github.com/eclipse-jgit/jgit.git");
cloneOrFetch("test/helloworld.git", HELLOWORLD_REPO_SOURCE.getAbsolutePath());
cloneOrFetch("test/ambition.git", AMBITION_REPO_SOURCE.getAbsolutePath());
cloneOrFetch("test/gitective.git", GITECTIVE_REPO_SOURCE.getAbsolutePath());
diff --git a/src/test/java/com/gitblit/tests/GitblitUnitTest.java b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
index 58bc60e4..2d915612 100644
--- a/src/test/java/com/gitblit/tests/GitblitUnitTest.java
+++ b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
@@ -31,7 +31,10 @@ import com.gitblit.servlet.GitblitContext;
public class GitblitUnitTest extends org.junit.Assert {
public static IStoredSettings settings() {
- return runtime().getSettings();
+ IStoredSettings settings = runtime().getSettings();
+ // Insert marker that this is running as a test
+ settings.overrideSetting("gitblit.testRun", "true");
+ return settings;
}
public static IRuntimeManager runtime() {
diff --git a/src/test/java/com/gitblit/tests/SshDaemonTest.java b/src/test/java/com/gitblit/tests/SshDaemonTest.java
index c7d06198..e88dc9bb 100644
--- a/src/test/java/com/gitblit/tests/SshDaemonTest.java
+++ b/src/test/java/com/gitblit/tests/SshDaemonTest.java
@@ -16,10 +16,12 @@
package com.gitblit.tests;
import java.io.File;
+import java.security.KeyPair;
import java.text.MessageFormat;
import java.util.List;
import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.session.ClientSession;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
@@ -42,11 +44,72 @@ public class SshDaemonTest extends SshUnitTest {
String url = GitBlitSuite.sshDaemonUrl;
@Test
+ public void testPasswordAuthentication() throws Exception {
+ SshClient client = getClient();
+ ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
+
+ session.addPasswordIdentity(password);
+ AuthFuture authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertTrue(authFuture.isSuccess());
+ }
+
+ @Test
public void testPublicKeyAuthentication() throws Exception {
SshClient client = getClient();
ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
+
session.addPublicKeyIdentity(rwKeyPair);
- assertTrue(session.auth().await());
+ AuthFuture authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertTrue(authFuture.isSuccess());
+ }
+
+ @Test
+ public void testWrongPublicKeyAuthentication() throws Exception {
+ SshClient client = getClient();
+ ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
+ KeyPair attackKeyPair = generator.generateKeyPair();
+
+ session.addPublicKeyIdentity(attackKeyPair);
+ AuthFuture authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertFalse(authFuture.isSuccess());
+ }
+
+ @Test
+ public void testWrongPublicKeyThenPasswordAuthentication() throws Exception {
+ SshClient client = getClient();
+ ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
+ KeyPair otherKeyPair = generator.generateKeyPair();
+
+ session.addPublicKeyIdentity(otherKeyPair);
+ AuthFuture authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertFalse(authFuture.isSuccess());
+
+ session.addPasswordIdentity(password);
+ authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertTrue(authFuture.isSuccess());
+ }
+
+ @Test
+ public void testWrongPublicKeyThenWrongPasswordAuthentication() throws Exception {
+ SshClient client = getClient();
+ ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
+ KeyPair otherKeyPair = generator.generateKeyPair();
+ KeyPair attackKeyPair = new KeyPair(rwKeyPair.getPublic(), otherKeyPair.getPrivate());
+
+ session.addPublicKeyIdentity(attackKeyPair);
+ AuthFuture authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertFalse(authFuture.isSuccess());
+
+ session.addPasswordIdentity("nothing");
+ authFuture = session.auth();
+ assertTrue(authFuture.await());
+ assertFalse(authFuture.isSuccess());
}
@Test
diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
index 8897ef7e..1553e2a5 100644
--- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
+++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -52,6 +52,8 @@ public class MockRuntimeManager implements IRuntimeManager {
public MockRuntimeManager(IStoredSettings settings) {
this.settings = settings;
+ // Insert marker that this is running as a test
+ settings.overrideSetting("gitblit.testRun", "true");
this.serverStatus = new ServerStatus();
this.serverStatus.servletContainer = "MockServer";
@@ -94,6 +96,11 @@ public class MockRuntimeManager implements IRuntimeManager {
return serverStatus.bootDate;
}
+ public void setStatus(ServerStatus status)
+ {
+ this.serverStatus = status;
+ }
+
@Override
public ServerStatus getStatus() {
// update heap memory status