www.github.com/gitblit/gitblit.git
Advanced tools
Sorry, the diff of this file is not supported yet
@@ -1,2 +0,2 @@ | ||
| name: Continous integration | ||
| name: Continous build - build and test on every push | ||
@@ -8,13 +8,10 @@ on: | ||
| - gh-pages | ||
| pull_request: | ||
| branches-ignore: | ||
| - 'release*' | ||
| - gh-pages | ||
| jobs: | ||
| build_linux: | ||
| name: Linux build and test | ||
| runs-on: ubuntu-latest | ||
| build: | ||
| name: Build and test | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| matrix: | ||
| os: [ubuntu-latest, windows-latest] | ||
| java-version: [8, 11] | ||
@@ -24,3 +21,3 @@ | ||
| - name: Checkout | ||
| uses: actions/checkout@v3 | ||
| uses: actions/checkout@v1 | ||
| with: | ||
@@ -30,13 +27,6 @@ submodules: true | ||
| - name: Setup Java ${{ matrix.java-version }} | ||
| uses: actions/setup-java@v3 | ||
| uses: actions/setup-java@v1 | ||
| with: | ||
| java-version: ${{ matrix.java-version }} | ||
| distribution: 'temurin' | ||
| - name: Setup Moxie | ||
| run: | | ||
| wget http://gitblit.github.io/moxie/maven/com/gitblit/moxie/moxie+ant/0.9.4/moxie+ant-0.9.4.tar.gz | ||
| tar -xzf moxie+ant-0.9.4.tar.gz | ||
| moxie-0.9.4/bin/moxie -version | ||
| - name: Report Java version | ||
@@ -47,24 +37,19 @@ run: | | ||
| - name: Build with Moxie | ||
| run: moxie-0.9.4/bin/moxie test | ||
| - name: Build with Ant | ||
| run: ant test | ||
| build_windows: | ||
| name: Windows build and test | ||
| runs-on: windows-latest | ||
| strategy: | ||
| matrix: | ||
| java-version: [8, 11] | ||
| build_j7: | ||
| name: Build and test on Java 7 | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v3 | ||
| uses: actions/checkout@v1 | ||
| with: | ||
| submodules: true | ||
| - name: Setup Java ${{ matrix.java-version }} | ||
| uses: actions/setup-java@v3 | ||
| - name: Setup Java 7 | ||
| uses: actions/setup-java@v1 | ||
| with: | ||
| java-version: ${{ matrix.java-version }} | ||
| distribution: 'temurin' | ||
| java-version: 7 | ||
@@ -76,3 +61,9 @@ - name: Report Java version | ||
| - name: Build with Ant | ||
| run: ant test | ||
| - name: Setup Moxie | ||
| run: | | ||
| wget http://gitblit.github.io/moxie/maven/com/gitblit/moxie/moxie+ant/0.9.4/moxie+ant-0.9.4.tar.gz | ||
| tar -xzf moxie+ant-0.9.4.tar.gz | ||
| moxie-0.9.4/bin/moxie -version | ||
| - name: Build with Moxie | ||
| run: moxie-0.9.4/bin/moxie test |
+1
-0
@@ -6,3 +6,4 @@ dist: trusty | ||
| jdk: | ||
| - openjdk7 | ||
| - openjdk8 | ||
| - oraclejdk11 |
@@ -34,5 +34,2 @@ /* | ||
| import java.io.IOException; | ||
| import java.nio.charset.Charset; | ||
| import java.nio.charset.IllegalCharsetNameException; | ||
| import java.nio.charset.UnsupportedCharsetException; | ||
| import java.util.ArrayList; | ||
@@ -43,3 +40,2 @@ import java.util.Collections; | ||
| import java.util.Set; | ||
| import java.util.StringTokenizer; | ||
@@ -63,4 +59,2 @@ import org.eclipse.jgit.errors.ConfigInvalidException; | ||
| import static java.nio.charset.StandardCharsets.UTF_8; | ||
| public final class BugtraqConfig { | ||
@@ -81,3 +75,2 @@ | ||
| private static final String LOG_LINKTEXT = "loglinktext"; | ||
| private static final String PROJECTS = "projects"; | ||
@@ -105,3 +98,2 @@ // Static ================================================================= | ||
| } | ||
| if (getString(null, URL, config, baseConfig) != null) { | ||
@@ -117,3 +109,3 @@ allNames.add(null); | ||
| final List<BugtraqConfigEntry> entries = new ArrayList<>(); | ||
| final List<BugtraqEntry> entries = new ArrayList<BugtraqEntry>(); | ||
| for (String name : allNames) { | ||
@@ -166,22 +158,4 @@ final String url = getString(name, URL, config, baseConfig); | ||
| final String projectsList = getString(name, PROJECTS, config, baseConfig); | ||
| final List<String> projects; | ||
| if (projectsList != null) { | ||
| projects = new ArrayList<>(); | ||
| final StringTokenizer tokenizer = new StringTokenizer(projectsList, ",", false); | ||
| while (tokenizer.hasMoreTokens()) { | ||
| projects.add(tokenizer.nextToken().trim()); | ||
| } | ||
| if (projects.isEmpty()) { | ||
| throw new ConfigInvalidException("'" + name + ".projects' must specify at least one project or be not present at all."); | ||
| } | ||
| } | ||
| else { | ||
| projects = null; | ||
| } | ||
| final String linkText = getString(name, LOG_LINKTEXT, config, baseConfig); | ||
| entries.add(new BugtraqConfigEntry(url, idRegex, linkRegex, filterRegex, linkText, projects)); | ||
| entries.add(new BugtraqEntry(url, idRegex, linkRegex, filterRegex, linkText)); | ||
| } | ||
@@ -199,7 +173,7 @@ | ||
| @NotNull | ||
| private final List<BugtraqConfigEntry> entries; | ||
| private final List<BugtraqEntry> entries; | ||
| // Setup ================================================================== | ||
| BugtraqConfig(@NotNull List<BugtraqConfigEntry> entries) { | ||
| BugtraqConfig(@NotNull List<BugtraqEntry> entries) { | ||
| this.entries = entries; | ||
@@ -211,3 +185,3 @@ } | ||
| @NotNull | ||
| public List<BugtraqConfigEntry> getEntries() { | ||
| public List<BugtraqEntry> getEntries() { | ||
| return Collections.unmodifiableList(entries); | ||
@@ -237,3 +211,2 @@ } | ||
| } | ||
| RevCommit commit = rw.parseCommit(headId); | ||
@@ -247,3 +220,3 @@ RevTree tree = commit.getTree(); | ||
| ObjectLoader ldr = repository.open(entid, Constants.OBJ_BLOB); | ||
| content = new String(ldr.getCachedBytes(), guessEncoding(commit)); | ||
| content = new String(ldr.getCachedBytes(), commit.getEncoding()); | ||
| break; | ||
@@ -284,11 +257,2 @@ } | ||
| @NotNull | ||
| private static Charset guessEncoding(RevCommit commit) { | ||
| try { | ||
| return commit.getEncoding(); | ||
| } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { | ||
| return UTF_8; | ||
| } | ||
| } | ||
| @Nullable | ||
@@ -305,4 +269,4 @@ private static String getString(@Nullable String subsection, @NotNull String key, @NotNull Config config, @Nullable Config baseConfig) { | ||
| return value; | ||
| } | ||
| return value; | ||
| } | ||
@@ -309,0 +273,0 @@ @Nullable |
@@ -34,3 +34,3 @@ /* | ||
| public final class BugtraqEntry { | ||
| final class BugtraqEntry { | ||
@@ -37,0 +37,0 @@ // Fields ================================================================= |
@@ -60,8 +60,6 @@ /* | ||
| for (BugtraqConfigEntry configEntry : config.getEntries()) { | ||
| for (BugtraqEntry entry : configEntry.getEntries()) { | ||
| final List<BugtraqParserIssueId> ids = entry.getParser().parse(message); | ||
| for (BugtraqParserIssueId id : ids) { | ||
| allIds.add(new IssueId(entry, id)); | ||
| } | ||
| for (BugtraqEntry entry : config.getEntries()) { | ||
| final List<BugtraqParserIssueId> ids = entry.getParser().parse(message); | ||
| for (BugtraqParserIssueId id : ids) { | ||
| allIds.add(new IssueId(entry, id)); | ||
| } | ||
@@ -68,0 +66,0 @@ } |
@@ -302,7 +302,3 @@ /* | ||
| ucm.user = userService.getUserModel(ucm.user.username); | ||
| // Users may have been deleted, but are still present in authority.conf. | ||
| // TODO: Currently this only keeps the app from crashing. It should provide means to show obsolete user entries and delete them. | ||
| if (ucm.user != null) { | ||
| map.put(ucm.user.username, ucm); | ||
| } | ||
| map.put(ucm.user.username, ucm); | ||
| } | ||
@@ -309,0 +305,0 @@ } catch (IOException e) { |
@@ -648,24 +648,2 @@ /* | ||
| public enum TlsClientCertPolicy { | ||
| REQUIRED, TRUE, OPTIONAL, FALSE, DISABLED, NONE; | ||
| public static TlsClientCertPolicy fromString(String value) { | ||
| for (TlsClientCertPolicy t : values()) { | ||
| if (t.name().equalsIgnoreCase(value)) { | ||
| switch(t) { | ||
| case TRUE: | ||
| return REQUIRED; | ||
| case FALSE: | ||
| return OPTIONAL; | ||
| case NONE: | ||
| return DISABLED; | ||
| default: | ||
| return t; | ||
| } | ||
| } | ||
| } | ||
| return TlsClientCertPolicy.OPTIONAL; | ||
| } | ||
| } | ||
| /** | ||
@@ -672,0 +650,0 @@ * The type of merge Gitblit will use when merging a ticket to the integration branch. |
@@ -230,7 +230,4 @@ /* | ||
| public String toString() { | ||
| if (propertiesFile == null) { | ||
| return "[empty]"; | ||
| } | ||
| return propertiesFile.getAbsolutePath(); | ||
| } | ||
| } |
@@ -47,4 +47,3 @@ /* | ||
| import org.eclipse.jetty.server.ServerConnector; | ||
| import org.eclipse.jetty.server.session.SessionHandler; | ||
| import org.eclipse.jetty.servlet.ListenerHolder; | ||
| import org.eclipse.jetty.server.session.HashSessionManager; | ||
| import org.eclipse.jetty.util.security.Constraint; | ||
@@ -62,3 +61,2 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; | ||
| import com.gitblit.Constants.TlsClientCertPolicy; | ||
| import com.gitblit.authority.GitblitAuthority; | ||
@@ -296,14 +294,10 @@ import com.gitblit.authority.NewCertificateConfig; | ||
| serverKeyStore, serverTrustStore, params.storePassword, caRevocationList); | ||
| TlsClientCertPolicy clientCertPolicy = TlsClientCertPolicy.fromString(params.requireClientCertificates); | ||
| if (clientCertPolicy == TlsClientCertPolicy.REQUIRED) { | ||
| if (params.requireClientCertificates) { | ||
| factory.setNeedClientAuth(true); | ||
| } else if (clientCertPolicy == TlsClientCertPolicy.OPTIONAL) { | ||
| factory.setNeedClientAuth(false); | ||
| } else { | ||
| factory.setWantClientAuth(true); | ||
| } else { | ||
| factory.setNeedClientAuth(false); | ||
| factory.setWantClientAuth(false); | ||
| } | ||
| ServerConnector connector = new ServerConnector(server, factory); | ||
| connector.setSoLingerTime(-1); | ||
| connector.setIdleTimeout(settings.getLong(Keys.server.httpIdleTimeout, 30000L)); | ||
@@ -345,2 +339,3 @@ connector.setPort(params.securePort); | ||
| ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); | ||
| connector.setSoLingerTime(-1); | ||
| connector.setIdleTimeout(settings.getLong(Keys.server.httpIdleTimeout, 30000L)); | ||
@@ -387,9 +382,9 @@ connector.setPort(params.port); | ||
| // Set cookies HttpOnly so they are not accessible to JavaScript engines | ||
| SessionHandler sessionHandler = rootContext.getSessionHandler(); | ||
| sessionHandler.setHttpOnly(true); | ||
| HashSessionManager sessionManager = new HashSessionManager(); | ||
| sessionManager.setHttpOnly(true); | ||
| // Use secure cookies if only serving https | ||
| sessionHandler.setSecureRequestOnly( (params.port <= 0 && params.securePort > 0) || | ||
| (params.port > 0 && params.securePort > 0 && settings.getBoolean(Keys.server.redirectToHttpsPort, true)) ); | ||
| sessionManager.setSecureRequestOnly( (params.port <= 0 && params.securePort > 0) || | ||
| (params.port > 0 && params.securePort > 0 && settings.getBoolean(Keys.server.redirectToHttpsPort, true)) ); | ||
| rootContext.getSessionHandler().setSessionManager(sessionManager); | ||
@@ -460,9 +455,8 @@ // Ensure there is a defined User Service | ||
| // Configure this context to use the Security Handler defined before | ||
| rootContext.setSecurityHandler(sh); | ||
| rootContext.setHandler(sh); | ||
| } | ||
| // Setup the Gitblit context | ||
| ListenerHolder gitblitHolder = new ListenerHolder(GitblitContext.class); | ||
| gitblitHolder.setListener(newGitblit(settings, baseFolder)); | ||
| rootContext.getServletHandler().addListener(gitblitHolder); | ||
| GitblitContext gitblit = newGitblit(settings, baseFolder); | ||
| rootContext.addEventListener(gitblit); | ||
@@ -615,3 +609,3 @@ try { | ||
| @Option(name = "--requireClientCertificates", usage = "Require client X509 certificates for https connections.") | ||
| public String requireClientCertificates = FILESETTINGS.getString(Keys.server.requireClientCertificates, "optional"); | ||
| public Boolean requireClientCertificates = FILESETTINGS.getBoolean(Keys.server.requireClientCertificates, false); | ||
@@ -618,0 +612,0 @@ /* |
@@ -113,3 +113,3 @@ /* | ||
| public List<RegistrantAccessPermission> getRepositoryPermissions() { | ||
| List<RegistrantAccessPermission> list = new ArrayList<>(); | ||
| List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>(); | ||
| if (canAdmin()) { | ||
@@ -139,2 +139,3 @@ // user has REWIND access to all repositories | ||
| // include immutable team permissions, being careful to preserve order | ||
| Set<RegistrantAccessPermission> set = new LinkedHashSet<RegistrantAccessPermission>(list); | ||
| for (TeamModel team : teams) { | ||
@@ -147,13 +148,6 @@ for (RegistrantAccessPermission teamPermission : team.getRepositoryPermissions()) { | ||
| teamPermission.mutable = false; | ||
| int i = list.indexOf(teamPermission); | ||
| if (i < 0) list.add(teamPermission); | ||
| else { | ||
| RegistrantAccessPermission lp = list.get(i); | ||
| if (teamPermission.permission.exceeds(lp.permission)) { | ||
| list.set(i, teamPermission); | ||
| } | ||
| } | ||
| set.add(teamPermission); | ||
| } | ||
| } | ||
| return list; | ||
| return new ArrayList<RegistrantAccessPermission>(set); | ||
| } | ||
@@ -160,0 +154,0 @@ |
@@ -21,9 +21,5 @@ /* | ||
| import java.io.File; | ||
| import java.io.FileInputStream; | ||
| import java.io.InputStreamReader; | ||
| import java.security.KeyFactory; | ||
| import java.security.KeyPair; | ||
| import java.security.PrivateKey; | ||
| import java.security.PublicKey; | ||
| import java.util.Arrays; | ||
@@ -33,21 +29,15 @@ import java.util.Iterator; | ||
| import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; | ||
| import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider; | ||
| import org.apache.sshd.common.util.security.SecurityUtils; | ||
| import org.apache.sshd.common.util.SecurityUtils; | ||
| import org.bouncycastle.openssl.PEMDecryptorProvider; | ||
| import org.bouncycastle.openssl.PEMEncryptedKeyPair; | ||
| import org.bouncycastle.openssl.PEMKeyPair; | ||
| import org.bouncycastle.openssl.PEMParser; | ||
| import org.bouncycastle.openssl.PasswordFinder; | ||
| import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; | ||
| import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | ||
| import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; | ||
| import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; | ||
| import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; | ||
| import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; | ||
| import org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec; | ||
| import org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec; | ||
| import org.bouncycastle.util.io.pem.PemObject; | ||
| import org.bouncycastle.util.io.pem.PemReader; | ||
| import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; | ||
| /** | ||
| * This host key provider loads private keys from the specified files. | ||
| * <p> | ||
| * | ||
| * Note that this class has a direct dependency on BouncyCastle and won't work | ||
@@ -58,53 +48,52 @@ * unless it has been correctly registered as a security provider. | ||
| */ | ||
| public class FileKeyPairProvider extends AbstractKeyPairProvider | ||
| { | ||
| public class FileKeyPairProvider extends AbstractKeyPairProvider { | ||
| private String[] files; | ||
| private PasswordFinder passwordFinder; | ||
| public FileKeyPairProvider() | ||
| { | ||
| public FileKeyPairProvider() { | ||
| } | ||
| public FileKeyPairProvider(String[] files) | ||
| { | ||
| public FileKeyPairProvider(String[] files) { | ||
| this.files = files; | ||
| } | ||
| public String[] getFiles() | ||
| { | ||
| public FileKeyPairProvider(String[] files, PasswordFinder passwordFinder) { | ||
| this.files = files; | ||
| this.passwordFinder = passwordFinder; | ||
| } | ||
| public String[] getFiles() { | ||
| return files; | ||
| } | ||
| public void setFiles(String[] files) | ||
| { | ||
| public void setFiles(String[] files) { | ||
| this.files = files; | ||
| } | ||
| public PasswordFinder getPasswordFinder() { | ||
| return passwordFinder; | ||
| } | ||
| @Override | ||
| public Iterable<KeyPair> loadKeys() | ||
| { | ||
| public void setPasswordFinder(PasswordFinder passwordFinder) { | ||
| this.passwordFinder = passwordFinder; | ||
| } | ||
| public Iterable<KeyPair> loadKeys() { | ||
| if (!SecurityUtils.isBouncyCastleRegistered()) { | ||
| throw new IllegalStateException("BouncyCastle must be registered as a JCE provider"); | ||
| } | ||
| return new Iterable<KeyPair>() | ||
| { | ||
| return new Iterable<KeyPair>() { | ||
| @Override | ||
| public Iterator<KeyPair> iterator() | ||
| { | ||
| return new Iterator<KeyPair>() | ||
| { | ||
| public Iterator<KeyPair> iterator() { | ||
| return new Iterator<KeyPair>() { | ||
| private final Iterator<String> iterator = Arrays.asList(files).iterator(); | ||
| private KeyPair nextKeyPair; | ||
| private boolean nextKeyPairSet = false; | ||
| @Override | ||
| public boolean hasNext() | ||
| { | ||
| public boolean hasNext() { | ||
| return nextKeyPairSet || setNextObject(); | ||
| } | ||
| @Override | ||
| public KeyPair next() | ||
| { | ||
| public KeyPair next() { | ||
| if (!nextKeyPairSet) { | ||
@@ -118,18 +107,9 @@ if (!setNextObject()) { | ||
| } | ||
| @Override | ||
| public void remove() | ||
| { | ||
| public void remove() { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
| private boolean setNextObject() | ||
| { | ||
| private boolean setNextObject() { | ||
| while (iterator.hasNext()) { | ||
| String file = iterator.next(); | ||
| File f = new File(file); | ||
| if (!f.isFile()) { | ||
| log.debug("File does not exist, skipping {}", file); | ||
| continue; | ||
| } | ||
| nextKeyPair = doLoadKey(file); | ||
@@ -149,49 +129,6 @@ if (nextKeyPair != null) { | ||
| private KeyPair doLoadKey(String file) | ||
| { | ||
| protected KeyPair doLoadKey(String file) { | ||
| try { | ||
| try (PemReader r = new PemReader(new InputStreamReader(new FileInputStream(file)))) { | ||
| PemObject pemObject = r.readPemObject(); | ||
| if ("OPENSSH PRIVATE KEY".equals(pemObject.getType())) { | ||
| // This reads a properly OpenSSH formatted ed25519 private key file. | ||
| // It is currently unused because the SSHD library in play doesn't work with proper keys. | ||
| // This is kept in the hope that in the future the library offers proper support. | ||
| try { | ||
| byte[] privateKeyContent = pemObject.getContent(); | ||
| AsymmetricKeyParameter privateKeyParameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privateKeyContent); | ||
| if (privateKeyParameters instanceof Ed25519PrivateKeyParameters) { | ||
| OpenSSHPrivateKeySpec privkeySpec = new OpenSSHPrivateKeySpec(privateKeyContent); | ||
| Ed25519PublicKeyParameters publicKeyParameters = ((Ed25519PrivateKeyParameters)privateKeyParameters).generatePublicKey(); | ||
| OpenSSHPublicKeySpec pubKeySpec = new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(publicKeyParameters)); | ||
| KeyFactory kf = KeyFactory.getInstance("Ed25519", "BC"); | ||
| PrivateKey privateKey = kf.generatePrivate(privkeySpec); | ||
| PublicKey publicKey = kf.generatePublic(pubKeySpec); | ||
| return new KeyPair(publicKey, privateKey); | ||
| } | ||
| else { | ||
| log.warn("OpenSSH format is only supported for Ed25519 key type. Unable to read key " + file); | ||
| } | ||
| } | ||
| catch (Exception e) { | ||
| log.warn("Unable to read key " + file, e); | ||
| } | ||
| return null; | ||
| } | ||
| if ("EDDSA PRIVATE KEY".equals(pemObject.getType())) { | ||
| // This reads the ed25519 key from a file format that we created in SshDaemon. | ||
| // The type EDDSA PRIVATE KEY was given by us and nothing official. | ||
| byte[] privateKeyContent = pemObject.getContent(); | ||
| PrivateKeyEntryDecoder<? extends PublicKey,? extends PrivateKey> decoder = SecurityUtils.getOpenSSHEDDSAPrivateKeyEntryDecoder(); | ||
| PrivateKey privateKey = decoder.decodePrivateKey(null, privateKeyContent, 0, privateKeyContent.length); | ||
| PublicKey publicKey = SecurityUtils. recoverEDDSAPublicKey(privateKey); | ||
| return new KeyPair(publicKey, privateKey); | ||
| } | ||
| } | ||
| try (PEMParser r = new PEMParser(new InputStreamReader(new FileInputStream(file)))) { | ||
| PEMParser r = new PEMParser(new InputStreamReader(new FileInputStream(file))); | ||
| try { | ||
| Object o = r.readObject(); | ||
@@ -201,16 +138,18 @@ | ||
| pemConverter.setProvider("BC"); | ||
| if (passwordFinder != null && o instanceof PEMEncryptedKeyPair) { | ||
| JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder(); | ||
| PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(passwordFinder.getPassword()); | ||
| o = pemConverter.getKeyPair(((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor)); | ||
| } | ||
| if (o instanceof PEMKeyPair) { | ||
| o = pemConverter.getKeyPair((PEMKeyPair)o); | ||
| return (KeyPair)o; | ||
| return (KeyPair) o; | ||
| } else if (o instanceof KeyPair) { | ||
| return (KeyPair) o; | ||
| } | ||
| else if (o instanceof KeyPair) { | ||
| return (KeyPair)o; | ||
| } | ||
| else { | ||
| log.warn("Cannot read unsupported PEM object of type: " + o.getClass().getCanonicalName()); | ||
| } | ||
| } finally { | ||
| r.close(); | ||
| } | ||
| } | ||
| catch (Exception e) { | ||
| } catch (Exception e) { | ||
| log.warn("Unable to read key " + file, e); | ||
@@ -217,0 +156,0 @@ } |
@@ -24,21 +24,21 @@ /* | ||
| @Override | ||
| public boolean canConnect(Type type, SshdSocketAddress address, Session session) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canConnect(Type type, SshdSocketAddress address, Session session) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canForwardAgent(Session session, String requestType) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canForwardAgent(Session session) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canForwardX11(Session session, String requestType) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canForwardX11(Session session) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canListen(SshdSocketAddress address, Session session) { | ||
| return false; | ||
| } | ||
| @Override | ||
| public boolean canListen(SshdSocketAddress address, Session session) { | ||
| return false; | ||
| } | ||
| } |
@@ -18,3 +18,2 @@ /* | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.File; | ||
@@ -27,3 +26,2 @@ import java.io.FileOutputStream; | ||
| import java.security.KeyPairGenerator; | ||
| import java.security.PrivateKey; | ||
| import java.text.MessageFormat; | ||
@@ -33,19 +31,9 @@ import java.util.List; | ||
| import net.i2p.crypto.eddsa.EdDSAPrivateKey; | ||
| import org.apache.sshd.common.config.keys.KeyEntryResolver; | ||
| import org.apache.sshd.common.io.IoServiceFactoryFactory; | ||
| import org.apache.sshd.common.io.mina.MinaServiceFactoryFactory; | ||
| import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory; | ||
| import org.apache.sshd.common.util.security.SecurityUtils; | ||
| import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleSecurityProviderRegistrar; | ||
| import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderRegistrar; | ||
| import org.apache.sshd.common.util.security.eddsa.OpenSSHEd25519PrivateKeyEntryDecoder; | ||
| import org.apache.sshd.common.util.SecurityUtils; | ||
| import org.apache.sshd.server.SshServer; | ||
| import org.apache.sshd.server.auth.pubkey.CachingPublicKeyAuthenticator; | ||
| import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | ||
| import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; | ||
| import org.bouncycastle.crypto.util.PrivateKeyFactory; | ||
| import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; | ||
| import org.bouncycastle.util.io.pem.PemObject; | ||
| import org.bouncycastle.util.io.pem.PemWriter; | ||
| import org.bouncycastle.openssl.PEMWriter; | ||
| import org.eclipse.jgit.internal.JGitText; | ||
@@ -72,3 +60,3 @@ import org.slf4j.Logger; | ||
| private static final Logger log = LoggerFactory.getLogger(SshDaemon.class); | ||
| private final Logger log = LoggerFactory.getLogger(SshDaemon.class); | ||
@@ -111,11 +99,6 @@ private static final String AUTH_PUBLICKEY = "publickey"; | ||
| // Ensure that Bouncy Castle is our JCE provider | ||
| SecurityUtils.registerSecurityProvider(new BouncyCastleSecurityProviderRegistrar()); | ||
| SecurityUtils.setRegisterBouncyCastle(true); | ||
| if (SecurityUtils.isBouncyCastleRegistered()) { | ||
| log.info("BouncyCastle is registered as a JCE provider"); | ||
| log.debug("BouncyCastle is registered as a JCE provider"); | ||
| } | ||
| // Add support for ED25519_SHA512 | ||
| SecurityUtils.registerSecurityProvider(new EdDSASecurityProviderRegistrar()); | ||
| if (SecurityUtils.isProviderRegistered("EdDSA")) { | ||
| log.info("EdDSA is registered as a JCE provider"); | ||
| } | ||
@@ -125,10 +108,6 @@ // Generate host RSA and DSA keypairs and create the host keypair provider | ||
| File dsaKeyStore = new File(gitblit.getBaseFolder(), "ssh-dsa-hostkey.pem"); | ||
| File ecdsaKeyStore = new File(gitblit.getBaseFolder(), "ssh-ecdsa-hostkey.pem"); | ||
| File eddsaKeyStore = new File(gitblit.getBaseFolder(), "ssh-eddsa-hostkey.pem"); | ||
| File ed25519KeyStore = new File(gitblit.getBaseFolder(), "ssh-ed25519-hostkey.pem"); | ||
| generateKeyPair(rsaKeyStore, "RSA", 2048); | ||
| generateKeyPair(ecdsaKeyStore, "ECDSA", 256); | ||
| generateKeyPair(eddsaKeyStore, "EdDSA", 0); | ||
| generateKeyPair(dsaKeyStore, "DSA", 0); | ||
| FileKeyPairProvider hostKeyPairProvider = new FileKeyPairProvider(); | ||
| hostKeyPairProvider.setFiles(new String [] { ecdsaKeyStore.getPath(), eddsaKeyStore.getPath(), ed25519KeyStore.getPath(), rsaKeyStore.getPath(), dsaKeyStore.getPath() }); | ||
| hostKeyPairProvider.setFiles(new String [] { rsaKeyStore.getPath(), dsaKeyStore.getPath(), dsaKeyStore.getPath() }); | ||
@@ -190,3 +169,3 @@ | ||
| sshd.setFileSystemFactory(new DisabledFilesystemFactory()); | ||
| sshd.setForwardingFilter(new NonForwardingFilter()); | ||
| sshd.setTcpipForwardingFilter(new NonForwardingFilter()); | ||
| sshd.setCommandFactory(new SshCommandFactory(gitblit, workQueue)); | ||
@@ -268,3 +247,3 @@ sshd.setShellFactory(new WelcomeShell(gitblit)); | ||
| static void generateKeyPair(File file, String algorithm, int keySize) { | ||
| private void generateKeyPair(File file, String algorithm, int keySize) { | ||
| if (file.exists()) { | ||
@@ -292,34 +271,4 @@ return; | ||
| FileOutputStream os = new FileOutputStream(file); | ||
| PemWriter w = new PemWriter(new OutputStreamWriter(os)); | ||
| if (algorithm.equals("ED25519")) { | ||
| // This generates a proper OpenSSH formatted ed25519 private key file. | ||
| // It is currently unused because the SSHD library in play doesn't work with proper keys. | ||
| // This is kept in the hope that in the future the library offers proper support. | ||
| AsymmetricKeyParameter keyParam = PrivateKeyFactory.createKey(kp.getPrivate().getEncoded()); | ||
| byte[] encKey = OpenSSHPrivateKeyUtil.encodePrivateKey(keyParam); | ||
| w.writeObject(new PemObject("OPENSSH PRIVATE KEY", encKey)); | ||
| } | ||
| else if (algorithm.equals("EdDSA")) { | ||
| // This saves the ed25519 key in a file format that the current SSHD library can work with. | ||
| // We call it EDDSA PRIVATE KEY, but that string is given by us and nothing official. | ||
| PrivateKey privateKey = kp.getPrivate(); | ||
| if (privateKey instanceof EdDSAPrivateKey) { | ||
| OpenSSHEd25519PrivateKeyEntryDecoder encoder = (OpenSSHEd25519PrivateKeyEntryDecoder)SecurityUtils.getOpenSSHEDDSAPrivateKeyEntryDecoder(); | ||
| EdDSAPrivateKey dsaPrivateKey = (EdDSAPrivateKey)privateKey; | ||
| // Jumping through some hoops here, because the decoder expects the key type as a string at the | ||
| // start, but the encoder doesn't put it in. So we have to put it in ourselves. | ||
| ByteArrayOutputStream encos = new ByteArrayOutputStream(); | ||
| String type = encoder.encodePrivateKey(encos, dsaPrivateKey); | ||
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||
| KeyEntryResolver.encodeString(bos, type); | ||
| encos.writeTo(bos); | ||
| w.writeObject(new PemObject("EDDSA PRIVATE KEY", bos.toByteArray())); | ||
| } | ||
| else { | ||
| log.warn("Unable to encode EdDSA key, got key type " + privateKey.getClass().getCanonicalName()); | ||
| } | ||
| } | ||
| else { | ||
| w.writeObject(new JcaMiscPEMGenerator(kp)); | ||
| } | ||
| PEMWriter w = new PEMWriter(new OutputStreamWriter(os)); | ||
| w.writeObject(kp); | ||
| w.flush(); | ||
@@ -329,4 +278,5 @@ w.close(); | ||
| log.warn(MessageFormat.format("Unable to generate {0} keypair", algorithm), e); | ||
| return; | ||
| } | ||
| } | ||
| } |
@@ -84,11 +84,2 @@ /* | ||
| public void detachPublicKey() | ||
| { | ||
| if (rawData == null) { | ||
| // Make sure the raw data is available | ||
| getRawData(); | ||
| } | ||
| publicKey = null; | ||
| } | ||
| public String getAlgorithm() { | ||
@@ -95,0 +86,0 @@ return getPublicKey().getAlgorithm(); |
@@ -60,7 +60,2 @@ /* | ||
| @Override | ||
| public Command get() { | ||
| return create(); | ||
| } | ||
| private static class SendMessage implements Command, SessionAware { | ||
@@ -67,0 +62,0 @@ |
@@ -158,6 +158,6 @@ /* | ||
| } | ||
| } catch (IOException e) { | ||
| logger.error(MessageFormat.format("Bugtraq config for {0} is invalid!", repositoryName), e); | ||
| } catch (ConfigInvalidException e) { | ||
| logger.warn("Bugtraq config for {} is invalid!", repositoryName, e); | ||
| } catch (Exception e) { | ||
| logger.warn("Failed to parse message through Bugtraq.", e); | ||
| logger.error(MessageFormat.format("Bugtraq config for {0} is invalid!", repositoryName), e); | ||
| } | ||
@@ -164,0 +164,0 @@ |
@@ -108,4 +108,2 @@ /* | ||
| int i = 0; | ||
| int l = 0; | ||
| while (i < inStr.length()) { | ||
@@ -123,14 +121,8 @@ if (inStr.charAt(i) == '&') { | ||
| } else if (changeSpace && inStr.charAt(i) == '\t') { | ||
| for (int j = 0; j < tabLength - l; j++) { | ||
| for (int j = 0; j < tabLength; j++) { | ||
| retStr.append(" "); | ||
| } | ||
| l = -1; | ||
| } else { | ||
| retStr.append(inStr.charAt(i)); | ||
| } | ||
| l = (l + 1) % tabLength; | ||
| if (inStr.charAt(i) == '\n') { | ||
| l = 0; | ||
| } | ||
| i++; | ||
@@ -137,0 +129,0 @@ } |
@@ -75,3 +75,3 @@ /* | ||
| import org.bouncycastle.asn1.x509.KeyUsage; | ||
| import org.bouncycastle.asn1.x509.Extension; | ||
| import org.bouncycastle.asn1.x509.X509Extension; | ||
| import org.bouncycastle.cert.X509CRLHolder; | ||
@@ -86,2 +86,3 @@ import org.bouncycastle.cert.X509v2CRLBuilder; | ||
| import org.bouncycastle.openssl.PEMEncryptor; | ||
| import org.bouncycastle.openssl.PEMWriter; | ||
| import org.bouncycastle.openssl.jcajce.JcaPEMWriter; | ||
@@ -449,5 +450,5 @@ import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder; | ||
| // PEM encoded X509 | ||
| JcaPEMWriter pemWriter = null; | ||
| PEMWriter pemWriter = null; | ||
| try { | ||
| pemWriter = new JcaPEMWriter(new FileWriter(tmpFile)); | ||
| pemWriter = new PEMWriter(new FileWriter(tmpFile)); | ||
| pemWriter.writeObject(cert); | ||
@@ -565,5 +566,5 @@ pemWriter.flush(); | ||
| JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); | ||
| certBuilder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(pair.getPublic())); | ||
| certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false)); | ||
| certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey())); | ||
| certBuilder.addExtension(X509Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(pair.getPublic())); | ||
| certBuilder.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false)); | ||
| certBuilder.addExtension(X509Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey())); | ||
@@ -577,3 +578,3 @@ // support alternateSubjectNames for SSL certificates | ||
| GeneralNames subjectAltName = new GeneralNames(altNames.toArray(new GeneralName [altNames.size()])); | ||
| certBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAltName); | ||
| certBuilder.addExtension(X509Extension.subjectAlternativeName, false, subjectAltName); | ||
| } | ||
@@ -636,6 +637,6 @@ | ||
| JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); | ||
| caBuilder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(caPair.getPublic())); | ||
| caBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caPair.getPublic())); | ||
| caBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true)); | ||
| caBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); | ||
| caBuilder.addExtension(X509Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(caPair.getPublic())); | ||
| caBuilder.addExtension(X509Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caPair.getPublic())); | ||
| caBuilder.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(true)); | ||
| caBuilder.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); | ||
@@ -870,10 +871,10 @@ JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BC); | ||
| JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); | ||
| certBuilder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(pair.getPublic())); | ||
| certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false)); | ||
| certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey())); | ||
| certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyEncipherment | KeyUsage.digitalSignature)); | ||
| certBuilder.addExtension(X509Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(pair.getPublic())); | ||
| certBuilder.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false)); | ||
| certBuilder.addExtension(X509Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey())); | ||
| certBuilder.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.keyEncipherment | KeyUsage.digitalSignature)); | ||
| if (!StringUtils.isEmpty(clientMetadata.emailAddress)) { | ||
| GeneralNames subjectAltName = new GeneralNames( | ||
| new GeneralName(GeneralName.rfc822Name, clientMetadata.emailAddress)); | ||
| certBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAltName); | ||
| certBuilder.addExtension(X509Extension.subjectAlternativeName, false, subjectAltName); | ||
| } | ||
@@ -880,0 +881,0 @@ |
@@ -738,4 +738,2 @@ gb.repository = Repository | ||
| gb.addSshKey = SSH Key hinzuf\u00fcgen | ||
| gb.addSshKeyErrorEmpty = SSH Public Key leer. Bitte geben Sie einen g\u00fcltigen SSH Public Key an | ||
| gb.addSshKeyErrorFormat = SSH Public Key Format ung�ltig. Bitte geben Sie einen g\u00fcltigen SSH Public Key an | ||
| gb.key = Key | ||
@@ -742,0 +740,0 @@ gb.sshKeyComment = Kommentar |
@@ -741,4 +741,2 @@ gb.repository = repository | ||
| gb.addSshKey = Add SSH Key | ||
| gb.addSshKeyErrorEmpty = SSH public key empty. Please provide a valid SSH public key | ||
| gb.addSshKeyErrorFormat = Not a valid SSH public key format. Please provide a valid SSH public key | ||
| gb.key = Key | ||
@@ -745,0 +743,0 @@ gb.sshKeyComment = Comment |
@@ -174,7 +174,2 @@ /* | ||
| // load clipboard library to copy repository URL | ||
| addBottomScript("../../clipboard/clipboard.min.js"); | ||
| // instantiate clipboard | ||
| addBottomScript("../../clipboard/gitblit-ctcbtn.js"); | ||
| // set stateless page preference | ||
@@ -181,0 +176,0 @@ setStatelessHint(true); |
@@ -64,5 +64,5 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
| </wicket:fragment> | ||
| </wicket:extend> | ||
| </wicket:extend> | ||
| </body> | ||
| </html> |
@@ -589,10 +589,16 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
| </wicket:fragment> | ||
| <!-- JavaScript automatic copy to clipboard --> | ||
| <wicket:fragment wicket:id="clippyPanel"> | ||
| <span class="tooltipped tooltipped-n"> | ||
| <img class="ctcbtn" wicket:id="copyIcon" wicket:message="title:gb.copyToClipboard" /> | ||
| </span> | ||
| </wicket:fragment> | ||
| <!-- flash-based button-press copy & paste --> | ||
| <wicket:fragment wicket:id="clippyPanel"> | ||
| <object wicket:message="title:gb.copyToClipboard" style="vertical-align:middle;" | ||
| wicket:id="clippy" | ||
| width="14" | ||
| height="14" | ||
| bgcolor="#ffffff" | ||
| quality="high" | ||
| wmode="transparent" | ||
| scale="noscale" | ||
| allowScriptAccess="sameDomain"></object> | ||
| </wicket:fragment> | ||
@@ -599,0 +605,0 @@ </wicket:extend> |
@@ -15,10 +15,8 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
| <div class="btn-toolbar" style="margin: 0px;"> | ||
| <div class="btn-group repositoryUrlContainer tooltipped tooltipped-w"> | ||
| <img style="max-width:inherit; vertical-align: middle;padding: 0px 0px 1px 3px;" wicket:id="accessRestrictionIcon"></img> | ||
| <div class="btn-group repositoryUrlContainer"> | ||
| <img style="vertical-align: middle;padding: 0px 0px 1px 3px;" wicket:id="accessRestrictionIcon"></img> | ||
| <span wicket:id="menu"></span> | ||
| <div class="repositoryUrl"> | ||
| <span wicket:id="primaryUrl">[repository primary url]</span> | ||
| <span class="tooltipped tooltipped-n"> | ||
| <span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span> | ||
| </span> | ||
| <span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span> | ||
| </div> | ||
@@ -39,3 +37,3 @@ <span class="hidden-phone hidden-tablet repositoryUrlRightCap" wicket:id="primaryUrlPermission">[repository primary url permission]</span> | ||
| <div class="btn-toolbar" style="margin: 4px 0px 0px 0px;"> | ||
| <div class="btn-group tooltipped tooltipped-w" wicket:id="appMenus"> | ||
| <div class="btn-group" wicket:id="appMenus"> | ||
| <span wicket:id="appMenu"></span> | ||
@@ -92,5 +90,13 @@ </div> | ||
| <!-- JavaScript automatic copy to clipboard --> | ||
| <!-- flash-based button-press copy & paste --> | ||
| <wicket:fragment wicket:id="clippyPanel"> | ||
| <img class="ctcbtn" style="max-width:inherit;" wicket:id="copyIcon" wicket:message="title:gb.copyToClipboard" /> | ||
| <object wicket:message="title:gb.copyToClipboard" style="vertical-align:middle;" | ||
| wicket:id="clippy" | ||
| width="14" | ||
| height="14" | ||
| bgcolor="#ffffff" | ||
| quality="high" | ||
| wmode="transparent" | ||
| scale="noscale" | ||
| allowScriptAccess="sameDomain"></object> | ||
| </wicket:fragment> | ||
@@ -97,0 +103,0 @@ |
@@ -28,3 +28,2 @@ /* | ||
| import org.apache.wicket.RequestCycle; | ||
| import org.apache.wicket.behavior.SimpleAttributeModifier; | ||
| import org.apache.wicket.markup.html.basic.Label; | ||
@@ -145,3 +144,4 @@ import org.apache.wicket.markup.html.image.ContextImage; | ||
| Fragment fragment = new Fragment("repoUrl", "actionFragment", this); | ||
| Component content = new Label("content", repoUrl.url).setOutputMarkupId(true); | ||
| Component content = new Label("content", repoUrl.url).setRenderBodyOnly(true); | ||
| WicketUtils.setCssClass(content, "commandMenuItem"); | ||
| fragment.add(content); | ||
@@ -155,3 +155,3 @@ item.add(fragment); | ||
| fragment.add(permissionLabel); | ||
| fragment.add(createCopyFragment(repoUrl.url, content.getMarkupId())); | ||
| fragment.add(createCopyFragment(repoUrl.url)); | ||
| } | ||
@@ -205,5 +205,3 @@ }; | ||
| Label primaryUrlLabel = new Label("primaryUrl", primaryUrl.url); | ||
| primaryUrlLabel.setOutputMarkupId(true); | ||
| urlPanel.add(primaryUrlLabel); | ||
| urlPanel.add(new Label("primaryUrl", primaryUrl.url).setRenderBodyOnly(true)); | ||
@@ -214,3 +212,3 @@ Label permissionLabel = new Label("primaryUrlPermission", primaryUrl.hasPermission() ? primaryUrl.permission.toString() : externalPermission); | ||
| urlPanel.add(permissionLabel); | ||
| urlPanel.add(createCopyFragment(primaryUrl.url, primaryUrlLabel.getMarkupId())); | ||
| urlPanel.add(createCopyFragment(primaryUrl.url)); | ||
@@ -327,3 +325,2 @@ return urlPanel; | ||
| Label content = new Label("content", command); | ||
| content.setOutputMarkupId(true); | ||
| WicketUtils.setCssClass(content, "commandMenuItem"); | ||
@@ -334,3 +331,3 @@ fragment.add(content); | ||
| // copy function for command | ||
| fragment.add(createCopyFragment(command, content.getMarkupId())); | ||
| fragment.add(createCopyFragment(command)); | ||
| } | ||
@@ -359,13 +356,12 @@ }}; | ||
| protected Fragment createCopyFragment(String text, String target) { | ||
| protected Fragment createCopyFragment(String text) { | ||
| if (app().settings().getBoolean(Keys.web.allowFlashCopyToClipboard, true)) { | ||
| // javascript: browser JS API based copy to clipboard | ||
| // clippy: flash-based copy & paste | ||
| Fragment copyFragment = new Fragment("copyFunction", "clippyPanel", this); | ||
| ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png"); | ||
| // Add the ID of the target element that holds the text to copy to clipboard | ||
| img.add(new SimpleAttributeModifier("data-clipboard-target", "#"+target)); | ||
| copyFragment.add(img); | ||
| String baseUrl = WicketUtils.getGitblitURL(getRequest()); | ||
| ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf"); | ||
| clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(text)); | ||
| copyFragment.add(clippy); | ||
| return copyFragment; | ||
| } | ||
| else { | ||
| } else { | ||
| // javascript: manual copy & paste with modal browser prompt dialog | ||
@@ -372,0 +368,0 @@ Fragment copyFragment = new Fragment("copyFunction", "jsPanel", this); |
@@ -40,4 +40,3 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
| <div wicket:id="addKeyComment"></div> | ||
| <div wicket:id="addKeyFeedback"></div> | ||
| <div class="form-actions"><input class="btn btn-appmenu" type="submit" value="Add" wicket:message="value:gb.add" wicket:id="addKeyButton" /></div> | ||
@@ -44,0 +43,0 @@ </form> |
@@ -22,4 +22,2 @@ /* | ||
| import com.gitblit.wicket.WicketUtils; | ||
| import org.apache.wicket.Component; | ||
| import org.apache.wicket.ajax.AjaxRequestTarget; | ||
@@ -69,27 +67,4 @@ import org.apache.wicket.ajax.markup.html.AjaxLink; | ||
| final IModel<String> keyFeedback = Model.of(""); | ||
| final List<SshKey> keys = new ArrayList<SshKey>(app().keys().getKeys(user.username)); | ||
| // Create list data provider that gets rid of the (not serializable EdDSA) PublicKey. | ||
| final ListDataProvider<SshKey> dp = new ListDataProvider<SshKey>(keys) { | ||
| @Override | ||
| public IModel<SshKey> model(final SshKey key) { | ||
| return new IModel<SshKey>() { | ||
| @Override | ||
| public SshKey getObject() { | ||
| return key; | ||
| } | ||
| @Override | ||
| public void setObject(SshKey object) { | ||
| // Cannot get set | ||
| } | ||
| @Override | ||
| public void detach() { | ||
| key.detachPublicKey(); | ||
| } | ||
| }; | ||
| } | ||
| }; | ||
| final ListDataProvider<SshKey> dp = new ListDataProvider<SshKey>(keys); | ||
| final DataView<SshKey> keysView = new DataView<SshKey>("keys", dp) { | ||
@@ -120,3 +95,2 @@ private static final long serialVersionUID = 1L; | ||
| } | ||
| keyFeedback.setObject(""); | ||
| } | ||
@@ -155,6 +129,2 @@ }; | ||
| Component addKeyFeedback = new Label("addKeyFeedback", keyFeedback).setOutputMarkupId(true); | ||
| WicketUtils.setCssStyle(addKeyFeedback, "color: red; font-weight: bold;"); | ||
| addKeyForm.add(addKeyFeedback); | ||
| addKeyForm.add(new AjaxButton("addKeyButton") { | ||
@@ -171,4 +141,2 @@ | ||
| // do not submit empty key | ||
| keyFeedback.setObject(getString("gb.addSshKeyErrorEmpty")); | ||
| target.addComponent(addKeyFeedback); | ||
| return; | ||
@@ -182,4 +150,2 @@ } | ||
| // failed to parse the key | ||
| keyFeedback.setObject(getString("gb.addSshKeyErrorFormat")); | ||
| target.addComponent(addKeyFeedback); | ||
| return; | ||
@@ -206,8 +172,5 @@ } | ||
| keyFeedback.setObject(""); | ||
| // update the panel | ||
| target.addComponent(SshKeysPanel.this); | ||
| } | ||
| else keyFeedback.setObject("Key not added."); | ||
| } | ||
@@ -214,0 +177,0 @@ }); |
@@ -91,3 +91,3 @@ #!/usr/bin/env python3 | ||
| if args.patchset is None or args.patchset == 0: | ||
| if args.patchset is None or args.patchset is 0: | ||
| branch = 'ticket/{:d}'.format(args.id) | ||
@@ -108,3 +108,3 @@ illegals = set(branches) & {'ticket'} | ||
| if args.patchset is None or args.patchset == 0: | ||
| if args.patchset is None or args.patchset is 0: | ||
| # checkout the current ticket patchset | ||
@@ -136,3 +136,3 @@ if args.force: | ||
| # pull the patchset from the remote repository | ||
| if args.patchset is None or args.patchset == 0: | ||
| if args.patchset is None or args.patchset is 0: | ||
| print("Pulling ticket {} from the '{}' repository".format(args.id, args.remote)) | ||
@@ -556,7 +556,7 @@ patchset_ref = 'ticket/{:d}'.format(args.id) | ||
| merge = __call(['git', 'merge', '--ff-only', branch, 'FETCH_HEAD'], echo=True, fail=False) | ||
| if len(merge) == 1: | ||
| if len(merge) is 1: | ||
| up_to_date = merge[0].lower().index('up-to-date') > 0 | ||
| if up_to_date: | ||
| return | ||
| elif len(merge) == 0: | ||
| elif len(merge) is 0: | ||
| print('') | ||
@@ -624,3 +624,3 @@ print("Your '{}' branch has diverged from patchset {} on the '{}' repository.".format(branch, patchset, remote)) | ||
| line_str = str(line).strip() | ||
| if len(line_str) == 0: | ||
| if len(line_str) is 0: | ||
| break | ||
@@ -631,3 +631,3 @@ lines.append(line_str) | ||
| p.wait() | ||
| if fail and p.returncode != 0: | ||
| if fail and p.returncode is not 0: | ||
| exit(p.returncode) | ||
@@ -634,0 +634,0 @@ |
@@ -2411,172 +2411,2 @@ body { | ||
| font-variant: normal; | ||
| } | ||
| /* | ||
| Copy-to-clipboard tooltip styling from Github's primer.css | ||
| https://primer.style/css/components/tooltips | ||
| Adjusted to not hover but fade-in/out on clipboard events. | ||
| */ | ||
| .tooltipped { | ||
| position:relative | ||
| } | ||
| .tooltipped:after { | ||
| position: absolute; | ||
| z-index: 1000000; | ||
| padding: 5px 8px; | ||
| font: normal normal 11px/1.5 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; | ||
| color: #fff; | ||
| background: rgba(42, 42, 42, .8); | ||
| text-align: center; | ||
| text-decoration: none; | ||
| text-shadow: none; | ||
| text-transform: none; | ||
| letter-spacing: normal; | ||
| word-wrap: break-word; | ||
| white-space: pre; | ||
| pointer-events: none; | ||
| content: attr(data-tt-text); | ||
| border-radius: 3px; | ||
| -webkit-font-smoothing:subpixel-antialiased; | ||
| opacity: 0; | ||
| transition: 0.5s opacity; | ||
| } | ||
| .tooltipped:before { | ||
| position: absolute; | ||
| z-index: 1000001; | ||
| width: 0; | ||
| height: 0; | ||
| color: rgba(42, 42, 42, .8); | ||
| pointer-events: none; | ||
| content: ""; | ||
| border:5px solid transparent; | ||
| opacity: 0; | ||
| transition: 0.5s opacity; | ||
| } | ||
| .tooltipped-active:before, .tooltipped-active:after { | ||
| opacity: 1; | ||
| text-decoration:none | ||
| } | ||
| .tooltipped-s:after, .tooltipped-se:after, .tooltipped-sw:after { | ||
| top: 100%; | ||
| right: 50%; | ||
| margin-top:5px | ||
| } | ||
| .tooltipped-s:before, .tooltipped-se:before, .tooltipped-sw:before { | ||
| top: auto; | ||
| right: 50%; | ||
| bottom: -5px; | ||
| margin-right: -5px; | ||
| border-bottom-color:rgba(42, 42, 42, .8) | ||
| } | ||
| .tooltipped-se:after { | ||
| right: auto; | ||
| left: 50%; | ||
| margin-left:-15px | ||
| } | ||
| .tooltipped-sw:after { | ||
| margin-right:-15px | ||
| } | ||
| .tooltipped-n:after, .tooltipped-ne:after, .tooltipped-nw:after { | ||
| right: 50%; | ||
| bottom: 100%; | ||
| margin-bottom:5px | ||
| } | ||
| .tooltipped-n:before, .tooltipped-ne:before, .tooltipped-nw:before { | ||
| top: -5px; | ||
| right: 50%; | ||
| bottom: auto; | ||
| margin-right: -5px; | ||
| border-top-color:rgba(42, 42, 42, .8) | ||
| } | ||
| .tooltipped-ne:after { | ||
| right: auto; | ||
| left: 50%; | ||
| margin-left:-15px | ||
| } | ||
| .tooltipped-nw:after { | ||
| margin-right:-15px | ||
| } | ||
| .tooltipped-s:after, .tooltipped-n:after { | ||
| -webkit-transform: translateX(50%); | ||
| -ms-transform: translateX(50%); | ||
| transform:translateX(50%) | ||
| } | ||
| .tooltipped-w:after { | ||
| right: 100%; | ||
| bottom: 50%; | ||
| margin-right: 5px; | ||
| -webkit-transform: translateY(50%); | ||
| -ms-transform: translateY(50%); | ||
| transform:translateY(50%) | ||
| } | ||
| .tooltipped-w:before { | ||
| top: 50%; | ||
| bottom: 50%; | ||
| left: -5px; | ||
| margin-top: -5px; | ||
| border-left-color:rgba(42, 42, 42, .8) | ||
| } | ||
| .tooltipped-e:after { | ||
| bottom: 50%; | ||
| left: 100%; | ||
| margin-left: 5px; | ||
| -webkit-transform: translateY(50%); | ||
| -ms-transform: translateY(50%); | ||
| transform:translateY(50%) | ||
| } | ||
| .tooltipped-e:before { | ||
| top: 50%; | ||
| right: -5px; | ||
| bottom: 50%; | ||
| margin-top: -5px; | ||
| border-right-color:rgba(42, 42, 42, .8) | ||
| } | ||
| .tooltipped-sticky:before, .tooltipped-sticky:after { | ||
| display:inline-block | ||
| } | ||
| .fullscreen-overlay-enabled.dark-theme .tooltipped:after { | ||
| color: #000; | ||
| background:rgba(200, 200, 200, .8) | ||
| } | ||
| .fullscreen-overlay-enabled.dark-theme .tooltipped .tooltipped-s:before, .fullscreen-overlay-enabled.dark-theme .tooltipped .tooltipped-se:before, .fullscreen-overlay-enabled.dark-theme .tooltipped .tooltipped-sw:before { | ||
| border-bottom-color:rgba(200, 200, 200, .8) | ||
| } | ||
| .fullscreen-overlay-enabled.dark-theme .tooltipped.tooltipped-n:before, .fullscreen-overlay-enabled.dark-theme .tooltipped.tooltipped-ne:before, .fullscreen-overlay-enabled.dark-theme .tooltipped.tooltipped-nw:before { | ||
| border-top-color:rgba(200, 200, 200, .8) | ||
| } | ||
| .fullscreen-overlay-enabled.dark-theme .tooltipped.tooltipped-e:before { | ||
| border-right-color:rgba(200, 200, 200, .8) | ||
| } | ||
| .fullscreen-overlay-enabled.dark-theme .tooltipped.tooltipped-w:before { | ||
| border-left-color:rgba(200, 200, 200, .8) | ||
| } | ||
| } |
@@ -35,3 +35,2 @@ /* | ||
| import java.util.List; | ||
| import java.util.StringTokenizer; | ||
@@ -48,3 +47,3 @@ import junit.framework.TestCase; | ||
| public void testSimpleWithExtendedLink() throws BugtraqException { | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/JRA-%BUGID%", null, "JRA-\\d+", "\\d+", null, null)); | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/JRA-%BUGID%", null, "JRA-\\d+", "\\d+", null)); | ||
| doTest(formatter, "JRA-7399: Email subject formatting", l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(": Email subject formatting")); | ||
@@ -56,3 +55,3 @@ doTest(formatter, " JRA-7399, JRA-7398: Email subject formatting", t(" "), l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(", "), l("JRA-7398", "https://jira.atlassian.com/browse/JRA-7398"), t(": Email subject formatting")); | ||
| public void testLinkText() throws BugtraqException { | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/JRA-%BUGID%", null, "JRA-\\d+", "\\d+", "JIRA-%BUGID%", null)); | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/JRA-%BUGID%", null, "JRA-\\d+", "\\d+", "JIRA-%BUGID%")); | ||
| doTest(formatter, " JRA-7399, JRA is text, JRA-7398: Email subject formatting", t(" "), l("JIRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(", JRA is text, "), l("JIRA-7398", "https://jira.atlassian.com/browse/JRA-7398"), t(": Email subject formatting")); | ||
@@ -62,4 +61,4 @@ } | ||
| public void testTwoNonIntersectingConfigurations() throws BugtraqException { | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/%BUGID%", null, null, "JRA-\\d+", null, null), | ||
| createEntry("https://issues.apache.org/jira/browse/%BUGID%", null, null, "VELOCITY-\\d+", null, null)); | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/%BUGID%", null, null, "JRA-\\d+", null), | ||
| createEntry("https://issues.apache.org/jira/browse/%BUGID%", null, null, "VELOCITY-\\d+", null)); | ||
| doTest(formatter, "JRA-7399, VELOCITY-847: fix", l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(", "), l("VELOCITY-847", "https://issues.apache.org/jira/browse/VELOCITY-847"), t(": fix")); | ||
@@ -71,4 +70,4 @@ doTest(formatter, " JRA-7399: fix/VELOCITY-847", t(" "), l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(": fix/"), l("VELOCITY-847", "https://issues.apache.org/jira/browse/VELOCITY-847")); | ||
| public void testTwoIntersectingConfigurations() throws BugtraqException { | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://host1/%BUGID%", null, null, "A[AB]", null, null), | ||
| createEntry("https://host2/%BUGID%", null, null, "BA[A]?", null, null)); | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://host1/%BUGID%", null, null, "A[AB]", null), | ||
| createEntry("https://host2/%BUGID%", null, null, "BA[A]?", null)); | ||
| doTest(formatter, "AA: fix", l("AA", "https://host1/AA"), t(": fix")); | ||
@@ -88,30 +87,10 @@ doTest(formatter, "AB: fix", l("AB", "https://host1/AB"), t(": fix")); | ||
| public void testMultipleProjects() throws BugtraqException { | ||
| final BugtraqFormatter formatter = createFormatter(createEntry("https://jira.atlassian.com/browse/%PROJECT%-%BUGID%", null, "%PROJECT%-\\d+", "\\d+", null, "JRA,JRB,JRC")); | ||
| doTest(formatter, "JRA-7399: Email subject formatting", l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(": Email subject formatting")); | ||
| doTest(formatter, " JRA-7399, JRB-7398: Email subject formatting", t(" "), l("JRA-7399", "https://jira.atlassian.com/browse/JRA-7399"), t(", "), l("JRB-7398", "https://jira.atlassian.com/browse/JRB-7398"), t(": Email subject formatting")); | ||
| doTest(formatter, "Fixed JRC-7399", t("Fixed "), l("JRC-7399", "https://jira.atlassian.com/browse/JRC-7399")); | ||
| } | ||
| // Utils ================================================================== | ||
| private BugtraqFormatter createFormatter(BugtraqConfigEntry ... entries) { | ||
| private BugtraqFormatter createFormatter(BugtraqEntry ... entries) { | ||
| return new BugtraqFormatter(new BugtraqConfig(Arrays.asList(entries))); | ||
| } | ||
| private BugtraqConfigEntry createEntry(String url, @Nullable String filterRegex, @Nullable String linkRegex, @NotNull String idRegex, @Nullable String linkText, @Nullable String projectsList) throws BugtraqException { | ||
| final List<String> projects; | ||
| if (projectsList != null) { | ||
| projects = new ArrayList<>(); | ||
| final StringTokenizer tokenizer = new StringTokenizer(projectsList, ",", false); | ||
| while (tokenizer.hasMoreTokens()) { | ||
| projects.add(tokenizer.nextToken()); | ||
| } | ||
| } | ||
| else { | ||
| projects = null; | ||
| } | ||
| return new BugtraqConfigEntry(url, idRegex, linkRegex, filterRegex, linkText, projects); | ||
| private BugtraqEntry createEntry(String url, @Nullable String filterRegex, @Nullable String linkRegex, @NotNull String idRegex, @Nullable String linkText) throws BugtraqException { | ||
| return new BugtraqEntry(url, idRegex, linkRegex, filterRegex, linkText); | ||
| } | ||
@@ -118,0 +97,0 @@ |
@@ -31,3 +31,3 @@ /* | ||
| import org.apache.sshd.common.util.security.SecurityUtils; | ||
| import org.apache.sshd.common.util.SecurityUtils; | ||
| import org.junit.BeforeClass; | ||
@@ -34,0 +34,0 @@ import org.junit.Test; |
@@ -39,3 +39,3 @@ /* | ||
| import org.apache.sshd.common.config.keys.FilePasswordProvider; | ||
| import org.apache.sshd.common.util.security.SecurityUtils; | ||
| import org.apache.sshd.common.util.SecurityUtils; | ||
| import org.eclipse.jgit.lib.Config; | ||
@@ -42,0 +42,0 @@ import org.eclipse.jgit.storage.file.FileBasedConfig; |
@@ -64,35 +64,7 @@ /* | ||
| public void testEscapeForHtml() throws Exception { | ||
| String input = "\t & < > \""; | ||
| String outputNoChange = "\t & < > ""; | ||
| String outputChange = " & < > ""; | ||
| String input = "& < > \" \t"; | ||
| String outputNoChange = "& < > " \t"; | ||
| String outputChange = "& < > " "; | ||
| assertEquals(outputNoChange, StringUtils.escapeForHtml(input, false)); | ||
| assertEquals(outputChange, StringUtils.escapeForHtml(input, true)); | ||
| input = "a\tb"; | ||
| outputNoChange = "a\tb"; | ||
| outputChange = "a b"; | ||
| assertEquals(outputNoChange, StringUtils.escapeForHtml(input, false)); | ||
| assertEquals(outputChange, StringUtils.escapeForHtml(input, true)); | ||
| input = "\ta b\t"; | ||
| outputNoChange = "\ta b\t"; | ||
| outputChange = " a b "; | ||
| assertEquals(outputNoChange, StringUtils.escapeForHtml(input, false)); | ||
| assertEquals(outputChange, StringUtils.escapeForHtml(input, true)); | ||
| input = "\t <> \t"; | ||
| outputNoChange = "\t <> \t"; | ||
| outputChange = " <> "; | ||
| assertEquals(outputNoChange, StringUtils.escapeForHtml(input, false)); | ||
| assertEquals(outputChange, StringUtils.escapeForHtml(input, true)); | ||
| String tabs = "\t"; | ||
| int tabSpaces; | ||
| int expectedLength; | ||
| for (int i = 0; i < 50; i++) { | ||
| tabSpaces = 4 - i % 4; | ||
| expectedLength = (i + tabSpaces) * 6; // = 6 chars | ||
| assertEquals(expectedLength, StringUtils.escapeForHtml(tabs, true).length()); | ||
| tabs = " " + tabs; | ||
| } | ||
| } | ||
@@ -99,0 +71,0 @@ |
@@ -18,5 +18,2 @@ /* | ||
| import com.gitblit.Constants; | ||
| import com.gitblit.models.RegistrantAccessPermission; | ||
| import com.gitblit.models.TeamModel; | ||
| import org.junit.Test; | ||
@@ -26,4 +23,2 @@ | ||
| import java.util.List; | ||
| /** | ||
@@ -59,46 +54,2 @@ * @author Alfred Schmid | ||
| @Test | ||
| public void getRepositoryPermissionsMultipleTeams() | ||
| { | ||
| TeamModel aTeam = new TeamModel("A team"); | ||
| aTeam.addRepositoryPermission("RW+:acerepo.git"); | ||
| aTeam.addRepositoryPermission("V:boobrepo.git"); | ||
| TeamModel bTeam = new TeamModel("Team B"); | ||
| bTeam.addRepositoryPermission("R:acerepo.git"); | ||
| bTeam.addRepositoryPermission("RWC:boobrepo.git"); | ||
| UserModel user = new UserModel("tessiur"); | ||
| user.teams.add(aTeam); | ||
| user.teams.add(bTeam); | ||
| user.addRepositoryPermission("RW+:myrepo.git"); | ||
| List<RegistrantAccessPermission> repoPerms = user.getRepositoryPermissions(); | ||
| int found = 0; | ||
| for (RegistrantAccessPermission p : repoPerms) { | ||
| switch (p.registrant) { | ||
| case "acerepo.git": | ||
| assertEquals("Expected REWIND(RW+) permission for " + p.registrant, Constants.AccessPermission.REWIND, p.permission); | ||
| found++; | ||
| break; | ||
| case "boobrepo.git": | ||
| assertEquals("Expected CREATE(RWC) permission for " + p.registrant, Constants.AccessPermission.CREATE, p.permission); | ||
| found++; | ||
| break; | ||
| case "myrepo.git": | ||
| assertEquals("Expected REWIND(RW+) permission for " + p.registrant, Constants.AccessPermission.REWIND, p.permission); | ||
| found++; | ||
| break; | ||
| default: | ||
| fail("Unknown repository registrant " + p.registrant); | ||
| break; | ||
| } | ||
| } | ||
| assertEquals("Repostory permissions missing in list.", 3, found); | ||
| } | ||
| } |
| # Security Policy | ||
| ## Reporting a Vulnerability | ||
| 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. | ||
| ``` | ||
| gitblitorg@gmail.com | ||
| ``` |
| # Nightly build of a snapshot version | ||
| # and a docker image which is pushed | ||
| # to a docker registry | ||
| name: Nightly image build and push | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| forced: | ||
| description: 'Force run, independent of new commits' | ||
| required: false | ||
| default: 'false' | ||
| schedule: | ||
| - cron: '33 1 * * *' | ||
| jobs: | ||
| # Check if new commits were added since the last time this workflow ran. | ||
| # The Github cache is used for this, using the SHA as the key. | ||
| check_commits: | ||
| name: Check for new commits | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| build: ${{ steps.cache-sha.outputs.cache-hit == false }} | ||
| steps: | ||
| - name: Cache marker for latest commit | ||
| uses: actions/cache@v3 | ||
| id: cache-sha | ||
| with: | ||
| key: sha-${{ github.sha }} | ||
| path: timestamp.txt | ||
| - name: Register latest commit | ||
| if: ${{ steps.cache-sha.outputs.cache-hit == false }} | ||
| run: | | ||
| echo "Current commit $GITHUB_SHA has no cache hit." | ||
| date > timestamp.txt | ||
| echo "Build job should be triggered now" | ||
| cat timestamp.txt | ||
| - name: Stop on no new commit | ||
| if: ${{ steps.cache-sha.outputs.cache-hit }} | ||
| run: | | ||
| echo "Current commit $GITHUB_SHA was already seen." | ||
| echo "Build job should be skipped." | ||
| [ -f timestamp.txt ] && cat timestamp.txt | ||
| # 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 | ||
| # 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. | ||
| build: | ||
| name: build GO | ||
| runs-on: ubuntu-latest | ||
| needs: check_commits | ||
| if: ${{ needs.check_commits.outputs.build == 'true' || github.event.inputs.forced == 'true' }} | ||
| steps: | ||
| - name: Checkout Gitblit | ||
| uses: actions/checkout@v3 | ||
| with: | ||
| submodules: true | ||
| - name: Setup Java 8 | ||
| uses: actions/setup-java@v3 | ||
| with: | ||
| java-version: 8 | ||
| distribution: 'temurin' | ||
| - name: Report Java version | ||
| run: | | ||
| java -version | ||
| javac -version | ||
| - name: Build GO with Ant | ||
| run: ant buildGO | ||
| - name: Save built Gitblit package | ||
| if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' }} | ||
| uses: actions/upload-artifact@v3 | ||
| with: | ||
| name: gitblit-nightly | ||
| path: build/target/gitblit-*-SNAPSHOT.tar.gz | ||
| # This is a gating job, which checks if the secrets necessary for pushing an image | ||
| # to the docker hub are present in the repository. This way this workflow can be | ||
| # present in repos which cannot upload to the docker hub. | ||
| secret-gate: | ||
| name: Gate job checking for docker hub secret | ||
| runs-on: ubuntu-latest | ||
| needs: build | ||
| outputs: | ||
| build_docker: ${{steps.check-dh-login.outputs.secrets_present}} | ||
| steps: | ||
| - name: Check if we have the necessary data for docker | ||
| id: check-dh-login | ||
| run: | | ||
| if [[ -n "${{secrets.DOCKERHUB_GB_TOKEN}}" && -n "${{secrets.DOCKERHUB_GB_USER}}" ]] ; then | ||
| echo "secrets_present=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "No Docker Hub login data found. Skipping Docker." | ||
| fi | ||
| # Only if the gating job signals success will this job run and build and push the docker image | ||
| # built for the current snapshot version of Gitblit. | ||
| docker: | ||
| name: Build and push nightly docker image | ||
| runs-on: ubuntu-latest | ||
| if: needs.secret-gate.outputs.build_docker == 'true' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop') | ||
| needs: secret-gate | ||
| env: | ||
| GH_ORG: gitblit | ||
| GITBLIT_VERSION: SNAPSHOT | ||
| steps: | ||
| - name: Checkout gitblit-docker | ||
| uses: actions/checkout@v3 | ||
| with: | ||
| repository: ${{ env.GH_ORG }}/gitblit-docker | ||
| ref: master | ||
| fetch-depth: 2 | ||
| - name: Download Gitblit nightly build | ||
| uses: actions/download-artifact@v3 | ||
| id: get-gb | ||
| with: | ||
| name: gitblit-nightly | ||
| - name: Extract snapshot version | ||
| id: gb-version | ||
| run: | | ||
| for file in $(ls -1 ${{steps.get-gb.outputs.download-path}}) ; do | ||
| if [[ "$file" = gitblit-*.gz ]] ; then gbver=$file ; fi | ||
| done | ||
| gbver=${gbver%.tar.gz} | ||
| gbver=${gbver##*gitblit-} | ||
| echo "Version detected: $gbver" | ||
| echo "GITBLIT_VERSION=$gbver" >> "${GITHUB_ENV}" | ||
| echo "gb-version=$gbver" >> $GITHUB_OUTPUT | ||
| - name: Generate Dockerfile for snapshot image | ||
| run: | | ||
| generate/generate_dockerfile.sh -v ${{ steps.gb-version.outputs.gb-version }} > generate/Dockerfile | ||
| echo "BUILD_DATE=$(date +%Y-%m-%dT%H:%M:%S)" >> "${GITHUB_ENV}" | ||
| - name: Login to Docker Hub | ||
| uses: docker/login-action@v2 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_GB_USER }} | ||
| password: ${{ secrets.DOCKERHUB_GB_TOKEN }} | ||
| - name: Build snapshot docker image | ||
| uses: docker/build-push-action@v3 | ||
| with: | ||
| file: generate/Dockerfile | ||
| context: . | ||
| load: true | ||
| tags: gitblit/gitblit:nightly | ||
| labels: | | ||
| org.label-schema.vcs-ref=${{github.sha}} | ||
| org.label-schema.build-date=${{env.BUILD_DATE}} | ||
| org.opencontainers.image.revision=${{ env.GITBLIT_GIT_SHA }} | ||
| org.opencontainers.image.created=${{ env.BUILD_DATE }} | ||
| - name: Install Goss for testing the docker image | ||
| uses: e1himself/goss-installation-action@v1.0.4 | ||
| with: | ||
| version: 'v0.3.16' | ||
| - 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 | ||
| - name: Test docker container - bind mount | ||
| env: | ||
| GOSS_WAIT_OPTS: "-r 15s -s 5s > /dev/null" | ||
| run: | | ||
| mkdir gitblit-data | ||
| mkdir gitblit-data/etc | ||
| echo "This should not be overwritten" > gitblit-data/etc/gitblit.properties | ||
| 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 | ||
| [ -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 | ||
| sudo rm -rf gitblit-data | ||
| - name: Test docker container - tmpfs | ||
| 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 | ||
| # Delete the artifact unless this is the official Gitblit repo | ||
| - uses: geekyeggo/delete-artifact@v2 | ||
| if: ${{ github.repository != 'gitblit/gitblit' }} | ||
| with: | ||
| name: gitblit-nightly | ||
| failOnError: false | ||
| - name: Push docker image to registry | ||
| uses: docker/build-push-action@v3 | ||
| with: | ||
| file: generate/Dockerfile | ||
| context: . | ||
| push: true | ||
| tags: gitblit/gitblit:nightly | ||
| labels: | | ||
| org.label-schema.vcs-ref=${{github.sha}} | ||
| org.label-schema.build-date=${{env.BUILD_DATE}} |
| /* | ||
| * Copyright (c) 2013 by syntevo GmbH. All Rights Reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions are met: | ||
| * | ||
| * o Redistributions of source code must retain the above copyright notice, | ||
| * this list of conditions and the following disclaimer. | ||
| * | ||
| * o Redistributions in binary form must reproduce the above copyright notice, | ||
| * this list of conditions and the following disclaimer in the documentation | ||
| * and/or other materials provided with the distribution. | ||
| * | ||
| * o Neither the name of syntevo GmbH nor the names of | ||
| * its contributors may be used to endorse or promote products derived | ||
| * from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | ||
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | ||
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| */ | ||
| package com.syntevo.bugtraq; | ||
| import java.util.*; | ||
| import org.jetbrains.annotations.*; | ||
| public final class BugtraqConfigEntry { | ||
| // Fields ================================================================= | ||
| private final String url; | ||
| private final List<String> projects; | ||
| private final List<BugtraqEntry> entries; | ||
| // Setup ================================================================== | ||
| public BugtraqConfigEntry(@NotNull String url, @NotNull String logIdRegex, @Nullable String logLinkRegex, @Nullable String logFilterRegex, @Nullable String logLinkText, @Nullable List<String> projects) throws BugtraqException { | ||
| this.url = url; | ||
| this.projects = projects; | ||
| this.entries = new ArrayList<>(); | ||
| if (projects == null) { | ||
| entries.add(new BugtraqEntry(url, logIdRegex, logLinkRegex, logFilterRegex, logLinkText)); | ||
| } | ||
| else { | ||
| for (String project : projects) { | ||
| final String projectUrl = this.url.replace("%PROJECT%", project); | ||
| final String projectLogIdRegex = logIdRegex.replace("%PROJECT%", project); | ||
| final String projectLogLinkRegex = logLinkRegex != null ? logLinkRegex.replace("%PROJECT%", project) : null; | ||
| final String projectLogFilterRegex = logFilterRegex != null ? logFilterRegex.replace("%PROJECT%", project) : null; | ||
| final String projectLogLinkText = logLinkText != null ? logLinkText.replace("%PROJECT%", project) : null; | ||
| entries.add(new BugtraqEntry(projectUrl, projectLogIdRegex, projectLogLinkRegex, projectLogFilterRegex, projectLogLinkText)); | ||
| } | ||
| } | ||
| } | ||
| // Accessing ============================================================== | ||
| @NotNull | ||
| public String getUrl() { | ||
| return url; | ||
| } | ||
| @Nullable | ||
| public List<String> getProjects() { | ||
| return projects != null ? Collections.unmodifiableList(projects) : null; | ||
| } | ||
| public List<BugtraqEntry> getEntries() { | ||
| return entries; | ||
| } | ||
| } |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml" | ||
| xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" | ||
| xml:lang="fr" | ||
| lang="fr"> | ||
| <body> | ||
| <wicket:extend> | ||
| <div class="container"> | ||
| <div class="markdown"> | ||
| <div class="row"> | ||
| <div class="span10 offset1"> | ||
| <h3><center>Dépôt vide</center></h3> | ||
| <div class="alert alert-info"> | ||
| <span wicket:id="repository" style="font-weight: bold;">[repository]</span> est un dépôt vide, Gitblit ne peut pas le visualiser. | ||
| <p></p> | ||
| S'il vous plaît, envoyer quelques commits dans <span wicket:id="pushurl"></span> | ||
| <hr/> | ||
| Après avoir envoyé (push) des commits, vous pouvez <b>rafraîchir</b> cette page pour visualiser votre dépôt. | ||
| </div> | ||
| <h3><center>Créer un nouveau référentiel en ligne de commande</center></h3> | ||
| <pre wicket:id="createSyntax"></pre> | ||
| <h3><center>Déposer un dépôt existant en ligne de commande</center></h3> | ||
| <pre wicket:id="existingSyntax"></pre> | ||
| <div class="span8 offset1"> | ||
| <h2><center>Apprendre Git</center></h2> | ||
| <p>Si vous n'êtes pas sûr de vous sur l'utilisation de ces commandes, envisagez de consulter le <a href="http://book.git-scm.com">Git Community Book (Livre de la communauté Git)</a> pour mieux comprendre comment utiliser Git.</p> | ||
| <h4>Clients Git "Open Source"</h4> | ||
| <table> | ||
| <tbody> | ||
| <tr><td><a href="http://git-scm.com">Git</a></td><td>Version officielle de Git, en ligne de commande</td></tr> | ||
| <tr><td><a href="http://tortoisegit.googlecode.com">TortoiseGit</a></td><td>Intégration de Git dans l'explorateur de fichiers Windows (nécessite l'application officielle Git, en ligne de commande)</td></tr> | ||
| <tr><td><a href="http://eclipse.org/egit">Eclipse/EGit</a></td><td>Module Git pour l'IDE Eclipse (basé sur JGit, comme Gitblit)</td></tr> | ||
| <tr><td><a href="http://gitextensions.github.io">Git Extensions</a></td><td>Client pour Git écrit en C#, intégré à l'Explorateur de fichier de Windows et à Visual Studio</td></tr> | ||
| <tr><td><a href="http://rowanj.github.io/gitx/">GitX-dev</a></td><td>Client Git pour Mac OS X</td></tr> | ||
| </tbody> | ||
| </table> | ||
| <h4>Clients Git propriétaire</h4> | ||
| <table> | ||
| <tbody> | ||
| <tr><td><a href="http://www.syntevo.com/smartgithg">SmartGit/Hg</a></td><td>Un client Git et Mercurial écrit Java pour Windows, Mac, et Linux</td></tr> | ||
| <tr><td><a href="http://www.sourcetreeapp.com/">SourceTree</a></td><td>Un client Git et Mercurial gratuit pour Windows et Mac</td></tr> | ||
| <tr><td><a href="http://www.git-tower.com/">Tower</a></td><td>Client Git pour Mac OS</td></tr> | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </wicket:extend> | ||
| </body> | ||
| </html> |
| /*! | ||
| * clipboard.js v2.0.11 | ||
| * https://clipboardjs.com/ | ||
| * | ||
| * Licensed MIT © Zeno Rocha | ||
| */ | ||
| !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body},n="";return"string"==typeof t?n=o(t,e):t instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(null==t?void 0:t.type)?n=o(t.value,e):(n=r()(t),c("copy")),n};function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var s=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},e=t.action,n=void 0===e?"copy":e,o=t.container,e=t.target,t=t.text;if("copy"!==n&&"cut"!==n)throw new Error('Invalid "action" value, use either "copy" or "cut"');if(void 0!==e){if(!e||"object"!==l(e)||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===n&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===n&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes')}return t?f(t,{container:o}):e?"cut"===n?a(e):f(e,{container:o}):void 0};function p(t){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function d(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function y(t,e){return(y=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(n){var o=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=v(n);return t=o?(t=v(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==p(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function v(t){return(v=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function m(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}var b=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&y(t,e)}(r,i());var t,e,n,o=h(r);function r(t,e){var n;return function(t){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}(this),(n=o.call(this)).resolveOptions(e),n.listenClick(t),n}return t=r,n=[{key:"copy",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body};return f(t,e)}},{key:"cut",value:function(t){return a(t)}},{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===p(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=u()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget,n=this.action(e)||"copy",t=s({action:n,container:this.container,target:this.target(e),text:this.text(e)});this.emit(t?"success":"error",{action:n,text:t,trigger:e,clearSelection:function(){e&&e.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(t){return m("action",t)}},{key:"defaultTarget",value:function(t){t=m("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return m("text",t)}},{key:"destroy",value:function(){this.listener.destroy()}}])&&d(t.prototype,e),n&&d(t,n),r}()},828:function(t){var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:function(t,e,n){var u=n(828);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=u(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},879:function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:function(t,e,n){var f=n(879),l=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!f.string(e))throw new TypeError("Second argument must be a String");if(!f.fn(n))throw new TypeError("Third argument must be a Function");if(f.node(t))return c=e,a=n,(u=t).addEventListener(c,a),{destroy:function(){u.removeEventListener(c,a)}};if(f.nodeList(t))return o=t,r=e,i=n,Array.prototype.forEach.call(o,function(t){t.addEventListener(r,i)}),{destroy:function(){Array.prototype.forEach.call(o,function(t){t.removeEventListener(r,i)})}};if(f.string(t))return t=t,e=e,n=n,l(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,u,c,a}},817:function(t){t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:function(t){function e(){}e.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,u=o.length;i<u;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},r={},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,{a:e}),e},o.d=function(t,e){for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o(686).default;function o(t){if(r[t])return r[t].exports;var e=r[t]={exports:{}};return n[t](e,e.exports,o),e.exports}var n,r}); |
| // Instantiate the clipboarding | ||
| var clipboard = new ClipboardJS('.ctcbtn'); | ||
| clipboard.on('success', function (e) { | ||
| showTooltip(e.trigger, "Copied!"); | ||
| }); | ||
| clipboard.on('error', function (e) { | ||
| showTooltip(e.trigger, fallbackMessage(e.action)); | ||
| }); | ||
| // Attach events to buttons to clear tooltip again | ||
| var btns = document.querySelectorAll('.ctcbtn'); | ||
| for (var i = 0; i < btns.length; i++) { | ||
| btns[i].addEventListener('mouseleave', clearTooltip); | ||
| btns[i].addEventListener('blur', clearTooltip); | ||
| } | ||
| function findTooltipped(elem) { | ||
| do { | ||
| if (elem.classList.contains('tooltipped')) return elem; | ||
| elem = elem.parentElement; | ||
| } while (elem != null); | ||
| return null; | ||
| } | ||
| // Show or hide tooltip by setting the tooltipped-active class | ||
| // on a parent that contains tooltipped. Since the copy button | ||
| // could be and image, or be hidden after clicking, the tooltipped | ||
| // element might be higher in the hierarchy. | ||
| var ttset; | ||
| function showTooltip(elem, msg) { | ||
| let ttelem = findTooltipped(elem); | ||
| if (ttelem != null) { | ||
| ttelem.classList.add('tooltipped-active'); | ||
| ttelem.setAttribute('data-tt-text', msg); | ||
| ttset=Date.now(); | ||
| } | ||
| else { | ||
| console.warn("Could not find any tooltipped element for clipboard button.", elem); | ||
| } | ||
| } | ||
| function clearTooltip(e) { | ||
| let ttelem = findTooltipped(e.currentTarget); | ||
| if (ttelem != null) { | ||
| let now = Date.now(); | ||
| if (now - ttset < 500) { | ||
| // Give the tooltip some time to display | ||
| setTimeout(function(){ttelem.classList.remove('tooltipped-active')}, 1000) | ||
| } | ||
| else { | ||
| ttelem.classList.remove('tooltipped-active'); | ||
| } | ||
| } | ||
| else { | ||
| console.warn("Could not find any tooltipped element for clipboard button.", e.currentTarget); | ||
| } | ||
| } | ||
| // If the API is not supported, at least fall back to a message saying | ||
| // that now that the text is selected, Ctrl-C can be used. | ||
| // This is still a problem in the repo URL dropdown. When it is hidden, Ctrl-C doesn't work. | ||
| function fallbackMessage(action) { | ||
| var actionMsg = ""; | ||
| if (/Mac/i.test(navigator.userAgent)) { | ||
| actionMsg = "Press ⌘-C to copy"; | ||
| } | ||
| else { | ||
| actionMsg = "Press Ctrl-C to copy"; | ||
| } | ||
| return actionMsg; | ||
| } |
| package com.gitblit.transport.ssh; | ||
| import org.junit.Rule; | ||
| import org.junit.Test; | ||
| import org.junit.rules.TemporaryFolder; | ||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.security.KeyPair; | ||
| import java.util.Iterator; | ||
| import static org.junit.Assert.*; | ||
| public class FileKeyPairProviderTest | ||
| { | ||
| @Rule | ||
| public TemporaryFolder testFolder = new TemporaryFolder(); | ||
| private void generateKeyPair(File file, String algorithm, int keySize) { | ||
| if (file.exists()) { | ||
| file.delete(); | ||
| } | ||
| SshDaemon.generateKeyPair(file, algorithm, keySize); | ||
| } | ||
| @Test | ||
| public void loadKeysEddsa() throws IOException | ||
| { | ||
| File file = testFolder.newFile("eddsa.pem"); | ||
| generateKeyPair(file, "EdDSA", 0); | ||
| FileKeyPairProvider hostKeyPairProvider = new FileKeyPairProvider(); | ||
| hostKeyPairProvider.setFiles(new String [] { file.getPath() }); | ||
| Iterable<KeyPair> keyPairs = hostKeyPairProvider.loadKeys(); | ||
| Iterator<KeyPair> iterator = keyPairs.iterator(); | ||
| assertTrue(iterator.hasNext()); | ||
| KeyPair keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "EdDSA", keyPair.getPrivate().getAlgorithm()); | ||
| } | ||
| @Test | ||
| public void loadKeysEd25519() throws IOException | ||
| { | ||
| File file = testFolder.newFile("ed25519.pem"); | ||
| generateKeyPair(file, "ED25519", 0); | ||
| FileKeyPairProvider hostKeyPairProvider = new FileKeyPairProvider(); | ||
| hostKeyPairProvider.setFiles(new String [] { file.getPath() }); | ||
| Iterable<KeyPair> keyPairs = hostKeyPairProvider.loadKeys(); | ||
| Iterator<KeyPair> iterator = keyPairs.iterator(); | ||
| assertTrue(iterator.hasNext()); | ||
| KeyPair keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "Ed25519", keyPair.getPrivate().getAlgorithm()); | ||
| } | ||
| @Test | ||
| public void loadKeysECDSA() throws IOException | ||
| { | ||
| File file = testFolder.newFile("ecdsa.pem"); | ||
| generateKeyPair(file, "ECDSA", 0); | ||
| FileKeyPairProvider hostKeyPairProvider = new FileKeyPairProvider(); | ||
| hostKeyPairProvider.setFiles(new String [] { file.getPath() }); | ||
| Iterable<KeyPair> keyPairs = hostKeyPairProvider.loadKeys(); | ||
| Iterator<KeyPair> iterator = keyPairs.iterator(); | ||
| assertTrue(iterator.hasNext()); | ||
| KeyPair keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "ECDSA", keyPair.getPrivate().getAlgorithm()); | ||
| } | ||
| @Test | ||
| public void loadKeysRSA() throws IOException | ||
| { | ||
| File file = testFolder.newFile("rsa.pem"); | ||
| generateKeyPair(file, "RSA", 4096); | ||
| FileKeyPairProvider hostKeyPairProvider = new FileKeyPairProvider(); | ||
| hostKeyPairProvider.setFiles(new String [] { file.getPath() }); | ||
| Iterable<KeyPair> keyPairs = hostKeyPairProvider.loadKeys(); | ||
| Iterator<KeyPair> iterator = keyPairs.iterator(); | ||
| assertTrue(iterator.hasNext()); | ||
| KeyPair keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "RSA", keyPair.getPrivate().getAlgorithm()); | ||
| } | ||
| @Test | ||
| public void loadKeysDefault() throws IOException | ||
| { | ||
| File rsa = testFolder.newFile("rsa.pem"); | ||
| generateKeyPair(rsa, "RSA", 2048); | ||
| File ecdsa = testFolder.newFile("ecdsa.pem"); | ||
| generateKeyPair(ecdsa, "ECDSA", 0); | ||
| File eddsa = testFolder.newFile("eddsa.pem"); | ||
| generateKeyPair(eddsa, "EdDSA", 0); | ||
| File ed25519 = testFolder.newFile("ed25519.pem"); | ||
| generateKeyPair(ed25519, "ED25519", 0); | ||
| FileKeyPairProvider hostKeyPairProvider = new FileKeyPairProvider(); | ||
| hostKeyPairProvider.setFiles(new String [] { ecdsa.getPath(), eddsa.getPath(), rsa.getPath(), ed25519.getPath() }); | ||
| Iterable<KeyPair> keyPairs = hostKeyPairProvider.loadKeys(); | ||
| Iterator<KeyPair> iterator = keyPairs.iterator(); | ||
| assertTrue(iterator.hasNext()); | ||
| KeyPair keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "ECDSA", keyPair.getPrivate().getAlgorithm()); | ||
| assertTrue(iterator.hasNext()); | ||
| keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "EdDSA", keyPair.getPrivate().getAlgorithm()); | ||
| assertTrue(iterator.hasNext()); | ||
| keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "RSA", keyPair.getPrivate().getAlgorithm()); | ||
| assertTrue(iterator.hasNext()); | ||
| keyPair = iterator.next(); | ||
| assertNotNull(keyPair); | ||
| assertEquals("Unexpected key pair type", "Ed25519", keyPair.getPrivate().getAlgorithm()); | ||
| assertFalse(iterator.hasNext()); | ||
| } | ||
| } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet