New Setting "Default Language" when creating usertags/r1.9.0
@@ -49,7 +49,7 @@ | |||
<classpathentry kind="lib" path="ext/httpcore-4.3.3.jar" sourcepath="ext/src/httpcore-4.3.3.jar" /> | |||
<classpathentry kind="lib" path="ext/commons-logging-1.1.3.jar" sourcepath="ext/src/commons-logging-1.1.3.jar" /> | |||
<classpathentry kind="lib" path="ext/commons-codec-1.7.jar" sourcepath="ext/src/commons-codec-1.7.jar" /> | |||
<classpathentry kind="lib" path="ext/org.eclipse.jdt.annotation-1.1.0.jar" /> | |||
<classpathentry kind="lib" path="ext/org.eclipse.jdt.annotation-1.1.0.jar" sourcepath="ext/src/org.eclipse.jdt.annotation-1.1.0.jar" /> | |||
<classpathentry kind="lib" path="ext/org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar" sourcepath="ext/src/org.eclipse.jgit.http.server-4.1.1.201511131810-r.jar" /> | |||
<classpathentry kind="lib" path="ext/bcprov-jdk15on-1.52.jar" sourcepath="ext/src/bcprov-jdk15on-1.52.jar" /> | |||
<classpathentry kind="lib" path="ext/bcmail-jdk15on-1.52.jar" sourcepath="ext/src/bcmail-jdk15on-1.52.jar" /> | |||
@@ -94,10 +94,5 @@ | |||
<classpathentry kind="lib" path="ext/mockito-core-1.10.19.jar" sourcepath="ext/src/mockito-core-1.10.19.jar" /> | |||
<classpathentry kind="lib" path="ext/objenesis-2.1.jar" sourcepath="ext/src/objenesis-2.1.jar" /> | |||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER" /> | |||
<classpathentry kind="src" path="src/main/dagger"> | |||
<attributes> | |||
<attribute name="optional" value="true"/> | |||
</attributes> | |||
</classpathentry> | |||
<classpathentry kind="output" path="bin/classes" /> | |||
</classpath> |
@@ -491,7 +491,9 @@ | |||
<root url="jar://$MODULE_DIR$/ext/org.eclipse.jdt.annotation-1.1.0.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/org.eclipse.jdt.annotation-1.1.0.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> |
@@ -0,0 +1,111 @@ | |||
******************************************************************************** | |||
Gitblit 伺服器 $serverHostname 所需之 SSL 用戶端憑證 | |||
******************************************************************************** | |||
$userDisplayname 您好, | |||
伺服器 $serverHostname 所需要的私鑰,公鑰以及Gitblit簽證檔案(CA)存放於 $username.p12, PKCS#12 certificate store[1] 以及 $username.pem. | |||
兩種證書皆受密碼保護. | |||
密碼提示: $storePasswordHint | |||
Git 憑證匯入步驟 | |||
============================================= | |||
附件之 PEM 檔案可以直接匯入至您的git程式裡. | |||
git config [--global] http.sslCert path/to/$username.pem | |||
PEM檔案受密碼保護,因此匯入過程會提示多次. 如果您偏好不使用密碼,您需要另外匯出無密碼之私鑰後,再匯入git程式裡. | |||
openssl rsa -in path/to/$username.pem -out path/to/$username.key | |||
git config [--global] http.sslKey path/to/$username.key | |||
此外,您應該妥善保管已經解除密碼保護之私鑰. | |||
註: | |||
如果沒有匯出私鑰, 有些早期git版本將會發生匯入失敗問題,例如:Ubuntu 12.04 with git 1.7.9.5. | |||
Firefox 憑證匯入步驟 | |||
============================================= | |||
Firefox 有自己的證書管理介面. | |||
1. 點選 "選項->進階->憑證" | |||
2. 點選 "檢視憑證清單" | |||
3. 切換至 "您的憑證" | |||
4. 點選 "匯入(M)" | |||
5. 選擇電腦中的憑證檔案 $username.p12 | |||
6. 輸入憑證檔案所需的密碼 | |||
7. 切換至"憑證機構" | |||
8. 找到 "Gitblit Certificate Authority" 憑證 | |||
9. 點選"編輯信任(E)" | |||
10.選擇信任網站. | |||
Chrome/IE (Windows) 憑證匯入步驟 | |||
============================================= | |||
在Windows作業系統下, Chrome 與 IE 共用相同的憑證設定. | |||
IE | |||
------------------------------------ | |||
1. 選擇 "網際網路選項->內容" | |||
2. 點選"憑證" | |||
Chrome | |||
------------------------------------ | |||
1. 選擇 "設定->顯示進階設定->HTTP/SSL" | |||
2. 點選"管理憑證" | |||
共同步驟 (Windows) | |||
------------------------------------ | |||
3. 切換至 "個人" | |||
4. 點選"匯入(I)" | |||
5. 依照指示匯入. | |||
請切換匯入檔案類型為p12並且找到 $username.p12 這個憑證檔案 | |||
6. 輸入憑證檔案保護密碼 | |||
7. 由於主要發放憑證單位(CA)與個人憑證檔案皆儲存於 $username.p12, 因此匯入時候,必須選擇 "自動根據憑證類型來選擇憑證存放區". | |||
如果選擇預設值匯入, 將不會安裝主要發放憑證單位(CA) | |||
Chrome (Linux) Installation Instructions | |||
============================================= | |||
On Linux, Chrome maintains it's own certificate store. | |||
1. Navigate to Settings->Show Advanced Settings->HTTP/SSL | |||
2. Click the "Manage Certificates..." button | |||
3. Navigate your filesystem and select $username.p12 | |||
4. At the password prompt enter the certificate store password | |||
You have now imported your private key, public certificate, and the CA certificate | |||
but now we must manually set the trust settings of the CA certificate. | |||
5. Switch to the "Authorities" tab | |||
6. Scroll down and find "Gitblit-> Gitblit Certificate Authority" | |||
7. Select it and click "Edit Trust..." | |||
8. Check "This certificate can identify websites" and click OK. | |||
Chrome/Safari (Mac OS X) Installation Instructions | |||
============================================= | |||
On Mac OS X, Chrome and Safari both use Keychain Access to store certificates | |||
so configuring one will automatically apply for both. | |||
1. Double-click $username.pem | |||
2. At the password prompt enter the certificate store password | |||
You have now imported your private key, public certificate, and the CA certificate | |||
but now we must manually set the trust settings of the CA certificate. | |||
3. Find the Gitblit Certificate Authority certificate, it should have a red | |||
indicator meaning untrusted, and double-click it. | |||
4. Open the "Trust" disclosure triangle and change "When using this certificate" | |||
to "Always Trust". | |||
5. Close the certificate view and enter your system password to save the changes | |||
to your keychain. | |||
[1] PKCS#12 is one of the standard container formats for sharing private keys and | |||
public certificates. | |||
[2] http://www.openssl.org |
@@ -0,0 +1,5 @@ | |||
$userDisplayname 您好 | |||
伺服器 $serverHostname 所需要的私鑰,公鑰以及Gitblit簽證檔案(CA)已經全部打包並且以zip壓縮檔方式寄給您. | |||
此外,檔案還附上各瀏覽器設定步驟供您參考. |
@@ -48,7 +48,9 @@ import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.ResourceBundle; | |||
import javax.mail.Message; | |||
import javax.swing.ImageIcon; | |||
@@ -98,6 +100,7 @@ import com.gitblit.utils.X509Utils; | |||
import com.gitblit.utils.X509Utils.RevocationReason; | |||
import com.gitblit.utils.X509Utils.X509Log; | |||
import com.gitblit.utils.X509Utils.X509Metadata; | |||
import com.gitblit.wicket.GitBlitWebSession; | |||
/** | |||
* Simple GUI tool for administering Gitblit client certificates. | |||
@@ -447,7 +450,7 @@ public class GitblitAuthority extends JFrame implements X509Log { | |||
} | |||
File caKeystoreFile = new File(folder, X509Utils.CA_KEY_STORE); | |||
File zip = X509Utils.newClientBundle(metadata, caKeystoreFile, caKeystorePassword, GitblitAuthority.this); | |||
File zip = X509Utils.newClientBundle(user,metadata, caKeystoreFile, caKeystorePassword, GitblitAuthority.this); | |||
// save latest expiration date | |||
if (ucm.expires == null || metadata.notAfter.before(ucm.expires)) { | |||
@@ -850,9 +853,19 @@ public class GitblitAuthority extends JFrame implements X509Log { | |||
try { | |||
if (mail.isReady()) { | |||
Mailing mailing = Mailing.newPlain(); | |||
mailing.subject = "Your Gitblit client certificate for " + metadata.serverHostname; | |||
if( user.getPreferences().getLocale()!=null ) | |||
mailing.subject = MessageFormat.format(ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp",user.getPreferences().getLocale()).getString("gb.emailClientCertificateSubject"), metadata.serverHostname); | |||
else | |||
mailing.subject = MessageFormat.format(ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp", Locale.ENGLISH).getString("gb.emailClientCertificateSubject") , metadata.serverHostname); | |||
mailing.setRecipients(user.emailAddress); | |||
String body = X509Utils.processTemplate(new File(folder, X509Utils.CERTS + File.separator + "mail.tmpl"), metadata); | |||
File fileMailTmp = null; | |||
String body = null; | |||
if( (fileMailTmp = new File(folder, X509Utils.CERTS + File.separator + "mail.tmpl"+"_"+user.getPreferences().getLocale())).exists()) | |||
body = X509Utils.processTemplate(fileMailTmp, metadata); | |||
else{ | |||
fileMailTmp = new File(folder, X509Utils.CERTS + File.separator + "mail.tmpl"); | |||
body = X509Utils.processTemplate(fileMailTmp, metadata); | |||
} | |||
if (StringUtils.isEmpty(body)) { | |||
body = MessageFormat.format("Hi {0}\n\nHere is your client certificate bundle.\nInside the zip file are installation instructions.", user.getDisplayName()); | |||
} |
@@ -743,6 +743,25 @@ public class X509Utils { | |||
*/ | |||
public static File newClientBundle(X509Metadata clientMetadata, File caKeystoreFile, | |||
String caKeystorePassword, X509Log x509log) { | |||
return newClientBundle(null,clientMetadata,caKeystoreFile,caKeystorePassword,x509log); | |||
} | |||
/** | |||
* Creates a new client certificate PKCS#12 and PEM store. Any existing | |||
* stores are destroyed. After generation, the certificates are bundled | |||
* into a zip file with a personalized README file. | |||
* | |||
* The zip file reference is returned. | |||
* | |||
* @param user | |||
* @param clientMetadata a container for dynamic parameters needed for generation | |||
* @param caKeystoreFile | |||
* @param caKeystorePassword | |||
* @param x509log | |||
* @return a zip file containing the P12, PEM, and personalized README | |||
*/ | |||
public static File newClientBundle(com.gitblit.models.UserModel user,X509Metadata clientMetadata, File caKeystoreFile, | |||
String caKeystorePassword, X509Log x509log) { | |||
try { | |||
// read the Gitblit CA key and certificate | |||
KeyStore store = openKeyStore(caKeystoreFile, caKeystorePassword); | |||
@@ -755,8 +774,17 @@ public class X509Utils { | |||
x509log.log(MessageFormat.format("New client certificate {0,number,0} [{1}]", cert.getSerialNumber(), cert.getSubjectDN().getName())); | |||
// process template message | |||
String readme = processTemplate(new File(caKeystoreFile.getParentFile(), "instructions.tmpl"), clientMetadata); | |||
String readme = null; | |||
String sInstructionsFileName = "instructions.tmpl"; | |||
if( user == null ) | |||
readme = processTemplate(new File(caKeystoreFile.getParentFile(),sInstructionsFileName), clientMetadata); | |||
else{ | |||
File fileInstructionsTmp = null; | |||
if( (fileInstructionsTmp = new File(caKeystoreFile.getParentFile(),sInstructionsFileName+"_"+user.getPreferences().getLocale())).exists() ) | |||
readme = processTemplate(fileInstructionsTmp,clientMetadata); | |||
else | |||
readme = processTemplate(new File(caKeystoreFile.getParentFile(),sInstructionsFileName),clientMetadata); | |||
} | |||
// Create a zip bundle with the p12, pem, and a personalized readme | |||
File zipFile = new File(targetFolder, clientMetadata.commonName + ".zip"); | |||
if (zipFile.exists()) { |
@@ -783,3 +783,4 @@ gb.deletePatchsetSuccess = Deleted Patchset {0}. | |||
gb.deletePatchsetFailure = Error deleting Patchset {0}. | |||
gb.referencedByCommit = Referenced by commit. | |||
gb.referencedByTicket = Referenced by ticket. | |||
gb.emailClientCertificateSubject = Your Gitblit client certificate for {0} |
@@ -781,3 +781,4 @@ gb.deletePatchsetSuccess = \u5df2\u522a\u9664 Patchset {0}. | |||
gb.deletePatchsetFailure = \u522a\u9664 Patchset {0} \u932f\u8aa4. | |||
gb.referencedByCommit = Referenced by commit. | |||
gb.referencedByTicket = Referenced by ticket. | |||
gb.emailClientCertificateSubject = \u4F3A\u670D\u5668 {0} \u9023\u7DDA\u6191\u8B49 |
@@ -31,11 +31,12 @@ | |||
<tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr> | |||
<tr><th><wicket:message key="gb.displayName"></wicket:message></th><td class="edit"><input type="text" wicket:id="displayName" size="30" tabindex="4" /></td></tr> | |||
<tr><th><wicket:message key="gb.emailAddress"></wicket:message></th><td class="edit"><input type="text" wicket:id="emailAddress" size="30" tabindex="5" /></td></tr> | |||
<tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="9" /> <span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.disableUser"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="disabled" tabindex="10" /> <span class="help-inline"><wicket:message key="gb.disableUserDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.languagePreference"></wicket:message></th><td class="edit"><select wicket:id="language" ></select></td></tr> | |||
<tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="9" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="10" /> <span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr> | |||
<tr><th><wicket:message key="gb.disableUser"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="disabled" tabindex="11" /> <span class="help-inline"><wicket:message key="gb.disableUserDescription"></wicket:message></span></label></td></tr> | |||
</tbody> | |||
</table> | |||
</div> |
@@ -20,15 +20,18 @@ import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import org.apache.wicket.PageParameters; | |||
import org.apache.wicket.behavior.SimpleAttributeModifier; | |||
import org.apache.wicket.extensions.markup.html.form.palette.Palette; | |||
import org.apache.wicket.markup.html.form.Button; | |||
import org.apache.wicket.markup.html.form.CheckBox; | |||
import org.apache.wicket.markup.html.form.DropDownChoice; | |||
import org.apache.wicket.markup.html.form.Form; | |||
import org.apache.wicket.markup.html.form.TextField; | |||
import org.apache.wicket.model.CompoundPropertyModel; | |||
import org.apache.wicket.model.IModel; | |||
import org.apache.wicket.model.Model; | |||
import org.apache.wicket.model.util.CollectionModel; | |||
import org.apache.wicket.model.util.ListModel; | |||
@@ -108,6 +111,30 @@ public class EditUserPage extends RootSubPage { | |||
final Palette<String> teams = new Palette<String>("teams", new ListModel<String>( | |||
new ArrayList<String>(userTeams)), new CollectionModel<String>(app().users() | |||
.getAllTeamNames()), new StringChoiceRenderer(), 10, false); | |||
Locale locale = userModel.getPreferences().getLocale(); | |||
if (locale == null) { | |||
locale = Locale.ENGLISH; | |||
} | |||
List<Language> languages = UserPage.getLanguages(); | |||
Language preferredLanguage = null; | |||
if (locale != null) { | |||
String localeCode = locale.getLanguage(); | |||
if (!StringUtils.isEmpty(locale.getCountry())) { | |||
localeCode += "_" + locale.getCountry(); | |||
} | |||
for (Language lang : languages) { | |||
if (lang.code.equals(localeCode)) { | |||
// language_COUNTRY match | |||
preferredLanguage = lang; | |||
} else if (preferredLanguage != null && lang.code.startsWith(locale.getLanguage())) { | |||
// language match | |||
preferredLanguage = lang; | |||
} | |||
} | |||
} | |||
final IModel<Language> language = Model.of(preferredLanguage); | |||
Form<UserModel> form = new Form<UserModel>("editForm", model) { | |||
private static final long serialVersionUID = 1L; | |||
@@ -123,6 +150,10 @@ public class EditUserPage extends RootSubPage { | |||
error(getString("gb.pleaseSetUsername")); | |||
return; | |||
} | |||
Language lang = language.getObject(); | |||
if (lang != null) { | |||
userModel.getPreferences().setLocale(lang.code); | |||
} | |||
// force username to lower-case | |||
userModel.username = userModel.username.toLowerCase(); | |||
String username = userModel.username; | |||
@@ -251,7 +282,10 @@ public class EditUserPage extends RootSubPage { | |||
form.add(confirmPasswordField.setEnabled(editCredentials)); | |||
form.add(new TextField<String>("displayName").setEnabled(editDisplayName)); | |||
form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress)); | |||
DropDownChoice<Language> choice = new DropDownChoice<Language>("language",language,languages ); | |||
form.add( choice.setEnabled(languages.size()>0) ); | |||
if (userModel.canAdmin() && !userModel.canAdmin) { | |||
// user inherits Admin permission | |||
// display a disabled-yet-checked checkbox |
@@ -0,0 +1,21 @@ | |||
package com.gitblit.wicket.pages; | |||
import java.io.Serializable; | |||
public class Language implements Serializable { | |||
private static final long serialVersionUID = 1L; | |||
final String name; | |||
final String code; | |||
public Language(String name, String code) { | |||
this.name = name; | |||
this.code = code; | |||
} | |||
@Override | |||
public String toString() { | |||
return name + " (" + code + ")"; | |||
} | |||
} |
@@ -166,12 +166,9 @@ public class UserPage extends RootPage { | |||
navLinks.add(menu); | |||
} | |||
private void addPreferences(UserModel user) { | |||
// add preferences | |||
Form<Void> prefs = new Form<Void>("prefsForm"); | |||
List<Language> languages = Arrays.asList( | |||
public static List<Language> getLanguages(){ | |||
return Arrays.asList( | |||
new Language("Deutsch","de"), | |||
new Language("English","en"), | |||
new Language("Español", "es"), | |||
@@ -185,6 +182,13 @@ public class UserPage extends RootPage { | |||
new Language("Português", "pt_BR"), | |||
new Language("簡體中文", "zh_CN"), | |||
new Language("正體中文", "zh_TW")); | |||
} | |||
private void addPreferences(UserModel user) { | |||
// add preferences | |||
Form<Void> prefs = new Form<Void>("prefsForm"); | |||
List<Language> languages = getLanguages(); | |||
Locale locale = user.getPreferences().getLocale(); | |||
if (locale == null) { | |||
@@ -315,22 +319,4 @@ public class UserPage extends RootPage { | |||
add(new Fragment("sshKeysLink", "sshKeysLinkFragment", this).setRenderBodyOnly(true)); | |||
add(keysTab.setRenderBodyOnly(true)); | |||
} | |||
private class Language implements Serializable { | |||
private static final long serialVersionUID = 1L; | |||
final String name; | |||
final String code; | |||
public Language(String name, String code) { | |||
this.name = name; | |||
this.code = code; | |||
} | |||
@Override | |||
public String toString() { | |||
return name + " (" + code +")"; | |||
} | |||
} | |||
} |