From 85c2e6eb34215e2242e388a8f8b7173a14b96ad3 Mon Sep 17 00:00:00 2001 From: James Moger Date: Sat, 25 Jun 2011 08:57:29 -0400 Subject: Big push for first release. * Build script overhaul including building & publishing GO, WAR, Docs, and Site. * Restored JGit 0.12.1 dependency and backported Blame. Got tired of waiting for JGit 1.0.0 Maven artifacts. * Changed Summary Page layout * Optional cookie authentication * Added icons for log, tags, and branches panels. * Show last commit author and short message on branches panel. * Unit testing. * Documentation. --- src/com/gitblit/Build.java | 21 +- src/com/gitblit/BuildThumbnails.java | 134 +++++++ src/com/gitblit/BuildWebXml.java | 40 ++- src/com/gitblit/Constants.java | 4 +- src/com/gitblit/FileLoginService.java | 372 -------------------- src/com/gitblit/FileSettings.java | 6 +- src/com/gitblit/FileUserService.java | 423 +++++++++++++++++++++++ src/com/gitblit/GitBlit.java | 82 +++-- src/com/gitblit/GitBlitServer.java | 18 +- src/com/gitblit/ILoginService.java | 47 --- src/com/gitblit/IStoredSettings.java | 6 +- src/com/gitblit/IUserService.java | 53 +++ src/com/gitblit/SyndicationServlet.java | 2 +- src/com/gitblit/Thumbnailer.java | 134 ------- src/com/gitblit/WebXmlSettings.java | 12 +- src/com/gitblit/models/UserModel.java | 2 +- src/com/gitblit/utils/JGitUtils.java | 15 +- src/com/gitblit/utils/StringUtils.java | 7 +- src/com/gitblit/wicket/pages/BasePage.java | 46 ++- src/com/gitblit/wicket/pages/CommitPage.java | 4 +- src/com/gitblit/wicket/pages/DocsPage.java | 4 +- src/com/gitblit/wicket/pages/EditUserPage.java | 3 +- src/com/gitblit/wicket/pages/LogPage.java | 2 +- src/com/gitblit/wicket/pages/LoginPage.java | 31 +- src/com/gitblit/wicket/pages/LogoutPage.java | 7 +- src/com/gitblit/wicket/pages/RepositoryPage.java | 9 +- src/com/gitblit/wicket/pages/SummaryPage.html | 12 +- src/com/gitblit/wicket/pages/SummaryPage.java | 17 +- src/com/gitblit/wicket/panels/BranchesPanel.html | 5 +- src/com/gitblit/wicket/panels/BranchesPanel.java | 32 +- src/com/gitblit/wicket/panels/LogPanel.html | 3 +- src/com/gitblit/wicket/panels/SearchPanel.java | 2 +- src/com/gitblit/wicket/panels/TagsPanel.html | 2 +- src/com/gitblit/wicket/panels/TagsPanel.java | 11 +- 34 files changed, 901 insertions(+), 667 deletions(-) create mode 100644 src/com/gitblit/BuildThumbnails.java delete mode 100644 src/com/gitblit/FileLoginService.java create mode 100644 src/com/gitblit/FileUserService.java delete mode 100644 src/com/gitblit/ILoginService.java create mode 100644 src/com/gitblit/IUserService.java delete mode 100644 src/com/gitblit/Thumbnailer.java (limited to 'src/com/gitblit') diff --git a/src/com/gitblit/Build.java b/src/com/gitblit/Build.java index 90224f08..b6c485a3 100644 --- a/src/com/gitblit/Build.java +++ b/src/com/gitblit/Build.java @@ -86,10 +86,10 @@ public class Build { downloadFromApache(MavenObject.JSCH, BuildType.COMPILETIME); downloadFromApache(MavenObject.ROME, BuildType.COMPILETIME); downloadFromApache(MavenObject.JDOM, BuildType.COMPILETIME); - + downloadFromEclipse(MavenObject.JGIT, BuildType.COMPILETIME); downloadFromEclipse(MavenObject.JGIT_HTTP, BuildType.COMPILETIME); - + // needed for site publishing downloadFromApache(MavenObject.COMMONSNET, BuildType.RUNTIME); } @@ -401,18 +401,17 @@ public class Build { "e528f593b19b04d500992606f58b87fcfded8883", "d0ffadd0a4ab909d94a577b5aad43c13b617ddcb"); - public static final MavenObject COMMONSNET = new MavenObject("commons-net", "commons-net", "commons-net", - "1.4.0", 181000, 0, 0, "eb47e8cad2dd7f92fd7e77df1d1529cae87361f7", - "", - ""); - - public static final MavenObject ROME = new MavenObject("rome", "rome", "rome", - "0.9", 208000, 196000, 407000, "dee2705dd01e79a5a96a17225f5a1ae30470bb18", + public static final MavenObject COMMONSNET = new MavenObject("commons-net", "commons-net", + "commons-net", "1.4.0", 181000, 0, 0, "eb47e8cad2dd7f92fd7e77df1d1529cae87361f7", + "", ""); + + public static final MavenObject ROME = new MavenObject("rome", "rome", "rome", "0.9", + 208000, 196000, 407000, "dee2705dd01e79a5a96a17225f5a1ae30470bb18", "226f851dc44fd94fe70b9c471881b71f88949cbf", "8d7d867b97eeb3a9196c3926da550ad042941c1b"); - public static final MavenObject JDOM = new MavenObject("jdom", "org/jdom", "jdom", - "1.1", 153000, 235000, 445000, "1d04c0f321ea337f3661cf7ede8f4c6f653a8fdd", + public static final MavenObject JDOM = new MavenObject("jdom", "org/jdom", "jdom", "1.1", + 153000, 235000, 445000, "1d04c0f321ea337f3661cf7ede8f4c6f653a8fdd", "a7ed425c4c46605b8f2bf2ee118c1609682f4f2c", "f3df91edccba2f07a0fced70887c2f7b7836cb75"); diff --git a/src/com/gitblit/BuildThumbnails.java b/src/com/gitblit/BuildThumbnails.java new file mode 100644 index 00000000..4f2b2ab8 --- /dev/null +++ b/src/com/gitblit/BuildThumbnails.java @@ -0,0 +1,134 @@ +/* + * Copyright 2011 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; + +import java.awt.Dimension; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.Iterator; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParameterException; +import com.beust.jcommander.Parameters; + +public class BuildThumbnails { + + public static void main(String[] args) { + Params params = new Params(); + JCommander jc = new JCommander(params); + try { + jc.parse(args); + } catch (ParameterException t) { + System.err.println(t.getMessage()); + jc.usage(); + } + createImageThumbnail(params.sourceFolder, params.destinationFolder, params.maximumDimension); + } + + public static void createImageThumbnail(String sourceFolder, String destinationFolder, + int maxDimension) { + if (maxDimension <= 0) + return; + File source = new File(sourceFolder); + File destination = new File(destinationFolder); + destination.mkdirs(); + File[] sourceFiles = source.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.toLowerCase().endsWith(".png"); + } + }); + + for (File sourceFile : sourceFiles) { + File destinationFile = new File(destination, sourceFile.getName()); + try { + Dimension sz = getImageDimensions(sourceFile); + int w = 0; + int h = 0; + if (sz.width > maxDimension) { + // Scale to Width + w = maxDimension; + float f = maxDimension; + h = (int) ((f / sz.width) * sz.height); // normalize height + } else if (sz.height > maxDimension) { + // Scale to Height + h = maxDimension; + float f = maxDimension; + w = (int) ((f / sz.height) * sz.width); // normalize width + } else { + // No thumbnail + return; + } + System.out.println("Generating thumbnail for " + sourceFile.getName() + " as (" + w + + "," + h + ")"); + BufferedImage image = ImageIO.read(sourceFile); + Image scaledImage = image.getScaledInstance(w, h, BufferedImage.SCALE_SMOOTH); + BufferedImage destImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + destImage.createGraphics().drawImage(scaledImage, 0, 0, null); + FileOutputStream fos = new FileOutputStream(destinationFile); + ImageIO.write(destImage, "png", fos); + fos.flush(); + fos.getFD().sync(); + fos.close(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + public static Dimension getImageDimensions(File file) throws IOException { + ImageInputStream in = ImageIO.createImageInputStream(file); + try { + final Iterator readers = ImageIO.getImageReaders(in); + if (readers.hasNext()) { + ImageReader reader = readers.next(); + try { + reader.setInput(in); + return new Dimension(reader.getWidth(0), reader.getHeight(0)); + } finally { + reader.dispose(); + } + } + } finally { + if (in != null) + in.close(); + } + return null; + } + + @Parameters(separators = " ") + private static class Params { + + @Parameter(names = { "--sourceFolder" }, description = "Source folder for raw images", required = true) + public String sourceFolder; + + @Parameter(names = { "--destinationFolder" }, description = "Destination folder for thumbnails", required = true) + public String destinationFolder; + + @Parameter(names = { "--maximumDimension" }, description = "Maximum width or height for thumbnail", required = true) + public int maximumDimension; + + } +} diff --git a/src/com/gitblit/BuildWebXml.java b/src/com/gitblit/BuildWebXml.java index 557c6a85..8e957df5 100644 --- a/src/com/gitblit/BuildWebXml.java +++ b/src/com/gitblit/BuildWebXml.java @@ -24,6 +24,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Vector; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParameterException; +import com.beust.jcommander.Parameters; +import com.gitblit.utils.StringUtils; + public class BuildWebXml { private static final String PARAMS = ""; @@ -34,9 +40,21 @@ public class BuildWebXml { private static final String PARAM_PATTERN = "\n\t\n\t\t{0}\n\t\t{1}\n\t\n"; public static void main(String[] args) throws Exception { + Params params = new Params(); + JCommander jc = new JCommander(params); + try { + jc.parse(args); + } catch (ParameterException t) { + System.err.println(t.getMessage()); + jc.usage(); + } + generateWebXml(params); + } + + private static void generateWebXml(Params params) throws Exception { // Read the current Gitblit properties BufferedReader propertiesReader = new BufferedReader(new FileReader(new File( - "distrib/gitblit.properties"))); + params.propertiesFile))); Vector settings = new Vector(); List comments = new ArrayList(); @@ -68,11 +86,11 @@ public class BuildWebXml { for (String comment : setting.comments) { parameters.append(MessageFormat.format(COMMENT_PATTERN, comment)); } - parameters.append(MessageFormat.format(PARAM_PATTERN, setting.name, setting.value)); + parameters.append(MessageFormat.format(PARAM_PATTERN, setting.name, StringUtils.escapeForHtml(setting.value, false))); } // Read the prototype web.xml file - File webxml = new File("src/WEB-INF/web.xml"); + File webxml = new File(params.sourceFile); char[] buffer = new char[(int) webxml.length()]; FileReader webxmlReader = new FileReader(webxml); webxmlReader.read(buffer); @@ -90,7 +108,7 @@ public class BuildWebXml { sb.append(webXmlContent.substring(idx + PARAMS.length())); // Save the merged web.xml to the war build folder - FileOutputStream os = new FileOutputStream(new File("war/WEB-INF/web.xml"), false); + FileOutputStream os = new FileOutputStream(new File(params.destinationFile), false); os.write(sb.toString().getBytes()); os.close(); } @@ -110,4 +128,18 @@ public class BuildWebXml { this.comments = new ArrayList(comments); } } + + @Parameters(separators = " ") + private static class Params { + + @Parameter(names = { "--sourceFile" }, description = "Source web.xml file", required = true) + public String sourceFile; + + @Parameter(names = { "--propertiesFile" }, description = "Properties settings file", required = true) + public String propertiesFile; + + @Parameter(names = { "--destinationFile" }, description = "Destination web.xml file", required = true) + public String destinationFile; + + } } diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java index b874a7b0..d410d35f 100644 --- a/src/com/gitblit/Constants.java +++ b/src/com/gitblit/Constants.java @@ -36,9 +36,9 @@ public class Constants { public static final String GIT_PATH = "/git/"; public static final String ZIP_PATH = "/zip/"; - + public static final String SYNDICATION_PATH = "/feed/"; - + public static final String BORDER = "***********************************************************"; public static enum AccessRestrictionType { diff --git a/src/com/gitblit/FileLoginService.java b/src/com/gitblit/FileLoginService.java deleted file mode 100644 index e239efc4..00000000 --- a/src/com/gitblit/FileLoginService.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2011 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; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.gitblit.models.UserModel; -import com.gitblit.utils.StringUtils; - -public class FileLoginService extends FileSettings implements ILoginService { - - private final Logger logger = LoggerFactory.getLogger(FileLoginService.class); - - public FileLoginService(File realmFile) { - super(realmFile.getAbsolutePath()); - } - - @Override - public UserModel authenticate(String username, char[] password) { - Properties allUsers = read(); - String userInfo = allUsers.getProperty(username); - if (StringUtils.isEmpty(userInfo)) { - return null; - } - UserModel returnedUser = null; - UserModel user = getUserModel(username); - if (user.password.startsWith(StringUtils.MD5_TYPE)) { - String md5 = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(password)); - if (user.password.equalsIgnoreCase(md5)) { - returnedUser = user; - } - } else if (user.password.equals(new String(password))) { - returnedUser = user; - } - return returnedUser; - } - - @Override - public UserModel getUserModel(String username) { - Properties allUsers = read(); - String userInfo = allUsers.getProperty(username); - if (userInfo == null) { - return null; - } - UserModel model = new UserModel(username); - String[] userValues = userInfo.split(","); - model.password = userValues[0]; - for (int i = 1; i < userValues.length; i++) { - String role = userValues[i]; - switch (role.charAt(0)) { - case '#': - // Permissions - if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) { - model.canAdmin = true; - } - break; - default: - model.addRepository(role); - } - } - return model; - } - - @Override - public boolean updateUserModel(UserModel model) { - return updateUserModel(model.username, model); - } - - @Override - public boolean updateUserModel(String username, UserModel model) { - try { - Properties allUsers = read(); - ArrayList roles = new ArrayList(model.repositories); - - // Permissions - if (model.canAdmin) { - roles.add(Constants.ADMIN_ROLE); - } - - StringBuilder sb = new StringBuilder(); - sb.append(model.password); - sb.append(','); - for (String role : roles) { - sb.append(role); - sb.append(','); - } - // trim trailing comma - sb.setLength(sb.length() - 1); - allUsers.remove(username); - allUsers.put(model.username, sb.toString()); - - write(allUsers); - return true; - } catch (Throwable t) { - logger.error(MessageFormat.format("Failed to update user model {0}!", model.username), - t); - } - return false; - } - - @Override - public boolean deleteUserModel(UserModel model) { - return deleteUser(model.username); - } - - @Override - public boolean deleteUser(String username) { - try { - // Read realm file - Properties allUsers = read(); - allUsers.remove(username); - write(allUsers); - return true; - } catch (Throwable t) { - logger.error(MessageFormat.format("Failed to delete user {0}!", username), t); - } - return false; - } - - @Override - public List getAllUsernames() { - Properties allUsers = read(); - List list = new ArrayList(allUsers.stringPropertyNames()); - return list; - } - - @Override - public List getUsernamesForRole(String role) { - List list = new ArrayList(); - try { - Properties allUsers = read(); - for (String username : allUsers.stringPropertyNames()) { - String value = allUsers.getProperty(username); - String[] values = value.split(","); - // skip first value (password) - for (int i = 1; i < values.length; i++) { - String r = values[i]; - if (r.equalsIgnoreCase(role)) { - list.add(username); - break; - } - } - } - } catch (Throwable t) { - logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t); - } - return list; - } - - @Override - public boolean setUsernamesForRole(String role, List usernames) { - try { - Set specifiedUsers = new HashSet(usernames); - Set needsAddRole = new HashSet(specifiedUsers); - Set needsRemoveRole = new HashSet(); - - // identify users which require add and remove role - Properties allUsers = read(); - for (String username : allUsers.stringPropertyNames()) { - String value = allUsers.getProperty(username); - String[] values = value.split(","); - // skip first value (password) - for (int i = 1; i < values.length; i++) { - String r = values[i]; - if (r.equalsIgnoreCase(role)) { - // user has role, check against revised user list - if (specifiedUsers.contains(username)) { - needsAddRole.remove(username); - } else { - // remove role from user - needsRemoveRole.add(username); - } - break; - } - } - } - - // add roles to users - for (String user : needsAddRole) { - String userValues = allUsers.getProperty(user); - userValues += "," + role; - allUsers.put(user, userValues); - } - - // remove role from user - for (String user : needsRemoveRole) { - String[] values = allUsers.getProperty(user).split(","); - String password = values[0]; - StringBuilder sb = new StringBuilder(); - sb.append(password); - sb.append(','); - List revisedRoles = new ArrayList(); - // skip first value (password) - for (int i = 1; i < values.length; i++) { - String value = values[i]; - if (!value.equalsIgnoreCase(role)) { - revisedRoles.add(value); - sb.append(value); - sb.append(','); - } - } - sb.setLength(sb.length() - 1); - - // update properties - allUsers.put(user, sb.toString()); - } - - // persist changes - write(allUsers); - return true; - } catch (Throwable t) { - logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t); - } - return false; - } - - @Override - public boolean renameRole(String oldRole, String newRole) { - try { - Properties allUsers = read(); - Set needsRenameRole = new HashSet(); - - // identify users which require role rename - for (String username : allUsers.stringPropertyNames()) { - String value = allUsers.getProperty(username); - String[] roles = value.split(","); - // skip first value (password) - for (int i = 1; i < roles.length; i++) { - String r = roles[i]; - if (r.equalsIgnoreCase(oldRole)) { - needsRenameRole.remove(username); - break; - } - } - } - - // rename role for identified users - for (String user : needsRenameRole) { - String userValues = allUsers.getProperty(user); - String[] values = userValues.split(","); - String password = values[0]; - StringBuilder sb = new StringBuilder(); - sb.append(password); - sb.append(','); - List revisedRoles = new ArrayList(); - revisedRoles.add(newRole); - // skip first value (password) - for (int i = 1; i < values.length; i++) { - String value = values[i]; - if (!value.equalsIgnoreCase(oldRole)) { - revisedRoles.add(value); - sb.append(value); - sb.append(','); - } - } - sb.setLength(sb.length() - 1); - - // update properties - allUsers.put(user, sb.toString()); - } - - // persist changes - write(allUsers); - return true; - } catch (Throwable t) { - logger.error( - MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t); - } - return false; - } - - @Override - public boolean deleteRole(String role) { - try { - Properties allUsers = read(); - Set needsDeleteRole = new HashSet(); - - // identify users which require role rename - for (String username : allUsers.stringPropertyNames()) { - String value = allUsers.getProperty(username); - String[] roles = value.split(","); - // skip first value (password) - for (int i = 1; i < roles.length; i++) { - String r = roles[i]; - if (r.equalsIgnoreCase(role)) { - needsDeleteRole.remove(username); - break; - } - } - } - - // delete role for identified users - for (String user : needsDeleteRole) { - String userValues = allUsers.getProperty(user); - String[] values = userValues.split(","); - String password = values[0]; - StringBuilder sb = new StringBuilder(); - sb.append(password); - sb.append(','); - List revisedRoles = new ArrayList(); - // skip first value (password) - for (int i = 1; i < values.length; i++) { - String value = values[i]; - if (!value.equalsIgnoreCase(role)) { - revisedRoles.add(value); - sb.append(value); - sb.append(','); - } - } - sb.setLength(sb.length() - 1); - - // update properties - allUsers.put(user, sb.toString()); - } - - // persist changes - write(allUsers); - return true; - } catch (Throwable t) { - logger.error(MessageFormat.format("Failed to delete role {0}!", role), t); - } - return false; - } - - private void write(Properties properties) throws IOException { - // Update realm file - File realmFileCopy = new File(propertiesFile.getAbsolutePath() + ".tmp"); - FileWriter writer = new FileWriter(realmFileCopy); - properties - .store(writer, - "# Gitblit realm file format: username=password,\\#permission,repository1,repository2..."); - writer.close(); - if (realmFileCopy.exists() && realmFileCopy.length() > 0) { - if (propertiesFile.delete()) { - if (!realmFileCopy.renameTo(propertiesFile)) { - throw new IOException(MessageFormat.format("Failed to rename {0} to {1}!", - realmFileCopy.getAbsolutePath(), propertiesFile.getAbsolutePath())); - } - } else { - throw new IOException(MessageFormat.format("Failed to delete (0)!", - propertiesFile.getAbsolutePath())); - } - } else { - throw new IOException(MessageFormat.format("Failed to save {0}!", - realmFileCopy.getAbsolutePath())); - } - } -} diff --git a/src/com/gitblit/FileSettings.java b/src/com/gitblit/FileSettings.java index e213e80f..1e654222 100644 --- a/src/com/gitblit/FileSettings.java +++ b/src/com/gitblit/FileSettings.java @@ -45,7 +45,7 @@ public class FileSettings extends IStoredSettings { Properties props = new Properties(); is = new FileInputStream(propertiesFile); props.load(is); - + // load properties after we have successfully read file properties.clear(); properties.putAll(props); @@ -67,6 +67,10 @@ public class FileSettings extends IStoredSettings { return properties; } + protected long lastRead() { + return lastread; + } + @Override public String toString() { return propertiesFile.getAbsolutePath(); diff --git a/src/com/gitblit/FileUserService.java b/src/com/gitblit/FileUserService.java new file mode 100644 index 00000000..01a50be1 --- /dev/null +++ b/src/com/gitblit/FileUserService.java @@ -0,0 +1,423 @@ +/* + * Copyright 2011 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; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.models.UserModel; +import com.gitblit.utils.StringUtils; + +public class FileUserService extends FileSettings implements IUserService { + + private final Logger logger = LoggerFactory.getLogger(FileUserService.class); + + private final Map cookies = new ConcurrentHashMap(); + + public FileUserService(File realmFile) { + super(realmFile.getAbsolutePath()); + } + + @Override + public boolean supportsCookies() { + return true; + } + + @Override + public char[] getCookie(UserModel model) { + Properties allUsers = super.read(); + String value = allUsers.getProperty(model.username); + String[] roles = value.split(","); + String password = roles[0]; + String cookie = StringUtils.getSHA1(model.username + password); + return cookie.toCharArray(); + } + + @Override + public UserModel authenticate(char[] cookie) { + String hash = new String(cookie); + if (StringUtils.isEmpty(hash)) { + return null; + } + read(); + UserModel model = null; + if (cookies.containsKey(hash)) { + String username = cookies.get(hash); + model = getUserModel(username); + } + return model; + } + + @Override + public UserModel authenticate(String username, char[] password) { + Properties allUsers = read(); + String userInfo = allUsers.getProperty(username); + if (StringUtils.isEmpty(userInfo)) { + return null; + } + UserModel returnedUser = null; + UserModel user = getUserModel(username); + if (user.password.startsWith(StringUtils.MD5_TYPE)) { + String md5 = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(password)); + if (user.password.equalsIgnoreCase(md5)) { + returnedUser = user; + } + } else if (user.password.equals(new String(password))) { + returnedUser = user; + } + return returnedUser; + } + + @Override + public UserModel getUserModel(String username) { + Properties allUsers = read(); + String userInfo = allUsers.getProperty(username); + if (userInfo == null) { + return null; + } + UserModel model = new UserModel(username); + String[] userValues = userInfo.split(","); + model.password = userValues[0]; + for (int i = 1; i < userValues.length; i++) { + String role = userValues[i]; + switch (role.charAt(0)) { + case '#': + // Permissions + if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) { + model.canAdmin = true; + } + break; + default: + model.addRepository(role); + } + } + return model; + } + + @Override + public boolean updateUserModel(UserModel model) { + return updateUserModel(model.username, model); + } + + @Override + public boolean updateUserModel(String username, UserModel model) { + try { + Properties allUsers = read(); + ArrayList roles = new ArrayList(model.repositories); + + // Permissions + if (model.canAdmin) { + roles.add(Constants.ADMIN_ROLE); + } + + StringBuilder sb = new StringBuilder(); + sb.append(model.password); + sb.append(','); + for (String role : roles) { + sb.append(role); + sb.append(','); + } + // trim trailing comma + sb.setLength(sb.length() - 1); + allUsers.remove(username); + allUsers.put(model.username, sb.toString()); + + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to update user model {0}!", model.username), + t); + } + return false; + } + + @Override + public boolean deleteUserModel(UserModel model) { + return deleteUser(model.username); + } + + @Override + public boolean deleteUser(String username) { + try { + // Read realm file + Properties allUsers = read(); + allUsers.remove(username); + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to delete user {0}!", username), t); + } + return false; + } + + @Override + public List getAllUsernames() { + Properties allUsers = read(); + List list = new ArrayList(allUsers.stringPropertyNames()); + return list; + } + + @Override + public List getUsernamesForRepository(String role) { + List list = new ArrayList(); + try { + Properties allUsers = read(); + for (String username : allUsers.stringPropertyNames()) { + String value = allUsers.getProperty(username); + String[] values = value.split(","); + // skip first value (password) + for (int i = 1; i < values.length; i++) { + String r = values[i]; + if (r.equalsIgnoreCase(role)) { + list.add(username); + break; + } + } + } + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t); + } + return list; + } + + @Override + public boolean setUsernamesForRepository(String role, List usernames) { + try { + Set specifiedUsers = new HashSet(usernames); + Set needsAddRole = new HashSet(specifiedUsers); + Set needsRemoveRole = new HashSet(); + + // identify users which require add and remove role + Properties allUsers = read(); + for (String username : allUsers.stringPropertyNames()) { + String value = allUsers.getProperty(username); + String[] values = value.split(","); + // skip first value (password) + for (int i = 1; i < values.length; i++) { + String r = values[i]; + if (r.equalsIgnoreCase(role)) { + // user has role, check against revised user list + if (specifiedUsers.contains(username)) { + needsAddRole.remove(username); + } else { + // remove role from user + needsRemoveRole.add(username); + } + break; + } + } + } + + // add roles to users + for (String user : needsAddRole) { + String userValues = allUsers.getProperty(user); + userValues += "," + role; + allUsers.put(user, userValues); + } + + // remove role from user + for (String user : needsRemoveRole) { + String[] values = allUsers.getProperty(user).split(","); + String password = values[0]; + StringBuilder sb = new StringBuilder(); + sb.append(password); + sb.append(','); + List revisedRoles = new ArrayList(); + // skip first value (password) + for (int i = 1; i < values.length; i++) { + String value = values[i]; + if (!value.equalsIgnoreCase(role)) { + revisedRoles.add(value); + sb.append(value); + sb.append(','); + } + } + sb.setLength(sb.length() - 1); + + // update properties + allUsers.put(user, sb.toString()); + } + + // persist changes + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t); + } + return false; + } + + @Override + public boolean renameRepositoryRole(String oldRole, String newRole) { + try { + Properties allUsers = read(); + Set needsRenameRole = new HashSet(); + + // identify users which require role rename + for (String username : allUsers.stringPropertyNames()) { + String value = allUsers.getProperty(username); + String[] roles = value.split(","); + // skip first value (password) + for (int i = 1; i < roles.length; i++) { + String r = roles[i]; + if (r.equalsIgnoreCase(oldRole)) { + needsRenameRole.remove(username); + break; + } + } + } + + // rename role for identified users + for (String user : needsRenameRole) { + String userValues = allUsers.getProperty(user); + String[] values = userValues.split(","); + String password = values[0]; + StringBuilder sb = new StringBuilder(); + sb.append(password); + sb.append(','); + List revisedRoles = new ArrayList(); + revisedRoles.add(newRole); + // skip first value (password) + for (int i = 1; i < values.length; i++) { + String value = values[i]; + if (!value.equalsIgnoreCase(oldRole)) { + revisedRoles.add(value); + sb.append(value); + sb.append(','); + } + } + sb.setLength(sb.length() - 1); + + // update properties + allUsers.put(user, sb.toString()); + } + + // persist changes + write(allUsers); + return true; + } catch (Throwable t) { + logger.error( + MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t); + } + return false; + } + + @Override + public boolean deleteRepositoryRole(String role) { + try { + Properties allUsers = read(); + Set needsDeleteRole = new HashSet(); + + // identify users which require role rename + for (String username : allUsers.stringPropertyNames()) { + String value = allUsers.getProperty(username); + String[] roles = value.split(","); + // skip first value (password) + for (int i = 1; i < roles.length; i++) { + String r = roles[i]; + if (r.equalsIgnoreCase(role)) { + needsDeleteRole.remove(username); + break; + } + } + } + + // delete role for identified users + for (String user : needsDeleteRole) { + String userValues = allUsers.getProperty(user); + String[] values = userValues.split(","); + String password = values[0]; + StringBuilder sb = new StringBuilder(); + sb.append(password); + sb.append(','); + List revisedRoles = new ArrayList(); + // skip first value (password) + for (int i = 1; i < values.length; i++) { + String value = values[i]; + if (!value.equalsIgnoreCase(role)) { + revisedRoles.add(value); + sb.append(value); + sb.append(','); + } + } + sb.setLength(sb.length() - 1); + + // update properties + allUsers.put(user, sb.toString()); + } + + // persist changes + write(allUsers); + return true; + } catch (Throwable t) { + logger.error(MessageFormat.format("Failed to delete role {0}!", role), t); + } + return false; + } + + private void write(Properties properties) throws IOException { + // Update realm file + File realmFileCopy = new File(propertiesFile.getAbsolutePath() + ".tmp"); + FileWriter writer = new FileWriter(realmFileCopy); + properties + .store(writer, + "# Gitblit realm file format: username=password,\\#permission,repository1,repository2..."); + writer.close(); + if (realmFileCopy.exists() && realmFileCopy.length() > 0) { + if (propertiesFile.delete()) { + if (!realmFileCopy.renameTo(propertiesFile)) { + throw new IOException(MessageFormat.format("Failed to rename {0} to {1}!", + realmFileCopy.getAbsolutePath(), propertiesFile.getAbsolutePath())); + } + } else { + throw new IOException(MessageFormat.format("Failed to delete (0)!", + propertiesFile.getAbsolutePath())); + } + } else { + throw new IOException(MessageFormat.format("Failed to save {0}!", + realmFileCopy.getAbsolutePath())); + } + } + + @Override + protected synchronized Properties read() { + long lastRead = lastRead(); + Properties allUsers = super.read(); + if (lastRead != lastRead()) { + // reload hash cache + cookies.clear(); + for (String username : allUsers.stringPropertyNames()) { + String value = allUsers.getProperty(username); + String[] roles = value.split(","); + String password = roles[0]; + cookies.put(StringUtils.getSHA1(username + password), username); + } + } + return allUsers; + } +} diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 1fa8b60f..9b661171 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -27,7 +27,9 @@ import java.util.Map.Entry; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import javax.servlet.http.Cookie; +import org.apache.wicket.protocol.http.WebResponse; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; @@ -55,7 +57,7 @@ public class GitBlit implements ServletContextListener { private boolean exportAll = true; - private ILoginService loginService; + private IUserService userService; private IStoredSettings storedSettings; @@ -105,44 +107,81 @@ public class GitBlit implements ServletContextListener { return cloneUrls; } - public void setLoginService(ILoginService loginService) { - logger.info("Setting up login service " + loginService.toString()); - this.loginService = loginService; + public void setUserService(IUserService userService) { + logger.info("Setting up user service " + userService.toString()); + this.userService = userService; } public UserModel authenticate(String username, char[] password) { - if (loginService == null) { + if (userService == null) { return null; } - return loginService.authenticate(username, password); + return userService.authenticate(username, password); + } + + public UserModel authenticate(Cookie[] cookies) { + if (userService == null) { + return null; + } + if (userService.supportsCookies()) { + if (cookies != null && cookies.length > 0) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals(Constants.NAME)) { + String value = cookie.getValue(); + return userService.authenticate(value.toCharArray()); + } + } + } + } + return null; + } + + public void setCookie(WebResponse response, UserModel user) { + if (userService == null) { + return; + } + if (userService.supportsCookies()) { + Cookie userCookie; + if (user == null) { + // clear cookie for logout + userCookie = new Cookie(Constants.NAME, ""); + } else { + // set cookie for login + char[] cookie = userService.getCookie(user); + userCookie = new Cookie(Constants.NAME, new String(cookie)); + userCookie.setMaxAge(Integer.MAX_VALUE); + } + userCookie.setPath("/"); + response.addCookie(userCookie); + } } public List getAllUsernames() { - List names = new ArrayList(loginService.getAllUsernames()); + List names = new ArrayList(userService.getAllUsernames()); Collections.sort(names); return names; } public boolean deleteUser(String username) { - return loginService.deleteUser(username); + return userService.deleteUser(username); } public UserModel getUserModel(String username) { - UserModel user = loginService.getUserModel(username); + UserModel user = userService.getUserModel(username); return user; } public List getRepositoryUsers(RepositoryModel repository) { - return loginService.getUsernamesForRole(repository.name); + return userService.getUsernamesForRepository(repository.name); } public boolean setRepositoryUsers(RepositoryModel repository, List repositoryUsers) { - return loginService.setUsernamesForRole(repository.name, repositoryUsers); + return userService.setUsernamesForRepository(repository.name, repositoryUsers); } public void editUserModel(String username, UserModel user, boolean isCreate) throws GitBlitException { - if (!loginService.updateUserModel(username, user)) { + if (!userService.updateUserModel(username, user)) { throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!"); } } @@ -181,6 +220,9 @@ public class GitBlit implements ServletContextListener { public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) { RepositoryModel model = getRepositoryModel(repositoryName); + if (model == null) { + return null; + } if (model.accessRestriction.atLeast(AccessRestrictionType.VIEW)) { if (user != null && user.canAccessRepository(model.name)) { return model; @@ -261,7 +303,7 @@ public class GitBlit implements ServletContextListener { repository.name)); } // rename the roles - if (!loginService.renameRole(repositoryName, repository.name)) { + if (!userService.renameRepositoryRole(repositoryName, repository.name)) { throw new GitBlitException(MessageFormat.format( "Failed to rename repository permissions ''{0}'' to ''{1}''.", repositoryName, repository.name)); @@ -309,7 +351,7 @@ public class GitBlit implements ServletContextListener { File folder = new File(repositoriesFolder, repositoryName); if (folder.exists() && folder.isDirectory()) { FileUtils.delete(folder, FileUtils.RECURSIVE); - if (loginService.deleteRole(repositoryName)) { + if (userService.deleteRepositoryRole(repositoryName)) { return true; } } @@ -360,13 +402,13 @@ public class GitBlit implements ServletContextListener { repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "git")); logger.info("Git repositories folder " + repositoriesFolder.getAbsolutePath()); repositoryResolver = new FileResolver(repositoriesFolder, exportAll); - String realm = settings.getString(Keys.realm.realmFile, "users.properties"); - ILoginService loginService = null; + String realm = settings.getString(Keys.realm.userService, "users.properties"); + IUserService loginService = null; try { // Check to see if this "file" is a login service class Class realmClass = Class.forName(realm); - if (ILoginService.class.isAssignableFrom(realmClass)) { - loginService = (ILoginService) realmClass.newInstance(); + if (IUserService.class.isAssignableFrom(realmClass)) { + loginService = (IUserService) realmClass.newInstance(); } } catch (Throwable t) { // Not a login service class OR other issue @@ -380,9 +422,9 @@ public class GitBlit implements ServletContextListener { MessageFormat.format("COULD NOT CREATE REALM FILE {0}!", realmFile), x); } } - loginService = new FileLoginService(realmFile); + loginService = new FileUserService(realmFile); } - setLoginService(loginService); + setUserService(loginService); } @Override diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java index 80a46902..02cc54a0 100644 --- a/src/com/gitblit/GitBlitServer.java +++ b/src/com/gitblit/GitBlitServer.java @@ -111,7 +111,7 @@ public class GitBlitServer { * Start Server. */ private static void start(Params params) { - FileSettings settings = params.FILESETTINGS; + FileSettings settings = Params.FILESETTINGS; logger = LoggerFactory.getLogger(GitBlitServer.class); logger.info(Constants.BORDER); @@ -194,15 +194,15 @@ public class GitBlitServer { sessionManager.setSecureCookies(params.port <= 0 && params.securePort > 0); rootContext.getSessionHandler().setSessionManager(sessionManager); - // Ensure there is a defined Login Service - String realmUsers = params.realmFile; + // Ensure there is a defined User Service + String realmUsers = params.userService; if (StringUtils.isEmpty(realmUsers)) { - logger.error(MessageFormat.format("PLEASE SPECIFY {0}!!", Keys.realm.realmFile)); + logger.error(MessageFormat.format("PLEASE SPECIFY {0}!!", Keys.realm.userService)); return; } - + // Override settings - settings.overrideSetting(Keys.realm.realmFile, params.realmFile); + settings.overrideSetting(Keys.realm.userService, params.userService); settings.overrideSetting(Keys.git.repositoriesFolder, params.repositoriesFolder); // Set the server's contexts @@ -342,7 +342,7 @@ public class GitBlitServer { @Parameter(names = { "--stop" }, description = "Stop Server") public Boolean stop = false; - @Parameter(names = { "--tempFolder" }, description = "Server temp folder") + @Parameter(names = { "--tempFolder" }, description = "Folder for server to extract built-in webapp") public String temp = FILESETTINGS.getString(Keys.server.tempFolder, "temp"); /* @@ -355,8 +355,8 @@ public class GitBlitServer { /* * Authentication Parameters */ - @Parameter(names = { "--realmFile" }, description = "Users Realm Hash File") - public String realmFile = FILESETTINGS.getString(Keys.realm.realmFile, "users.properties"); + @Parameter(names = { "--userService" }, description = "Authentication and Authorization Service (filename or fully qualified classname)") + public String userService = FILESETTINGS.getString(Keys.realm.userService, "users.properties"); /* * JETTY Parameters diff --git a/src/com/gitblit/ILoginService.java b/src/com/gitblit/ILoginService.java deleted file mode 100644 index 0e706cf3..00000000 --- a/src/com/gitblit/ILoginService.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011 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; - -import java.util.List; - -import com.gitblit.models.UserModel; - -public interface ILoginService { - - UserModel authenticate(String username, char[] password); - - UserModel getUserModel(String username); - - boolean updateUserModel(UserModel model); - - boolean updateUserModel(String username, UserModel model); - - boolean deleteUserModel(UserModel model); - - boolean deleteUser(String username); - - List getAllUsernames(); - - List getUsernamesForRole(String role); - - boolean setUsernamesForRole(String role, List usernames); - - boolean renameRole(String oldRole, String newRole); - - boolean deleteRole(String role); - - String toString(); -} diff --git a/src/com/gitblit/IStoredSettings.java b/src/com/gitblit/IStoredSettings.java index 6fcb437e..e220a81c 100644 --- a/src/com/gitblit/IStoredSettings.java +++ b/src/com/gitblit/IStoredSettings.java @@ -27,7 +27,7 @@ import com.gitblit.utils.StringUtils; public abstract class IStoredSettings { protected final Logger logger; - + protected final Properties overrides = new Properties(); public IStoredSettings(Class clazz) { @@ -35,7 +35,7 @@ public abstract class IStoredSettings { } protected abstract Properties read(); - + private Properties getSettings() { Properties props = read(); props.putAll(overrides); @@ -110,7 +110,7 @@ public abstract class IStoredSettings { } return strings; } - + public void overrideSetting(String key, String value) { overrides.put(key, value); } diff --git a/src/com/gitblit/IUserService.java b/src/com/gitblit/IUserService.java new file mode 100644 index 00000000..d0d0105a --- /dev/null +++ b/src/com/gitblit/IUserService.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011 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; + +import java.util.List; + +import com.gitblit.models.UserModel; + +public interface IUserService { + + boolean supportsCookies(); + + char[] getCookie(UserModel model); + + UserModel authenticate(char[] cookie); + + UserModel authenticate(String username, char[] password); + + UserModel getUserModel(String username); + + boolean updateUserModel(UserModel model); + + boolean updateUserModel(String username, UserModel model); + + boolean deleteUserModel(UserModel model); + + boolean deleteUser(String username); + + List getAllUsernames(); + + List getUsernamesForRepository(String role); + + boolean setUsernamesForRepository(String role, List usernames); + + boolean renameRepositoryRole(String oldRole, String newRole); + + boolean deleteRepositoryRole(String role); + + String toString(); +} diff --git a/src/com/gitblit/SyndicationServlet.java b/src/com/gitblit/SyndicationServlet.java index 66dc467a..998949ad 100644 --- a/src/com/gitblit/SyndicationServlet.java +++ b/src/com/gitblit/SyndicationServlet.java @@ -62,7 +62,7 @@ public class SyndicationServlet extends HttpServlet { } return url.toString(); } - + public static String getTitle(String repository, String objectId) { String id = objectId; if (!StringUtils.isEmpty(id)) { diff --git a/src/com/gitblit/Thumbnailer.java b/src/com/gitblit/Thumbnailer.java deleted file mode 100644 index 5976f25e..00000000 --- a/src/com/gitblit/Thumbnailer.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2011 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; - -import java.awt.Dimension; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.Iterator; - -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; - -import com.beust.jcommander.JCommander; -import com.beust.jcommander.Parameter; -import com.beust.jcommander.ParameterException; -import com.beust.jcommander.Parameters; - -public class Thumbnailer { - - public static void main(String[] args) { - Params params = new Params(); - JCommander jc = new JCommander(params); - try { - jc.parse(args); - } catch (ParameterException t) { - System.err.println(t.getMessage()); - jc.usage(); - } - createImageThumbnail(params.sourceFolder, params.destinationFolder, params.maximumDimension); - } - - public static void createImageThumbnail(String sourceFolder, String destinationFolder, - int maxDimension) { - if (maxDimension <= 0) - return; - File source = new File(sourceFolder); - File destination = new File(destinationFolder); - destination.mkdirs(); - File[] sourceFiles = source.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.toLowerCase().endsWith(".png"); - } - }); - - for (File sourceFile : sourceFiles) { - File destinationFile = new File(destination, sourceFile.getName()); - try { - Dimension sz = getImageDimensions(sourceFile); - int w = 0; - int h = 0; - if (sz.width > maxDimension) { - // Scale to Width - w = maxDimension; - float f = maxDimension; - h = (int) ((f / sz.width) * sz.height); // normalize height - } else if (sz.height > maxDimension) { - // Scale to Height - h = maxDimension; - float f = maxDimension; - w = (int) ((f / sz.height) * sz.width); // normalize width - } else { - // No thumbnail - return; - } - System.out.println("Generating thumbnail for " + sourceFile.getName() + " as (" + w - + "," + h + ")"); - BufferedImage image = ImageIO.read(sourceFile); - Image scaledImage = image.getScaledInstance(w, h, BufferedImage.SCALE_SMOOTH); - BufferedImage destImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); - destImage.createGraphics().drawImage(scaledImage, 0, 0, null); - FileOutputStream fos = new FileOutputStream(destinationFile); - ImageIO.write(destImage, "png", fos); - fos.flush(); - fos.getFD().sync(); - fos.close(); - } catch (Throwable t) { - t.printStackTrace(); - } - } - } - - public static Dimension getImageDimensions(File file) throws IOException { - ImageInputStream in = ImageIO.createImageInputStream(file); - try { - final Iterator readers = ImageIO.getImageReaders(in); - if (readers.hasNext()) { - ImageReader reader = readers.next(); - try { - reader.setInput(in); - return new Dimension(reader.getWidth(0), reader.getHeight(0)); - } finally { - reader.dispose(); - } - } - } finally { - if (in != null) - in.close(); - } - return null; - } - - @Parameters(separators = " ") - private static class Params { - - @Parameter(names = { "--sourceFolder" }, description = "Source folder for raw images", required = true) - public String sourceFolder; - - @Parameter(names = { "--destinationFolder" }, description = "Destination folder for thumbnails", required = true) - public String destinationFolder; - - @Parameter(names = { "--maxDimension" }, description = "Maximum width or height for thumbnail", required = true) - public int maximumDimension; - - } -} diff --git a/src/com/gitblit/WebXmlSettings.java b/src/com/gitblit/WebXmlSettings.java index 0ff2a3e7..dff5700e 100644 --- a/src/com/gitblit/WebXmlSettings.java +++ b/src/com/gitblit/WebXmlSettings.java @@ -20,20 +20,28 @@ import java.util.Properties; import javax.servlet.ServletContext; +import com.gitblit.utils.StringUtils; + public class WebXmlSettings extends IStoredSettings { private final Properties properties = new Properties(); - + public WebXmlSettings(ServletContext context) { super(WebXmlSettings.class); Enumeration keys = context.getInitParameterNames(); while (keys.hasMoreElements()) { String key = keys.nextElement().toString(); String value = context.getInitParameter(key); - properties.put(key, value); + properties.put(key, decodeValue(value)); + logger.debug(key + "=" + properties.getProperty(key)); } } + private String decodeValue(String value) { + // Decode escaped backslashes and HTML entities + return StringUtils.decodeFromHtml(value).replace("\\\\", "\\"); + } + @Override protected Properties read() { return properties; diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java index 29647088..fd355fbb 100644 --- a/src/com/gitblit/models/UserModel.java +++ b/src/com/gitblit/models/UserModel.java @@ -43,7 +43,7 @@ public class UserModel implements Principal, Serializable { } @Override - public String getName() { + public String getName() { return username; } diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java index 5656efb3..1c607ca7 100644 --- a/src/com/gitblit/utils/JGitUtils.java +++ b/src/com/gitblit/utils/JGitUtils.java @@ -402,12 +402,12 @@ public class JGitUtils { public static List getFilesInCommit(Repository r, RevCommit commit) { List list = new ArrayList(); - RevWalk rw = new RevWalk(r); + RevWalk rw = new RevWalk(r); try { if (commit == null) { ObjectId object = r.resolve(Constants.HEAD); commit = rw.parseCommit(object); - } + } if (commit.getParentCount() == 0) { TreeWalk tw = new TreeWalk(r); @@ -441,7 +441,7 @@ public class JGitUtils { } catch (Throwable t) { LOGGER.error("failed to determine files in commit!", t); } finally { - rw.dispose(); + rw.dispose(); } return list; } @@ -526,6 +526,9 @@ public class JGitUtils { public static List getRevLog(Repository r, String objectId, String path, int offset, int maxCount) { List list = new ArrayList(); + if (maxCount == 0) { + return list; + } if (!hasCommits(r)) { return list; } @@ -591,6 +594,9 @@ public class JGitUtils { final SearchType type, int offset, int maxCount) { final String lcValue = value.toLowerCase(); List list = new ArrayList(); + if (maxCount == 0) { + return list; + } if (!hasCommits(r)) { return list; } @@ -677,6 +683,9 @@ public class JGitUtils { private static List getRefs(Repository r, String refs, boolean fullName, int maxCount) { List list = new ArrayList(); + if (maxCount == 0) { + return list; + } try { Map map = r.getRefDatabase().getRefs(refs); RevWalk rw = new RevWalk(r); diff --git a/src/com/gitblit/utils/StringUtils.java b/src/com/gitblit/utils/StringUtils.java index b53b5e15..219699fc 100644 --- a/src/com/gitblit/utils/StringUtils.java +++ b/src/com/gitblit/utils/StringUtils.java @@ -58,6 +58,11 @@ public class StringUtils { return retStr.toString(); } + public static String decodeFromHtml(String inStr) { + return inStr.replace("&", "&").replace("<", "<").replace(">", ">") + .replace(""", "\"").replace(" ", " "); + } + public static String encodeURL(String inStr) { StringBuffer retStr = new StringBuffer(); int i = 0; @@ -165,7 +170,7 @@ public class StringUtils { } return sb.toString(); } - + public static String getRootPath(String path) { if (path.indexOf('/') > -1) { return path.substring(0, path.lastIndexOf('/')); diff --git a/src/com/gitblit/wicket/pages/BasePage.java b/src/com/gitblit/wicket/pages/BasePage.java index 5a0eb90f..06d54837 100644 --- a/src/com/gitblit/wicket/pages/BasePage.java +++ b/src/com/gitblit/wicket/pages/BasePage.java @@ -19,13 +19,17 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.TimeZone; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.wicket.PageParameters; import org.apache.wicket.RestartResponseAtInterceptPageException; +import org.apache.wicket.RestartResponseException; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.protocol.http.WebRequest; +import org.apache.wicket.protocol.http.WebResponse; import org.apache.wicket.protocol.http.servlet.ServletWebRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +38,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.GitBlit; import com.gitblit.Keys; +import com.gitblit.models.UserModel; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.LinkPanel; @@ -45,14 +50,40 @@ public abstract class BasePage extends WebPage { public BasePage() { super(); logger = LoggerFactory.getLogger(getClass()); + loginByCookie(); } public BasePage(PageParameters params) { super(params); logger = LoggerFactory.getLogger(getClass()); + loginByCookie(); + } + + private void loginByCookie() { + if (!GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) { + return; + } + UserModel user = null; + + // Grab cookie from Browser Session + Cookie[] cookies = ((WebRequest) getRequestCycle().getRequest()).getCookies(); + if (cookies != null && cookies.length > 0) { + user = GitBlit.self().authenticate(cookies); + } + + // Login the user + if (user != null) { + // Set the user into the session + GitBlitWebSession.get().setUser(user); + + // Set Cookie + WebResponse response = (WebResponse) getRequestCycle().getResponse(); + GitBlit.self().setCookie(response, user); + } } protected void setupPage(String repositoryName, String pageName) { + if (repositoryName != null && repositoryName.trim().length() > 0) { add(new Label("title", getServerName() + " - " + repositoryName)); } else { @@ -122,7 +153,7 @@ public abstract class BasePage extends WebPage { HttpServletRequest req = servletWebRequest.getHttpServletRequest(); return req.getServerName(); } - + public void warn(String message, Throwable t) { logger.warn(message, t); } @@ -131,7 +162,7 @@ public abstract class BasePage extends WebPage { logger.error(message); if (redirect) { GitBlitWebSession.get().cacheErrorMessage(message); - throw new RestartResponseAtInterceptPageException(getApplication().getHomePage()); + throw new RestartResponseException(getApplication().getHomePage()); } else { super.error(message); } @@ -141,9 +172,18 @@ public abstract class BasePage extends WebPage { logger.error(message, t); if (redirect) { GitBlitWebSession.get().cacheErrorMessage(message); - throw new RestartResponseAtInterceptPageException(getApplication().getHomePage()); + throw new RestartResponseException(getApplication().getHomePage()); } else { super.error(message); } } + + public void authenticationError(String message) { + logger.error(message); + if (GitBlitWebSession.get().isLoggedIn()) { + error(message, true); + } else { + throw new RestartResponseAtInterceptPageException(LoginPage.class); + } + } } diff --git a/src/com/gitblit/wicket/pages/CommitPage.java b/src/com/gitblit/wicket/pages/CommitPage.java index a34917b6..3e3dcb8b 100644 --- a/src/com/gitblit/wicket/pages/CommitPage.java +++ b/src/com/gitblit/wicket/pages/CommitPage.java @@ -128,8 +128,8 @@ public class CommitPage extends RepositoryPage { SearchType.AUTHOR)); item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef .getAuthorIdent().getWhen(), getTimeZone())); - item.add(new Label("noteContent", GitBlit.self().processCommitMessage(repositoryName, entry.content)) - .setEscapeModelStrings(false)); + item.add(new Label("noteContent", GitBlit.self().processCommitMessage( + repositoryName, entry.content)).setEscapeModelStrings(false)); } }; add(notesView.setVisible(notes.size() > 0)); diff --git a/src/com/gitblit/wicket/pages/DocsPage.java b/src/com/gitblit/wicket/pages/DocsPage.java index 2f899bbe..40518b5c 100644 --- a/src/com/gitblit/wicket/pages/DocsPage.java +++ b/src/com/gitblit/wicket/pages/DocsPage.java @@ -64,8 +64,8 @@ public class DocsPage extends RepositoryPage { .newPathParameter(repositoryName, entry.commitId, entry.path))); item.add(new BookmarkablePageLink("raw", RawPage.class, WicketUtils .newPathParameter(repositoryName, entry.commitId, entry.path))); - item.add(new BookmarkablePageLink("blame", BlamePage.class, - WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))); + item.add(new BookmarkablePageLink("blame", BlamePage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); item.add(new BookmarkablePageLink("history", HistoryPage.class, WicketUtils .newPathParameter(repositoryName, entry.commitId, entry.path))); WicketUtils.setAlternatingBackground(item, counter); diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index 63916276..8f68ac28 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -130,7 +130,8 @@ public class EditUserPage extends BasePage { String type = GitBlit.getString(Keys.realm.passwordStorage, "md5"); if (type.equalsIgnoreCase("md5")) { // store MD5 digest of password - userModel.password = StringUtils.MD5_TYPE + StringUtils.getMD5(userModel.password); + userModel.password = StringUtils.MD5_TYPE + + StringUtils.getMD5(userModel.password); } } diff --git a/src/com/gitblit/wicket/pages/LogPage.java b/src/com/gitblit/wicket/pages/LogPage.java index 2cd787c7..c012538f 100644 --- a/src/com/gitblit/wicket/pages/LogPage.java +++ b/src/com/gitblit/wicket/pages/LogPage.java @@ -27,7 +27,7 @@ public class LogPage extends RepositoryPage { super(params); addSyndicationDiscoveryLink(); - + int pageNumber = WicketUtils.getPage(params); int prevPage = Math.max(0, pageNumber - 1); int nextPage = pageNumber + 1; diff --git a/src/com/gitblit/wicket/pages/LoginPage.java b/src/com/gitblit/wicket/pages/LoginPage.java index 971ba327..6ee72db3 100644 --- a/src/com/gitblit/wicket/pages/LoginPage.java +++ b/src/com/gitblit/wicket/pages/LoginPage.java @@ -15,7 +15,10 @@ */ package com.gitblit.wicket.pages; +import javax.servlet.http.Cookie; + import org.apache.wicket.PageParameters; +import org.apache.wicket.RestartResponseException; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.PasswordTextField; @@ -24,6 +27,8 @@ import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; +import org.apache.wicket.protocol.http.WebRequest; +import org.apache.wicket.protocol.http.WebResponse; import com.gitblit.Constants; import com.gitblit.GitBlit; @@ -42,8 +47,11 @@ public class LoginPage extends WebPage { // If we are already logged in because user directly accessed // the login url, redirect to the home page if (GitBlitWebSession.get().isLoggedIn()) { - setRedirect(true); - setResponsePage(getApplication().getHomePage()); + throw new RestartResponseException(getApplication().getHomePage()); + } + + if (GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) { + loginByCookie(); } add(new Label("title", GitBlit.getString(Keys.web.siteName, Constants.NAME))); @@ -72,11 +80,30 @@ public class LoginPage extends WebPage { add(loginForm); } + private void loginByCookie() { + UserModel user = null; + + // Grab cookie from Browser Session + Cookie[] cookies = ((WebRequest) getRequestCycle().getRequest()).getCookies(); + if (cookies != null && cookies.length > 0) { + user = GitBlit.self().authenticate(cookies); + } + + // Login the user + loginUser(user); + } + private void loginUser(UserModel user) { if (user != null) { // Set the user into the session GitBlitWebSession.get().setUser(user); + // Set Cookie + if (GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) { + WebResponse response = (WebResponse) getRequestCycle().getResponse(); + GitBlit.self().setCookie(response, user); + } + if (!continueToOriginalDestination()) { // Redirect to home page setResponsePage(getApplication().getHomePage()); diff --git a/src/com/gitblit/wicket/pages/LogoutPage.java b/src/com/gitblit/wicket/pages/LogoutPage.java index 05beab3c..b049e8e0 100644 --- a/src/com/gitblit/wicket/pages/LogoutPage.java +++ b/src/com/gitblit/wicket/pages/LogoutPage.java @@ -16,11 +16,16 @@ package com.gitblit.wicket.pages; import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.protocol.http.WebResponse; + +import com.gitblit.GitBlit; +import com.gitblit.wicket.GitBlitWebSession; public class LogoutPage extends WebPage { public LogoutPage() { - getSession().invalidate(); + GitBlitWebSession.get().invalidate(); + GitBlit.self().setCookie(((WebResponse) getResponse()), null); setRedirect(true); setResponsePage(getApplication().getHomePage()); } diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java index 00ed7554..22d3323a 100644 --- a/src/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/com/gitblit/wicket/pages/RepositoryPage.java @@ -15,6 +15,7 @@ */ package com.gitblit.wicket.pages; +import java.io.Serializable; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -205,7 +206,7 @@ public abstract class RepositoryPage extends BasePage { RepositoryModel model = GitBlit.self().getRepositoryModel( GitBlitWebSession.get().getUser(), repositoryName); if (model == null) { - error("Unauthorized access for repository " + repositoryName, true); + authenticationError("Unauthorized access for repository " + repositoryName); return null; } m = model; @@ -333,7 +334,9 @@ public abstract class RepositoryPage extends BasePage { return WicketUtils.newPathParameter(repositoryName, objectId, path); } - private static class PageRegistration { + private static class PageRegistration implements Serializable { + private static final long serialVersionUID = 1L; + final String translationKey; final Class pageClass; @@ -343,7 +346,7 @@ public abstract class RepositoryPage extends BasePage { } } - private static class SearchForm extends StatelessForm { + private static class SearchForm extends StatelessForm implements Serializable { private static final long serialVersionUID = 1L; private final String repositoryName; diff --git a/src/com/gitblit/wicket/pages/SummaryPage.html b/src/com/gitblit/wicket/pages/SummaryPage.html index bbf89798..35ad3477 100644 --- a/src/com/gitblit/wicket/pages/SummaryPage.html +++ b/src/com/gitblit/wicket/pages/SummaryPage.html @@ -32,15 +32,11 @@
[commits panel]
- -
-
[branches panel]
-
- -
-
[tags panel]
-
+
[tags panel]
+ + +
[branches panel]
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.java b/src/com/gitblit/wicket/pages/SummaryPage.java index e31375c0..39b8a97e 100644 --- a/src/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/com/gitblit/wicket/pages/SummaryPage.java @@ -58,18 +58,11 @@ public class SummaryPage extends RepositoryPage { public SummaryPage(PageParameters params) { super(params); - int numCommitsDef = 20; - int numRefsDef = 5; - - int numberCommits = GitBlit.getInteger(Keys.web.summaryCommitCount, numCommitsDef); + int numberCommits = GitBlit.getInteger(Keys.web.summaryCommitCount, 20); if (numberCommits <= 0) { - numberCommits = numCommitsDef; - } - - int numberRefs = GitBlit.getInteger(Keys.web.summaryRefsCount, numRefsDef); - if (numberRefs <= 0) { - numberRefs = numRefsDef; + numberCommits = 20; } + int numberRefs = GitBlit.getInteger(Keys.web.summaryRefsCount, 5); Repository r = getRepository(); List metrics = null; @@ -78,7 +71,7 @@ public class SummaryPage extends RepositoryPage { metrics = MetricUtils.getDateMetrics(r, null, true, null); metricsTotal = metrics.remove(0); } - + addSyndicationDiscoveryLink(); // repository description @@ -121,7 +114,7 @@ public class SummaryPage extends RepositoryPage { add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); } StringBuilder sb = new StringBuilder(); - sb.append(WicketUtils.getHostURL(getRequestCycle().getRequest())); + sb.append(WicketUtils.getHostURL(getRequestCycle().getRequest())); sb.append(Constants.GIT_PATH); sb.append(repositoryName); repositoryUrls.add(sb.toString()); diff --git a/src/com/gitblit/wicket/panels/BranchesPanel.html b/src/com/gitblit/wicket/panels/BranchesPanel.html index 7e87067a..c58f42ef 100644 --- a/src/com/gitblit/wicket/panels/BranchesPanel.html +++ b/src/com/gitblit/wicket/panels/BranchesPanel.html @@ -8,14 +8,15 @@ -
[branches header]
+
[branches header]
- + + diff --git a/src/com/gitblit/wicket/panels/BranchesPanel.java b/src/com/gitblit/wicket/panels/BranchesPanel.java index 302b48dd..8e58d673 100644 --- a/src/com/gitblit/wicket/panels/BranchesPanel.java +++ b/src/com/gitblit/wicket/panels/BranchesPanel.java @@ -27,18 +27,20 @@ import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; import org.apache.wicket.model.StringResourceModel; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import com.gitblit.SyndicationServlet; import com.gitblit.models.RefModel; import com.gitblit.models.RepositoryModel; import com.gitblit.utils.JGitUtils; +import com.gitblit.utils.JGitUtils.SearchType; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.pages.BranchesPage; +import com.gitblit.wicket.pages.CommitPage; import com.gitblit.wicket.pages.LogPage; import com.gitblit.wicket.pages.MetricsPage; +import com.gitblit.wicket.pages.SearchPage; import com.gitblit.wicket.pages.SummaryPage; import com.gitblit.wicket.pages.TreePage; @@ -90,11 +92,24 @@ public class BranchesPanel extends BasePanel { entry.displayName, 28), LogPage.class, WicketUtils.newObjectParameter( model.name, entry.getName()))); - // only show branch type on the branches page - boolean remote = entry.getName().startsWith(Constants.R_REMOTES); - item.add(new Label("branchType", remote ? getString("gb.remote") - : getString("gb.local")).setVisible(maxCount <= 0)); - + String author = entry.getAuthorIdent().getName(); + LinkPanel authorLink = new LinkPanel("branchAuthor", "list", author, + SearchPage.class, WicketUtils.newSearchParameter(model.name, entry.getName(), + author, SearchType.AUTHOR)); + setPersonSearchTooltip(authorLink, author, SearchType.AUTHOR); + item.add(authorLink); + + // short message + String shortMessage = entry.getShortMessage(); + String trimmedMessage = StringUtils.trimShortLog(shortMessage); + LinkPanel shortlog = new LinkPanel("branchLog", "list subject", + trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter( + model.name, entry.getName())); + if (!shortMessage.equals(trimmedMessage)) { + WicketUtils.setHtmlTooltip(shortlog, shortMessage); + } + item.add(shortlog); + if (maxCount <= 0) { Fragment fragment = new Fragment("branchLinks", "branchPageLinks", this); fragment.add(new BookmarkablePageLink("log", LogPage.class, WicketUtils @@ -103,8 +118,9 @@ public class BranchesPanel extends BasePanel { .newObjectParameter(model.name, entry.getName()))); fragment.add(new BookmarkablePageLink("metrics", MetricsPage.class, WicketUtils.newObjectParameter(model.name, entry.getName()))); - fragment.add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest() - .getRelativePathPrefixToContextRoot(), model.name, entry.getName(), 0))); + fragment.add(new ExternalLink("syndication", SyndicationServlet.asLink( + getRequest().getRelativePathPrefixToContextRoot(), model.name, + entry.getName(), 0))); item.add(fragment); } else { Fragment fragment = new Fragment("branchLinks", "branchPanelLinks", this); diff --git a/src/com/gitblit/wicket/panels/LogPanel.html b/src/com/gitblit/wicket/panels/LogPanel.html index 1ca92851..712a6628 100644 --- a/src/com/gitblit/wicket/panels/LogPanel.html +++ b/src/com/gitblit/wicket/panels/LogPanel.html @@ -8,8 +8,7 @@ -
[log header]
- +
[log header]
[branch date] [branch name][branch type][branch author][branch log]
diff --git a/src/com/gitblit/wicket/panels/SearchPanel.java b/src/com/gitblit/wicket/panels/SearchPanel.java index 759040e6..d118790c 100644 --- a/src/com/gitblit/wicket/panels/SearchPanel.java +++ b/src/com/gitblit/wicket/panels/SearchPanel.java @@ -74,7 +74,7 @@ public class SearchPanel extends BasePanel { // header add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); - + add(new Label("searchString", value)); add(new Label("searchType", searchType.toString())); diff --git a/src/com/gitblit/wicket/panels/TagsPanel.html b/src/com/gitblit/wicket/panels/TagsPanel.html index 481d8e81..86eedd60 100644 --- a/src/com/gitblit/wicket/panels/TagsPanel.html +++ b/src/com/gitblit/wicket/panels/TagsPanel.html @@ -8,7 +8,7 @@ -
[tags header]
+
[tags header]
diff --git a/src/com/gitblit/wicket/panels/TagsPanel.java b/src/com/gitblit/wicket/panels/TagsPanel.java index 95bc8575..58cb4586 100644 --- a/src/com/gitblit/wicket/panels/TagsPanel.java +++ b/src/com/gitblit/wicket/panels/TagsPanel.java @@ -90,13 +90,10 @@ public class TagsPanel extends BasePanel { item.add(new LinkPanel("tagName", "list name", entry.displayName, linkClass, WicketUtils.newObjectParameter(repositoryName, entry .getReferencedObjectId().getName()))); - String message; - if (maxCount > 0) { - message = StringUtils.trimString(entry.getShortMessage(), 40); - } else { - // workaround for RevTag returning a lengthy shortlog. :( - message = StringUtils.trimShortLog(entry.getShortMessage()); - } + + // workaround for RevTag returning a lengthy shortlog. :( + String message = StringUtils.trimShortLog(entry.getShortMessage()); + if (linkClass.equals(BlobPage.class)) { // Blob Tag Object item.add(WicketUtils.newImage("tagIcon", "file_16x16.png")); -- cgit v1.2.3