integrate cert4android

This commit is contained in:
schaarsc 2017-04-23 00:27:06 +02:00 committed by Niedermann IT-Dienstleistungen
parent 6ec8da66d0
commit 231de0a64c
15 changed files with 230 additions and 59 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "cert4android"]
path = cert4android
url = https://gitlab.com/bitfireAT/cert4android.git

View file

@ -24,6 +24,8 @@ android {
} }
dependencies { dependencies {
compile project(':cert4android')
compile 'com.yydcdut:rxmarkdown:0.1.0' compile 'com.yydcdut:rxmarkdown:0.1.0'
compile 'com.android.support:support-v4:25.3.1' compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support:appcompat-v7:25.3.1'

View file

@ -15,9 +15,9 @@ public class NotesClientUtilTest extends TestCase {
} }
public void testIsValidURLTest() { public void testIsValidURLTest() {
assertTrue(NotesClientUtil.isValidURL("https://demo.owncloud.org/")); assertTrue(NotesClientUtil.isValidURL(null, "https://demo.owncloud.org/"));
assertFalse(NotesClientUtil.isValidURL("https://www.example.com/")); assertFalse(NotesClientUtil.isValidURL(null, "https://www.example.com/"));
assertFalse(NotesClientUtil.isValidURL("htp://www.example.com/")); assertFalse(NotesClientUtil.isValidURL(null, "htp://www.example.com/"));
assertFalse(NotesClientUtil.isValidURL(null)); assertFalse(NotesClientUtil.isValidURL(null, null));
} }
} }

View file

@ -21,6 +21,7 @@ import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import at.bitfire.cert4android.CustomCertManager;
import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper; import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper;
import it.niedermann.owncloud.notes.util.NotesClientUtil; import it.niedermann.owncloud.notes.util.NotesClientUtil;
@ -47,8 +48,10 @@ public class SettingsActivity extends AppCompatActivity {
private TextInputLayout password_wrapper = null; private TextInputLayout password_wrapper = null;
private String old_password = ""; private String old_password = "";
private Button btn_submit = null; private Button btn_submit = null;
private Button btn_cert_reset = null;
private boolean first_run = false; private boolean first_run = false;
private boolean showNotification = false; private boolean showNotification = false;
private boolean trustSystemCerts = true;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -77,6 +80,29 @@ public class SettingsActivity extends AppCompatActivity {
} }
}); });
trustSystemCerts = preferences.getBoolean("trustSystemCerts", true);
cb = (CheckBox)findViewById(R.id.settings_cert_trust_system);
cb.setChecked(trustSystemCerts);
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("trustSystemCerts", isChecked);
editor.commit();
}
});
btn_cert_reset = (Button) findViewById(R.id.settings_cert_reset);
btn_cert_reset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
CustomCertManager ccm = new CustomCertManager(getApplicationContext(), true);
ccm.resetCertificates();
ccm.close();
Toast.makeText(getApplicationContext(), getString(R.string.settings_cert_reset_toast), Toast.LENGTH_SHORT).show();
}
});
field_url = (EditText) findViewById(R.id.settings_url); field_url = (EditText) findViewById(R.id.settings_url);
field_username = (EditText) findViewById(R.id.settings_username); field_username = (EditText) findViewById(R.id.settings_username);
field_password = (EditText) findViewById(R.id.settings_password); field_password = (EditText) findViewById(R.id.settings_password);
@ -215,7 +241,7 @@ public class SettingsActivity extends AppCompatActivity {
@Override @Override
protected Boolean doInBackground(String... params) { protected Boolean doInBackground(String... params) {
return NotesClientUtil.isValidURL(params[0]); return NotesClientUtil.isValidURL(getApplicationContext(), params[0]);
} }
@Override @Override
@ -251,7 +277,7 @@ public class SettingsActivity extends AppCompatActivity {
url = params[0]; url = params[0];
username = params[1]; username = params[1];
password = params[2]; password = params[2];
return NotesClientUtil.isValidLogin(url, username, password); return NotesClientUtil.isValidLogin(getApplicationContext(), url, username, password);
} }
@Override @Override

View file

