-
-
Save biblioeteca/435045d15607eeae3bfb55696cdbbc91 to your computer and use it in GitHub Desktop.
Chrome `79.0.3945.79` update hotfix to rescue user data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Licensed to the Apache Software Foundation (ASF) under one | |
or more contributor license agreements. See the NOTICE file | |
distributed with this work for additional information | |
regarding copyright ownership. The ASF licenses this file | |
to you 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.biblioeteca.apps.NoMorePass; | |
import android.annotation.TargetApi; | |
import android.app.AlertDialog; | |
import android.content.pm.PackageInfo; | |
import android.content.pm.PackageManager; | |
import android.os.Build; | |
import android.os.Bundle; | |
import androidx.core.content.ContextCompat; | |
import android.view.Window; | |
import android.view.WindowManager; | |
import android.webkit.WebView; | |
import android.widget.Toast; | |
import org.apache.cordova.CordovaActivity; | |
import org.apache.cordova.LOG; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.OutputStream; | |
public class MainActivity extends CordovaActivity { | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
// enable Cordova apps to be started in the background | |
Bundle extras = getIntent().getExtras(); | |
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) { | |
moveTaskToBack(true); | |
} | |
// 2019-12-14, dom: workaround for chrome v79 update disaster | |
if (_isIssue1033655()) { | |
_tryToSaveUserData(() -> { | |
loadUrl(launchUrl); | |
}); | |
} else { | |
// Set by <content src="index.html" /> in config.xml | |
loadUrl(launchUrl); | |
} | |
} | |
private boolean _isIssue1033655() { | |
String userAgent = new WebView(getApplicationContext()).getSettings().getUserAgentString(); | |
return userAgent.contains("Chrome/79.0.3945.79"); | |
} | |
private void _tryToSaveUserData(Runnable next) { | |
String appPath = getApplicationInfo().dataDir; | |
File databaseOld = new File(appPath.concat("/app_webview/databases/file__0/1")); | |
File databaseBk = new File(appPath.concat("/app_webview/databases.bak")); | |
File databaseNew = new File(appPath.concat("/app_webview/Default/databases/file__0/1")); | |
// nichts tun, falls keine alte Datenbank existiert | |
if (!databaseOld.exists()) { | |
// Two cases: | |
// 1.- New app installations with v79 in place | |
// 2.- Patched version... In any case we will copy back the files | |
_copyUserDataToRoot(); | |
next.run(); | |
return; | |
} | |
// falls die neuen Daten noch nicht vorhanden sind, die Daten kopieren | |
if (!databaseNew.exists()) { | |
_migrateUserDataToDefault(); | |
next.run(); | |
return; | |
} | |
// At this point 2 possible options: | |
// 1.- Already patched version with root again in place | |
// 2.- Affected by the bug and not patched at all (need to ask) | |
if (databaseBk.exists()){ | |
// Already patched | |
next.run(); | |
return; | |
} | |
new AlertDialog.Builder(this) | |
.setTitle("¿Recuperacion de datos?") | |
.setIcon(android.R.drawable.ic_dialog_alert) | |
.setMessage("Debido a un error en la actualización de Google Chrome 79, las contraseñas introducidas ya no se encontrarán.\n Si introdujo nuevas contraseñas después de la pérdida de datos, serán borrados. ¿Deberíamos intentarlo?") | |
.setPositiveButton("Si", (dialog, which) -> { | |
_migrateUserDataToDefault(); | |
next.run(); | |
}) | |
.setNegativeButton("No", ((dialog, which) -> { | |
_lastQuestion(next); | |
})) | |
.setCancelable(false) | |
.show(); | |
} | |
private void _lastQuestion(Runnable next) { | |
new AlertDialog.Builder(this) | |
.setTitle("¿Estás seguro?") | |
.setIcon(android.R.drawable.ic_dialog_alert) | |
.setMessage("Si elige \"No preguntar más\", sus datos anteriores no podrán ser restaurados.") | |
.setPositiveButton("Si", (dialog, which) -> { | |
showToast( | |
"Puede decidir de nuevo en el próximo reinicio si desea restaurar sus datos anteriores.", | |
Toast.LENGTH_LONG | |
); | |
next.run(); | |
}) | |
.setNegativeButton("No preguntar más", (dialog, which) -> { | |
_renameOldData(); | |
showToast("Ha decidido no restaurar sus datos anteriores.", Toast.LENGTH_LONG); | |
next.run(); | |
}) | |
.show(); | |
} | |
private void _migrateUserDataToDefault() { | |
String appPath = getApplicationInfo().dataDir; | |
try { | |
copyRecursive(new File(appPath, "/app_webview/databases/"), new File(appPath, "/app_webview/Default/databases/")); | |
copyRecursive(new File(appPath, "/app_webview/Local Storage/"), new File(appPath, "/app_webview/Default/Local Storage/")); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
showToast("Lo siento, no se pudieron copiar datos."); | |
} | |
_renameOldData(); | |
showToast("Se han restaurado sus contraseñas anteriores.", Toast.LENGTH_LONG); | |
} | |
private void _copyUserDataToRoot() { | |
String appPath = getApplicationInfo().dataDir; | |
try { | |
copyRecursive(new File(appPath, "/app_webview/Default/databases/"), new File(appPath, "/app_webview/databases/")); | |
copyRecursive(new File(appPath, "/app_webview/Default/Local Storage/"), new File(appPath, "/app_webview/Local Storage/")); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
showToast("Lo siento, no se pudieron copiar datos."); | |
} | |
_renameOldData(); | |
} | |
private void showToast(String message) { | |
showToast(message, Toast.LENGTH_SHORT); | |
} | |
private void showToast(String message, int duration) { | |
Toast.makeText(getApplicationContext(), message, duration).show(); | |
} | |
/** | |
* @param source | |
* @param target | |
* | |
* @throws IOException | |
* | |
* @see <https://www.androidcode.ninja/copy-or-move-file-from-one-directory-to/> for the idea | |
*/ | |
private void copyRecursive(File source, File target) throws IOException { | |
if (source.isDirectory()) { | |
if (!target.exists()) { | |
target.mkdirs(); | |
} | |
String[] children = source.list(); | |
for (String child : children) { | |
copyRecursive(new File(source, child), new File(target, child)); | |
} | |
} else { | |
InputStream in = new FileInputStream(source); | |
OutputStream out = new FileOutputStream(target); | |
byte[] buffer = new byte[1024]; | |
int length; | |
while ((length = in.read(buffer)) > 0) { | |
out.write(buffer, 0, length); | |
} | |
in.close(); | |
out.close(); | |
} | |
} | |
private void _renameOldData() { | |
String appPath = getApplicationInfo().dataDir; | |
renameFile(appPath, "/app_webview/databases", "/app_webview/databases.bak"); | |
renameFile(appPath, "/app_webview/Local Storage", "/app_webview/Local Storage.bak"); | |
} | |
private void renameFile(String basePath, String nameOld, String nameNew) { | |
new File(basePath, nameOld).renameTo(new File(basePath, nameNew)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment