mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-22 14:59:14 +00:00
Merge pull request #106 from alexbakker/feature-import-freeotp+
Add support for importing from FreeOTP+
This commit is contained in:
commit
6769fefd00
10 changed files with 221 additions and 132 deletions
|
@ -32,6 +32,7 @@ public class AegisImporter extends DatabaseImporter {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public State read(FileReader reader) throws DatabaseImporterException {
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = reader.readAll();
|
byte[] bytes = reader.readAll();
|
||||||
|
|
|
@ -50,6 +50,7 @@ public class AndOtpImporter extends DatabaseImporter {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public State read(FileReader reader) throws DatabaseImporterException {
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
try {
|
try {
|
||||||
|
@ -110,6 +111,7 @@ public class AndOtpImporter extends DatabaseImporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void decrypt(Context context, DecryptListener listener) {
|
public void decrypt(Context context, DecryptListener listener) {
|
||||||
Dialogs.showPasswordInputDialog(context, password -> {
|
Dialogs.showPasswordInputDialog(context, password -> {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import com.beemdevelopment.aegis.encoding.Base32Exception;
|
||||||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
import com.beemdevelopment.aegis.otp.OtpInfo;
|
||||||
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
||||||
import com.beemdevelopment.aegis.otp.TotpInfo;
|
import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||||
|
import com.beemdevelopment.aegis.util.PreferenceParser;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
@ -36,6 +37,7 @@ public class AuthyImporter extends DatabaseImporter {
|
||||||
return _subPath;
|
return _subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public State read(FileReader reader) throws DatabaseImporterException {
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
try {
|
try {
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
XmlPullParser parser = Xml.newPullParser();
|
||||||
|
@ -43,8 +45,14 @@ public class AuthyImporter extends DatabaseImporter {
|
||||||
parser.setInput(reader.getStream(), null);
|
parser.setInput(reader.getStream(), null);
|
||||||
parser.nextTag();
|
parser.nextTag();
|
||||||
|
|
||||||
JSONArray entries = parse(parser);
|
JSONArray array = new JSONArray();
|
||||||
return new State(entries);
|
for (PreferenceParser.XmlEntry entry : PreferenceParser.parse(parser)) {
|
||||||
|
if (entry.Name.equals("com.authy.storage.tokens.authenticator.key")) {
|
||||||
|
array = new JSONArray(entry.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new State(array);
|
||||||
} catch (XmlPullParserException | JSONException | IOException e) {
|
} catch (XmlPullParserException | JSONException | IOException e) {
|
||||||
throw new DatabaseImporterException(e);
|
throw new DatabaseImporterException(e);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +66,6 @@ public class AuthyImporter extends DatabaseImporter {
|
||||||
_obj = obj;
|
_obj = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result convert() throws DatabaseImporterException {
|
public Result convert() throws DatabaseImporterException {
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
|
@ -117,72 +124,6 @@ public class AuthyImporter extends DatabaseImporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JSONArray parse(XmlPullParser parser)
|
|
||||||
throws IOException, XmlPullParserException, JSONException {
|
|
||||||
JSONArray entries = new JSONArray();
|
|
||||||
|
|
||||||
parser.require(XmlPullParser.START_TAG, null, "map");
|
|
||||||
while (parser.next() != XmlPullParser.END_TAG) {
|
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parser.getName().equals("string")) {
|
|
||||||
skip(parser);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JSONArray(parseEntry(parser).Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static XmlEntry parseEntry(XmlPullParser parser) throws IOException, XmlPullParserException {
|
|
||||||
parser.require(XmlPullParser.START_TAG, null, "string");
|
|
||||||
String name = parser.getAttributeValue(null, "name");
|
|
||||||
String value = parseText(parser);
|
|
||||||
parser.require(XmlPullParser.END_TAG, null, "string");
|
|
||||||
|
|
||||||
XmlEntry entry = new XmlEntry();
|
|
||||||
entry.Name = name;
|
|
||||||
entry.Value = value;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String parseText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
|
||||||
String text = "";
|
|
||||||
if (parser.next() == XmlPullParser.TEXT) {
|
|
||||||
text = parser.getText();
|
|
||||||
parser.nextTag();
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void skip(XmlPullParser parser) throws IOException, XmlPullParserException {
|
|
||||||
// source: https://developer.android.com/training/basics/network-ops/xml.html
|
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
int depth = 1;
|
|
||||||
while (depth != 0) {
|
|
||||||
switch (parser.next()) {
|
|
||||||
case XmlPullParser.END_TAG:
|
|
||||||
depth--;
|
|
||||||
break;
|
|
||||||
case XmlPullParser.START_TAG:
|
|
||||||
depth++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class XmlEntry {
|
|
||||||
String Name;
|
|
||||||
String Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AuthyEntryInfo {
|
private static class AuthyEntryInfo {
|
||||||
String OriginalName;
|
String OriginalName;
|
||||||
String AccountType;
|
String AccountType;
|
||||||
|
|
|
@ -34,12 +34,14 @@ public abstract class DatabaseImporter {
|
||||||
_importers.put("Authy", AuthyImporter.class);
|
_importers.put("Authy", AuthyImporter.class);
|
||||||
_importers.put("andOTP", AndOtpImporter.class);
|
_importers.put("andOTP", AndOtpImporter.class);
|
||||||
_importers.put("FreeOTP", FreeOtpImporter.class);
|
_importers.put("FreeOTP", FreeOtpImporter.class);
|
||||||
|
_importers.put("FreeOTP+", FreeOtpPlusImporter.class);
|
||||||
_importers.put("Google Authenticator", GoogleAuthImporter.class);
|
_importers.put("Google Authenticator", GoogleAuthImporter.class);
|
||||||
_importers.put("Steam", SteamImporter.class);
|
_importers.put("Steam", SteamImporter.class);
|
||||||
|
|
||||||
_appImporters = new LinkedHashMap<>();
|
_appImporters = new LinkedHashMap<>();
|
||||||
_appImporters.put("Authy", AuthyImporter.class);
|
_appImporters.put("Authy", AuthyImporter.class);
|
||||||
_appImporters.put("FreeOTP", FreeOtpImporter.class);
|
_appImporters.put("FreeOTP", FreeOtpImporter.class);
|
||||||
|
_appImporters.put("FreeOTP+", FreeOtpPlusImporter.class);
|
||||||
_appImporters.put("Google Authenticator", GoogleAuthImporter.class);
|
_appImporters.put("Google Authenticator", GoogleAuthImporter.class);
|
||||||
_appImporters.put("Steam", SteamImporter.class);
|
_appImporters.put("Steam", SteamImporter.class);
|
||||||
}
|
}
|
||||||
|
@ -133,43 +135,35 @@ public abstract class DatabaseImporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FileReader implements Closeable {
|
public static class FileReader {
|
||||||
private InputStream _stream;
|
private InputStream _stream;
|
||||||
|
private boolean _internal;
|
||||||
|
|
||||||
private FileReader(InputStream stream) {
|
public FileReader(InputStream stream) {
|
||||||
|
this(stream, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileReader(InputStream stream, boolean internal) {
|
||||||
_stream = stream;
|
_stream = stream;
|
||||||
}
|
_internal = internal;
|
||||||
|
|
||||||
public static FileReader open(String filename)
|
|
||||||
throws FileNotFoundException {
|
|
||||||
FileInputStream stream = new FileInputStream(filename);
|
|
||||||
return new FileReader(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FileReader open(SuFile file)
|
|
||||||
throws FileNotFoundException {
|
|
||||||
SuFileInputStream stream = new SuFileInputStream(file);
|
|
||||||
return new FileReader(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FileReader open(Context context, Uri uri)
|
|
||||||
throws FileNotFoundException {
|
|
||||||
InputStream stream = context.getContentResolver().openInputStream(uri);
|
|
||||||
return new FileReader(stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] readAll() throws IOException {
|
public byte[] readAll() throws IOException {
|
||||||
ByteInputStream stream = ByteInputStream.create(_stream);
|
try (ByteInputStream stream = ByteInputStream.create(_stream)) {
|
||||||
return stream.getBytes();
|
return stream.getBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getStream() {
|
public InputStream getStream() {
|
||||||
return _stream;
|
return _stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void close() throws IOException {
|
* Reports whether this reader reads the internal state of an app.
|
||||||
_stream.close();
|
* @return true if reading from internal file, false if reading from external file
|
||||||
|
*/
|
||||||
|
public boolean isInternal() {
|
||||||
|
return _internal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ import com.beemdevelopment.aegis.db.DatabaseEntry;
|
||||||
import com.beemdevelopment.aegis.otp.HotpInfo;
|
import com.beemdevelopment.aegis.otp.HotpInfo;
|
||||||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
import com.beemdevelopment.aegis.otp.OtpInfo;
|
||||||
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
||||||
|
import com.beemdevelopment.aegis.otp.SteamInfo;
|
||||||
import com.beemdevelopment.aegis.otp.TotpInfo;
|
import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||||
|
import com.beemdevelopment.aegis.util.PreferenceParser;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
@ -37,6 +39,7 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
return _subPath;
|
return _subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public State read(FileReader reader) throws DatabaseImporterException {
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
try {
|
try {
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
XmlPullParser parser = Xml.newPullParser();
|
||||||
|
@ -44,17 +47,22 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
parser.setInput(reader.getStream(), null);
|
parser.setInput(reader.getStream(), null);
|
||||||
parser.nextTag();
|
parser.nextTag();
|
||||||
|
|
||||||
List<XmlEntry> entries = parse(parser);
|
List<JSONObject> entries = new ArrayList<>();
|
||||||
|
for (PreferenceParser.XmlEntry entry : PreferenceParser.parse(parser)) {
|
||||||
|
if (!entry.Name.equals("tokenOrder")) {
|
||||||
|
entries.add(new JSONObject(entry.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
return new State(entries);
|
return new State(entries);
|
||||||
} catch (XmlPullParserException | IOException e) {
|
} catch (XmlPullParserException | IOException | JSONException e) {
|
||||||
throw new DatabaseImporterException(e);
|
throw new DatabaseImporterException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class State extends DatabaseImporter.State {
|
public static class State extends DatabaseImporter.State {
|
||||||
private List<XmlEntry> _entries;
|
private List<JSONObject> _entries;
|
||||||
|
|
||||||
private State(List<XmlEntry> entries) {
|
public State(List<JSONObject> entries) {
|
||||||
super(false);
|
super(false);
|
||||||
_entries = entries;
|
_entries = entries;
|
||||||
}
|
}
|
||||||
|
@ -63,34 +71,37 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
public Result convert() {
|
public Result convert() {
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
|
|
||||||
for (XmlEntry xmlEntry : _entries) {
|
for (JSONObject obj : _entries) {
|
||||||
// TODO: order
|
try {
|
||||||
if (!xmlEntry.Name.equals("tokenOrder")) {
|
DatabaseEntry entry = convertEntry(obj);
|
||||||
try {
|
result.addEntry(entry);
|
||||||
DatabaseEntry entry = convertEntry(xmlEntry);
|
} catch (DatabaseImporterEntryException e) {
|
||||||
result.addEntry(entry);
|
result.addError(e);
|
||||||
} catch (DatabaseImporterEntryException e) {
|
|
||||||
result.addError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DatabaseEntry convertEntry(XmlEntry entry) throws DatabaseImporterEntryException {
|
private static DatabaseEntry convertEntry(JSONObject obj) throws DatabaseImporterEntryException {
|
||||||
try {
|
try {
|
||||||
JSONObject obj = new JSONObject(entry.Value);
|
|
||||||
|
|
||||||
String type = obj.getString("type").toLowerCase();
|
String type = obj.getString("type").toLowerCase();
|
||||||
String algo = obj.getString("algo");
|
String algo = obj.getString("algo");
|
||||||
int digits = obj.getInt("digits");
|
int digits = obj.getInt("digits");
|
||||||
byte[] secret = toBytes(obj.getJSONArray("secret"));
|
byte[] secret = toBytes(obj.getJSONArray("secret"));
|
||||||
|
|
||||||
|
String issuer = obj.getString("issuerExt");
|
||||||
|
String name = obj.optString("label");
|
||||||
|
|
||||||
OtpInfo info;
|
OtpInfo info;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "totp":
|
case "totp":
|
||||||
info = new TotpInfo(secret, algo, digits, obj.getInt("period"));
|
int period = obj.getInt("period");
|
||||||
|
if (issuer.equals("Steam")) {
|
||||||
|
info = new SteamInfo(secret, algo, digits, period);
|
||||||
|
} else {
|
||||||
|
info = new TotpInfo(secret, algo, digits, period);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "hotp":
|
case "hotp":
|
||||||
info = new HotpInfo(secret, algo, digits, obj.getLong("counter"));
|
info = new HotpInfo(secret, algo, digits, obj.getLong("counter"));
|
||||||
|
@ -99,18 +110,16 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
throw new DatabaseImporterException("unsupported otp type: " + type);
|
throw new DatabaseImporterException("unsupported otp type: " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
String issuer = obj.getString("issuerExt");
|
|
||||||
String name = obj.optString("label");
|
|
||||||
return new DatabaseEntry(info, name, issuer);
|
return new DatabaseEntry(info, name, issuer);
|
||||||
} catch (DatabaseImporterException | OtpInfoException | JSONException e) {
|
} catch (DatabaseImporterException | OtpInfoException | JSONException e) {
|
||||||
throw new DatabaseImporterEntryException(e, entry.Value);
|
throw new DatabaseImporterEntryException(e, obj.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<XmlEntry> parse(XmlPullParser parser)
|
private static List<JSONObject> parseXml(XmlPullParser parser)
|
||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException, JSONException {
|
||||||
List<XmlEntry> entries = new ArrayList<>();
|
List<JSONObject> entries = new ArrayList<>();
|
||||||
|
|
||||||
parser.require(XmlPullParser.START_TAG, null, "map");
|
parser.require(XmlPullParser.START_TAG, null, "map");
|
||||||
while (parser.next() != XmlPullParser.END_TAG) {
|
while (parser.next() != XmlPullParser.END_TAG) {
|
||||||
|
@ -123,7 +132,10 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.add(parseEntry(parser));
|
JSONObject entry = parseXmlEntry(parser);
|
||||||
|
if (entry != null) {
|
||||||
|
entries.add(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
|
@ -137,19 +149,21 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XmlEntry parseEntry(XmlPullParser parser) throws IOException, XmlPullParserException {
|
private static JSONObject parseXmlEntry(XmlPullParser parser)
|
||||||
|
throws IOException, XmlPullParserException, JSONException {
|
||||||
parser.require(XmlPullParser.START_TAG, null, "string");
|
parser.require(XmlPullParser.START_TAG, null, "string");
|
||||||
String name = parser.getAttributeValue(null, "name");
|
String name = parser.getAttributeValue(null, "name");
|
||||||
String value = parseText(parser);
|
String value = parseXmlText(parser);
|
||||||
parser.require(XmlPullParser.END_TAG, null, "string");
|
parser.require(XmlPullParser.END_TAG, null, "string");
|
||||||
|
|
||||||
XmlEntry entry = new XmlEntry();
|
if (name.equals("tokenOrder")) {
|
||||||
entry.Name = name;
|
return null;
|
||||||
entry.Value = value;
|
}
|
||||||
return entry;
|
|
||||||
|
return new JSONObject(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String parseText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
private static String parseXmlText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||||
String text = "";
|
String text = "";
|
||||||
if (parser.next() == XmlPullParser.TEXT) {
|
if (parser.next() == XmlPullParser.TEXT) {
|
||||||
text = parser.getText();
|
text = parser.getText();
|
||||||
|
@ -176,9 +190,4 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class XmlEntry {
|
|
||||||
String Name;
|
|
||||||
String Value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.beemdevelopment.aegis.importers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FreeOtpPlusImporter extends DatabaseImporter {
|
||||||
|
private static final String _subPath = "shared_prefs/tokens.xml";
|
||||||
|
private static final String _pkgName = "org.liberty.android.freeotpplus";
|
||||||
|
|
||||||
|
public FreeOtpPlusImporter(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAppPkgName() {
|
||||||
|
return _pkgName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAppSubPath() {
|
||||||
|
return _subPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
|
State state;
|
||||||
|
|
||||||
|
if (reader.isInternal()) {
|
||||||
|
state = new FreeOtpImporter(getContext()).read(reader);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
String json = new String(reader.readAll(), StandardCharsets.UTF_8);
|
||||||
|
JSONObject obj = new JSONObject(json);
|
||||||
|
JSONArray array = obj.getJSONArray("tokens");
|
||||||
|
|
||||||
|
List<JSONObject> entries = new ArrayList<>();
|
||||||
|
for (int i = 0; i < array.length(); i++) {
|
||||||
|
entries.add(array.getJSONObject(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
state = new FreeOtpImporter.State(entries);
|
||||||
|
} catch (IOException | JSONException e) {
|
||||||
|
throw new DatabaseImporterException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,7 @@ public class GoogleAuthImporter extends DatabaseImporter {
|
||||||
return _subPath;
|
return _subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public State read(FileReader reader) throws DatabaseImporterException {
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ public class SteamImporter extends DatabaseImporter {
|
||||||
return new SuFile(_subDir, files[0].getName()).getPath();
|
return new SuFile(_subDir, files[0].getName()).getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public State read(FileReader reader) throws DatabaseImporterException {
|
public State read(FileReader reader) throws DatabaseImporterException {
|
||||||
try (ByteInputStream stream = ByteInputStream.create(reader.getStream())) {
|
try (ByteInputStream stream = ByteInputStream.create(reader.getStream())) {
|
||||||
JSONObject obj = new JSONObject(new String(stream.getBytes(), StandardCharsets.UTF_8));
|
JSONObject obj = new JSONObject(new String(stream.getBytes(), StandardCharsets.UTF_8));
|
||||||
|
|
|
@ -41,9 +41,11 @@ import com.beemdevelopment.aegis.ui.preferences.SwitchPreference;
|
||||||
import com.takisoft.preferencex.PreferenceFragmentCompat;
|
import com.takisoft.preferencex.PreferenceFragmentCompat;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
import com.topjohnwu.superuser.io.SuFile;
|
||||||
|
import com.topjohnwu.superuser.io.SuFileInputStream;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -439,7 +441,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
}
|
}
|
||||||
|
|
||||||
SuFile file = importer.getAppPath();
|
SuFile file = importer.getAppPath();
|
||||||
try (DatabaseImporter.FileReader reader = DatabaseImporter.FileReader.open(file)) {
|
try (SuFileInputStream stream = new SuFileInputStream(file)) {
|
||||||
|
DatabaseImporter.FileReader reader = new DatabaseImporter.FileReader(stream, true);
|
||||||
importDatabase(importer, reader);
|
importDatabase(importer, reader);
|
||||||
}
|
}
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
@ -511,8 +514,9 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (DatabaseImporter.FileReader reader = DatabaseImporter.FileReader.open(getContext(), uri)) {
|
try (InputStream stream = getContext().getContentResolver().openInputStream(uri)) {
|
||||||
DatabaseImporter importer = DatabaseImporter.create(getContext(), _importerType);
|
DatabaseImporter importer = DatabaseImporter.create(getContext(), _importerType);
|
||||||
|
DatabaseImporter.FileReader reader = new DatabaseImporter.FileReader(stream);
|
||||||
importDatabase(importer, reader);
|
importDatabase(importer, reader);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Toast.makeText(getActivity(), R.string.file_not_found, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.file_not_found, Toast.LENGTH_SHORT).show();
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
package com.beemdevelopment.aegis.util;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PreferenceParser {
|
||||||
|
private PreferenceParser() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<XmlEntry> parse(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||||
|
List<XmlEntry> entries = new ArrayList<>();
|
||||||
|
|
||||||
|
parser.require(XmlPullParser.START_TAG, null, "map");
|
||||||
|
while (parser.next() != XmlPullParser.END_TAG) {
|
||||||
|
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parser.getName().equals("string")) {
|
||||||
|
skip(parser);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.add(parseEntry(parser));
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static XmlEntry parseEntry(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||||
|
parser.require(XmlPullParser.START_TAG, null, "string");
|
||||||
|
String name = parser.getAttributeValue(null, "name");
|
||||||
|
String value = parseText(parser);
|
||||||
|
parser.require(XmlPullParser.END_TAG, null, "string");
|
||||||
|
|
||||||
|
XmlEntry entry = new XmlEntry();
|
||||||
|
entry.Name = name;
|
||||||
|
entry.Value = value;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String parseText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||||
|
String text = "";
|
||||||
|
if (parser.next() == XmlPullParser.TEXT) {
|
||||||
|
text = parser.getText();
|
||||||
|
parser.nextTag();
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void skip(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||||
|
// source: https://developer.android.com/training/basics/network-ops/xml.html
|
||||||
|
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int depth = 1;
|
||||||
|
while (depth != 0) {
|
||||||
|
switch (parser.next()) {
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
depth--;
|
||||||
|
break;
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
depth++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class XmlEntry {
|
||||||
|
public String Name;
|
||||||
|
public String Value;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue