From 9d44ade215922fd9e7bda7c604b31c31d217d750 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 17 Mar 2014 21:23:44 -0400 Subject: Create git and gitblit dispatchers --- .../gitblit/transport/ssh/SshCommandFactory.java | 41 ++----- .../transport/ssh/commands/AddKeyCommand.java | 53 --------- .../transport/ssh/commands/BaseGitCommand.java | 103 ----------------- .../transport/ssh/commands/BaseKeyCommand.java | 58 ---------- .../transport/ssh/commands/CreateRepository.java | 36 ------ .../transport/ssh/commands/DispatchCommand.java | 65 +++++------ .../ssh/commands/ListRepositoriesCommand.java | 72 ------------ .../gitblit/transport/ssh/commands/Receive.java | 33 ------ .../transport/ssh/commands/RemoveKeyCommand.java | 61 ----------- .../transport/ssh/commands/ReviewCommand.java | 88 --------------- .../transport/ssh/commands/SetAccountCommand.java | 88 --------------- .../com/gitblit/transport/ssh/commands/Upload.java | 33 ------ .../transport/ssh/commands/VersionCommand.java | 29 ----- .../gitblit/transport/ssh/git/BaseGitCommand.java | 104 ++++++++++++++++++ .../transport/ssh/git/GitDispatchCommand.java | 61 +++++++++++ .../com/gitblit/transport/ssh/git/Receive.java | 33 ++++++ .../java/com/gitblit/transport/ssh/git/Upload.java | 33 ++++++ .../transport/ssh/gitblit/AddKeyCommand.java | 51 +++++++++ .../transport/ssh/gitblit/BaseKeyCommand.java | 64 +++++++++++ .../transport/ssh/gitblit/CreateRepository.java | 37 +++++++ .../ssh/gitblit/GitblitDispatchCommand.java | 38 +++++++ .../gitblit/transport/ssh/gitblit/LsCommand.java | 122 +++++++++++++++++++++ .../transport/ssh/gitblit/RemoveKeyCommand.java | 59 ++++++++++ .../transport/ssh/gitblit/ReviewCommand.java | 89 +++++++++++++++ .../transport/ssh/gitblit/SetAccountCommand.java | 85 ++++++++++++++ .../transport/ssh/gitblit/VersionCommand.java | 30 +++++ 26 files changed, 840 insertions(+), 726 deletions(-) delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/BaseGitCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/CreateRepository.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/ListRepositoriesCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/Receive.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/ReviewCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/Upload.java delete mode 100644 src/main/java/com/gitblit/transport/ssh/commands/VersionCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/git/BaseGitCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/git/Receive.java create mode 100644 src/main/java/com/gitblit/transport/ssh/git/Upload.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java create mode 100644 src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java (limited to 'src') diff --git a/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java b/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java index b8dd5b9f..de7aad1f 100644 --- a/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java +++ b/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java @@ -34,21 +34,11 @@ import org.apache.sshd.server.session.ServerSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.git.GitblitReceivePackFactory; -import com.gitblit.git.GitblitUploadPackFactory; -import com.gitblit.git.RepositoryResolver; import com.gitblit.manager.IGitblit; import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.commands.AddKeyCommand; -import com.gitblit.transport.ssh.commands.CreateRepository; import com.gitblit.transport.ssh.commands.DispatchCommand; -import com.gitblit.transport.ssh.commands.ListRepositoriesCommand; -import com.gitblit.transport.ssh.commands.Receive; -import com.gitblit.transport.ssh.commands.RemoveKeyCommand; -import com.gitblit.transport.ssh.commands.ReviewCommand; -import com.gitblit.transport.ssh.commands.SetAccountCommand; -import com.gitblit.transport.ssh.commands.Upload; -import com.gitblit.transport.ssh.commands.VersionCommand; +import com.gitblit.transport.ssh.git.GitDispatchCommand; +import com.gitblit.transport.ssh.gitblit.GitblitDispatchCommand; import com.gitblit.utils.IdGenerator; import com.gitblit.utils.WorkQueue; import com.google.common.util.concurrent.Atomics; @@ -86,31 +76,16 @@ public class SshCommandFactory implements CommandFactory { protected DispatchCommand createRootDispatcher(SshDaemonClient client, String cmdLine) { final UserModel user = client.getUser(); - DispatchCommand gitblitCmd = new DispatchCommand(); - gitblitCmd.registerCommand(user, VersionCommand.class); - gitblitCmd.registerCommand(user, AddKeyCommand.class); - gitblitCmd.registerCommand(user, RemoveKeyCommand.class); - gitblitCmd.registerCommand(user, ListRepositoriesCommand.class); - gitblitCmd.registerCommand(user, ReviewCommand.class); - - gitblitCmd.registerCommand(user, CreateRepository.class); - gitblitCmd.registerCommand(user, SetAccountCommand.class); - - DispatchCommand gitCmd = new DispatchCommand(); - gitCmd.registerCommand(user, Upload.class); - gitCmd.registerCommand(user, Receive.class); + DispatchCommand root = new DispatchCommand() { + }; + root.setContext(new SshCommandContext(gitblit, client, cmdLine)); - DispatchCommand root = new DispatchCommand(); - root.registerDispatcher("gitblit", gitblitCmd); - root.registerDispatcher("git", gitCmd); + // TODO convert these dispatchers to plugin extension points + root.registerDispatcher(user, GitblitDispatchCommand.class); + root.registerDispatcher(user, GitDispatchCommand.class); - root.setRepositoryResolver(new RepositoryResolver(gitblit)); - root.setUploadPackFactory(new GitblitUploadPackFactory(gitblit)); - root.setReceivePackFactory(new GitblitReceivePackFactory(gitblit)); root.setAuthenticator(keyAuthenticator); - root.setContext(new SshCommandContext(gitblit, client, cmdLine)); - return root; } diff --git a/src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java deleted file mode 100644 index 35bb1bbf..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/AddKeyCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.gitblit.transport.ssh.commands; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.kohsuke.args4j.Argument; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.gitblit.transport.ssh.CommandMetaData; -import com.gitblit.transport.ssh.IKeyManager; - -/** - * Add a key to the current user's authorized keys list. - * - * @author James Moger - * - */ -@CommandMetaData(name = "add-key", description = "Add an SSH public key to your account") -public class AddKeyCommand extends BaseKeyCommand { - - protected final Logger log = LoggerFactory.getLogger(getClass()); - - @Argument(metaVar = "|KEY", usage = "the key to add") - private List addKeys = new ArrayList(); - - @Override - public void run() throws IOException, UnloggedFailure { - String username = ctx.getClient().getUsername(); - List keys = readKeys(addKeys); - IKeyManager keyManager = authenticator.getKeyManager(); - for (String key : keys) { - keyManager.addKey(username, key); - log.info("added SSH public key for {}", username); - } - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/BaseGitCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/BaseGitCommand.java deleted file mode 100644 index a3411616..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/BaseGitCommand.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.transport.ssh.commands; - -import java.io.IOException; - -import org.apache.sshd.server.Environment; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.transport.resolver.ReceivePackFactory; -import org.eclipse.jgit.transport.resolver.UploadPackFactory; -import org.kohsuke.args4j.Argument; - -import com.gitblit.git.GitblitReceivePackFactory; -import com.gitblit.git.GitblitUploadPackFactory; -import com.gitblit.git.RepositoryResolver; -import com.gitblit.transport.ssh.SshDaemonClient; - -/** - * @author Eric Myhre - * - */ -public abstract class BaseGitCommand extends BaseCommand { - @Argument(index = 0, metaVar = "REPOSITORY", required = true, usage = "repository name") - protected String repository; - - protected RepositoryResolver repositoryResolver; - protected ReceivePackFactory receivePackFactory; - protected UploadPackFactory uploadPackFactory; - - protected Repository repo; - - @Override - public void start(final Environment env) { - startThread(new RepositoryCommandRunnable() { - @Override - public void run() throws Exception { - parseCommandLine(); - BaseGitCommand.this.service(); - } - - @Override - public String getRepository() { - return repository; - } - }); - } - - private void service() throws IOException, Failure { - try { - repo = openRepository(); - runImpl(); - } finally { - if (repo != null) { - repo.close(); - } - } - } - - protected abstract void runImpl() throws IOException, Failure; - - protected Repository openRepository() throws Failure { - // Assume any attempt to use \ was by a Windows client - // and correct to the more typical / used in Git URIs. - // - repository = repository.replace('\\', '/'); - // ssh://git@thishost/path should always be name="/path" here - // - if (!repository.startsWith("/")) { - throw new Failure(1, "fatal: '" + repository + "': not starts with / character"); - } - repository = repository.substring(1); - try { - return repositoryResolver.open(ctx.getClient(), repository); - } catch (Exception e) { - throw new Failure(1, "fatal: '" + repository + "': not a git archive", e); - } - } - - public void setRepositoryResolver(RepositoryResolver repositoryResolver) { - this.repositoryResolver = repositoryResolver; - } - - public void setReceivePackFactory(GitblitReceivePackFactory receivePackFactory) { - this.receivePackFactory = receivePackFactory; - } - - public void setUploadPackFactory(GitblitUploadPackFactory uploadPackFactory) { - this.uploadPackFactory = uploadPackFactory; - } -} \ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java deleted file mode 100644 index f92ea6f9..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/BaseKeyCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.gitblit.transport.ssh.commands; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.util.List; - -import com.gitblit.transport.ssh.CachingPublicKeyAuthenticator; -import com.google.common.base.Charsets; - -/** - * - * Base class for commands that read SSH keys from stdin or a parameter list. - * - */ -public abstract class BaseKeyCommand extends SshCommand { - - protected List readKeys(List sshKeys) - throws UnsupportedEncodingException, IOException { - int idx = -1; - if (sshKeys.isEmpty() || ((idx = sshKeys.indexOf("-")) >= 0)) { - String sshKey = ""; - BufferedReader br = new BufferedReader(new InputStreamReader( - in, Charsets.UTF_8)); - String line; - while ((line = br.readLine()) != null) { - sshKey += line + "\n"; - } - if (idx == -1) { - sshKeys.add(sshKey.trim()); - } else { - sshKeys.set(idx, sshKey.trim()); - } - } - return sshKeys; - } - - protected CachingPublicKeyAuthenticator authenticator; - public void setAuthenticator(CachingPublicKeyAuthenticator authenticator) { - this.authenticator = authenticator; - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/CreateRepository.java b/src/main/java/com/gitblit/transport/ssh/commands/CreateRepository.java deleted file mode 100644 index 20f69015..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/CreateRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.gitblit.transport.ssh.commands; - -import org.kohsuke.args4j.Option; - -import com.gitblit.transport.ssh.CommandMetaData; - -@CommandMetaData(name = "create-repository", description = "Create new GIT repository", admin = true, hidden = true) -public class CreateRepository extends SshCommand { - - @Option(name = "--name", aliases = {"-n"}, required = true, metaVar = "NAME", usage = "name of repository to be created") - private String name; - - @Option(name = "--description", aliases = {"-d"}, metaVar = "DESCRIPTION", usage = "description of repository") - private String repositoryDescription; - - @Override - public void run() { - stdout.println(String.format("Repository <%s> was created", name)); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java index 00d3b819..38f1a48f 100644 --- a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java @@ -30,21 +30,17 @@ import org.kohsuke.args4j.Argument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.git.GitblitReceivePackFactory; -import com.gitblit.git.GitblitUploadPackFactory; -import com.gitblit.git.RepositoryResolver; import com.gitblit.models.UserModel; import com.gitblit.transport.ssh.CommandMetaData; import com.gitblit.transport.ssh.CachingPublicKeyAuthenticator; -import com.gitblit.transport.ssh.SshDaemonClient; -mport com.gitblit.utils.StringUtils; +import com.gitblit.transport.ssh.gitblit.BaseKeyCommand; +import com.gitblit.utils.StringUtils; import com.gitblit.utils.cli.SubcommandHandler; import com.google.common.base.Charsets; import com.google.common.base.Strings; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -public class DispatchCommand extends BaseCommand { +public abstract class DispatchCommand extends BaseCommand { private Logger log = LoggerFactory.getLogger(getClass()); @@ -62,11 +58,31 @@ public class DispatchCommand extends BaseCommand { commands = new HashSet>(); } - public void registerDispatcher(String name, Command cmd) { + public void registerDispatcher(UserModel user, Class cmd) { + if (!cmd.isAnnotationPresent(CommandMetaData.class)) { + throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!", cmd.getName(), + CommandMetaData.class.getName())); + } if (dispatchers == null) { dispatchers = Maps.newHashMap(); } - dispatchers.put(name, cmd); + + CommandMetaData meta = cmd.getAnnotation(CommandMetaData.class); + if (meta.admin() && !user.canAdmin()) { + log.debug(MessageFormat.format("excluding admin dispatch command {0} for {1}", meta.name(), user.username)); + return; + } + + try { + DispatchCommand dispatcher = cmd.newInstance(); + dispatcher.registerCommands(user); + dispatchers.put(meta.name(), dispatcher); + } catch (Exception e) { + log.error("failed to register {} dispatcher", meta.name()); + } + } + + protected void registerCommands(UserModel user) { } @@ -237,41 +253,12 @@ public class DispatchCommand extends BaseCommand { cmd.setErrorStream(err); cmd.setExitCallback(exit); - if (cmd instanceof BaseGitCommand) { - BaseGitCommand a = (BaseGitCommand) cmd; - a.setRepositoryResolver(repositoryResolver); - a.setUploadPackFactory(gitblitUploadPackFactory); - a.setReceivePackFactory(gitblitReceivePackFactory); - } else if (cmd instanceof DispatchCommand) { - DispatchCommand d = (DispatchCommand) cmd; - d.setRepositoryResolver(repositoryResolver); - d.setUploadPackFactory(gitblitUploadPackFactory); - d.setReceivePackFactory(gitblitReceivePackFactory); - d.setAuthenticator(authenticator); - } else if (cmd instanceof BaseKeyCommand) { + if (cmd instanceof BaseKeyCommand) { BaseKeyCommand k = (BaseKeyCommand) cmd; k.setAuthenticator(authenticator); } } - private RepositoryResolver repositoryResolver; - - public void setRepositoryResolver(RepositoryResolver repositoryResolver) { - this.repositoryResolver = repositoryResolver; - } - - private GitblitUploadPackFactory gitblitUploadPackFactory; - - public void setUploadPackFactory(GitblitUploadPackFactory gitblitUploadPackFactory) { - this.gitblitUploadPackFactory = gitblitUploadPackFactory; - } - - private GitblitReceivePackFactory gitblitReceivePackFactory; - - public void setReceivePackFactory(GitblitReceivePackFactory gitblitReceivePackFactory) { - this.gitblitReceivePackFactory = gitblitReceivePackFactory; - } - private CachingPublicKeyAuthenticator authenticator; public void setAuthenticator(CachingPublicKeyAuthenticator authenticator) { diff --git a/src/main/java/com/gitblit/transport/ssh/commands/ListRepositoriesCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/ListRepositoriesCommand.java deleted file mode 100644 index 7c58e7fc..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/ListRepositoriesCommand.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.gitblit.transport.ssh.commands; - -import java.text.MessageFormat; -import java.text.SimpleDateFormat; -import java.util.List; - -import org.kohsuke.args4j.Option; -import org.parboiled.common.StringUtils; - -import com.gitblit.manager.IGitblit; -import com.gitblit.models.RepositoryModel; -import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; - -@CommandMetaData(name = "repositories", description = "List the available repositories") -public class ListRepositoriesCommand extends SshCommand { - - @Option(name = "--verbose", aliases = { "-v" }, usage = "verbose") - private boolean verbose; - - @Override - public void run() { - IGitblit gitblit = ctx.getGitblit(); - UserModel user = ctx.getClient().getUser(); - List repositories = gitblit.getRepositoryModels(user); - int nameLen = 0; - int descLen = 0; - for (RepositoryModel repo : repositories) { - int len = repo.name.length(); - if (len > nameLen) { - nameLen = len; - } - if (!StringUtils.isEmpty(repo.description)) { - len = repo.description.length(); - if (len > descLen) { - descLen = len; - } - } - } - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); - - String pattern; - if (verbose) { - pattern = MessageFormat.format("%-{0,number,0}s\t%-{1,number,0}s\t%s", nameLen, descLen); - } else { - pattern = "%s"; - } - - for (RepositoryModel repo : repositories) { - stdout.println(String.format(pattern, - repo.name, - repo.description == null ? "" : repo.description, - df.format(repo.lastChange))); - } - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/Receive.java b/src/main/java/com/gitblit/transport/ssh/commands/Receive.java deleted file mode 100644 index 559cfa5d..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/Receive.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.transport.ssh.commands; - -import org.eclipse.jgit.transport.ReceivePack; - -import com.gitblit.transport.ssh.CommandMetaData; - -@CommandMetaData(name = "git-receive-pack", description = "Receive pack") -public class Receive extends BaseGitCommand { - @Override - protected void runImpl() throws Failure { - try { - ReceivePack rp = receivePackFactory.create(ctx.getClient(), repo); - rp.receive(in, out, null); - } catch (Exception e) { - throw new Failure(1, "fatal: Cannot receive pack: ", e); - } - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java deleted file mode 100644 index 90e70418..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/RemoveKeyCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.gitblit.transport.ssh.commands; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.kohsuke.args4j.Argument; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.gitblit.transport.ssh.CommandMetaData; -import com.gitblit.transport.ssh.IKeyManager; - - -/** - * Remove an SSH public key from the current user's authorized key list. - * - * @author James Moger - * - */ -@CommandMetaData(name = "rm-key", description = "Remove an SSH public key from your account") -public class RemoveKeyCommand extends BaseKeyCommand { - - protected final Logger log = LoggerFactory.getLogger(getClass()); - - private static final String ALL = "ALL"; - - @Argument(metaVar = "||ALL", usage = "the key to remove") - private List removeKeys = new ArrayList(); - - @Override - public void run() throws IOException, UnloggedFailure { - String username = ctx.getClient().getUsername(); - List keys = readKeys(removeKeys); - IKeyManager keyManager = authenticator.getKeyManager(); - if (keys.contains(ALL)) { - keyManager.removeAllKeys(username); - log.info("removed all SSH public keys from {}", username); - } else { - for (String key : keys) { - keyManager.removeKey(username, key); - log.info("removed SSH public key from {}", username); - } - } - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/ReviewCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/ReviewCommand.java deleted file mode 100644 index b088a2e6..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/ReviewCommand.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.transport.ssh.commands; - -import java.util.HashSet; -import java.util.Set; - -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; - -import com.gitblit.models.TicketModel.Change; -import com.gitblit.models.TicketModel.Patchset; -import com.gitblit.models.TicketModel.Score; -import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; -import com.gitblit.wicket.GitBlitWebSession; - -@CommandMetaData(name = "review", description = "Verify, approve and/or submit one or more patch sets", hidden = true) -public class ReviewCommand extends SshCommand { - - private final static short REV_ID_LEN = 40; - private final Set patchSets = new HashSet(); - - @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}", usage = "list of commits or patch sets to review") - void addPatchSetId(final String token) { - try { - patchSets.add(parsePatchSet(token)); - } catch (UnloggedFailure e) { - throw new IllegalArgumentException(e.getMessage(), e); - } - } - - @Option(name = "--project", required = true, aliases = "-p", usage = "project containing the specified patch set(s)") - private String project; - - @Option(name = "--message", aliases = "-m", usage = "cover message to publish on change(s)", metaVar = "MESSAGE") - private String changeComment; - - @Option(name = "--vote", aliases = "-v", usage = "vote on this patch set", metaVar = "VOTE") - private int vote; - - @Option(name = "--submit", aliases = "-s", usage = "submit the specified patch set(s)") - private boolean submitChange; - - @Override - public void run() throws UnloggedFailure { - UserModel user = GitBlitWebSession.get().getUser(); - // TODO ensure user has permission to score +2/-2 - for (Patchset ps : patchSets) { - // review - Change change = new Change(user.username); - change.review(ps, Score.fromScore(vote), false); - // TODO(davido): add patchset comment - if (submitChange) { - // TODO(davido): merge (when desired and the change is mergeable) - } - } - } - - private Patchset parsePatchSet(String ps) throws UnloggedFailure { - // By commit? - // - if (ps.matches("^([0-9a-fA-F]{4," + REV_ID_LEN + "})$")) { - // TODO; parse - } - - // By older style change,patchset? - // - if (ps.matches("^[1-9][0-9]*,[1-9][0-9]*$")) { - // TODO: parse - } - - throw new UnloggedFailure(1, "fatal: Cannot parse patchset: " + ps); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java deleted file mode 100644 index 1f0d902b..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/SetAccountCommand.java +++ /dev/null @@ -1,88 +0,0 @@ -//Copyright (C) 2012 The Android Open Source Project -// -//Licensed under the Apache License, Version 2.0 (the "License"); -//you may not use this file except in compliance with the License. -//You may obtain a copy of the License at -// -//http://www.apache.org/licenses/LICENSE-2.0 -// -//Unless required by applicable law or agreed to in writing, software -//distributed under the License is distributed on an "AS IS" BASIS, -//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -//See the License for the specific language governing permissions and -//limitations under the License. - -package com.gitblit.transport.ssh.commands; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; - -import com.gitblit.transport.ssh.CommandMetaData; -import com.gitblit.transport.ssh.IKeyManager; - -/** Set a user's account settings. **/ -@CommandMetaData(name = "set-account", description = "Change an account's settings", admin = true) -public class SetAccountCommand extends BaseKeyCommand { - - private static final String ALL = "ALL"; - - @Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id") - private String user; - - @Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account") - private List addSshKeys = new ArrayList(); - - @Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account") - private List deleteSshKeys = new ArrayList(); - - @Override - public void run() throws IOException, UnloggedFailure { - validate(); - setAccount(); - } - - private void validate() throws UnloggedFailure { - if (addSshKeys.contains("-") && deleteSshKeys.contains("-")) { - throw new UnloggedFailure(1, "Only one option may use the stdin"); - } - if (deleteSshKeys.contains(ALL)) { - deleteSshKeys = Collections.singletonList(ALL); - } - } - - private void setAccount() throws IOException, UnloggedFailure { - addSshKeys = readKeys(addSshKeys); - if (!addSshKeys.isEmpty()) { - addSshKeys(addSshKeys); - } - - deleteSshKeys = readKeys(deleteSshKeys); - if (!deleteSshKeys.isEmpty()) { - deleteSshKeys(deleteSshKeys); - } - } - - private void addSshKeys(List sshKeys) throws UnloggedFailure, - IOException { - IKeyManager keyManager = authenticator.getKeyManager(); - for (String sshKey : sshKeys) { - keyManager.addKey(user, sshKey); - } - } - - private void deleteSshKeys(List sshKeys) { - IKeyManager keyManager = authenticator.getKeyManager(); - if (sshKeys.contains(ALL)) { - keyManager.removeAllKeys(user); - } else { - for (String sshKey : sshKeys) { - keyManager.removeKey(user, sshKey); - } - } - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/Upload.java b/src/main/java/com/gitblit/transport/ssh/commands/Upload.java deleted file mode 100644 index ac98bb20..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/Upload.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.transport.ssh.commands; - -import org.eclipse.jgit.transport.UploadPack; - -import com.gitblit.transport.ssh.CommandMetaData; - -@CommandMetaData(name = "git-upload-pack", description = "Upload pack") -public class Upload extends BaseGitCommand { - @Override - protected void runImpl() throws Failure { - try { - UploadPack up = uploadPackFactory.create(ctx.getClient(), repo); - up.upload(in, out, null); - } catch (Exception e) { - throw new Failure(1, "fatal: Cannot upload pack: ", e); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/commands/VersionCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/VersionCommand.java deleted file mode 100644 index c2c4f52d..00000000 --- a/src/main/java/com/gitblit/transport/ssh/commands/VersionCommand.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.gitblit.transport.ssh.commands; - -import com.gitblit.Constants; -import com.gitblit.transport.ssh.CommandMetaData; - -@CommandMetaData(name="version", description = "Display the Gitblit version") -public class VersionCommand extends SshCommand { - - @Override - public void run() { - stdout.println(Constants.getGitBlitVersion()); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/git/BaseGitCommand.java b/src/main/java/com/gitblit/transport/ssh/git/BaseGitCommand.java new file mode 100644 index 00000000..b203d476 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/git/BaseGitCommand.java @@ -0,0 +1,104 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.transport.ssh.git; + +import java.io.IOException; + +import org.apache.sshd.server.Environment; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.resolver.ReceivePackFactory; +import org.eclipse.jgit.transport.resolver.UploadPackFactory; +import org.kohsuke.args4j.Argument; + +import com.gitblit.git.GitblitReceivePackFactory; +import com.gitblit.git.GitblitUploadPackFactory; +import com.gitblit.git.RepositoryResolver; +import com.gitblit.transport.ssh.SshDaemonClient; +import com.gitblit.transport.ssh.commands.BaseCommand; + +/** + * @author Eric Myhre + * + */ +abstract class BaseGitCommand extends BaseCommand { + @Argument(index = 0, metaVar = "REPOSITORY", required = true, usage = "repository name") + protected String repository; + + protected RepositoryResolver repositoryResolver; + protected ReceivePackFactory receivePackFactory; + protected UploadPackFactory uploadPackFactory; + + protected Repository repo; + + @Override + public void start(final Environment env) { + startThread(new RepositoryCommandRunnable() { + @Override + public void run() throws Exception { + parseCommandLine(); + BaseGitCommand.this.service(); + } + + @Override + public String getRepository() { + return repository; + } + }); + } + + private void service() throws IOException, Failure { + try { + repo = openRepository(); + runImpl(); + } finally { + if (repo != null) { + repo.close(); + } + } + } + + protected abstract void runImpl() throws IOException, Failure; + + protected Repository openRepository() throws Failure { + // Assume any attempt to use \ was by a Windows client + // and correct to the more typical / used in Git URIs. + // + repository = repository.replace('\\', '/'); + // ssh://git@thishost/path should always be name="/path" here + // + if (!repository.startsWith("/")) { + throw new Failure(1, "fatal: '" + repository + "': not starts with / character"); + } + repository = repository.substring(1); + try { + return repositoryResolver.open(ctx.getClient(), repository); + } catch (Exception e) { + throw new Failure(1, "fatal: '" + repository + "': not a git archive", e); + } + } + + public void setRepositoryResolver(RepositoryResolver repositoryResolver) { + this.repositoryResolver = repositoryResolver; + } + + public void setReceivePackFactory(GitblitReceivePackFactory receivePackFactory) { + this.receivePackFactory = receivePackFactory; + } + + public void setUploadPackFactory(GitblitUploadPackFactory uploadPackFactory) { + this.uploadPackFactory = uploadPackFactory; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java new file mode 100644 index 00000000..adeace52 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.transport.ssh.git; + +import com.gitblit.git.GitblitReceivePackFactory; +import com.gitblit.git.GitblitUploadPackFactory; +import com.gitblit.git.RepositoryResolver; +import com.gitblit.manager.IGitblit; +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.SshCommandContext; +import com.gitblit.transport.ssh.SshDaemonClient; +import com.gitblit.transport.ssh.commands.BaseCommand; +import com.gitblit.transport.ssh.commands.DispatchCommand; + +@CommandMetaData(name = "git", description="Dispatcher for git receive and upload commands", hidden = true) +public class GitDispatchCommand extends DispatchCommand { + + protected RepositoryResolver repositoryResolver; + protected GitblitUploadPackFactory uploadPackFactory; + protected GitblitReceivePackFactory receivePackFactory; + + @Override + public void setContext(SshCommandContext context) { + super.setContext(context); + + IGitblit gitblit = context.getGitblit(); + repositoryResolver = new RepositoryResolver(gitblit); + uploadPackFactory = new GitblitUploadPackFactory(gitblit); + receivePackFactory = new GitblitReceivePackFactory(gitblit); + } + + @Override + protected void registerCommands(UserModel user) { + registerCommand(user, Upload.class); + registerCommand(user, Receive.class); + } + + @Override + protected void provideStateTo(final BaseCommand cmd) { + super.provideStateTo(cmd); + + BaseGitCommand a = (BaseGitCommand) cmd; + a.setRepositoryResolver(repositoryResolver); + a.setUploadPackFactory(uploadPackFactory); + a.setReceivePackFactory(receivePackFactory); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/git/Receive.java b/src/main/java/com/gitblit/transport/ssh/git/Receive.java new file mode 100644 index 00000000..4089f1df --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/git/Receive.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.transport.ssh.git; + +import org.eclipse.jgit.transport.ReceivePack; + +import com.gitblit.transport.ssh.CommandMetaData; + +@CommandMetaData(name = "git-receive-pack", description = "Receives pushes from a client") +public class Receive extends BaseGitCommand { + @Override + protected void runImpl() throws Failure { + try { + ReceivePack rp = receivePackFactory.create(ctx.getClient(), repo); + rp.receive(in, out, null); + } catch (Exception e) { + throw new Failure(1, "fatal: Cannot receive pack: ", e); + } + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/git/Upload.java b/src/main/java/com/gitblit/transport/ssh/git/Upload.java new file mode 100644 index 00000000..5793c3e6 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/git/Upload.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.transport.ssh.git; + +import org.eclipse.jgit.transport.UploadPack; + +import com.gitblit.transport.ssh.CommandMetaData; + +@CommandMetaData(name = "git-upload-pack", description = "Sends packs to a client for clone and fetch") +public class Upload extends BaseGitCommand { + @Override + protected void runImpl() throws Failure { + try { + UploadPack up = uploadPackFactory.create(ctx.getClient(), repo); + up.upload(in, out, null); + } catch (Exception e) { + throw new Failure(1, "fatal: Cannot upload pack: ", e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java new file mode 100644 index 00000000..6d5c85c7 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.gitblit.transport.ssh.gitblit; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.kohsuke.args4j.Argument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.transport.ssh.CommandMetaData; + +/** + * Add a key to the current user's authorized keys list. + * + * @author James Moger + * + */ +@CommandMetaData(name = "add-key", description = "Add an SSH public key to your account") +public class AddKeyCommand extends BaseKeyCommand { + + protected final Logger log = LoggerFactory.getLogger(getClass()); + + @Argument(metaVar = "|KEY", usage = "the key to add") + private List addKeys = new ArrayList(); + + @Override + public void run() throws IOException, UnloggedFailure { + String username = ctx.getClient().getUsername(); + List keys = readKeys(addKeys); + for (String key : keys) { + getKeyManager().addKey(username, key); + log.info("added SSH public key for {}", username); + } + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java new file mode 100644 index 00000000..09099578 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.gitblit.transport.ssh.gitblit; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import com.gitblit.transport.ssh.IKeyManager; +import com.gitblit.transport.ssh.CachingPublicKeyAuthenticator; +import com.gitblit.transport.ssh.commands.SshCommand; +import com.google.common.base.Charsets; + +/** + * + * Base class for commands that read SSH keys from stdin or a parameter list. + * + */ +abstract class BaseKeyCommand extends SshCommand { + + protected List readKeys(List sshKeys) + throws UnsupportedEncodingException, IOException { + int idx = -1; + if (sshKeys.isEmpty() || ((idx = sshKeys.indexOf("-")) >= 0)) { + String sshKey = ""; + BufferedReader br = new BufferedReader(new InputStreamReader( + in, Charsets.UTF_8)); + String line; + while ((line = br.readLine()) != null) { + sshKey += line + "\n"; + } + if (idx == -1) { + sshKeys.add(sshKey.trim()); + } else { + sshKeys.set(idx, sshKey.trim()); + } + } + return sshKeys; + } + + protected CachingPublicKeyAuthenticator authenticator; + public void setAuthenticator(CachingPublicKeyAuthenticator authenticator) { + this.authenticator = authenticator; + } + + protected IKeyManager getKeyManager() { + return authenticator.getKeyManager(); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java b/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java new file mode 100644 index 00000000..b2e1b1b0 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gitblit.transport.ssh.gitblit; + +import org.kohsuke.args4j.Option; + +import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.SshCommand; + +@CommandMetaData(name = "create-repository", description = "Create new GIT repository", admin = true, hidden = true) +public class CreateRepository extends SshCommand { + + @Option(name = "--name", aliases = {"-n"}, required = true, metaVar = "NAME", usage = "name of repository to be created") + private String name; + + @Option(name = "--description", aliases = {"-d"}, metaVar = "DESCRIPTION", usage = "description of repository") + private String repositoryDescription; + + @Override + public void run() { + stdout.println(String.format("Repository <%s> was created", name)); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java new file mode 100644 index 00000000..544b204f --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.transport.ssh.gitblit; + +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.DispatchCommand; + +@CommandMetaData(name = "gitblit", description = "Gitblit server commands") +public class GitblitDispatchCommand extends DispatchCommand { + + @Override + protected void registerCommands(UserModel user) { + // normal usage commands + registerCommand(user, VersionCommand.class); + registerCommand(user, AddKeyCommand.class); + registerCommand(user, RemoveKeyCommand.class); + registerCommand(user, LsCommand.class); + registerCommand(user, ReviewCommand.class); + + // administrative commands + registerCommand(user, CreateRepository.class); + registerCommand(user, SetAccountCommand.class); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java new file mode 100644 index 00000000..cf50a2ee --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gitblit.transport.ssh.gitblit; + +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.List; + +import org.kohsuke.args4j.Option; +import org.parboiled.common.StringUtils; + +import com.gitblit.manager.IGitblit; +import com.gitblit.models.ProjectModel; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.SshCommand; + +@CommandMetaData(name = "ls", description = "List repositories or projects") +public class LsCommand extends SshCommand { + + @Option(name = "--projects", aliases = { "-p" }, usage = "list projects") + private boolean projects; + + @Option(name = "--verbose", aliases = { "-v" }, usage = "verbose") + private boolean verbose; + + @Override + public void run() { + if (projects) { + listProjects(); + } else { + listRepositories(); + } + } + + protected void listProjects() { + IGitblit gitblit = ctx.getGitblit(); + UserModel user = ctx.getClient().getUser(); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + + List projects = gitblit.getProjectModels(user, false); + int nameLen = 0; + int descLen = 0; + for (ProjectModel project : projects) { + int len = project.name.length(); + if (len > nameLen) { + nameLen = len; + } + if (!StringUtils.isEmpty(project.description)) { + len = project.description.length(); + if (len > descLen) { + descLen = len; + } + } + } + + String pattern; + if (verbose) { + pattern = MessageFormat.format("%-{0,number,0}s\t%-{1,number,0}s\t%s", nameLen, descLen); + } else { + pattern = "%s"; + } + + for (ProjectModel project : projects) { + stdout.println(String.format(pattern, + project.name, + project.description == null ? "" : project.description, + df.format(project.lastChange))); + } + } + + protected void listRepositories() { + IGitblit gitblit = ctx.getGitblit(); + UserModel user = ctx.getClient().getUser(); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + + List repositories = gitblit.getRepositoryModels(user); + int nameLen = 0; + int descLen = 0; + for (RepositoryModel repo : repositories) { + int len = repo.name.length(); + if (len > nameLen) { + nameLen = len; + } + if (!StringUtils.isEmpty(repo.description)) { + len = repo.description.length(); + if (len > descLen) { + descLen = len; + } + } + } + + String pattern; + if (verbose) { + pattern = MessageFormat.format("%-{0,number,0}s\t%-{1,number,0}s\t%s", nameLen, descLen); + } else { + pattern = "%s"; + } + + for (RepositoryModel repo : repositories) { + stdout.println(String.format(pattern, + repo.name, + repo.description == null ? "" : repo.description, + df.format(repo.lastChange))); + } + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java new file mode 100644 index 00000000..7c9abfd4 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.gitblit.transport.ssh.gitblit; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.kohsuke.args4j.Argument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.transport.ssh.CommandMetaData; + + +/** + * Remove an SSH public key from the current user's authorized key list. + * + * @author James Moger + * + */ +@CommandMetaData(name = "rm-key", description = "Remove an SSH public key from your account") +public class RemoveKeyCommand extends BaseKeyCommand { + + protected final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String ALL = "ALL"; + + @Argument(metaVar = "||ALL", usage = "the key to remove") + private List removeKeys = new ArrayList(); + + @Override + public void run() throws IOException, UnloggedFailure { + String username = ctx.getClient().getUsername(); + List keys = readKeys(removeKeys); + if (keys.contains(ALL)) { + getKeyManager().removeAllKeys(username); + log.info("removed all SSH public keys from {}", username); + } else { + for (String key : keys) { + getKeyManager().removeKey(username, key); + log.info("removed SSH public key from {}", username); + } + } + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java new file mode 100644 index 00000000..9e4d8ba7 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java @@ -0,0 +1,89 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.transport.ssh.gitblit; + +import java.util.HashSet; +import java.util.Set; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +import com.gitblit.models.TicketModel.Change; +import com.gitblit.models.TicketModel.Patchset; +import com.gitblit.models.TicketModel.Score; +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.SshCommand; +import com.gitblit.wicket.GitBlitWebSession; + +@CommandMetaData(name = "review", description = "Verify, approve and/or submit one or more patch sets", hidden = true) +public class ReviewCommand extends SshCommand { + + private final static short REV_ID_LEN = 40; + private final Set patchSets = new HashSet(); + + @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}", usage = "list of commits or patch sets to review") + void addPatchSetId(final String token) { + try { + patchSets.add(parsePatchSet(token)); + } catch (UnloggedFailure e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + @Option(name = "--project", required = true, aliases = "-p", usage = "project containing the specified patch set(s)") + private String project; + + @Option(name = "--message", aliases = "-m", usage = "cover message to publish on change(s)", metaVar = "MESSAGE") + private String changeComment; + + @Option(name = "--vote", aliases = "-v", usage = "vote on this patch set", metaVar = "VOTE") + private int vote; + + @Option(name = "--submit", aliases = "-s", usage = "submit the specified patch set(s)") + private boolean submitChange; + + @Override + public void run() throws UnloggedFailure { + UserModel user = GitBlitWebSession.get().getUser(); + // TODO ensure user has permission to score +2/-2 + for (Patchset ps : patchSets) { + // review + Change change = new Change(user.username); + change.review(ps, Score.fromScore(vote), false); + // TODO(davido): add patchset comment + if (submitChange) { + // TODO(davido): merge (when desired and the change is mergeable) + } + } + } + + private Patchset parsePatchSet(String ps) throws UnloggedFailure { + // By commit? + // + if (ps.matches("^([0-9a-fA-F]{4," + REV_ID_LEN + "})$")) { + // TODO; parse + } + + // By older style change,patchset? + // + if (ps.matches("^[1-9][0-9]*,[1-9][0-9]*$")) { + // TODO: parse + } + + throw new UnloggedFailure(1, "fatal: Cannot parse patchset: " + ps); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java new file mode 100644 index 00000000..28ac9e19 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java @@ -0,0 +1,85 @@ +//Copyright (C) 2012 The Android Open Source Project +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + +package com.gitblit.transport.ssh.gitblit; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +import com.gitblit.transport.ssh.CommandMetaData; + +/** Set a user's account settings. **/ +@CommandMetaData(name = "set-account", description = "Change an account's settings", admin = true) +public class SetAccountCommand extends BaseKeyCommand { + + private static final String ALL = "ALL"; + + @Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id") + private String user; + + @Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account") + private List addSshKeys = new ArrayList(); + + @Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account") + private List deleteSshKeys = new ArrayList(); + + @Override + public void run() throws IOException, UnloggedFailure { + validate(); + setAccount(); + } + + private void validate() throws UnloggedFailure { + if (addSshKeys.contains("-") && deleteSshKeys.contains("-")) { + throw new UnloggedFailure(1, "Only one option may use the stdin"); + } + if (deleteSshKeys.contains(ALL)) { + deleteSshKeys = Collections.singletonList(ALL); + } + } + + private void setAccount() throws IOException, UnloggedFailure { + addSshKeys = readKeys(addSshKeys); + if (!addSshKeys.isEmpty()) { + addSshKeys(addSshKeys); + } + + deleteSshKeys = readKeys(deleteSshKeys); + if (!deleteSshKeys.isEmpty()) { + deleteSshKeys(deleteSshKeys); + } + } + + private void addSshKeys(List sshKeys) throws UnloggedFailure, + IOException { + for (String sshKey : sshKeys) { + getKeyManager().addKey(user, sshKey); + } + } + + private void deleteSshKeys(List sshKeys) { + if (sshKeys.contains(ALL)) { + getKeyManager().removeAllKeys(user); + } else { + for (String sshKey : sshKeys) { + getKeyManager().removeKey(user, sshKey); + } + } + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java new file mode 100644 index 00000000..513f6d96 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gitblit.transport.ssh.gitblit; + +import com.gitblit.Constants; +import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.SshCommand; + +@CommandMetaData(name="version", description = "Display the Gitblit version") +public class VersionCommand extends SshCommand { + + @Override + public void run() { + stdout.println(Constants.getGitBlitVersion()); + } +} -- cgit v1.2.3