Loading app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java +66 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,66 @@ import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.shared.model.Capabilities; import it.niedermann.owncloud.notes.shared.model.IResponseCallback; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.http.SslCertificate; import android.net.http.SslError; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.webkit.SslErrorHandler; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import foundation.e.cert4android.CustomCertManager; import foundation.e.cert4android.IOnCertificateDecision; import butterknife.BindView; import butterknife.ButterKnife; import foundation.e.notes.R; import foundation.e.notes.persistence.NoteSQLiteOpenHelper; import foundation.e.notes.persistence.NoteServerSyncHelper; import foundation.e.notes.util.ExceptionHandler; import foundation.e.notes.util.NotesClientUtil; import foundation.e.notes.util.NotesClientUtil.LoginStatus; import androidx.annotation.ColorInt; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.textfield.TextInputLayout; import java.io.ByteArrayInputStream; import java.net.URLDecoder; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Locale; import java.util.Map; import static android.os.Process.killProcess; import static android.os.Process.myPid; public class ImportAccountActivity extends AppCompatActivity { Loading Loading @@ -111,6 +171,12 @@ public class ImportAccountActivity extends AppCompatActivity { } }); binding.addButton1.setOnClickListener((v) -> { binding.addButton1.setEnabled(false); binding.status.setVisibility(View.GONE); } } Loading app/src/main/java/it/niedermann/owncloud/notes/shared/util/NotesClient.java 0 → 100644 +189 −0 Original line number Diff line number Diff line package it.niedermann.owncloud.notes.shared.util; import androidx.annotation.WorkerThread; import android.util.Base64; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import foundation.e.cert4android.CustomCertManager; import foundation.e.notes.model.CloudNote; import foundation.e.notes.BuildConfig; import foundation.e.notes.model.CloudNote; import foundation.e.notes.util.ServerResponse.NoteResponse; import foundation.e.notes.util.ServerResponse.NotesResponse; @WorkerThread public class NotesClient { /** * This entity class is used to return relevant data of the HTTP reponse. */ public static class ResponseData { private final String content; private final String etag; private final long lastModified; public ResponseData(String content, String etag, long lastModified) { this.content = content; this.etag = etag; this.lastModified = lastModified; } public String getContent() { return content; } public String getETag() { return etag; } public long getLastModified() { return lastModified; } } public static final String METHOD_GET = "GET"; public static final String METHOD_PUT = "PUT"; public static final String METHOD_POST = "POST"; public static final String METHOD_DELETE = "DELETE"; public static final String JSON_ID = "id"; public static final String JSON_TITLE = "title"; public static final String JSON_CONTENT = "content"; public static final String JSON_FAVORITE = "favorite"; public static final String JSON_CATEGORY = "category"; public static final String JSON_ETAG = "etag"; public static final String JSON_MODIFIED = "modified"; private static final String application_json = "application/json"; private String url = ""; private String username = ""; private String password = ""; public NotesClient(String url, String username, String password) { this.url = url; this.username = username; this.password = password; } public NotesResponse getNotes(CustomCertManager ccm, long lastModified, String lastETag) throws JSONException, IOException { String url = "notes"; if (lastModified > 0) { url += "?pruneBefore=" + lastModified; } return new NotesResponse(requestServer(ccm, url, METHOD_GET, null, lastETag)); } /** * Fetches a Note by ID from Server * * @param id long - ID of the wanted note * @return Requested Note * @throws JSONException * @throws IOException */ @SuppressWarnings("unused") public NoteResponse getNoteById(CustomCertManager ccm, long id) throws JSONException, IOException { return new NoteResponse(requestServer(ccm, "notes/" + id, METHOD_GET, null, null)); } private NoteResponse putNote(CustomCertManager ccm, CloudNote note, String path, String method) throws JSONException, IOException { JSONObject paramObject = new JSONObject(); paramObject.accumulate(JSON_CONTENT, note.getContent()); paramObject.accumulate(JSON_MODIFIED, note.getModified().getTimeInMillis() / 1000); paramObject.accumulate(JSON_FAVORITE, note.isFavorite()); paramObject.accumulate(JSON_CATEGORY, note.getCategory()); return new NoteResponse(requestServer(ccm, path, method, paramObject, null)); } /** * Creates a Note on the Server * * @param note {@link CloudNote} - the new Note * @return Created Note including generated Title, ID and lastModified-Date * @throws JSONException * @throws IOException */ public NoteResponse createNote(CustomCertManager ccm, CloudNote note) throws JSONException, IOException { return putNote(ccm, note, "notes", METHOD_POST); } public NoteResponse editNote(CustomCertManager ccm, CloudNote note) throws JSONException, IOException { return putNote(ccm, note, "notes/" + note.getRemoteId(), METHOD_PUT); } public void deleteNote(CustomCertManager ccm, long noteId) throws IOException { this.requestServer(ccm, "notes/" + noteId, METHOD_DELETE, null, null); } /** * Request-Method for POST, PUT with or without JSON-Object-Parameter * * @param target Filepath to the wanted function * @param method GET, POST, DELETE or PUT * @param params JSON Object which shall be transferred to the server. * @return Body of answer * @throws MalformedURLException * @throws IOException */ private ResponseData requestServer(CustomCertManager ccm, String target, String method, JSONObject params, String lastETag) throws IOException { StringBuffer result = new StringBuffer(); // setup connection String targetURL = url + "index.php/apps/notes/api/v0.2/" + target; HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, targetURL); con.setRequestMethod(method); con.setRequestProperty( "Authorization", "Basic " + Base64.encodeToString((username + ":" + password).getBytes(), Base64.NO_WRAP)); // https://github.com/square/retrofit/issues/805#issuecomment-93426183 con.setRequestProperty( "Connection", "Close"); con.setRequestProperty("User-Agent", "nextcloud-notes/" + BuildConfig.VERSION_NAME + " (Android)"); if (lastETag != null && METHOD_GET.equals(method)) { con.setRequestProperty("If-None-Match", lastETag); } con.setConnectTimeout(10 * 1000); // 10 seconds Log.d(getClass().getSimpleName(), method + " " + targetURL); // send request data (optional) byte[] paramData = null; if (params != null) { paramData = params.toString().getBytes(); Log.d(getClass().getSimpleName(), "Params: " + params); con.setFixedLengthStreamingMode(paramData.length); con.setRequestProperty("Content-Type", application_json); con.setDoOutput(true); OutputStream os = con.getOutputStream(); os.write(paramData); os.flush(); os.close(); } // read response data int responseCode = con.getResponseCode(); Log.d(getClass().getSimpleName(), "HTTP response code: " + responseCode); if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) { throw new ServerResponse.NotModifiedException(); } BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } // create response object String etag = con.getHeaderField("ETag"); long lastModified = con.getHeaderFieldDate("Last-Modified", 0) / 1000; Log.i(getClass().getSimpleName(), "Result length: " + result.length() + (paramData == null ? "" : "; Request length: " + paramData.length)); Log.d(getClass().getSimpleName(), "ETag: " + etag + "; Last-Modified: " + lastModified + " (" + con.getHeaderField("Last-Modified") + ")"); // return these header fields since they should only be saved after successful processing the result! return new ResponseData(result.toString(), etag, lastModified); } } app/src/main/java/it/niedermann/owncloud/notes/shared/util/NotesClientUtil.java 0 → 100644 +149 −0 Original line number Diff line number Diff line package it.niedermann.owncloud.notes.shared.util; import androidx.annotation.StringRes; import android.util.Base64; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.SocketTimeoutException; import foundation.e.cert4android.CustomCertManager; import foundation.e.notes.R; /** * Utils for Validation etc * Created by stefan on 25.09.15. */ public class NotesClientUtil { public enum LoginStatus { OK(0), AUTH_FAILED(R.string.error_username_password_invalid), CONNECTION_FAILED(R.string.error_io), NO_NETWORK(R.string.error_no_network), JSON_FAILED(R.string.error_json), SERVER_FAILED(R.string.error_server); @StringRes public final int str; LoginStatus(@StringRes int str) { this.str = str; } } /** * Checks if the given url String starts with http:// or https:// * * @param url String * @return true, if the given String is only http */ public static boolean isHttp(String url) { return url != null && url.length() > 4 && url.startsWith("http") && url.charAt(4) != 's'; } /** * Strips the api part from the path of a given url, handles trailing slash and missing protocol * * @param url String * @return formatted URL */ public static String formatURL(String url) { if (!url.endsWith("/")) { url += "/"; } if (!url.startsWith("http://") && !url.startsWith("https://")) { url = "https://" + url; } String[] replacements = new String[]{"notes/", "v0.2/", "api/", "notes/", "apps/", "index.php/"}; for (String replacement : replacements) { if (url.endsWith(replacement)) { url = url.substring(0, url.length() - replacement.length()); } } return url; } /** * @param url String * @param username String * @param password String * @return Username and Password are a valid Login-Combination for the given URL. */ public static LoginStatus isValidLogin(CustomCertManager ccm, String url, String username, String password) { try { String targetURL = url + "index.php/apps/notes/api/v0.2/notes"; HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, targetURL); con.setRequestMethod("GET"); con.setRequestProperty( "Authorization", "Basic " + new String(Base64.encode((username + ":" + password).getBytes(), Base64.NO_WRAP))); con.setConnectTimeout(10 * 1000); // 10 seconds con.connect(); Log.v(NotesClientUtil.class.getSimpleName(), "Establishing connection to server"); if (con.getResponseCode() == 200) { Log.v(NotesClientUtil.class.getSimpleName(), "" + con.getResponseMessage()); StringBuilder result = new StringBuilder(); BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } Log.v(NotesClientUtil.class.getSimpleName(), result.toString()); new JSONArray(result.toString()); return LoginStatus.OK; } else if (con.getResponseCode() >= 401 && con.getResponseCode() <= 403) { return LoginStatus.AUTH_FAILED; } else { return LoginStatus.SERVER_FAILED; } } catch (MalformedURLException | SocketTimeoutException e) { Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); return LoginStatus.CONNECTION_FAILED; } catch (IOException e) { Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); return LoginStatus.CONNECTION_FAILED; } catch (JSONException e) { Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); return LoginStatus.JSON_FAILED; } } /** * Pings a server and checks if there is a installed ownCloud instance * * @param url String URL to server * @return true if there is a installed instance, false if not */ public static boolean isValidURL(CustomCertManager ccm, String url) { StringBuilder result = new StringBuilder(); try { HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, url + "status.php"); con.setRequestMethod(NotesClient.METHOD_GET); con.setConnectTimeout(10 * 1000); // 10 seconds BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } JSONObject response = new JSONObject(result.toString()); return response.getBoolean("installed"); } catch (IOException | JSONException | NullPointerException e) { return false; } } } app/src/main/java/it/niedermann/owncloud/notes/shared/util/ServerResponse.java 0 → 100644 +101 −0 Original line number Diff line number Diff line package it.niedermann.owncloud.notes.shared.util; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; import foundation.e.notes.model.CloudNote; import foundation.e.notes.model.CloudNote; /** * Provides entity classes for handling server responses with a single note ({@link NoteResponse}) or a list of notes ({@link NotesResponse}). */ public class ServerResponse { public static class NotModifiedException extends IOException { } public static class NoteResponse extends ServerResponse { public NoteResponse(NotesClient.ResponseData response) { super(response); } public CloudNote getNote() throws JSONException { return getNoteFromJSON(new JSONObject(getContent())); } } public static class NotesResponse extends ServerResponse { public NotesResponse(NotesClient.ResponseData response) { super(response); } public List<CloudNote> getNotes() throws JSONException { List<CloudNote> notesList = new ArrayList<>(); JSONArray notes = new JSONArray(getContent()); for (int i = 0; i < notes.length(); i++) { JSONObject json = notes.getJSONObject(i); notesList.add(getNoteFromJSON(json)); } return notesList; } } private final NotesClient.ResponseData response; public ServerResponse(NotesClient.ResponseData response) { this.response = response; } protected String getContent() { return response.getContent(); } public String getETag() { return response.getETag(); } public long getLastModified() { return response.getLastModified(); } protected CloudNote getNoteFromJSON(JSONObject json) throws JSONException { long id = 0; String title = ""; String content = ""; Calendar modified = null; boolean favorite = false; String category = null; String etag = null; if (!json.isNull(NotesClient.JSON_ID)) { id = json.getLong(NotesClient.JSON_ID); } if (!json.isNull(NotesClient.JSON_TITLE)) { title = json.getString(NotesClient.JSON_TITLE); } if (!json.isNull(NotesClient.JSON_CONTENT)) { content = json.getString(NotesClient.JSON_CONTENT); } if (!json.isNull(NotesClient.JSON_MODIFIED)) { modified = GregorianCalendar.getInstance(); modified.setTimeInMillis(json.getLong(NotesClient.JSON_MODIFIED) * 1000); } if (!json.isNull(NotesClient.JSON_FAVORITE)) { favorite = json.getBoolean(NotesClient.JSON_FAVORITE); } if (!json.isNull(NotesClient.JSON_CATEGORY)) { category = json.getString(NotesClient.JSON_CATEGORY); } if (!json.isNull(NotesClient.JSON_ETAG)) { etag = json.getString(NotesClient.JSON_ETAG); } return new CloudNote(id, modified, title, content, favorite, category, etag); } } Loading
app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java +66 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,66 @@ import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.shared.model.Capabilities; import it.niedermann.owncloud.notes.shared.model.IResponseCallback; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.http.SslCertificate; import android.net.http.SslError; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.webkit.SslErrorHandler; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import foundation.e.cert4android.CustomCertManager; import foundation.e.cert4android.IOnCertificateDecision; import butterknife.BindView; import butterknife.ButterKnife; import foundation.e.notes.R; import foundation.e.notes.persistence.NoteSQLiteOpenHelper; import foundation.e.notes.persistence.NoteServerSyncHelper; import foundation.e.notes.util.ExceptionHandler; import foundation.e.notes.util.NotesClientUtil; import foundation.e.notes.util.NotesClientUtil.LoginStatus; import androidx.annotation.ColorInt; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.textfield.TextInputLayout; import java.io.ByteArrayInputStream; import java.net.URLDecoder; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Locale; import java.util.Map; import static android.os.Process.killProcess; import static android.os.Process.myPid; public class ImportAccountActivity extends AppCompatActivity { Loading Loading @@ -111,6 +171,12 @@ public class ImportAccountActivity extends AppCompatActivity { } }); binding.addButton1.setOnClickListener((v) -> { binding.addButton1.setEnabled(false); binding.status.setVisibility(View.GONE); } } Loading
app/src/main/java/it/niedermann/owncloud/notes/shared/util/NotesClient.java 0 → 100644 +189 −0 Original line number Diff line number Diff line package it.niedermann.owncloud.notes.shared.util; import androidx.annotation.WorkerThread; import android.util.Base64; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import foundation.e.cert4android.CustomCertManager; import foundation.e.notes.model.CloudNote; import foundation.e.notes.BuildConfig; import foundation.e.notes.model.CloudNote; import foundation.e.notes.util.ServerResponse.NoteResponse; import foundation.e.notes.util.ServerResponse.NotesResponse; @WorkerThread public class NotesClient { /** * This entity class is used to return relevant data of the HTTP reponse. */ public static class ResponseData { private final String content; private final String etag; private final long lastModified; public ResponseData(String content, String etag, long lastModified) { this.content = content; this.etag = etag; this.lastModified = lastModified; } public String getContent() { return content; } public String getETag() { return etag; } public long getLastModified() { return lastModified; } } public static final String METHOD_GET = "GET"; public static final String METHOD_PUT = "PUT"; public static final String METHOD_POST = "POST"; public static final String METHOD_DELETE = "DELETE"; public static final String JSON_ID = "id"; public static final String JSON_TITLE = "title"; public static final String JSON_CONTENT = "content"; public static final String JSON_FAVORITE = "favorite"; public static final String JSON_CATEGORY = "category"; public static final String JSON_ETAG = "etag"; public static final String JSON_MODIFIED = "modified"; private static final String application_json = "application/json"; private String url = ""; private String username = ""; private String password = ""; public NotesClient(String url, String username, String password) { this.url = url; this.username = username; this.password = password; } public NotesResponse getNotes(CustomCertManager ccm, long lastModified, String lastETag) throws JSONException, IOException { String url = "notes"; if (lastModified > 0) { url += "?pruneBefore=" + lastModified; } return new NotesResponse(requestServer(ccm, url, METHOD_GET, null, lastETag)); } /** * Fetches a Note by ID from Server * * @param id long - ID of the wanted note * @return Requested Note * @throws JSONException * @throws IOException */ @SuppressWarnings("unused") public NoteResponse getNoteById(CustomCertManager ccm, long id) throws JSONException, IOException { return new NoteResponse(requestServer(ccm, "notes/" + id, METHOD_GET, null, null)); } private NoteResponse putNote(CustomCertManager ccm, CloudNote note, String path, String method) throws JSONException, IOException { JSONObject paramObject = new JSONObject(); paramObject.accumulate(JSON_CONTENT, note.getContent()); paramObject.accumulate(JSON_MODIFIED, note.getModified().getTimeInMillis() / 1000); paramObject.accumulate(JSON_FAVORITE, note.isFavorite()); paramObject.accumulate(JSON_CATEGORY, note.getCategory()); return new NoteResponse(requestServer(ccm, path, method, paramObject, null)); } /** * Creates a Note on the Server * * @param note {@link CloudNote} - the new Note * @return Created Note including generated Title, ID and lastModified-Date * @throws JSONException * @throws IOException */ public NoteResponse createNote(CustomCertManager ccm, CloudNote note) throws JSONException, IOException { return putNote(ccm, note, "notes", METHOD_POST); } public NoteResponse editNote(CustomCertManager ccm, CloudNote note) throws JSONException, IOException { return putNote(ccm, note, "notes/" + note.getRemoteId(), METHOD_PUT); } public void deleteNote(CustomCertManager ccm, long noteId) throws IOException { this.requestServer(ccm, "notes/" + noteId, METHOD_DELETE, null, null); } /** * Request-Method for POST, PUT with or without JSON-Object-Parameter * * @param target Filepath to the wanted function * @param method GET, POST, DELETE or PUT * @param params JSON Object which shall be transferred to the server. * @return Body of answer * @throws MalformedURLException * @throws IOException */ private ResponseData requestServer(CustomCertManager ccm, String target, String method, JSONObject params, String lastETag) throws IOException { StringBuffer result = new StringBuffer(); // setup connection String targetURL = url + "index.php/apps/notes/api/v0.2/" + target; HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, targetURL); con.setRequestMethod(method); con.setRequestProperty( "Authorization", "Basic " + Base64.encodeToString((username + ":" + password).getBytes(), Base64.NO_WRAP)); // https://github.com/square/retrofit/issues/805#issuecomment-93426183 con.setRequestProperty( "Connection", "Close"); con.setRequestProperty("User-Agent", "nextcloud-notes/" + BuildConfig.VERSION_NAME + " (Android)"); if (lastETag != null && METHOD_GET.equals(method)) { con.setRequestProperty("If-None-Match", lastETag); } con.setConnectTimeout(10 * 1000); // 10 seconds Log.d(getClass().getSimpleName(), method + " " + targetURL); // send request data (optional) byte[] paramData = null; if (params != null) { paramData = params.toString().getBytes(); Log.d(getClass().getSimpleName(), "Params: " + params); con.setFixedLengthStreamingMode(paramData.length); con.setRequestProperty("Content-Type", application_json); con.setDoOutput(true); OutputStream os = con.getOutputStream(); os.write(paramData); os.flush(); os.close(); } // read response data int responseCode = con.getResponseCode(); Log.d(getClass().getSimpleName(), "HTTP response code: " + responseCode); if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) { throw new ServerResponse.NotModifiedException(); } BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } // create response object String etag = con.getHeaderField("ETag"); long lastModified = con.getHeaderFieldDate("Last-Modified", 0) / 1000; Log.i(getClass().getSimpleName(), "Result length: " + result.length() + (paramData == null ? "" : "; Request length: " + paramData.length)); Log.d(getClass().getSimpleName(), "ETag: " + etag + "; Last-Modified: " + lastModified + " (" + con.getHeaderField("Last-Modified") + ")"); // return these header fields since they should only be saved after successful processing the result! return new ResponseData(result.toString(), etag, lastModified); } }
app/src/main/java/it/niedermann/owncloud/notes/shared/util/NotesClientUtil.java 0 → 100644 +149 −0 Original line number Diff line number Diff line package it.niedermann.owncloud.notes.shared.util; import androidx.annotation.StringRes; import android.util.Base64; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.SocketTimeoutException; import foundation.e.cert4android.CustomCertManager; import foundation.e.notes.R; /** * Utils for Validation etc * Created by stefan on 25.09.15. */ public class NotesClientUtil { public enum LoginStatus { OK(0), AUTH_FAILED(R.string.error_username_password_invalid), CONNECTION_FAILED(R.string.error_io), NO_NETWORK(R.string.error_no_network), JSON_FAILED(R.string.error_json), SERVER_FAILED(R.string.error_server); @StringRes public final int str; LoginStatus(@StringRes int str) { this.str = str; } } /** * Checks if the given url String starts with http:// or https:// * * @param url String * @return true, if the given String is only http */ public static boolean isHttp(String url) { return url != null && url.length() > 4 && url.startsWith("http") && url.charAt(4) != 's'; } /** * Strips the api part from the path of a given url, handles trailing slash and missing protocol * * @param url String * @return formatted URL */ public static String formatURL(String url) { if (!url.endsWith("/")) { url += "/"; } if (!url.startsWith("http://") && !url.startsWith("https://")) { url = "https://" + url; } String[] replacements = new String[]{"notes/", "v0.2/", "api/", "notes/", "apps/", "index.php/"}; for (String replacement : replacements) { if (url.endsWith(replacement)) { url = url.substring(0, url.length() - replacement.length()); } } return url; } /** * @param url String * @param username String * @param password String * @return Username and Password are a valid Login-Combination for the given URL. */ public static LoginStatus isValidLogin(CustomCertManager ccm, String url, String username, String password) { try { String targetURL = url + "index.php/apps/notes/api/v0.2/notes"; HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, targetURL); con.setRequestMethod("GET"); con.setRequestProperty( "Authorization", "Basic " + new String(Base64.encode((username + ":" + password).getBytes(), Base64.NO_WRAP))); con.setConnectTimeout(10 * 1000); // 10 seconds con.connect(); Log.v(NotesClientUtil.class.getSimpleName(), "Establishing connection to server"); if (con.getResponseCode() == 200) { Log.v(NotesClientUtil.class.getSimpleName(), "" + con.getResponseMessage()); StringBuilder result = new StringBuilder(); BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } Log.v(NotesClientUtil.class.getSimpleName(), result.toString()); new JSONArray(result.toString()); return LoginStatus.OK; } else if (con.getResponseCode() >= 401 && con.getResponseCode() <= 403) { return LoginStatus.AUTH_FAILED; } else { return LoginStatus.SERVER_FAILED; } } catch (MalformedURLException | SocketTimeoutException e) { Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); return LoginStatus.CONNECTION_FAILED; } catch (IOException e) { Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); return LoginStatus.CONNECTION_FAILED; } catch (JSONException e) { Log.e(NotesClientUtil.class.getSimpleName(), "Exception", e); return LoginStatus.JSON_FAILED; } } /** * Pings a server and checks if there is a installed ownCloud instance * * @param url String URL to server * @return true if there is a installed instance, false if not */ public static boolean isValidURL(CustomCertManager ccm, String url) { StringBuilder result = new StringBuilder(); try { HttpURLConnection con = SupportUtil.getHttpURLConnection(ccm, url + "status.php"); con.setRequestMethod(NotesClient.METHOD_GET); con.setConnectTimeout(10 * 1000); // 10 seconds BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); } JSONObject response = new JSONObject(result.toString()); return response.getBoolean("installed"); } catch (IOException | JSONException | NullPointerException e) { return false; } } }
app/src/main/java/it/niedermann/owncloud/notes/shared/util/ServerResponse.java 0 → 100644 +101 −0 Original line number Diff line number Diff line package it.niedermann.owncloud.notes.shared.util; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; import foundation.e.notes.model.CloudNote; import foundation.e.notes.model.CloudNote; /** * Provides entity classes for handling server responses with a single note ({@link NoteResponse}) or a list of notes ({@link NotesResponse}). */ public class ServerResponse { public static class NotModifiedException extends IOException { } public static class NoteResponse extends ServerResponse { public NoteResponse(NotesClient.ResponseData response) { super(response); } public CloudNote getNote() throws JSONException { return getNoteFromJSON(new JSONObject(getContent())); } } public static class NotesResponse extends ServerResponse { public NotesResponse(NotesClient.ResponseData response) { super(response); } public List<CloudNote> getNotes() throws JSONException { List<CloudNote> notesList = new ArrayList<>(); JSONArray notes = new JSONArray(getContent()); for (int i = 0; i < notes.length(); i++) { JSONObject json = notes.getJSONObject(i); notesList.add(getNoteFromJSON(json)); } return notesList; } } private final NotesClient.ResponseData response; public ServerResponse(NotesClient.ResponseData response) { this.response = response; } protected String getContent() { return response.getContent(); } public String getETag() { return response.getETag(); } public long getLastModified() { return response.getLastModified(); } protected CloudNote getNoteFromJSON(JSONObject json) throws JSONException { long id = 0; String title = ""; String content = ""; Calendar modified = null; boolean favorite = false; String category = null; String etag = null; if (!json.isNull(NotesClient.JSON_ID)) { id = json.getLong(NotesClient.JSON_ID); } if (!json.isNull(NotesClient.JSON_TITLE)) { title = json.getString(NotesClient.JSON_TITLE); } if (!json.isNull(NotesClient.JSON_CONTENT)) { content = json.getString(NotesClient.JSON_CONTENT); } if (!json.isNull(NotesClient.JSON_MODIFIED)) { modified = GregorianCalendar.getInstance(); modified.setTimeInMillis(json.getLong(NotesClient.JSON_MODIFIED) * 1000); } if (!json.isNull(NotesClient.JSON_FAVORITE)) { favorite = json.getBoolean(NotesClient.JSON_FAVORITE); } if (!json.isNull(NotesClient.JSON_CATEGORY)) { category = json.getString(NotesClient.JSON_CATEGORY); } if (!json.isNull(NotesClient.JSON_ETAG)) { etag = json.getString(NotesClient.JSON_ETAG); } return new CloudNote(id, modified, title, content, favorite, category, etag); } }