@ -222,7 +222,7 @@ public class NoteServerSyncHelper {
if (note.getRemoteId()>0) { if (note.getRemoteId()>0) {
Log.d(getClass().getSimpleName(), " ...try to edit"); Log.d(getClass().getSimpleName(), " ...try to edit");
try { try {
remoteNote = client.editNote(note); remoteNote = client.editNote(appContext, note);
} catch(FileNotFoundException e) { } catch(FileNotFoundException e) {
// Note does not exists anymore // Note does not exists anymore
} }
@ -231,7 +231,7 @@ public class NoteServerSyncHelper {
// Please note, thas dbHelper.updateNote() realizes an optimistic conflict resolution, which is required for parallel changes of this Note from the UI. // Please note, thas dbHelper.updateNote() realizes an optimistic conflict resolution, which is required for parallel changes of this Note from the UI.
if (remoteNote == null) { if (remoteNote == null) {
Log.d(getClass().getSimpleName(), " ...Note does not exist on server -> (re)create"); Log.d(getClass().getSimpleName(), " ...Note does not exist on server -> (re)create");
remoteNote = client.createNote(note); remoteNote = client.createNote(appContext, note);
} }
dbHelper.updateNote(note.getId(), remoteNote, note); dbHelper.updateNote(note.getId(), remoteNote, note);
break; break;
@ -239,7 +239,7 @@ public class NoteServerSyncHelper {
if(note.getRemoteId()>0) { if(note.getRemoteId()>0) {
Log.d(getClass().getSimpleName(), " ...delete (from server and local)"); Log.d(getClass().getSimpleName(), " ...delete (from server and local)");
try { try {
client.deleteNote(note.getRemoteId()); client.deleteNote(appContext, note.getRemoteId());
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.d(getClass().getSimpleName(), " ...Note does not exist on server (anymore?) -> delete locally"); Log.d(getClass().getSimpleName(), " ...Note does not exist on server (anymore?) -> delete locally");
} }
@ -267,7 +267,7 @@ public class NoteServerSyncHelper {
LoginStatus status = null; LoginStatus status = null;
try { try {
Map<Long, Long> idMap = dbHelper.getIdMap(); Map<Long, Long> idMap = dbHelper.getIdMap();
List<CloudNote> remoteNotes = client.getNotes(); List<CloudNote> remoteNotes = client.getNotes(appContext);
Set<Long> remoteIDs = new HashSet<>(); Set<Long> remoteIDs = new HashSet<>();
// pull remote changes: update or create each remote note // pull remote changes: update or create each remote note
for (CloudNote remoteNote : remoteNotes) { for (CloudNote remoteNote : remoteNotes) {

View file

@ -1,5 +1,6 @@
package it.niedermann.owncloud.notes.util; package it.niedermann.owncloud.notes.util;
import android.content.Context;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
@ -13,12 +14,12 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import at.bitfire.cert4android.CustomCertManager;
import it.niedermann.owncloud.notes.model.CloudNote; import it.niedermann.owncloud.notes.model.CloudNote;
public class NotesClient { public class NotesClient {
@ -78,9 +79,9 @@ public class NotesClient {
return new CloudNote(id, modified, title, content, favorite, category, etag); return new CloudNote(id, modified, title, content, favorite, category, etag);
} }
public List<CloudNote> getNotes() throws JSONException, IOException { public List<CloudNote> getNotes(Context ctx) throws JSONException, IOException {
List<CloudNote> notesList = new ArrayList<>(); List<CloudNote> notesList = new ArrayList<>();
JSONArray notes = new JSONArray(requestServer("notes", METHOD_GET, null)); JSONArray notes = new JSONArray(requestServer(ctx, "notes", METHOD_GET, null));
for (int i = 0; i < notes.length(); i++) { for (int i = 0; i < notes.length(); i++) {
JSONObject json = notes.getJSONObject(i); JSONObject json = notes.getJSONObject(i);
notesList.add(getNoteFromJSON(json)); notesList.add(getNoteFromJSON(json));
@ -97,17 +98,17 @@ public class NotesClient {
* @throws IOException * @throws IOException
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public CloudNote getNoteById(long id) throws JSONException, IOException { public CloudNote getNoteById(Context ctx, long id) throws JSONException, IOException {
JSONObject json = new JSONObject(requestServer("notes/" + id, METHOD_GET, null)); JSONObject json = new JSONObject(requestServer(ctx, "notes/" + id, METHOD_GET, null));
return getNoteFromJSON(json); return getNoteFromJSON(json);
} }
private CloudNote putNote(CloudNote note, String path, String method) throws JSONException, IOException { private CloudNote putNote(Context ctx, CloudNote note, String path, String method) throws JSONException, IOException {
JSONObject paramObject = new JSONObject(); JSONObject paramObject = new JSONObject();
paramObject.accumulate(key_content, note.getContent()); paramObject.accumulate(key_content, note.getContent());
paramObject.accumulate(key_modified, note.getModified().getTimeInMillis()/1000); paramObject.accumulate(key_modified, note.getModified().getTimeInMillis()/1000);
paramObject.accumulate(key_favorite, note.isFavorite()); paramObject.accumulate(key_favorite, note.isFavorite());
JSONObject json = new JSONObject(requestServer(path, method, paramObject)); JSONObject json = new JSONObject(requestServer(ctx, path, method, paramObject));
return getNoteFromJSON(json); return getNoteFromJSON(json);
} }
@ -119,17 +120,17 @@ public class NotesClient {
* @throws JSONException * @throws JSONException
* @throws IOException * @throws IOException
*/ */
public CloudNote createNote(CloudNote note) throws JSONException, IOException { public CloudNote createNote(Context ctx, CloudNote note) throws JSONException, IOException {
return putNote(note, "notes", METHOD_POST); return putNote(ctx, note, "notes", METHOD_POST);
} }
public CloudNote editNote(CloudNote note) throws JSONException, IOException { public CloudNote editNote(Context ctx, CloudNote note) throws JSONException, IOException {
return putNote(note, "notes/" + note.getRemoteId(), METHOD_PUT); return putNote(ctx, note, "notes/" + note.getRemoteId(), METHOD_PUT);
} }
public void deleteNote(long noteId) throws public void deleteNote(Context ctx, long noteId) throws
IOException { IOException {
this.requestServer("notes/" + noteId, METHOD_DELETE, null); this.requestServer(ctx, "notes/" + noteId, METHOD_DELETE, null);
} }
/** /**
@ -142,12 +143,13 @@ public class NotesClient {
* @throws MalformedURLException * @throws MalformedURLException
* @throws IOException * @throws IOException
*/ */
private String requestServer(String target, String method, JSONObject params) private String requestServer(Context ctx, String target, String method, JSONObject params)
throws IOException { throws IOException {
StringBuffer result = new StringBuffer(); StringBuffer result = new StringBuffer();
String targetURL = url + "index.php/apps/notes/api/v0.2/" + target; String targetURL = url + "index.php/apps/notes/api/v0.2/" + target;
HttpURLConnection con = (HttpURLConnection) new URL(targetURL) CustomCertManager ccm = SupportUtil.getCertManager(ctx);
.openConnection(); try {
HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, targetURL);
con.setRequestMethod(method); con.setRequestMethod(method);
con.setRequestProperty( con.setRequestProperty(
"Authorization", "Authorization",
@ -156,7 +158,7 @@ public class NotesClient {
Log.d(getClass().getSimpleName(), method + " " + targetURL); Log.d(getClass().getSimpleName(), method + " " + targetURL);
if (params != null) { if (params != null) {
byte[] paramData = params.toString().getBytes(); byte[] paramData = params.toString().getBytes();
Log.d(getClass().getSimpleName(), "Params: "+params); Log.d(getClass().getSimpleName(), "Params: " + params);
con.setFixedLengthStreamingMode(paramData.length); con.setFixedLengthStreamingMode(paramData.length);
con.setRequestProperty("Content-Type", application_json); con.setRequestProperty("Content-Type", application_json);
con.setDoOutput(true); con.setDoOutput(true);
@ -170,6 +172,10 @@ public class NotesClient {
while ((line = rd.readLine()) != null) { while ((line = rd.readLine()) != null) {
result.append(line); result.append(line);
} }
} finally {
ccm.close();
}
return result.toString(); return result.toString();
} }
} }

View file

@ -1,5 +1,6 @@
package it.niedermann.owncloud.notes.util; package it.niedermann.owncloud.notes.util;
import android.content.Context;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
@ -12,8 +13,8 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL;
import at.bitfire.cert4android.CustomCertManager;
import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.R;
/** /**
@ -52,11 +53,11 @@ public class NotesClientUtil {
* @param password String * @param password String
* @return Username and Password are a valid Login-Combination for the given URL. * @return Username and Password are a valid Login-Combination for the given URL.
*/ */
public static LoginStatus isValidLogin(String url, String username, String password) { public static LoginStatus isValidLogin(Context ctx, String url, String username, String password) {
CustomCertManager ccm = SupportUtil.getCertManager(ctx);
try { try {
String targetURL = url + "index.php/apps/notes/api/v0.2/notes"; String targetURL = url + "index.php/apps/notes/api/v0.2/notes";
HttpURLConnection con = (HttpURLConnection) new URL(targetURL) HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, targetURL);
.openConnection();
con.setRequestMethod("GET"); con.setRequestMethod("GET");
con.setRequestProperty( con.setRequestProperty(
"Authorization", "Authorization",
@ -89,6 +90,8 @@ public class NotesClientUtil {
} catch (JSONException e) { } catch (JSONException e) {
Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e);
return LoginStatus.JSON_FAILED; return LoginStatus.JSON_FAILED;
} finally {
ccm.close();
} }
} }
@ -98,11 +101,11 @@ public class NotesClientUtil {
* @param url String URL to server * @param url String URL to server
* @return true if there is a installed instance, false if not * @return true if there is a installed instance, false if not
*/ */
public static boolean isValidURL(String url) { public static boolean isValidURL(Context ctx, String url) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
CustomCertManager ccm = SupportUtil.getCertManager(ctx);
try { try {
HttpURLConnection con = (HttpURLConnection) new URL(url + "status.php") HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, url + "status.php");
.openConnection();
con.setRequestMethod(NotesClient.METHOD_GET); con.setRequestMethod(NotesClient.METHOD_GET);
con.setConnectTimeout(10 * 1000); // 10 seconds con.setConnectTimeout(10 * 1000); // 10 seconds
BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream()));
@ -114,6 +117,8 @@ public class NotesClientUtil {
return response.getBoolean("installed"); return response.getBoolean("installed");
} catch (IOException | JSONException | NullPointerException e) { } catch (IOException | JSONException | NullPointerException e) {
return false; return false;
} finally {
ccm.close();
} }
} }

View file

@ -1,11 +1,28 @@
package it.niedermann.owncloud.notes.util; package it.niedermann.owncloud.notes.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager;
import android.text.Html; import android.text.Html;
import android.text.Spanned; import android.text.Spanned;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.widget.TextView; import android.widget.TextView;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import at.bitfire.cert4android.CustomCertManager;
/** /**
* Some helper functionality in alike the Android support library. * Some helper functionality in alike the Android support library.
* Currently, it offers methods for working with HTML string resources. * Currently, it offers methods for working with HTML string resources.
@ -37,4 +54,37 @@ public class SupportUtil {
view.setText(SupportUtil.fromHtml(view.getResources().getString(stringId, formatArgs))); view.setText(SupportUtil.fromHtml(view.getResources().getString(stringId, formatArgs)));
view.setMovementMethod(LinkMovementMethod.getInstance()); view.setMovementMethod(LinkMovementMethod.getInstance());
} }
/**
* Create a new {@link HttpURLConnection} for strUrl.
* If protocol equals https, then install CustomCertManager in {@link SSLContext}.
* @param ccm
* @param strUrl
* @return HttpURLConnection with custom trust manager
* @throws MalformedURLException
* @throws IOException
*/
public static HttpURLConnection getHttpURLConnection(CustomCertManager ccm, String strUrl) throws MalformedURLException, IOException {
URL url = new URL(strUrl);
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
if (ccm != null && url.getProtocol().equals("https")) {
HttpsURLConnection httpsCon = (HttpsURLConnection) httpCon;
httpsCon.setHostnameVerifier(ccm.hostnameVerifier(httpsCon.getHostnameVerifier()));
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{ccm}, null);
httpsCon.setSSLSocketFactory(sslContext.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
// ignore, use default TrustManager
} catch (KeyManagementException e) {
// ignore, use default TrustManager
}
}
return httpCon;
}
public static CustomCertManager getCertManager(Context ctx) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
return new CustomCertManager(ctx, preferences.getBoolean("trustSystemCerts", true));
}
} }

View file

@ -8,6 +8,14 @@
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp"> android:paddingRight="16dp">
<TextView
android:id="@+id/settings_server_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_server_header"
android:textSize="18sp"
android:textStyle="bold" />
<android.support.design.widget.TextInputLayout <android.support.design.widget.TextInputLayout
android:id="@+id/settings_url_wrapper" android:id="@+id/settings_url_wrapper"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -70,6 +78,15 @@
android:shadowColor="@color/fg_default_low" android:shadowColor="@color/fg_default_low"
android:text="@string/settings_submit" /> android:text="@string/settings_submit" />
<TextView
android:id="@+id/settings_notification_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:text="@string/settings_notification_header"
android:textSize="18sp"
android:textStyle="bold" />
<CheckBox <CheckBox
android:id="@+id/settings_notification" android:id="@+id/settings_notification"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -77,4 +94,25 @@
android:defaultValue="false" android:defaultValue="false"
android:key="notificationCheckbox" android:key="notificationCheckbox"
android:text="@string/settings_notification" /> android:text="@string/settings_notification" />
<TextView
android:id="@+id/settings_cert_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:text="@string/settings_cert_header"
android:textSize="18sp"
android:textStyle="bold" />
<CheckBox
android:id="@+id/settings_cert_trust_system"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_cert_trust_system" />
<Button
android:id="@+id/settings_cert_reset"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_cert_reset" />
</LinearLayout> </LinearLayout>

View file

@ -35,6 +35,7 @@
<string name="listview_updated_earlier">Früher</string> <string name="listview_updated_earlier">Früher</string>
<!-- Settings --> <!-- Settings -->
<string name="settings_server_header">Server Einstellungen</string>
<string name="settings_server">Server</string> <string name="settings_server">Server</string>
<string name="settings_url">Server-Adresse</string> <string name="settings_url">Server-Adresse</string>
<string name="settings_url_check_description">Zeigt an, ob die angegebene URL erreichbar ist.</string> <string name="settings_url_check_description">Zeigt an, ob die angegebene URL erreichbar ist.</string>
@ -44,7 +45,16 @@
<string name="settings_password_check_description">Zeigt an, ob die angegebenen Zugangsdaten korrekt sind.</string> <string name="settings_password_check_description">Zeigt an, ob die angegebenen Zugangsdaten korrekt sind.</string>
<string name="settings_submit">Verbinden</string> <string name="settings_submit">Verbinden</string>
<string name="settings_submitting">Verbindet&#8230;</string> <string name="settings_submitting">Verbindet&#8230;</string>
<string name="settings_notification_header">Benachrichtigung</string>
<string name="settings_notification">Aktivieren, um eine dauerhafte Benachrichtigung zur schnellen Eingabe von Notizen anzuzeigen.</string> <string name="settings_notification">Aktivieren, um eine dauerhafte Benachrichtigung zur schnellen Eingabe von Notizen anzuzeigen.</string>
<string name="settings_cert_header">Zertifikate</string>
<string name="settings_cert_trust_system">Zertifikaten aus System Trust Store vertrauen.</string>
<string name="settings_cert_reset">Bisher akzeptierte/abgelehnte Zertifikate zurücksetzen</string>
<string name="settings_cert_reset_toast">Informationen über Zertifikate zurückgesetzt.</string>
<!-- Certificates -->
<string name="certificate_notification_connection_security">Notizen - Verbindungssicherheit</string>
<string name="trust_certificate_unknown_certificate_found">Der Server nutzt ein unbekanntes Zertifikat. Soll diesem Zertifikat vertraut werden?</string>
<!-- Network --> <!-- Network -->
<string name="network_connecting">Verbinde</string> <string name="network_connecting">Verbinde</string>

View file

@ -35,6 +35,7 @@
<string name="listview_updated_earlier">Früher</string> <string name="listview_updated_earlier">Früher</string>
<!-- Settings --> <!-- Settings -->
<string name="settings_server_header">Server Einstellungen</string>
<string name="settings_server">Server</string> <string name="settings_server">Server</string>
<string name="settings_url">Server-Adresse</string> <string name="settings_url">Server-Adresse</string>
<string name="settings_url_check_description">Zeigt an, ob die angegebene URL erreichbar ist.</string> <string name="settings_url_check_description">Zeigt an, ob die angegebene URL erreichbar ist.</string>
@ -44,7 +45,16 @@
<string name="settings_password_check_description">Zeigt an, ob die angegebenen Zugangsdaten korrekt sind.</string> <string name="settings_password_check_description">Zeigt an, ob die angegebenen Zugangsdaten korrekt sind.</string>
<string name="settings_submit">Verbinden</string> <string name="settings_submit">Verbinden</string>
<string name="settings_submitting">Verbindet&#8230;</string> <string name="settings_submitting">Verbindet&#8230;</string>
<string name="settings_notification_header">Benachrichtigung</string>
<string name="settings_notification">Aktivieren um eine dauerhafte Benachrichtigung zur schnellen Eingabe von Notizen anzuzeigen.</string> <string name="settings_notification">Aktivieren um eine dauerhafte Benachrichtigung zur schnellen Eingabe von Notizen anzuzeigen.</string>
<string name="settings_cert_header">Zertifikate</string>
<string name="settings_cert_trust_system">Zertifikaten aus System Trust Store vertrauen.</string>
<string name="settings_cert_reset">Bisher akzeptierte/abgelehnte Zertifikate zurücksetzen</string>
<string name="settings_cert_reset_toast">Informationen über Zertifikate zurückgesetzt.</string>
<!-- Certificates -->
<string name="certificate_notification_connection_security">Notizen - Verbindungssicherheit</string>
<string name="trust_certificate_unknown_certificate_found">Der Server nutzt ein unbekanntes Zertifikat. Soll diesem Zertifikat vertraut werden?</string>
<!-- Network --> <!-- Network -->
<string name="network_connecting">Verbindung wird hergestellt</string> <string name="network_connecting">Verbindung wird hergestellt</string>

View file

@ -35,6 +35,7 @@
<string name="listview_updated_earlier">Earlier</string> <string name="listview_updated_earlier">Earlier</string>
<!-- Settings --> <!-- Settings -->
<string name="settings_server_header">Server Settings</string>
<string name="settings_server">Server</string> <string name="settings_server">Server</string>
<string name="settings_url">Server address</string> <string name="settings_url">Server address</string>
<string name="settings_url_check_description">Shows if the address can be pinged.</string> <string name="settings_url_check_description">Shows if the address can be pinged.</string>
@ -45,7 +46,16 @@
<string name="settings_password_check_description">Shows if the credentials are correct.</string> <string name="settings_password_check_description">Shows if the credentials are correct.</string>
<string name="settings_submit">Connect</string> <string name="settings_submit">Connect</string>
<string name="settings_submitting">Connecting &#8230;</string> <string name="settings_submitting">Connecting &#8230;</string>
<string name="settings_notification_header">Notification</string>
<string name="settings_notification">Enable to show a persistant notification for quickly creating new notes.</string> <string name="settings_notification">Enable to show a persistant notification for quickly creating new notes.</string>
<string name="settings_cert_header">Certificates</string>
<string name="settings_cert_trust_system">Trust certificates from system trust store.</string>
<string name="settings_cert_reset">Reset trust store</string>
<string name="settings_cert_reset_toast">Stored trust information cleared.</string>
<!-- Certificates -->
<string name="certificate_notification_connection_security">Notes - Connection security</string>
<string name="trust_certificate_unknown_certificate_found">Notes has encountered an unknown certificate. Do you want to trust it?</string>
<!-- Network --> <!-- Network -->
<string name="network_connecting">Connecting</string> <string name="network_connecting">Connecting</string>

View file

@ -13,6 +13,15 @@
<item name="android:windowBackground">@color/bg_normal</item> <item name="android:windowBackground">@color/bg_normal</item>
</style> </style>
<!--
cert4android is using these styles and we want the same button style in the trust activity
-->
<style name="Widget.AppCompat.Button.Borderless" parent="ocbutton">
<item name="android:layout_margin">2dp</item>
</style>
<style name="Widget.AppCompat.Button.Borderless.Colored" parent="Widget.AppCompat.Button.Borderless">
</style>
<style name="fab"> <style name="fab">
<item name="android:layout_margin">16dp</item> <item name="android:layout_margin">16dp</item>
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>

1
cert4android Submodule

@ -0,0 +1 @@
Subproject commit 9033f39d1f541b62750c2bfa9c93a893d6af2f63

View file

@ -1 +1,2 @@
include ':app' include ':app'
include ':cert4android'